I am trying to use ngx-translate inside an Angular 5 lib.
I have read from docs that _"The forRoot static method is a convention that provides and configures services at the same time. Make sure you only call this method in the root module of your application, most of the time called AppModule"_
So I thought that I should use Translate.forRoot() in my application and Translate.forChild() in my lib module
The problem is that when I use forRoot in my App and forChild in my lib I always get the following error:
ERROR Error: Uncaught (in promise): Error: StaticInjectorError(AppModule)[TranslateService -> TranslateStore]:
StaticInjectorError(Platform: core)[TranslateService -> TranslateStore]:
NullInjectorError: No provider for TranslateStore!
Error: StaticInjectorError(AppModule)[TranslateService -> TranslateStore]:
StaticInjectorError(Platform: core)[TranslateService -> TranslateStore]:
NullInjectorError: No provider for TranslateStore!
I have tested and it works when I use forRoot in application and lib, but I have to use this.translate.use("myLanguage") because seems I have two instances of TranslateService and this doesn't seems to be the proper way.
My lib should work using Translate.forChild({}) and my application using Translate.forRoot({})
Application module
export function createTranslateLoader(http: HttpClient) {
return new TranslateHttpLoader(http, './assets/i18n/', '.json');
}
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useFactory: (createTranslateLoader),
deps: [HttpClient],
}
})
],
providers: [MyService],
bootstrap: [AppComponent]
})
Lib module
export function createTranslateLoader(http: HttpClient) {
return new TranslateHttpLoader(http, './assets/my-other-path/i18n/', '.json');
}
@NgModule({
imports: [
NoopAnimationsModule,
CommonModule
TranslateModule.forChild({
loader: {
provide: TranslateLoader,
useFactory: (createTranslateLoader),
deps: [HttpClient],
}
})
],
declarations: [
MessageButtonComponent,
],
exports: [
MessageButtonComponent
],
providers: [
TranslateService
],
entryComponents: [
]
})
ngx-translate version: 9.1.1
Angular version: core 5.2.0
Browser:
- [x] Chrome (desktop) version 67
- [ ] Chrome (Android) version XX
- [ ] Chrome (iOS) version XX
- [ ] Firefox version XX
- [ ] Safari (desktop) version XX
- [ ] Safari (iOS) version XX
- [ ] IE version XX
- [ ] Edge version XX
For Tooling issues:
- Node version: v8.11.2
- Platform: Windows 10
Others:
We have the exact same problem.
I think you should just import TranslateModule directly to get access to the directives and pipes, and leave it up to the app to provide the services. Having multiple loaders is not really supported anyway: https://github.com/ngx-translate/core/issues/763
See the angular documentation on what to import:
What should I import?
Import NgModules whose public (exported) declarable classes you need to reference in this module's component templates.
Note: nothing mentioned of services
How do I restrict service scope to a module?
[...]
As a general rule, import modules with providers exactly once, preferably in the application's root module. That's also usually the best place to configure, wrap, and override them.
They also distinguish between Widget modules and Service modules.
If I understand the usage section of the README of ngx-translate correctly, they also recommend importing TranslateModule in shared modules:
Note: Never call a forRoot static method in the SharedModule. You might end up with different instances of the service in your injector tree. But you can use forChild if necessary.
Note that it says use forChild if necessary, not as a general rule for shared modules.
Maybe we should document this more explicitly in the README.
@matheuscaldasrj - Could you find any approach to achieve this behaviour? I am facing similar issue where language change event on application translate service is not propagating to the library.
Hi I have similar error. I'm using:
"@ngx-translate/core": "11.0.0",
"@ngx-translate/http-loader": "4.0.0",
App.module.ts:
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useFactory: TranslationProviders,
deps: [HttpClient],
},
}),
My LazyLoaded module Imports SharedModule which imports and exports TranslateModule. I tried to import TranslateModule with forChild but didn't help.
Any idea?
Hi, i wrote this ugly solution invoking setTranslation with TranslateService and appending, all translations are come to be loaded and run everything fine:
This is my finally solution
Library code
availableLanguages.ts
import { en } from './en.ts';
import { es } from './es.ts';
export const languages = { en, es };
translations.service.ts
@Injectable()
export class LibTranslationsService {
private availableLanguages = languages;
constructor(private translate: TranslateService) {
}
init(): any {
Object.keys(this.availableLanguages).forEach((language) => {
// Timeout because i need to be async calls after init app
setTimeout(() => this.translate.setTranslation(language, this.availableLanguages[language], true));
});
}
getTranslations() {
return this.availableLanguages;
}
}
App
app.component.ts
ngOnInit() {
this.translateUiService.init();
}
I dont have problems with Translate module, I have in my app.module
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
import { FormsModule } from '@angular/forms';
import {HttpClient, HttpClientModule} from '@angular/common/http';
import {TranslateLoader, TranslateModule} from '@ngx-translate/core';
import {TranslateHttpLoader} from '@ngx-translate/http-loader';
import { SharedModule } from './shared/shared.module';
import { AppRoutingModule } from './app.routing';
import { AppComponent } from './app.component';
@NgModule({
declarations: [
AppComponent,
],
imports: [
BrowserModule,
BrowserAnimationsModule,
FormsModule,
HttpClientModule,
SharedModule,
AppRoutingModule,
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useFactory: HttpLoaderFactory,
deps: [HttpClient]
}
})
],
exports: [],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
// required for AOT compilation
export function HttpLoaderFactory(http: HttpClient) {
return new TranslateHttpLoader(http);
}
And In my shared.module I have
import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';
import { MaterialModule } from '../pages/component/material.module';
import { FlexLayoutModule } from '@angular/flex-layout';
import { ToastrModule } from 'ngx-toastr';
import {TranslateLoader, TranslateModule} from '@ngx-translate/core';
import {HttpClient, HttpClientModule} from '@angular/common/http';
import {TranslateHttpLoader} from '@ngx-translate/http-loader';
@NgModule({
declarations: [],
imports: [
RouterModule,
MaterialModule,
FlexLayoutModule,
HttpClientModule,
ToastrModule.forRoot(),
TranslateModule.forChild({
loader: {
provide: TranslateLoader,
useFactory: HttpLoaderFactory,
deps: [HttpClient]
}
})
],
exports: [
MaterialModule,
FlexLayoutModule,
ToastrModule,
TranslateModule
]
})
export class SharedModule { }
export function HttpLoaderFactory(http: HttpClient) {
return new TranslateHttpLoader(http);
}
I think that the problem can be that you didnt put the Translate Module in the exports zone of the Shared Module.
Facing the same issue. I have even tried exporting TranslateModule as well.
import { CoreModule } from './core/core.module';
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { UpgradeModule } from '@angular/upgrade/static';
import { EventPolicyModule } from './policy/event-policy/event-policy.module';
import { TranslateHttpLoader } from '@ngx-translate/http-loader';
import { HttpClient } from '@angular/common/http';
import { TranslateModule, TranslateLoader } from '@ngx-translate/core';
export function createTranslateLoader1( http: HttpClient){
return new TranslateHttpLoader(http, 'assets/i18n/core/', '.json');
}
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
AppRoutingModule,
UpgradeModule,
CoreModule,
EventPolicyModule,
TranslateModule.forRoot({
loader : {
provide : TranslateLoader,
useFactory : (createTranslateLoader1),
deps : [HttpClient]
}
})
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
import { AppRoutingModule } from './../app-routing.module';
import { NgModule } from '@angular/core';
import { CommonModule, LocationStrategy, HashLocationStrategy } from '@angular/common';
import { UrlHandlingStrategy, UrlTree } from '@angular/router';
import { HttpClientModule, HttpClient } from '@angular/common/http';
import { TranslateModule, TranslateLoader } from '@ngx-translate/core';
import { TranslateHttpLoader } from '@ngx-translate/http-loader';
export class NgAppUrlHandlingStrategy implements UrlHandlingStrategy {
// only process the angular url
shouldProcessUrl(url: UrlTree) {
return url.toString().startsWith('/configuration/impolicies');
}
extract(url: UrlTree) {
return url;
}
merge(url: UrlTree, whole: UrlTree) {
return url;
}
}
export function createTranslateLoader2( http: HttpClient){
return new TranslateHttpLoader(http, 'assets/i18n/core/', '.json');
}
@NgModule({
declarations: [],
imports: [
CommonModule,
HttpClientModule,
TranslateModule.forChild({
loader : {
provide : TranslateLoader,
useFactory : (createTranslateLoader2),
deps : [HttpClient]
},
isolate : true
})
],
exports :[TranslateModule ],
providers: [
]
})
export class CoreModule { }
@juanjinario
Thanks.
Guys,
I also had that issue, but after adding:
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useFactory: createTranslateLoader,
deps: [HttpClient]
}
})
into app.module.ts it started work fine.
and in Shared module:
TranslateModule.forChild({
useDefaultLang: true,
isolate: false,
loader: {
provide: TranslateLoader,
useFactory: (createTranslateLoader),
deps: [HttpClient]
}
})
I had a similar problem as described in the first message in this thread. I tried to create an Angular 7 library with ng g lib. Turned out that I had @ngx-translate/core in node_modules and in projects/<my-lib>/node_modules. Removing the inner folder completely (projects/<my-lib>/node_modules) solved my problem.
After that, I use TranslateModule.forRoot() with no parameters in my AppModule of the tester app and TranslateModule in the imports of my library module.
I hope my message will help somebody.
Hi, faced this issue just yesterday with version 11.0.1 and Angular & CLI 8, what worked for me was:
Like state in the documentation in my shared module i had:
TranslateModule.forChild({
loader: {
provide: TranslateLoader,
useFactory: (createtranslateloader),
deps: [HttpClient]
},
isolate: true
}),
and in my AppModule, wich also imports the shared module , i add to provide the TranslateStore
@NgModule({
declarations: [
AppComponent
],
imports: [
CommonModule,
SharedModule,
OAuthModule.forRoot(),
AppRoutingModule,
CoreModule.forRoot(),
UiBlocksModule,
ThemeModule.forRoot(AppThemes)
],
providers: [
TranslateStore,
{ provide: OAuthStorage, useValue: localStorage },
{ provide: OAuthLogger, useValue: LoggingService }
],
bootstrap: [AppComponent]
})
export class AppModule { }
Not sure if this is supposed to be done this way but this did resolve the original error message "NullInjectorError: No provider for TranslateStore!".
But now everything is translated except the lazy loaded modules. (every component loaded inside the
I then notice there were at least two instances of the TranslateService, the one create for components outside of the router outlet, and another one for the lazy loaded modules.
What fixed this was setting the isolate: false when registering the translate module in my SharedModule.
This issue ultimately seems to depend a lot with the way the angular project and module registration is set up.
In my case the SharedModule and the AppModule do share the same i18n files, but i do realize that if i want to get different i18n files for the SharedModule and the AppModule it does make sense to have different instances of the TranslateService and would have to register the the TranslateModule.forRoot in the AppModule and keep the flag isolate: true in my Shared Module
Hope this can help..
I had the same issue when lazy loading many translated angular 8 modules with ngx-translate/core v.11.0.1 .
In the translation module I have :
@NgModule({
declarations: [ MyComponent ],
imports: [
CommonModule,
TranslateModule.forChild({
loader: {
provide: TranslateLoader,
useFactory: MyTranslationLoaderFactory,
deps: [ HttpClient ]
},
isolate: false
}),
RouterModule.forChild(MY_ROUTES),
SharedModule
]
})
export class MyModule {}
In the container I have to add this line in the ngOnInit to make it work:
export class MyContainer implements OnInit {
constructor(public translationService: TranslateService) {}
ngOnInit() {
this.translate.use(this.translate.store.currentLang);
this.translate.store.onLangChange.subscribe((lang) => this.translate.use(lang));
}
}
This worked for me, In tsconfig.ts of the main application add this to paths and restart your application:
"@ngx-translate/core": [
"node_modules/@ngx-translate/core"
],
"@ngx-translate/http-loader": [
"node_modules/@ngx-translate/http-loader"
],
Besides adding the standard TranslateModule.forRoot(...) in my AppModule, I simply import and export the TranslateModule (no .forChild()) in my SharedModule worked for me also, surprisingly. Before that, I got translate pipe error.
Besides adding the standard
TranslateModule.forRoot(...)in myAppModule, I simply import and export theTranslateModule(no .forChild()) in mySharedModuleworked for me also, surprisingly. Before that, I gottranslatepipe error.
I can confirm that just dropping all .forChild(), and having one .forRoot({...}) in app.module throughout my application + library did the trick. Seems strange though that you can't call .forChild() on what I see as child modules. Oh well.
Most helpful comment
Hi, faced this issue just yesterday with version 11.0.1 and Angular & CLI 8, what worked for me was:
Like state in the documentation in my shared module i had:
and in my AppModule, wich also imports the shared module , i add to provide the TranslateStore
Not sure if this is supposed to be done this way but this did resolve the original error message "NullInjectorError: No provider for TranslateStore!".
But now everything is translated except the lazy loaded modules. (every component loaded inside the had missing translations).
I then notice there were at least two instances of the TranslateService, the one create for components outside of the router outlet, and another one for the lazy loaded modules.
What fixed this was setting the isolate: false when registering the translate module in my SharedModule.
This issue ultimately seems to depend a lot with the way the angular project and module registration is set up.
In my case the SharedModule and the AppModule do share the same i18n files, but i do realize that if i want to get different i18n files for the SharedModule and the AppModule it does make sense to have different instances of the TranslateService and would have to register the the TranslateModule.forRoot in the AppModule and keep the flag isolate: true in my Shared Module
Hope this can help..