Search code examples
angulartranslationngx-translate

Angular ngx-translate problem with forChild in non-lazy-load modules


I have problem with TranslateModule.forChild() in some case it doesn't triggered


export function MainHttpLoaderFactory(http: HttpClient) {
  return new TranslateHttpLoader(http, `${Environment.ASSETS_BASE_URL}/assets/i18n/main/`, '.json');
}

@NgModule({
  declarations: [
    AppComponent,
  ],
  exports: [],
  bootstrap: [AppComponent],
  imports: [
    CommonModule,
    TranslateModule.forRoot({
      loader: {
        provide: TranslateLoader,
        useFactory: MainHttpLoaderFactory,
        deps: [HttpClient]
      }
    }),
    ChildModule
  ]

and ChildModule:



export function ChildHttpLoaderFactory(http: HttpClient) {
  return new TranslateHttpLoader(http, `${Environment.ASSETS_BASE_URL}/assets/i18n/child/`, '.json');
}



@NgModule({
  declarations: [ChildComponent],
  imports: [
    CommonModule,
    TableModule,
    TranslateModule.forChild({
      loader: {
        provide: TranslateLoader,
        useFactory: ChildHttpLoaderFactory,
        deps: [HttpClient]
      },
      extend: true
    }),
  ],
  providers: [TranslateService],
  exports: [
    ChildComponent
  ]
})
export class ChildModule {
  constructor(private translate: TranslateService) {
    this.translate.currentLang = '';
    this.translate.use('en');
  }
}

And this is problem, when I just import ChildModule to ParentModule and use component by tag, ChildHttpLoaderFactory doesn't triggered. But if you use lazy-load - everything is okay. So, maybe someone know how to trigger it?

Thank you for your time


Solution

  • This happens because TranslateModule.forChild() is designed to work for lazy-loaded modules. Angular does not create a new child injector, for translations, when you are eagerly importing a child module. Because of this, your ChildHttpLoaderFactory won’t be called.

    As you state, one solution is to use lazy-loading so that each module has its own translation loader.

    The alternative is simply to use one TranslateModule.forRoot().

    In your AppModule (or any root module shared between children) use:

    TranslateModule.forRoot({
      loader: {
        provide: TranslateLoader,
        useFactory: MainHttpLoaderFactory,
        deps: [HttpClient]
      }
    })
    

    Then in your child module import TranslateModule without calling forChild()

    @NgModule({
      imports: [CommonModule, TranslateModule],
      declarations: [ChildComponent],
      exports: [ChildComponent]
    })
    export class ChildModule {
      constructor(private translate: TranslateService) {
        // manually load or merge child translations:
        //  1. you could directly load a JSON via HttpClient
        //  2. or set them in code: this.translate.setTranslation('en', {...}, true);
      }
    }
    

    If you need child-specific translations files, you can do it manually in your child module/component.

    this.http.get('/assets/i18n/child/en.json')
      .subscribe(childEn => {
        this.translate.setTranslation('en', childEn, /* merge */ true);
      });