As you start translating you App, sooner or later you will come across pluralization. Different languages have different concepts of pluralization rules; it's not always as simple as "one apple" and "two apples".
In this guide we will cover how to pluralize your translations in JavaScript together with the i18n library react-i18next and Applanga.
If you already want to get straight to examples, see our React-Native i18n example.
To use plurals in React-Native it's common to use the react-i18next package.
Let's assume we have a simple phrase "I buy X apple(s)".
The amount of apples is calculated so we don't know it yet.
Some languages have different rules depending on the amount.
In english it's simple, if it's more than one OR zero then append an s
.
For every rule we add the whole phrase to our dedicated string file which is a json
file working with i18next
.
We use the string key buying-apples
here.
The plural rule is appended at the end of the key with an underscore plus the rule.
Possible rules are: zero
, one
, two
, few
, many
, other
.
For the english language we need the rules one
, other
and zero
.
This results in the following example:
//en.json
{
"buying-apples_one": "I buy one apple",
"buying-apples_other": "I buy two apples",
"buying-apples_zero": "I don't buy apples",
}
First, we need to install our i18next and applanga dependencies:
$ npm install react-i18next i18next applanga-react-native --save
To be able to run applanga-react-native
on Android we also need to add the Applanga maven repository to our app/build.gradle
file:
repositories {
maven { url 'https://maven.applanga.com/'}
}
For more information read the react-i18next getting-started article and our Applanga React-Native documentation.
We create two string files in a json format. One for english with the name en.json and one for german with the name de.json.
We create a few translations:
//en.json
{
"test-1": "Hello Example",
"buying-apples_one": "I buy one apple",
"buying-apples_other": "I buy two apples",
"buying-apples_zero": "I don't buy apples",
"some_array-here": [
"one",
"two",
"three"
]
}
Applanga supports the i18next json v4 Format.
We want to separate the i18n logic into a new file called: i18n.config.ts
First, we need to create a resource map for i18n with our en.json
and de.json
// i18n.config.ts
import en from './strings/en.json';
import de from './strings/de.json';
var resources = {
en: {
translation: en,
},
de: {
translation: de,
},
}
We pass this resource map to i18n in a function we call later in our App.tsx
.
// i18n.config.ts
async function initLocalisations(): Promise<void> {
await i18n.use(initReactI18next).init({
resources,
//language to use if translations in user language are not available
fallbackLng: 'en',
interpolation: {
escapeValue: false, // not needed for react!!
},
});
}
We have now initialized i18n-next
and we can use the plural forms of our strings.
To make over-the-air updates work, we need applanga-react-native
with its Applanga.localizeMapI18NextJsonV4()
method.
In our example we create a method called initApplangaLocalisations
which first updates all local translations with the newest one from your Applanga dashboard and then we pass those updates to our i18next
instance.
The first step is the Applanga update to get all newest over-the-air translations. Here we pass in all languages we want to update, otherwise Applanga will update only the current device language and it may not be the language you want to show later.
// i18n.config.ts
await Applanga.update(['en', 'de']);
The method Applanga.localizeMapI18NextJsonV4(map)
accepts a map of keys and its translations and returns its keys and updated translations as a promise.
If the keys and translations do not exist on your Applanga dashboard, run your iOS or Android app in Debug Mode and the map and all its keys and (local) translations will be uploaded.
Then we use the updated map as resources which we later pass on to our i18next instance.
// i18n.config.ts
var map = await Applanga.localizeMapI18NextJsonV4(m);
resources = {
en: {
translation: map.en,
},
de: {
translation: map.de,
},
};
Now we update the i18next instance with our translated strings.
Note that we also call changeLanguage
with our current language to actually let i18next
know that the translations have been updated.
// i18n.config.ts
i18n.addResourceBundle('en', 'translation', resources.en.translation);
i18n.addResourceBundle('de', 'translation', resources.de.translation);
i18n.changeLanguage(i18n.language);
In our example we start the Applanga update and it's update to our i18next
instance in an useEffect
hook in our App.tsx.
// App.tsx
const _init = async () => {
var success = false;
try {
await initApplangaLocalisations();
success = true;
} catch (e) {
console.log("Couldn't init localisations");
console.log(e);
}
if (success) {
setApplangaInitialized(success);
}
};
useEffect(() => {
_init();
}, []);
To display i18next
plural strings it's as easy as t('string_key', {count: myCount})
for example.
myCount
is the count of objects you are talking about, i18next
takes care of choosing the right translation for you.
// App.tsx
<Section title={t('buying-apples', {count: 0})} />
<Section title={t('buying-apples', {count: 1})} />
<Section title={t('buying-apples', {count: 2})} />
You also can change a language as you would normally do with your i18next
instance.
Be aware that if you want to use the over-the-air updates from Applanga, you have to first do an update call with that language.
// LanguagePicker.tsx
i18n.changeLanguage(lang.name);
Learn what the GL Strings team has been working on
Read the Full ArticleAre you wondering which keys stored in your Applanga projects are actually used in your app and which ones are just dead weight?
Read the Full Article