How to translate in Ionic 5— Internationalization and Localization

Abhijeet Rathore
Enappd
Published in
14 min readJul 29, 2020
How to translate in Ionic 5- Internationalization and Localization

In this post you’ll learn how to translate text in Ionic 5 apps and PWA. You will also learn how to get device specific language and convert your app’s text to the same language / locale.

We will also look at a popular sought after method of loading JSON files from servers instead of keeping them in local build. This is specially useful for mobile apps, as refreshing the build on user device is not possible at runtime.

Ionic has a variety of app types nowadays (Angular/React/Vue , Cordova/Capacitor). This post will explore the Ionic apps made in Angular Cordova, but the same process can apply in Angular Capacitor apps as well.

Translation in Apps — how is it done ?

Multi-language translation, OR internationalization is a growing need for every app that wants to target international customers. Till date, majority of apps have been developed in English, no surprise ! But with growing apps users, every app is now focusing on translating to local languages.

First we need to understand the steps involved in the process. Translations, thanks to Google, look very easy, but they are a bit involved in case of apps and websites, in our case Ionic 5 apps. There are 3 major steps in the translation process in an app —

  1. Translation Language — Detect the language you want to translate into. This can either be done automatically by detecting phone or browser’s language (Globalization), OR, can be done with user actions (say, by using a dropdown).
    For our use case, we will detect device’s language using both Cordova Globalization plugin and Browser’s Internationalization API.
  2. Prepare Language Text — There are two ways to do this
    a. You need to have a pre-translated dictionary (or JSON file) in your app build which stores the translations of all your app’s text in the required translation languages, OR
    b. You load language files from your server every time the app starts. This gives you the advantage of loading updated files, but costs you load time.
    Creating the translation JSON files is mostly a manual process for smaller apps, but you can use online tools like this for quick translations, or like POEditor for more standardized workflow.
  3. Translate — After the above two steps, you finally translate your app’s text to the intended language. We will use ngx-translate library for translating our texts as we are talking about only Angular Ionic apps in this post

Structure of the post

So the development outline of this blog will be

  1. Create a starter Ionic 5 tab app
  2. Prepare multiple language JSON files in assets
  3. Implement ngx-translate library to detect and translate AND Implement Cordova Globalization plugin or browser Internationalization API to detect device language
  4. Test translations on browser
  5. The Directive Gotcha
  6. Setup stand alone translations
  7. Load language files from a server
  8. Test translations on Android / iOS

We will translate English text in 2 languages — French and Spanish

Sounds pretty easy, right ? Well, let’s dive right into it.

Step 1— Create a basic Ionic Angular app

First you need to make sure you have the latest Ionic CLI. This will ensure you are using everything latest. Ensure latest Ionic CLI installation using

$ npm install -g ionic@latest

Here’s my environment for this blogpost

Ionic:
Ionic CLI : 6.10.1
Ionic Framework : @ionic/angular 5.3.1
@angular-devkit/build-angular : 0.901.12
@angular-devkit/schematics : 9.1.12
@angular/cli : 9.1.12
@ionic/angular-toolkit : 2.3.0
Cordova:
Cordova CLI : 9.0.0 (cordova-lib@9.0.1)
System:
Android SDK Tools : 26.1.1
NodeJS : v12.14.0
npm : 6.13.4
OS : macOS Catalina
Xcode : Xcode 11.5 Build version 11E608c

Creating a basic Ionic-Angular app. Start a basic tabs starter using

$ ionic start ionicTranslate tabs --type=angular --cordova

The --type=angular told the CLI to create an Angular app, and --cordova tells the CLI to integrate Cordova in the app.

Run the app in browser using

$ ionic serve

You won’t see much in the homepage created in the starter. I have modified pages ( tab1 and tab2) to align it to our translation functionality.

My tab pages look like this

Tab UI for translation

HTML and SCSS file code for the above UI, if you want to just get started

Step 2 — Prepare multiple language JSON files in assets

