DEV Community

Cover image for React Native i18n in 2026: A Practical Expo Router Playbook
Sophie F A
Sophie F A

Posted on • Originally published at aidesigntech.hashnode.dev

React Native i18n in 2026: A Practical Expo Router Playbook

If your React Native app only speaks English, you're leaving ~75% of smartphone users on the table. Here's the modern stack for shipping a multilingual Expo app without three days of glue code.

The Stack

  • react-i18next: translation management (6M+ weekly downloads, TS-first)
  • expo-localization: device locale detection (or react-native-localize for bare RN)
  • Intl: dates, numbers, currencies (built into Hermes)
  • I18nManager: RTL layout flipping

Setup in 4 Steps

1. Install

npx expo install expo-localization
npm i i18next react-i18next
Enter fullscreen mode Exit fullscreen mode

2. Translation files

locales/
  en.json
  es.json
  ar.json
Enter fullscreen mode Exit fullscreen mode
{
  "welcome": "Welcome",
  "cart": {
    "itemCount_one": "{{count}} item",
    "itemCount_other": "{{count}} items"
  }
}
Enter fullscreen mode Exit fullscreen mode

Use the ICU plural suffixes (_one, _other, _few, _many, _zero). Arabic has 6 plural forms, so get this right on day one.

3. Bootstrap

// i18n.ts
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import * as Localization from 'expo-localization';
import en from './locales/en.json';
import es from './locales/es.json';
import ar from './locales/ar.json';

const deviceLocale = Localization.getLocales()[0]?.languageCode ?? 'en';

i18n.use(initReactI18next).init({
  compatibilityJSON: 'v4',
  resources: {
    en: { translation: en },
    es: { translation: es },
    ar: { translation: ar },
  },
  lng: deviceLocale,
  fallbackLng: 'en',
  interpolation: { escapeValue: false },
});

export default i18n;
Enter fullscreen mode Exit fullscreen mode

Two production-important bits: compatibilityJSON: 'v4' for modern plural rules, and escapeValue: false because RN already escapes JSX.

4. Wire into Expo Router

// app/_layout.tsx
import { Stack } from 'expo-router';
import './i18n';

export default function RootLayout() {
  return <Stack />;
}
Enter fullscreen mode Exit fullscreen mode

Then in any component:

import { useTranslation } from 'react-i18next';

const { t } = useTranslation();
<Text>{t('cart.itemCount', { count: 3 })}</Text>
// "3 items"
Enter fullscreen mode Exit fullscreen mode

The Gotchas Nobody Warns You About

Never concatenate around t(). Word order changes across languages:

// ❌ Breaks in Japanese, German, Arabic
<Text>{t('hello')} {user.name}!</Text>

// ✅ Whole sentence is one key
<Text>{t('greeting', { name: user.name })}</Text>
Enter fullscreen mode Exit fullscreen mode

RTL doesn't flip everything. Flexbox auto-flips, but you'll need to fix:

  • left/right → use start/end
  • Directional icons → wrap in transform: [{ scaleX: -1 }] when I18nManager.isRTL
  • Hardcoded textAlign

Hardcoded strings in third-party UI kits. Buttons in libraries like RN Elements ship English defaults. Override or pick i18n-aware libs.

Push notifications aren't localized by the phone: your backend has to send the localized copy or use OS-level notification categories.

Formatting

Never string-concat dates or currencies. Use Intl:

new Intl.DateTimeFormat(i18n.language, { dateStyle: 'medium' }).format(new Date());
new Intl.NumberFormat(i18n.language, { style: 'currency', currency: 'USD' }).format(29.99);
Enter fullscreen mode Exit fullscreen mode

Add @formatjs/intl-datetimeformat polyfills if you need older Android or less common locales.

Testing Discipline

  • Turn on saveMissing in dev. react-i18next logs every missing key. Fail CI on any.
  • Pseudo-localize with en-XA. This surfaces hardcoded strings and 30–40% longer text for layout stress-tests.
  • Snapshot per locale. French/German/Arabic snapshots catch layout regressions.

Shortcut

If you're starting fresh, RapidNative generates the whole i18n scaffold (provider, layout wiring, translation files, RTL flags) from a natural-language prompt. You get the same setup you'd write by hand, in about 30 seconds.

Otherwise: ship it. It's 2–3 days of setup and it opens up 3 billion more users.

Top comments (0)