When translating an Angular app there are multiple choices you have to make before diving into the internationalization (i18n) process. We will take a closer look at the different options for Angular localization and i18n in this post, point out advantages and disadvantages and provide some examples.

At first, you have to decide if you want to choose the built-in tools or a third party library. Please notice that the built-in tools are not yet finished so there are missing some features we will point out in this post.

When you go with the built-in tools for your Angular localization there is a second decision to make: Do you want to use the Ahead-of-Time (AOT) compiler or the Just-in-Time (JIT) compiler. With AOT your application can be served fast and your users profit from a better performance. As a disadvantage, you need to serve an application for each locale due to all information including the content is built-in when compiling the app. The decision which language should be shown to the users needs to happen with serverside logic or by URL parameters. If you go for JIT, translations are dynamic but you need to take care of providing the translations in your application. However, keep in mind that in this case, the performance might decrease.

There is also the option to choose a third-party library for internationalization. As an example, we will pick ngx-translate, one of the most popular libraries. The library can be used for both JIT and AOT compiled versions of your app.

Angular localization with built-in i18n

At first, we take a closer look at the built-in tools of Angular. We will show you how to setup your Angular localization and how to actually translate content. Then we will look at issues like pluralization and placeholders in your content. Last but not least, we’ll present a basic workflow of how to integrate PhraseApp into your development flow.

Setup

With AOT there is nothing to set up for starting internationalization within your app. The only thing for testing different locales is starting your app with the locale code as a parameter. Here is an example if you want to test the German translations using the locale code de:

1

ng serve--aot--locale de

If you are using JIT you need to define your LOCALE_ID provider in your main module:

1

2

3

4

5

6

7

8

9

10

11

12

import{LOCALE_ID,NgModule}from'@angular/core';

import{BrowserModule}from'@angular/platform-browser';

import{AppComponent}from'../src/app/app.component';

@NgModule({

imports:[BrowserModule],

declarations:[AppComponent],

providers:[{provide:LOCALE_ID,useValue:'de'}],

bootstrap:[AppComponent]

})

exportclassAppModule{}

That’s all you need for getting started with internationalization in your Angular app using the built-in tools.

Extract your unlocalized content

In most cases, you already have an app that now needs to be translated into several languages. Extracting every existing translation can be very annoying.

Angular’s CLI provides a command that exports every content that is marked with the i18n attribute (you will read about that in the next section). Unfortunately, you need to mark every content yourself. Once this is done you can generate a file that includes every source translation with:

1

ng x18n

By default, this will generate a message.xlfXLIFF 1.2 file. With this file, you can start translating the content into multiple languages.

Best practice is to create a directory where every content that needs localization is located e.g. ./locale. Now copy your generated file into the new folder and include the locale information into the filename. For example, messages.en.xlfif the content is English or messages.de.xlf if it’s German content.

Translate your content

For translating the content the type of the built-in compiler doesn’t matter. Both options are using the same syntax.

1

<h1 i18n>My Headline<h1>

The attribute i18n will take care of the localization of this content. We highly recommend to add an ID for the translation otherwise it will be generated by angular which results in a random ID.

1

<h1 i18n="@@my_meaningful_id">My Headline<h1>

You can also add a description for your translation which could help your translators understanding the context:

1

<h1 i18n="This is a very good description@@my_meaningful_id">My Headline<h1>

In a few cases, you need to localize an image for example. You can do this by localizing the src attribute of the image tag:

1

<img[src]="a localized images"i18n-title title="the localized title of the image"i18n-x="@@meaningful_id"/>

This works with any attribute of any element.

Unfortunately, localizing content somewhere other than in an html-file is not possible yet. There is already an open issue on github but it seems to be quite tricky so it might take a while until this is implemented. If you need this feature, we recommend taking a closer look at the ngx-translate library.

Use pluralization and placeholders in your content

Angular uses the ICU message format by default. With this format, you can almost implement every constellation of pluralization and placeholders you can imagine. Here’s a basic example followed by an advanced one:

The first one simply says hello to the given name. The second example will print different content based on the value of minutes. If the minutes are unequal 0 and 1 the content of the other case will be taken where the content is dependent on the gender of a person. ICU message format is really powerful but also a bit complicated for users that are not used to it. You can read more about the format here.

Angular localization with ngx-translate

ngx-translate is an internationalization library for angular which tries to close the gap between the missing features of the built-in internationalization functionalities.

Setup

For setting it up you first need to install the library

1

npm install@ngx-translate/core--save

After that, you need to configure the TranslateModule for loading the i18n files where the translated content is located.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

import{NgModule}from'@angular/core';

import{BrowserModule}from'@angular/platform-browser';

import{HttpClientModule,HttpClient}from'@angular/common/http';

import{TranslateModule,TranslateLoader}from'@ngx-translate/core';

import{TranslateHttpLoader}from'@ngx-translate/http-loader';

import{AppComponent}from'./app';

export functionHttpLoaderFactory(http:HttpClient){

returnnewTranslateHttpLoader(http);

}

@NgModule({

imports:[

BrowserModule,

HttpClientModule,

TranslateModule.forRoot({

loader:{

provide:TranslateLoader,

useFactory:HttpLoaderFactory,

deps:[HttpClient]

}

})

],

bootstrap:[AppComponent]

})

exportclassAppModule{}

This would load the translations from /assets/i18n/<locale-code>.json. <locale-code> is the placeholder for all the languages you provide.

The next step initializes the TranslationService. Here, you have to tell the app what the default language should be. The default language will be used in cases where no translation in the target language exists.

1

2

3

4

5

6

7

8

9

exportclassAppComponent{

param={value:'world'};

constructor(translate:TranslateService){

translate.setDefaultLang('en');

translate.use('en');

}

}

Your app is now ready for i18n. You can also setup ngx-translate for working with AOT. For more details please visit the official page where some more informations about the setup are shown.

Extract your unlocalized content

ngx-translate can’t export your content automatically. But there is a plugin that can extract every translatable content and save it as JSON or Gettext pot files. Visit the github page for more information and a basic integration.

Translate the content

ngx-translate provides three ways to localize the content. You can either use the TranslationService, the TranslatePipe or the TranslateDirective to get your localized content. Use theTranslationService if you need to localize content in one of your services or controllers.

1

translate.get('my_meaningful_id').subscribe((res:string)=>{...});

For translating content in your html files you can use the TranslatePipe:

1

<h1>{{'my_meaningful_id'|translate}}

In addition to the pipe you can use the TranslateDirective to translate the content in your view:

1

<div translate>my_meaningful_id</div>

Localizing single attributes of an HTML-Tag is not possible. Therefore you need to set up the whole tag as a translation which is no problem at all. You only need to use the innerHTML-Attribute and it should work out of the box:

1

<h1[innerHTML]="'key_id_with_html_content' | translate"></h1>

Use pluralization and placeholders in your content

Placeholders can be filled in by simply passing a hash when inserting. Here the examples of the above-mentioned ways:

Automate workflow

It’s very easy to integrate PhraseApp into your yarn/npm build flow. You can simply add the phraseapp pull command into your scripts in the package.json.

Here is an example of how your scripts can look like:

1

2

3

4

5

6

7

8

9

"scripts":{

"ng":"ng",

"start":"ng serve",

"build":"phraseapp pull && ng build",

"localize":"phraseapp push",

"test":"ng test",

"lint":"ng lint",

"e2e":"ng e2e"

}

There are to actions we implement. First one is yarn localize / npm localize. This will push all translations to PhraseApp where the content can be translated by your translators or you can order translations. The second action is yarn build / npm build. Here we added phraseapp pull in order to have the translation always up to date before releasing a new version. To use this configuration you only need to install our CLI Tool and create a config in your project.

Conclusion

For your Angular localization & i18n, ngx-translate seems to be more feature complete and usable as the built-in tools. The plugins for ngx-translate are adding most of the missing features like ICU message format and extracting the content for an easy start. But we think that Angular has done some very good work on their i18n tools. The easy setup is one of the biggest advantages of Angular’s i18n feature, especially if you only use translation in your view files.