Intl.RelativeTimeFormat

发布于 · 标签:Intl

现代 Web 应用程序通常使用诸如“昨天”、“42 秒前”或“3 个月后”之类的短语,而不是完整的日期和时间戳。这种相对时间格式的值已经变得如此普遍,以至于几个流行的库实现了以本地化方式格式化它们的实用程序函数。(例如 Moment.jsGlobalizedate-fns。)

实现本地化相对时间格式化程序的一个问题是,您需要为要支持的每种语言提供一个习惯用语或短语列表(例如“昨天”或“上个季度”。Unicode CLDR 提供了这些数据,但要在 JavaScript 中使用它,必须将其嵌入并与其他库代码一起发布。不幸的是,这会增加此类库的包大小,从而对加载时间、解析/编译成本和内存消耗产生负面影响。

全新的 Intl.RelativeTimeFormat API 将此负担转移到 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'

您可能已经注意到,上面的格式化程序生成了字符串 '1 day ago' 而不是 'yesterday',以及略显尴尬的 'in 0 weeks' 而不是 'this week'。这是因为默认情况下,格式化程序在输出中使用数值。

要更改此行为,请将 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.jsGlobalizedate-fns 之类的库放弃了对硬编码 CLDR 数据库的依赖,转而使用本机相对时间格式化功能,从而提高了加载时间性能、解析和编译时间性能、运行时性能以及内存使用率。

Intl.RelativeTimeFormat 支持 #