Expo Integration
Learn how to integrate i18next with React Native Expo applications for internationalization.
Integrate i18next with your React Native Expo application to support multiple languages using Lengrise-managed translations, with full support for mobile-specific internationalization features.
Prerequisites
- Expo project (SDK 48+)
- Node.js (v16.0.0+)
- Package manager (npm, yarn, or pnpm)
- Translations downloaded from Lengrise
Pull Translation Files
First, you must pull your translation files from Lengrise API. These files will contain all the translated text for your application.
- Go to the Installation Guide and follow the steps to download your translations
- Place the downloaded JSON files in your project as shown in the project structure below
- Ensure that each language has its own JSON file named with the language code (e.g.,
en.json
,es.json
)
Integration Setup
After downloading your translation files, install the necessary packages:
javascript npm install i18next react-i18next react-native-localize
Project Structure
Configuration Steps
1. Set up i18n Configuration
Create a file at src/localization/i18n.js
:
import i18next from "i18next";
import { initReactI18next } from "react-i18next";
import * as RNLocalize from "react-native-localize";
import { I18nManager } from "react-native";
// Import your translation JSON files
import en from "../../assets/locales/en.json";
import es from "../../assets/locales/es.json";
// Define the supported locales
export const LANGUAGES = {
en: { translation: en, label: "English", isRTL: false },
es: { translation: es, label: "EspaƱol", isRTL: false },
};
// Function to get the device language and use a supported one
export const getDeviceLanguage = () => {
// Get device locales
const deviceLocales = RNLocalize.getLocales();
if (deviceLocales && deviceLocales.length > 0) {
// Get the language tag (e.g., 'en-US' -> 'en')
const languageTag = deviceLocales[0].languageTag.split("-")[0];
// Check if we support this language
if (Object.keys(LANGUAGES).includes(languageTag)) {
return languageTag;
}
}
// Default to English if not supported
return "en";
};
// Set up i18next
i18next.use(initReactI18next).init({
compatibilityJSON: "v3", // Required for Android devices
resources: LANGUAGES,
lng: getDeviceLanguage(),
fallbackLng: "en",
interpolation: {
escapeValue: false, // Not needed for React
},
react: {
useSuspense: false,
},
});
// For RTL support if you have RTL languages
export const setI18nConfig = (language) => {
const isRTL = LANGUAGES[language]?.isRTL || false;
// Set the RTL status for the app
I18nManager.forceRTL(isRTL);
// Set the new language
i18next.changeLanguage(language);
return isRTL;
};
export default i18next;
2. Create a Language Context
Create a file at src/localization/LanguageContext.js
:
import { createContext } from "react";
const LanguageContext = createContext({
language: "en",
setLanguage: () => {},
languages: {},
isRTL: false,
});
export default LanguageContext;
3. Create a Language Provider
Create a file at src/localization/LanguageProvider.js
:
import React, { useState, useEffect } from "react";
import AsyncStorage from "@react-native-async-storage/async-storage";
import * as RNLocalize from "react-native-localize";
import { LANGUAGES, setI18nConfig, getDeviceLanguage } from "./i18n";
import LanguageContext from "./LanguageContext";
const LANGUAGE_STORAGE_KEY = "@app_language";
export const LanguageProvider = ({ children }) => {
const [language, setLanguageState] = useState(getDeviceLanguage());
const [isRTL, setIsRTL] = useState(false);
// Load the saved language from storage on app start
useEffect(() => {
const loadSavedLanguage = async () => {
try {
const savedLanguage = await AsyncStorage.getItem(LANGUAGE_STORAGE_KEY);
if (savedLanguage && Object.keys(LANGUAGES).includes(savedLanguage)) {
const rtlStatus = setI18nConfig(savedLanguage);
setLanguageState(savedLanguage);
setIsRTL(rtlStatus);
}
} catch (error) {
console.error("Failed to load language", error);
}
};
loadSavedLanguage();
// Add listener for device locale changes
const localeChangeListener = RNLocalize.addEventListener("change", () => {
const deviceLang = getDeviceLanguage();
setLanguage(deviceLang);
});
// Clean up listener
return () => {
localeChangeListener.remove();
};
}, []);
// Function to change the app language
const setLanguage = async (newLanguage) => {
try {
if (Object.keys(LANGUAGES).includes(newLanguage)) {
await AsyncStorage.setItem(LANGUAGE_STORAGE_KEY, newLanguage);
const rtlStatus = setI18nConfig(newLanguage);
setLanguageState(newLanguage);
setIsRTL(rtlStatus);
}
} catch (error) {
console.error("Failed to save language", error);
}
};
return (
<LanguageContext.Provider
value={{
language,
setLanguage,
languages: LANGUAGES,
isRTL,
}}
>
{children}
</LanguageContext.Provider>
);
};
export default LanguageProvider;
4. Create a Language Switcher Component
Create a file at src/components/LanguageSwitcher.js
:
import React, { useContext } from "react";
import { View, Text, TouchableOpacity, StyleSheet } from "react-native";
import { useTranslation } from "react-i18next";
import LanguageContext from "../localization/LanguageContext";
const LanguageSwitcher = () => {
const { t } = useTranslation();
const { language, setLanguage, languages } = useContext(LanguageContext);
return (
<View style={styles.container}>
<Text style={styles.label}>{t("settings.language")}</Text>
<View style={styles.buttonContainer}>
{Object.keys(languages).map((langCode) => (
<TouchableOpacity
key={langCode}
style={[
styles.button,
language === langCode && styles.activeButton,
]}
onPress={() => setLanguage(langCode)}
>
<Text
style={[
styles.buttonText,
language === langCode && styles.activeButtonText,
]}
>
{languages[langCode].label}
</Text>
</TouchableOpacity>
))}
</View>
</View>
);
};
const styles = StyleSheet.create({
container: {
marginVertical: 16,
},
label: {
fontSize: 16,
fontWeight: "bold",
marginBottom: 8,
},
buttonContainer: {
flexDirection: "row",
flexWrap: "wrap",
},
button: {
paddingHorizontal: 16,
paddingVertical: 8,
marginRight: 8,
marginBottom: 8,
borderRadius: 4,
backgroundColor: "#f0f0f0",
},
activeButton: {
backgroundColor: "#0066cc",
},
buttonText: {
color: "#333",
},
activeButtonText: {
color: "#fff",
},
});
export default LanguageSwitcher;
5. Update Your App Entry File
Edit your App.js
file to include the language provider:
import React from "react";
import { StatusBar } from "expo-status-bar";
import { SafeAreaProvider } from "react-native-safe-area-context";
import { NavigationContainer } from "@react-navigation/native";
import { createStackNavigator } from "@react-navigation/stack";
// Import screens
import HomeScreen from "./src/screens/HomeScreen";
import SettingsScreen from "./src/screens/SettingsScreen";
// Import language provider
import "./src/localization/i18n"; // Initialize i18next
import LanguageProvider from "./src/localization/LanguageProvider";
const Stack = createStackNavigator();
export default function App() {
return (
<SafeAreaProvider>
<LanguageProvider>
<NavigationContainer>
<Stack.Navigator initialRouteName="Home">
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Settings" component={SettingsScreen} />
</Stack.Navigator>
<StatusBar style="auto" />
</NavigationContainer>
</LanguageProvider>
</SafeAreaProvider>
);
}
6. Create a Settings Screen
Create a file at src/screens/SettingsScreen.js
:
import React from "react";
import { ScrollView, View, StyleSheet } from "react-native";
import { useTranslation } from "react-i18next";
import LanguageSwitcher from "../components/LanguageSwitcher";
const SettingsScreen = () => {
const { t } = useTranslation();
return (
<ScrollView style={styles.container}>
<View style={styles.section}>
<LanguageSwitcher />
</View>
{/* Add other settings here */}
</ScrollView>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
},
section: {
padding: 16,
borderBottomWidth: 1,
borderBottomColor: "#eee",
},
});
export default SettingsScreen;
7. Create Example Translation Files
Create a file at assets/locales/en.json
:
{
"home": {
"welcome": "Welcome to our app",
"description": "This is a multilingual React Native app"
},
"settings": {
"title": "Settings",
"language": "Select Language"
},
"features": {
"title": "Features",
"easy": "Easy to use",
"fast": "Fast translation",
"flexible": "Flexible integration"
},
"buttons": {
"settings": "Settings",
"back": "Back",
"continue": "Continue"
},
"greeting": "Hello, {{name}}!"
}
Create a file at assets/locales/es.json
:
{
"home": {
"welcome": "Bienvenido a nuestra aplicación",
"description": "Esta es una aplicación React Native multilingüe"
},
"settings": {
"title": "Configuración",
"language": "Seleccionar Idioma"
},
"features": {
"title": "CaracterĆsticas",
"easy": "FƔcil de usar",
"fast": "Traducción rÔpida",
"flexible": "Integración flexible"
},
"buttons": {
"settings": "Configuración",
"back": "AtrƔs",
"continue": "Continuar"
},
"greeting": "”Hola, {{name}}!"
}
Using Translations
In Function Components
Use the useTranslation
hook in your functional components:
import React from "react";
import { View, Text, Button, StyleSheet } from "react-native";
import { useTranslation } from "react-i18next";
const HomeScreen = ({ navigation }) => {
const { t } = useTranslation();
return (
<View style={styles.container}>
<Text style={styles.title}>{t("home.welcome")}</Text>
<Text style={styles.description}>{t("home.description")}</Text>
<View style={styles.section}>
<Text style={styles.sectionTitle}>{t("features.title")}</Text>
<Text style={styles.feature}>⢠{t("features.easy")}</Text>
<Text style={styles.feature}>⢠{t("features.fast")}</Text>
<Text style={styles.feature}>⢠{t("features.flexible")}</Text>
</View>
<Text style={styles.greeting}>
{t("greeting", { name: "React Native Developer" })}
</Text>
<Button
title={t("buttons.settings")}
onPress={() => navigation.navigate("Settings")}
/>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: "center",
justifyContent: "center",
padding: 20,
backgroundColor: "#fff",
},
title: {
fontSize: 24,
fontWeight: "bold",
marginBottom: 10,
},
description: {
fontSize: 16,
textAlign: "center",
marginBottom: 20,
},
section: {
width: "100%",
marginBottom: 20,
},
sectionTitle: {
fontSize: 18,
fontWeight: "bold",
marginBottom: 10,
},
feature: {
fontSize: 16,
marginBottom: 5,
},
greeting: {
fontSize: 18,
marginVertical: 20,
},
});
export default HomeScreen;
In Class Components
For class components, use the Higher Order Component (HOC) approach:
import React, { Component } from "react";
import { View, Text, StyleSheet } from "react-native";
import { withTranslation } from "react-i18next";
class ProfileScreen extends Component {
render() {
const { t } = this.props;
return (
<View style={styles.container}>
<Text style={styles.title}>{t("profile.title")}</Text>
{/* Rest of your component */}
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 20,
},
title: {
fontSize: 24,
fontWeight: "bold",
},
});
export default withTranslation()(ProfileScreen);
Date and Number Formatting
For proper date and number formatting, you can use additional libraries:
import { format } from "date-fns";
import { enUS, es } from "date-fns/locale";
// Get the correct locale for date-fns
const getDateLocale = () => {
const language = i18next.language || "en";
switch (language) {
case "es":
return es;
default:
return enUS;
}
};
// Format a date according to the current language
export const formatDate = (date, formatString = "PPP") => {
return format(new Date(date), formatString, {
locale: getDateLocale(),
});
};
Handling Right-to-Left (RTL) Languages
If you plan to support RTL languages like Arabic or Hebrew:
import { View, Text, StyleSheet, I18nManager } from "react-native";
import { useContext } from "react";
import LanguageContext from "../localization/LanguageContext";
const RTLAwareComponent = () => {
const { isRTL } = useContext(LanguageContext);
return (
<View
style={[
styles.container,
{ flexDirection: isRTL ? "row-reverse" : "row" },
]}
>
<Text>First Item</Text>
<Text>Second Item</Text>
</View>
);
};
const styles = StyleSheet.create({
container: {
width: "100%",
justifyContent: "space-between",
},
});
Resources
For more detailed information, check out these resources: