Skip to content

viatcheslav-zadorozhniy/ng-i18n-dynamic

Repository files navigation

Dynamic locale change using Angular i18n

Table of contents

Introduction

So, is it possible? In short - yes!

Thanks to the clearTranslations() and loadTranslations() functions from the @angular/localize package it became possible. But, of course, you should follow some conventions so it will work properly.

Conventions

There are 2 places where the text can be marked for translation:

According to the principle of Angular Ivy compiler operations, translations in the template are performed only once. Therefore, if we want to achieve dynamic translation, we must use component code and not a template to mark text for translation.

E.g.

#translations = {
  title: $localize`Page title`,
  imageAltText: $localize`Image alt text`
};

and then use text interpolation or binding in the template:

<h1>{{ translations['title'] }}</h1>
<img [alt]="translations['imageAltText']" />

LOCALE_ID

Angular currently doesn't allow dynamic LOCALE_ID change (#47637). Although it is necessary with a dynamic locale change for proper work of the built-in pipes. To deal with it, we have several options:

ICU expressions

ICU expressions are not supported by the $localize.

Luckily, we have several alternatives:

Page title

Angular Route provides the ability to set the title of the current route via title property. It can be a string or ResolveFn.

E.g.

const routes: Routes = [
  {
    path: 'users',
    component: UsersComponent,
    title: $localize`Users page`
  }
];

In the case of a string, the title will be calculated only once. Which is not suitable for dynamic translation. Therefore, we must use ResolveFn instead.

E.g.

const routes: Routes = [
  {
    // ...the same as above
    title: () => $localize`Users page`
  }
];

One more thing to be done - implement a custom TitleStrategy to trigger the title ResolveFn recalculation. See page-title.strategy.ts for more details.

Locale change handling

With the described approach, all we need to apply the translation on locale change is to reload the current route (do not confuse it with full page reload). Of course, the translations themselves should be loaded and applied before reloading.

E.g.

this.router.navigateByUrl(this.router.url, {
  onSameUrlNavigation: 'reload'
});

{ onSameUrlNavigation: 'reload' } is required, otherwise, Angular will not perform recalculation. See usage notes.

Do not forget to update the Document dir and lang attributes according to the locale.

getLocaleDirection() function from the @angular/common package can be used to retrieve the writing direction of the locale. Intl.Locale.prototype.textInfo can be used as an alternative. But keep in mind that it is not supported by all major engines at the time of writing.

Installation

npm run initialize

Demo

This repository contains a complete example of the Angular application with dynamic locale change.

First, initialize the project as described in the installation section.

After that, run yarn start to see the app in action.

Additionally

To extract i18n messages from source code, run yarn extract-i18n.

Even when we use dynamic translation, we can run validation for missing and duplicate translations, e.g. during CI/CD. Run yarn validate-i18n to perform it.

See angular.json for more configuration details.