Translate your expo.io (react-native) mobile application

Jan Mühlemann
4 min readJul 13, 2017

In this getting started guide you will learn how to translate your mobile application created using expo.io. The code works also for pure react-native projects, but expo.io did an awesome job lowering the entry hurdle using react-native.

For instrumenting our code we will use react-i18next which is the react.js integration for the i18next framework: learn once — translate everywhere.

The result:

If you like to directly get to the running example and check the code on github just open:

https://github.com/i18next/react-i18next/tree/master/example/react-native-expo

First step

To get started we used create-react-native-app as it takes away the complete pain of start using react-native.

npm start

And you will get the nice qr code to start your app directly in the expo.io app. Awesome.

Translate your views

In the next step you will need to add i18next and react-i18next packages:

npm i i18next react-i18next --save

Create a first file to configure and init i18next i18n.js :

import i18n from 'i18next';
import Expo from 'expo';
// creating a language detection plugin using expo
// http://i18next.com/docs/ownplugin/#languagedetector
const languageDetector = {
type: 'languageDetector',
async: true, // async detection
detect: (cb) => {
return Expo.Util.getCurrentLocaleAsync()
.then(lng => { cb(lng.replace('_', '-')); })
},
init: () => {},
cacheUserLanguage: () => {}
}
i18n
.use(languageDetector)
.init({
fallbackLng: 'en',
// the translations
// realworld load that via xhr or bundle those using webpack
resources: {
en: {
home: {
title: 'Welcome''
}
},
de: {
home: {
title: 'Willkommen'
}
},
// have a initial namespace
ns: ['translation'],
defaultNS: 'translation',
interpolation: {
escapeValue: false // not needed for react
}
});
export default i18n;

For realworld usage you should load the translation using:

Getting a translation function to your components

Now it’s time to expose the i18n instance to your components by first adding a i18nextProvider which will expose needed functionality using react context.

To make this sample more useful we also integrate react-navigation.

In your app.js:

import React from 'react';
import { I18nextProvider, translate } from 'react-i18next';
import { StackNavigator } from 'react-navigation';
// the previous created file
import i18n from './js/i18n';
// our content pages
import Home from './js/pages/Home';
import Page2 from './js/pages/Page2';
// the navigation stack
const Stack = StackNavigator({
Home: { screen: Home },
Page2: { screen: Page2 }
});
// Wrapping a stack with translation hoc asserts we trigger new render on language change
// the hoc is set to only trigger rerender on languageChanged
const WrappedStack = () => {
return <Stack screenProps={{ t: i18n.getFixedT() }} />;
}
const ReloadAppOnLanguageChange = translate('translation', {
bindI18n: 'languageChanged',
bindStore: false
})(WrappedStack);
// The entry point using a react navigation stack navigation
// gets wrapped by the I18nextProvider enabling using translations
// https://github.com/i18next/react-i18next#i18nextprovider
export default class App extends React.Component {
render() {
return (
<I18nextProvider i18n={ i18n }>
<ReloadAppOnLanguageChange />
</I18nextProvider>
);
}
}

Now your ready to wrap your component with the translate hoc to pass down a translation function. Your pages will look like this:

import React from 'react';
import { translate } from 'react-i18next';
import { StyleSheet, Text, View, Button } from 'react-native';
// using the translation hoc to provie t function in props using home as default namespace
// https://react.i18next.com/components/translate-hoc.html
@translate(['home', 'common'], { wait: true })
export default class Home extends React.Component {
static navigationOptions = ({ navigation, screenProps }) => ({
title: screenProps.t('home:title')
});
render() {
const { t, i18n, navigation } = this.props;
const { navigate } = navigation;
return (
<View style={styles.container}>
<Text>{t('common:currentLanguage', { lng: i18n.language })}</Text>
<Button
onPress={() => { i18n.changeLanguage('en') }}
title={t('common:actions.toggleToEnglish')}
/>
<Button
onPress={() => { i18n.changeLanguage('de') }}
title={t('common:actions.toggleToGerman')}
/>
<Text style={styles.separate}>{t('introduction')}</Text>
<Button
onPress={() => navigate('Page2')}
title={t('common:actions.goToPage2')}
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
separate: {
marginTop: 50
}
});

You can use i18n.changeLanguage(lng) to change the language pragmatically.

For richer translation options there is the trans component which allows you to translate nested react components like:

<Trans i18nKey="userMessagesUnread" count={count}>
Hello <strong title={t('nameTitle')}>{{name}}</strong>, you have {{count}} unread message. <Link to="/msgs">Go to messages</Link>.
</Trans>

Thats all needed to get your react-native application translated.

Learn more:

Checkout the working sample: https://github.com/i18next/react-i18next/tree/master/example/react-native-expo

react-i18next documentation: https://react.i18next.com
i18next documentation: http://i18next.com

--

--

Jan Mühlemann

Always in search for the holy grail ;)...loving javascript, node.js, html5, interaction design, usability