Core: How to load translation files per module

Created on 15 Dec 2017  路  8Comments  路  Source: ngx-translate/core

[ ] bug report => check the FAQ and search github for a similar issue or PR before submitting
[X] support request => check the FAQ and search github for a similar issue before submitting
[ ] feature request

Current behavior
in app.module.ts imports : ..., CatalogsModule, AuthModule, ...
always load /i18n/auth/*.json

Expected/desired behavior
load /i18n/catalogs/*.json then i go to /catalogs route

Reproduction of the problem

app.module.ts:


import {HttpClientModule} from '@angular/common/http';
import {BrowserModule} from '@angular/platform-browser';
import {NgModule} from '@angular/core';
import 'rxjs/add/operator/do';
import 'rxjs/add/operator/catch';
import 'rxjs/add/observable/throw';

import {AppComponent} from './app.component';
import {AuthModule} from './auth/auth.module';
import {CatalogsModule} from './catalogs/catalogs.module';
import {DashboardModule} from './dashboard/dashboard.module';
import {NotFoundComponent} from './not-found/not-found.component';
import {Routing} from './app.routing';
import {SvgIconComponent} from './svg-icon/svg-icon.component';

@NgModule({
  imports: [
    BrowserModule,
    HttpClientModule,
    Routing,
    CatalogsModule,
    AuthModule,
    DashboardModule
  ],
  declarations: [AppComponent, SvgIconComponent, NotFoundComponent],
  bootstrap: [AppComponent]
})
export class AppModule { }

auth.module.ts


import {NgModule} from '@angular/core';
import {CommonModule} from '@angular/common';
import {HttpClient, HttpClientModule} from '@angular/common/http';
import {RouterModule} from '@angular/router';
import {TranslateModule, TranslateLoader, MissingTranslationHandler} from '@ngx-translate/core';
import {TranslateHttpLoader} from '@ngx-translate/http-loader';
import {FormsModule, ReactiveFormsModule} from '@angular/forms';

import {IndexComponent} from './index/index.component';
import {LoginComponent} from './login/login.component';
import {RegistrationComponent} from './registration/registration.component';
import {RestorePasswordComponent} from './restore-password/restore-password.component';
import {AuthService} from '../services/auth/auth.service';
import {ConfirmComponent} from './registration/confirm/confirm.component';
import {NewPasswordComponent} from './restore-password/new-password/new-password.component';
import {TranslateHandler} from '../classes/translate-handler';
import {LoginGuard} from '../guards/login.guard';
import {RegistrationConfirmGuard} from '../guards/registration-confirm.guard';

export function AuthHttpLoaderFactory(httpClient: HttpClient) {
  return new TranslateHttpLoader(httpClient, 'i18n/auth/', '.json');
}

@NgModule({
  imports: [
    CommonModule,
    RouterModule,
    HttpClientModule,
    FormsModule,
    ReactiveFormsModule,
    TranslateModule.forChild({
      loader: {
        provide: TranslateLoader,
        useFactory: (AuthHttpLoaderFactory),
        deps: [HttpClient]
      },
      isolate: true,
      missingTranslationHandler: [{provide: MissingTranslationHandler, useClass: TranslateHandler}]
    })
  ],
  declarations: [RegistrationComponent, LoginComponent, IndexComponent, RestorePasswordComponent, ConfirmComponent, NewPasswordComponent],
  bootstrap: [IndexComponent],
  providers: [AuthService, LoginGuard, RegistrationConfirmGuard]
})
export class AuthModule {}

catalogs.module.ts


import {NgModule} from '@angular/core';
import {CommonModule} from '@angular/common';
import {CatalogComponent} from './catalog/catalog.component';
import {ClientComponent} from './client/client.component';
import {MissingTranslationHandler, TranslateLoader, TranslateModule} from '@ngx-translate/core';
import {RouterModule} from '@angular/router';
import {HttpClient, HttpClientModule} from '@angular/common/http';
import {TranslateHandler} from '../classes/translate-handler';
import {TranslateHttpLoader} from '@ngx-translate/http-loader';
import {MenuModule} from '../menu/menu.module';
import {TranslateStore} from '@ngx-translate/core/src/translate.store';

export function CatalogsHttpLoaderFactory(httpClient: HttpClient) {
  return new TranslateHttpLoader(httpClient, 'i18n/catalogs/', '.json');
}

@NgModule({
  imports: [
    CommonModule,
    RouterModule,
    HttpClientModule,
    TranslateModule.forChild({
      loader: {
        provide: TranslateLoader,
        useFactory: CatalogsHttpLoaderFactory,
        deps: [HttpClient]
      },
      missingTranslationHandler: [{provide: MissingTranslationHandler, useClass: TranslateHandler}]
    }),
    MenuModule
  ],
  declarations: [CatalogComponent, ClientComponent]
})
export class CatalogsModule {}

What is the expected behavior?
if go to AuthModule routing - download /18n/auth/*.json
if CatalogModule - download /i18n/catalogs/*.json

What is the motivation / use case for changing the behavior?
Download the translation needed only for this module

Please tell us about your environment:

  • Node: 8.5.0
  • NPM: 5.5.1
  • ngx-translate version: 8.0.0
  • Angular CLI: 1.5.0
  • Angular version: 5.0.0
  • Browser: [all]

Most helpful comment

AFAIU, you don't need a translation per module, but a translation per user group.


The simplest way is creating different translation flavors, like admin-en.json, user-en.json, moderator-en.json. When selecting the language, you would need only use translateService.use('admin-en')


The advanced (and organized way) is creating a specific loader. It would organize like this:

  • /assets/i18n/user/en.json
  • /assets/i18n/user/fr.json
  • /assets/i18n/admin/en.json
  • /assets/i18n/admin/fr.json
@Injectable()
export class MyCustomHttpLoader implements TranslateLoader {
  public prefix: string = '/assets/i18n/';
  public suffix: string = '.json';

  constructor(private user: MyUserService, private http: HttpClient) { }

  public getTranslation(lang: string): any {
    const group: string = this.user.getUserGroup();  // The secret is here!
    const filename = `${group}/${lang}`;

    return this.http.get(this.prefix + filename + this.suffix);
  }
}

and import it into the module like this:

export function MyCustomHttpLoaderFactory(myUserService: MyUserService, httpClient: HttpClient) {
  return new MyCustomHttpLoader(myUserService, httpClient);
}

@NgModule({
  imports: [
    // ...  
    TranslateModule.forRoot({
      loader: {
        provide: TranslateLoader,
        useFactory: MyCustomHttpLoaderFactory,
        deps: [MyUserService, HttpClient]
      }
    })
    // ...
  ]
})
export class AppModule { }

All 8 comments

I'm also looking for this feature. Can someone help?

You may try isolating the services by using isolate: true in all TranslateModule.forChild:

Lazy-loaded Modules:

In which case the service is a completely isolated instance (for translations, current lang, events, ...). Otherwise, by default, it will share its data with other instances of the service (but you can still use a different loader/compiler/parser/handler even if you don't isolate the service).

I need something similar, but depending on the group to which a user belongs.
When a user logs in, the group is obtained. Then that loads the translation files for that group.

So I have some translation files when you logout, and others when you are logged in, and depending on the group to which the user belongs.

How could I do something like that? I'm a little lost, all this is new to me.

Thank you

AFAIU, you don't need a translation per module, but a translation per user group.


The simplest way is creating different translation flavors, like admin-en.json, user-en.json, moderator-en.json. When selecting the language, you would need only use translateService.use('admin-en')


The advanced (and organized way) is creating a specific loader. It would organize like this:

  • /assets/i18n/user/en.json
  • /assets/i18n/user/fr.json
  • /assets/i18n/admin/en.json
  • /assets/i18n/admin/fr.json
@Injectable()
export class MyCustomHttpLoader implements TranslateLoader {
  public prefix: string = '/assets/i18n/';
  public suffix: string = '.json';

  constructor(private user: MyUserService, private http: HttpClient) { }

  public getTranslation(lang: string): any {
    const group: string = this.user.getUserGroup();  // The secret is here!
    const filename = `${group}/${lang}`;

    return this.http.get(this.prefix + filename + this.suffix);
  }
}

and import it into the module like this:

export function MyCustomHttpLoaderFactory(myUserService: MyUserService, httpClient: HttpClient) {
  return new MyCustomHttpLoader(myUserService, httpClient);
}

@NgModule({
  imports: [
    // ...  
    TranslateModule.forRoot({
      loader: {
        provide: TranslateLoader,
        useFactory: MyCustomHttpLoaderFactory,
        deps: [MyUserService, HttpClient]
      }
    })
    // ...
  ]
})
export class AppModule { }

Alexandreazevedo, thank you very much for the response and for your time
It has been a great help

We are having the exact same problem as described by @launcelot66 : "How to have two modules with different translation loader cohabitate on the same page"

Here is what I found :

  • The TranslateModule (and TranslateLoader) used is the one used in the latest imported Module (in this case AuthModule)
  • Using isolate: true as suggested @alexndreazevedo has no effect.
  • Lazy-loading modules (CatalogsModule & AuthModule) has no effect.

Any solution on this ?

@pdelorme it's hard to understand the situation without checking the code.

You may:

  1. Create a plunkr example of the problem
  2. Share part of the code on a support request
  3. Invite me for a session on codementor.

@pdelorme, I had the same issue. I needed to call translateService.use('en') in a component of the lazy loaded module again to "activate" the new loader. Maybe this helps?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

guysan picture guysan  路  4Comments

gmquiroga picture gmquiroga  路  3Comments

briancullinan picture briancullinan  路  3Comments

ryanki1 picture ryanki1  路  4Comments

bjornharvold picture bjornharvold  路  3Comments