Skip to content

国际化支持

Node.js 具有许多特性,使编写国际化程序更加容易。其中一些特性包括:

Node.js 和底层的 V8 引擎使用 Unicode 国际组件 (ICU) 在原生 C/C++ 代码中实现这些特性。Node.js 默认提供完整的 ICU 数据集。但是,由于 ICU 数据文件的大小,在构建或运行 Node.js 时,提供了多个选项来定制 ICU 数据集。

Node.js 构建选项

在编译过程中,可以使用四个 configure 选项来控制 ICU 在 Node.js 中的使用方式。有关如何编译 Node.js 的更多详细信息,请参阅 BUILDING.md

  • --with-intl=none/--without-intl
  • --with-intl=system-icu
  • --with-intl=small-icu
  • --with-intl=full-icu (默认)

每个 configure 选项可用的 Node.js 和 JavaScript 功能概述:

功能nonesystem-icusmall-icufull-icu
String.prototype.normalize()无 (函数为无操作)全部全部全部
String.prototype.to*Case()全部全部全部全部
Intl无 (对象不存在)部分/全部 (取决于操作系统)部分 (仅限英语)全部
String.prototype.localeCompare()部分 (不区分区域设置)全部全部全部
String.prototype.toLocale*Case()部分 (不区分区域设置)全部全部全部
Number.prototype.toLocaleString()部分 (不区分区域设置)部分/全部 (取决于操作系统)部分 (仅限英语)全部
Date.prototype.toLocale*String()部分 (不区分区域设置)部分/全部 (取决于操作系统)部分 (仅限英语)全部
旧版 URL 解析器部分 (无 IDN 支持)全部全部全部
WHATWG URL 解析器部分 (无 IDN 支持)全部全部全部
require('node:buffer').transcode()无 (函数不存在)全部全部全部
REPL部分 (行编辑不准确)全部全部全部
require('node:util').TextDecoder部分 (支持基本编码)部分/全部 (取决于操作系统)部分 (仅限 Unicode)全部
RegExp Unicode 属性转义无 (无效 RegExp 错误)全部全部全部

“(不区分区域设置)” 表示该函数执行的操作与该函数的非 Locale 版本(如果存在)的操作相同。例如,在 none 模式下,Date.prototype.toLocaleString() 的操作与 Date.prototype.toString() 的操作相同。

禁用所有国际化功能 (none)

如果选择此选项,则 ICU 将被禁用,上面提到的大多数国际化功能在生成的 node 二进制文件中将不可用

使用预安装的 ICU 构建 (system-icu)

Node.js 可以链接到系统上已安装的 ICU 构建。事实上,大多数 Linux 发行版都已预装 ICU,此选项可以重用操作系统中其他组件使用的同一数据集。

仅需 ICU 库本身的功能,例如 String.prototype.normalize()WHATWG URL 解析器,在 system-icu 下完全受支持。此外还需要 ICU 本地化数据的特性,例如 Intl.DateTimeFormat 可能完全或部分受支持,具体取决于系统上安装的 ICU 数据的完整性。

嵌入有限的 ICU 数据 (small-icu)

此选项使生成的二进制文件静态链接 ICU 库,并在 node 可执行文件中包含 ICU 数据的一个子集(通常只有英语语言环境)。

仅需要 ICU 库本身的功能,例如 String.prototype.normalize()WHATWG URL 解析器,在 small-icu 下得到完全支持。此外还需要 ICU 语言环境数据的特性,例如 Intl.DateTimeFormat,通常只支持英语语言环境:

js
const january = new Date(9e8)
const english = new Intl.DateTimeFormat('en', { month: 'long' })
const spanish = new Intl.DateTimeFormat('es', { month: 'long' })

console.log(english.format(january))
// 打印 "January"
console.log(spanish.format(january))
// 在 small-icu 上打印 "M01" 或 "January",取决于用户的默认语言环境
// 应该打印 "enero"

此模式在功能和二进制大小之间取得了平衡。

运行时提供 ICU 数据

如果使用了 small-icu 选项,仍然可以在运行时提供额外的语言环境数据,以便 JS 方法能够用于所有 ICU 语言环境。假设数据文件存储在 /runtime/directory/with/dat/file,可以通过以下方式将其提供给 ICU:

  • --with-icu-default-data-dir 配置选项:这仅将默认数据目录路径嵌入到二进制文件中。实际数据文件将在运行时从此目录路径加载。
  • NODE_ICU_DATA 环境变量:
  • --icu-data-dir [/api/cli#--icu-data-dirfile] CLI 参数:

当指定多个选项时,--icu-data-dir CLI 参数具有最高优先级,然后是 NODE_ICU_DATA 环境变量,最后是 --with-icu-default-data-dir 配置选项。

ICU 能够自动查找和加载各种数据格式,但数据必须适合 ICU 版本,并且文件名正确。数据文件最常见的名称是 icudtX[bl].dat,其中 X 表示预期的 ICU 版本,bl 表示系统的字节序。如果无法从指定的目录读取预期的数据文件,Node.js 将加载失败。与当前 Node.js 版本对应的数据文件名可以通过以下方式计算:

js
;`icudt${process.versions.icu.split('.')[0]}${os.endianness()[0].toLowerCase()}.dat`

查看 ICU 用户指南中的 "ICU 数据" 文章,了解其他受支持的格式以及有关 ICU 数据的更多详细信息。

full-icu npm 模块可以通过检测正在运行的 node 可执行文件的 ICU 版本并下载相应的数据文件来极大地简化 ICU 数据安装。通过 npm i full-icu 安装模块后,数据文件将位于 ./node_modules/full-icu。然后可以将此路径传递给 NODE_ICU_DATA--icu-data-dir,如上所示,以启用完整的 Intl 支持。

嵌入整个 ICU (full-icu)

此选项使生成的二进制文件静态链接 ICU 并包含一整套 ICU 数据。以这种方式创建的二进制文件没有其他外部依赖项,并支持所有区域设置,但可能相当大。如果未传递 --with-intl 标志,则这是默认行为。官方二进制文件也是在这种模式下构建的。

检测国际化支持

要验证是否已启用 ICU(system-icusmall-icufull-icu),只需检查 Intl 是否存在即可:

js
const hasICU = typeof Intl === 'object'

或者,检查 process.versions.icu(仅在启用 ICU 时定义的属性)也可以:

js
const hasICU = typeof process.versions.icu === 'string'

要检查对非英语语言环境的支持(即 full-icusystem-icu),Intl.DateTimeFormat 可以是一个很好的区分因素:

js
const hasFullICU = (() => {
  try {
    const january = new Date(9e8)
    const spanish = new Intl.DateTimeFormat('es', { month: 'long' })
    return spanish.format(january) === 'enero'
  } catch (err) {
    return false
  }
})()

有关 Intl 支持的更详细测试,以下资源可能会有所帮助:

  • btest402:通常用于检查是否正确构建了具有 Intl 支持的 Node.js。
  • Test262:ECMAScript 的官方一致性测试套件包含一个专门用于 ECMA-402 的部分。