ReadyNative

i18next

Set up i18next for i18n in an Expo app with ReadyNative: react-i18next + expo-localization, 6 languages bundled incl. Arabic (RTL) · Expo Go OK

Expo Go: yes

Runs in Expo Go; no dev build needed for this module.

i18next plus react-i18next replace the core i18n shim in src/lib/i18n.ts, keeping exactly the same surface your screens already use: i18n.t(key, vars) and useT(). I'd pick it when you want the ecosystem - plurals, formatters, ICU add-ons, and translators who already know the format. Pick lingui if you'd rather have a CLI-driven catalog workflow, and none while you're still English-only. Keys are the English source strings, so a screen reads identically with or without this module.

Setup

bun run setup --i18n i18next

Six languages ship - English, Spanish, Russian, Chinese (Simplified), Portuguese and Arabic (src/locales/{en,es,ru,zh,pt,ar}.json); the device language wins, and Settings has a language picker that renders from LANGUAGES. To add a locale:

  1. Create src/locales/<code>.json next to the shipped ones (a test checks every locale has the same keys as en.json).
  2. Register it: add the code to LANGUAGES, a native name to LANGUAGE_LABELS and an entry in resources in src/lib/i18n.ts - and to RTL_LANGUAGES if it's written right-to-left (Hebrew, Persian, Urdu). LANGUAGES is the single source of truth - the Settings picker (and /examples/i18n, with --with-examples) render from it.

bun run gen screen --tab appends new tab titles to every locale file (English value, translate later). Locale files are yours: setup/clean never remove them.

Setup also adds expo-localization and its config plugin for the device language, persists the user's override under readynative:language through your storage adapter, registers I18nProvider (order 60), and adds a test (plus the /examples/i18n route with --with-examples).

Usage

import { useT } from "@/lib/i18n";
import { Text } from "@/components/ui";

const t = useT();

<Text>{t("Version {{version}}", { version })}</Text>;

To add a key, write the English sentence in code and add it to every src/locales/*.json. Missing keys fall back to English, then to the key itself.

To switch language at runtime, use setLanguage(code) and read the current one with useLanguage(); deviceLanguage() gives you what the OS reports.

Right-to-left

Arabic is in RTL_LANGUAGES. setLanguage("ar") calls I18nManager.forceRTL(true) and restarts the app with reloadAppAsync(), because React Native applies a new layout direction only on launch; switching back to a left-to-right language does the reverse. Rows, stacks, tab bars and back buttons mirror on their own. On web it flips <html dir> in place, with no restart. isRTL(language) tells you the direction of any language.

  • Expo Go resets the direction whenever it opens a project, so the text turns Arabic but the layout stays left-to-right there - check RTL in a dev build.
  • The expo-localization config plugin keeps supportsRTL on (the default). Set ["expo-localization", { supportsRTL: false }] in your app config if you never ship an RTL language.
  • Write layouts with start/end in mind: marginLeft/paddingRight mirror automatically, absolute left/right positions and direction-bearing icons (arrows, chevrons) need a look.

Gotchas

  • Expo Go works - it's pure JS plus expo-localization.
  • keySeparator and nsSeparator are off, so sentences containing dots or colons are valid keys.
  • On an async storage adapter (async-storage), the stored language is only known after initI18n() resolves - gate first paint on the splash screen if a language flash would show.
  • Swapping stacks: bun run setup --i18n none restores the shim re-export, removes the locales, the example and the three dependencies. Screens keep working - t(key) returns the English key.

Remove it

While modules/ exists (a tree set up with --keep-modules), setup does all of it:

bun run setup --i18n none --yes --keep-modules

In a finalized tree setup is a stub, so you undo it by hand. Here is everything this module added:

  1. Delete the files that are still there (the demo screens are gone already unless you set up with --with-examples): src/app/examples/i18n.tsx, src/lib/__tests__/i18n.test.tsx, src/locales/ar.json, src/locales/en.json, src/locales/es.json, src/locales/pt.json, src/locales/ru.json, src/locales/zh.json, src/screens/examples/i18n-example-screen.tsx.
  2. Replace, don't delete src/lib/i18n.ts: core code imports it, so swap in the no-op version from modules/i18n/none/files/ of a fresh clone of your tier repo - same exports, nothing behind them.
  3. Uninstall the dependencies: bun remove expo-localization i18next react-i18next. Keep any of expo-localization (also used by analytics/posthog, consent/consent) that another module you picked still needs.
  4. Drop the config plugin expo-localization from .readynative.json → modules.app.expo.plugins (that is where app.config.ts reads it from), then rebuild the dev build.
  5. Unwrap the provider: delete <I18nProvider> and its import from src/providers.tsx.
  6. Check it: bun run typecheck and bun run lint point at anything that still imports the removed files; bun run gen:graph refreshes docs/ARCHITECTURE.md.

Reference

Everything below is generated from modules/i18n/i18next/module.json - the same file bun run setup reads, so it is what actually lands in your repo.

Install

bun run setup --i18n i18next

Module id: i18n/i18next (the default for this category).

Dependencies

PackageVersionKind
expo-localization~57.0.2dependency (expo install)
i18next^26.4.2dependency
react-i18next^17.0.15dependency

Config plugins

Merged into app.config.ts through .readynative.json (modules.app):

  • expo-localization

Providers

Rendered in src/providers.tsx (lower order = outermost):

OrderProviderFrom
60I18nProvider@/lib/i18n

Compatibility

Files

10 files copied to the project root
  • src/app/examples/i18n.tsx
  • src/lib/__tests__/i18n.test.tsx
  • src/lib/i18n.ts
  • src/locales/ar.json
  • src/locales/en.json
  • src/locales/es.json
  • src/locales/pt.json
  • src/locales/ru.json
  • src/locales/zh.json
  • src/screens/examples/i18n-example-screen.tsx

On this page

Get ReadyNative