core icon indicating copy to clipboard operation
core copied to clipboard

.forChild({}) is not loading anything

Open vladkasianenko opened this issue 3 years ago • 4 comments

Hello.

I'm facing an issue with loading translations. The thing is only main is loading, but everything else is not. What I'm doing wrong?

translate.loader.ts

import { TranslateLoader } from '@ngx-translate/core';
import { Observable, from } from 'rxjs';

export class TranslateLoaderFactory {
  static forModule(module: string): any {
    console.log('module', module); // calls for each feature
    return class LazyTranslateLoader implements TranslateLoader {

      getTranslation(lang: string): Observable<any> {
        console.log('module for ' + lang, module); // calls only for main translations (from AppModule)
        return from(import(`assets/i18n/${module}/${lang}.json`));
      }
    };
  }
}

app.module.ts

@NgModule({
  imports: [
    StoreModule.forRoot({
      ...
    }),
    EffectsModule.forRoot([
      MainEffects  // here's  an effect that call: `.setDefaultLang('en')` and `.use('en')` 
    ]),
    TranslateModule.forRoot({
      extend: true,
      isolate: false,
      loader: {
        provide: TranslateLoader,
        useClass: TranslateLoaderFactory.forModule('main'),
        deps: [HttpClient],
      },
      compiler: {
        provide: TranslateCompiler,
        useClass: TranslateMessageFormatCompiler,
      },
    }),
    ... // other modules
  ]
})
export class AppModule {}

shared.module.ts

@NgModule({
  imports: [TranslateModule], // other modules as well
  exports: [TranslateModule], // other modules as well
})
export class SharedModule {}

feature1.module1.ts

@NgModule({
  imports: [
    TranslateModule.forChild({
      extend: true,
      isolate: false,
      loader: {
        provide: TranslateLoader,
        useClass: TranslateLoaderFactory.forModule('feature1'),
        deps: [HttpClient],
      },
      compiler: {
        provide: TranslateCompiler,
        useClass: TranslateMessageFormatCompiler,
      },
    }),
    ... // other modules
  ]
})
export class Feature1 {}

vladkasianenko avatar Apr 15 '21 15:04 vladkasianenko

Duplicate of #1266 ? This seems to be old problem because we couldn't make forChild to work correctly when there was a need, so we just went with single json file per project (actually we have 2 files, but loading both on app init).

Also, this library seems to be abandoned as its creator joined Angular team to work on native angular i18n library.

liesahead avatar May 28 '21 15:05 liesahead

Hello, I did workaround to this problem and using small function it does work as below.

  • In lazy loading module,
TranslateModule.forChild({
      loader: {
        provide: TranslateLoader,
        useFactory: HttpLoaderFactory,
        deps: [HttpClient]
      },
      extend: true
    })

export function HttpLoaderFactory(http: HttpClient) {
  return new TranslateHttpLoader(http, './path-to-child-json/', '.json');
}
  • in root component of the child module

constructor(
    private translate: TranslateService
  ) {
    // Calls when module initialize first time
    this.changeLanguage(this.translate.currentLang);
    // Calls when user changes language manually
    this.translate.onLangChange.subscribe((event: LangChangeEvent) => {
      this.changeLanguage(event.lang);
    });
  }

  changeLanguage(lang: string) {
    if (this.currentLang === lang) {
      return;
    }
    this.currentLang = lang;
    this.translate.currentLang = '';
    this.translate.use(lang);
  }

kunjan343 avatar Jun 25 '21 16:06 kunjan343

For lazy-loaded modules with different translation loaders (loading .json from different files) it seems to be either (in the case of the lazy-loaded):

  • (LazyModule isolate: false, extend: true) React to parent module translation events automatically without having to connect anything, just as they say, but cannot load the lazy loaded specific files.
  • (LazyModule isolate: true, extend: true) We have to propagate changes to parent's translation event changes to the lazy child ourselves, and we can have our specific translations working! But the parent's translation won't work.

It's like I can't blend the two.

I got pretty close though maybe you could have a look and play within StackBlitz: https://stackblitz.com/edit/translations-and-lazy-loading?file=README.md

eulersson avatar Jul 15 '21 12:07 eulersson

@vladkasianenko @docwhite @kunjan343 @liesahead @peterblazejewicz I found the best workaround to make it works with extend: true and isolate: false. The solution is to force the loading of the translation in the constructor of your lazy module: constructor(private translateService: TranslateService) { this.translateService.getTranslation(this.translateService.currentLang); }

I opened a PR to add this to the README doc: https://github.com/ngx-translate/core/pull/1328/files However you will still encounter problem if you want to change lang dynamically without refreshing the page.

pegaltier avatar Aug 13 '21 12:08 pegaltier