JavaScriptのビルトインオブジェクトから日本語が返ってくる面白さ

UI開発者 宇賀

皆さんこんにちは!UI開発者の宇賀です。

JavaScriptにはIntlというビルトインオブジェクトがあります。これは言語に依存した文字列や数値フォーマットを扱う名前空間ですが、そこに「RelativeTimeFormat」というコンストラクタが追加されたようです。

Intlオブジェクトが持つコンストラクタは、Collator・DateTimeFormat・NumberFormat・PluralRulesなどがあります。

例えば、NumberFormatやDateTimeFormatは次のようにローカライズされた文字列を返してくれます。

let number = 123456.789;
let date = new Date(Date.UTC(2018, 9, 23, 0, 0, 0)); // -> Tue Oct 23 2018 09:00:00 GMT+0900 (日本標準時)
  
// NumberFormat
console.log(new Intl.NumberFormat('ja-JP', {
    style: 'currency',
    currency: 'JPY',
    currencyDisplay: 'code', // default
    useGrouping: true // default
}).format(number)); // > ¥123,457
  
console.log(new Intl.NumberFormat('ja-JP', {
    style: 'currency',
    currency: 'JPY',
    currencyDisplay: 'code', // default
    useGrouping: true // default
}).format(number)); // JPY 123,457
    
console.log(new Intl.NumberFormat('ja-JP', {
    style: 'currency',
    currency: 'EUR',
    currencyDisplay: 'name',
    useGrouping: true // default
}).format(number)); // > 123,456.79 ユーロ

// DateTimeFormat
console.log(new Intl.DateTimeFormat('ja-JP-u-ca-japanese').format(date)); // 30/10/23

console.log(new Intl.DateTimeFormat('ja-JP-u-ca-japanese', {
    weekday: 'long',
    year: 'numeric',
    month: 'long',
    day: 'numeric'
}).format(date)); // 30年10月23日水曜日

ご覧のように、指定した通りのローカライズされた返り値が戻ってきます。

ネイティブのJavaScriptが日本語を返してくるなんて、なんだか面白いですね。

Intl.RelativeTimeFormat

さて、今回追加されたRelativeTimeFormatは、単純に日時と時刻のフォーマットをローカライズして返すDateTimeFormatと異なり、受け取った時刻が「現在時刻から相対的にみてどうか」をローカライズした文字列を返してくれます。

例えば次のように(Chrome71以降、Canary版で確認)。

const RTF_EN = new Intl.RelativeTimeFormat('en'); // 英語でお願いします
const RTF_JA = new Intl.RelativeTimeFormat('ja'); // 日本語でお願いします

console.log(RTF_EN.format(10, 'second')); // > in 10 seconds
console.log(RTF_JA.format(10, 'second')); // > 10 秒後

console.log(RTF_EN.format(10, 'day')); // > in 10 days
console.log(RTF_JA.format(10, 'day')); // > 10 日後
console.log(RTF_EN.format(-10, 'day')); // > 10 days ago
console.log(RTF_JA.format(-10, 'day')); // > 10 日前

さらに、オプションで他のフォーマットも指定できます。

console.log(new Intl.RelativeTimeFormat('en', {
   style: 'long' // default
}).format(10, 'minute')); // > in 10 minutes

console.log(new Intl.RelativeTimeFormat('en', {
   style: 'short'
}).format(10, 'minute')); // > in 10 min.

console.log(new Intl.RelativeTimeFormat('ja', {
   numeric: 'always', // default
}).format(-1, 'year')); // > 1 年前

console.log(new Intl.RelativeTimeFormat('ja', {
   numeric: 'auto',
}).format(-1, 'year')); // > 昨年

console.log(new Intl.RelativeTimeFormat('ja', {
   numeric: 'always', // default
}).format(2, 'day')); // > 2 日後

console.log(new Intl.RelativeTimeFormat('ja', {
   numeric: 'auto',
}).format(2, 'day')); // > 明後日

「1日前」が「昨日」で返されたり、「1日後」が「明日」に返されたりするのは非常に面白いですね...!

このAPIに関する詳細は、Githubのtc39 / proposal-intl-relative-timeに掲載されています。

今はまだまだ実際に使っていくことは難しいですが、各ブラウザの実装が進めばライブラリを利用するよりも優れたパフォーマンスでこうした表現を実現できそうですね。ポリフィルの開発も進行中とのことなので、今後が楽しみです!