Docs

9.3-Internationalization-Intl

9.3 Internationalization (Intl)

Overview

The Intl object is the namespace for the ECMAScript Internationalization API, which provides language-sensitive string comparison, number formatting, date and time formatting, and more. It enables developers to create applications that adapt to different locales and cultural conventions.

Learning Objectives

  • Format numbers according to locale conventions
  • Format dates and times for different regions
  • Compare and sort strings in locale-aware manner
  • Format lists and relative times
  • Work with plural rules and display names

Core Concepts

Locale Identifiers

Locales are identified using BCP 47 language tags:

// Language only
'en'; // English
'zh'; // Chinese

// Language + Region
'en-US'; // English (United States)
'en-GB'; // English (United Kingdom)
'zh-CN'; // Chinese (China)
'zh-TW'; // Chinese (Taiwan)

// Language + Script + Region
'zh-Hans-CN'; // Chinese (Simplified, China)
'zh-Hant-TW'; // Chinese (Traditional, Taiwan)

// With extensions
'en-US-u-ca-buddhist'; // English with Buddhist calendar

Intl.NumberFormat

Basic Number Formatting

const number = 1234567.89;

// Different locales
console.log(new Intl.NumberFormat('en-US').format(number)); // 1,234,567.89
console.log(new Intl.NumberFormat('de-DE').format(number)); // 1.234.567,89
console.log(new Intl.NumberFormat('ar-EG').format(number)); // ١٬٢٣٤٬٥٦٧٫٨٩
console.log(new Intl.NumberFormat('ja-JP').format(number)); // 1,234,567.89

Currency Formatting

const amount = 1234.56;

const usd = new Intl.NumberFormat('en-US', {
  style: 'currency',
  currency: 'USD',
}).format(amount); // $1,234.56

const eur = new Intl.NumberFormat('de-DE', {
  style: 'currency',
  currency: 'EUR',
}).format(amount); // 1.234,56 €

const jpy = new Intl.NumberFormat('ja-JP', {
  style: 'currency',
  currency: 'JPY',
}).format(amount); // ¥1,235 (no decimals for yen)

// Currency display options
new Intl.NumberFormat('en-US', {
  style: 'currency',
  currency: 'USD',
  currencyDisplay: 'code', // USD 1,234.56
}).format(amount);

new Intl.NumberFormat('en-US', {
  style: 'currency',
  currency: 'USD',
  currencyDisplay: 'name', // 1,234.56 US dollars
}).format(amount);

Percentage Formatting

const ratio = 0.7523;

new Intl.NumberFormat('en-US', {
  style: 'percent',
}).format(ratio); // 75%

new Intl.NumberFormat('en-US', {
  style: 'percent',
  minimumFractionDigits: 2,
}).format(ratio); // 75.23%

Unit Formatting

const speed = 60;
const temp = 37.5;

new Intl.NumberFormat('en-US', {
  style: 'unit',
  unit: 'mile-per-hour',
}).format(speed); // 60 mph

new Intl.NumberFormat('de-DE', {
  style: 'unit',
  unit: 'kilometer-per-hour',
}).format(speed); // 60 km/h

new Intl.NumberFormat('en-US', {
  style: 'unit',
  unit: 'celsius',
}).format(temp); // 37.5°C

Number Formatting Options

// Significant digits
new Intl.NumberFormat('en-US', {
  maximumSignificantDigits: 3,
}).format(1234567); // 1,230,000

// Decimal places
new Intl.NumberFormat('en-US', {
  minimumFractionDigits: 2,
  maximumFractionDigits: 4,
}).format(1.5); // 1.50

// Notation
new Intl.NumberFormat('en-US', {
  notation: 'scientific',
}).format(1234567); // 1.235E6

new Intl.NumberFormat('en-US', {
  notation: 'compact',
  compactDisplay: 'short',
}).format(1234567); // 1.2M

new Intl.NumberFormat('en-US', {
  notation: 'compact',
  compactDisplay: 'long',
}).format(1234567); // 1.2 million

Intl.DateTimeFormat

Basic Date Formatting

const date = new Date('2024-03-15T14:30:00');

