@k8ordo/i18n

API

@k8ordo/i18nがexportする関数と型の一覧です。入口は@k8ordo/i18nの1つだけで、Server Componentのモジュールからも、Client Componentのモジュールからもimportできます。

このページの内容

defineLocales

import元 @k8ordo/i18n

ロケールの集合を定義します。ロケールの一覧に依存するものは、どれもこの戻り値から読みます。

ts
defineLocales(
  definitions: Record<string, LocaleDefinition>,
  options?: LocalesOptions<D>,
): Locales<L, D>

引数

definitionsRecord<string, LocaleDefinition>
ロケールのタグをキーに、そのロケールのtimeZoneとdirを値にしたオブジェクト。タグはBCP 47で書き、書いた順がallの順になります。
optionsLocalesOptions<D>
defaultで既定のロケールを選びます。省くと、先頭に書いたロケールが既定です。

戻り値

Locales<L, D> — ロケールの一覧と、一覧から作った道具をまとめた集合。

注意

  • ロケールが1つも無い定義と、一覧に無いdefaultは、呼んだ時点でTypeErrorを投げます。BCP 47ではないタグと、実行環境が知らないタイムゾーンも同じです。欠けたtimeZoneと、ltrかrtlではないdirもエラーになります。
  • 定義した集合はglobalThisに登録され、messageはそこから既定のロケールを読みます。後から定義した集合が勝つので、アプリで1回だけ呼びます。
  • キーはリテラル型のまま推論されるので、as constは要りません。
i18n.ts
export const locales = defineLocales(
  {
    ja: { timeZone: 'Asia/Tokyo', dir: 'ltr' },
    en: { timeZone: 'America/New_York', dir: 'ltr' },
  },
  { default: 'en' },
);

Locales

import元 @k8ordo/i18n

defineLocalesが返す集合の型です。Lはタグの和集合、Dは既定のロケールのタグです。

ts
type Locales<L extends string, D extends L> =
  IntlFormats & {
    all: readonly L[];
    definitions: Readonly<Record<L, LocaleDefinition>>;
    default: D;
    is: (value: unknown) => value is L;
    negotiate: (requested: Iterable<string>) => L;
    negotiateRequest: (
      request: Request,
      options?: NegotiateRequestOptions,
    ) => L;
    localize: (pathname: string, locale: L) => string;
    delocalize: (pathname: string) => Delocalized<L>;
    paths: (patterns: readonly string[]) => string[];
    paramsSchema: LocaleParamsSchema<L>;
    getLocale: () => L;
    run: <T>(locale: L, fn: () => T) => T;
  };

フィールド

allreadonly L[]
書いた順に並んだタグ。
definitionsReadonly<Record<L, LocaleDefinition>>
ロケールごとの{ timeZone, dir }。defineLocalesに渡したオブジェクトそのものです。
defaultD
既定のロケール。何もロケールを指名していないときと、交渉でどのロケールも一致しなかったときに使います。
is(value: unknown) => value is L
一覧に含まれるかを確かめる型ガード。大文字と小文字を区別するので、is('EN')はfalseです。
negotiate(requested) => L
希望の並びから、集合のロケールを1つ選びます。タグごとに同じタグ、同じ言語の順に探し、最後まで無ければ既定のロケールを返します。
negotiateRequest(request, options?) => L
Requestからロケールを選びます。options.cookieで名前を渡したCookieを先に読み、次にAccept-Languageを読みます。
localize(pathname, locale) => string
pathnameの前にロケールの区間を付けます。'/ui'は'/en/ui'に、'/'は'/en'になります。
delocalize(pathname) => Delocalized<L>
先頭のロケールの区間を外します。先頭の区間がロケールでなければ、localeはnullです。
paths(patterns) => string[]
@k8ordo/staticのpathsオプション。/:localeの区間を持つパターンを、ロケールの数だけ展開します。
paramsSchemaLocaleParamsSchema<L>
[locale]の区間のスキーマ。サーバーでは、受け付けたロケールがそのページの描画のロケールになります。
getLocale() => L
描画中のロケール。サーバーでは受け付けたロケール、ブラウザではURLの先頭の区間で、どちらも無ければ既定のロケールです。
run(locale, fn) => T
fnと、そこから始まる処理をlocaleで動かし、fnの戻り値を返します。サーバーでだけ使えます。
dateTimeFormat …IntlFormats
今のロケールのIntlのオブジェクトを返すメンバー。下のIntlFormatsを見てください。

