最新のウェブアプリケーションでは、完全な日付やタイムスタンプの代わりに、「昨日」、「42秒前」、「3か月後」などのフレーズがよく使用されます。このような相対時間形式の値は非常に一般的になり、ローカライズされた方法でフォーマットするユーティリティ関数を実装する人気のあるライブラリがいくつかあります。(例としては、Moment.js、Globalize、date-fnsなどがあります。)
ローカライズされた相対時間フォーマッタを実装する際の問題の1つは、サポートする言語ごとに、慣用的な単語やフレーズ(「昨日」や「前四半期」など)のリストが必要になることです。Unicode CLDRはこのデータを提供していますが、JavaScriptで使用するには、他のライブラリコードと一緒に埋め込んで配布する必要があります。これは残念ながら、このようなライブラリのバンドルサイズを増加させ、読み込み時間、解析/コンパイルコスト、およびメモリ消費に悪影響を及ぼします。
最新のIntl.RelativeTimeFormat
APIは、その負担をJavaScriptエンジンに移します。JavaScriptエンジンはロケールデータを配布し、JavaScript開発者が直接利用できるようにすることができます。Intl.RelativeTimeFormat
は、パフォーマンスを犠牲にすることなく、相対時間のローカライズされたフォーマットを可能にします。
使用例 #
次の例は、英語を使用して相対時間フォーマッタを作成する方法を示しています。
const rtf = new Intl.RelativeTimeFormat('en');
rtf.format(3.14, 'second');
// → 'in 3.14 seconds'
rtf.format(-15, 'minute');
// → '15 minutes ago'
rtf.format(8, 'hour');
// → 'in 8 hours'
rtf.format(-2, 'day');
// → '2 days ago'
rtf.format(3, 'week');
// → 'in 3 weeks'
rtf.format(-5, 'month');
// → '5 months ago'
rtf.format(2, 'quarter');
// → 'in 2 quarters'
rtf.format(-42, 'year');
// → '42 years ago'
Intl.RelativeTimeFormat
コンストラクターに渡される引数は、BCP 47言語タグを含む文字列、またはそのような言語タグの配列のいずれかになります。
別の言語(スペイン語)を使用する例を次に示します。
const rtf = new Intl.RelativeTimeFormat('es');
rtf.format(3.14, 'second');
// → 'dentro de 3,14 segundos'
rtf.format(-15, 'minute');
// → 'hace 15 minutos'
rtf.format(8, 'hour');
// → 'dentro de 8 horas'
rtf.format(-2, 'day');
// → 'hace 2 días'
rtf.format(3, 'week');
// → 'dentro de 3 semanas'
rtf.format(-5, 'month');
// → 'hace 5 meses'
rtf.format(2, 'quarter');
// → 'dentro de 2 trimestres'
rtf.format(-42, 'year');
// → 'hace 42 años'
さらに、Intl.RelativeTimeFormat
コンストラクターは、出力の細かい制御を可能にするオプションのoptions
引数を受け入れます。柔軟性を示すために、デフォルト設定に基づく英語の出力をいくつか見てみましょう。
// Create a relative time formatter for the English language, using the
// default settings (just like before). In this example, the default
// values are explicitly passed in.
const rtf = new Intl.RelativeTimeFormat('en', {
localeMatcher: 'best fit', // other values: 'lookup'
style: 'long', // other values: 'short' or 'narrow'
numeric: 'always', // other values: 'auto'
});
// Now, let’s try some special cases!
rtf.format(-1, 'day');
// → '1 day ago'
rtf.format(0, 'day');
// → 'in 0 days'
rtf.format(1, 'day');
// → 'in 1 day'
rtf.format(-1, 'week');
// → '1 week ago'
rtf.format(0, 'week');
// → 'in 0 weeks'
rtf.format(1, 'week');
// → 'in 1 week'
上記のフォーマッタは、'yesterday'
の代わりに'1 day ago'
を、'this week'
の代わりに少しぎこちない'in 0 weeks'
を出力したことに気付いたかもしれません。これは、デフォルトでは、フォーマッタが出力に数値を使用するためです。
この動作を変更するには、numeric
オプションを'auto'
(暗黙のデフォルトの'always'
の代わりに)に設定します。
// Create a relative time formatter for the English language that does
// not always have to use numeric value in the output.
const rtf = new Intl.RelativeTimeFormat('en', { numeric: 'auto' });
rtf.format(-1, 'day');
// → 'yesterday'
rtf.format(0, 'day');
// → 'today'
rtf.format(1, 'day');
// → 'tomorrow'
rtf.format(-1, 'week');
// → 'last week'
rtf.format(0, 'week');
// → 'this week'
rtf.format(1, 'week');
// → 'next week'
他のIntl
クラスと同様に、Intl.RelativeTimeFormat
には、format
メソッドに加えて、formatToParts
メソッドがあります。format
は最も一般的なユースケースに対応していますが、生成された出力の個々の部分にアクセスする必要がある場合は、formatToParts
が役立ちます。
// Create a relative time formatter for the English language that does
// not always have to use numeric value in the output.
const rtf = new Intl.RelativeTimeFormat('en', { numeric: 'auto' });
rtf.format(-1, 'day');
// → 'yesterday'
rtf.formatToParts(-1, 'day');
// → [{ type: 'literal', value: 'yesterday' }]
rtf.format(3, 'week');
// → 'in 3 weeks'
rtf.formatToParts(3, 'week');
// → [{ type: 'literal', value: 'in ' },
// { type: 'integer', value: '3', unit: 'week' },
// { type: 'literal', value: ' weeks' }]
残りのオプションとその動作の詳細については、提案リポジトリのAPIドキュメントを参照してください。
結論 #
Intl.RelativeTimeFormat
は、V8 v7.1およびChrome 71でデフォルトで利用可能です。このAPIがより広く利用可能になるにつれて、Moment.js、Globalize、date-fnsなどのライブラリは、ハードコードされたCLDRデータベースへの依存をなくし、ネイティブの相対時間フォーマット機能を優先するようになります。これにより、読み込み時間のパフォーマンス、解析およびコンパイル時間のパフォーマンス、実行時のパフォーマンス、およびメモリ使用量が向上します。
Intl.RelativeTimeFormat
のサポート #
- Chrome: バージョン 71 からサポート
- Firefox: バージョン 65 からサポート
- Safari: バージョン 14 からサポート
- Node.js: バージョン 12 からサポート
- Babel: サポートなし