国际化支持#

Node.js 有许多功能可以更轻松地编写国际化程序。其中一些是:

Node.js 和底层的 V8 引擎使用国际化统一码组件 (ICU) 在本地 C/C++ 代码中实现这些功能。默认情况下,Node.js 提供完整的 ICU 数据集。但是,由于 ICU 数据文件的大小,提供了几个选项用于在构建或运行 Node.js 时自定义 ICU 数据集。

构建 Node.js 的选项#

为了控制 ICU 在 Node.js 中的使用方式,编译期间有四个 configure 选项可用。有关如何编译 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,此选项可以重用操作系统中其他组件所使用的同一组数据。

system-icu 模式下,仅需要 ICU 库本身的功能(例如 String.prototype.normalize()WHATWG URL 解析器)会得到完全支持。而额外需要 ICU 语言环境数据的功能(例如 Intl.DateTimeFormat可能会得到完全或部分支持,具体取决于系统上安装的 ICU 数据的完整性。

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

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

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

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));
// Prints "January"
console.log(spanish.format(january));
// Prints either "M01" or "January" on small-icu, depending on the user’s default locale
// Should print "enero" 

此模式在功能和二进制文件大小之间提供了一种平衡。

在运行时提供 ICU 数据#

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

  • --with-icu-default-data-dir 配置选项

    ./configure --with-icu-default-data-dir=/runtime/directory/with/dat/file --with-intl=small-icu 

    这只会将默认数据目录路径嵌入到二进制文件中。实际的数据文件将在运行时从此目录路径加载。

  • NODE_ICU_DATA 环境变量

    env NODE_ICU_DATA=/runtime/directory/with/dat/file node 
  • --icu-data-dir CLI 参数

    node --icu-data-dir=/runtime/directory/with/dat/file 

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

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

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

有关其他支持的格式和 ICU 数据的更多详细信息,请查阅 ICU 用户指南中的 "ICU Data" 文章。

full-icu npm 模块可以大大简化 ICU 数据的安装,它会检测正在运行的 node 可执行文件的 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 的存在即可:

const hasICU = typeof Intl === 'object'; 

或者,检查 process.versions.icu 也可以,这个属性仅在 ICU 启用时才会被定义:

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

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

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 的部分。