I'm submitting a ... (check one with "x")
[ ] 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
AppModule
export function createTranslateLoader(http: Http) {
return new TranslateHttpLoader(http, "/i18n/", "/index.json");
}
imports: [
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useFactory: createTranslateLoader,
deps: [Http]
}
}),
]
SharedModule
imports: [
//TranslateModule
],
exports: [
//TranslateModule,
]
AdminModule
export function createTranslateLoader(http: Http) {
return new TranslateHttpLoader(http, "/i18n/", "/admin.json");
}
imports: [
TranslateModule.forChild({
loader: {
provide: TranslateLoader,
useFactory: createTranslateLoader,
deps: [Http]
}
}),
]
Expected/desired behavior
I would like to load additional JSON files per component / module, i.e. an admin.json for the administration panel of our app.
I would like to import one TranslateModule inside of SharedModule and configure it allow all modules that don't explicite call .forChild().
Both doesn't work, it simply doesn't load the admin.json and hence doesn't translate strings defined in that file.
Please tell us about your environment:
ngx-translate version: 6.0.0-beta.1
Angular version: 2.4.7
Browser: [Firefox 51.0.1]
Language: [TypeScript 2.0]
Since I didn't found any plunker working with ngx-translate librairy and I also had some difficulties to manage to make it work with LoadChildren,
I've setup a way that work pretty well for me:
_I've created two SharedModules, (one for lazyLoading and one for the other part of my application)_
SharedLazyModule for lazy loading content:
@NgModule({
imports: [
HttpModule,
CommonModule,
TranslateModule.forChild({}),
],
exports: [
CommonModule,
TranslateModule
]
})
export class SharedLazyModule {}
SahredModule for App
// AoT requires an exported function for factories
export function HttpLoaderFactory(http: Http) {
return new TranslateHttpLoader(http, './assets/i18n/', '.json');
}
@NgModule({
imports: [
HttpModule,
CommonModule,
TranslateModule.forRoot({
provide: TranslateLoader,
useFactory: HttpLoaderFactory,
deps: [Http],
})
],
exports: [
CommonModule,
TranslateModule
]
})
export class SharedModule {
constructor(private translate: TranslateService) {
translate.addLangs(["en", "fr"]);
translate.setDefaultLang('en');
let browserLang = translate.getBrowserLang();
translate.use(browserLang.match(/en|fr/) ? browserLang : 'en');
}
}
See Plunker:
https://plnkr.co/LVmIuI1Xw9vFn0IuC2jW
@neolanders your answer does not relate to the question, you are posting the solution explained in the README for SharedModule.
I'm trying to create a module on top of the TranslateModule where each module could put in his translations, but so far not successful
I believe ngx-translate is broken in regards to its "Lazy loading feature" and since ocombe is now part of the Angular core team, it will probably never get fixed.
Most likely, people will have to switch to Angular's i18n functionality once it becomes more rich in regards to its features.
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 a workaround, since you are basically creating TranslateModule in every lazy loaded module, and you need something in between to keep the selected lang synced. The problem we are talking about is that it should work without this workaround that we all have to do for now
@mebibou I'm curious about what contributors think about that. For me it's not a workaround has I simply follow what the documentation say (paragraph "lazy loaded module")
@Tuizi no I'm saying that's not the point of the issue here. We want to have lazy loading modules being in sync with the master modules, without having to push the changes of lang from master to slave everytime. It should basically work without needing to use isolate: true and adding some code (your this.store.dispatch and all)
any progress on this? is Tuizi's solution is indead a work-around. Anyone found a real solution / fix?
What would be a real solution?
I have time to work on a PR and I would like to try to solve this problem, which seems to impact many people.
What do you think of that?
Core Module
export function createTranslateLoader(http: HttpClient) {
// We may need a new loader? To define the folder where i18n's files are, and the extension
return new LazyTranslateHttpLoader(http, './assets/i18n/', '.json');
}
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useFactory: (createTranslateLoader),
deps: [HttpClient]
}
})
Lazy loaded Module: admin
TranslateModule.forChild({lazy: 'admin'})
When admin module is loaded, the file ./assets/i18n/admin/en.json will be requested.
What do you think of that?
I wouldn't mind having to create different translateLoader per module, just without using isolate: true should work, something along:
// app.module.ts
export function HttpLoaderFactory(http: Http) {
return new TranslateHttpLoader(http, './assets/i18n/app/', '.json');
}
@NgModule({
imports: [
TranslateModule.forChild({
loader: {
provide: TranslateLoader,
useFactory: HttpLoaderFactory,
deps: [Http]
}
})
]
})
export class AppModule {}
// in a lazy-loaded page's module
// pages/home/page.module.ts
export function HttpLoaderFactory(http: Http) {
return new TranslateHttpLoader(http, './assets/i18n/home/', '.json');
}
@NgModule({
imports: [
TranslateModule.forChild({
loader: {
provide: TranslateLoader,
useFactory: HttpLoaderFactory,
deps: [Http]
}
})
]
})
export class HomePageModule {}
@Tuizi taken from the README:
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 don't think that is true, when I don't use isolate: true, my custom translate loader (like in example above) does not load the translation at all, nothing happens
Thank you are right. I will check that
If I understand correctly, the OP wants to lazily load translations along with his lazily loaded modules. We did managed to load translations lazily but used a slightly different approach. All our translations are defined in 'namespaces' and every translation key is prefixed with the namespace (for instance 'validations.required'). Our translations are loaded with a MissingTranslationHandler. The MissingTranslationHandler uses the namespace to determine which translation file to load.
So, we're not lazily loading our translations per (lazily loaded) module but per translation namespace. By prefixing your translation keys with your module name you could of course get the required effect.
Gist with our MissingTranslationHandler
Hope this can help someone.
Seems the best thing you can do right now is use namespacing, with the -f namespaced-json flag. Seems to be the only solution for modularity. The problem i would like to solve now is a way to globally load the pipe once in a lazy loading environment. I have to use a sharedmodule to load 'TranslateModule.forRoot()' in all my modules for it to work right now, not very efficient.
@Almar Thanks !! That's a great solution for now.
@ocombe are you planning to fix/support this any time soon?
I tried forchild solution but it is not working. Could we have any plunk working well ?
ngx-translate version: 6.0.0-beta.1
Angular version: 6.0.3
Browser: [Chrome Version 67.0.3396.79 (Official Build) (64-bit)]
Language: [TypeScript 2.7.2]
If you use Angular v6, you have to use ngx translate version >= 10
@ocombe here my configs:
"@ngx-translate/core": "^10.0.2",
"@ngx-translate/http-loader": "^3.0.1",
Same here
Same here (angular 6.1.3, ngx-translate 10.0.2)
don't get this... do we need to keep .forChild and .forRoot together? I get an error if I don't add the second one:
Could not find IonicModule.forRoot call in "imports"
Personnaly I still have a issue for getting all my translations... my scenario is :
a main application calling
a lazy loaded module
where is a container module
where the translation is used.
Everything works expect the translation :-/
If I dont lazy load I get my translations.
There is a sample:
app.module
// Http loader for ngx-translate.
export function createTranslateLoader(http: HttpClient, settings: GlobalAppSettings) {
return new TranslationLoader(http, settings);
}
@NgModule({
declarations: [
....
],
imports: [
....
// Other external modules.
TranslateModule.forRoot({
loader: { provide: TranslateLoader, useFactory: (createTranslateLoader), deps: [HttpClient, GlobalAppSettings] }, isolate: true
....
],
bootstrap: [AppComponent]
})
export class AppModule { }
app-routing.module
imports....
export const routes: Routes = [
...
{
path: 'unemployment-info',
canActivate:[OAuthGuardService],
loadChildren: './unemployment.module#UnemploymentModule',
data: { id: 4, title:'tabs.eDossier' }
}
...
];
@NgModule({
imports: [RouterModule.forRoot(routes, {preloadingStrategy:聽PreloadAllModules, enableTracing:false})],
exports: [RouterModule]
})
export class AppRoutingModule { }
unemployment.module
export const routes: Routes = [{ path: '', component: UnemploymentInfoComponent }];
// Http loader for ngx-translate.
export function createTranslateLoader(httpClient: HttpClient, settings: GlobalAppSettings) {
return new TranslationLoader(httpClient, settings);
}
@NgModule({
imports: [
CommonModule,
RouterModule.forChild(routes),
EDossierContainerModule,
TranslateModule.forChild({
loader: { provide: TranslateLoader, useFactory: (createTranslateLoader), deps: [HttpClient,
GlobalAppSettings] }
}),
], exports: [],
declarations: [...]
})
export class UnemploymentModule { }
e-dossier-container.module
// Http loader for ngx-translate.
export function createTranslateLoader(httpClient: HttpClient, settings: GlobalAppSettings) {
return new TranslationLoader(httpClient, settings);
}
@NgModule({
imports: [
....
// Translate
TranslateModule.forChild({
loader: { provide: TranslateLoader, useFactory: (createTranslateLoader), deps: [HttpClient, GlobalAppSettings] }
}),
....
],
declarations: [
....
],
exports: [HomeMenuComponent],
providers: [
...
]
})
export class EDossierContainerModule { }
It is an issue,
@ocombe a couple of days ago i've faced the same issue for another Angular Library (igniteui),
The problem can be solved by removing the forRoot() implementation and using the recently introduced providedInproperty of the @Injectable decorator, in short TranslateModule.forRoot() will be deprecated.
This would be breaking-change so it requires someone to dedicate at least a full day to migrate the implementation, this is what the Angular 6 documentation says:
Beginning with Angular 6.0, the preferred way to create a singleton services is to specify on the service that it should be provided in the application root. This is done by setting providedIn to root on the service's @Injectable decorator:
Same issue here using a lazy load modules.
Same issue with lazy loading, any signs of progress?
@ocombe
Until they fix this, I have a workaround here
any update on this ?
temp solution works for me
in your shared module import and export like so
without using forChild or forRoot
imports: [
TranslateModule
],
exports: [
TranslateModule
],
in you app module import forRoot
imports:[
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useFactory: createTranslateLoader,
deps: [HttpClient]
},
isolate: true
})
]
this is was cool for me .
I've been struggling with a similar issue.
I had a lazy loaded module that didn't show any translations.
After (a lot) of debugging, I saw that the TranslateStore was being created twice.
At first I thought it was a bug, but after digging into it I saw that the Lazy Loaded module imported a module, which imported a module which had a TranslateModule.forRoot() in its imports.
It was hard to trace because it was "hidden" inside of a shared library project.
Anyway, I hope it will save some of you some debugging time, if you're suffering from the same (hidden) cluster fudge 馃槃
appModule.ts

