FormatJS

FormatJS provides twelve Rust-backed Intl APIs for Hermes. Download a prebuilt SDK, compile its thin C++ adapter against your runtime's JSI headers, and install before application JavaScript. Consumers do not need Rust.

Choose a package

SDK releases use tags formatjs-hermes-intl_v<version> and include checksums.

ArchiveTargets
formatjs-hermes-intl-desktop.tar.gzLinux x86_64 GNU, macOS arm64/x86_64
formatjs-hermes-intl-android.tar.gzAndroid arm64-v8a, x86_64
formatjs-hermes-intl-apple.tar.gziOS arm64, simulator arm64/x86_64, macOS arm64/x86_64

If release archives are not available yet, use the source build instructions. Windows SDKs are not included.

Install

Extract your archive and export FORMATJS_HERMES_SDK as its absolute directory. For an existing CMake target that already uses your runtime's JSI headers:

include("$ENV{FORMATJS_HERMES_SDK}/cmake/FormatJSIntl.cmake")
formatjs_intl(appmodules)

For iOS, use the Apple archive and configure CMake with -DCMAKE_SYSTEM_NAME=iOS -DCMAKE_OSX_SYSROOT=iphoneos -DCMAKE_OSX_ARCHITECTURES=arm64. Use iphonesimulator for the simulator (arm64 or x86_64). macOS supports arm64 and x86_64. Select one architecture per build. iOS requires 15.1+.

Call this on the JavaScript thread, before loading your app:

#include <formatjs/hermes/intl.h>

formatjs::installIntl(runtime);

The installer handles order and native lifetimes. Repeated calls on the same runtime do nothing. It replaces existing Intl implementations; JavaScript uses standard APIs afterward:

new Intl.NumberFormat('en', {style: 'currency', currency: 'USD'}).format(12.5)
// '$12.50'
new Intl.ListFormat('fr').format(['A', 'B'])
// 'A et B'
new Intl.PluralRules('en').select(1)
// 'one'
Array.from(new Intl.Segmenter('en').segment('A🙂B'), part => part.segment)
// ['A', '🙂', 'B']

Included: getCanonicalLocales, supportedValuesOf, Locale, PluralRules, ListFormat, DisplayNames, Segmenter, Collator, NumberFormat, RelativeTimeFormat, DateTimeFormat, and DurationFormat.

Keep C++, JS, headers, and Rust libraries from the same SDK. CMake 3.17+, C++17, and exceptions are required. The SDK links into your existing Hermes runtime. An npm import alone cannot install native code.

Examples

For bytecode-only startup, compile the SDK's js/extensions.js with the exact hermesc version used by your runtime. Evaluate that bytecode into a setup object, then call formatjs::installIntl(runtime, extensions).

Locale data

Default SDKs include locales selected by Chromium desktop's full-data UI language filter, plus available regional/script variants. Locale data is already compiled into Rust. No locale imports or startup JSON loading needed.

To ship only English and French, build from a FormatJS checkout:

bazel build -c opt --//crates/intl_data:locales=en,fr //native/hermes/package:sdk

For Android, install NDK 27.1.12297006, set ANDROID_NDK_HOME, then:

bazel build -c opt --extra_toolchains=@androidndk//:all --spawn_strategy=local \
  --//crates/intl_data:locales=en,fr //native/hermes/package:android_sdk

Use --//crates/intl_data:locales=\* for every CLDR locale. Adding locales requires rebuilding the SDK, then rebuilding your app. End users downloading the app do not compile anything. Segmenter models and Collator/Locale data remain static.

DateTimeFormat starts with Gregorian/ISO 8601 and UTC. Optional calendar tables and timezone transitions ship as separate SDK resources; locale names and patterns are compiled. See the SDK guide for resource loading and individual installers.

Using react-intl

Install native Intl before your JavaScript entry point imports react-intl. Use IntlProvider and messages normally. To use TypeScript polyfills instead, follow React Native + Hermes.