core icon indicating copy to clipboard operation
core copied to clipboard

Translation for dynamic components which are loaded lazily doesn't work

Open Jannis37 opened this issue 1 year ago • 1 comments

Current behavior

In my application I am using dynamic components which are loaded lazily. For every component also exists one module. Furthermore I want to store the translations for every component in a seperate folder. I tried to solve this issue by defining different paths inside the HttpLoaderFactory-function. The code below is an example of one module.

export function HttpLoaderFactory(http: HttpClient) {
  return new TranslateHttpLoader(http, './assets/i18n/lazy/','.json');
}

const routes: Routes = [
  {path: '', component: LazyComponent}
]

@NgModule({
  declarations: [
    LazyComponent
  ],
  imports: [
    CommonModule,
    RouterModule.forChild(routes),
    TranslateModule.forChild({
      loader: {
        provide: TranslateLoader,
        useFactory: HttpLoaderFactory,
        deps: [HttpClient]
      },
      isolate: true
    })
  ]
})
export class LazyModule { 
  static getComponent() {
    return LazyComponent;
  }
}

This also works completely fine, when I am using lazy loading via routes. But when I try to load the component dynamic (not via routes) as shown below, ngx-translate seems to use the path ./assets/i18n/[lang].json and not /assets/i18n/lazy/[lang].json as defined in the module above.

onCreateDynamicComp() {
    const viewContainerRef = this.view.viewContainerRef;
    import('./lazy/lazy.module').then(({LazyModule}) => {
      const comp = LazyModule.getComponent();
      viewContainerRef.clear();
      viewContainerRef.createComponent<any>(comp);
    })
}

Expected behavior

Translations should be loaded from the path defined in the corresponding module.

How do you think that we should fix this?

Minimal reproduction of the problem with instructions

https://stackblitz.com/edit/github-jktcya-cpjbpn?file=src/app/lazy/lazy.module.ts

Inside the app there are four buttons:

  • Change Language: To Toggle the language
  • Create dynamic Component: Adds a dynamic component to the current page. The content should be translated aswell, when the Change Language-Button gets clicked. This is the thing which doesn't work.
  • Lazy: Navigates to /lazy. This loads the same component as created with the Create dynamic Component-Button. The difference is that the translation works with this method.
  • Home: Navigates to back to an empty route.

Environment


ngx-translate version: 14.0.0
Angular version: 13.3.0 also tested with 14.1.0


Browser:
- [x] Chrome (desktop) Version 103.0.5060.134 (Official Build) (64-bit)
- [ ] Chrome (Android) version XX
- [ ] Chrome (iOS) version XX
- [ ] Firefox version XX
- [ ] Safari (desktop) version XX
- [ ] Safari (iOS) version XX
- [ ] IE version XX
- [ ] Edge version XX
 
For Tooling issues:
- Node version: v16.14.2
- Platform:  Windows

Others:

Jannis37 avatar Aug 09 '22 16:08 Jannis37

I have exactly the same issue. In my case, we created a component dynamically (module context injected) via Module Federation, and it works only for one instance of a component.

@NgModule({
  imports: [
    EffectsModule.forFeature([TranslationEffect]),
    TranslateModule.forRoot({
      loader: {
        provide: TranslateLoader,
        useClass: CustomLoader,
        deps: [APP_NAME, HttpClient],
      },
      extend: true,
    }),
  ],
  providers: [TranslationService],
  exports: [TranslateModule],
})
export class TranslationModuleForRoot {}

@NgModule({
  imports: [
    EffectsModule.forFeature([TranslationEffect]),
    TranslateModule.forChild({
      loader: {
        provide: TranslateLoader,
        useClass: CustomLoader,
        deps: [APP_NAME, HttpClient],
      },
      isolate: true,
      missingTranslationHandler: {
        provide: MissingTranslationHandler,
        useClass: CustomMissingTranslationHandler,
      },
    }),
  ],
  providers: [TranslationService],
  exports: [TranslateModule],
})
export class TranslationModuleForFeature {}

@NgModule({
  imports: [
    EffectsModule.forFeature([TranslationEffect]),
    TranslateModule.forChild({
      loader: {
        provide: TranslateLoader,
        useClass: CustomLoader,
        deps: [APP_NAME, HttpClient],
      },
      isolate: false,
    }),
  ],
  providers: [TranslationService],
  exports: [TranslateModule],
})
export class TranslationModuleForLazy {}

@NgModule({})
export class TranslationModule {
  static forRoot(
    appName: string,
  ): ModuleWithProviders<TranslationModuleForRoot> {
    return {
      ngModule: TranslationModuleForRoot,
      providers: [provideAppName(appName)],
    };
  }

  static forFeature(
    appName: string,
  ): ModuleWithProviders<TranslationModuleForFeature> {
    return {
      ngModule: TranslationModuleForFeature,
      providers: [provideAppName(appName)],
    };
  }

  static forLazy(
    appName: string,
  ): ModuleWithProviders<TranslationModuleForLazy> {
    return {
      ngModule: TranslationModuleForLazy,
      providers: [provideAppName(appName)],
    };
  }
}

czareknster avatar May 18 '23 07:05 czareknster