Core: Lazy loaded module specific JSON translation file not loading

Created on 13 Jul 2017  Â·  14Comments  Â·  Source: ngx-translate/core

I'm submitting a

[x] feature request => load child module specific translation JSON file

Current behavior
In my lazy loaded child module account.module.ts I'm importing TranslateModule with forChild()

@NgModule({
  imports: [
    CommonModule,
    HttpModule,
    FormsModule,
    AccountRoutingModule,
    TranslateModule.forChild({
      loader: { provide: TranslateLoader, useClass: AccountTranslationLoader, deps: [Http] },
    })
  ],
})
export class AccountModule { }

I have custom translate loader AccountTranslationLoader written as

export class AccountTranslationLoader implements TranslateLoader {

    constructor(private http: Http) {}

    getTranslation(lang: string): Observable<any> {
        return this.http.get(`./assets/i18n/account/${lang}.json`)
    }
}

Currently the expected json file request is never made and translation in child module views not working.

Expected/desired behavior
It is expected to load the child module json translation file and append it to the previously loaded translation file loaded from AppModule using TranslateModule.forRoot()

Please tell us about your environment:

  • ngx-translate version: ^7.0.0

  • Angular version: ^4.1.3

Most helpful comment

The GET request is never made because there are no subscribers on the Observable for fetching the child JSON. I assume translate.use() is used in the root to set language, which auto-subscribes and completes for root only Source: translate.use. It does not automatically fetch the JSON for the child.

Make a test by subscribing to onLangChange() manually in the child module and change the language in code. It should fetch the JSON.

All 14 comments

Subscribing.
Also expecting this problem, but with usage of factory based on TranslateHttpLoader.

The GET request is never made because there are no subscribers on the Observable for fetching the child JSON. I assume translate.use() is used in the root to set language, which auto-subscribes and completes for root only Source: translate.use. It does not automatically fetch the JSON for the child.

Make a test by subscribing to onLangChange() manually in the child module and change the language in code. It should fetch the JSON.

I also encountered the same problem, who solved it?

It seems like this

import { Http } from '@angular/http';
import { TranslateHttpLoader } from '@ngx-translate/http-loader';
import { NgModule } from '@angular/core';
import { IonicPageModule } from 'ionic-angular';
import { SettingsAboutLanguagePage } from './settings-about-language';
import { TranslateModule, TranslateLoader } from '@ngx-translate/core';

export function createTranslateLoader(http: Http) {
  return new TranslateHttpLoader(http, './assets/i18n/', '.json');
}

@NgModule({
  declarations: [
    SettingsAboutLanguagePage,
  ],
  imports: [
    IonicPageModule.forChild(SettingsAboutLanguagePage),
    TranslateModule.forChild({
      loader: {
        provide: TranslateLoader,
        useFactory: (createTranslateLoader),
        deps: [Http]
      }
    })
  ],
})
export class SettingsAboutLanguagePageModule { }

I made it work will help from matkarlg. Just add the translate.use in the lazy loaded module's constructor. BUT I rolled it back. Because I could see some problems with sharing translations between the modules. With the isolated;false. the lazy loaded module will get the 'top' translation. So far so good. But how will it work the other way around. If a module has not yet been loaded (lazy), will it's translations be loaded? Probably not. So some of the translation will need to stay in the 'top' files. Because they are so general. And they might be needed in achors/menus that navigates to the lazy loaded module. So if you have a module called ex. Fruits, You would end up with a part of the translations in the top translation file and a part of it in the FruitsModule json file. ex en.json and fruits-en.json. I prefer to have all the 'fruits' translation in one place. So I keep all translations i one big file until a better approach comes my way

@Jensiator The other way I guess is to duplicate the translations.

I ended up like you said, with some translations in the AppModule - We prefixed them with "common".

The translations with the "common"-prefix were not part of the "FruitsModule", but at least they were easy to find. Working with the translations feels the same as the css, always a few globals.

To create a big file. A script could concatenate the translation files.

Nice idea with the prefix. That should work!!

On Sat, Sep 2, 2017 at 10:03 AM, Mathias Karlgren notifications@github.com
wrote:

@Jensiator https://github.com/jensiator The other way I guess is to
duplicate the translations.

I ended up like you said, with some translations in the AppModule - We
prefixed them with "common".

The translations with the "common"-prefix were not part of the
"FruitsModule", but at least they were easy to find. Working with the
translations feels the same as the css, always a few globals.

To create a big file. A script could concatenate the translation files.

—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/ngx-translate/core/issues/602#issuecomment-326729518,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AQ5pq2Mf2pEWZYsxVM7-zNKakbJhBNqUks5seQvpgaJpZM4OXbv1
.

@matkarlg could you please provide your solution, that would be great because i am at the beginning.

/* Translation Module */
import { HttpClientModule, HttpClient } from '@angular/common/http';
import { TranslateModule, TranslateLoader } from '@ngx-translate/core';
import { TranslateHttpLoader } from '@ngx-translate/http-loader';
import { Observable } from "rxjs/Observable";

// AoT requires an exported function for factories
export function createTranslateLoader(http: HttpClient) {
    return new CustomLoader(http);
}

export class CustomLoader implements TranslateLoader {

    private commonTranslations: any;
    private moduleTranslations: any;
    private translations: any;

    constructor(private http: HttpClient) {
        console.log("CustomLoader is initialized...");
    }

    getTranslation(lang: string): Observable<any> {
        this.commonTranslations = this.http.get(`./assets/i18n/${lang}/common-values.json`).map((response: JSON) => response);
        this.moduleTranslations = this.http.get(`./assets/i18n/${lang}/values.json`).map((response: JSON) => response);
        //console.log(this.moduleTranslations);

        let transStr: string = '[' + JSON.stringify(this.commonTranslations) + ',' + JSON.stringify(this.moduleTranslations) + ']';
        console.log(transStr);

        this.translations = JSON.parse(transStr);
        return Observable.of(this.translations);
    }
}

I wrote a article about how to have 1 json file per lazy loaded module without having to write a new Custom Loader etc... it's quiet simple, only the documentation is not clear in fact:
https://medium.com/@TuiZ/how-to-split-your-i18n-file-per-lazy-loaded-module-with-ngx-translate-3caef57a738f

@Tuizi your solution is not working with me.
It will be good to have a complete demo source of your article.

any update on this? solution mentioned here does not work for me as well. it always loads only first translation but never the one defined in lazy loaded module.

@matkarlg setting the translate.use() it finally works, thank you very very much you saved my day :D

@panagulis72 it does not work for me actually even in a child module which is lazy loaded it does not work and never loads language.

Hi, I have integrated ngx-translate/core for my angular 6 application. My application contains lazy loaded modules also other than the main application module. I have added translator module config inside the shared module and have imported the shared module in other modules, but still, I need to create an instance translate in each component and use that, Is there an efficient way of adding some default configuration in some place and need not initialize the translation service in each component.

Any suggestions?

Was this page helpful?
0 / 5 - 0 ratings