Building Angular apps that will be accessible for people from different countries and cultures requires you to implement internationalization (i18n) and localization in web applications. In this article, we will explore the concepts of i18n and localization in Angular and provide a complete guide to implementing Angular i18n and then localization in the most effective way.
Why Angular i18n and Localization are Important?
Angular is a popular web framework for developing dynamic and interactive web applications. Implementing Angular localization and i18n features can improve your app’s accessibility, usability, and loyalty for people from different countries and cultures by providing them with a UI and content that is relevant to their region and culture. Furthermore, it can lead to increased revenue and growth, a gap in the global market which needs to be targeted.
The good news is that Angular provides built-in support for i18n and localization, making it relatively easy to implement these features in your application.
Angular i18n and Localization Process
We’ll provide you with a simple tutorial on how to implement localization and internationalization in Angular. To view the demo app we’ll be using in this article, you can visit our GitHub repo.
Step 1: Installing the Required Libraries
Generally, three basic libraries for Angular i18n can be used to implement internationalization:
@ngx-translate@angular/localizei18next
@angular/localize is the built-in module that is convenient and feature-rich. Most developers opt to go with it because it does not require any third-party library installation. In addition, it allows developers to easily extract translations and use an AoT (Ahead-of-Time) compiler, which converts Angular HTML and TypeScript code into efficient JavaScript code during the build phase before the browser downloads and runs that code and serves localized apps with very little effort.
On the other hand, there is a downside to using this module because @angular/localize supports either XLIFF or XMB (both are XML formats), whereas @ngx-translate supports JSON by default, but developers can write their language translation loader. Also, the built-in module forces you to build the application per language, which is tedious. You wouldn’t want to always reload your entire application when someone switches the language.
Lastly, we have I18next, a general localization framework that supports pure JavaScript and framework-powered applications. This framework is large and heavy, so we will not be using this for our example. But it has support for all features related to the translation process.
We chose to go with @ngx-translate for our example. Therefore, the following libraries are required:
@ngx-translate/core: this library provides Angular language translation services for applications.@ngx-translate/http-loader: this library provides a way to load Angular translations from external files.
To install these libraries, run the following commands:
npm install @ngx-translate/corenpm install @ngx-translate/http-loaderIn the upcoming steps, we will see an Angular localization example application which will later be converted into Angular Internationalization.
Step 2: Set Up an Angular Application
Now, we need to set up a basic Angular application. You can create a new Angular application using the Angular CLI (Command Line Interface) by running the following command:
ng new my-appHere, in the place of my-app you can place the name of the app, for now, let’s name it translation-app, so the command would now be:
ng new translation-appThis command will create a new Angular application named translation-app in the current directory. Once the application is created, you can navigate to the application’s directory and start the development server by running the following command:
cd translation-appng serveThis command will start the development server, and you can access the application by navigating to http://localhost:4200 in your web browser.
Step 3: Adding Translatable Text
Once we have set up a basic Angular application, the next step is to add translatable text to the application’s UI, and to do that, you need to use the i18n attribute on the HTML element that contains the text.
Open app.component.html and write the following text:
<h1 i18n="User welcome|An introduction header for this sample@@introductionHeader">Hello!</h1><ng-container i18n>I cannot translate everything</ng-container><br /><img [src]="logo" i18n-title title="OpenRecipe logo" alt="OpenRecipe logo" /><br />
<button type="button" (click)="inc(1)">+</button><button type="button" (click)="inc(-1)">-</button><span i18n> Counter updated {minutes, plural, =0 {just now} =1 {one minute ago} other {{{minutes}} minutes ago}}</span>({{minutes}})<br /><br />
<button type="button" (click)="male()">♂</button><button type="button" (click)="female()">♀</button><button type="button" (click)="other()">⚧</button><span i18n>The reader is {gender, select, male {male} female {female} other {other}}</span><br /><br />
<span i18n> Updated: {minutes, plural, =0 {just now} =1 {one minute ago} other {{{minutes}} minutes ago by {gender, select, male {male} female {female} other {other}}}}</span>In this example, we mark the text as translatable by adding the i18n attribute to the elements. For example, Hello! in <h1> tag is marked translatable.
Step 4: Extracting Translations
After marking the translatable text, the next step is to extract it into a separate translation file. Again, angular provides a command-line interface (CLI) tool called ng xi18n.
To extract the translatable text, run the following command:
ng xi18n --output-path src/locale --i18n-format xlfThis command will extract the translatable text from your application and create an XLIFF (XML Localization Interchange File Format) file in the src/locale directory. The XLIFF file contains the source text and an empty target element for each marked translatable text, which will be replaced in the language files with .xlf extensions. So, for example, a glimpse of our English language file named messages.xlf file would look this way:
<?xml version="1.0" encoding="UTF-8" ?><xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> <file source-language="en-US" datatype="plaintext" original="ng2.template"> <body> <trans-unit id="introductionHeader" datatype="html"> <source> Hello! </source> <context-group purpose="location"> <context context-type="sourcefile">src/app/app.component.html</context> <context context-type="linenumber">1,3</context> </context-group> <note priority="1" from="description">An introduction header for this sample</note> <note priority="1" from="meaning">User welcome</note> </trans-unit> <trans-unit id="5206857922697139278" datatype="html"> <source>I cannot translate everything</source> <context-group purpose="location"> <context context-type="sourcefile">src/app/app.component.html</context> <context context-type="linenumber">5</context> </context-group> </trans-unit> </body> </file></xliff>Here’s what our French language file, named messages.fr.xlf, looks like:
<?xml version="1.0" encoding="UTF-8" ?><xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> <file source-language="en" datatype="plaintext" original="ng2.template"> <body> <trans-unit id="introductionHeader" datatype="html"> <source> Hello! </source> <target> Bonjour! </target> <context-group purpose="location"> <context context-type="sourcefile">app\app.component.ts</context> <context context-type="linenumber">4</context> </context-group> <note priority="1" from="description">An introduction header for this sample</note> <note priority="1" from="meaning">User welcome</note> </trans-unit> <trans-unit id="5206857922697139278" datatype="html"> <source>I cannot translate everything</source> <target>Je ne peux pas tout traduire</target> <context-group purpose="location"> <context context-type="sourcefile">app\app.component.ts</context> <context context-type="linenumber">10</context> </context-group> </trans-unit> </body> </file></xliff>Both messages.xlf and messages.fr.xlf files are quite similar, but you can notice in the file messages.fr.xlf that there is a new tag name <target></target>, this is actually the translatable text written in the desired language that needs to be translated. So in this case, the target tag would have the French translation of the English text.
Step 5: Loading Translations for your Angular app
After extracting and translating the translatable text, the next step is to load the translations in your application. Angular provides a built-in module called HttpClientModule that allows you to fetch the translations from a remote server or load them from a local file. So our app.module.ts would look as follows:
import { NgModule } from "@angular/core";import { BrowserModule } from "@angular/platform-browser";import { AppComponent } from "./app.component";
@NgModule({ imports: [BrowserModule], declarations: [AppComponent], bootstrap: [AppComponent]})export class AppModule {}And our app.component.ts would look as follows:
import { Component } from '@angular/core';
@Component({ selector: 'app-root', templateUrl: './app.component.html'})export class AppComponent { minutes = 0; gender = 'female'; fly = true; logo = 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSpvdaVGSQVXaKRkoDKFkb32BY37Pi6wEx_og&usqp=CAU';
inc(i: number) { this.minutes = Math.min(5, Math.max(0, this.minutes + i)); }
male() { this.gender = 'male'; } female() { this.gender = 'female'; } other() { this.gender = 'other'; }}Step 6: Translating Text
It is finally time to translate our texts. Open index.html and replace it with the following:
<!doctype html><html> <head> <base href="/" /> <title>Angular i18n example</title> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> </head> <body> <app-root>Loading...</app-root> </body></html>