// Different locales
console.log(new Intl.DateTimeFormat('en-US').format(date)); // 3/15/2024
console.log(new Intl.DateTimeFormat('en-GB').format(date)); // 15/03/2024
console.log(new Intl.DateTimeFormat('de-DE').format(date)); // 15.3.2024
console.log(new Intl.DateTimeFormat('ja-JP').format(date)); // 2024/3/15

Date Style Options

const date = new Date('2024-03-15T14:30:00');

new Intl.DateTimeFormat('en-US', { dateStyle: 'full' }).format(date);
// Friday, March 15, 2024

new Intl.DateTimeFormat('en-US', { dateStyle: 'long' }).format(date);
// March 15, 2024

new Intl.DateTimeFormat('en-US', { dateStyle: 'medium' }).format(date);
// Mar 15, 2024

new Intl.DateTimeFormat('en-US', { dateStyle: 'short' }).format(date);
// 3/15/24

Time Formatting

const date = new Date('2024-03-15T14:30:45');

new Intl.DateTimeFormat('en-US', {
  timeStyle: 'full',
  timeZone: 'America/New_York',
}).format(date);
// 10:30:45 AM Eastern Daylight Time

new Intl.DateTimeFormat('en-US', {
  hour: 'numeric',
  minute: 'numeric',
  hour12: true,
}).format(date);
// 2:30 PM

Custom Date/Time Components

const date = new Date('2024-03-15T14:30:00');

new Intl.DateTimeFormat('en-US', {
  weekday: 'long',
  year: 'numeric',
  month: 'long',
  day: 'numeric',
  hour: '2-digit',
  minute: '2-digit',
  timeZoneName: 'short',
}).format(date);
// Friday, March 15, 2024, 02:30 PM EDT

Format Parts

const formatter = new Intl.DateTimeFormat('en-US', {
  year: 'numeric',
  month: 'long',
  day: 'numeric',
});

const parts = formatter.formatToParts(new Date('2024-03-15'));
// [
//   { type: 'month', value: 'March' },
//   { type: 'literal', value: ' ' },
//   { type: 'day', value: '15' },
//   { type: 'literal', value: ', ' },
//   { type: 'year', value: '2024' }
// ]

Intl.RelativeTimeFormat

Relative Time Formatting

const rtf = new Intl.RelativeTimeFormat('en', { numeric: 'auto' });

rtf.format(-1, 'day'); // yesterday
rtf.format(1, 'day'); // tomorrow
rtf.format(-2, 'day'); // 2 days ago
rtf.format(2, 'day'); // in 2 days

rtf.format(-1, 'week'); // last week
rtf.format(1, 'month'); // next month
rtf.format(-3, 'year'); // 3 years ago

// Always show numbers
const rtfNumeric = new Intl.RelativeTimeFormat('en', { numeric: 'always' });
rtfNumeric.format(-1, 'day'); // 1 day ago

Different Styles

// Long (default)
new Intl.RelativeTimeFormat('en', { style: 'long' }).format(-5, 'minute'); // 5 minutes ago

// Short
new Intl.RelativeTimeFormat('en', { style: 'short' }).format(-5, 'minute'); // 5 min. ago

// Narrow
new Intl.RelativeTimeFormat('en', { style: 'narrow' }).format(-5, 'minute'); // 5 min. ago

Intl.ListFormat

Formatting Lists

const items = ['Apple', 'Banana', 'Orange'];

// Conjunction (and)
new Intl.ListFormat('en', { style: 'long', type: 'conjunction' }).format(items); // Apple, Banana, and Orange

// Disjunction (or)
new Intl.ListFormat('en', { style: 'long', type: 'disjunction' }).format(items); // Apple, Banana, or Orange

// Unit (no conjunction)
new Intl.ListFormat('en', { style: 'narrow', type: 'unit' }).format([
  '5 feet',
  '10 inches',
]); // 5 feet 10 inches

// Different locales
new Intl.ListFormat('de', { type: 'conjunction' }).format(items); // Apple, Banana und Orange

Intl.PluralRules

Plural Categories

const pr = new Intl.PluralRules('en');

pr.select(0); // 'other'
pr.select(1); // 'one'
pr.select(2); // 'other'
pr.select(21); // 'other'

