i18n in React Native with Expo
Tags: i18next, i18n, react, reactnative
Published: 2024-06-27 01:43:47

---
title: i18n in React Native with Expo
published: true
description: This article is about implementing i18n in a React Native app with react-i18next
tags: i18next, i18n, react, reactnative
# cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/57kzjdm4nupsf4jiy45v.jpg
# Use a ratio of 100:42 for best results.
---

## Project on Github
To make this article comprehensive, I have created a repository with a real application where you can analyze the code and see the complete implementation of the examples mentioned. Visit the repository on GitHub: [app-internationalization](https://github.com/livresaber/app-internationalization).

![Image app-internationalization in chinese](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y66pc6xfxx19x2u7g9a1.jpeg)![Image app-internationalization in Portuguese of Brazilian](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sjh0bg3c9kk5fv1zkwc0.jpeg)![Image app-internationalization in English](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f15xe575a2fmanjjeb9y.jpeg)

## First, install the Libraries

You need to install the necessary libraries for react-i18next, i18next, and expo-localization.

```bash
npx expo install expo-localization react-i18next i18next
```

In this example, I use AsyncStorage, so you'll need to install it as well. However, if you use another solution to persist the data, feel free to replace it accordingly.

```bash
npx expo install @react-native-async-storage/async-storage
```

Now, create the configuration file in your src directory. Create a file named `./i18n/index.ts` with the content below:

```ts
import i18n from "i18next";
import { initReactI18next } from "react-i18next";
import * as Localization from "expo-localization";
import AsyncStorage from "@react-native-async-storage/async-storage";
import translationEn from "./locales/en-US/translation.json";
import translationPt from "./locales/pt-BR/translation.json";
import translationZh from "./locales/zh-CN/translation.json";

const resources = {
  "pt-BR": { translation: translationPt },
  "en-US": { translation: translationEn },
  "zh-CN": { translation: translationZh },
};

const initI18n = async () => {
  let savedLanguage = await AsyncStorage.getItem("language");

  if (!savedLanguage) {
    savedLanguage = Localization.locale;
  }

  i18n.use(initReactI18next).init({
    compatibilityJSON: "v3",
    resources,
    lng: savedLanguage,
    fallbackLng: "pt-BR",
    interpolation: {
      escapeValue: false,
    },
  });
};

initI18n();

export default i18n;
```

In this example, I am using AsyncStorage to persist the internationalization data in case the user manually changes the language. Additionally, the configuration with expo-localization is used to get the device's current language.

## Import the i18n File in your root App
"I use it in `_layout.tsx`, but if your root file is `index.ts` or another file, you need to import it in that root file instead."
Example import in the file `_layout.tsx` of the root App:

```tsx
import { useEffect } from 'react';
import { DarkTheme, DefaultTheme, ThemeProvider } from '@react-navigation/native';
import { useFonts } from 'expo-font';
import { Stack } from 'expo-router';
import * as SplashScreen from 'expo-splash-screen';
import 'react-native-reanimated';
import '@/i18n'; // This line imports the i18n configuration
import { useColorScheme } from '@/hooks/useColorScheme';

export default function RootLayout() {
  const colorScheme = useColorScheme();
  const [loaded] = useFonts({
    SpaceMono: require('../assets/fonts/SpaceMono-Regular.ttf'),
  });

  useEffect(() => {
    if (loaded) {
      SplashScreen.hideAsync();
    }
  }, [loaded]);

  if (!loaded) {
    return null;
  }

  return (
    <ThemeProvider value={colorScheme === 'dark' ? DarkTheme : DefaultTheme}>
      <Stack>
        <Stack.Screen name="(tabs)" options={{ headerShown: false }} />
        <Stack.Screen name="+not-found" />
      </Stack>
    </ThemeProvider>
  );
}
```

Now you need to create your translation files and use them in your components.

## Create files for translated locales

In the i18n folder, create a folder named **locales**. Inside the **locales** folder, create subfolders for each locale, such as **en-US**, **pt-BR**, or **zh-CN**. Inside each subfolder, create a JSON file named `translation.json` with your translation entries. Below are examples of these JSON files.

name file: `./i18n/locales/en-US/translation.json`
```json
{
  "language": "Language",
  "home": {
    "title": "Home",
    "welcome": "Welcome",
    "subtitle": "Example i18n App!",
    "description": "This is an example React Native application demonstrating how to implement internationalization (i18n) using react-i18next. The app allows users to switch between different languages for a more localized experience.",
    "exploringLanguages": "Exploring Languages",
    "exploringLanguagesDescription": "Click on country flags to explore the app's content in different languages.",
    "learnMore": "Want to Learn More?",
    "repositoryLinkText": "Project repository on GitHub",
    "articlesLinkText": "More articles"
  },
  "features": {
    "title": "Features",
    "collapsibles": {
      "i18n": {
        "title": "Internationalization with i18next",
        "description": "Uses react-i18next for language management, allowing the app to be localized for different languages."
      },
      "persistent": {
        "title": "Persistent Language Selection",
        "description": "Uses AsyncStorage to persistently store the user's preferred language, providing a consistent experience across app restarts."
      },
      "fallback": {
        "title": "Language Fallback",
        "description": "Defaults to the device's language if no language preference is saved."
      },
      "switching": {
        "title": "Easy Language Switching",
        "description": "Users can switch languages by tapping on country flags."
      }
    }
  }
}
```

name file: `./i18n/locales/pt-BR/translation.json`
```json
{
  "language": "Idioma",
  "home": {
    "title": "Início",
    "welcome": "Bem-vindo",
    "subtitle": "App de Exemplo com i18n!",
    "description": "Este é um exemplo de aplicativo React Native que demonstra como implementar internacionalização (i18n) usando react-i18next. O aplicativo permite aos usuários alternar entre diferentes idiomas para uma experiência mais localizada.",
    "exploringLanguages": "Explorando Idiomas",
    "exploringLanguagesDescription": "Clique nas bandeiras dos países para explorar o conteúdo do aplicativo em diferentes idiomas.",
    "learnMore": "Quer Saber Mais?",
    "repositoryLinkText": "O repositório do projeto no GitHub",
    "articlesLinkText": "Mais artigos"
  },
  "features": {
    "title": "Funcionalidades",
    "collapsibles": {
      "i18n": {
        "title": "Internacionalização com i18next",
        "description": "Utiliza react-i18next para gerenciamento de idiomas, permitindo que o aplicativo seja localizado para diferentes idiomas."
      },
      "persistent": {
        "title": "Seleção de Idioma Persistente",
        "description": "Utiliza AsyncStorage para armazenar persistentemente o idioma preferido do usuário, proporcionando uma experiência consistente ao reiniciar o aplicativo."
      },
      "fallback": {
        "title": "Fallback de Idioma",
        "description": "Padrão para o idioma do dispositivo se nenhuma preferência de idioma for salva."
      },
      "switching": {
        "title": "Troca Fácil de Idioma",
        "description": "Os usuários podem trocar de idioma tocando nas bandeiras dos países."
      }
    }
  }
}
```

name file: `./i18n/locales/zh-CN/translation.json`
```json
{
  "language": "语言",
  "home": {
    "title": "开始",
    "welcome": "欢迎",
    "subtitle": "i18n示例应用！",
    "description": "这是一个使用react-i18next实现国际化（i18n）的React Native示例应用。该应用允许用户在不同语言之间切换，以提供更本地化的体验。",
    "exploringLanguages": "探索语言",
    "exploringLanguagesDescription": "点击国家旗帜以在不同语言下探索应用内容。",
    "learnMore": "想了解更多？",
    "repositoryLinkText": "GitHub上的项目仓库",
    "articlesLinkText": "更多文章"
  },
  "features": {
    "title": "功能",
    "collapsibles": {
      "i18n": {
        "title": "使用i18next进行国际化",
        "description": "使用react-i18next进行语言管理，使应用程序能够在不同语言环境下本地化。"
      },
      "persistent": {
        "title": "持久化语言选择",
        "description": "使用AsyncStorage持久化存储用户的首选语言，提供应用重启后的一致体验。"
      },
      "fallback": {
        "title": "语言回退

",
        "description": "如果未保存语言首选项，则默认使用设备的语言。"
      },
      "switching": {
        "title": "简便的语言切换",
        "description": "用户可以通过点击国家旗帜来切换语言。"
      }
    }
  }
}
```

Excellent! Now you have translation files for English, Portuguese, and Chinese.

## Use your translations in components

Now, you need to use the translations in your components and create a list of flags for changing the locale using the **useTranslation** hook.

```tsx
// import hook
import { useTranslation } from "react-i18next";

// inside a component 
const { t } = useTranslation();
const text = t('example.text');

```

An example of basic usage in a real component:

```tsx
import React, { useEffect } from "react";
import { StyleSheet, View, ScrollView, TouchableOpacity } from "react-native";
import AsyncStorage from "@react-native-async-storage/async-storage";
import { ThemedText } from "@/components/ThemedText";
import { useTranslation } from "react-i18next";
import Brasil from "./flags/Brasil";
import USA from "./flags/USA";
import China from "./flags/China";

const flags = [
  { component: Brasil, lang: "pt-BR", name: "Brasil" },
  { component: USA, lang: "en-US", name: "USA" },
  { component: China, lang: "zh-CN", name: "China" },
];

export function Language() {
  const { i18n, t } = useTranslation();
  const currentLanguage = i18n.language;

  useEffect(() => {
    const loadLanguage = async () => {
      const savedLanguage = await AsyncStorage.getItem("language");
      if (savedLanguage) {
        i18n.changeLanguage(savedLanguage);
      }
    };
    loadLanguage();
  }, [i18n]);

  const changeLanguage = async (lang: string) => {
    await AsyncStorage.setItem("language", lang);
    i18n.changeLanguage(lang);
  };

  return (
    <View style={styles.container}>
      <ThemedText style={styles.text}>{t('language')}</ThemedText>
      <ScrollView
        horizontal
        showsHorizontalScrollIndicator={false}
        contentContainerStyle={styles.flagsContainer}
      >
        {flags.map(({ component: Flag, lang, name }) => (
          <TouchableOpacity
            key={name}
            onPress={() => changeLanguage(lang)}
            style={[
              styles.flag,
              currentLanguage === lang && styles.activeFlag,
              currentLanguage !== lang && styles.inactiveFlag,
            ]}
          >
            <Flag width={45} height={45} />
          </TouchableOpacity>
        ))}
      </ScrollView>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    justifyContent: "center",
  },
  flagsContainer: {
    flexDirection: "row",
    paddingVertical: 10,
  },
  flag: {
    paddingHorizontal: 10,
  },
  activeFlag: {
    transform: [{ scale: 1.2 }],
  },
  inactiveFlag: {
    opacity: 0.5,
  },
  text: {
    fontSize: 22,
    lineHeight: 32,
    marginTop: -6,
  },
});
```

Finished! You now have a React Native app with internationalization support for multiple languages, accessible to people around the world. Happy coding and enjoy your #hacktoberfest!

## References

If you need references, check out the links below for more examples:
- The source of the app implementation on [GitHub](https://github.com/livresaber/app-internationalization)
- My profile on LinkedIn: [Lucas Ferreira Lima](https://www.linkedin.com/in/lucasferreiralimax)
- My profile on GitHub: [@lucasferreiralimax](https://github.com/lucasferreiralimax)
- The official site: [react-i18next](https://react.i18next.com)
- React Native: [reactnative.dev](https://reactnative.dev)
- Expo: [expo.dev](https://expo.dev/)


## Need Help?

Comment or get in touch with me. I'd be happy to help, and it was nice to meet you.