'Angular i18 internationalization, language change programmatically
From this link I tried to implement the i18 internationalization in my Angular 6 app in order to translate in English and Italian some text and datetime in my html template.
https://next.angular.io/guide/i18n
I understood that this function consist in 3 phases:
Define translation text. No problem, I created a folder src/locale folder with 2 files messages.en.xlf (and message.it.xlf); here is an example for en version.
Hello i18n! (en-EN) An introduction header for this sample User welcomelink this text to html pages with appropriates tag, and also here no problem, there is my example tag in my app.translations.html.
Hello i18n!
Now, I read the way (3. phase) to localize the app during startup (some editing in Angular.json file and start ng serve with configuration option); but, instead of this, I would change the language of the app programmatically. In other words, I want a command such as
SwitchAppLanguage('en')
For example, so that the user can change it self by a button or the app can do this reading the browser default language. How can I do this?
Edit
I tried to edit my angular.json file in this way
"configurations": {
"production": {
"i18nFile": "src/locale/messages.it.xlf",
"i18nFormat": "xlf",
"i18nLocale": "it",
(...)
And, after ng build and ng serve, I expect to see the Italian text but it doesn't happens (and the app start and serve correctly). What have I done wrong?
Solution 1:[1]
I solved this issue for dev-mode this way. maybe someone could benefit from this.
This is just a temporary solution untill Angular provides this feature in ivy i18n.
Drawback: can only be done when language files are generated to JSON :-(
polyfills.ts:
import { loadTranslations } from '@angular/localize';
import { isDevMode } from '@angular/core';
// All translation objects: must be json files for runtime-conditions! (XLF not supported)
import * as fr from "./i18n/messages.fr.json";
import * as nl from "./i18n/messages.nl.json";
import * as en from "./i18n/messages.json";
// Non-official translation loader to switch languages at runtime in development mode
if(isDevMode()){
let translations = {};
let lang = localStorage.getItem("lang");
if(lang === "fr"){
translations = fr;
} else if (lang === "nl"){
translations = nl;
} else{
translations = en;
}
// load translations at runtime
loadTranslations(translations['default']['translations']);
}
Solution 2:[2]
So if you use JIT, you can use webpacks loader to hotswap language files:
main.ts
import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
import { environment } from './environments/environment';
import { getTranslationProviders } from './app/providers/i18n.provider';
import { LocaleService } from './app/services/locale.service';
if ( environment.production ) {
enableProdMode();
}
const locale = new LocaleService();
locale.getLocale().then( ( localeValue ) => {
getTranslationProviders( localeValue ).then( providers => {
platformBrowserDynamic().bootstrapModule( AppModule, { providers } )
.catch( err => console.log( err ) );
} );
} );
i18n.provider
import { TRANSLATIONS, TRANSLATIONS_FORMAT } from '@angular/core';
declare const require;
export function getTranslationProviders( locale: string ): Promise<any[]> {
// Get the locale id as arugment or from the global
//
const localeValue = locale || document[ 'locale' ] as string;
// return no providers if fail to get translation file for locale
//
const noProviders: Object[] = [];
// No locale or AU, doesn't require translation
//
if ( !localeValue || localeValue === 'au' ) {
return Promise.resolve( noProviders );
}
try {
const translations = require( `raw-loader!../../locale/messages.${ localeValue }.xlf` );
return Promise.resolve( [
{ provide: TRANSLATIONS, useValue: translations },
{ provide: TRANSLATIONS_FORMAT, useValue: 'xlf' }
] );
} catch ( error ) {
console.error( error );
return Promise.resolve( noProviders );
}
}
and the local.service
import { WindowRef } from 'app/services/windowRef.service';
import { environment } from 'environments/environment';
@Injectable()
export class LocaleService {
_locale: string;
set locale( val: string ) {
this._locale = val;
}
get locale() {
return this._locale;
}
constructor() {
this.setLocale();
}
setLocale() {
const winRef = new WindowRef();
this.locale = ( environment.countryLookup[ document.location.hostname ] || 'au' ).toLowerCase();
const match = document.location.search.match( /au|nz/ );
if ( match ) {
this.locale = match.shift();
}
// store locale in document
//
winRef.nativeWindow.document.locale = this.locale;
}
getLocale(): Promise<string> {
return Promise.resolve( this.locale );
}
}
You will have to refactor it a bit to match your project, but I hope you get the gist. This might be a solution until Ivy supports proper language switching.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Niek Vandael |
| Solution 2 | Mattijs |
