• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Internationalization support
2
3<!--introduced_in=v8.2.0-->
4
5<!-- type=misc -->
6
7Node.js has many features that make it easier to write internationalized
8programs. Some of them are:
9
10* Locale-sensitive or Unicode-aware functions in the [ECMAScript Language
11  Specification][ECMA-262]:
12  * [`String.prototype.normalize()`][]
13  * [`String.prototype.toLowerCase()`][]
14  * [`String.prototype.toUpperCase()`][]
15* All functionality described in the [ECMAScript Internationalization API
16  Specification][ECMA-402] (aka ECMA-402):
17  * [`Intl`][] object
18  * Locale-sensitive methods like [`String.prototype.localeCompare()`][] and
19    [`Date.prototype.toLocaleString()`][]
20* The [WHATWG URL parser][]'s [internationalized domain names][] (IDNs) support
21* [`require('node:buffer').transcode()`][]
22* More accurate [REPL][] line editing
23* [`require('node:util').TextDecoder`][]
24* [`RegExp` Unicode Property Escapes][]
25
26Node.js and the underlying V8 engine use
27[International Components for Unicode (ICU)][ICU] to implement these features
28in native C/C++ code. The full ICU data set is provided by Node.js by default.
29However, due to the size of the ICU data file, several
30options are provided for customizing the ICU data set either when
31building or running Node.js.
32
33## Options for building Node.js
34
35To control how ICU is used in Node.js, four `configure` options are available
36during compilation. Additional details on how to compile Node.js are documented
37in [BUILDING.md][].
38
39* `--with-intl=none`/`--without-intl`
40* `--with-intl=system-icu`
41* `--with-intl=small-icu`
42* `--with-intl=full-icu` (default)
43
44An overview of available Node.js and JavaScript features for each `configure`
45option:
46
47| Feature                                  | `none`                            | `system-icu`                 | `small-icu`            | `full-icu` |
48| ---------------------------------------- | --------------------------------- | ---------------------------- | ---------------------- | ---------- |
49| [`String.prototype.normalize()`][]       | none (function is no-op)          | full                         | full                   | full       |
50| `String.prototype.to*Case()`             | full                              | full                         | full                   | full       |
51| [`Intl`][]                               | none (object does not exist)      | partial/full (depends on OS) | partial (English-only) | full       |
52| [`String.prototype.localeCompare()`][]   | partial (not locale-aware)        | full                         | full                   | full       |
53| `String.prototype.toLocale*Case()`       | partial (not locale-aware)        | full                         | full                   | full       |
54| [`Number.prototype.toLocaleString()`][]  | partial (not locale-aware)        | partial/full (depends on OS) | partial (English-only) | full       |
55| `Date.prototype.toLocale*String()`       | partial (not locale-aware)        | partial/full (depends on OS) | partial (English-only) | full       |
56| [Legacy URL Parser][]                    | partial (no IDN support)          | full                         | full                   | full       |
57| [WHATWG URL Parser][]                    | partial (no IDN support)          | full                         | full                   | full       |
58| [`require('node:buffer').transcode()`][] | none (function does not exist)    | full                         | full                   | full       |
59| [REPL][]                                 | partial (inaccurate line editing) | full                         | full                   | full       |
60| [`require('node:util').TextDecoder`][]   | partial (basic encodings support) | partial/full (depends on OS) | partial (Unicode-only) | full       |
61| [`RegExp` Unicode Property Escapes][]    | none (invalid `RegExp` error)     | full                         | full                   | full       |
62
63The "(not locale-aware)" designation denotes that the function carries out its
64operation just like the non-`Locale` version of the function, if one
65exists. For example, under `none` mode, `Date.prototype.toLocaleString()`'s
66operation is identical to that of `Date.prototype.toString()`.
67
68### Disable all internationalization features (`none`)
69
70If this option is chosen, ICU is disabled and most internationalization
71features mentioned above will be **unavailable** in the resulting `node` binary.
72
73### Build with a pre-installed ICU (`system-icu`)
74
75Node.js can link against an ICU build already installed on the system. In fact,
76most Linux distributions already come with ICU installed, and this option would
77make it possible to reuse the same set of data used by other components in the
78OS.
79
80Functionalities that only require the ICU library itself, such as
81[`String.prototype.normalize()`][] and the [WHATWG URL parser][], are fully
82supported under `system-icu`. Features that require ICU locale data in
83addition, such as [`Intl.DateTimeFormat`][] _may_ be fully or partially
84supported, depending on the completeness of the ICU data installed on the
85system.
86
87### Embed a limited set of ICU data (`small-icu`)
88
89This option makes the resulting binary link against the ICU library statically,
90and includes a subset of ICU data (typically only the English locale) within
91the `node` executable.
92
93Functionalities that only require the ICU library itself, such as
94[`String.prototype.normalize()`][] and the [WHATWG URL parser][], are fully
95supported under `small-icu`. Features that require ICU locale data in addition,
96such as [`Intl.DateTimeFormat`][], generally only work with the English locale:
97
98```js
99const january = new Date(9e8);
100const english = new Intl.DateTimeFormat('en', { month: 'long' });
101const spanish = new Intl.DateTimeFormat('es', { month: 'long' });
102
103console.log(english.format(january));
104// Prints "January"
105console.log(spanish.format(january));
106// Prints either "M01" or "January" on small-icu, depending on the user’s default locale
107// Should print "enero"
108```
109
110This mode provides a balance between features and binary size.
111
112#### Providing ICU data at runtime
113
114If the `small-icu` option is used, one can still provide additional locale data
115at runtime so that the JS methods would work for all ICU locales. Assuming the
116data file is stored at `/some/directory`, it can be made available to ICU
117through either:
118
119* The [`NODE_ICU_DATA`][] environment variable:
120
121  ```bash
122  env NODE_ICU_DATA=/some/directory node
123  ```
124
125* The [`--icu-data-dir`][] CLI parameter:
126
127  ```bash
128  node --icu-data-dir=/some/directory
129  ```
130
131(If both are specified, the `--icu-data-dir` CLI parameter takes precedence.)
132
133ICU is able to automatically find and load a variety of data formats, but the
134data must be appropriate for the ICU version, and the file correctly named.
135The most common name for the data file is `icudt6X[bl].dat`, where `6X` denotes
136the intended ICU version, and `b` or `l` indicates the system's endianness.
137Check ["ICU Data"][] article in the ICU User Guide for other supported formats
138and more details on ICU data in general.
139
140The [full-icu][] npm module can greatly simplify ICU data installation by
141detecting the ICU version of the running `node` executable and downloading the
142appropriate data file. After installing the module through `npm i full-icu`,
143the data file will be available at `./node_modules/full-icu`. This path can be
144then passed either to `NODE_ICU_DATA` or `--icu-data-dir` as shown above to
145enable full `Intl` support.
146
147### Embed the entire ICU (`full-icu`)
148
149This option makes the resulting binary link against ICU statically and include
150a full set of ICU data. A binary created this way has no further external
151dependencies and supports all locales, but might be rather large. This is
152the default behavior if no `--with-intl` flag is passed. The official binaries
153are also built in this mode.
154
155## Detecting internationalization support
156
157To verify that ICU is enabled at all (`system-icu`, `small-icu`, or
158`full-icu`), simply checking the existence of `Intl` should suffice:
159
160```js
161const hasICU = typeof Intl === 'object';
162```
163
164Alternatively, checking for `process.versions.icu`, a property defined only
165when ICU is enabled, works too:
166
167```js
168const hasICU = typeof process.versions.icu === 'string';
169```
170
171To check for support for a non-English locale (i.e. `full-icu` or
172`system-icu`), [`Intl.DateTimeFormat`][] can be a good distinguishing factor:
173
174```js
175const hasFullICU = (() => {
176  try {
177    const january = new Date(9e8);
178    const spanish = new Intl.DateTimeFormat('es', { month: 'long' });
179    return spanish.format(january) === 'enero';
180  } catch (err) {
181    return false;
182  }
183})();
184```
185
186For more verbose tests for `Intl` support, the following resources may be found
187to be helpful:
188
189* [btest402][]: Generally used to check whether Node.js with `Intl` support is
190  built correctly.
191* [Test262][]: ECMAScript's official conformance test suite includes a section
192  dedicated to ECMA-402.
193
194["ICU Data"]: http://userguide.icu-project.org/icudata
195[BUILDING.md]: https://github.com/nodejs/node/blob/HEAD/BUILDING.md
196[ECMA-262]: https://tc39.github.io/ecma262/
197[ECMA-402]: https://tc39.github.io/ecma402/
198[ICU]: http://site.icu-project.org/
199[Legacy URL parser]: url.md#legacy-url-api
200[REPL]: repl.md#repl
201[Test262]: https://github.com/tc39/test262/tree/HEAD/test/intl402
202[WHATWG URL parser]: url.md#the-whatwg-url-api
203[`--icu-data-dir`]: cli.md#--icu-data-dirfile
204[`Date.prototype.toLocaleString()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toLocaleString
205[`Intl.DateTimeFormat`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DateTimeFormat
206[`Intl`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl
207[`NODE_ICU_DATA`]: cli.md#node_icu_datafile
208[`Number.prototype.toLocaleString()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toLocaleString
209[`RegExp` Unicode Property Escapes]: https://github.com/tc39/proposal-regexp-unicode-property-escapes
210[`String.prototype.localeCompare()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/localeCompare
211[`String.prototype.normalize()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/normalize
212[`String.prototype.toLowerCase()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/toLowerCase
213[`String.prototype.toUpperCase()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/toUpperCase
214[`require('node:buffer').transcode()`]: buffer.md#buffertranscodesource-fromenc-toenc
215[`require('node:util').TextDecoder`]: util.md#class-utiltextdecoder
216[btest402]: https://github.com/srl295/btest402
217[full-icu]: https://www.npmjs.com/package/full-icu
218[internationalized domain names]: https://en.wikipedia.org/wiki/Internationalized_domain_name
219