0

Pretty (very) new to Node so this is probably stupid. I have a module that defines various routes that I iterate over to define the app's routes. This works fine.

While setting up the route I want to call a function checkAvailableTranslation in another module language that checks whether a translation of that page exists in another language (req.locale being the user's favoured language that we are trying to find a match for), and if so return a URL fragment for it.

The strings object is loaded from a json file and contains an item translations that is an array of ISO country codes mapped to URL fragments.

** app.js **

var routes = require("./config/routing.js")
routes.forEach(function(item) {
    item.routes.forEach(function(route) {
        app.get(route.path, function(req, res) {
            var strings = require(route.strings)
            translations = language.checkAvailableTranslation(req.locale, strings.translations))
            console.log(translations) // undefined?!?!?!?!
            res.render(route.render, {
                layout: route.layout,
                strings: strings
            })
        })
    })
})

** strings.translations **

[
    { "fr": "/fr" },
    { "ar": "/ar" },
    { "es": "/es" },
    { "pt": "/pt" },
    { "de": "/de" }
]

** language.js **

module.exports = function() {
    var module = {}

    module.checkAvailableTranslation = function(language, translations) {
        translations.forEach(function(el) {
            if( el[language] ) {
                console.log(el[language]) // this logs a matched language
                return el[language] // this disappears into the ether
            }
        })
    }
    return module
}

So everything generally behaves as expected with translations.forEach iterating successfully and finding matches. However it doesn't seem to return the value back to app.js - when I output the function's return I get undefined.

Does the fact that strings is being loaded from a json file make this an asynchronous call, as if it were a database? If so (and that would need explaining), what should I be doing here to set up a promise to deal with this?

1 Answer 1

1

You're returning from the forEach callback which is not possible. You need to iterate manually over the array or write the result into a variable in the scope of your checkAvailableTranslation method(but still iterate over all items in translations).

Manual "forEach"

module.checkAvailableTranslation = function(language, translations) {
    for (
        var i = 0, translation = translations[i][language];
        i < translations.length;
        i++, translation = translations[i][language]
    ) {
        if (translation)
            return translation;
    }
}

Or using Array.prototype.some

function (language, translations) {
    var res;
    translations.some(function (translation) {
        return !!(res = translation[language]);
    });
    return res;
}

EDIT: Ninja approach:

function n(l,t,i){return t[i|0][l]||g(l,t,(i|0)+1)}
Sign up to request clarification or add additional context in comments.

5 Comments

oh right. is every() more the right thing to go for here?
@artparks as you wanted to return the first matched item some should do the job in combination with a scoped variable.
thanks. all this just because i didn't know foreach() couldn't be used in this way :/ as this function will be called on every page request it needs to be as efficient as possible. any reason to use some() over an old fashioned for() loop?
No, some will be slower than an old fashioned for loop(like in my first example), yet I've added an example using some.
Not code golf but I added a ninja approach, just call with n(language, translations)

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.