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