你的程序很有可能需要支持多种语言。其中包括对语言敏感的日期处理。一个广受欢迎的库Moment.js有助于实现这一目标,它的功能之一是国际化其源代码中包含对许多不同语言的本地化。现在这可能已经不是最好的方法了,因为我们有 ECMAScript 国际化 API。

国际化 API 旨在提供许多应用所需的语言敏感功能。它可以帮助你完成需要考虑语言的任务。浏览器将所有上述功能保留在 Intl 全局对象中,以避免发生命名冲突。

使用 DateTimeFormat 处理日期

Intl.DateTimeFormat 是一个构造函数,它允许我们进行语言敏感的日期处理。

const date = Date.now();
console.log(new Intl.DateTimeFormat('en-US').format(date)); //  8/30/2019
console.log(new Intl.DateTimeFormat('zh-ch').format(date)); //  2019/8/30

它不仅仅能够对日期中数字的规则进行格式化。通过提供额外的选项,还可以委托它翻译诸如周和月的字符串。

new Intl.DateTimeFormat(
  'zh-CN',
  { 
    weekday: 'short',
    month: 'long',
    day: '2-digit'
  }
).format(date)

输出:9月05日周四

通过选择传递给 DateTimeFormat 构造函数的内容,我们可以根据需要对结果进行调整。我们可以将工作日、时代和月份等属性设置为 *long*,short 或 *narrow*。年和日的数值可以设置为 *numeric*(例如,1)或 *2-digit*(例如,01)。月份可以表示为数字或字符串。

我们还可以指定是否要用 12 小时制。此处的默认设置取决于区域设置。

new Intl.DateTimeFormat(
  'zh-CN',
  { 
    day: '2-digit',
    month: 'long',
    year: 'numeric',
    hour: '2-digit',
    minute: '2-digit',
    hour12: true
  }
).format(date)

2019年9月05日 上午11:41

你还可以使用其他一些选项。有关完整列表,请转到MDN进行查看。

MDN Docs 还提到了 dateStyletimeStyle。那些属性目前处于阶段-3

相对时间格式

通过 ECMAScript 国际化 API,还可以根据所提供的语言处理相对时间的格式。

const formatter = new Intl.RelativeTimeFormat('en');
formatter.format(-1, 'day'); // 1 day ago

通过将 numeric 设置为 *auto*,我们也可以使用字符串值(如果可用的话)。

const formatter = new Intl.RelativeTimeFormat('en', { numeric: 'auto' });
formatter.format(-1, 'day'); // yesterday

通过将 style 设置为 long,short 或 narrow,可以配置消息的长度。

const formatter = new Intl.RelativeTimeFormat('en', { style: 'long' });
formatter.format(5, 'year'); // in 5 years
const formatter = new Intl.RelativeTimeFormat('en', { style: 'short' });
formatter.format(5, 'year'); // in 5 yr.

narrow 风格可能类似于某些地区的短风格。

用 Luxon 替换 Moment.js

你可能不愿意用原生 Date API 替换 Moment.js 库的许多有用功能。 Luxon 是一个有趣的选择。这个项目是由 Moment.js 维护者之一发起的,他们希望提供一些不同的 API,但不想在 Moment.js 中破坏任何东西。通过从头编写新库,他能够改变一些重要的事情。最重要的是 Luxon 使用了国际化 API。多亏了这一点,它不必像Moment 那样发布国际化文件。

我们还需要考虑浏览器支持。 Sine Luxon 专注于使用原生 API,但并非每个浏览器都能完整的支持。如果你对此担心的话,也可以考虑使用 polyfill。有关详细信息,请查看support matrix

国际化 API 其他很酷的功能

ECMAScript Internationalization API提供了其他有用的功能。其中之一是格式化列表的能力。

使用 Intl.ListFormat 格式化列表

const list = ['Cat', 'Dog', 'Rat'];
new Intl.ListFormat('en-GB', { style: 'long', type: 'conjunction' }).format(list);

Cat, Dog and Rat

const list = ['Cat', 'Dog', 'Rat'];
new Intl.ListFormat('en-US', { style: 'long', type: 'conjunction' }).format(list);

Cat, Dog, and Rat

注意,此 API 非常精确,甚至考虑到了相当微妙的差异,例如在英国和美国英语的 and 之前使用 serial comma

语言敏感的字符串比较

另一个很有用的功能是 collator 功能。在比较可能包含某些特定于语言的字符的字符串时会派上用场。 “ä”字母是一个很好的例子,因为它出现在德语和瑞典语的字母表中时的顺序可能不同。

new Intl.Collator('de').compare('ä', 'z'); // -1
new Intl.Collator('sv').compare('ä', 'z'); // 1

你可以把许多选项传递给 collator 函数。在 MDN docs 中可以找到一个列表

多个规则

通过使用 Intl.PluralRules,我们可以使用多个敏感格式。

例如,你可以用它来确定在指定语言中使用的复数形式。

new Intl.PluralRules('en-US').select(1); // one

函数返回“one”,所以正确的形式将是“one dog”。

new Intl.PluralRules('en-US').select(41); // other

函数返回“other”,所以正确的形式将是“fourty one dogs”。

另一个用例是找出序数

new Intl.PluralRules('en-US', { type: 'ordinal' }).select(41); // one

由于函数的结果为“one”,序数为:41

new Intl.PluralRules('en-US', { type: 'ordinal' }).select(32); // two

因为结果为“2”,序数为:32

格式化数字

格式编号中的规则因语言和国家地区而异。使用 Intl.NumberFormat 可以为给定国家/地区使用正确的格式。

const number = 1025.15;
new Intl.NumberFormat('en-US').format(number); // 1,025.15
new Intl.NumberFormat('ar-EG').format(number); // 输出奇怪的阿拉伯文

你可以使用许多不同的选项

const number = 125.5678;
new Intl.NumberFormat('zh-CN', { style: 'currency', currency: 'CNY' }).format(number); //¥1,025.15
new Intl.NumberFormat('en-GB', { style: 'currency', currency: 'GBP' }).format(number); // £125.57

总结

在本文中,我们了解了 ECMAScript Internationalization API 的基本功能。它可能在很多场合对你有用。我相信知道它能够提供什么是有必要,这样我们就不必再去寻找能够做同样事情的外部库。并非所有浏览器都支持上述功能,记得在使用钱先进行检查,在必要时可以使用polyfills