We will create these JSON files in src/assets/i18n folder. The assets folder remains in the root even after a production build, so the path does not break. We will create three JSON files en.json (English), fr.json (French) and es.json (Spanish).

Folder structure for i18n files

en.json

{
"TITLE": "Hello sir",
"TITLE_2": "Hello {{value}}",
"description": "Ooohh .... did you just translate this text ?",
"data": {
"name": "My name is {{name_value}}"}
}

fr.json

{
"TITLE": "Bonjour Monsieur",
"TITLE_2": "Bonjour {{value}}",
"description": "Ooohh .... vous venez de traduire ce texte?",
"data" :{
"name": "je m'appelle {{name_value}}"}
}

es.json

{
"TITLE": "Hola señor",
"TITLE_2": "Hola {{value}}",
"description": "Ooohh .... acabas de traducir este texto?",
"data": {
"name": "Me llamo {{name_value}}"}
}

Note, the {{value}} and {{name_value}} are kind of variable/constants we can pass from our component. This can be used to

  • Replace the variable with a user input or a value depending on the situation OR
  • To give translations not supported by the library OR
  • Keep a word constant across translations

STEP 3: Implement ngx-translate library and Cordova Globalization plugin

Cordova globalization plugin is used to detect device’s default language/locale. Unfortunately, this plugin is deprecated, but it is still supported by Ionic. Hence, you can opt to use it. However, the latest way of detecting the language / locale of the browser is by using browsers’s default Internationalization API.

Install Cordova globalization Plugin using

$ ionic cordova plugin add cordova-plugin-globalization$ npm install @ionic-native/globalization

Install ngx-translate library

ngx-translate is the internationalization (i18n) library for Angular. Since our app has Angular under the hood, we can use this library for app as well as progressive web apps.

// Install core library
npm install --save @ngx-translate/core
// Install http loader
npm install @ngx-translate/http-loader --save

http-loader is used for loading the translation files (JSONs in our case) via Angular’s HttpClient module.

Note the versions of ngx-translate you should have as per your Angular version

Use appropriate version of ngx-translate based on your Angular version

Setup the translation library and http-loader

We need to define a function that loads the external JSON files to the app using http-loader. Add the following function to app.module.ts

export function HttpLoaderFactory(http: HttpClient) {
return new TranslateHttpLoader(http, "./assets/i18n/", ".json");
}

where we have provided the external path of our JSON files to the function.

We need to add the translation and http-loader modules in our root module app.module.ts. This is how the file looks after setup.

Pay attention to TranslateModule.forRoot() This is used in case of a Tabbed application, or general non lazy-loaded module. For a tab child, however, we will have to use TranslateModule.forChild() . We will see later how this will affect our functionality.

Setup the translate library in child component

Let’s say, we want to implement the translation in Tab1. As mentioned previously, src/app/tab1 folder contains all the files for this page. We will import the translationService in tab1.page.ts file using

import { TranslateService } from '@ngx-translate/core';

The completed tab1.page.ts file will look like this

Let’s break down the code to understand a bit more

  • On page load we check if we have default browser internationalization API by checking window.Intl . We then get default browser language using navigator.language . We also set a fall back on Cordova globalization plugin (deprecated) and set a default language if neither browser nor Cordova plugin works.
  • Then we use this._translate.use(this.language) to tell the translation service which language to translate to. If the app has just loaded, it should default to your browser’s default language OR en (english)
  • Important: Usethis._translate.get('TITLE').subscribe() function from translateService to asynchronously fetch translations. Here,
    - get() is the function to fetch translations.
    - TITLE is the key to search for in the JSON files. If the data is in a nested JSON, then we use the dot notation to fetch e.g. data.name
    - subscribe is used for asynchronous fetching (no need to use timeouts)
  • changeLanguage is called from user action. This function will use the previous two steps to translate to the intended language

Step 4— Test translations on browser

Run the app on browser using ionic serve and test the translations using the dropdown. Here’s a GIF to show the functionality on browser

Translate in Ionic 5 using ngx-translate
Translate in Ionic 5 using ngx-translate

