Reputation: 446
I have a structured translation file as follows:
"myApp":{
"errorMessages": {
"unauthorized": "This {{serviceName}} account is not valid for the {{appName}} app.",
"missing_role": "You can not use this account to access {{appName}} application"
}
}
If I access single translation directly, I can easily use interpolation:
const appNameObject = { appName: 'My app', serviceName: 'My Service' };
const unauthorizedErrorMessage = translateService.instant('myApp.errorMessages.unauthorized', appNameObject);
But sometimes I would like to get all keys in a structured object at once - and interpolation seems not to work in this case
const errorMessages = translateService.instant('myApp.errorMessages', appNameObject);
Can I get this working? Thanks
Upvotes: 4
Views: 4117
Reputation: 530
You can interpolate your parameters using a regex. In the .replace()
function, call them with an object or a table using the match string.
Use the regex /{{(\w+)}}/gm
to match the string to replace
const appNameObject: any = {
serviceName: 'potatoe'
appName: 'jam'
}
const message: string = (
await this.translateService
.get('myApp.errorMessages.unauthorized')
.toPromise()
)
.replace(
/{{(\w+)}}/gm,
(fullMatch, match) => appNameObject[match]
);
Please, refer to Atscub answer which apply a regex on every elements of the translation object (even nested ones) using JSON.stringify
.
My implementation of a NgxInterpolation method without JSON import (es2019+):
const NgxInterpolation: any = (translationObject: any, interpolationObject: {[k: string]: any}) => {
switch(typeof translationObject){
case "object":
return Object.fromEntries(
Object.entries(translationObject).map(
([k, v], i) => [k, NgxInterpolation(v, interpolationObject)]
)
);
case "string":
return translationObject.replace(
/{{(\w+)}}/gm,
(fullMatch, match) => interpolationObject[match]
);
default:
return translationObject;
}
}
Use it as follow:
const errorMessages: any = NgxInterpolation(
this.translateService.instant('myApp.errorMessages'),
appNameObject
)
ngx-translate has a parser and the get
function from the translation service accept an interpolation object.
for the json file en.json
:
{
"HOME": {
"HELLO": "hello {{value}}"
}
}
you can interpolate the key value
set to world
for the translation string HELLO
as follow:
// With the interpolationObject parameter from the get (or instant) method
this.translateService.get('HELLO', { value: 'world' })
// With the interpolation method from the ngx-translate parser
this.translateService.parser.interpolate(
this.translateService.instant("HELLO"),
{ value: 'world' }
)
The translation only works for translation string. If you want to apply interpolation on every translation string by using ngx-translate methods, you need to define a method as follow (es2019+):
NgxObjectInterpolation(
translationObject: any,
interpolationObject: { [k: string]: any }
) {
switch (typeof translationObject) {
case "object":
return Object.fromEntries(
Object.entries(translationObject).map(([k, v], i) => [
k,
this.NgxObjectInterpolation(v, interpolationObject),
])
);
case "string":
return this.translateService.parser.interpolate(
translationObject,
interpolationObject
);
default:
return translationObject;
}
}
Use it like this:
this.NgxObjectInterpolation(
this.translateService.instant("HELLO"),
{ value: "world" }
);
Upvotes: 1
Reputation: 411
Although it can't be done out of the box, you can easily accomplish what you need using JSON.stringify() / JSON.parse() and interpolate by yourself using regular expressions.
Define a function in your utils
service or any other place like this:
const objectInterpolate = (obj: any, params: {[k: string]: any}) => {
return JSON.parse(
JSON.stringify(obj)
.replace(/{{\s*([^}\s]+)\s*}}/gm, (_, group) => params[group] ?? "")
);
}
Then use it in your anywhere:
this.translate.get("myApp.errorMessages")
.subscribe(value => {
this.errorMessages = this.utils.objectInterpolate(
value,
{
paramName: paramValue,
paramName2: paramValue2,
...
}
);
);
Upvotes: 1
Reputation: 2816
The ngx-translate doesn't support this.
If you want/expect to get an object that looks like this
{
"unauthorized": "This My Service account is not valid for the My app app.",
"missing_role": "You can not use this account to access My app application"
}
You have to actually create it yourself the way you use interpolation in the example that works
Upvotes: 1