jsverse / transloco

🚀 😍 The internationalization (i18n) library for Angular
https://jsverse.github.io/transloco/
MIT License
2k stars 193 forks source link

lazy loading with scope, doen't find key of main scope when pressing F5 #422

Open tomalaforge opened 3 years ago

tomalaforge commented 3 years ago

I have an application with lazy loaded module.

I set up my application like describe in the installation documentation. ( TranslocoRootModule is imported in my AppModule ) and I have a assets folder:

assets
-- i18n
----- fr.json
----- en.json
----- pageB
-------- fr.json
-------- en.json

containing

fr.json:

{
   "title": "test"
}

pageB > fr.json

{
  "header": "page B"
}

pageB is a lazy loaded module :

  {
    path: 'pageB',
    loadChildren: () => import('./modules/pages/pageB/pageB.module').then(mod => mod.pageBModule)
  }
@NgModule({
  declarations: [PageBComponent],
  imports: [
    TranslocoModule
    PageBRoutingModule
  ],
  providers: [
    {
      provide: TRANSLOCO_SCOPE,
      useValue: {
        scope: 'pageB'
      }
    }
  ]
})
export class PageBModule { }

and my template is:

<ng-container *transloco="let trans'">
    {{trans('pageB.header')}}
</ng-container>
{{'title' | transloco}}

When I launch my application and navigate to pageB => translation is good

However if I refresh my page from pageB => pageB.header is correctly translate but title translation is missing. => My pageB score is well loaded but not my root scope. When I suscribe to event$ and filter on translationLoadSuccess => I can see the scope pageB loaded and if I go back to main page, then the scope 'null' is loaded.

I was expected that the root scope will be loaded at the start of the application, but it seems to be override by the provided scope if application is launched when a module with a overriding TRANSLOCO_SCOPE.

Did I miss something? I have read the document many times and haven't find any thing else.

Thank you for your help

tomalaforge commented 3 years ago

Heads up after digging: I've cloned your projet and tested it and it's working well, but the version is angular v7 and compiler have changed to Ivy with import module differently. I've done the same with angular v11 and it's not working. Only scope json is loaded when i refresh my page on lazy loaded module.

The only hack that I found is to provide the scope and the root scope like below:

@NgModule({
  declarations: [LazyComponent],
  imports: [
    CommonModule,
    TranslocoModule,
    LazyRoutingModule
  ],
  providers: [
    {
      provide: TRANSLOCO_SCOPE,
      useValue: 'lazy',
      multi: true
    },
    // hack to load root scope when page refresh (to be improved)
    {
      provide: TRANSLOCO_SCOPE,
      useValue: null,
      multi: true
    }
  ]
})
export class LazyModule { }
itayod commented 3 years ago

@tomalaforge please read this guide carefully, you might find your answer there

tomalaforge commented 3 years ago

@itayod Thanks. I've already read that article. But I found that using the scope parameter in the directive is working (which is understandable because I'm not overriding the TRANSLOCO_SCOPE token). But what I don't get is that in your example (in github), you make it work by overriding the token in the module provider array which doesn't work if you simply create a new project v11, add the library and create a lazy module with a scope.

thanks anyway for your answer

FabienDehopre commented 10 months ago

I have the exact same issue as @tomalaforge. This issue is opened since more than 2 years now. I read the article but didn't find a solution that would work easily for me. Can't the pipe and directive also listen to the "translationLoadSuccess" event and refresh the output just like for the "langChanges$" event? Also, about the structural directive, can't it be solution to not memoize the translate result if the translation wasn't found (output = input)? Or provide an option to skip the memoization in this case?

FabienDehopre commented 10 months ago

After a couple of hour of investigation, this might be related to the withEnabledBlockingInitialNavigation() router feature. When turned on, the "main" language file (unscoped) is not loaded before the lazy loaded scoped translation and thus is never loaded. At least, it's what I've found when setting my breakpoint in the _loadDependencies method of the TranslocoService. The isLoadedTranslation() method return true even if the unscoped translation is not loaded because it find the scoped translations from the lazy loaded module. Removing the withEnabledBlockingInitialNavigation() feature from the router configuration solve the issue for me. I hope this can help to try to fix the issue.