0

I'm trying to complete an exercise and somethings just not clicking.

Here's the question: Could you write in JS (or Coffescript or any language that actually makes sense) a method getTranslation(lang, path) --> string that works the following way: You have this global object:

strings = {
    home: {
        intro: {
            en: 'Welcome',
            fr: 'Bienvenue'
        },
        content: {
            explanation: {
                en: 'This is an interesting exercise',
                fr: 'C\'est un exercice intéressant',
                de: 'Es ist eine interesante Übung'
            },
            contact: 'Contact',
            goodbye: {
                en: 'Goodbye',
                fr: 'Au revoir',
                es: 'Adios'
            }
        }
    }
}

and

getTranslation('home.intro', 'fr') // => 'Bienvenue'
getTranslation('home.content.contact', 'fr') // => 'Contact'
getTranslation('home.intro', 'es') // => 'Welcome'
getTranslation('home.content.goodbye') // => 'Goodbye'
getTranslation('unvalid.path','en') // => ''

So the first argument is a string that describes the path through the keys separated by a dot (not dots in keys assumed), and the second argument is the language, which falls back to 'en' if not provided or nonexistent (we also assume that at the end of every branch, either the 'en' keys exists, or it is a single string like in home.content.contact).

Here's my answer that I've come up with so far but I know I'm doing something wrong because nothings being returned.

function getTranslation (path, lang) {

    lang = lang || "en";

    var strings = {
        home: {
            intro: {
                en: 'Welcome',
                fr: 'Bienvenue'
        },
        content: {
            explanation: {
                en: 'This is an interesting exercise',
                fr: 'C\'est un exercice intéressant',
                de: 'Es ist eine interesante Übung'
            },
            contact: 'Contact',
            goodbye: {
                en: 'Goodbye',
                fr: 'Au revoir',
                es: 'Adios'
            }
        }
    }

    if (path == 'home.content.contact') {
        return strings.path;
    } else if (path == 'unvalid.path') {
        return '';
    } else {
        return strings.path.lang;
    }
}

getTranslation('home.intro', 'fr'); // => 'Bienvenue'
getTranslation('home.content.contact', 'fr'); // => 'Contact'
getTranslation('home.intro', 'es'); // => 'Welcome'
getTranslation('home.content.goodbye'); // => 'Goodbye'
getTranslation('unvalid.path','en'); // => ''

Thank you to anyone willing to help.

1
  • there are quite a few ways to do this.. the path you seem to be going down is tedious as you'd have to compare your path to each of the pathes in strings json. <== bad idea.. what you could do is eval your path parameter to get the string you want, then select out the lang var.. see answer Commented Nov 19, 2013 at 22:26

4 Answers 4

2

Not sure if it is the best solution but it satisfies all your needs.

function getTranslation(path, lang) {

    lang = lang || "en";
    strings = {
        home: {
            intro: {
                en: 'Welcome',
                fr: 'Bienvenue'
            },
            content: {
                explanation: {
                    en: 'This is an interesting exercise',
                    fr: 'C\'est un exercice intéressant',
                    de: 'Es ist eine interesante Übung'
                },
                contact: 'Contact',
                goodbye: {
                    en: 'Goodbye',
                    fr: 'Au revoir',
                    es: 'Adios'
                }
            }
        }
    }
    path = path.split(".");
    var result = strings;
    for(var i in path){
        result = result[path[i]];
        if(result == undefined){
            return '';
        }
    }
    return (result[lang]==undefined)?"":result[lang];
}
Sign up to request clarification or add additional context in comments.

1 Comment

Good answer for avoiding eval and returning an empty string for invalid paths. Note that this code actually fixes a couple syntax errors in the original code.
0
function getTranslation (path, lang) {

                lang = lang || "en";

                var strings = {
                    home: {
                        intro: {
                            en: 'Welcome',
                            fr: 'Bienvenue'
                    },
                    content: {
                        explanation: {
                            en: 'This is an interesting exercise',
                            fr: 'C\'est un exercice intéressant',
                            de: 'Es ist eine interesante Übung'
                        },
                        contact: 'Contact',
                        goodbye: {
                            en: 'Goodbye',
                            fr: 'Au revoir',
                            es: 'Adios'
                        }
                    }
                }
            };
            var string = eval('strings.' + path);
            return string[lang];
            }

not a fan of this solution as i avoid evals but it solves your problem. try out your function calls.

jsfiddle

1 Comment

the path being sent it in a json shorthand syntax. the eval just tries to evaluate your path against the strings variable holding json. your better option is to parse the information out of the path variable and then reference the object you need in json.
0

I think part of the difficulty you're having is that you've got a some JavaScript code that you want to run, but it's trapped inside a string.

I believe when you say

return strings.path.lang

you wanted this to be executed (assuming path = 'home.intro' and lang = 'fr':

return strings.home.intro.fr

not this:

return strings.'home.intro'.'fr'

You could use eval to evaluate path into the code you want, but eval can lead to security holes.

I would approach this by splitting your path string on the . character.

Here's a quick function I wrote that does this:

function getTranslation (path, lang, obj) {

    obj = obj || strings;
    lang = lang || "en";

    var dotIndex = path.indexOf('.');

    if(dotIndex === -1) {
    return obj[path][lang];
}
else
{
    var firstFromPath = path.substring(0, dotIndex);
    var restPath = path.substring(dotIndex + 1);
    return getTranslation(restPath, lang, obj[firstFromPath]);
}

This doesn't do everything you want to do, but hopefully it helps.

Comments

0
return strings.path;

won't return anything, because there's no "path" property on your string object.

You want:

return strings[path];

...but this will only work if your property is at the first level of nesting within your object. For example...

strings['home'];

will give you and object like

{intro: {
    en: 'Welcome',
    fr: 'Bienvenue'
}}

However, trying to access nested properties by name, like the following, returns undefined:

strings['home.intro']

So, you'll have to split the path string by ., loop through the resulting array, and get each property by name individually.

I'll leave the implementation to you since you mentioned it's an exercise, but feel free to ask questions if you get stuck.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.