Create one shared module translateSharedModule.ts

appComponent.ts
import {TranslateService} from '@ngx-translate/core';
constructor(public translate: TranslateService) {
translate.setDefaultLang('en');
}
homeModule.ts //or any other submodules
import { TranslateSharedLazyModule } from '../../Common/translateSharedLazyModule';
imports : [
TranslateSharedLazyModule
], ..
My case was:
I solved my problem by adding an option extend , which allows lazy loaded modules to extend the translations for a given language instead of ignoring them, if already present.
TranslateModule.forChild({
loader: {
provide: TranslateLoader,
useFactory: (createTranslateLoader),
deps: [HttpClient]
},
extend: true
}),
If you're interested, you can get it here:
https://github.com/stemda/ngx-translate
Probably not good enough for a PR but maybe it helps some of you...
Hi all, I trying to use this example, but its not working? Why for lazy module translation dictionary not merged with module forRoot?
I wouldn't mind having to create different translateLoader per module, just without using
isolate: trueshould work, something along:// app.module.ts export function HttpLoaderFactory(http: Http) { return new TranslateHttpLoader(http, './assets/i18n/app/', '.json'); } @NgModule({ imports: [ TranslateModule.forChild({ loader: { provide: TranslateLoader, useFactory: HttpLoaderFactory, deps: [Http] } }) ] }) export class AppModule {} // in a lazy-loaded page's module // pages/home/page.module.ts export function HttpLoaderFactory(http: Http) { return new TranslateHttpLoader(http, './assets/i18n/home/', '.json'); } @NgModule({ imports: [ TranslateModule.forChild({ loader: { provide: TranslateLoader, useFactory: HttpLoaderFactory, deps: [Http] } }) ] }) export class HomePageModule {}
I posted a possible solution for your problem above. If you dont want to check out the fork, just download a patch
https://github.com/foo/bar/commit/${SHA}.patch
https://github.com/stemda/ngx-translate/commit/f54bc5303124ec35a5e2ab4f51e59cf9920f5cd8.patch
and try it out.
@stemda omg, nice! I just few minutes already forked for same patch. :)
Are you can create PR for resolve this issue?
@iamruslanbakirov okay, I just started a pull request.
btw. I decided against overwriting already present translations within the merge since that could lead to very confusing behaviour. the result would depend on the loading sequence of the modules, which isn't really great I think.
Hello.
If I understand correctly, with "extend" it will be possible to use a shared.json and a module.json file (by lazy loading module) and the "extend" will not overwrite but make an append with shared.json?
Would be perfect.
I'm really in need of this to better organize the translations and still make GET just the necessary one used in the module (lazy-loading).
Thanks.
Hey, @Tolitech, sorry for my late response. Yes, that's excactly what the patch does.
@stemda
thank you.
I'll wait for this feature.
@ocombe what we can do for you to speed up merging @stemda changes?
Hey!
I'm facing the same issue here and @stemda changes will fix the problem. I'm really looking forward to this PR being merged.
Thank you.
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
Hey , Could you please give it a clear documentation. I am using ngrx/store and i need to use ngx-translate in lazy loaded module and other places it should be in module level transalation.
if you have time please upload a sample example in github
@pvkrijesh a working example updated to Angular 8:
https://github.com/Tuizi/i18n-split-example
@pvkrijesh a working example updated to Angular 8:
https://github.com/Tuizi/i18n-split-example
@Tuizi
This example does not work exactly.
The problem is not just detaching each module into a new json file.
But if you have a shared json with 10 translations for example, it cannot be used by others and always has to be copied again, which makes using this way bad.
Based on the solution @Almar provided, I'm also using the MissingTranslationHandler to determine if additional translations need to be fetched. The parts that I've changed compared to @Almar solution is that I make use of the loader configured inside the translation service. Because a new instance of the TranslationService is created when using the forChild method, this is nicely isolated, the same counts for the missinghandler that is configured.
https://gist.github.com/kristofdegrave/64863e249bbc8768fe33fc666dfa8bf5
I隆ve developed a lazy loading per module solution through a factory.
import { TranslateLoader } from '@ngx-translate/core';
import { Observable, from, merge } from 'rxjs';
const appAvailableLanguages = ['ar', 'en', 'es', 'fr'];
const defaultLanguage = 'en';
export class TranslateLoaderFactory {
static forModule(module: string): any {
return class LazyTranslateLoader implements TranslateLoader {
getTranslation(lang: string): Observable<any> {
if (!appAvailableLanguages.includes(lang)) {
return merge(
from(import(`../../../assets/i18n/${defaultLanguage}.json`)),
from(import(`../../../assets/i18n/${module}/${defaultLanguage}.json`))
);
}
return merge(
from(import(`../../../assets/i18n/${lang}.json`)),
from(import(`../../../assets/i18n/${module}/${lang}.json`))
);
}
}
}
}
typescript
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useClass: TranslateLoaderFactory.forModule('main'),
deps: [HttpClient]
}
}),
typescript
TranslateModule.forChild({
loader: {
provide: TranslateLoader,
useClass: TranslateLoaderFactory.forModule('mymodule'),
deps: [HttpClient]
}
}),
I隆ve developed a lazy loading per module solution through a factory.
- create a folder assets/i18n/modulexxx for every module
- add the language json en.json, fr.json..etc in that folder and the shared ones in assets/i18n
- Add the TranslateLoder factory (e.g shared/i18n/TranslateLoader.ts)
import { TranslateLoader } from '@ngx-translate/core'; import { Observable, from, merge } from 'rxjs'; const appAvailableLanguages = ['ar', 'en', 'es', 'fr']; const defaultLanguage = 'en'; export class TranslateLoaderFactory { static forModule(module: string): any { return class LazyTranslateLoader implements TranslateLoader { getTranslation(lang: string): Observable<any> { if (!appAvailableLanguages.includes(lang)) { return merge( from(import(`../../../assets/i18n/${defaultLanguage}.json`)), from(import(`../../../assets/i18n/${module}/${defaultLanguage}.json`)) ); } return merge( from(import(`../../../assets/i18n/${lang}.json`)), from(import(`../../../assets/i18n/${module}/${lang}.json`)) ); } } } }
- Use in in your root and lazy loaded modules as:
- root:
TranslateModule.forRoot({ loader: { provide: TranslateLoader, useClass: TranslateLoaderFactory.forModule('main'), deps: [HttpClient] } }),
- lazy loaded module:
TranslateModule.forChild({ loader: { provide: TranslateLoader, useClass: TranslateLoaderFactory.forModule('mymodule'), deps: [HttpClient] } }),Hope that helps
Hi, could you share a github project working? i have testest but not work.
one more workaround to trigger language change globally including lazy modules
export class SharedModule {
constructor(
private languageService: LanguageService,
private translateService: TranslateService
) {
this.languageService.language.subscribe((lang) => {
this.translateService.use(lang);
});
}
}
I am the same problem. Isolet true not working for me. Do you have a solution ?
I use Angular 9
Most helpful comment
appModule.ts
Create one shared module translateSharedModule.ts
appComponent.ts
import {TranslateService} from '@ngx-translate/core';
constructor(public translate: TranslateService) {
translate.setDefaultLang('en');
}
homeModule.ts //or any other submodules
import { TranslateSharedLazyModule } from '../../Common/translateSharedLazyModule';
imports : [
TranslateSharedLazyModule
], ..