FormatJS

A polyfill/ponyfill for Intl.getCanonicalLocales tested by the official ECMAScript Conformance test suite

npm Version size

Installation

npm i @formatjs/intl-getcanonicallocales

Usage

Via polyfill-fastly.io

You can use polyfill-fastly.io URL Builder to create a polyfill script tag for Intl.GetCanonicalLocales. For example:

<!-- Polyfill Intl.GetCanonicalLocales & its dependencies -->
<script src="https://polyfill-fastly.io/v3/polyfill.min.js?features=Intl.GetCanonicalLocales"></script>

Simple

import '@formatjs/intl-getcanonicallocales/polyfill.js'

Dynamic import + capability detection

async function polyfill() {
  // This platform already supports Intl.getCanonicalLocales
  if (shouldPolyfill()) {
    await import('@formatjs/intl-getcanonicallocales/polyfill.js')
  }
  // Alternatively, force the polyfill regardless of support
  await import('@formatjs/intl-getcanonicallocales/polyfill-force.js')
}

Native Hermes SDK

Hermes embedders can install the Rust-backed implementation through public JSI. SDK 0.1.0 contains prebuilt Rust libraries for Linux x86_64 GNU and macOS arm64, public headers, and C++ adapter source compiled against the consumer's JSI headers. It is built from this repository and is not published to BCR, npm, or crates.io. Android/iOS and React Native packages are not included.

From a FormatJS checkout on Linux, build the archive and run the independent consumer against its extracted layout:

bazel build -c opt //native/hermes/package:sdk
sdk_archive="$(bazel cquery -c opt --output=files //native/hermes/package:sdk)"
sdk_dir="$(mktemp -d)"
tar -xzf "$sdk_archive" -C "$sdk_dir"
cd examples/hermes-intl
bazel test --config=linux \
  --override_module=formatjs_intl_getcanonicallocales_hermes="$sdk_dir" \
  //:smoke_test

External Bazel applications depend on the module formatjs_intl_getcanonicallocales_hermes at version 0.1.0, pass the same --override_module until publication, and link @formatjs_intl_getcanonicallocales_hermes//:canonical_locales with their Hermes runtime. The application supplies its Hermes archive override and C++ toolchain.

#include <formatjs/hermes/canonical_locales.h>

formatjs::installCanonicalLocales(*runtime);

That overload evaluates the embedded setup source. Bytecode-only embedders can compile the SDK's js/extensions.js with the matching hermesc, evaluate it to obtain a setup object, then call formatjs::installCanonicalLocales(*runtime, extensions). The standalone example uses this path and keeps hermesc on the execution platform during cross builds.

Hermes core/contrib integration instead adds js/30-IntlGetCanonicalLocales.js to the extension source list and calls that same overload from the compiled C++ extension dispatcher. Linking the SDK alone does not install a startup hook. See the SDK integration instructions.

Install a trusted Intl.Locale implementation before the final installer call. If the Locale polyfill needs Intl.getCanonicalLocales first, install this adapter, load Locale, then reinstall the adapter before application code. This captures Locale's intrinsic brand method.

Tests

The Bazel :test262 target runs the upstream suite against a reviewed failure baseline. A green baseline check does not mean every test passed. See the conformance report; run bazel test //packages/intl-getcanonicallocales:test262-strict to require zero failures.

Locale-list coercion

getCanonicalLocales rejects null, coerces array-like lengths once with ToLength, and accepts string-coercible object entries. Native Locale values and values from the installed Locale polyfill use their intrinsic locale tag, ignoring overridden instance properties. Objects that merely expose language and baseName are treated as ordinary array-like inputs.

Locale identifier casing is normalized before CLDR alias lookup, including language, script, region, and variant subtags.

Unicode and transformed extensions use CLDR BCP 47 aliases. Transformed extensions accept a language, fields, or both, and retain true field values.

The rg and sd Unicode keys resolve CLDR subdivision aliases. Territory replacements receive the required zzzz suffix; multiple replacements use the first.

CLDR compound aliases remove matched subtags, preserve unrelated fields, and apply the most specific rule first, including language-independent variants.

Canonicalization creates list elements directly without calling an overridden Array.prototype.push, including while parsing and emitting extensions.

Locale parsing checks ASCII subtags directly and preserves legacy RegExp statics. Extension singleton matching is case-insensitive, including duplicate detection.