6

I have a angular library where I created a LanguageModule defined as follows

@NgModule({
    imports: [
      TranslateModule.forRoot({
        loader: {
          provide: TranslateLoader,
          useFactory: (createTranslateLoader),
          deps: [HttpClient]
        },
      })
    ],
    exports: [TranslateModule]
  })
  export class LanguageModule {
    public constructor(translateSvc: TranslateService, http: HttpClient) {
      translateSvc.onLangChange
        .pipe(
          switchMap((currentLang: LangChangeEvent) => zip(
            of(currentLang),
            http.get(`assets/i18n/${currentLang.lang}.json`),
          ))
        ).subscribe(([currentLang, localizations, syncfusionLocalization]) => {
          translateSvc.setTranslation(translateSvc.currentLang, localizations, true);
          setCulture(currentLang.lang);
        });
  
      translateSvc.use(translateSvc.getDefaultLang());
    }
  }

This allows me to merge library and app localization files.

Inside my app I import the LanguageModule in the main app.module.ts, where I also import my CoreModule, defined as follows:

@NgModule({
    imports: [
      CommonModule,
      HttpClientModule,
      BrowserAnimationsModule,
      ...
    ],
    declarations: [],
    providers: [
        ....
      // Http interceptors
      {
        provide: HTTP_INTERCEPTORS,
        useClass: AuthInterceptor,
        multi: true
      }
    ]
  })
  export class CoreModule {  
    public constructor(@Optional() @SkipSelf() parentModule: CoreModule) {
      if (parentModule) {
        throw new Error('CoreModule has already been loaded. Import CoreModule in the AppModule only.');
      }
    }  
  }

In the AuthInterceptor, if I inject the TranslateService I get the following error: Circular dependency in DI detected for InjectionToken HTTP_INTERCEPTORS.

What am I missing?

Aaron Ullal
  • 4,855
  • 8
  • 35
  • 63
  • Is it possible for you to provide a stackblitz? I would like to what your AuthInterceptor have. I did also had created a library for my ngx-translate, but realized that the `TranslateModule.forRoot({})` still had to be instantiated in the project that does import the library. Also usefull if you wants to merge multiple i18n files together. _the one from your library and the one from you local project_ – Raphaël Balet Jul 09 '21 at 08:20
  • normally you can solve a Circular dependency using `injector` or moving the components to diferents Module, see this https://stackoverflow.com/questions/67152273/angular-circular-dependency-when-inject-translateservice-to-interceptor (It's looks like your problem) – Eliseo Jul 09 '21 at 09:07
  • @Eliseo I have tried with the injector but still get the same error. In this case I cannot move the interceptor to another module – Aaron Ullal Jul 09 '21 at 09:29

3 Answers3

5

After losing my mind it seems someone on github found a solution, by removing defaultLanguage from the TranslateModule.forRoot() in AppModule. https://github.com/gilsdav/ngx-translate-router/issues/94#issuecomment-791584329

AFlawlessGuy
  • 98
  • 1
  • 7
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Sep 28 '21 at 19:53
  • While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes. - [From Review](/review/late-answers/29943776) – tomerpacific Sep 28 '21 at 21:13
  • 1
    This works! No clue why to be honest, but it does! – Aaron Ullal Sep 29 '21 at 07:01
2

Your TranslateService depends on HttpClient, HttpClient depends on HTTP_INTERCEPTORS which include AuthInterceptor.

So when you add TranslateService as a dependency for AuthInterceptor you get a full circle: TranslateService => TranslateLoader => HttpClient => AuthInterceptor => TranslateService.

There is an official guide here https://angular.io/errors/NG0200

kemsky
  • 14,727
  • 3
  • 32
  • 51
0

Just solved the problem by removing the HttpClient Dependency and making the Translate i18n request using fetch().

getTranslation(lang: string): Observable<any> {
        const timestamp = new Date().getTime();
        const url = `${environment.i18nURL}/${lang}.json?ts=${timestamp}`;
        return from(fetch(url).then((el: any) => el.json()));
}

export function CustomLoaderFactory() {
    return new CustomTranslateLoader();
}

@NgModule({
 imports: [
    TranslateModule.forRoot({
        defaultLanguage: environment.defaultLanguage,
        loader: {
            provide: TranslateLoader,
            useFactory: CustomLoaderFactory,
            deps: [], // Removed => HttpClient
        },
    }),
],
...
axelferreira
  • 1,990
  • 1
  • 12
  • 10