# react-native: React Native Quickstart with Expo
URL: https://generaltranslation.com/en-US/docs/react-native/tutorials/quickstart-expo.mdx
---
title: React Native Quickstart with Expo
description: Add multiple languages to your Expo app in under 10 minutes
---
By the end of this guide, your Expo app will display content in multiple languages, with a language switcher your users can interact with.
**Prerequisites:**
- An Expo project (SDK 49+)
- Node.js 18+
`gt-react-native` is still experimental and may not work for all projects.
Please let us know if you encounter any issues by [opening an issue on GitHub](https://github.com/generaltranslation/gt/issues).
**Want automatic setup?** Run `npx gt@latest` to configure everything with the [Setup Wizard](/docs/cli/init). This guide covers manual setup.
Looking for a bare React Native CLI project? See the [React Native Quickstart](/docs/react-native/tutorials/quickstart).
---
## Step 1: Install the packages
`gt-react-native` is the library that powers translations in your app. `gt` is the CLI tool that prepares translations for production.
```bash
npm i gt-react-native
npm i -D gt
```
```bash
yarn add gt-react-native
yarn add --dev gt
```
```bash
bun add gt-react-native
bun add --dev gt
```
```bash
pnpm add gt-react-native
pnpm add --save-dev gt
```
---
## Step 2: Create a translation config file
Create a **`gt.config.json`** file in your project root. This tells the library which languages you support:
```json title="gt.config.json"
{
"defaultLocale": "en",
"locales": ["es", "fr", "ja"],
"files": {
"gt": {
"output": "content/[locale].json"
}
}
}
```
- **`defaultLocale`** — the language your app is written in (your source language).
- **`locales`** — the languages you want to translate into. Pick any from the [supported locales list](/docs/platform/supported-locales).
- **`files.gt.output`** — where the CLI saves translation files. `[locale]` is replaced with each language code (e.g., `content/es.json`).
---
## Step 3: Set up polyfills
React Native's JavaScript runtime doesn't include the `Intl` APIs that `gt-react-native` needs. The easiest fix is the included Babel plugin.
Add it to your Babel config:
```js title="babel.config.js"
import gtPlugin from 'gt-react-native/plugin';
import { createRequire } from 'module';
import gtConfig from './gt.config.json' with { type: 'json' };
const require = createRequire(import.meta.url);
export default function (api) {
api.cache(true);
return {
presets: ['babel-preset-expo'],
plugins: [
[
gtPlugin,
{
locales: [gtConfig.defaultLocale, ...gtConfig.locales],
entryPointFilePath: require.resolve('expo-router/entry'),
},
],
],
};
}
```
Install the FormatJS polyfills and import them at the top of your entry file. You need base polyfills plus locale-specific data for each language you support.
See [FormatJS's polyfill documentation](https://formatjs.github.io/docs/polyfills) for the full list. At minimum you need:
```tsx title="index.js"
import '@formatjs/intl-getcanonicallocales/polyfill';
import '@formatjs/intl-locale/polyfill';
import '@formatjs/intl-pluralrules/polyfill-force';
import '@formatjs/intl-numberformat/polyfill';
import '@formatjs/intl-datetimeformat/polyfill';
import '@formatjs/intl-datetimeformat/add-all-tz';
// Add locale data for each language:
import '@formatjs/intl-pluralrules/locale-data/en';
import '@formatjs/intl-pluralrules/locale-data/es';
import '@formatjs/intl-numberformat/locale-data/en';
import '@formatjs/intl-numberformat/locale-data/es';
// ... repeat for each locale and polyfill
```
---
## Step 4: Create a translation loader
Metro (Expo's bundler) doesn't support dynamic imports, so you need to explicitly map each locale to its translation file:
```ts title="loadTranslations.ts"
const translations: Record = {
es: require("@/content/es.json"),
fr: require("@/content/fr.json"),
ja: require("@/content/ja.json"),
};
export function loadTranslations(locale: string) {
return translations[locale] ?? {};
}
```
These files are generated by the CLI when you run `npx gt translate`.
---
## Step 5: Add the GTProvider to your layout
The **`GTProvider`** component gives your entire app access to translations. Add it to your root layout:
```tsx title="app/_layout.tsx"
import { Slot } from 'expo-router';
import { GTProvider } from 'gt-react-native';
import gtConfig from '../gt.config.json';
import { loadTranslations } from '../loadTranslations';
export default function RootLayout() {
return (
);
}
```
`GTProvider` manages locale state and makes translations available to all child components. The `devApiKey` prop enables on-demand translation during development.
---
## Step 6: Mark content for translation
Wrap any text you want translated with the **``** component:
```tsx title="app/index.tsx"
import { Text, View } from 'react-native';
import { T } from 'gt-react-native';
export default function Home() {
return (
Welcome to my app
This content will be translated automatically.
);
}
```
Everything inside `` gets translated as a unit.
---
## Step 7: Add a language switcher
Drop in a **``** so users can change languages:
```tsx title="app/index.tsx"
import { Text, View } from 'react-native';
import { T, LocaleSelector } from 'gt-react-native';
export default function Home() {
return (
Welcome to my app
);
}
```
`LocaleSelector` renders a picker populated with the languages from your `gt.config.json`.
---
## Step 8: Set up environment variables (optional)
To see translations in development, you need API keys from General Translation.
Create a **`.env.local`** file. Expo requires public env vars to be prefixed with `EXPO_PUBLIC_`:
```bash title=".env.local"
EXPO_PUBLIC_GT_DEV_API_KEY="your-dev-api-key"
EXPO_PUBLIC_GT_PROJECT_ID="your-project-id"
```
Get your free keys at [dash.generaltranslation.com](https://dash.generaltranslation.com/signup) or by running:
```bash
npx gt auth
```
For development, use a key starting with `gtx-dev-`. Production keys (`gtx-api-`) are for CI/CD only.
Never expose production API keys in your app bundle or commit them to source control.
Yes. Without API keys, `gt-react-native` works as a standard i18n library. You won't get on-demand translation in development, but you can still:
- Provide your own translation files manually
- Use all components (``, ``, `LocaleSelector`, etc.)
- Run `npx gt generate` to create translation file templates, then translate them yourself
---
## Step 9: See it working
Start your development build:
```bash
npx expo start --dev-client
```
**Expo Go does not work** with `gt-react-native` because it includes a native module. You need a [development build](https://docs.expo.dev/develop/development-builds/introduction/):
```bash
npx expo run:ios
# or
npx expo run:android
```
Use the language picker to switch languages. You should see your content translated.
In development, translations happen on-demand — you may see a brief loading state the first time you switch to a new language. In production, translations are pre-generated and load instantly.
---
## Step 10: Translate strings (not just JSX)
For plain strings — like `placeholder` attributes or `accessibilityLabel` values — use the **`useGT`** hook:
```tsx title="app/contact.tsx"
import { TextInput, View } from 'react-native';
import { useGT } from 'gt-react-native';
export default function Contact() {
const gt = useGT();
return (
);
}
```
---
## Step 11: Deploy to production
In production, translations are pre-generated at build time (no real-time API calls). Add the translate command to your build script:
```json title="package.json"
{
"scripts": {
"build": "npx gt translate && "
}
}
```
Set your **production** environment variables in your CI/CD (these are server-side only, not `EXPO_PUBLIC_`):
```bash
GT_PROJECT_ID=your-project-id
GT_API_KEY=gtx-api-your-production-key
```
Production keys start with `gtx-api-` (not `gtx-dev-`). Get one from [dash.generaltranslation.com](https://dash.generaltranslation.com). Never expose production keys in your app bundle.
That's it — your app is now multilingual. 🎉
---
## Troubleshooting
```
ERROR [Invariant Violation: TurboModuleRegistry.getEnforcing(...): 'GtReactNative' could not be found.]
```
This means the native module hasn't been linked. Common causes:
1. **You're using Expo Go** instead of a development build. Switch to a dev build:
```bash
npx expo run:ios
# or
npx expo run:android
```
2. **Pods are out of date (iOS).** Try reinstalling:
```bash
cd ios && rm -rf build Pods Podfile.lock && pod install && cd ..
```
```
Error: You are using invalid locale codes in your configuration.
```
This typically means polyfills aren't set up correctly. Make sure the Babel plugin is configured (or manual polyfills are imported) and clear the cache:
```bash
npx expo start --clear
```
This is expected. In development, translations happen on-demand (your content is translated in real time via the API). This delay **does not exist in production** — all translations are pre-generated by `npx gt translate`.
Ambiguous text can lead to inaccurate translations. For example, "apple" could mean the fruit or the company. Add a `context` prop to help:
```jsx
Apple
```
Both `` and `useGT()` support the `context` option.
---
## Next steps
- [**`` Component Guide**](/docs/react-native/guides/t) — Learn about variables, plurals, and advanced translation patterns
- [**String Translation Guide**](/docs/react-native/guides/strings) — Deep dive into `useGT`
- [**Variable Components**](/docs/react-native/guides/variables) — Handle dynamic content with ``, ``, ``, and ``
- [**Deploying to Production**](/docs/react-native/tutorials/quickdeploy) — CI/CD setup, caching, and performance optimization