ICU 構文とリッチテキスト描画
ts-intl は ICU MessageFormat 1.x の標準構文をサポートします。
複数形サポート (Pluralization)
構造化複数形オブジェクト
CLDR 標準の複数形カテゴリ(zero、one、two、few、many、other)に準拠したネストオブジェクト形式をサポートします:
const messages = {
cart: {
zero: "カートは空です",
other: "カートに合計 {count} 件の商品があります",
},
} as const;
const t = getTranslations("ja-JP");
t("cart", { count: 0 }); // "カートは空です"
t("cart", { count: 1 }); // "カートに合計 1 件の商品があります"
t("cart", { count: 5 }); // "カートに合計 5 件の商品があります"
説明:CLDR 仕様において、日本語には
other複数形カテゴリのみが存在します(ts-intlではcount === 0の場合にzeroも追加サポートしています)。特定数値(例:1)に応じた文言の出し分けが必要な場合は、下記のテンプレート内埋め込み ICUplural構文(=1など)の利用を推奨します。
テンプレート内 ICU plural 構文
const messages = {
inbox:
"{count, plural, =0 {未読メッセージはありません} other {未読メッセージが # 件あります}}。",
} as const;
const t = getTranslations("ja-JP");
t("inbox", { count: 0 }); // "未読メッセージはありません。"
t("inbox", { count: 3 }); // "未読メッセージが 3 件あります。"
序数詞のフォーマット (selectordinal)
序数表現の処理に使用します(完全一致 = が分類ルールより優先されます):
const messages = {
podium:
"{rank, selectordinal, =1 {1位} =2 {2位} =3 {3位} other {#位}}になりました!",
} as const;
const t = getTranslations("ja-JP");
t("podium", { rank: 1 }); // "1位になりました!"
t("podium", { rank: 4 }); // "4位になりました!"
条件分岐選択 (select)
ステータス列挙型や分類値に基づいて異なる文言をマッチングします:
const messages = {
roleBadge:
"{role, select, admin {管理者} editor {編集者} other {一般メンバー}}",
} as const;
const t = getTranslations("ja-JP");
t("roleBadge", { role: "admin" }); // "管理者"
t("roleBadge", { role: "guest" }); // "一般メンバー"
汎用リッチテキスト補間 t.rich()
XML 風タグを通じて文言をフロントエンドコンポーネントや DOM ノードへマッピングし、dangerouslySetInnerHTML による XSS リスクを回避します:
const messages = {
notice: "続行する前に<terms>利用規約</terms>と<privacy>プライバシーポリシー</privacy>をご確認ください。",
} as const;
const t = getTranslations("ja-JP");
// React / Vue 等で直接コンポーネント化
const elements = t.rich("notice", {
terms: (children) => <a href="/terms" className="underline">{children}</a>,
privacy: (children) => <a href="/privacy" className="underline">{children}</a>,
});
HTML 文字列マークアップ描画 t.markup()
安全な HTML タグを含む文字列を生成するために使用します:
const html = t.markup("notice", {
terms: (c) => `<a href="/terms">${c}</a>`,
privacy: (c) => `<a href="/privacy">${c}</a>`,
});