All the texts for my app are inside a .json file for translation purposes. I need a function to get the corresponding text based on the selected language.
I think it should be an easy task, but I don't see the solution.
I have the following object:
{
section1: {
btn: { en: "English", es: "Español" },
title: {
en: "Web Frontend Developer",
es: "Desarrollador Web de Frontend"
},
card: {
title: { en: "Hello!", es: "Hola!" },
btn: { en: "Get started", es: "Empecemos" },
}
}
}
This object should be passed to a function as the first parameter and the second parameter should be the language (in this case "en" or "es"). I want something like this: filterObjByLanguage(obj, "es")
And it should return:
{
section1: {
btn: "Español",
title: "Desarrollador Web de Frontend",
card: {
title: "Hola!",
btn: "Empecemos"
}
}
}
Basically, it goes through each part of the object and wherever there is a { en:"text", es: "texto" }
, it chooses one of them based on the second parameter.
This is my attempt, but only the first layer of the object is returned correctly, the rest is undefined.
const filterObjByLanguage= (obj: any, lang: string): any => {
const output = Object.assign(obj, {});
const loop = (obj: any, isRoot: boolean = true): any => {
for (var k in obj) {
const value = output[k];
const valueAtSelected = value?.[lang];
if (typeof value === "string") {
continue;
} else if (valueAtSelected) {
if (isRoot) output[k] = valueAtSelected;
else return valueAtSelected;
} else {
if (isRoot) output[k] = loop(value, false);
else return loop(value, false);
}
}
};
loop(output);
return output;
};
There's one difficulty here: knowing what objects are language values versus which are collections of them. In this solution, I use the existence of a 'en'
property as a signal. Once we have that, it's mostly a matter of tearing apart and rebuilding objects using Object.entries
and Object.fromEntries
. In plain JS (I'll leave Typescript for those who appreciate it!), it might look like this:
const filterObjByLanguage = (lang) => (o) => Object (o) === o ? 'en' in o ? o [lang] || '' : Object .fromEntries ( Object .entries (o) .map (([k, v]) => [k, filterObjByLanguage (lang) (v)]) ) : o const i18n = {section1: {btn: {en: "English", es: "Español"}, title: {en: "Web Frontend Developer", es: "Desarrollador Web de Frontend"}, card: {title: {en: "Hello!", es: "Hola!"}, btn: {en: "Get started", es: "Empecemos"}}}} console .log ('English', filterObjByLanguage ('en') (i18n)) console .log ('Español', filterObjByLanguage ('es') (i18n)) console .log ('Français', filterObjByLanguage ('fr') (i18n))
.as-console-wrapper {max-height: 100% !important; top: 0}
This also makes the decision that missing language values are simply empty strings. If you prefer undefined
, then you could just remove || ''
|| ''
. We can extend this to arrays if that's required with a simple modification:
const filterObjByLanguage = (lang) => (o) =>
Array .isArray (o)
? o .map (filterObjByLanguage (lang))
: Object (o) === o
? 'en' in o
? o [lang] || ''
: Object .fromEntries (
Object .entries (o) .map (([k, v]) => [k, filterObjByLanguage (lang) (v)])
)
: o
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.