JavaScriptの標準組み込みオブジェクトにIntl
オブジェクトがあります。国際化APIの名前空間で、locale
に依存した数値のフォーマットや分かち書きを行うプロパティを持ちます。
この記事ではそんなプロパティの1つであるRelativeTimeFormat
について解説します。
RelativeTimeFormat
RelativeTimeFormat
は相対時刻をlocale
に応じて扱うためのオブジェクトです。
const rtf = new Intl.RelativeTimeFormat('ja-JP');
// 2 日後
console.log(rtf.format(2, 'day'));
// 9 か月前
console.log(rtf.format(-9, 'month'));
RelativeTimeFormat
を初期化するタイミングで扱いたいlocale
を指定します。
const rtf = new Intl.RelativeTimeFormat('ja-JP');
RelativeTimeFormat
には第2引数でオプションをオブジェクトとして渡せます。
const rtf = new Intl.RelativeTimeFormat(
'ja-JP',
{
localeMatcher: 'lookup',
numeric: 'auto',
style: 'short',
},
);
オプションはlocaleMatcher
とnumeric
とstyle
の3つです。
localeMathcer
は第一引数のlocale
が配列で複数渡ってきた時の優先順位の付け方を決めます。デフォルトではbest fit
で他にlookup
を指定できます。
best fit
はリクエストやランタイムを用いて最適なlocale
を決定し、lookup
を指定した場合はLookup
のアルゴリズムによって決定されます。
numeric
はメッセージを表示する形式を指定できます。デフォルトはalways
でどのような数値であっても一貫した形式でフォーマットするのですが、auto
にすると明日や昨日のように特定の数値を別の一般的な言い方に置き換えます。
const rtf1 = new Intl.RelativeTimeFormat('ja-JP');
const rtf2 = new Intl.RelativeTimeFormat(
'ja-JP',
{
numeric: 'auto',
},
);
// 2 日後
console.log(rtf1.format(2, 'day'));
// 明後日
console.log(rtf2.format(2, 'day'));
style
は単位の長さを指定します。デフォルトはlong
でshort
とnarrow
が存在します。
locale
がja-JP
の場合はlong
とshort
に違いがありません(例えばlocale
がen
の場合はlong
ではmonth
、short
ではmo
のように表示されます)。narrow
は数値と単位の間の空白を埋めた形で出力します。
const rtf1 = new Intl.RelativeTimeFormat('ja-JP');
const rtf2 = new Intl.RelativeTimeFormat(
'ja-JP',
{
style: 'short',
},
);
const rtf3 = new Intl.RelativeTimeFormat(
'ja-JP',
{
style: 'narrow',
},
);
// 2 日後
console.log(rtf1.format(2, 'day'));
// 2 日後
console.log(rtf2.format(2, 'day'));
// 2日後
console.log(rtf3.format(2, 'day'));
このように作成されたRelativeTimeFormat
はformat
メソッドを用いて相対時刻を表示します。第1引数に相対日付の数値を、第2引数には単位を渡します。
第1引数の数値は正であれば未来との相対時刻を、負であれば過去との相対日付と判断します。
const rtf = new Intl.RelativeTimeFormat('ja-JP');
// 1 年後
console.log(rtf.format(1, 'year'));
// 1 年前
console.log(rtf.format(-1, 'year'));
第2引数はyear
、quarter
、month
、week
、day
、hour
、minute
、second
とその複数形を渡します。それぞれその名の通りのフォーマットをしてくれます。
const rtf = new Intl.RelativeTimeFormat('ja-JP');
// 1 年後
console.log(rtf.format(1, 'year'));
// 1 四半期後
console.log(rtf.format(1, 'quarter'));
// 1 か月後
console.log(rtf.format(1, 'month'));
// 1 週間後
console.log(rtf.format(1, 'week'));
// 1 日後
console.log(rtf.format(1, 'day'));
// 1 時間後
console.log(rtf.format(1, 'hour'));
// 1 分後
console.log(rtf.format(1, 'minute'));
// 1 秒後
console.log(rtf.format(1, 'second'));
部品単位で相対時刻を取得する
RelatveTimeFormat
オブジェクトのformatToParts
メソッドを使えば数値と単位を配列の要素に分けて表示できます。
const rtf = new Intl.RelativeTimeFormat('ja-JP');
/**
* [
* {
* type: 'integer',
* unit: 'day',
* value: 2,
* },
* {
* type: 'literal',
* value: ' 日後',
* },
* ]
*/
console.log(rtf.formatToParts(2, 'day'));
/**
* [
* {
* type: 'integer',
* unit: 'day',
* value: 9,
* },
* {
* type: 'literal',
* value: ' か月前',
* },
* ]
*/
console.log(rtf.formatToParts(-9, 'month'));
引数はformat
メソッドと同じです。単位には空白が含まれていることに注意です。
localeが対応していることを確認する
RelativeTimeFormat
オブジェクトに渡すlocale
は静的メソッドであるsupportedLocalesOf
を用いて確認できます。引数はRelativeTimeFormat
オブジェクトのコンストラクタと同じです。
// ['ja', 'ja-JP']
console.log(
Intl.RelativeTimeFormat.supportedLocalesOf(
['ja', 'JP', 'ja-JP']
)
);
有効なオプションを確認する
resolvedOptions
はRelativeTimeFormat
オブジェクトを作成したときに有効となった設定を表示します。
// {locale: 'ja', style: 'long', numeric: 'always', numberingSystem: 'latn'}
console.log((new Intl.RelativeTimeFormat('ja')).resolvedOptions());
// {locale: 'ja-JP', style: 'long', numeric: 'always', numberingSystem: 'latn'}
console.log((new Intl.RelativeTimeFormat(['ja-JP', 'en'])).resolvedOptions());
const rtf = new Intl.RelativeTimeFormat(
'ja-JP',
{
localeMatcher: 'lookup',
numeric: 'auto',
style: 'short',
},
);
// {locale: 'ja-JP', style: 'short', numeric: 'auto', numberingSystem: 'latn'}
console.log(rtf.resolvedOptions());
localeMatcher
はおそらくlocale
の決定後は使われないことから表示されません。
numberingSystem
だけ見慣れませんが、これはlocale
に依存する命数法を渡しています。
const locale = new Intl.Locale(
'ja-JP',
{ numberingSystem: 'arab' }
);
// ['arab']
console.log(locale.getNumberingSystems());
// {locale: 'ja-JP-u-nu-arab', style: 'long', numeric: 'always', numberingSystem: 'arab'}
console.log((new Intl.RelativeTimeFormat(locale)).resolvedOptions())