Language has always been an essential part of any business. As the business grows it becomes important for the business to expand in different countries and regions. To achieve success in these local regions it is important to provide localization.
When it comes to the mobile app, the conditions are no different. As the app users expand to different countries, it becomes important to provide the users with the ability to use the app in their native languages.
In this article, we are going to build a React Native app that supports multi-language using react-native-localize package.
Prerequisites
This tutorial requires basic knowledge of React Native. To set up your development machine, follow the official guide here.
To make sure we are on the same page, following are the versions used in this tutorial -
- Node v10.15.0
- npm 6.4.1
- yarn 1.16.0
- react-native 0.59.9
- react-native-localize 1.1.3
- i18n-js 3.3.0
Getting Started
We'll be building a React Native app which will support English, French and Arabic language.
If you want to have a look at the source code right away, here is the Github link.
To create a new project using react-native-cli
, type the following in the terminal:
$ react-native init multiLanguage
$ cd multiLanguage
Add required libraries
Install react-native-localize
by typing the following:
$ yarn add react-native-localize
and then link it using:
$ react-native link react-native-localize
If you face any error during installation, check the installation instructions here.
The react-native-localize
lib gives you access to a lot of localization related device constants, but does not come with an i18n lib.
We'll use I18n.js
to provide a I18n translations on the JavaScript.
$ yarn add i18n-js
Since i18n-js
does not seem to provides any cache / memoization we'll use lodash.memoize
for the same.
$ yarn add lodash.memoize
Add Translations
Create a translations
directory inside src
and then create, three JSON files as below for each language.
-
en.json
for English -
fr.json
for French -
ar.json
for Arabic
Inside these files will be JSON object with keys and values.
Key will the be same for each language and will be used in the app to display text.
The value will be the actual translation that we want to show to the user and will be different for each language.
For English:
{
"hello": "Hello World!"
}
For French:
{
"hello": "Salut le Monde!"
}
For Arabic:
{
"hello": "أهلاً بالعالم"
}
Similarly, you can add more key-value pairs for every text that will be used in the app.
Add Main Code
Open App.js
file and the following imports:
import React from "react";
import * as RNLocalize from "react-native-localize";
import i18n from "i18n-js";
import memoize from "lodash.memoize"; // Use for caching/memoize for better performance
import {
I18nManager,
SafeAreaView,
ScrollView,
StyleSheet,
Text,
View
} from "react-native";
After that, we'll add some helper functions and constants that we'll use later.
const translationGetters = {
// lazy requires (metro bundler does not support symlinks)
ar: () => require("./src/translations/ar.json"),
en: () => require("./src/translations/en.json"),
fr: () => require("./src/translations/fr.json")
};
const translate = memoize(
(key, config) => i18n.t(key, config),
(key, config) => (config ? key + JSON.stringify(config) : key)
);
const setI18nConfig = () => {
// fallback if no available language fits
const fallback = { languageTag: "en", isRTL: false };
const { languageTag, isRTL } =
RNLocalize.findBestAvailableLanguage(Object.keys(translationGetters)) ||
fallback;
// clear translation cache
translate.cache.clear();
// update layout direction
I18nManager.forceRTL(isRTL);
// set i18n-js config
i18n.translations = { [languageTag]: translationGetters[languageTag]() };
i18n.locale = languageTag;
};
Now, we'll create our App
class component.
export default class App extends React.Component {
constructor(props) {
super(props);
setI18nConfig(); // set initial config
}
componentDidMount() {
RNLocalize.addEventListener("change", this.handleLocalizationChange);
}
componentWillUnmount() {
RNLocalize.removeEventListener("change", this.handleLocalizationChange);
}
handleLocalizationChange = () => {
setI18nConfig();
this.forceUpdate();
};
render() {
return (
<SafeAreaView style={styles.safeArea}>
<Text style={styles.value}>{translate("hello")}</Text>
</SafeAreaView>
);
}
}
const styles = StyleSheet.create({
safeArea: {
backgroundColor: "white",
flex: 1,
alignItems: "center",
justifyContent: "center"
},
value: {
fontSize: 18
}
});
In our constructor method, we called setI18nConfig()
which will set the initial configuration.
Then in componentDidMount()
we'll add an event listener which will listen for any changes and call handleLocalizationChange()
if any changes occur.
The handleLocalizationChange()
method does two things one is that it fires setI18nConfig()
and forceUpdate()
. This is necessary for Android devices as the component needs to be re-render for the changes to be visible.
We will remove the listener in componentWillUnmount()
lifecycle method.
Finally, in render()
we'll print out hello
by using translate()
and passing our key
as a parameter into it. It will then automatically figure out the language and the text that needs to be shown for that language.
Running the App
Now its time to see our if the translations are working.
Run your app in simulator or emulator by typing:
$ react-native run-ios
$ react-native run-android
It should be something like this:
Now, change your device language setting to French and open your app again.
Similarly, you can change your language setting to Arabic and see hello in Arabic.
So far so great.
But what happens if I choose some random language whose translation is not added in the app? What language will it fall back to?
Well as it turns out the goal of findBestAvailableLanguage
is to return the best available translation. So It will look at your language preference setting to figure out the fallback language.
If you go to the Language & Region setting in your iOS simulator you can see the preference order of the languages.
If the language chosen is not in the preferred language findBestAvailableLanguage
returns undefined
(so the retained value will be your fallback) because none of the user's preferred languages are available in your translations.
Bonus
The react-native-localize
has API that can provides access to lot localization related device constants. Be sure to check out the full APIs available in the docs.
Conclusion
Adding multi-language support is that easy. You can now use react-native-localize to easily provide multiple language support in your app which can help in increasing user's app usage.
Find the source code in the Github repo here.
Originally published on Medium
If you like this article, go ahead and show some love and share.
Top comments (9)
Hi Vikrant Negi! How do I go about doing this with multiple screens? Can I have all of these code in a
translate.js
file and pass the translate variable as a prop?You can put all your translations in the
translate.js
file and use the keys in your multiple filesI figured it out! The question now is how do I use useMemo hook instead of lodash.memoize?
This is a great article about creating a multi-language app in React Native. It is interesting to see how the React Native app development company has been able to utilize this technology to create a great app for their clients. The article is definitely worth reading for anyone interested in learning about the process of creating a multi-language app.
Hello, I have problem with rewrite your code using Typescript, can you help me with types?
Here is what I have in a typescript file for the helpers:
Sorry, I'm not very good at the typescript.
Is it possible to change the language from app settings menu itself? So that I can change the language for this app alone
Did you got any solution?