Skip to main content

Implementing Internationalization (i18n)

1. Installing i18n Library

For internationalization in Expo projects, the i18next library is commonly used. It provides a robust framework for handling translations and locale management.

Example: Installing i18next

npm install i18next
npm install react-i18next
Package Description Version
i18next Main i18n library for managing translations and resources 23.7.16
react-i18next React integration for i18next, providing hooks and components 15.0.0
Note: Ensure that you are using compatible versions of i18next and react-i18next to avoid runtime errors.

2. Configuring Languages

Property Values Description
supportedLocales ['en', 'es', 'fr'] List of locales supported by the app
defaultLocale 'en' Default locale when no language is detected
localeConfig {} Configuration object for locale-specific settings

Example: Configuring supported locales in app.json

{
  "expo": {
    "locales": {
      "en": "./locales/en.json",
      "es": "./locales/es.json",
      "fr": "./locales/fr.json"
    },
    "defaultLocale": "en"
  }
}
Note: Ensure that all locale files are properly formatted and located in the specified paths.

3. Creating Translation Files

File Type Location Description
JSON locales/en.json English translation file with key-value pairs
JSON locales/es.json Spanish translation file with key-value pairs
JSON locales/fr.json French translation file with key-value pairs

Example: en.json

{
  "welcome": "Welcome to our app",
  "greeting": "Hello, {name}!",
  "settings": "Settings",
  "logout": "Logout"
}

Example: es.json

{
  "welcome": "Bienvenido a nuestra aplicación",
  "greeting": "Hola, {name}!",
  "settings": "Configuración",
  "logout": "Cerrar sesión"
}
Note: Translation files should be structured consistently across languages to ensure easy maintenance and scalability.

4. Using Translation Hook

Property Description Usage
useTranslation Custom React hook to access translation functions and language context const { t, i18n } = useTranslation();

Example: Basic usage of useTranslation hook

import { useTranslation } from 'expo-i18n';

export default function MyComponent() {
  const { t } = useTranslation();

  return (
    <View>
      <Text>{t('welcome_message')}</Text>
    </View>
  );
}

Example: Accessing i18n instance

import { useTranslation } from 'expo-i18n';

export default function LanguageSwitcher() {
  const { t, i18n } = useTranslation();

  const changeLanguage = (lng) => {
    i18n.changeLanguage(lng);
  };

  return (
    <View>
      <Text>{t('current_language', { lng: i18n.language })}</Text>
      <Button title="Switch to Spanish" onPress={() => changeLanguage('es')} />
    </View>
  );
}
Note: The useTranslation hook must be used inside a component that is wrapped in the <I18nProvider> context.

5. Switching Languages

Method Description Notes
I18n.switchLanguage() Changes the current language of the app Must be called with a valid locale code from your supported languages list
I18n.getCurrentLanguage() Returns the currently active language code Useful for debugging or displaying current language in UI

Example: Switching Language Programmatically

I18n.switchLanguage('es');
Note: Ensure that the language code passed to I18n.switchLanguage() is one of your supported locales defined in the configuration.
Warning: Switching languages does not automatically reload the app. You may need to manually refresh or navigate to see changes.

6. Formatting Dates

Property Description Example
formatDate Formats a date according to the locale formatDate(new Date(), { locale: 'fr-FR' })
formatTime Formats a time according to the locale formatTime(new Date(), { locale: 'en-US' })
formatDateTime Formats a date and time according to the locale formatDateTime(new Date(), { locale: 'de-DE' })

Example: Formatting Dates in Different Locales

import { formatDate } from 'expo-localization';

const date = new Date('2025-04-15');

console.log(formatDate(date, { locale: 'en-US' })); // "4/15/2025"
console.log(formatDate(date, { locale: 'fr-FR' })); // "15/04/2025"
console.log(formatDate(date, { locale: 'ja-JP' })); // "2025/04/15"

Example: Custom Date Formatting

import { formatDate } from 'expo-localization';

const date = new Date('2025-04-15');

console.log(formatDate(date, {
  locale: 'en-US',
  year: 'numeric',
  month: 'long',
  day: 'numeric'
})); // "April 15, 2025"
Note: The formatDate function uses the device's locale settings by default, but can be overridden with a custom locale option.

7. Formatting Numbers

Property Description Example
Intl.NumberFormat Formats numbers according to locale new Intl.NumberFormat('en-US').format(1234567.89)
style Formatting style: 'decimal', 'currency', 'percent' { style: 'currency', currency: 'USD' }
currency Currency code (ISO 4217) { style: 'currency', currency: 'EUR' }
minimumFractionDigits Minimum number of digits after decimal point { minimumFractionDigits: 2 }
maximumFractionDigits Maximum number of digits after decimal point { maximumFractionDigits: 2 }

Example: Formatting Numbers in Different Locales

import { Intl } from 'intl';

const number = 1234567.89;

// US locale
console.log(new Intl.NumberFormat('en-US').format(number));
// Output: 1,234,567.89

// German locale
console.log(new Intl.NumberFormat('de-DE').format(number));
// Output: 1.234.567,89

// Currency formatting
console.log(new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(number));
// Output: $1,234,567.89

Example: Custom Number Formatting

const formatter = new Intl.NumberFormat('en-US', {
  style: 'decimal',
  minimumFractionDigits: 2,
  maximumFractionDigits: 4
});

console.log(formatter.format(1234.56789));
// Output: 1,234.5679

8. Using Device Locale

Property Description Default
locale Current device locale code (e.g., en-US, fr-FR) System default

Example: Detecting Device Locale

import * as Localization from 'expo-localization';

const locale = Localization.locale;
console.log("Device locale:", locale); // e.g. "en-US"
Note: The expo-localization package provides access to the device's current locale settings, which can be used to determine language and region preferences for internationalization.

9. Handling RTL Languages

Property Description Values
direction Defines text direction for layout and content ltr, rtl
locale Current locale used for formatting and localization String (e.g., ar-SA, he-IL)

Example: Setting RTL layout in Expo

import { I18nManager } from 'react-native';

I18nManager.forceRTL(true);
Note: Enabling RTL requires careful handling of layout and component positioning to ensure proper rendering.

RTL Support in Expo

  • Uses I18nManager to control text direction
  • Supports right-to-left languages like Arabic and Hebrew
  • Requires manual adjustment of layout components for RTL alignment

10. Using Pluralization

Feature Description Usage
pluralization Supports plural forms in different languages {count, plural, one{# item} other{# items}}
plural rules Rules for determining plural forms in various languages Based on CLDR (Common Locale Data Repository)

Example: Pluralizing Items

<Trans>
  {count, plural,
    one{# item}
    other{# items}
  }
</Trans>
Note: The count variable is used to determine the correct plural form based on the language's rules.

11. Creating Translation Namespaces

Namespace Description Usage
common Shared translations used across the app { common: { welcome: 'Welcome' } }
auth Authentication-related strings { auth: { login: 'Login', register: 'Register' } }
settings Settings and preferences strings { settings: { theme: 'Theme', language: 'Language' } }

Example: Defining Translation Namespaces

// locales/en.json
{
  "common": {
    "welcome": "Welcome",
    "loading": "Loading..."
  },
  "auth": {
    "login": "Login",
    "logout": "Logout"
  }
}
Note: Namespaces help organize translations and improve maintainability.

12. Interpolating Values

Property Description Example
format Used to format values within translation strings {name}, you have {count} messages

Example: Basic Interpolation

<Trans i18nKey="greeting" values={{ name: "John", count: 5 }}>
  Hello {{name}}, you have {{count}} messages
</Trans>

Example: Nested Values

<Trans i18nKey="userProfile" values={{
  firstName: "Alex",
  lastName: "Johnson",
  age: 30
}}>
  {{firstName}} {{lastName}} is {{age}} years old
</Trans>
Note: Values must be passed as an object with keys matching the placeholders in the translation string.

Was this article helpful?