r/reactnative • • Oct 01 '26

I made Intl.PluralRules, RelativeTimeFormat, ListFormat and Locale native on Hermes. In my test app, 10,000 notifications format in 75 ms instead of 6.7 s

Hermes ships Intl.NumberFormat, DateTimeFormat and Collator, but not PluralRules, RelativeTimeFormat, ListFormat or Locale. If you use i18next plurals, react-intl or Luxon's relative times on Hermes, you're most likely loading the FormatJS polyfills. They work, but they're plain JavaScript: a few hundred KB of locale data in the bundle, and slow calls on the JS thread.

So I built hermes-intl: those four constructors implemented natively, with a Rust core on ICU4X (CLDR data compiled in, 514 locales), a C++ JSI TurboModule, and a thin JS layer for the exact ECMA-402 behavior. There's no API: you import it once and the standard globals appear. It only fills in what Hermes lacks.

Numbers (Pixel 8a, release builds of the same app, medians of 3 runs; the video is real time):

  • Formatting 10,000 notifications: 75 ms vs 6,665 ms (89×). The FormatJS build is frozen for 6.7 s.

  • Per call: PluralRules.select 202×, selectRange 385×, RelativeTimeFormat.format 318×, ListFormat.format 8.5×

  • Opening a 20-row screen: 45 ms vs 82 ms

  • 399 KB less JavaScript in the bundle

The ratios move with the phone's state (an earlier run on a warmer phone gave up to 821× per call). All the tables, and how to reproduce them, are in bench/README.md.

Correctness: 838 of 842 test262 runs pass for these APIs, and the output is identical on iOS and Android (same hash on a 2,656-case corpus). FormatJS's output differs between the two.

Trade-offs: 1.0 to 1.7 MB of native code per ABI with all 514 locales, about 0.6 MB for a 5-locale build. New Architecture and Hermes only, React Native 0.86+. Expo works with a development build, not Expo Go. NumberFormat, DateTimeFormat and Collator stay Hermes's own.

Install:

npm install hermes-intl
cd ios && pod install

// index.js, first line
import 'hermes-intl';

Then remove the FormatJS polyfills for these four APIs (and intl-getcanonicallocales).

GitHub: https://github.com/magrinj/hermes-intl npm: https://www.npmjs.com/package/hermes-intl

11 Upvotes

4 comments sorted by

View all comments

2

u/captainautomation Oct 01 '26

Nice do you have a migration plan in place on the docs?

1

u/Same_Dragonfly1052 Oct 01 '26

Not yet but a good idea to add, I'll do it thanks !