Expected/desired behavior
I am new in angular , Our application is large and we don't want to load whole translation in single call . We want to load translation in per module as well as per component wise.
My environment is :
Angular CLI: 6.0.8
Node: 8.10.0
typescript 2.7.2
if you search around there are some solutions but those do not work, I am also having this problem and so far i can not find any way around it.
Hi @Vishnu0522
as you see in the official doc of ngx-translate, there is this paragraph...if you are using lazy loading and you have a different modules, you can configure different services by using isolate: true.
With this approach, the service is a completely isolated instance (for translations, current lang, events, ...).
@adelloste Using this approach, I run into the issue described here https://github.com/ngx-translate/core/issues/876
Do you know a way around this issue?
How to load translations per module is described in the documentation. If you want to load on a component by component basis you can try something like this:
import { Component, OnInit } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { TranslateService } from '@ngx-translate/core';
export const EN_TRANSLATIONS = {
'found': 'found',
'not found': 'not found'
};
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
translationsUrl = 'assets/i18n';
constructor(private translate: TranslateService, private http: HttpClient) {
this.translate.setDefaultLang('en');
this.translate.use('de');
this.translate.setTranslation('en', EN_TRANSLATIONS);
}
ngOnInit() {
this.loadTranslations('de');
}
loadTranslations(locale: string) {
return this.http.get(${this.translationsUrl}/${this.constructor.name}-${locale}.json).subscribe((data: any) => {
this.translate.setTranslation(locale, data);
});
}
}
Tested w/ Angular 6
Here is well explained.
https://medium.com/@TuiZ/how-to-split-your-i18n-file-per-lazy-loaded-module-with-ngx-translate-3caef57a738f
However, I didn't get it working in my project. Seems that even with the flag isolate: true i'm still getting the same TranslateService with root translations.
Experiencing the same as @david-dlc-cerezo, the xhr call is only made for the file specified in the forRoot factory, the lazy-loaded child modules factories are called, but XHR request does not fire.
As of, translation service only has the root translations.
@shane-arthur I finally kind of get it working but I'm not sure how/why 馃ぃ
One thing I did it was to add TranslateService to the providers array on the module where I use Translate.forChild
```typescript
@NgModule({
imports: [
...,
TranslateModule.forChild({
loader: {
provide: TranslateLoader,
useFactory: MyImporterFactory
},
isolate: true
}),
...
],
providers: [
...,
TranslateService
]
})
export class MyModule {}
````
But I can ensure this was what finally isolated the TranslateService in my Module.
Angular documentation about providers says:
When the router creates a component within the lazy-loaded context, Angular prefers service instances created from these providers to the service instances of the application root injector.
The original @Vishnu0522 question asked also about loading a different set of translations for each module... Well if for a module you should provide a TranslateLoader with your customized public getTranslation(lang: string): Observable<any> method, my guess is that in a component you should do the same.
I just tested a PoC about that... and worked! 馃帀
To have a different TranslateService with its TranslateLoader on each Component:
```typescript
class MyTranslateLoader implements TranslateLoader {
constructor() {}
public getTranslation(lang: string): Observable
const translations = ...// Obtain your translations as you wish
return of(translations);
}
}
// AoT requires an exported function for factories
export function MyTranslateLoaderFactory() {
return new MyTranslateLoader();
}
@Component({
selector: 'my-component',
templateUrl: './my-component.component.html',
styleUrls: ['./my-component.component.scss'],
providers: [
TranslateService,
{
provide: TranslateLoader,
useFactory: MyTranslateLoaderFactory
}
]
})
export class SchoolEditionComponent implements OnInit {
constructor(
private readonly translate: TranslateService,
) {}
ngOnInit() {
// This will show the loaded translations
this.translate.getTranslation('en').subscribe(translations => console.log(translations));
}
}
````
@shane-arthur I finally kind of get it working but I'm not sure how/why
One thing I did it was to add
TranslateServiceto the providers array on the module where I useTranslate.forChild@NgModule({ imports: [ ..., TranslateModule.forChild({ loader: { provide: TranslateLoader, useFactory: MyImporterFactory }, isolate: true }), ... ], providers: [ ..., TranslateService ] }) export class MyModule {}But I can ensure this was what finally isolated the
TranslateServicein my Module.Angular documentation about providers says:
When the router creates a component within the lazy-loaded context, Angular prefers service instances created from these providers to the service instances of the application root injector.
The original @Vishnu0522 question asked also about loading a different set of translations for each module... Well if for a module you should provide a
TranslateLoaderwith your customizedpublic getTranslation(lang: string): Observable<any>method, my guess is that in a component you should do the same.
@david-dlc-cerezo the solution from Medium was working absolutely fine earlier but now it doesn't work. I have Translate service provided in lazy loaded module as well. but unable to split the translate file per module.Isolate: true does not work at all. This is in angular 6 as well as 7. It was working perfectly fine not sure what affected it and where.
I was struggling with the same issue and got it working when using _isolate: true_ and setting a default language(and current if needed) again.
For app module:
export class AppTranslateLoader implements TranslateLoader {
getTranslation(lang: string): Observable<any> {
return from(import(`../assets/i18n/${lang}.json`));
}
}
TranslateModule.forRoot({
defaultLanguage: 'ET',
loader: {
provide: TranslateLoader,
useClass: AppTranslateLoader,
}
}),
md5-a982be11ced3ba76f76443f714ae068e
export class LazyTranslateLoader implements TranslateLoader {
getTranslation(lang: string): Observable<any> {
return from(import(`../../assets/i18n/lazyModule/${lang}.json`));
}
}
md5-4ed49727091940cd98e4905162042575
TranslateModule.forChild({
defaultLanguage: 'ET',
isolate: true,
loader: {provide: TranslateLoader, useClass: LazyTranslateLoader}
}),
md5-d391db72f04a0b3eb9838af8340d7052
constructor(translate: TranslateService, store: Store<fromCore.State>) {
store.pipe(select(UserSelectors.selectUserLanguage)).subscribe(
(lang) => translate.use(lang)
);
}
I'm not using http loader due to browser cache issues.
Most helpful comment
if you search around there are some solutions but those do not work, I am also having this problem and so far i can not find any way around it.