2020-06-14 14:49:34 -07:00
|
|
|
|
# Internationalization support
|
2017-06-26 13:05:49 +08:00
|
|
|
|
|
2017-11-04 09:08:46 +01:00
|
|
|
|
<!--introduced_in=v8.2.0-->
|
2021-09-19 17:18:42 -07:00
|
|
|
|
|
2018-04-14 05:05:56 +03:00
|
|
|
|
<!-- type=misc -->
|
2017-11-04 09:08:46 +01:00
|
|
|
|
|
2017-06-26 13:05:49 +08:00
|
|
|
|
Node.js has many features that make it easier to write internationalized
|
|
|
|
|
programs. Some of them are:
|
|
|
|
|
|
2019-09-13 00:22:29 -04:00
|
|
|
|
* Locale-sensitive or Unicode-aware functions in the [ECMAScript Language
|
2017-06-26 13:05:49 +08:00
|
|
|
|
Specification][ECMA-262]:
|
2019-09-13 00:22:29 -04:00
|
|
|
|
* [`String.prototype.normalize()`][]
|
|
|
|
|
* [`String.prototype.toLowerCase()`][]
|
|
|
|
|
* [`String.prototype.toUpperCase()`][]
|
|
|
|
|
* All functionality described in the [ECMAScript Internationalization API
|
2017-06-26 13:05:49 +08:00
|
|
|
|
Specification][ECMA-402] (aka ECMA-402):
|
2019-09-13 00:22:29 -04:00
|
|
|
|
* [`Intl`][] object
|
|
|
|
|
* Locale-sensitive methods like [`String.prototype.localeCompare()`][] and
|
2017-06-26 13:05:49 +08:00
|
|
|
|
[`Date.prototype.toLocaleString()`][]
|
2019-09-13 00:22:29 -04:00
|
|
|
|
* The [WHATWG URL parser][]'s [internationalized domain names][] (IDNs) support
|
2022-04-20 10:23:41 +02:00
|
|
|
|
* [`require('node:buffer').transcode()`][]
|
2019-09-13 00:22:29 -04:00
|
|
|
|
* More accurate [REPL][] line editing
|
2022-04-20 10:23:41 +02:00
|
|
|
|
* [`require('node:util').TextDecoder`][]
|
2019-09-13 00:22:29 -04:00
|
|
|
|
* [`RegExp` Unicode Property Escapes][]
|
2017-06-26 13:05:49 +08:00
|
|
|
|
|
2021-03-26 22:03:11 -07:00
|
|
|
|
Node.js and the underlying V8 engine use
|
|
|
|
|
[International Components for Unicode (ICU)][ICU] to implement these features
|
2019-09-30 11:17:49 -07:00
|
|
|
|
in native C/C++ code. The full ICU data set is provided by Node.js by default.
|
|
|
|
|
However, due to the size of the ICU data file, several
|
|
|
|
|
options are provided for customizing the ICU data set either when
|
2017-06-26 13:05:49 +08:00
|
|
|
|
building or running Node.js.
|
|
|
|
|
|
|
|
|
|
## Options for building Node.js
|
|
|
|
|
|
|
|
|
|
To control how ICU is used in Node.js, four `configure` options are available
|
|
|
|
|
during compilation. Additional details on how to compile Node.js are documented
|
|
|
|
|
in [BUILDING.md][].
|
|
|
|
|
|
2019-09-13 00:22:29 -04:00
|
|
|
|
* `--with-intl=none`/`--without-intl`
|
|
|
|
|
* `--with-intl=system-icu`
|
2019-09-30 11:17:49 -07:00
|
|
|
|
* `--with-intl=small-icu`
|
|
|
|
|
* `--with-intl=full-icu` (default)
|
2017-06-26 13:05:49 +08:00
|
|
|
|
|
|
|
|
|
An overview of available Node.js and JavaScript features for each `configure`
|
|
|
|
|
option:
|
|
|
|
|
|
2022-04-20 10:23:41 +02:00
|
|
|
|
| Feature | `none` | `system-icu` | `small-icu` | `full-icu` |
|
|
|
|
|
| ---------------------------------------- | --------------------------------- | ---------------------------- | ---------------------- | ---------- |
|
|
|
|
|
| [`String.prototype.normalize()`][] | none (function is no-op) | full | full | full |
|
|
|
|
|
| `String.prototype.to*Case()` | full | full | full | full |
|
|
|
|
|
| [`Intl`][] | none (object does not exist) | partial/full (depends on OS) | partial (English-only) | full |
|
|
|
|
|
| [`String.prototype.localeCompare()`][] | partial (not locale-aware) | full | full | full |
|
|
|
|
|
| `String.prototype.toLocale*Case()` | partial (not locale-aware) | full | full | full |
|
|
|
|
|
| [`Number.prototype.toLocaleString()`][] | partial (not locale-aware) | partial/full (depends on OS) | partial (English-only) | full |
|
|
|
|
|
| `Date.prototype.toLocale*String()` | partial (not locale-aware) | partial/full (depends on OS) | partial (English-only) | full |
|
|
|
|
|
| [Legacy URL Parser][] | partial (no IDN support) | full | full | full |
|
|
|
|
|
| [WHATWG URL Parser][] | partial (no IDN support) | full | full | full |
|
|
|
|
|
| [`require('node:buffer').transcode()`][] | none (function does not exist) | full | full | full |
|
|
|
|
|
| [REPL][] | partial (inaccurate line editing) | full | full | full |
|
|
|
|
|
| [`require('node:util').TextDecoder`][] | partial (basic encodings support) | partial/full (depends on OS) | partial (Unicode-only) | full |
|
|
|
|
|
| [`RegExp` Unicode Property Escapes][] | none (invalid `RegExp` error) | full | full | full |
|
2017-06-26 13:05:49 +08:00
|
|
|
|
|
2018-02-05 21:55:16 -08:00
|
|
|
|
The "(not locale-aware)" designation denotes that the function carries out its
|
|
|
|
|
operation just like the non-`Locale` version of the function, if one
|
2017-06-26 13:05:49 +08:00
|
|
|
|
exists. For example, under `none` mode, `Date.prototype.toLocaleString()`'s
|
|
|
|
|
operation is identical to that of `Date.prototype.toString()`.
|
|
|
|
|
|
|
|
|
|
### Disable all internationalization features (`none`)
|
|
|
|
|
|
2019-09-30 11:17:49 -07:00
|
|
|
|
If this option is chosen, ICU is disabled and most internationalization
|
|
|
|
|
features mentioned above will be **unavailable** in the resulting `node` binary.
|
2017-06-26 13:05:49 +08:00
|
|
|
|
|
|
|
|
|
### Build with a pre-installed ICU (`system-icu`)
|
|
|
|
|
|
|
|
|
|
Node.js can link against an ICU build already installed on the system. In fact,
|
|
|
|
|
most Linux distributions already come with ICU installed, and this option would
|
|
|
|
|
make it possible to reuse the same set of data used by other components in the
|
|
|
|
|
OS.
|
|
|
|
|
|
|
|
|
|
Functionalities that only require the ICU library itself, such as
|
|
|
|
|
[`String.prototype.normalize()`][] and the [WHATWG URL parser][], are fully
|
|
|
|
|
supported under `system-icu`. Features that require ICU locale data in
|
2021-10-10 21:55:04 -07:00
|
|
|
|
addition, such as [`Intl.DateTimeFormat`][] _may_ be fully or partially
|
2017-06-26 13:05:49 +08:00
|
|
|
|
supported, depending on the completeness of the ICU data installed on the
|
|
|
|
|
system.
|
|
|
|
|
|
|
|
|
|
### Embed a limited set of ICU data (`small-icu`)
|
|
|
|
|
|
|
|
|
|
This option makes the resulting binary link against the ICU library statically,
|
|
|
|
|
and includes a subset of ICU data (typically only the English locale) within
|
|
|
|
|
the `node` executable.
|
|
|
|
|
|
|
|
|
|
Functionalities that only require the ICU library itself, such as
|
|
|
|
|
[`String.prototype.normalize()`][] and the [WHATWG URL parser][], are fully
|
|
|
|
|
supported under `small-icu`. Features that require ICU locale data in addition,
|
|
|
|
|
such as [`Intl.DateTimeFormat`][], generally only work with the English locale:
|
|
|
|
|
|
|
|
|
|
```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));
|
|
|
|
|
// Prints "January"
|
|
|
|
|
console.log(spanish.format(january));
|
2022-06-27 12:51:07 -04:00
|
|
|
|
// Prints either "M01" or "January" on small-icu, depending on the user’s default locale
|
2017-06-26 13:05:49 +08:00
|
|
|
|
// Should print "enero"
|
|
|
|
|
```
|
|
|
|
|
|
2019-09-30 11:17:49 -07:00
|
|
|
|
This mode provides a balance between features and binary size.
|
2017-06-26 13:05:49 +08:00
|
|
|
|
|
|
|
|
|
#### Providing ICU data at runtime
|
|
|
|
|
|
|
|
|
|
If the `small-icu` option is used, one can still provide additional locale data
|
|
|
|
|
at runtime so that the JS methods would work for all ICU locales. Assuming the
|
2023-09-15 15:25:36 +02:00
|
|
|
|
data file is stored at `/runtime/directory/with/dat/file`, it can be made
|
|
|
|
|
available to ICU through either:
|
|
|
|
|
|
|
|
|
|
* The `--with-icu-default-data-dir` configure option:
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
./configure --with-icu-default-data-dir=/runtime/directory/with/dat/file --with-intl=small-icu
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
This only embeds the default data directory path into the binary.
|
|
|
|
|
The actual data file is going to be loaded at runtime from this directory
|
|
|
|
|
path.
|
2017-06-26 13:05:49 +08:00
|
|
|
|
|
2017-08-22 18:27:14 +10:00
|
|
|
|
* The [`NODE_ICU_DATA`][] environment variable:
|
2017-06-26 13:05:49 +08:00
|
|
|
|
|
2020-05-20 11:10:22 -04:00
|
|
|
|
```bash
|
2023-09-15 15:25:36 +02:00
|
|
|
|
env NODE_ICU_DATA=/runtime/directory/with/dat/file node
|
2017-06-26 13:05:49 +08:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
* The [`--icu-data-dir`][] CLI parameter:
|
|
|
|
|
|
2020-05-20 11:10:22 -04:00
|
|
|
|
```bash
|
2023-09-15 15:25:36 +02:00
|
|
|
|
node --icu-data-dir=/runtime/directory/with/dat/file
|
2017-06-26 13:05:49 +08:00
|
|
|
|
```
|
|
|
|
|
|
2023-09-15 15:25:36 +02:00
|
|
|
|
When more than one of them is specified, the `--icu-data-dir` CLI parameter has
|
|
|
|
|
the highest precedence, then the `NODE_ICU_DATA` environment variable, then
|
|
|
|
|
the `--with-icu-default-data-dir` configure option.
|
2017-06-26 13:05:49 +08:00
|
|
|
|
|
|
|
|
|
ICU is able to automatically find and load a variety of data formats, but the
|
|
|
|
|
data must be appropriate for the ICU version, and the file correctly named.
|
2023-09-15 15:25:36 +02:00
|
|
|
|
The most common name for the data file is `icudtX[bl].dat`, where `X` denotes
|
2017-06-26 13:05:49 +08:00
|
|
|
|
the intended ICU version, and `b` or `l` indicates the system's endianness.
|
2023-09-15 15:25:36 +02:00
|
|
|
|
Node.js would fail to load if the expected data file cannot be read from the
|
|
|
|
|
specified directory. The name of the data file corresponding to the current
|
|
|
|
|
Node.js version can be computed with:
|
|
|
|
|
|
|
|
|
|
```js
|
|
|
|
|
`icudt${process.versions.icu.split('.')[0]}${os.endianness()[0].toLowerCase()}.dat`;
|
|
|
|
|
```
|
|
|
|
|
|
2017-06-26 13:05:49 +08:00
|
|
|
|
Check ["ICU Data"][] article in the ICU User Guide for other supported formats
|
|
|
|
|
and more details on ICU data in general.
|
|
|
|
|
|
|
|
|
|
The [full-icu][] npm module can greatly simplify ICU data installation by
|
|
|
|
|
detecting the ICU version of the running `node` executable and downloading the
|
|
|
|
|
appropriate data file. After installing the module through `npm i full-icu`,
|
|
|
|
|
the data file will be available at `./node_modules/full-icu`. This path can be
|
|
|
|
|
then passed either to `NODE_ICU_DATA` or `--icu-data-dir` as shown above to
|
|
|
|
|
enable full `Intl` support.
|
|
|
|
|
|
|
|
|
|
### Embed the entire ICU (`full-icu`)
|
|
|
|
|
|
|
|
|
|
This option makes the resulting binary link against ICU statically and include
|
|
|
|
|
a full set of ICU data. A binary created this way has no further external
|
2019-09-30 11:17:49 -07:00
|
|
|
|
dependencies and supports all locales, but might be rather large. This is
|
|
|
|
|
the default behavior if no `--with-intl` flag is passed. The official binaries
|
|
|
|
|
are also built in this mode.
|
2017-06-26 13:05:49 +08:00
|
|
|
|
|
|
|
|
|
## Detecting internationalization support
|
|
|
|
|
|
|
|
|
|
To verify that ICU is enabled at all (`system-icu`, `small-icu`, or
|
|
|
|
|
`full-icu`), simply checking the existence of `Intl` should suffice:
|
|
|
|
|
|
|
|
|
|
```js
|
|
|
|
|
const hasICU = typeof Intl === 'object';
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Alternatively, checking for `process.versions.icu`, a property defined only
|
|
|
|
|
when ICU is enabled, works too:
|
|
|
|
|
|
|
|
|
|
```js
|
|
|
|
|
const hasICU = typeof process.versions.icu === 'string';
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
To check for support for a non-English locale (i.e. `full-icu` or
|
|
|
|
|
`system-icu`), [`Intl.DateTimeFormat`][] can be a good distinguishing factor:
|
|
|
|
|
|
|
|
|
|
```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;
|
|
|
|
|
}
|
|
|
|
|
})();
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
For more verbose tests for `Intl` support, the following resources may be found
|
|
|
|
|
to be helpful:
|
|
|
|
|
|
2019-09-13 00:22:29 -04:00
|
|
|
|
* [btest402][]: Generally used to check whether Node.js with `Intl` support is
|
2017-06-26 13:05:49 +08:00
|
|
|
|
built correctly.
|
2019-09-13 00:22:29 -04:00
|
|
|
|
* [Test262][]: ECMAScript's official conformance test suite includes a section
|
2017-06-26 13:05:49 +08:00
|
|
|
|
dedicated to ECMA-402.
|
|
|
|
|
|
|
|
|
|
["ICU Data"]: http://userguide.icu-project.org/icudata
|
2021-02-18 12:29:37 -05:00
|
|
|
|
[BUILDING.md]: https://github.com/nodejs/node/blob/HEAD/BUILDING.md
|
2020-09-17 18:53:37 +02:00
|
|
|
|
[ECMA-262]: https://tc39.github.io/ecma262/
|
|
|
|
|
[ECMA-402]: https://tc39.github.io/ecma402/
|
|
|
|
|
[ICU]: http://site.icu-project.org/
|
2021-07-04 20:39:17 -07:00
|
|
|
|
[Legacy URL parser]: url.md#legacy-url-api
|
|
|
|
|
[REPL]: repl.md#repl
|
2021-02-18 12:29:37 -05:00
|
|
|
|
[Test262]: https://github.com/tc39/test262/tree/HEAD/test/intl402
|
2021-07-04 20:39:17 -07:00
|
|
|
|
[WHATWG URL parser]: url.md#the-whatwg-url-api
|
|
|
|
|
[`--icu-data-dir`]: cli.md#--icu-data-dirfile
|
2018-02-07 23:55:37 +02:00
|
|
|
|
[`Date.prototype.toLocaleString()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toLocaleString
|
2017-06-26 13:05:49 +08:00
|
|
|
|
[`Intl.DateTimeFormat`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DateTimeFormat
|
2018-11-27 11:49:21 -08:00
|
|
|
|
[`Intl`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl
|
2021-07-04 20:39:17 -07:00
|
|
|
|
[`NODE_ICU_DATA`]: cli.md#node_icu_datafile
|
2018-02-07 23:55:37 +02:00
|
|
|
|
[`Number.prototype.toLocaleString()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toLocaleString
|
2018-04-29 20:46:41 +03:00
|
|
|
|
[`RegExp` Unicode Property Escapes]: https://github.com/tc39/proposal-regexp-unicode-property-escapes
|
2018-02-07 23:55:37 +02:00
|
|
|
|
[`String.prototype.localeCompare()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/localeCompare
|
|
|
|
|
[`String.prototype.normalize()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/normalize
|
|
|
|
|
[`String.prototype.toLowerCase()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/toLowerCase
|
|
|
|
|
[`String.prototype.toUpperCase()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/toUpperCase
|
2022-04-20 10:23:41 +02:00
|
|
|
|
[`require('node:buffer').transcode()`]: buffer.md#buffertranscodesource-fromenc-toenc
|
|
|
|
|
[`require('node:util').TextDecoder`]: util.md#class-utiltextdecoder
|
2017-07-26 00:02:37 +03:00
|
|
|
|
[btest402]: https://github.com/srl295/btest402
|
|
|
|
|
[full-icu]: https://www.npmjs.com/package/full-icu
|
|
|
|
|
[internationalized domain names]: https://en.wikipedia.org/wiki/Internationalized_domain_name
|