core
core copied to clipboard
translate pipe doesn't work for dynamic translation files when we use 'use' function (change the current language)
Hello. Thank you for the amazing library!
Current behavior
Our project has dynamic translation files loading for lazy-loading modules. This fine-tuning is obtained by implementing custom AppMissingTranslationHandler, which requests missing translations from custom TranslateLoader implementation.
Problem is reproduced when we use the translate
pipe in our templates and if we change the language => those template parts where we use translate
pipe do not get a new translation (they obtain that ones which were for default language)
Important note:
If we use setDefaultLang
instead of use
problems do not reproduce
Steps to reproduce:
- Language by default - for example ‘en';
- Open a web page where there are several lazy-loading modules;
-
MissingTranslationHandler
helps us load additional translations for the default language; - We have some translation string in template:
'SOME_TRANSLATION' | translate
- Change the language through the menu - for example to 'es';
- Inside the library a language change takes place and as a result:
currentLang
has a new value and is equal to the selected language ('es'), we have loaded the base translation file (not lazy-loading) and get the onLangChange event => - Inside pipe: translate.pipe.ts
we got new event from
onLangChange
and callupdateValue
();
Issues:
First issue - getParsedResult
returns default value, not new one for currentLang (for the complex case of retrieving a translation from the MissingTranslationHandler)
Second issue - in pipe: onTranslation
function executed twice
Third issue - in pipe - updateValue has invalid condition: isObservable(res.subscribe)
Expected behavior
When we switch translations using the use
function from the TranslateService
we get a new translations for our templates where we are using translate
pipe, even if the translation is taken from lazy-loading files.
How do you think that we should fix this?
First issue - getParsedResult
returns default value, not for currentLang (for the complex case of retrieving a translation from the MissingTranslationHandler)
updateValue(key: string, interpolateParams?: Object, translations?: any): void {
...
if (translations) {
let res = this.translate.getParsedResult(translations, key, interpolateParams);
if (isObservable(res.subscribe)) {
res.subscribe(onTranslation);
} else {
onTranslation(res);
}
}
this.translate.get(key, interpolateParams).subscribe(onTranslation);
}
here we have translations equal the base file with translations (no lazy-loading files) so we go into the if(translations) block and get res by getParsedResult
execution
translate.service.ts
public getParsedResult(translations: any, key: any, interpolateParams?: Object): any {
let res: string | Observable<string> | undefined;
...
// until the translations for the new language are not loaded res variable equals 'undefined'
if (translations) {
res = this.parser.interpolate(this.parser.getValue(translations, key), interpolateParams);
}
// (!!!) main problem - all conditions are fulfilled and
// res variable gets a value equal to the translation from the default language, although it should remain 'undefined' in order to load the needed translations by the missingTranslationHandler in the next step
// useDefaultLang - has a place to use, but it should be possible to use it for the missingTranslationHandler if we do not get a correct translation there
if (typeof res === "undefined" && this.defaultLang != null && this.defaultLang !== this.currentLang && this.useDefaultLang) {
res = this.parser.interpolate(this.parser.getValue(this.translations[this.defaultLang], key), interpolateParams);
}
if (typeof res === "undefined") {
let params: MissingTranslationHandlerParams = {key, translateService: this};
if (typeof interpolateParams !== 'undefined') {
params.interpolateParams = interpolateParams;
}
res = this.missingTranslationHandler.handle(params);
}
return typeof res !== "undefined" ? res : key;
}
see comments above in snippet
Issue: res variable gets an invalid value equal to the value from the default translations, although we already have a different current language
Possible solution:
Perhaps We should be able to avoid useDefaultLang check before missingTranslationHandler execution here and add the ability to handle this case after missingTranslationHandler fails
Second issue translate.pipe.ts
updateValue(key: string, interpolateParams?: Object, translations?: any): void {
...
if (translations) {
let res = this.translate.getParsedResult(translations, key, interpolateParams);
if (isObservable(res.subscribe)) {
res.subscribe(onTranslation);
} else {
onTranslation(res);
}
}
this.translate.get(key, interpolateParams).subscribe(onTranslation);
}
Everything in the translation block has the same logic as in this.translate.get(key, interpolateParams).subscribe(onTranslation);
=> we have the onTranslation function executed twice (because translations === this.translations[this.currentLang] from get
function)
Third issue
the same pipe and the same snippet as above:
if (isObservable(res.subscribe)) {
I think there is a flaw here. Here should be not isObservable(res.subscribe)
, only isObservable(res)
according to the same logic as in this.translate.get(...)
function;
getParsedResult
- should return Observable
Environment
ngx-translate version: 14.0.0
Angular version: 15.0.2
Browser:
- [ 112.0.5615.137 ] Chrome (desktop) version XX
I also have the same issue with even if I use setDefaultLang
, I figure it out and I don't know if it's a good practice to do it, what I did was to use setDefaultLang but in the app.component and shared service with the app.component and use a var to set the Language. Any update on this issue please let me know.