Internationalization

Configure English and Simplified Chinese localization.

The Expo template localizes product UI with i18n-js and expo-localization. It ships English and Simplified Chinese catalogs, exposes a small useI18n() hook, and lets users change language from the Profile screen.

Key files

i18n.tsx
app/_layout.tsx

I18nProvider is mounted inside the root provider stack and exposes:

APIPurpose
t(key, options?)Translate catalog keys through i18n-js
localeCurrent supported locale, en or zh
setLocale(locale)Persist and apply a language override

The provider returns null until it hydrates the saved preference, which avoids rendering the app in one language and immediately switching to another.

Locale persistence

Language is stored under app_locale. Native platforms use expo-secure-store; web uses window.localStorage. The code imports expo-localization and computes the device language with Localization.getLocales()?.[0]?.languageTag.

In the current template code, getStoredLocale() normalizes a missing stored value to en, so device-locale detection does not actually win on a fresh install. If you want first launch to follow the device language, return null when app_locale is absent and fall back to the device locale after that.

Add a language

Add the catalog

Create lib/i18n/<locale>.json with the same key shape as en.json and zh.json.

Register it in lib/i18n.tsx

Import the JSON file, add it to translations, and update any user-facing language labels.

Normalize the locale

Extend normalizeLocale() if the language needs aliases such as pt-BR, zh-Hant, or region-specific fallback behavior.

Add the picker option

app/profile.tsx defines the language picker rows. Add the new option there so users can persist the override.

Verify both platforms

Run native and web, switch language from Profile, kill and relaunch the app, and confirm the selected locale survives.

What is localized

Most app surfaces call t(...): auth, profile, Home, drawer labels, todos, paywall/subscription, legal consent, permissions, notifications, showcase catalog rows, and showcase demo screens.

The Component gallery is intentionally English-only. Its catalog comment says copy lives as plain strings in lib/component/component-catalog.ts, and the detail demos in app/component/[slug].tsx also use inline English labels. Treat that tab as a developer-facing reference unless you decide to move those strings into the catalogs.

There are a few inline operational toasts such as password-reset success copy in auth routes. Search for string literals in app/ before claiming complete app localization.

On this page