- Introduction
- Conventions
- LOCALE_ID
- ICU expressions
- Page title
- Locale change handling
- Installation
- Demo
- Additionally
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.
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']" />
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:
- provide it directly to the pipes
- implement wrappers for the pipes and provide it there
- use ECMAScript Internationalization API instead
- implement custom locale provider (e.g. locale.provider.ts)
ICU expressions are not supported by the $localize.
Luckily, we have several alternatives:
- Angular ICU pipes (I18nSelectPipe, I18nPluralPipe)
- ECMAScript Internationalization API, such as Intl.PluralRules
- Intl MessageFormat library
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.
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.
npm run initialize
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.
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.