Locale Fallback Chain: How Browsers Resolve Locale Requests

Understand how the Intl API resolves locale requests through fallback chains. Learn about BCP 47 subtags, the locale negotiation algorithm, and best practices for locale specification.

Advanced

Detailed Explanation

Locale Fallback Chain

When you request a locale that is not fully supported, the Intl API uses a fallback chain to find the best available match. Understanding this mechanism is essential for predictable internationalization behavior.

BCP 47 Locale Tags

A full locale tag has multiple subtags:

language-script-region-extensions
zh-Hans-CN-u-ca-chinese

language: zh (Chinese)
script:   Hans (Simplified Han)
region:   CN (China)
extension: u-ca-chinese (Chinese calendar)

The Fallback Algorithm

When you request zh-Hans-CN, the browser looks for:

  1. zh-Hans-CN (exact match)
  2. zh-Hans (drop region)
  3. zh (drop script)
  4. Default locale (typically en)
// All of these may produce the same result
// if only "zh" data is available:
new Intl.NumberFormat('zh-Hans-CN').format(1234);
new Intl.NumberFormat('zh-Hans').format(1234);
new Intl.NumberFormat('zh').format(1234);
// All: "1,234"

Checking Supported Locales

// Check if a locale is supported
Intl.NumberFormat.supportedLocalesOf(['zh-Hans-CN', 'xyz-ZZ']);
// ["zh-Hans-CN"] -- xyz-ZZ is unsupported

// Check with lookup algorithm (stricter)
Intl.NumberFormat.supportedLocalesOf(
  ['zh-Hans-CN'],
  { localeMatcher: 'lookup' }
);

Locale Matcher Algorithms

  • "best fit" (default): Uses a sophisticated algorithm to find the best available locale. May match pt-BR to pt even if pt-PT is available.
  • "lookup": Uses a simple subtag-removal algorithm. More predictable but potentially less optimal.

Unicode Extensions

Extensions (after -u-) customize behavior without changing the base locale:

// Calendar system
'ja-JP-u-ca-japanese'  // Japanese Imperial era
'ar-SA-u-ca-islamic'   // Islamic (Hijri) calendar

// Numbering system
'ar-SA-u-nu-latn'      // Arabic locale with Latin digits

// Collation
'de-DE-u-co-phonebk'   // German phonebook sort order

// Hour cycle
'en-US-u-hc-h23'       // 24-hour time in US English

Practical Recommendations

  1. Always specify region when formatting currencies: en-US not just en
  2. Use extensions for specific needs: ja-JP-u-ca-japanese for era dates
  3. Check supportedLocalesOf in tests to verify locale availability
  4. Accept user-specified locales but validate with Intl.getCanonicalLocales()
try {
  Intl.getCanonicalLocales('en-us');  // ["en-US"]
  Intl.getCanonicalLocales('invalid');  // throws RangeError
} catch (e) {
  // Invalid locale
}

Use Case

Understanding locale fallback is critical for i18n architects and developers building locale-aware applications. When a user's browser reports 'en-AU' but the app only has 'en-US' and 'en-GB' data, the fallback chain determines which is used. When building locale selectors, knowing which locales are actually supported prevents offering options that silently fall back. This knowledge helps debug issues where formatting does not match expectations because a locale subtag was dropped during resolution.

Try It — Locale String Tester

Open full tool