I am working on an Angular@11 application and facing an issue. In my app there are two panels, left and right. I want to translate the left panel in Spanish and the right one in German.
Using @ngx-translate/core, it will translate both panels in any one language at a time, but I want to translate both panels in different languages.
Any kind of help is appreciable.
You can achieve that by creating your own translate
pipe, to use it instead of the default one provided by ngx-translte
.
The new custom translate
pipe should depend on the same translations provided by TranslateService
, and handle the most logic handled by the default translate
pipe, but without handling the onLangChange
, onDefaultLangChange
, or onTranslationChange
events.
You can try something like the following:
import {
ChangeDetectorRef,
Injectable,
Pipe,
PipeTransform,
} from '@angular/core';
import { isObservable } from 'rxjs';
import { TranslateService } from '@ngx-translate/core';
@Injectable()
@Pipe({
name: 'translateBy',
pure: false, // required to update the value when the promise is resolved
})
export class TranslatePipe implements PipeTransform {
value: string = '';
lastKey: string;
lastParams: any[];
constructor(
private translate: TranslateService,
private _ref: ChangeDetectorRef
) {}
updateValue(
key: string,
interpolateParams?: Object,
translations?: any
): void {
let onTranslation = (res: string) => {
this.value = res !== undefined ? res : key;
this.lastKey = key;
this._ref.markForCheck();
};
if (translations) {
let res = this.translate.getParsedResult(
translations,
key,
interpolateParams
);
if (isObservable(res.subscribe)) {
res.subscribe(onTranslation);
} else {
onTranslation(res);
}
} else this.translate.get(key, interpolateParams).subscribe(onTranslation);
}
transform(query: string, lang: string, ...args: any[]): any {
if (!query || !query.length) {
return query;
}
// if we ask another time for the same key, return the last value
if (equals(query, this.lastKey) && equals(args, this.lastParams)) {
return this.value;
}
let interpolateParams: Object;
if (!!args[0] && args.length) {
if (typeof args[0] === 'string' && args[0].length) {
// we accept objects written in the template such as {n:1}, {'n':1}, {n:'v'}
// which is why we might need to change it to real JSON objects such as {"n":1} or {"n":"v"}
let validArgs: string = args[0]
.replace(/(\')?([a-zA-Z0-9_]+)(\')?(\s)?:/g, '"$2":')
.replace(/:(\s)?(\')(.*?)(\')/g, ':"$3"');
try {
interpolateParams = JSON.parse(validArgs);
} catch (e) {
throw new SyntaxError(
`Wrong parameter in TranslatePipe. Expected a valid Object, received: ${args[0]}`
);
}
} else if (typeof args[0] === 'object' && !Array.isArray(args[0])) {
interpolateParams = args[0];
}
}
// store the query, in case it changes
this.lastKey = query;
// store the params, in case they change
this.lastParams = args;
// set the value
this.updateValue(
query,
interpolateParams,
this.translate.translations[lang] // <<<<< This is the main requried change to return the translation for the provided lang.
);
return this.value;
}
}
And in the component, you can use it like the following:
<span>ES Value: {{ "MAIN_TITLE" | translateBy: "es" }}</span>
<span>DE Value: {{ "MAIN_TITLE" | translateBy: "de" }}</span>
P.S. The above custom pipe (and the original pipe also) uses the equals
function to check if the args
and lastParams
are equal or not. You can copy the ngx-translate
eqauls function and use it in your code, or you can use any other deeply equals
functions (e.g. lodash
isEqual)