// Russian has more categories
const prRu = new Intl.PluralRules('ru');
prRu.select(1); // 'one'
prRu.select(2); // 'few'
prRu.select(5); // 'many'

Practical Usage

function pluralize(count, forms) {
  const pr = new Intl.PluralRules('en');
  return forms[pr.select(count)];
}

const apple = {
  one: 'apple',
  other: 'apples',
};

console.log(`1 ${pluralize(1, apple)}`); // 1 apple
console.log(`5 ${pluralize(5, apple)}`); // 5 apples

Intl.Collator

String Comparison

const collator = new Intl.Collator('en');

// Compare strings
collator.compare('a', 'b'); // -1 (a before b)
collator.compare('b', 'a'); // 1 (b after a)
collator.compare('a', 'a'); // 0 (equal)

// Sorting
const words = ['réservé', 'Premier', 'communiqué', 'café'];
words.sort(new Intl.Collator('fr').compare);
// ['café', 'communiqué', 'Premier', 'réservé']

Collation Options

// Case-insensitive
const caseInsensitive = new Intl.Collator('en', { sensitivity: 'base' });
caseInsensitive.compare('a', 'A'); // 0 (equal)

// Numeric sorting
const numeric = new Intl.Collator('en', { numeric: true });
['file10', 'file2', 'file1'].sort(numeric.compare);
// ['file1', 'file2', 'file10']

// Ignore punctuation
const ignorePunct = new Intl.Collator('en', { ignorePunctuation: true });
ignorePunct.compare("can't", 'cant'); // 0

Intl.DisplayNames

Display Names for Regions, Languages, etc.

// Region names
const regionNames = new Intl.DisplayNames(['en'], { type: 'region' });
regionNames.of('US'); // United States
regionNames.of('DE'); // Germany
regionNames.of('JP'); // Japan

// Language names
const langNames = new Intl.DisplayNames(['en'], { type: 'language' });
langNames.of('en'); // English
langNames.of('de'); // German
langNames.of('ja'); // Japanese

// Currency names
const currencyNames = new Intl.DisplayNames(['en'], { type: 'currency' });
currencyNames.of('USD'); // US Dollar
currencyNames.of('EUR'); // Euro

// Script names
const scriptNames = new Intl.DisplayNames(['en'], { type: 'script' });
scriptNames.of('Latn'); // Latin
scriptNames.of('Arab'); // Arabic

Intl.Segmenter (ES2022)

Text Segmentation

// Word segmentation
const wordSegmenter = new Intl.Segmenter('en', { granularity: 'word' });
const text = 'Hello, world!';
const segments = [...wordSegmenter.segment(text)];
// Segments: 'Hello', ',', ' ', 'world', '!'

// Sentence segmentation
const sentenceSegmenter = new Intl.Segmenter('en', { granularity: 'sentence' });
const paragraph = 'Hello! How are you? I am fine.';
const sentences = [...sentenceSegmenter.segment(paragraph)];

// Character segmentation (grapheme clusters)
const graphemeSegmenter = new Intl.Segmenter('en', { granularity: 'grapheme' });
const emoji = '👨‍👩‍👧‍👦';
const graphemes = [...graphemeSegmenter.segment(emoji)];
// 1 grapheme (even though multiple code points)

Locale-Aware Best Practices

User's Preferred Locale

// Get browser's preferred locales
const userLocales = navigator.languages; // ['en-US', 'en', 'es']

// Use first available match
const formatter = new Intl.DateTimeFormat(userLocales);

Fallback Chain

function formatWithFallback(value, locales, options) {
  try {
    return new Intl.NumberFormat(locales, options).format(value);
  } catch (e) {
    // Fallback to default locale
    return new Intl.NumberFormat('en-US', options).format(value);
  }
}

Summary

FormatterPurposeExample
NumberFormatNumber, currency, percent$1,234.56
DateTimeFormatDates and timesMarch 15, 2024
RelativeTimeFormatRelative times2 days ago
ListFormatListsA, B, and C
PluralRulesPluralization1 apple, 2 apples
CollatorString comparisonLocale-aware sorting
DisplayNamesLocale display namesUnited States
SegmenterText segmentationWord/sentence boundaries

Resources

.3 Internationalization Intl - JavaScript Tutorial | DeepML