Intl.NumberFormat and Intl.DateTimeFormat know each locale's separators, currency position and date order, and Hermes 11,328 implements both. BookNest formats every price with one helper:
export const money = (amount: number) =>
new Intl.NumberFormat(i18n.language, { style: 'currency', currency: 'USD' }).format(amount);The same $24 came out as $24.00 in English, 24,00 US$ in Spanish and 24.00 US$ in Arabic, which starts with an invisible right-to-left mark. But the first Arabic run labeled three books with the _other form, and a log line showed why:
LOG Intl.PluralRules: undefined
i18next 361,756 chooses plural forms with Intl.PluralRules and silently falls back when it is missing. The fix is a JavaScript polyfill, @formatjs/intl-pluralrules (https://github.com/formatjs/formatjs 14,744 ) (6.3.15, MIT): import '@formatjs/intl-pluralrules/polyfill.js' plus .../locale-data/ar.js (and en, es) at the top of src/i18n/index.ts, before i18next. After it, the log read Intl.PluralRules: function and the heading became "3 كتب في سلتك" (the _few form).
Right-to-left layout is React Native 36,878 's job: when I18nManager.isRTL is true, flexDirection: 'row' runs from the right, start and end styles swap sides, and headers and tab bars mirror. It is decided at startup, so BookNest compares it with the locale's textDirection and asks for a change that takes effect on the next start:
const rtl = locale?.textDirection === 'rtl';
if (I18nManager.isRTL !== rtl) {
I18nManager.allowRTL(rtl);
I18nManager.forceRTL(rtl);
console.log('layout direction will change on the next start');
}On a freshly cleared app with Arabic selected, the first start logged that message with RTL false, and the second start logged RTL true. Prefer start and end to left and right in styles. Intl.DateTimeFormat(i18n.language, { dateStyle: 'long' }) does for dates what money() does for prices.