# Getting Started

i18next integration for Expo and React Native with offline caching and instant language switching

## Overview

`@better-i18n/expo` is an i18next integration that pre-loads translations from the better-i18n CDN. It plugs into your existing i18next + react-i18next setup with zero native modules — meaning it works in **Expo Go** out of the box.

- **Pre-loaded translations** — CDN fetch, caching, and namespace discovery handled automatically
- **Offline-first** — Persistent caching via MMKV or AsyncStorage with network-first strategy
- **Expo Go compatible** — Pure JavaScript, no native modules required
- **Device locale detection** — Auto-detect via expo-localization

<Callout type="info">
  `initBetterI18n` handles everything — CDN fetch, caching, namespace discovery, and language switching. Your existing `useTranslation()` calls stay exactly the same.
</Callout>

<Callout type="tip">
  **Integrating with AI?** Run `npx skills add better-i18n/skills` first — your agent (Cursor, Claude Code, or Windsurf) will already know the SDK patterns, CDN behavior, and key conventions. Then just ask it to set up the integration for you. [Learn more →](/mcp/agent-skill)
</Callout>

## Features

<Cards>
  <Card title="Works in Expo Go" icon="Smartphone">
    Pure JS implementation — no native modules, no dev client required.
  </Card>
  <Card title="Offline Support" icon="WifiOff">
    Persistent caching ensures translations are always available, even without network.
  </Card>
  <Card title="Pluggable Storage" icon="Database">
    Uses MMKV by default, falls back to AsyncStorage, or any custom key-value store.
  </Card>
  <Card title="Device Locale" icon="Globe">
    Auto-detect the user's language via expo-localization.
  </Card>
  <Card title="Instant Language Switching" icon="Zap">
    Translations are pre-loaded before the switch happens — no English flash or loading spinners.
  </Card>
</Cards>

## Quick Start

```ts title="i18n.ts"
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import { initBetterI18n } from '@better-i18n/expo'; // [!code highlight]

i18n.use(initReactI18next); // [!code highlight]

export const { languages } = await initBetterI18n({ // [!code highlight]
  project: 'your-org/your-project', // [!code highlight]
  i18n,
  defaultLocale: 'en',
  debug: __DEV__,
});
```

```tsx title="App.tsx"
import './i18n';
import { useTranslation } from 'react-i18next';
import { Text } from 'react-native';

function HomeScreen() {
  const { t } = useTranslation();
  return <Text>{t('welcome')}</Text>;
}
```

## Production-Ready Setup

The Quick Start above works for development, but production mobile apps need **offline fallback**. Your app's translations come from the CDN at runtime — if the CDN is unreachable (airplane mode, slow network, or App Store Review), you need a safety net.

<Callout type="warn">
  **App Store Review risk:** Apple reviewers may test your app in environments where CDN calls timeout. Without offline fallback, your app shows raw keys like `common.button.save` — and gets rejected as "incomplete."
</Callout>

Add two things: **persistent storage** (caches translations on device) and **bundled translations** (last-resort fallback shipped in your app binary).

```ts title="i18n.ts"
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import { MMKV } from 'react-native-mmkv';
import { initBetterI18n, storageAdapter } from '@better-i18n/expo';

// Generated by: npx @better-i18n/cli pull
import en from './locales/en.json'; // [!code highlight]
import tr from './locales/tr.json'; // [!code highlight]

const mmkv = new MMKV({ id: 'i18n' });
i18n.use(initReactI18next);

export const i18nReady = initBetterI18n({
  project: 'your-org/your-project',
  i18n,
  defaultLocale: 'en',
  useDeviceLocale: true,
  storage: storageAdapter(mmkv, { localeKey: '@app:locale' }), // [!code highlight]
  staticData: { en, tr }, // [!code highlight]
});
```

**How it works:**
1. **CDN available** — Your app uses the freshest translations
2. **CDN unavailable, has cache** — Falls back to previously cached translations (MMKV)
3. **First launch, no network** — Falls back to bundled `staticData` from your locale files

Keep your bundled translations in sync by running `pull` before each build:

```bash
npx @better-i18n/cli pull -o ./locales
```

Add this to your CI/CD (e.g., `eas-build-pre-install.sh`) so it runs automatically. [Learn more about offline caching →](/frameworks/expo/offline-caching)

## Guide

<Cards>
  <Card title="Setup" icon="Settings" href="/frameworks/expo/setup">
    Installation, configuration, and language switching.
  </Card>
  <Card title="Offline & Caching" icon="WifiOff" href="/frameworks/expo/offline-caching">
    How persistent caching and offline fallback works.
  </Card>
  <Card title="Dynamic CFBundleLocalizations" icon="Globe" href="/frameworks/expo/dynamic-localizations">
    Sync iOS locale support automatically from your CDN manifest.
  </Card>
  <Card title="API Reference" icon="FileCode" href="/frameworks/expo/api-reference">
    Complete API documentation for all exports.
  </Card>
</Cards>

## Comparison

| Feature | Expo | Vite | TanStack Start | Next.js |
|---------|------|------|----------------|---------|
| Rendering | Client | Client | Client + SSR | Client + SSR |
| i18n library | i18next | use-intl | use-intl | next-intl |
| Offline support | Built-in | Manual | Manual | Manual |
| Expo Go | Yes | N/A | N/A | N/A |
| Persistent cache | MMKV / AsyncStorage | N/A | N/A | N/A |

Choose Expo for React Native / Expo apps. For web apps, see [Vite](/frameworks/vite), [TanStack Start](/frameworks/tanstack-start), or [Next.js](/frameworks/nextjs).


## AI Tooling

Now that you've integrated the SDK, your AI agent can check coverage, translate keys, and publish — all without leaving your editor.

<Cards>
  <Card title="MCP Server" icon="Bot" href="/mcp/getting-started">
    Translate keys, check coverage, and publish — all from your editor via Cursor, Claude Code, or Windsurf.
  </Card>
  <Card title="Agent Skill" icon="Sparkles" href="/mcp/agent-skill">
    Permanent better-i18n knowledge for your AI agent — SDK patterns, CDN behavior, key conventions. No prompts needed each session.
  </Card>
</Cards>