Localizing a React Native mobile app

No Comments

The European Union has 24 official languages. If you are targeting the European market with a mobile application, you need to offer the app’s content in different languages, i.e. localize the app.

In computing, internationalization and localization (internationalisation and localisation) are means of adapting computer software to different languages, regional peculiarities and technical requirements of a target locale.

Internationalization is the process of designing a software application so that it can be adapted to various languages and regions without engineering changes. Localization is the process of adapting internationalized software for a specific region or language by translating text and adding locale-specific components. From Wikipedia.

Internationalization is usually shortened to i18n meaning “letter i followed by eighteen letters n”, and localization is l10n meaning “letter l followed by ten letters n”.

For localization in a mobile application created with the React Native framework we use two libraries:

Installation

We need to install needed libraries with the yarn or npm command:

yarn add react-native-localization react-native-localize

or

npm install react-native-localization react-native-localize

For React Native version 0.60+ there is no need to link manually,
running cd ios && pod install is sufficient.

Translations file

We will create a translations file with an object containing all keys with belonging values for each language our app will support. Depending on the project, you might receive those strings from the backend or keep in JSON files. This approach supports this too.

File: translations.js

import LocalizedStrings from 'react-native-localization';
export const DEFAULT_LANGUAGE = 'en';

const translations = {
  en: {
    WELCOME: 'Welcome to React',
    STEP1: 'Step One',
    SEE_CHANGES: 'See Your Changes',
    CHANGE_LANGUAGE: 'Change Language',
    LANGUAGE_SETTINGS: 'Change Language',
    BACK: 'Back'
  },
  de: {
    WELCOME: 'Willkommen bei React',
    STEP1: '1. Schritt',
    SEE_CHANGES: 'Änderungen ansehen',
    CHANGE_LANGUAGE: 'Sprache wechseln',
    LANGUAGE_SETTINGS: 'Sprache wechseln',
    BACK: 'Zurück'
  }
};

export default new LocalizedStrings(translations);

React Context

The following step is to create the Context that will contain the Provider. There we will set the selected language and provide it to the Context.

React Native Localization API has a method setLanguage that accepts the language code we want to use as an app language.

We will keep that value in the state too and when we set language code to state, the interface language will be changed.

At the same time, we will persist chosen language to the phone storage to be able to use it on the next start of the app.

File: LocalizationContext.js

import React, { createContext, useState } from 'react';
import translations, { DEFAULT_LANGUAGE } from './translations';
import AsyncStorage from '@react-native-community/async-storage';
import * as RNLocalize from 'react-native-localize';

const APP_LANGUAGE = 'appLanguage';

export const LocalizationContext = createContext({
  translations,
  setAppLanguage: () => {},
  appLanguage: DEFAULT_LANGUAGE,
  initializeAppLanguage: () => {},
});

export const LocalizationProvider = ({ children }) => {
  const [appLanguage, setAppLanguage] = useState(DEFAULT_LANGUAGE);

  const setLanguage = language => {
    translations.setLanguage(language);
    setAppLanguage(language);
    AsyncStorage.setItem(APP_LANGUAGE, language);
  };

  const initializeAppLanguage = async () => {
    const currentLanguage = await AsyncStorage.getItem(APP_LANGUAGE);

    if (!currentLanguage) {
      let localeCode = DEFAULT_LANGUAGE;
      const supportedLocaleCodes = translations.getAvailableLanguages();
      const phoneLocaleCodes = RNLocalize.getLocales().map(
        locale => locale.languageCode,
      );
      phoneLocaleCodes.some(code => {
        if (supportedLocaleCodes.includes(code)) {
          localeCode = code;
          return true;
        }
      });
      setLanguage(localeCode);
    } else {
      setLanguage(currentLanguage);
    }
  };

  return (
    <LocalizationContext.Provider
      value={{
        translations,
        setAppLanguage: setLanguage,
        appLanguage,
        initializeAppLanguage,
      }}>
      {children}
    </LocalizationContext.Provider>
  );
};

