原文: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 数据库的依赖性,而使用本机相对时间格式化功能,从而提升加载时性能、分析和编译时性能、运行时性能和内存使用。