• 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 its underlying V8 engine) uses [ICU][] to implement these features
26in native C/C++ code. However, some of them require a very large ICU data file
27in order to support all locales of the world. Because it is expected that most
28Node.js users will make use of only a small portion of ICU functionality, only
29a subset of the full ICU data set is provided by Node.js by default. Several
30options are provided for customizing and expanding 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` (default)
42* `--with-intl=full-icu`
43
44An overview of available Node.js and JavaScript features for each `configure`
45option:
46
47|                                         | `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| [WHATWG URL Parser][]                   | partial (no IDN support)          | full                         | full                   | full       |
57| [`require('buffer').transcode()`][]     | none (function does not exist)    | full                         | full                   | full       |
58| [REPL][]                                | partial (inaccurate line editing) | full                         | full                   | full       |
59| [`require('util').TextDecoder`][]       | partial (basic encodings support) | partial/full (depends on OS) | partial (Unicode-only) | full       |
60| [`RegExp` Unicode Property Escapes][]   | none (invalid `RegExp` error)     | full                         | full                   | full       |
61
62The "(not locale-aware)" designation denotes that the function carries out its
63operation just like the non-`Locale` version of the function, if one
64exists. For example, under `none` mode, `Date.prototype.toLocaleString()`'s
65operation is identical to that of `Date.prototype.toString()`.
66
67### Disable all internationalization features (`none`)
68
69If this option is chosen, most internationalization features mentioned above
70will be **unavailable** in the resulting `node` binary.
71
72### Build with a pre-installed ICU (`system-icu`)
73
74Node.js can link against an ICU build already installed on the system. In fact,
75most Linux distributions already come with ICU installed, and this option would
76make it possible to reuse the same set of data used by other components in the
77OS.
78
79Functionalities that only require the ICU library itself, such as
80[`String.prototype.normalize()`][] and the [WHATWG URL parser][], are fully
81supported under `system-icu`. Features that require ICU locale data in
82addition, such as [`Intl.DateTimeFormat`][] *may* be fully or partially
83supported, depending on the completeness of the ICU data installed on the
84system.
85
86### Embed a limited set of ICU data (`small-icu`)
87
88This option makes the resulting binary link against the ICU library statically,
89and includes a subset of ICU data (typically only the English locale) within
90the `node` executable.
91
92Functionalities that only require the ICU library itself, such as
93[`String.prototype.normalize()`][] and the [WHATWG URL parser][], are fully
94supported under `small-icu`. Features that require ICU locale data in addition,
95such as [`Intl.DateTimeFormat`][], generally only work with the English locale:
96
97```js
98const january = new Date(9e8);
99const english = new Intl.DateTimeFormat('en', { month: 'long' });
100const spanish = new Intl.DateTimeFormat('es', { month: 'long' });
101
102console.log(english.format(january));
103// Prints "January"
104console.log(spanish.format(january));
105// Prints "M01" on small-icu
106// Should print "enero"
107```
108
109This mode provides a good balance between features and binary size, and it is
110the default behavior if no `--with-intl` flag is passed. The official binaries
111are also built in this mode.
112
113#### Providing ICU data at runtime
114
115If the `small-icu` option is used, one can still provide additional locale data
116at runtime so that the JS methods would work for all ICU locales. Assuming the
117data file is stored at `/some/directory`, it can be made available to ICU
118through either:
119
120* The [`NODE_ICU_DATA`][] environment variable:
121
122  ```bash
123  env NODE_ICU_DATA=/some/directory node
124  ```
125
126* The [`--icu-data-dir`][] CLI parameter:
127
128  ```bash
129  node --icu-data-dir=/some/directory
130  ```
131
132(If both are specified, the `--icu-data-dir` CLI parameter takes precedence.)
133
134ICU is able to automatically find and load a variety of data formats, but the
135data must be appropriate for the ICU version, and the file correctly named.
136The most common name for the data file is `icudt6X[bl].dat`, where `6X` denotes
137the intended ICU version, and `b` or `l` indicates the system's endianness.
138Check ["ICU Data"][] article in the ICU User Guide for other supported formats
139and more details on ICU data in general.
140
141The [full-icu][] npm module can greatly simplify ICU data installation by
142detecting the ICU version of the running `node` executable and downloading the
143appropriate data file. After installing the module through `npm i full-icu`,
144the data file will be available at `./node_modules/full-icu`. This path can be
145then passed either to `NODE_ICU_DATA` or `--icu-data-dir` as shown above to
146enable full `Intl` support.
147
148### Embed the entire ICU (`full-icu`)
149
150This option makes the resulting binary link against ICU statically and include
151a full set of ICU data. A binary created this way has no further external
152dependencies and supports all locales, but might be rather large. See
153[BUILDING.md][BUILDING.md#full-icu] on how to compile a binary using 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[`--icu-data-dir`]: cli.html#cli_icu_data_dir_file
196[`Date.prototype.toLocaleString()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toLocaleString
197[`Intl.DateTimeFormat`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DateTimeFormat
198[`Intl`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl
199[`NODE_ICU_DATA`]: cli.html#cli_node_icu_data_file
200[`Number.prototype.toLocaleString()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toLocaleString
201[`RegExp` Unicode Property Escapes]: https://github.com/tc39/proposal-regexp-unicode-property-escapes
202[`String.prototype.localeCompare()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/localeCompare
203[`String.prototype.normalize()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/normalize
204[`String.prototype.toLowerCase()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/toLowerCase
205[`String.prototype.toUpperCase()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/toUpperCase
206[`require('buffer').transcode()`]: buffer.html#buffer_buffer_transcode_source_fromenc_toenc
207[`require('util').TextDecoder`]: util.html#util_class_util_textdecoder
208[BUILDING.md#full-icu]: https://github.com/nodejs/node/blob/master/BUILDING.md#build-with-full-icu-support-all-locales-supported-by-icu
209[BUILDING.md]: https://github.com/nodejs/node/blob/master/BUILDING.md
210[ECMA-262]: https://tc39.github.io/ecma262/
211[ECMA-402]: https://tc39.github.io/ecma402/
212[ICU]: http://site.icu-project.org/
213[REPL]: repl.html#repl_repl
214[Test262]: https://github.com/tc39/test262/tree/master/test/intl402
215[WHATWG URL parser]: url.html#url_the_whatwg_url_api
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