Notice that the text loads in English by default in my browser. You can change your browser language from browser settings and check if the initial text loads in your default language. For chrome, the settings can be found here

Change your browser language to load app text in default language
Change your browser language to load app text in default language

And now my text loads default in French …. Bonjour !!

Step 5 — The Directive GOTCHA 😎

If you have followed the above steps exactly, you might not get the exact result as shown in the above GIF.

You will realize that the translation works in places where you have used

this._translate.get('TITLE').subscribe((res: string) => {           
this.title = res;
});
this._translate.get('description').subscribe((res: string) => {
this.description = res;
});

to get the translation, and shown it in the HTML using the local variable like this

<h1>{{ title }}</h1><p>{{ description }}</p>

BUT, the translation does not work in places where you have used a directive like either of the following

<h1 translate>TITLE</h1><p [translate]="'description'"></p>

This is because in our Ionic 5 tab app, the tab pages are lazy-loaded. In lazy-loaded modules, you need to import the translation module in child modules as well for everything to work correctly.

Let’s go to our tab1.module.ts file, and import the translation and http-loader modules similar to our root module. But this time, we will use TranslateModule.forChild . The complete module file looks like the following

Now, if you run the app again, the directive translations will also work fine. 😎 😎 😎

directive method is preferred for bigger apps with lots of code, since this method results in smaller code size and no need of local variables.

Step 6— Setup stand alone translations

The process of setting up separate language file in assets for each language is the standard way of translation in Angular. But sometimes it becomes a little cumbersome, especially when you don’t have that much data to translate.

In case you want to quickly translate in the component itself, so that there is no spill over on other components, you can declare the variables in the components itself instead of reading them from the JSON files from assets

Let’s do these changes in tab2, so it doesn’t affect the global translations in tab1

HTML and SCSS

Similar to tab1.page.html , just remove the usage of variable data from the HTML. You can keep the styling same

tab2.page.ts

Stays pretty much same as tab1.page.ts . Just add the following in the constructor

_translate.setTranslation('en', {
"TITLE": "Bye sir",
"TITLE_2": "Bye {{value}}",
"description": "Thanks for translating this text"
});
_translate.setTranslation('fr', {
"TITLE": "Au revoir Monsieur",
"TITLE_2": "Au revoir {{value}}",
"description": "Merci d'avoir traduit ce texte"
});
_translate.setTranslation('es', {
"TITLE": "Adiós señor",
"TITLE_2": "Adiós {{value}}",
"description": "Gracias por traducir este texto"
});

Here, you are defining the translations locally in your component itself. Also, to let angular know that these are standalone translations, you use isolate:true in your tab2.module.ts

....
TranslateModule.forChild({
loader: {
provide: TranslateLoader,
useFactory: HttpLoaderFactory,
deps: [HttpClient]
},
isolate: true
}),
....

Now run the app in browser and test translations. Your translations will be picked from the local component itself

Translation in Ionic 5 apps using component level translations
Translation in Ionic 5 apps using component level translations

Notice, the directive method and variable also work well with the local definitions.

Step 7 — Load language files from server

This is a popular sought after feature for translation. In websites you can possibly keep updating the language files in the assets regularly. But when you are dealing with a mobile app, you cannot update the language file on user’s device, unless the app runs an update call every time the app starts.

Instead, the easier solution is to not keep language files locally, but load them from your server. These files on your server, in turn, could be created by some script using data from your database itself. This way as soon as you update the database, the server JSON file updates, and the updated data is fetched by the app next time the app launches.

Create Demo Node/Express Server

For demo purpose we will create a local Node Express server. Create a separate folder serverfor node server. To create Node JS script, we will run npm init in the working directory .

$ npm init

Above command will ask few basic questions and creates the package.json file in working directory. Now you can create the index.js file (All logic will be contained in index file because we’re making a simple server).

We have to install some of the libraries that will help in implementing node script. To install the libraries run the below command :-

$ npm install cors express

