Localization (i18n)
Recommended stack: i18next + react-i18next for translations, with
expo-localization to read the device locale.
// src/shared/config/i18n.ts
import * as Localization from "expo-localization";
import i18n from "i18next";
import { initReactI18next } from "react-i18next";
import en from "@shared/config/locales/en.json";
import es from "@shared/config/locales/es.json";
i18n.use(initReactI18next).init({
lng: Localization.getLocales()[0]?.languageCode ?? "en",
fallbackLng: "en",
resources: { en: { translation: en }, es: { translation: es } },
interpolation: { escapeValue: false },
});
export default i18n;
import { useTranslation } from "react-i18next";
const { t } = useTranslation();
<Text>{t("orders.title")}</Text>;
Conventions:
- Namespace keys by feature (
orders.title,auth.login.cta) so they stay organized as the app grows. - Use keys, not English strings, as ids.
t("orders.empty")is stable;t("You have no orders")breaks the moment the copy changes.
Single-language app? Still route copy through t() with one resources
block. It costs almost nothing now and means adding a second language later is
dropping in another JSON file — not hunting hardcoded strings across the app.