聊聊什么是 i18n?JavaScript 中的 i18n 基本概念

简介: 聊聊什么是 i18n?JavaScript 中的 i18n 基本概念

为什么需要 i18n?


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

在互联网呈指数级增长的新兴市场,存在大量非英语用户。如果你的网站可以在全球范围内进行翻译,那么你的潜在目标市场可能会增加 700%!

i18n 全称 Internationalization,也就是国际化的意思,因为单词太长,所以中间的 18 个字母被缩写为 18,再加上开头和结尾的字母,就组成了 i18n。

JavaScript i18n API 可以帮助我们对网站进行多语言翻译,让它们可以轻松适应使用不同语言用户的需求。

在本文中,我将介绍 i18n API 提供的各种方法,以及如何在实际项目中实现 i18n 来覆盖更广泛、更国际化的用户。


i18n 其实很难


从上面的描述中,i18n 看起来很容易,但是当你尝试去做的时候,又发现它并不简单。

基于拉丁语的语言可能表面上相似。比如,请求姓名、电子邮件和日期的表单翻译如下:

英语 name email date
西班牙语 nombre email fecha
法语 nom e-mail date
德语 name email datum

Gettext 是一种在类 Unix 计算机操作系统上实现国际化和本地化程序的系统,它已经存在了几十年,而且这个库可以用在大多数编程语言中,在 nodejs 也可用。

在最简单的场景下,我们可以使用某种形式的标记来实现它。比如下面这段 HTML 模板:


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

当用户将英语设置为主要语言时,NAME 会被动态替换。

但是只是最简单的案例,实际情况中会有很多问题:

  1. 同一种语言可以有不同的变体。在西班牙使用的西班牙语与在南美洲使用的西班牙语不同。
  2. 一种语言中的单词在其他语言中可能会更长。例如,“电子邮件”在俄语中翻译为“электронное письмо”。
  3. 文本并不总是从左到右。有些语言是从右向左书写的,例如阿拉伯语、希伯来语、库尔德语和意第绪语。也有一些语言是可以从上到下书写的,比如中文、韩文、日文和闽南文。


更糟糕的问题


除了上面提到的问题,还有更糟糕的情况。

当我们需要显示日期、时间、数字、货币或单位时,会出现进一步的复杂问题。

在英文中显示其日,通常是 12/03/24 这种格式。但是在其他语言中:

  • 使用 MDY 格式的美国居民会使用 3 December 2024。
  • 使用 DMY 格式的欧洲、南美和亚洲居民会使用 12 March 2024
  • 加拿大、中国、日本和匈牙利居民会使用 2012 年 3 月 24 日,他们选择了实用得多的 YMD 格式。

英文中的数字 1,000,在其他语言中:

  • 美国、英国、加拿大、中国和日本会以千为单位,表示为一千。
  • 西班牙、法国、德国和俄罗斯会表示为一个零点,其中数字的小数部分用逗号分隔。


JavaScript Intl API


其实很多人不知道,在 JavaScript 中存在 Intl 对象

在大多数现代浏览器和运行时中都实现了 ECMAScript 国际化 API,并且兼容性还不错。甚至在 IE11 中也有很多比较有用的方法。

对于较旧的浏览器,还有一个 polyfill 可以用。

Intl API 有点不寻常。它为日期、时间、数字和列表分别提供了几个构造函数,它们会接收一个语言环境和一个包含配置参数的可选对象。

比如,指定美国英语的 DateTime 对象:


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

这个对象可以被多次调用,传递一个 Date 实例,或者是一个 ES6 Temporal,如果它被支持的话。

format 是最常用也是最实用的方法。它的用法如下:


const valentinesDay = dateFormatter.format(new Date('2022-02-14')); 
// "2/14/2022" 
const starwarsDay = dateFormatter.format(new Date('2022-05-04')); 
// "5/4/2022"

你也可以这么用:


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

除了 format() 方法之外,某些对象还支持这些:

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


定义语言环境


所有 Intl 对象都需要一个语言环境参数。它是一个字符串,它可以表示以下含义:

  • 语言子标签
  • 脚本子标签(可选)
  • 地区(或国家)子标签(可选)
  • 一个或多个变体子标签(可选)
  • 一个或多个 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"

如果没定义区域设置,则使用设备的当前语言和区域设置。


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

