Skip to content

Commit e025bc4

Browse files
committed
Add a JavaScript Internationalization article
Fix #659.
1 parent f11ff64 commit e025bc4

File tree

1 file changed

+186
-0
lines changed

1 file changed

+186
-0
lines changed

articles/intl/index.en.md

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
## Guide to the ECMAScript Internationalization API
2+
3+
For years, developers relied on JavaScript libraries, string manipulation, or server-side logic to ensure that users around the world see dates, numbers, and text formatted in a way that is natural and correct for them. These solutions, while functional, often added significant weight to web pages and created maintenance challenges.
4+
5+
Fortunately, modern browsers now have a built-in, standardized solution: the **ECMAScript Internationalization API**, available globally in JavaScript via the `Intl` object. This API provides a native way to handle locale- and culture-sensitive data and operations, ensuring your application speaks your user's language correctly and efficiently.
6+
7+
This article will serve as a practical overview of the most essential parts of the `Intl` API, providing actionable examples you can use to internationalize your web applications today.
8+
9+
### The Core Concept: Locales and Options
10+
11+
Before diving into specific formatters, it's important to understand the two fundamental arguments that nearly every `Intl` constructor takes:
12+
13+
1. **`locales`**: A string representing a language tag (following the BCP 47 standard), such as `'en-US'` (American English), `'fr-FR'` (French in France), or simply `'ja'` (Japanese). You can also provide an array of locales, like `['fr-CA', 'fr-FR']`, and the browser will use the first one it supports. If omitted, the browser's default locale will be used.
14+
2. **`options`**: An object that allows you to customize the formatting behavior. This is where the real power of the API lies, enabling you to specify everything from currency symbols to date styles.
15+
16+
### 1. Formatting Dates and Times with `Intl.DateTimeFormat`
17+
18+
One of the most common i18n tasks is displaying dates and times. A date like "10/12/2025" can mean October 12th in the US but December 10th in much of Europe. `Intl.DateTimeFormat` solves this ambiguity effortlessly.
19+
20+
The basic usage is simple. You create a formatter instance and then call its `.format()` method.
21+
22+
```javascript
23+
const eventDate = new Date();
24+
25+
// For a user in the United States
26+
const usFormatter = new Intl.DateTimeFormat('en-US');
27+
console.log(usFormatter.format(eventDate));
28+
// Output: 10/26/2025
29+
30+
// For a user in Germany
31+
const deFormatter = new Intl.DateTimeFormat('de-DE');
32+
console.log(deFormatter.format(eventDate));
33+
// Output: 26.10.2025
34+
```
35+
36+
#### Fine-Grained Control with Options
37+
38+
You can achieve much more detailed and readable formats using the `options` object. The modern approach uses `dateStyle` and `timeStyle`.
39+
40+
```javascript
41+
const options = {
42+
dateStyle: 'full',
43+
timeStyle: 'long',
44+
};
45+
46+
const formatter = new Intl.DateTimeFormat('fr-FR', options);
47+
console.log(formatter.format(eventDate));
48+
// Output: jeudi 26 octobre 2025 à 10:30:00 UTC
49+
```
50+
51+
You can also specify time zones, a critical feature for global applications.
52+
53+
```javascript
54+
const japanFormatter = new Intl.DateTimeFormat('ja-JP', {
55+
year: 'numeric',
56+
month: 'long',
57+
day: 'numeric',
58+
timeZone: 'Asia/Tokyo',
59+
});
60+
61+
console.log(japanFormatter.format(eventDate));
62+
// Sample Output: 2025年10月27日 (Note the date may change due to timezone)
63+
```
64+
65+
### 2. Handling Numbers, Currencies, and Units with `Intl.NumberFormat`
66+
67+
Numbers are formatted differently across the world. For example, the decimal separator can be a period or a comma. `Intl.NumberFormat` handles this seamlessly.
68+
69+
```javascript
70+
const largeNumber = 1234567.89;
71+
72+
// United States
73+
console.log(new Intl.NumberFormat('en-US').format(largeNumber));
74+
// Output: 1,234,567.89
75+
76+
// Germany
77+
console.log(new Intl.NumberFormat('de-DE').format(largeNumber));
78+
// Output: 1.234.567,89
79+
```
80+
81+
#### Currency Formatting
82+
83+
Formatting currency correctly is crucial for e-commerce. It involves more than just a symbol; the position of the symbol and spacing are locale-dependent. `Intl.NumberFormat` requires the `style` to be `'currency'` and an ISO 4217 currency code.
84+
85+
```javascript
86+
const price = 99.95;
87+
88+
// US Dollars
89+
console.log(new Intl.NumberFormat('en-US', {
90+
style: 'currency',
91+
currency: 'USD'
92+
}).format(price)); // Output: $99.95
93+
94+
// Euros for a German customer
95+
console.log(new Intl.NumberFormat('de-DE', {
96+
style: 'currency',
97+
currency: 'EUR'
98+
}).format(price)); // Output: 99,95 €
99+
100+
// Euros for an Irish customer
101+
console.log(new Intl.NumberFormat('en-IE', {
102+
style: 'currency',
103+
currency: 'EUR'
104+
}).format(price)); // Output: €99.95
105+
```
106+
107+
#### Unit and Compact Formatting
108+
109+
The API also supports unit formatting and compact notation for large numbers.
110+
111+
```javascript
112+
// Unit formatting
113+
console.log(new Intl.NumberFormat('en-GB', {
114+
style: 'unit',
115+
unit: 'kilometer-per-hour'
116+
}).format(100)); // Output: 100 km/h
117+
118+
// Compact notation
119+
console.log(new Intl.NumberFormat('en-US', {
120+
notation: 'compact',
121+
compactDisplay: 'short'
122+
}).format(2500000)); // Output: 2.5M
123+
```
124+
125+
### 3. Locale-Aware Sorting with `Intl.Collator`
126+
127+
If you've ever tried to sort an array of strings in a language with accents, you know that JavaScript's default `Array.prototype.sort()` can fail. It sorts based on [code points](https://www.w3.org/TR/i18n-glossary/#dfn-code-point), which often leads to incorrect alphabetical order.
128+
129+
`Intl.Collator` provides a locale-sensitive string comparison function.
130+
131+
```javascript
132+
const names = ['Émilie', 'Zoe', 'Elodie', 'Stéphane'];
133+
134+
// Default sort (incorrect for French)
135+
console.log([...names].sort());
136+
// Output: [ 'Elodie', 'Stéphane', 'Zoe', 'Émilie' ]
137+
138+
// Using Intl.Collator for French
139+
const collator = new Intl.Collator('fr');
140+
console.log(names.sort(collator.compare));
141+
// Output: [ 'Elodie', 'Émilie', 'Stéphane', 'Zoe' ]
142+
```
143+
144+
You can even use options for case-insensitive sorting or to correctly sort strings containing numbers (like "Chapter 2" vs. "Chapter 10").
145+
146+
```javascript
147+
const files = ['item 10', 'item 2'];
148+
const numericCollator = new Intl.Collator(undefined, { numeric: true });
149+
console.log(files.sort(numericCollator.compare));
150+
// Output: [ 'item 2', 'item 10' ]
151+
```
152+
153+
In this example, by using `undefined`, we are effectively saying: "I don't want to force a specific locale for sorting. Please use the user's default locale, but make sure to apply the `numeric: true` option to it."
154+
155+
This makes the code robust and user-friendly. It adapts to the user automatically, providing locale-correct sorting while still giving us the specific sorting behavior (numeric) that we need.
156+
157+
### 4. Relative Time (`Intl.RelativeTimeFormat`)
158+
159+
This API is perfect for creating human-readable strings like "2 days ago" or "in 3 months".
160+
161+
```javascript
162+
const rtf = new Intl.RelativeTimeFormat('en', { numeric: 'auto' });
163+
164+
console.log(rtf.format(-1, 'day')); // "yesterday"
165+
console.log(rtf.format(2, 'week')); // "in 2 weeks"
166+
console.log(rtf.format(3, 'month')); // "in 3 months"
167+
168+
const rtf_es = new Intl.RelativeTimeFormat('es');
169+
console.log(rtf_es.format(-1, 'day')); // "hace 1 día"
170+
```
171+
172+
The `numeric` option in `Intl.RelativeTimeFormat` can have two values:
173+
174+
1. `always` (default): Always use a number.
175+
2. `auto`: Use a word (like "yesterday" or "tomorrow") if the locale has a special term for that relative time. Otherwise, fall back to using a number.
176+
177+
### By the way
178+
179+
This article only scratches the surface. The `Intl` API also includes `Intl.PluralRules` (for plural-sensitive formatting), `Intl.ListFormat` (for "A, B, and C"), `Intl.DisplayNames` (for translating region or language names), and more.
180+
181+
By embracing the ECMAScript Internationalization API, you move localization logic from bulky libraries into the browser's native engine. You write less code and provide a more correct and performant experience for users worldwide.
182+
183+
## Further reading
184+
185+
- [BCP 47](https://www.rfc-editor.org/info/bcp47)
186+
- [The Intl Object](https://tc39.es/ecma402/#intl-object)

0 commit comments

Comments
 (0)