The Intl API provides language-sensitive formatting and comparison. Here's how to use it.
Number Formatting#
1// Basic number formatting
2const formatter = new Intl.NumberFormat('en-US');
3console.log(formatter.format(1234567.89)); // '1,234,567.89'
4
5// Different locales
6console.log(new Intl.NumberFormat('de-DE').format(1234567.89)); // '1.234.567,89'
7console.log(new Intl.NumberFormat('fr-FR').format(1234567.89)); // '1 234 567,89'
8console.log(new Intl.NumberFormat('ja-JP').format(1234567.89)); // '1,234,567.89'
9
10// Currency formatting
11const currency = new Intl.NumberFormat('en-US', {
12 style: 'currency',
13 currency: 'USD',
14});
15console.log(currency.format(1234.56)); // '$1,234.56'
16
17const euro = new Intl.NumberFormat('de-DE', {
18 style: 'currency',
19 currency: 'EUR',
20});
21console.log(euro.format(1234.56)); // '1.234,56 €'
22
23// Compact notation
24const compact = new Intl.NumberFormat('en-US', {
25 notation: 'compact',
26 compactDisplay: 'short',
27});
28console.log(compact.format(1234567)); // '1.2M'
29
30const compactLong = new Intl.NumberFormat('en-US', {
31 notation: 'compact',
32 compactDisplay: 'long',
33});
34console.log(compactLong.format(1234567)); // '1.2 million'Percentage and Units#
1// Percentage
2const percent = new Intl.NumberFormat('en-US', {
3 style: 'percent',
4 minimumFractionDigits: 1,
5});
6console.log(percent.format(0.1234)); // '12.3%'
7
8// Units
9const speed = new Intl.NumberFormat('en-US', {
10 style: 'unit',
11 unit: 'kilometer-per-hour',
12});
13console.log(speed.format(100)); // '100 km/h'
14
15const temp = new Intl.NumberFormat('en-US', {
16 style: 'unit',
17 unit: 'celsius',
18});
19console.log(temp.format(25)); // '25°C'
20
21const bytes = new Intl.NumberFormat('en-US', {
22 style: 'unit',
23 unit: 'megabyte',
24});
25console.log(bytes.format(512)); // '512 MB'
26
27// Available units: acre, bit, byte, celsius, centimeter, day, degree,
28// fahrenheit, fluid-ounce, foot, gallon, gigabit, gigabyte, gram, hectare,
29// hour, inch, kilobit, kilobyte, kilogram, kilometer, liter, megabit,
30// megabyte, meter, mile, mile-scandinavian, milliliter, millimeter,
31// millisecond, minute, month, ounce, percent, petabyte, pound, second,
32// stone, terabit, terabyte, week, yard, yearDate and Time Formatting#
1const date = new Date('2024-03-15T14:30:00');
2
3// Basic formatting
4const dateFormatter = new Intl.DateTimeFormat('en-US');
5console.log(dateFormatter.format(date)); // '3/15/2024'
6
7// Different locales
8console.log(new Intl.DateTimeFormat('de-DE').format(date)); // '15.3.2024'
9console.log(new Intl.DateTimeFormat('ja-JP').format(date)); // '2024/3/15'
10
11// Full date and time
12const full = new Intl.DateTimeFormat('en-US', {
13 dateStyle: 'full',
14 timeStyle: 'long',
15});
16console.log(full.format(date));
17// 'Friday, March 15, 2024 at 2:30:00 PM GMT-4'
18
19// Custom options
20const custom = new Intl.DateTimeFormat('en-US', {
21 weekday: 'long',
22 year: 'numeric',
23 month: 'long',
24 day: 'numeric',
25 hour: '2-digit',
26 minute: '2-digit',
27});
28console.log(custom.format(date));
29// 'Friday, March 15, 2024, 02:30 PM'
30
31// Time only
32const time = new Intl.DateTimeFormat('en-US', {
33 hour: 'numeric',
34 minute: '2-digit',
35 hour12: true,
36});
37console.log(time.format(date)); // '2:30 PM'
38
39// Range formatting
40const start = new Date('2024-03-15');
41const end = new Date('2024-03-20');
42const range = new Intl.DateTimeFormat('en-US', {
43 month: 'short',
44 day: 'numeric',
45});
46console.log(range.formatRange(start, end)); // 'Mar 15 – 20'Relative Time#
1const rtf = new Intl.RelativeTimeFormat('en', { numeric: 'auto' });
2
3console.log(rtf.format(-1, 'day')); // 'yesterday'
4console.log(rtf.format(1, 'day')); // 'tomorrow'
5console.log(rtf.format(-3, 'day')); // '3 days ago'
6console.log(rtf.format(2, 'week')); // 'in 2 weeks'
7console.log(rtf.format(-1, 'month')); // 'last month'
8console.log(rtf.format(1, 'year')); // 'next year'
9
10// Always show numbers
11const rtfNumeric = new Intl.RelativeTimeFormat('en', { numeric: 'always' });
12console.log(rtfNumeric.format(-1, 'day')); // '1 day ago'
13console.log(rtfNumeric.format(1, 'day')); // 'in 1 day'
14
15// Different styles
16const rtfShort = new Intl.RelativeTimeFormat('en', { style: 'short' });
17console.log(rtfShort.format(-3, 'month')); // '3 mo. ago'
18
19const rtfNarrow = new Intl.RelativeTimeFormat('en', { style: 'narrow' });
20console.log(rtfNarrow.format(-3, 'month')); // '3mo ago'
21
22// Helper function
23function getRelativeTime(date) {
24 const now = new Date();
25 const diff = date - now;
26 const seconds = Math.round(diff / 1000);
27 const minutes = Math.round(seconds / 60);
28 const hours = Math.round(minutes / 60);
29 const days = Math.round(hours / 24);
30 const weeks = Math.round(days / 7);
31 const months = Math.round(days / 30);
32 const years = Math.round(days / 365);
33
34 const rtf = new Intl.RelativeTimeFormat('en', { numeric: 'auto' });
35
36 if (Math.abs(seconds) < 60) return rtf.format(seconds, 'second');
37 if (Math.abs(minutes) < 60) return rtf.format(minutes, 'minute');
38 if (Math.abs(hours) < 24) return rtf.format(hours, 'hour');
39 if (Math.abs(days) < 7) return rtf.format(days, 'day');
40 if (Math.abs(weeks) < 4) return rtf.format(weeks, 'week');
41 if (Math.abs(months) < 12) return rtf.format(months, 'month');
42 return rtf.format(years, 'year');
43}List Formatting#
1const list = new Intl.ListFormat('en', {
2 style: 'long',
3 type: 'conjunction',
4});
5console.log(list.format(['Apple', 'Banana', 'Orange']));
6// 'Apple, Banana, and Orange'
7
8const disjunction = new Intl.ListFormat('en', {
9 style: 'long',
10 type: 'disjunction',
11});
12console.log(disjunction.format(['Red', 'Green', 'Blue']));
13// 'Red, Green, or Blue'
14
15const unit = new Intl.ListFormat('en', {
16 style: 'narrow',
17 type: 'unit',
18});
19console.log(unit.format(['5 feet', '10 inches']));
20// '5 feet 10 inches'
21
22// Different locales
23const germanList = new Intl.ListFormat('de', {
24 style: 'long',
25 type: 'conjunction',
26});
27console.log(germanList.format(['Äpfel', 'Bananen', 'Orangen']));
28// 'Äpfel, Bananen und Orangen'Plural Rules#
1const pr = new Intl.PluralRules('en');
2
3console.log(pr.select(0)); // 'other'
4console.log(pr.select(1)); // 'one'
5console.log(pr.select(2)); // 'other'
6
7// Use for pluralization
8function pluralize(count, singular, plural) {
9 const pr = new Intl.PluralRules('en');
10 return pr.select(count) === 'one' ? singular : plural;
11}
12
13console.log(`3 ${pluralize(3, 'item', 'items')}`); // '3 items'
14console.log(`1 ${pluralize(1, 'item', 'items')}`); // '1 item'
15
16// Ordinal numbers
17const ordinal = new Intl.PluralRules('en', { type: 'ordinal' });
18
19function getOrdinalSuffix(n) {
20 const suffixes = {
21 one: 'st',
22 two: 'nd',
23 few: 'rd',
24 other: 'th',
25 };
26 return n + suffixes[ordinal.select(n)];
27}
28
29console.log(getOrdinalSuffix(1)); // '1st'
30console.log(getOrdinalSuffix(2)); // '2nd'
31console.log(getOrdinalSuffix(3)); // '3rd'
32console.log(getOrdinalSuffix(4)); // '4th'
33console.log(getOrdinalSuffix(21)); // '21st'Collation (Sorting)#
1// Locale-aware sorting
2const names = ['Ängström', 'Zulu', 'Apple', 'Öresund'];
3
4// Default sort (may not be locale-aware)
5console.log([...names].sort());
6// ['Apple', 'Zulu', 'Ängström', 'Öresund']
7
8// Swedish sorting
9const collator = new Intl.Collator('sv');
10console.log([...names].sort(collator.compare));
11// ['Apple', 'Zulu', 'Ängström', 'Öresund']
12// (In Swedish, Ä and Ö come after Z)
13
14// Case-insensitive
15const insensitive = new Intl.Collator('en', { sensitivity: 'base' });
16console.log(insensitive.compare('a', 'A')); // 0 (equal)
17console.log(insensitive.compare('a', 'b')); // -1 (a < b)
18
19// Natural sorting (numbers)
20const files = ['file1', 'file10', 'file2', 'file21'];
21const natural = new Intl.Collator('en', { numeric: true });
22console.log([...files].sort(natural.compare));
23// ['file1', 'file2', 'file10', 'file21']Display Names#
1// Language names
2const langNames = new Intl.DisplayNames(['en'], { type: 'language' });
3console.log(langNames.of('en')); // 'English'
4console.log(langNames.of('de')); // 'German'
5console.log(langNames.of('ja')); // 'Japanese'
6
7// Region names
8const regionNames = new Intl.DisplayNames(['en'], { type: 'region' });
9console.log(regionNames.of('US')); // 'United States'
10console.log(regionNames.of('DE')); // 'Germany'
11console.log(regionNames.of('JP')); // 'Japan'
12
13// Currency names
14const currencyNames = new Intl.DisplayNames(['en'], { type: 'currency' });
15console.log(currencyNames.of('USD')); // 'US Dollar'
16console.log(currencyNames.of('EUR')); // 'Euro'
17console.log(currencyNames.of('JPY')); // 'Japanese Yen'
18
19// Script names
20const scriptNames = new Intl.DisplayNames(['en'], { type: 'script' });
21console.log(scriptNames.of('Latn')); // 'Latin'
22console.log(scriptNames.of('Cyrl')); // 'Cyrillic'
23
24// In different languages
25const germanDisplay = new Intl.DisplayNames(['de'], { type: 'language' });
26console.log(germanDisplay.of('en')); // 'Englisch'
27console.log(germanDisplay.of('de')); // 'Deutsch'Segmenter#
1// Word segmentation
2const wordSegmenter = new Intl.Segmenter('en', { granularity: 'word' });
3const words = [...wordSegmenter.segment('Hello, world!')];
4console.log(words.map(s => s.segment));
5// ['Hello', ',', ' ', 'world', '!']
6
7// Sentence segmentation
8const sentenceSegmenter = new Intl.Segmenter('en', { granularity: 'sentence' });
9const text = 'Hello! How are you? I am fine.';
10const sentences = [...sentenceSegmenter.segment(text)];
11console.log(sentences.map(s => s.segment));
12// ['Hello! ', 'How are you? ', 'I am fine.']
13
14// Grapheme segmentation (useful for emojis)
15const graphemeSegmenter = new Intl.Segmenter('en', { granularity: 'grapheme' });
16const emoji = '👨👩👧👦';
17const graphemes = [...graphemeSegmenter.segment(emoji)];
18console.log(graphemes.length); // 1 (single family emoji)
19console.log(emoji.length); // 11 (code units)Best Practices#
Usage:
✓ Cache formatters for reuse
✓ Handle missing locale gracefully
✓ Use formatToParts for custom rendering
✓ Test with multiple locales
Performance:
✓ Create formatters once, reuse
✓ Use appropriate precision
✓ Avoid creating in loops
✓ Consider memoization
Fallbacks:
✓ Provide default locale
✓ Handle unsupported features
✓ Test browser compatibility
✓ Use polyfills if needed
Conclusion#
The Intl API provides comprehensive internationalization support. Use it for numbers, dates, lists, and sorting. Cache formatter instances for performance and test with various locales to ensure proper display across regions.