In App.js we will import Localization provider and wrap our application with it. As a result, we can use the Context anywhere in the app.

File: App.js

import React from 'react';
import { SafeAreaView } from 'react-native';
import AppContainer from './src/navigation/Navigator';
import { LocalizationProvider } from './src/services/localization/localizationContext';

const App: () => React$Node = () => {
  return (
    <LocalizationProvider>
      <SafeAreaView style={{ flex: 1 }}>
        <AppContainer />
      </SafeAreaView>
    </LocalizationProvider>
  );
};

export default App;

Example React Native application

As an example of localized screens in the app, we will use the default React Native app created with the CLI command npx react-native init ourAppName. It will create an empty project from the template. To be able to navigate to the settings screen to switch languages, we need to install the React Navigation library and create navigators.

File: Navigator.js

import { createSwitchNavigator, createAppContainer } from 'react-navigation';
import { createStackNavigator } from 'react-navigation-stack';
import { SplashScreen, MainScreen, SettingsScreen } from '../screens';

const MainNavigator = createStackNavigator(
  { Main: { screen: MainScreen }, Settings: { screen: SettingsScreen } },
  { initialRouteName: 'Main', headerMode: 'none' }
);

const AppNavigator = createSwitchNavigator(
  { Splash: { screen: SplashScreen }, Main: { screen: MainNavigator } },
  { initialRouteName: 'Splash', headerMode: 'none' }
);

export default createAppContainer(AppNavigator);

 

The application will have the splash screen where we check if any language is already set, and if not, we use the React Native Localize library to check a user’s preferred locales ordered in the same way as in the phone’s settings. Then we use the first language from that list that our app supports. But, if there is no matching language, we set English as default. After the splash screen, the app shows the main screen that is the initial route of the Stack navigator. The other route is the settings screen where we will add options to choose a language.

On the Settings screen, we will use LocalizationContext from which we need translations, appLanguage, and setAppLanguage.

The React Native Localization API has a method getAvailableLanguages that returns an array of the languages we support in translations.js file.

On the screen, we will show the list of the languages and mark the selected language. When the user chooses a language, that language will be used and the app will show text in the chosen language.

Applying localization

To apply localization on the main screen, we need to import LocalizationContext and get translations from the context. Every string on the screen we need to replace with the belonging key from the translations file.

We need to replace the Sections title Step One in the app template with the object’s property STEP1 because we defined that key in the translations file.

<Text style={styles.sectionTitle}>Step One</Text>
<Text style={styles.sectionTitle}>{translations.STEP1}</Text>

We need to change See Your Changes with the object’s property SEE_CHANGES following the same principle.

<Text style={styles.sectionTitle}>See Your Changes</Text>
<Text style={styles.sectionTitle}>{translations.SEE_CHANGES}</Text>

For a component with the text, we can send a translation of that text through props. If the component has only one string, we should send its translated value. On the other hand, if it has more strings we should send the translations object and use values from it.

<Header text={translations.WELCOME} />

Here is the implementation of the header component in which we have translated text.

const Header = ({ text }) => (
  <ImageBackground
    accessibilityRole={'image'}
    source={require('./logo.png')}
    style={styles.background}
    imageStyle={styles.logo}>
      <Text style={styles.text}>{text}</Text>
  </ImageBackground>
);

The whole example project is available on GitHub.

localization with react native: switching application's language from English to German

 

Milan Susnjar

Software developer at codecentric since August 2015.
Member of the codecentric Digitization Labs team, an initiative within codecentric that focuses on digital prototyping. From the very first day, we implement our customers’ ideas and help validate them both internally and on the market. Any insights gained are immediately incorporated into the further development of the product – without tedious planning or detailed requirements.

Comment

Your email address will not be published. Required fields are marked *