Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lazy loaded module specific JSON translation file not loading #602

Open
tushamsbe opened this issue Jul 13, 2017 · 17 comments
Open

Lazy loaded module specific JSON translation file not loading #602

tushamsbe opened this issue Jul 13, 2017 · 17 comments

Comments

@tushamsbe
Copy link

tushamsbe commented Jul 13, 2017

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

@AlexFreem
Copy link

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

@matkarlg
Copy link
Contributor

matkarlg commented Jul 24, 2017

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.

@qifanrui
Copy link

I also encountered the same problem, who solved it?

@qifanrui
Copy link

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 { }

@Jensiator
Copy link

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

@matkarlg
Copy link
Contributor

matkarlg commented Sep 2, 2017

@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.

@Jensiator
Copy link

Jensiator commented Sep 3, 2017 via email

@JavanXD
Copy link

JavanXD commented Sep 6, 2017

@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);
	}
}

@Tuizi
Copy link

Tuizi commented Sep 23, 2017

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

@emmano3h
Copy link

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

@ratidzidziguri
Copy link

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.

@panagulis72
Copy link

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

@ratidzidziguri
Copy link

@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.

@Mythrim
Copy link

Mythrim commented Oct 24, 2018

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?

@agrinko
Copy link

agrinko commented Dec 20, 2020

Thanks @matkarlg . In my case subscribing to onLangChange wasn't working for some reason, but I solved it by calling getTranslation() and subscribing to it:

  // calling this in the root component of the lazy-loaded module
  constructor(private translate: TranslateService) {
    translate.getTranslation(translate.currentLang).subscribe();
  }

In my case it was enough, because I refresh the page after language is changed. Somebody might also need to load language on every lang change, i.e. to call the same getTranslation method in subscription to onLangChange observable.

UPDATE:
although eventually I rejected this solution because I noticed problems when loading multiple files in the main app.module.ts and lazy-loading a sub-module like I mentioned. Something weird... {erhaps better not complicate with ngx-translate and keep everything in one file.

@Jensiator
Copy link

Jensiator commented Dec 21, 2020 via email

@MiguelCh24
Copy link

MiguelCh24 commented Feb 25, 2021

Hi all, I have the same issue:

I have three different modules:

app.module
module1.module
module2.module

and they are nested that way.

in app.module I have implemented module1 and in module1 I have implemented module2.

That was really crazy, despite configuring module2, it takes the configurations of module1.

Any idea on that?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests