Complete Guide to React Native Internationalization (i18n)
Learn how to implement internationalization in your React Native app using react-i18next
Complete Guide to React Native Internationalization (i18n)
In today’s global app marketplace, supporting multiple languages isn’t just a nice-to-have—it’s essential. Let’s explore how to implement internationalization (i18n) in React Native, making your app accessible to users worldwide! 🌎
What is i18n?
Internationalization (i18n) helps adapt your app for different languages and regions. The term “i18n” comes from the word “internationalization” - there are 18 letters between the ‘i’ and the ‘n’!
Setting Up i18n in React Native
1. Installation
First, let’s install the necessary packages:
yarn add i18next react-i18next
# or
npm install i18next react-i18next
2. Creating Language Files
Create a languages
folder with JSON files for each language:
// languages/en.json
{
"translation": {
"welcome": "Welcome",
"choose": "Select a language",
"name": "Name",
"portuguese": "Portuguese",
"english": "English",
"spanish": "Spanish"
}
}
// languages/es.json
{
"translation": {
"welcome": "Bienvenido",
"choose": "Seleccione un idioma",
"name": "Nombre",
"portuguese": "Portugués",
"english": "Inglés",
"spanish": "Español"
}
}
// languages/pt.json
{
"translation": {
"welcome": "Seja Bem-Vindo",
"choose": "Selecione um idioma",
"name": "Nome",
"portuguese": "Português",
"english": "Inglês",
"spanish": "Espanhol"
}
}
3. Configuring i18n
Create an i18n.ts
configuration file:
import i18n from "i18next";
import { initReactI18next } from "react-i18next";
import en from "./languages/en.json";
import es from "./languages/es.json";
import pt from "./languages/pt.json";
const resources = {
en,
es,
pt,
};
i18n.use(initReactI18next).init({
compatibilityJSON: "v3",
resources,
lng: "en", // default language
fallbackLng: "en",
interpolation: {
escapeValue: false,
},
});
export default i18n;
Implementation Methods
Let’s look at three different ways to implement language selection in your app:
1. Manual Language Selection with Dropdown
import React, { useState } from "react";
import { View, Text } from "react-native";
import { useTranslation } from "react-i18next";
import DropDownPicker from "react-native-dropdown-picker";
export default function LanguageSelector() {
const { t, i18n } = useTranslation();
const [open, setOpen] = useState(false);
const [value, setValue] = useState(i18n.language);
const [items] = useState([
{ label: "English", value: "en" },
{ label: "Español", value: "es" },
{ label: "Português", value: "pt" },
]);
return (
<View style={styles.container}>
<Text style={styles.title}>{t("choose")}</Text>
<DropDownPicker
open={open}
value={value}
items={items}
setOpen={setOpen}
setValue={setValue}
onChangeValue={(value) => {
i18n.changeLanguage(value);
}}
style={styles.dropdown}
/>
</View>
);
}
2. Device Location Based Language
import { useEffect } from "react";
import * as Location from "expo-location";
import { useTranslation } from "react-i18next";
export function useLocationBasedLanguage() {
const { i18n } = useTranslation();
useEffect(() => {
async function setLanguageByLocation() {
try {
const { status } = await Location.requestForegroundPermissionsAsync();
if (status !== "granted") return;
const location = await Location.getCurrentPositionAsync({});
const geocode = await Location.reverseGeocodeAsync({
latitude: location.coords.latitude,
longitude: location.coords.longitude,
});
const countryCode = geocode[0]?.isoCountryCode;
const languageMap = {
US: "en",
ES: "es",
BR: "pt",
// Add more country-to-language mappings
};
const language = languageMap[countryCode] || "en";
i18n.changeLanguage(language);
} catch (error) {
console.error("Error setting language by location:", error);
}
}
setLanguageByLocation();
}, []);
}
3. Device Language Based
import { useEffect } from "react";
import * as Localization from "expo-localization";
import { useTranslation } from "react-i18next";
export function useDeviceLanguage() {
const { i18n } = useTranslation();
useEffect(() => {
const deviceLanguage = Localization.getLocales()[0].languageCode;
const supportedLanguages = ["en", "es", "pt"];
const language = supportedLanguages.includes(deviceLanguage)
? deviceLanguage
: "en";
i18n.changeLanguage(language);
}, []);
}
Using Translations in Your Components
Here’s how to use translations in your components:
import React from "react";
import { View, Text } from "react-native";
import { useTranslation } from "react-i18next";
export default function WelcomeScreen() {
const { t } = useTranslation();
return (
<View style={styles.container}>
<Text style={styles.title}>{t("welcome")}</Text>
<Text>{t("name", { name: "John" })}</Text>
</View>
);
}
Best Practices
- Organize Translation Keys:
// Structured translation files
{
"translation": {
"common": {
"welcome": "Welcome",
"save": "Save"
},
"auth": {
"login": "Login",
"signup": "Sign Up"
}
}
}
- Handle Loading States:
function App() {
const { t, i18n } = useTranslation();
if (!i18n.isInitialized) {
return <LoadingScreen />;
}
return <MainApp />;
}
- Remember Platform Differences:
// Configure based on platform
i18n.init({
compatibilityJSON: Platform.OS === "android" ? "v3" : undefined,
// other config...
});
Performance Tips
- Namespace Splitting: Split translations into namespaces for lazy loading
- Memoize Components: Use React.memo for components that only depend on translations
- Avoid Nested Translations: Keep translation keys flat when possible
// Good
{
"welcome_message": "Welcome to our app",
"user_greeting": "Hello, {{name}}"
}
// Avoid
{
"messages": {
"welcome": {
"title": "Welcome to our app"
}
}
}
Testing Internationalization
Here’s a simple test setup:
import { render, screen } from "@testing-library/react-native";
import { useTranslation } from "react-i18next";
jest.mock("react-i18next", () => ({
useTranslation: () => ({
t: (key) => key,
i18n: {
changeLanguage: jest.fn(),
},
}),
}));
test("renders welcome message", () => {
render(<WelcomeScreen />);
expect(screen.getByText("welcome")).toBeTruthy();
});
Conclusion
Implementing internationalization in your React Native app opens it up to a global audience. Whether you choose manual language selection, location-based, or device-language-based implementation, the key is to plan your translation structure early and maintain it consistently.
Remember:
- Start with a good translation key structure
- Choose the right implementation method for your needs
- Consider performance implications
- Test your translations
Need help setting this up? Drop your questions in the comments below! 👇
Happy coding! 🚀