注意

  • どのメンバーもthisを使わないので、export const { getLocale } = localesのように取り出して使えます。
  • runをブラウザで呼ぶと、locales.run: in the browser the URL is the locale — navigate insteadを投げます。
  • AsyncLocalStorageを取り出せないサーバーのランタイムでは、runと、ロケールを受け付けるときのparamsSchemaがエラーを投げます。

IntlFormats

import元 @k8ordo/i18n

集合のうち、今のロケールのIntlのオブジェクトを返すメンバーです。返すのはIntlのオブジェクトそのものです。

ts
type IntlFormats = {
  dateTimeFormat: (
    options?: LocaleDateTimeFormatOptions,
  ) => Intl.DateTimeFormat;
  numberFormat: (
    options?: Intl.NumberFormatOptions,
  ) => Intl.NumberFormat;
  relativeTimeFormat: (
    options?: Intl.RelativeTimeFormatOptions,
  ) => Intl.RelativeTimeFormat;
  pluralRules: (
    options?: Intl.PluralRulesOptions,
  ) => Intl.PluralRules;
  listFormat: (options?: Intl.ListFormatOptions) => Intl.ListFormat;
};

フィールド

dateTimeFormat(options?) => Intl.DateTimeFormat
今のロケールと、そのロケールのtimeZoneで書くIntl.DateTimeFormat。
numberFormat(options?) => Intl.NumberFormat
今のロケールのIntl.NumberFormat。
relativeTimeFormat(options?) => Intl.RelativeTimeFormat
今のロケールのIntl.RelativeTimeFormat。
pluralRules(options?) => Intl.PluralRules
今のロケールのIntl.PluralRules。
listFormat(options?) => Intl.ListFormat
今のロケールのIntl.ListFormat。

注意

  • ロケールとオプションの組ごとに1つだけ作り、次からは同じものを返します。オプションはJSONにして見分けます。
  • どれもフックではないので、Server ComponentでもClient Componentでも、文言の関数の中でも呼べます。

message

import元 @k8ordo/i18n

1つの文言を、すべてのロケールの文とともに宣言します。返す関数は、呼ばれた場所のロケールの文を返します。

ts
function message(variants: Variants<string>): Message;
function message<A extends readonly unknown[]>(
  variants: Variants<(...args: A) => string>,
): Message<A>;

引数

variantsVariants<string> | Variants<(...args: A) => string>
ロケールごとの文。すべてのロケールを文で書くか、すべてを同じ引数の関数で書きます。

戻り値

Message<A> — 引数を受け取り、今のロケールの文を返す関数。

注意

  • Registerを登録すると、ロケールが欠けた宣言は型エラーになります。型をすり抜けた欠けは、読んだ時点でmessage: no text for "en" in ["ja"]のようなTypeErrorを投げます。
  • 何もロケールを指名していないときは、既定のロケールの文を返します。この環境で集合がまだ定義されていなければ、既定のロケールの代わりに最初に書いた文を返します。
  • 引数の型は、注釈を書いたロケールから決まります。どこにも書かないとunknownになるので、少なくとも1つに書くか、message<[name: string]>({ … })のように型引数で渡します。
  • 宣言には副作用が無いので、どこからも呼ばれない文言はバンドラが取り除きます。
messages/nav.ts
export const home = message({ ja: 'ホーム', en: 'Home' });

export const greeting = message({
  ja: (name: string) => `こんにちは、${name}さん`,
  en: (name) => `Hello, ${name}`,
});

Message

import元 @k8ordo/i18n

messageが返す関数の型です。文言をpropsで受け取るコンポーネントは、この型で受け取ります。

ts
type Message<A extends readonly unknown[] = []> = (
  ...args: A
) => string;

注意

  • 関数なので、Server ComponentからClient Componentへpropsで渡せません。そこでは、呼んだ結果の文字列を渡します。

parseAcceptLanguage

import元 @k8ordo/i18n

Accept-Languageヘッダーを、negotiateに渡せる希望の並びにします。

ts
parseAcceptLanguage(header: string | null): string[]

引数

headerstring | null
ヘッダーの値。request.headers.get('accept-language')をそのまま渡せます。

戻り値

string[] — 重みの大きい順に並べたタグ。ヘッダーが無いか空白だけなら、空の配列。

注意

  • 重みが同じタグは、ヘッダーの順を保ちます。重みが0以下のタグと*は落とします。
  • タグそのものは確かめません。BCP 47ではないタグは、negotiateが飛ばします。
ts
parseAcceptLanguage('en-US;q=0.8, ja, en;q=0.9');
// ['ja', 'en', 'en-US']

currentLocale

import元 @k8ordo/i18n

アプリの集合が決める、今のロケールを返します。アプリのことを知らないライブラリが、アプリのロケールに合わせるために使います。

ts
currentLocale(): RegisteredLocale | null

戻り値

RegisteredLocale | null — 指名されたロケール。無ければ集合の既定のロケールで、この環境で集合が定義されていなければnull。

注意

  • @k8ordo/uiのコンポーネントは、自分で描く文言のロケールをこれで決めています。
  • アプリのコードでは、集合の型が付くlocales.getLocale()を使います。

Register

import元 @k8ordo/i18n

アプリのロケールの型を、パッケージに伝えるための宣言です。アプリで1回だけマージします。

ts
declare module '@k8ordo/i18n' {
  interface Register {
    locale: LocaleOf<typeof locales>;
  }
}

注意

  • マージされるための型なので、typeではなくinterfaceで書きます。
  • 登録する前はRegisteredLocaleがstringなので、ロケールの欠けは型エラーになりません。

RegisteredLocale

import元 @k8ordo/i18n

Registerに登録したロケールの和集合です。登録する前はstringです。

ts
type RegisteredLocale = Register extends {
  locale: infer L extends string;
}
  ? L
  : string;

Variants

import元 @k8ordo/i18n

Registerに登録したロケールごとに、1つずつ値を持つオブジェクトの型です。messageが受け取るのもこの型です。

ts
type Variants<V> = Readonly<Record<RegisteredLocale, V>>;

注意

  • 言語の切り替えに並べる言語名のように、文言以外でもロケールごとに漏れなくそろえたい値に使えます。

LocaleOf

import元 @k8ordo/i18n

集合のタグの和集合を取り出します。Registerのlocaleにも、この型を書きます。

ts
type LocaleOf<Ls> =
  Ls extends Locales<infer L, infer _D> ? L : never;

LocaleDefinition

import元 @k8ordo/i18n

1つのロケールに添える情報です。どちらも実行環境から導かずに書きます。

ts
type LocaleDefinition = {
  timeZone: string;
  dir: 'ltr' | 'rtl';
};

フィールド

timeZonestring
そのロケールで日付を表示するIANAのタイムゾーン。サーバーでもブラウザでも同じタイムゾーンで書くので、日付がずれません。
dir'ltr' | 'rtl'
そのロケールの文字の向き。<html dir>に使います。

LocalesOptions

import元 @k8ordo/i18n

defineLocalesの第2引数の型です。

ts
type LocalesOptions<D extends string> = { default?: D };

フィールド

defaultD
既定のロケール。一覧のタグでなければならず、省くと先頭に書いたロケールです。

NegotiateRequestOptions

import元 @k8ordo/i18n

negotiateRequestの第2引数の型です。

ts
type NegotiateRequestOptions = { cookie?: string };

フィールド

cookiestring
訪問者が選んだ言語を持つCookieの名前。省くとAccept-Languageだけを読みます。

Delocalized

import元 @k8ordo/i18n

delocalizeが返す値の型です。

ts
type Delocalized<L extends string> = {
  locale: L | null;
  pathname: string;
};

フィールド

localeL | null
先頭の区間が示すロケール。先頭の区間がロケールでなければnull。
pathnamestring
区間を外した残りのpathname。ロケールの区間しか無いときは/です。

LocaleParamsSchema

import元 @k8ordo/i18n

paramsSchemaの型です。スキーマのライブラリに頼らないよう、Standard Schemaの形をこのパッケージ自身が宣言しています。

ts
type LocaleParamsSchema<L extends string> = {
  '~standard': {
    version: 1;
    vendor: '@k8ordo/i18n';
    validate: (value: unknown) =>
      | { value: { locale: L } }
      | { issues: { message: string; path: ['locale'] }[] };
  };
};

注意

  • 検証は同期的です。一覧に無いロケールには、path: ['locale']のissueを返します。
  • 受け付けた値は{ locale }だけです。ほかのパラメータは、後に続くスキーマのために文字列のまま残ります。

LocaleDateTimeFormatOptions

import元 @k8ordo/i18n

dateTimeFormatのオプションの型です。Intl.DateTimeFormatOptionsのうち、timeZoneだけを受け付けません。

ts
type LocaleDateTimeFormatOptions = Intl.DateTimeFormatOptions & {
  timeZone?: never;
};

注意

  • asでtimeZoneを通しても、ロケールのtimeZoneで上書きします。
k8ordo

Baselineに入った機能を、制限なく使うReactのライブラリ群。

© 2026 k8o — MIT License

組版:Noto Sans JP / M PLUS 2