日付と数値
複数形・日付・数値・並びの書式は Intl そのものです。ロケール集合は、今のロケール(日付ならそのロケールのタイムゾーンも)で Intl のオブジェクトを引き、作ったものを使い回します。独自の書式の記法はありません。
集合が引く Intl
どれも集合のメンバーで、hook ではありません。Server Component でも Client Component でも、文言の関数の中でも呼べます。
| メンバー | 返すもの |
|---|---|
dateTimeFormat(options?) | 今のロケールと、そのロケールの timeZone の Intl.DateTimeFormat。 |
numberFormat(options?) | 今のロケールの Intl.NumberFormat。 |
relativeTimeFormat(options?) | 今のロケールの Intl.RelativeTimeFormat。 |
pluralRules(options?) | 今のロケールの Intl.PluralRules。 |
listFormat(options?) | 今のロケールの Intl.ListFormat。 |
返すのは Intl のオブジェクトそのものなので、format・formatToParts・formatRange・select・resolvedOptions は Intl のものをそのまま使えます。オプションも Intl のものです。
ここに無い Intl(Intl.Collator、Intl.DisplayNames など)は、getLocale() のタグを渡して自分で作ります。
日付はロケールのタイムゾーンで
dateTimeFormat は、defineLocales に書いたそのロケールの timeZone でしか日付を書きません。
// src/components/published-at.tsx
import { locales } from '../i18n';
export function PublishedAt({ date }: { date: Date }) {
return (
<time dateTime={date.toISOString()}>
{locales.dateTimeFormat({ dateStyle: 'medium' }).format(date)}
</time>
);
}実行環境のタイムゾーンは、サーバーではサーバーのもの、ブラウザでは訪問者のものです。それに任せて日付を書くと、サーバーの HTML とブラウザの hydrate で文が変わり、日付の境目では 1 日ずれます。ロケールのタイムゾーンは両側で同じなので、この食い違いが起きません。
オプションの型は timeZone を受け付けません。as で押し通しても、ロケールのタイムゾーンが上書きします。
// the type refuses it — the locale's time zone is the only one
locales.dateTimeFormat({ dateStyle: 'medium', timeZone: 'UTC' });訪問者のタイムゾーンで見せたい表示(手元の時計、今からの相対時間)は、サーバーとブラウザで必ず違うものです。Intl を直接使い、ブラウザだけで描く部分に置きます。
文言の中で
値を取る文言の関数の中で呼べば、複数形も日付もその文言の一部になります。関数が呼ばれるのは、そのロケールが今のロケールのときです。
// src/messages/cart.ts
import { message } from '@k8ordo/i18n';
import { locales } from '../i18n';
export const items = message({
ja: (count: number) => `${locales.numberFormat().format(count)} 件`,
en: (count) =>
`${locales.numberFormat().format(count)} ${locales.pluralRules().select(count) === 'one' ? 'item' : 'items'}`,
});
export const updated = message({
ja: (date: Date) =>
`${locales.dateTimeFormat({ dateStyle: 'long' }).format(date)} 更新`,
en: (date) =>
`Updated ${locales.dateTimeFormat({ dateStyle: 'long' }).format(date)}`,
});作ったものは使い回す
Intl のオブジェクトは作るのが重いので、ロケールとオプションの組ごとに 1 つ作り、次からは同じものを返します。
オプションは JSON で見分けます。同じオプションを違う順で書くと 2 つ作られますが、答えが変わることはありません。描画のたびに呼んでも、作り直しにはなりません。