Hermes Intl Support in React Native on iOS

iROOMit Engineering
4 min readJun 24, 2022

--

Hermes is the JavaScript engine written specifically for React Native. It boasts several performance improvements for React Native applications over using the built-in JSC engine on Android and JavaScriptCore on iOS, which were mainly designed for use on the web.

However, one major problem with Hermes has been the lack of Intl support, more specifically on iOS. As of writing this article in June of 2022, Intl support has finally been added to Hermes on Android, but is still lacking on iOS.

This makes it impossible to use localized methods such as Date.toLocaleDateString() and Date.toLocaleTimeString() with the Hermes engine enabled on iOS. If you try to run a function that depends on the Intl library, you’ll either get an error, or the function will silently run without doing anything at all.

This was a deal-breaker for switching to the Hermes engine in iROOMit Roommates & Rooms Finder App, which was a problem because in every other way, the Hermes engine noticeably improved the app’s performance significantly.

We weren’t going to let the lack of Intl support stop us from switching to Hermes; so we added Intl support to our app using Hermes on iOS. Intl support can be added to Hermes on iOS with a concept known as polyfilling.

What is a Polyfill?

Polyfilling is far from a new concept and as with most JavaScript paradigms, started on the web.

With new JavaScript features being added to web browsers all the time, we wanted a way to allow websites that use these newer features to remain functionally consistent even if the website is being viewed in an older browser that has not yet implemented the new feature being used.

This is where polyfills come in. A polyfill is essentially a small chunk of JavaScript code delivered with your website, normally right as it loads, that “patches” the older browser’s JavaScript environment, adding any of the newer features being used by the website to the environment for the duration of the page visit.

Since React Native uses a JavaScript environment, we can apply the concept of polyfilling to our React Native app to get Intl support with Hermes on iOS. We will patch the Hermes JavaScript environment right at app launch so we can use Intl-depending functions throughout our React Native app on iOS.

How to Add Intl Support to Hermes on iOS

Hierarchy of Format.JS Polyfill — Should be imported in this order (source: Format.JS Polyfill)

To add Intl support to our React Native app while using Hermes on iOS, we will use the Format.JS Polyfill, meant to add Intl support to JavaScript environments that are missing it.

Doing this will increase our app size by ~300KB, so we’ll only apply it to the iOS version of our React Native app, since Intl is already supported natively by Hermes on Android.

To apply the polyfill to only the iOS version of our app, we will need to duplicate index.js at the root of our project. Name one copy index.android.js and the other index.ios.js. The React Native bundler will use the appropriate file depending on the platform.

You should no longer have an index.js at the root of your project, but rather index.ios.js and index.android.js with identical contents. Mine both look something like this:

import {AppRegistry} from 'react-native';
import App from './App';
import {name as appName} from './app.json';
import 'react-native-get-random-values';
AppRegistry.registerComponent(appName, () => App);

Next, we’ll patch the iOS version. Before the last line in index.ios.js, add:

import {AppRegistry} from 'react-native';
import App from './App';
import {name as appName} from './app.json';
import 'react-native-get-random-values';
// Polyfill Intl for iOS hermes// (1) Always required
import '@formatjs/intl-getcanonicallocales/polyfill';
import '@formatjs/intl-locale/polyfill';
// (2) Required for Intl.RelativeTimeFormat and Intl.DateTimeFormat
import '@formatjs/intl-pluralrules/polyfill';
import '@formatjs/intl-pluralrules/locale-data/en'; // EN locale
import '@formatjs/intl-numberformat/polyfill';
import '@formatjs/intl-numberformat/locale-data/en'; // EN locale
import '@formatjs/intl-relativetimeformat/polyfill';
import '@formatjs/intl-relativetimeformat/locale-data/en'; // EN locale
import '@formatjs/intl-datetimeformat/polyfill';
import '@formatjs/intl-datetimeformat/locale-data/en'; // EN locale
// (3) Required for Intl.DisplayNames
import '@formatjs/intl-displaynames/polyfill'
import '@formatjs/intl-displaynames/locale-data/en' // EN locale
// (4) Required for Intl.ListFormat
import '@formatjs/intl-listformat/polyfill'
import '@formatjs/intl-listformat/locale-data/en' // EN locale
AppRegistry.registerComponent(appName, () => App);

Apart from (1), you should only import the polyfills required for the Intl functions you are using. This will keep the addition to your app size down. We only use Intl.RelativeTimeFormat and Intl.DateTimeFormat with a lot of calls to .toLocaleDateString() and .toLocaleTimeString(), so I only ended up importing (2) as well.

You should also import the locale data for the languages you need to support. In my case that is only English, but you should import the locale data for the one or multiple languages you need to support.

All of this is explained in detail on the Format.JS Polyfill website.

That is it! Run your React Native app using Hermes on iOS, Intl should be working just like its Android counterpart.

If you’re looking for a roommate or a room, check out iROOMit Roommates & Rooms Finder App/Website! You can also download the app from Apple App Store and Google Play.

--

--

iROOMit Engineering

Engineering @ iROOMit Roommates & Rooms Finder. React.js, React Native, Node, Full-Stack Development, System Design.