原文:The Intl.RelativeTimeFormat API
做者:Mathias Bynens(@mathias)html
現代 Web 應用程序一般使用「昨天」,「42秒前」或「3個月」之類的短語,而不是完整的日期和時間戳。這種相對時間格式已經變得很是廣泛,以致於幾個流行的庫都實現了本地化格式化的函數。(例如 Moment.js,Globalize 和 date-fns。)git
實現本地化相對時間格式化的一個問題是,您須要爲每種語言提供習慣詞或短語列表(例如「昨天」或「上一季度」)。Unicode CLDR 提供了此數據,但要在 JavaScript 中使用它,必須將其嵌入到庫代碼中一塊兒提供。遺憾的是,這無疑會增長這些庫的包大小,這會影響到腳本的加載時間、解析/編譯成本和內存消耗。github
全新的 Intl.RelativeTimeFormat
API 將此負擔轉移到了 JavaScript 引擎,JavaScript 引擎能夠提供語言環境數據並使其直接供 JavaScript 開發人員使用。 Intl.RelativeTimeFormat
在不犧牲性能的狀況下實現相對時間的本地化格式化。web
如下示例展現瞭如何使用英語建立相對時間格式化程序。數據庫
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 語言標記,或者是一個包括多個語言標記的數組。api
如下是使用其餘語言(漢語簡體中文)的示例:(譯註:原文是西班牙語)數組
const rtf = new Intl.RelativeTimeFormat('zh'); // 或 'zh-Hans-CN'
rtf.format(3.14, 'second');
// → '3.14秒鐘後'
rtf.format(-15, 'minute');
// → '15分鐘前'
rtf.format(8, 'hour');
// → '8小時後'
rtf.format(-2, 'day');
// → '2天前'
rtf.format(3, 'week');
// → '3周後'
rtf.format(-5, 'month');
// → '5個月前'
rtf.format(2, 'quarter');
// → '2個季度後'
rtf.format(-42, 'year');
// → '42年前'
複製代碼
此外,Intl.RelativeTimeFormat
構造函數還接受一個可選 options
參數,該參數能夠對輸出進行細粒度控制。爲了說明靈活性,讓咱們根據默認設置查看更多輸出:ecmascript
// 建立一個簡體中文相對時間格式化示例,使用默認設置。
// 在這個例子中,咱們將默認參數顯式的傳進去
const rtf = new Intl.RelativeTimeFormat('zh', {
localeMatcher: 'best fit', // 其餘值: 'lookup'
style: 'long', // 其餘值: 'short' 或 'narrow'
numeric: 'always', // 其餘值: 'auto'
});
rtf.format(-1, 'day');
// → '1天前'
rtf.format(0, 'day');
// → '0天后'
rtf.format(1, 'day');
// → '1天后'
rtf.format(-1, 'week');
// → '1周前'
rtf.format(0, 'week');
// → '0周後'
rtf.format(1, 'week');
// → '1周後'
複製代碼
您可能已經注意到上面的格式化程序生成了字符串 '1天前'
而不是 '昨天'
,還有顯得比較弱智的 '0周後'
而不是 '本週'
。發生這種狀況是由於默認狀況下,格式化程序使用數值進行輸出。ide
要更改此行爲,請將 numeric
選項設置爲 'auto'
(默認值是 'always'
):函數
const rtf = new Intl.RelativeTimeFormat('zh', { numeric: 'auto' });
rtf.format(-1, 'day');
// → '昨天'
rtf.format(-2, 'day');
// → '前天'
rtf.format(0, 'day');
// → '今天'
rtf.format(1, 'day');
// → '明天'
rtf.format(2, 'day');
// → '後天'
rtf.format(-1, 'week');
// → '上週'
rtf.format(0, 'week');
// → '本週'
rtf.format(1, 'week');
// → '下週'
複製代碼
Analogous to other Intl
classes, Intl.RelativeTimeFormat
has a formatToParts
method in addition to the format method. Although format covers the most common use case, formatToParts
can be helpful if you need access to the individual parts of the generated output:
與其餘 Intl
類同樣,Intl.RelativeTimeFormat
除了 format
方法以外,還有一個 formatToParts
方法。雖然 format
涵蓋了最多見的用例,但若是您須要訪問生成的輸出的各個部分,formatToParts
會頗有幫助:
const rtf = new Intl.RelativeTimeFormat('zh', { numeric: 'auto' });
rtf.format(-1, 'day');
// → '昨天'
rtf.formatToParts(-1, 'day');
// → [{ type: 'literal', value: '昨天' }]
rtf.format(3, 'week');
// → '3周後'
rtf.formatToParts(3, 'week');
// → [
// { type: 'integer', value: '3', unit: 'week' },
// { type: 'literal', value: '周後' }
// ]
複製代碼
有關其他選項及其行爲的詳細信息,請參閱 API docs in the proposal repository.
Intl.RelativeTimeFormat
默認狀況下在 V8 v7.1.179 和 Chrome 71 中可用。隨着此 API 變得更加普遍可用,您將發現諸如 Moment.js、Globalize、date-fns 之類的庫,會從代碼庫中移除對硬編碼 CLDR 數據庫的依賴性,而使用本機相對時間格式化功能,從而提升加載時性能、分析和編譯時性能、運行時性能和內存使用。