To know more about cors and express you can follow the links. You can also check official Ionic documentation on CORS which we believe is very good for understanding purpose.

Now we have all the basic requirements to start our node script.

Note — Check your project’s package.json file, it should contain the value stated below in scripts section. If it doesn’t, just add manually :-

package.json file
package.json file for node server

Translation assets

You need to store your translation JSON files in a folder, say, assets/i18n on the server. In production scenario, these files can be manually updated, OR can be written by scripts which run when the database changes.

Project Structure

In your node server index.js you need to declare assets/i18n folder as static asset. Also you will need to set a Access-Control-Allow-Origin: ‘*’ header, so that your Ionic app (localhost:8100) can access resource from your server at , say, localhost:3000.

Here’s how your index.js should look

const express = require("express");
const app = express();
const path = require('path');
app.use(function (req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, authorization");
next();
});
app.use('/assets', express.static(path.resolve(__dirname, 'assets')));app.listen(3000, () => {
console.log("Server Started at", process.env.PORT || 3000);
});

Once setup, you can run the server with

$ npm start

Access server resource from Ionic app

This step is way easier than anyone can imagine. Instead of accessing the local resource at assets/i18n folder, you just need to access the resource via server URL. Make the following change in your .module.ts (I used Tab 3, a copy of Tab1, as the test page for this)

export function HttpLoaderFactory(http: HttpClient) {
return new TranslateHttpLoader(http, "http://localhost:3000/assets/i18n/", ".json");}

Instead of localhost:3000 you can use your server URL, if you have one deployed.

Now you can test this setup by removing your local JSON files (at the app level) and loading files from the server. This will work as expected !

Note: You might not want to keep a JSON file on server which anyone can access. In that case, when you try to access the JSON file from Ionic app for translation — you must fetch the data from your DB, create a JSON file, put all the data inside it, and send it back as the API response. After this you can delete the created file. This, of course, can have performance issues if thousands of users are requesting these files every second. Optimize !

Step 8— Test translations in iOS/Android

To build the app on android, run the following commands one after another

$ ionic cordova platform add android$ ionic cordova run android

The final command will run the app on either default emulator, or an android device attached to your system. Here’s the translation running on my android device

Ionic 5 Angular app — Translation and Globalization
Ionic 5 Angular app — Translation and Globalization

Interesting fact: In device, the language id may be different from browser. For me
- Device default language comes out to be en-US
- Browser’s default language comes out to be en

Hence, you need to be careful to detect all variations of a language. Accordingly, you’ll need to have JSON file named accordingly.

Conclusion

In this post we learnt how to detect device / browser language, create multiple language files, and implement translation using different methods in Ionic 5 apps. We also learnt how we can load language files from server instead of keeping them in local assets.

The only limitation of using the ngx-translate library is that you will need to define your language texts for your application beforehand. These will be stored as country code titled JSON files (i.e. en.json, jp.json, it.json etc) either in local assets or on server. You can’t dynamically generate the language translation for a word which is not in these files. If you require that type of functionality you’ll need to look into using the Google Translate API or something similar.

Ionic React Full App with Capacitor

If you need a base to start your next Ionic 5 React Capacitor app, you can make your next awesome app using Ionic 5 React Full App in Capacitor

Ionic 5 React Full App in Capacitor from Enappd
Ionic 5 React Full App in Capacitor from Enappd

Ionic Capacitor Full App (Angular)

If you need a base to start your next Angular Capacitor app, you can make your next awesome app using Capacitor Full App

Capacitor Full App with huge number of layouts and features
Capacitor Full App with huge number of layouts and features

Ionic Full App (Angular and Cordova)

If you need a base to start your next Ionic 5 app, you can make your next awesome app using Ionic 5 Full App

Ionic Full App with huge number of layouts and features
Ionic Full App in Cordova, with huge number of layouts and features

--

--

Abhijeet Rathore
Enappd
Editor for

Rocket scientist turned programmer. Co-founder at Enappd and Youstart Education. Trying to make the world a better place, one solution at a time.