什么是JavaScript国际化API(I18n)?

648 阅读5分钟

英语是世界上使用最广泛的语言,但只有七分之一的人会说英语。它是3.79亿人的第一(母语)语言,但有9.17亿人说汉语,4.6亿人说西班牙语,3.41亿人说印度语。

许多非英语使用者居住在互联网指数增长的新兴市场。如果你的网络应用能够被全球翻译,你的潜在目标市场可能会增加700%!

JavaScript国际化API(也称为i18n)允许你以这样的方式设计网页和应用程序,使它们能够轻松地适应支持讲不同语言的用户的需求。

在这篇文章中,我们将看看该API提供的各种方法,以及你如何在你的代码中实现它们,以达到更广泛、更国际化的受众。

国际化(I18n)可能很棘手

国际化看起来很容易......直到你尝试去做

基于拉丁语的语言在表面上可能是相似的。例如,一个要求提供姓名、电子邮件和日期的表格可以这样翻译。

  • 西班牙文:nombre, email, fecha
  • 法语:姓名、电子邮件、日期
  • 德文:姓名、电子邮件、数据

Gettext国际化和本地化系统已经存在了几十年,而且大多数编程语言都有库可用。

在更简单的情况下,你可以使用某种形式的标记化。例如,以一个包含以下内容的HTML模板为例。

<label for="name">{{ NAME }}</label>

当用户将英语设置为其主要语言时,这将被动态地替换为*"姓名"*。不幸的是,对于你的用户界面来说,这就是问题的开始。

  1. 同一种语言可以有不同的变化。在西班牙说的西班牙语与在南美说的西班牙语不一样。
  2. 一种语言的单词在其他语言中可能要长得多。例如,"email "在俄语中被翻译成 "электронное письмо"。
  3. 文本并不总是从左到右的。有些是从右到左写的--如阿拉伯语、希伯来语、库尔德语和意第绪语。其他语言可以从上到下书写,如中文、韩文、日文和台湾话。

许多问题可以通过尽量减少文本和采用CSS属性来解决,如 direction, writing-mode逻辑尺寸进行布局。

术语混乱

当你的应用程序需要显示日期、时间、数字、货币或单位时,会出现进一步的混乱。

考虑一个显示为 "12/03/24 "的日期。它将被理解为。

  • 对于使用MDY格式的美国居民来说是 "2024年12月3日"。
  • 使用DMY格式的欧洲、南美和亚洲居民会读作 "2024年3月12日",以及
  • 加拿大、中国、日本和匈牙利居民使用 "2012年3月24日",他们选择更实用的YMD格式。

(请注意,日期分隔符的斜线在所有语言中并不常见!)。

数字 "1,000 "将被理解为。

  • 美国、英国、加拿大、中国和日本的人认为是 "一千",而中国的人认为是 "一(零点)"。
  • 而在西班牙、法国、德国和俄罗斯,如果数字的小数点被逗号隔开,则读作 "一(零点)"。

仅就英语而言,情况甚至会很复杂。术语 "1,000米 "是指

  • 对美国居民来说是1千米(或0.62英里)。
  • 对英国、加拿大和澳大利亚的人来说,是一千个测量仪器的集合!

JavaScript国际API

鲜为人知的JavaScriptIntl 对象在大多数现代浏览器和运行系统中实现了ECMAScript的国际化API。一般来说,支持度很高,甚至IE11也有很多比较有用的方法。对于旧的浏览器,有一个polyfill,可以像这样检测API。

if (window.Intl) {
  // Intl supported
}

该API稍微有点不寻常。它为日期、时间、数字和列表提供了几个对象构造器,这些构造器被传递给一个locale和一个包含配置参数的可选对象。例如,这里有一个DateTime 对象,指定为美国英语。

const dateFormatter = new Intl.DateTimeFormat('en-US');

这个对象可以被多次用来调用各种方法,这些方法被传递一个Date() 值(或者在可用的情况下传递一个ES6 Temporal)。format 方法通常是最实用的选择。比如说。

const valentinesDay = dateFormatter.format( new Date('2022-02-14') );
// returns US format "2/14/2022"

const starwarsDay = dateFormatter.format( new Date('2022-05-04') );
// returns US format "5/4/2022"

另外,你可以创建Intl 对象并在一行代码中运行一个方法。

const starwarsDay = new Intl.DateTimeFormat('en-US').format( new Date('2022-05-04') );

除了format() 方法外,有些对象还支持这些。

  • formatToParts(): 返回一个包含格式化字符串的对象数组,例如{ type: 'weekday', value: 'Monday' }
  • resolvedOptions():返回一个新的对象,其属性反映了所使用的地区和格式化选项,如:dateFormatter.resolvedOptions().locale

定义地域性

所有Intl 对象都需要一个locale参数。这是一个字符串,用于识别。

  • 一个语言子标签
  • 脚本子标签(可选)
  • 一个地区(或国家)子标签(可选)。
  • 一个或多个变体子标签(可选)
  • 一个或多个BCP 47扩展序列(可选)
  • 一个私人使用的扩展序列(可选)

语言和地区通常就足够了。例如,"en-US","fr-FR", 等等。

除了使用字符串之外,一个 Intl.locale对象可以被用来构建地域,比如12小时时间格式的美国英语。

const us = new Intl.Locale('en', {
  region: 'US', hourCycle: 'h12', calendar: 'gregory'
});

这可以在另一个Intl 构造函数中使用。比如说。

new Intl.DateTimeFormat(us, { timeStyle: 'medium' })
  .format( new Date('2022-05-04T13:00:00') );

// "1:00:00 PM"

如果没有定义locale,则使用设备当前的语言和地区设置。举例来说。

new Intl.DateTimeFormat().format( new Date('2022-05-04') );

在有美国设置的设备上返回"5/4/2022" ,在有英国设置的设备上返回"04/05/2022"

继续阅读What is the JavaScript Internationalization API (I18n)?onSitePoint.