I updated my app from Angular 6 to Angular 7 and @ngx-translate/core to ^11.0.1.
But ngx-translate doesn't working, no errors... just showing keys instead translations.
What can be the reason?
Flow how I load the translations:
import * as translation from '../locale/i18n/en.json';
...
translate.setDefaultLang(environment.locale); // 'en'
translate.setTranslation(environment.locale, translation);
translate.use(environment.locale);
in translate.store has loaded EN translation
I have same problem...
Same problem here.
My thought that it might be a bug in translate, but downgrading to the old version
"@ngx-translate/core": "^10.0.2",
"@ngx-translate/http-loader": "^3.0.1",
doesn't help.
Maybe it's some incompability with other packages?
"dependencies": {
"@angular/animations": "^7.0.4",
"@angular/cdk": "^7.0.4",
"@angular/common": "^7.0.4",
"@angular/compiler": "^7.0.4",
"@angular/core": "^7.0.4",
"@angular/forms": "^7.0.4",
"@angular/http": "^7.0.4",
"@angular/material": "^7.0.4",
"@angular/platform-browser": "^7.0.4",
"@angular/platform-browser-dynamic": "^7.0.4",
"@angular/pwa": "^0.10.6",
"@angular/router": "^7.0.4",
"@angular/service-worker": "^7.0.4",
"@ngx-translate/core": "^11.0.1",
"@ngx-translate/http-loader": "^4.0.0",
"apollo": "^2.1.2",
"apollo-angular": "^1.5.0",
"apollo-angular-link-http": "^1.4.0",
"apollo-cache-inmemory": "1.3.10",
"apollo-client": "2.4.6",
"apollo-link": "1.2.3",
"core-js": "^2.5.4",
"graphql": "14.0.2",
"graphql-tag": "2.10.0",
"ng-pick-datetime": "^7.0.0",
"ngx-image-cropper": "^1.2.2",
"rxjs": "^6.3.3",
"zone.js": "^0.8.26"
},
"devDependencies": {
"@angular-devkit/build-angular": "~0.10.6",
"@angular/cli": "~7.0.6",
"@angular/compiler-cli": "^7.0.4",
"@angular/language-service": "^7.0.4",
"@fortawesome/angular-fontawesome": "^0.3.0",
"@fortawesome/fontawesome-svg-core": "^1.2.8",
"@fortawesome/pro-light-svg-icons": "^5.5.0",
"@fortawesome/pro-regular-svg-icons": "^5.5.0",
"@fortawesome/pro-solid-svg-icons": "^5.5.0",
"@types/graphql": "14.0.3",
"@types/jasmine": "~3.3.0",
"@types/jasminewd2": "~2.0.6",
"@types/node": "~10.12.9",
"codelyzer": "~4.5.0",
"jasmine-core": "~3.3.0",
"jasmine-spec-reporter": "~4.2.1",
"karma": "~3.1.1",
"karma-chrome-launcher": "~2.2.0",
"karma-coverage-istanbul-reporter": "~2.0.0",
"karma-jasmine": "~2.0.1",
"karma-jasmine-html-reporter": "^1.4.0",
"protractor": "~5.4.1",
"ts-node": "~7.0.1",
"tslint": "~5.11.0",
"typescript": "~3.1.6"
}
It seems to have something to do with how you initialize your translate file. When you switch a HTTP-loader, it will work again.
old (not working):
TranslateModule.forRoot({
loader: {provide: TranslateLoader, useClass: CustomTranslate}
}),
Probably its the import * as de from './de.json'; not working anymore in Angular 7?
import {TranslateLoader} from '@ngx-translate/core';
import * as de from './de.json';
import {Observable, of} from 'rxjs';
export class CustomTranslate implements TranslateLoader {
getTranslation(_lang: string): Observable<any> {
return of(de);
}
}
new (working):
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useFactory: HttpLoaderFactory,
deps: [HttpClient]
}
}),
export function HttpLoaderFactory(httpClient: HttpClient) {
return new TranslateHttpLoader(httpClient);
}
Not sure what's the issue. I updated the example on stackblitz to check and everything works fine: https://stackblitz.com/github/ngx-translate/example?file=package.json
This issue is back: https://github.com/ngx-translate/core/issues/790
Translatetion fails when translate directive is used and the key has spaces at the begining or at the end.
Currently my solution with Angular 7 and
"@ngx-translate/core": "^10.0.2",
"@ngx-translate/http-loader": "^3.0.1",
I write a pipe for replace the translate pipe based on it (works with Angular 7, messageformat and the lazy loading on your project)
import { Pipe, PipeTransform, ChangeDetectorRef, EventEmitter, OnDestroy, Injectable } from '@angular/core';
import { TranslateService, DefaultLangChangeEvent, LangChangeEvent, TranslationChangeEvent } from '@ngx-translate/core';
import { TextsService } from '../services/texts.service';
const messageFormat = require('messageformat');
const mf = new messageFormat('fr');
@Pipe({
name: 'lang',
pure: false // required to update the value when the promise is resolved
})
export class Lang implements PipeTransform, OnDestroy {
value: string = '';
lastKey: string;
lastParams: any[];
onTranslationChange: EventEmitter<TranslationChangeEvent>;
onLangChange: EventEmitter<LangChangeEvent>;
onDefaultLangChange: EventEmitter<DefaultLangChangeEvent>;
constructor(
private _textsService: TextsService,
private _translate: TranslateService,
private _ref: ChangeDetectorRef
) { }
updateValue(key: string, interpolateParams?: Object, translations?: any): void {
const onTranslation = (res: string) => {
this.value = this.formatMessage(res, this.lastParams);
this.lastKey = key;
this._ref.markForCheck();
};
if (translations) {
const res = this._translate.getParsedResult(translations, key, interpolateParams);
if (typeof res.subscribe === 'function') {
res.subscribe(onTranslation);
} else {
onTranslation(res);
}
}
this._translate.get(key, interpolateParams).subscribe(onTranslation);
}
transform(query: string, params?: any): string {
this.lastKey = query;
this.lastParams = params;
const message = this.formatMessage(this._textsService.getTextInstante(query), params);
// subscribe to onTranslationChange event, in case the translations change
if (!this.onTranslationChange) {
this.onTranslationChange = this._translate.onTranslationChange.subscribe(
(event: TranslationChangeEvent) => {
if (this.lastKey && event.lang === this._translate.currentLang) {
this.lastKey = null;
this.updateValue(query, params, event.translations);
}
}
);
}
// subscribe to onLangChange event, in case the language changes
if (!this.onLangChange) {
this.onLangChange = this._translate.onLangChange.subscribe(
(event: LangChangeEvent) => {
if (this.lastKey) {
this.lastKey = null;
// we want to make sure it doesn't return the same value until it's been updated
this.updateValue(query, params, event.translations);
}
}
);
}
// subscribe to onDefaultLangChange event, in case the default language changes
if (!this.onDefaultLangChange) {
this.onDefaultLangChange = this._translate.onDefaultLangChange.subscribe(() => {
if (this.lastKey) {
this.lastKey = null;
// we want to make sure it doesn't return the same value until it's been updated
this.updateValue(query, params);
}
});
}
return message;
}
formatMessage(message: string, params: any): string {
if (message.indexOf('{') > -1 && message.indexOf('}') > -1) {
message = mf.compile(message)(params);
}
return message;
}
ngOnDestroy(): void {
this._dispose();
}
/**
* Clean any existing subscription to change events
*/
private _dispose(): void {
if (typeof this.onTranslationChange !== 'undefined') {
this.onTranslationChange.unsubscribe();
this.onTranslationChange = undefined;
}
if (typeof this.onLangChange !== 'undefined') {
this.onLangChange.unsubscribe();
this.onLangChange = undefined;
}
if (typeof this.onDefaultLangChange !== 'undefined') {
this.onDefaultLangChange.unsubscribe();
this.onDefaultLangChange = undefined;
}
}
}
And this service
import { Injectable } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { Subject, Observable } from 'rxjs';
const CMP_NAME = 'TextsService';
@Injectable({
providedIn: 'root'
})
export class TextsService {
readonly onChange: Subject<void> = new Subject<void>();
get currentTextsIentifier(): string {
return this._currentTextsID;
}
set currentTextsIentifier(identifier: string) {
this._currentTextsID = identifier;
this._translate.use(this._currentTextsID);
this.onChange.next();
}
private _currentTextsID: string = 'default';
constructor(
private _translate: TranslateService
) {
this._translate.setDefaultLang(this.currentTextsIentifier);
}
getTexts(
i18n: { [key: string]: string },
translations: { [key: string]: string } | string
): { [key: string]: string } {
if (typeof translations === 'object') {
Object.keys(translations).forEach(((key: any) => {
this._translate.get(key).subscribe(
(res: string) => i18n[translations[key]] = res
);
}).bind(this));
} else if (typeof translations === 'string') {
this._translate.get(translations).subscribe(
(res: string) => i18n[translations] = res
);
}
return i18n;
}
getText(key: string): string {
let text: string;
this._translate.get(key).subscribe(
(res: string) => text = res
);
return text;
}
getTextInstante(key: string): string {
return this._translate.instant(key);
}
setTexts(translations: any): void {
if (typeof translations === 'object') {
this._translate.setTranslation(this.currentTextsIentifier, translations);
} else {
this._translate.setTranslation(this.currentTextsIentifier, JSON.parse(translations));
}
this.onChange.next();
}
reset(lang?: string): Observable<any> {
return this._translate.reloadLang(lang || this.currentTextsIentifier);
}
}
I have the same issue. I tried to fix it by following this tutorial: https://www.codeandweb.com/babeledit/tutorials/how-to-translate-your-angular7-app-with-ngx-translate
My dependencies:
"@ngx-translate/core": "^11.0.1",
"@ngx-translate/http-loader": "^4.0.0",
The way I found it to work in Angular 7:
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useClass: TranslateUniversalLoader
}
}),
import { TranslateLoader } from '@ngx-translate/core';
import { Observable, of } from 'rxjs';
import * as contentEn from './en.json';
import * as contentRo from './ro.json';
const TRANSLATIONS = {
en: contentEn,
ro: contentRo
};
export class TranslateUniversalLoader implements TranslateLoader {
getTranslation(lang: string): Observable<any> {
return of(TRANSLATIONS[lang].default);
}
}
It looks like the returned object is added under the default key
tested this in Angular 7 and also tested dynamic change works just fine
The way I found it to work in Angular 7:
TranslateModule.forRoot({ loader: { provide: TranslateLoader, useClass: TranslateUniversalLoader } }),```
import { TranslateLoader } from '@ngx-translate/core';
import { Observable, of } from 'rxjs';import * as contentEn from './en.json';
import * as contentRo from './ro.json';const TRANSLATIONS = {
en: contentEn,
ro: contentRo
};export class TranslateUniversalLoader implements TranslateLoader {
getTranslation(lang: string): Observable{
return of(TRANSLATIONS[lang].default);
}
}
```
It looks like the returned object is added under the default key
tested this in Angular 7 and also tested dynamic change works just fine
Finally, it working fine with me. thanks
and i have same problem...
The issue isn't with translate. Typescript/Angular stopped allowing imports without defaults (import * as ...) without wrapping it in a default property. You need to add the following to compiler options in the tsconfig.
"allowSyntheticDefaultImports": true,
"esModuleInterop": true
Also, change your imports to "import en from en.json" (not * as) or something similar depending on your lint set up.
@ajmccallum I use TranslateHttpLoader and my loader for translation files looks like this:
export function createTranslateLoader(http: HttpClient) {
return new TranslateHttpLoader(http, './static/dist/browser/assets/i18n/all/', '.json');
}
I don't have this kind of imports: "import en from en.json" but still have an issue with translate pipe:
The pipe 'translate' could not be found in production mode
@Maryna-Yelakova I believe that might be a different issue. This might help.
https://github.com/ngx-translate/core/issues/163
@ajmccallum It looks very similar but i got this error after angular upgrade to v7 and only in production mode. Everything worked fine before that. I downgraded angular to 6 version and now everything works. But i would like to have possibility upgrade angular packages
@Maryna-Yelakova are you using Ivy? It removes pipes in production mode for tree shaking?
Honestly I have found the HTTPTranslateLoader to be a pain in the ass sometimes so I just prefer to use a custom loader like this
export class CustomTranslateLoader implements TranslateLoader {
getTranslation(lang: string): Observable<any> {
return from(import(`../assets/i18n/${lang}.json`));
}
}
Then I go ahead and import it like
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useClass: CustomTranslateLoader ,
}
}),
import { Observable, from } from 'rxjs'
Works all the time
@ajmccallum thank you so much! The problem was because of Ivy. I had "enableIvy": true
in my tsconfig.json. It's my bad.
@ajmccallum thank you so much! The problem was because of Ivy. I had
"enableIvy": true
in my tsconfig.json. It's my bad.
That did it for me....Thanks
The problem is the new version of angular with 7.1 it works just fine but when you update it to 7.2 the problems start to pop up. In my case i use:
"@ngx-translate/core": "^11.0.1",
"@ngx-translate/http-loader": "^4.0.0",
"@ngx-translate/core": "^7.2.14"
With the same implementation as this https://www.codeandweb.com/babeledit/tutorials/how-to-translate-your-angular7-app-with-ngx-translate.
Everything works fine until i subscribe to the LangChangeEvent and the problem starts:
Type 'Subscription' is missing the following properties from type 'EventEmitter
It looks like EventEmitters are changed in angular 7.2.
The first call to translate.use(..) doesn't emit the event, but the second one yes: first one call is not considered as a change.
Then, to make the trick, just call translate.use(..) one time to receive next changes in your subscriber
It's any 'oficial' solution to solve this issue? I oppen other issue some time ago https://github.com/ngx-translate/core/issues/1060 because I don't see this one. Sorry
Honestly I have found the HTTPTranslateLoader to be a pain in the ass sometimes so I just prefer to use a custom loader like this
export class CustomTranslateLoader implements TranslateLoader { getTranslation(lang: string): Observable<any> { return from(import(`../assets/i18n/${lang}.json`)); } }Then I go ahead and import it like
TranslateModule.forRoot({ loader: { provide: TranslateLoader, useClass: CustomTranslateLoader , } }),
import { Observable, from } from 'rxjs'Works all the time
What's the difference on using the two approaches?
(useProvider vs useClass)
"allowSyntheticDefaultImports": true,
"esModuleInterop": true
Thanks @ajmccallum for your solution, this works fine for me.
I am facing issue with ngx-translate while running in production mode.
I am using Angular 8 , ngx-translate/core : 11.0.1 & ngx-translate/http-loader: 4.0.0
It is always displaying only key.
In dev mode it works fine using ng serve
Any help?
Thanks!
The issue isn't with translate. Typescript/Angular stopped allowing imports without defaults (import * as ...) without wrapping it in a default property. You need to add the following to compiler options in the tsconfig.
"allowSyntheticDefaultImports": true,
"esModuleInterop": trueAlso, change your imports to "import en from en.json" (not * as) or something similar depending on your lint set up.
Yeh! I was facing this problem with ngx-rocket, in the i18n service made by them, the import of translates is: import enUS from '../../translations/en-US.json'; Changing to import * as enUS from '../../translations/en-US.json'; works fine!
Don't need of this changes:
> "allowSyntheticDefaultImports": true,
> "esModuleInterop": true
Thanks @ajmccallum
Most helpful comment
The way I found it to work in Angular 7:
It looks like the returned object is added under the default key
tested this in Angular 7 and also tested dynamic change works just fine