I18n 的 API 其实比较多,在这里就不再多赘述,更加详细的内容可以参考 MDN 文档

我会在下一篇文章中详细聊聊更详细的业界解决方案。

下一篇:前端 i18n 最佳实践:在 React 中使用 i18next



相关文章
|
2月前
|
自然语言处理 JavaScript 前端开发
JavaScript中闭包:概念、用途与潜在问题
【4月更文挑战第22天】JavaScript中的闭包是函数及其相关词法环境的组合,允许访问外部作用域,常用于数据封装、回调函数和装饰器。然而,不恰当使用可能导致内存泄漏和性能下降。为避免问题,需及时解除引用,减少不必要的闭包,以及优化闭包使用。理解并慎用闭包是关键。
|
2月前
|
存储 JavaScript 前端开发
解释 JavaScript 中的作用域和作用域链的概念。
【4月更文挑战第4天】JavaScript作用域定义了变量和函数的可见范围,静态决定于编码时。每个函数作为对象拥有`scope`属性,关联运行期上下文集合。执行上下文在函数执行时创建,定义执行环境,每次调用函数都会生成独特上下文。作用域链是按层级组织的作用域集合,自内向外查找变量。变量查找遵循从当前执行上下文到全局上下文的顺序,若找不到则抛出异常。
28 6
|
2月前
|
JavaScript 前端开发 网络协议
​Node.js 教程(一) 基本概念与基本使用
​Node.js 教程(一) 基本概念与基本使用
|
2月前
|
JavaScript 前端开发 Java
Node.js专题讲解 第1期 概念篇
Node.js专题讲解 第1期 概念篇
29 0
|
1月前
|
设计模式 JavaScript 前端开发
在JavaScript中,继承是一个重要的概念,它允许我们基于现有的类(或构造函数)创建新的类
【6月更文挑战第15天】JavaScript继承促进代码复用与扩展,创建类层次结构,但过深的继承链导致复杂性增加,紧密耦合增加维护成本,单继承限制灵活性,方法覆盖可能隐藏父类功能,且可能影响性能。设计时需谨慎权衡并考虑使用组合等替代方案。
35 7
|
26天前
|
JSON JavaScript 前端开发
【JavaScript】JavaScript中的深拷贝与浅拷贝详解:基础概念与区别
JavaScript 中,理解数据拷贝的深浅至关重要。浅拷贝(如扩展运算符`...`、`Object.assign()`)仅复制对象第一层,共享内部引用,导致修改时产生意外联动。深拷贝(如自定义递归函数、`_.cloneDeep`或`JSON.parse(JSON.stringify())`)创建独立副本,确保数据隔离。选择哪种取决于性能、数据独立性和资源需求。深拷贝虽慢,但确保安全;浅拷贝快,但需小心引用共享。在面试中,理解这些概念及其应用场景是关键。
34 4
【JavaScript】JavaScript中的深拷贝与浅拷贝详解:基础概念与区别
|
20天前
|
JavaScript 前端开发
JavaScript函数核心概念:用于代码复用与管理。
【6月更文挑战第25天】JavaScript函数核心概念:用于代码复用与管理。示例包括定义(无参、有参、有返回值)与调用,参数按值传递。函数内修改参数不影响外部变量。
13 1
|
1月前
|
JavaScript 前端开发
深入解析JavaScript中的面向对象编程,包括对象的基本概念、创建对象的方法、继承机制以及面向对象编程的优势
【6月更文挑战第12天】本文探讨JavaScript中的面向对象编程,解释了对象的基本概念,如属性和方法,以及基于原型的结构。介绍了创建对象的四种方法:字面量、构造函数、Object.create()和ES6的class关键字。还阐述了继承机制,包括原型链和ES6的class继承,并强调了面向对象编程的代码复用和模块化优势。
27 0
|
2月前
|
设计模式 JavaScript 前端开发
在JavaScript中,继承是一个重要的概念
【5月更文挑战第9天】JavaScript继承有优点和缺点。优点包括代码复用、扩展性和层次结构清晰。缺点涉及深继承导致的复杂性、紧耦合、单一继承限制、隐藏父类方法以及可能的性能问题。在使用时需谨慎,并考虑其他设计模式。
25 2
|
2月前
|
JavaScript 前端开发
11.JavaScript 事件的概念以及绑定方法
11.JavaScript 事件的概念以及绑定方法