Configuring ngx-translate to load at startup in Angular
This is not trivial. I lost about four hours trying to figure how this can be done and reading a lot of links, until I found the unique place where the process was done, but not described why.
Well, I will explain why you need to do this and how.
ngx-translate is wonderful, easy to configure and easy to use… until you need to load translations instantly to assign to other things with no waits.
The problem is that ngx-translate lazyloads translations. It doesn’t matter when you need to translate a message or a component, but when you need to set translations before things are loaded, then you are in troubles.
Typically the translation in the component is like this (I’m assuming you know how to use it):
this.translate.get('My_text').subscribe((text: string) => {
console.log('Text translated: ' + text);
}
That .get
function needs to subscribe and wait for the response to have the translation available.
But if you do this (too much basic example):
const tempTrans = '';this.translate.get('My_text').subscribe((text: string) => {
tempTrans = text;
}console.log(tempTrans) // Empty
you will get nothing, because log will not wait for the .get
response.
There exists another way to retrieve the translations:
const tempTrans = '';console.log(this.translate.instant('My_text'));
But in order this to work you need to preload your translations at app startup.
And this is the tricky part, because it is not explained in official docs. Fortunately, kneefer explained it in a comment of a issue in GitHub (hard to find):
So, basically, this is what you need to do in order to have instant translations in your app: preload translations using .use()
method.
The problem that the method is async (we should wait for the result). The best way to force the application to wait for "something" to finish before it shows up is using APP_INITIALIZER
function in your AppModule
You have to add following provider to your AppModule
's providers
section:
providers: [
{
provide: APP_INITIALIZER,
useFactory: appInitializerFactory,
deps: [TranslateService],
multi: true
}
]
And define factory function appInitializerFactory
upper in the same file:
import { APP_INITIALIZER } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { LOCATION_INITIALIZED } from '@angular/common';export function appInitializerFactory(translate: TranslateService) {
return () => {
translate.setDefaultLang('es');
return translate.use('es').toPromise();
};
}
Now application will wait for translations initialization before it shows up for user.
That’s all, you can use .instant
now without problems.
Note that this function is not exactly the same as the kneefer answer. This is because RxJS has a built-in toPromise()
function that converts observables to promises, so you can shorten the appInitializerFactory
code in his answer.