React Native Flow

App Features

Multilingual app

The `languageConfig` folder helps your Expo or React Native CLI app support many languages. It uses i18next, includes 25 ready-made language files, starts from the phone’s language, and adds an easy way to switch language and right-to-left (RTL) layout. With Expo Router you connect it in `app/_layout.tsx`. With React Native CLI you usually only change the localization wiring in your root `App.tsx`—navigation and screens can stay as they are. Download the ZIP, unzip it next to your code (for example in `src/`), then follow the steps below.

Demo video

Short screen recording showing the language starter in the app: changing locale, RTL layout, and translated UI strings.

Download

The ZIP contains the full `languageConfig` folder. On Mac you may see an extra `__MACOSX` folder—you can ignore it. After unzipping you should have one main folder named `languageConfig`.

Folder layout

languageConfig/
├── config.ts
├── languages.ts
├── context/
│   └── LanguageContext.tsx
├── i18n/
│   └── index.ts
└── locales/
    ├── ar.json … zh.json (25 languages)

What each file is for

  • config.ts Passes through the helpers from `languages.ts`. You can import from `config` or `languages`, whichever you prefer.
  • languages.ts Lists supported languages, knows which ones are right-to-left (RTL), and includes data for a language picker (flag, native name, English name).
  • i18n/index.ts Sets up i18next: loads each JSON file, starts with the device language, falls back to English, and connects `react-i18next` for React Native.
  • context/LanguageContext.tsx Provides `LanguageProvider`: shares the current language and RTL flag, saves the user’s choice, and offers `setLanguage` to switch languages. It expects storage helpers from your project—change the import path if yours is different.
  • locales/*.json One JSON file per language. Each key is a text ID for your UI. i18next loads them under the `translation` namespace.

Dependencies

Install these packages in your Expo or React Native CLI project if they are not already there:

  • i18next
  • react-i18next
  • expo-localization

Connect it in a few steps

  1. Copy or unzip `languageConfig` into your project (for example `src/languageConfig`).
  2. Install: `i18next`, `react-i18next`, and `expo-localization`.
  3. Wrap your root layout (or `App`) with `LanguageProvider` from `languageConfig/context/LanguageContext.tsx`.
  4. In your screens, use `useTranslation()` from `react-i18next` and use keys from your JSON files.

Example: wire up your root file

Keep `languageConfig` next to your main app file—for example `src/languageConfig` beside `src/app/_layout.tsx` (Expo Router) or `src/App.tsx` (CLI). If your folders look different, change the import paths to match.

If you use shortcuts like `@/languageConfig/...`, use those instead of `../languageConfig` or `./languageConfig`.

Expo Router — `app/_layout.tsx`

Import the i18n file once, wrap everything in `LanguageProvider`, and use `useAppLanguage` so the root `View` can switch to RTL when needed. Keep `LanguageProvider` outside `Stack` so all screens use the same language state.

import { Stack } from 'expo-router';
import { StatusBar } from 'expo-status-bar';
import React from 'react';
import { StyleSheet, View } from 'react-native';
import 'react-native-reanimated';
import { LanguageProvider, useAppLanguage } from '../languageConfig/context/LanguageContext';
import '../languageConfig/i18n';

function RootLayoutContent() {
  const { isRtl } = useAppLanguage();

  return (
    <View style={[styles.root, isRtl && { direction: 'rtl' }]}>
      <Stack>
        <Stack.Screen name="index" />
      </Stack>
      <StatusBar style="auto" />
    </View>
  );
}

export default function RootLayout() {
  return (
    <LanguageProvider>
      <RootLayoutContent />
    </LanguageProvider>
  );
}

const styles = StyleSheet.create({
  root: {
    flex: 1,
  },
});

React Native CLI — `App.tsx`

On React Native CLI you usually only change the localization part of your root file—same steps as below (import i18n once, wrap with `LanguageProvider`, use `useAppLanguage` in an inner component). The rest of your app can stay as it is. Replace the sample `NavigationContainer` with your real navigator.

import React from 'react';
import { StyleSheet, View } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { LanguageProvider, useAppLanguage } from './languageConfig/context/LanguageContext';
import './languageConfig/i18n';
// import your root navigator

function AppShell() {
  const { isRtl } = useAppLanguage();

  return (
    <View style={[styles.root, isRtl && { direction: 'rtl' }]}>
      <NavigationContainer>{/* <RootNavigator /> */}</NavigationContainer>
    </View>
  );
}

export default function App() {
  return (
    <LanguageProvider>
      <AppShell />
    </LanguageProvider>
  );
}

const styles = StyleSheet.create({
  root: {
    flex: 1,
  },
});

Simple recap: your root file

Here is the same pattern as the code samples above, in simple terms. Expo Router and React Native CLI use slightly different import paths, but the steps are the same. On CLI, you typically only touch this localization block in your root file.

  • Import `languageConfig/i18n` once at the top of your root file. That file starts i18next, loads all translation JSON files, reads the device language with expo-localization, and uses English when a translation is missing.
  • Wrap your whole app with `LanguageProvider` from `languageConfig/context/LanguageContext.tsx`. Put it above your navigator (`Stack`, `NavigationContainer`, and so on) so every screen shares the same language and the saved user choice.
  • In a child component, call `useAppLanguage()` and set the root `View` to `direction: 'rtl'` when the user picks a RTL language (for example Arabic). You write this once instead of copying it into every screen.
  • On normal screens, use `useTranslation()` from `react-i18next` for your text. The root file only sets up i18n, the provider, and the overall layout direction.

Sponsored

Quick promo