Isak Berglind

Isak Berglind

Translate content on the front end

Isak Berglind • April 23, 2018

php javascript

A multilingual site comes with a few more challenges than a normal single language site. One of those challenges is how to provide the translated strings to your frontend framework.

How to approach this all depends on your site. If your site is a single page application — you are probably fetching the strings with ajax. If your site is a multi page application with some dynamic functionality sprinkled in, you might want to pass the strings to frontend on page load.

I was lately at this crossroads and none of the options felt good. The ajax solution is what I guess most people would call the Right Way™. To me it felt a bit wasteful. Hammering your server on each request for the same content over and over. You might also get a little glitch while it fetches the strings and may need to show an extra loading screen.

So what about the other option, to pass the strings to the frontend on page load? The pro’s are fewer requests and therefore faster loading times, and no loading glitches. There are some cons too, of course. How would you even go about this? Should you pass all your strings and let the frontend pick the ones it needs? That can get out of hands pretty fast. It’s maybe okay if you only got a few strings, but what if you have thousands? Your poor users would have to download a bunch of stuff they would never use. Nah, that doesn’t feel right..

It would be a lot better if you only passed the strings the frontend needed.

How would we make this work thought? There is a simple option — to manually add/remove strings to an array that gets passed to the frontend. This could maybe work if you don’t change the code so often, but in most cases, this is probably not a great idea.

A better idea would maybe be to do this in your build step. To copy all the string keys from our frontend code to a json-file, translate them server side and pass only those on page load. Let’s take a look at how that might look.

In my case, I have my translations stored in a database, but this approach would work with language files too.

Making it happen

Let’s start at the frontend. We’ll create a translate function that all my frontend components can use. Let’s decide to store the translations as an array where they key is the translation key and the value is the translated string itself. Here’s what that might look like.

_(key) {
    return translatedStrings[key];
},

That’s all good, just one problem. We haven’t got any strings in the translatedStrings array. How do we populate that?

Use a webpack plugin

I compile and build my assets using webpack, so we need a plugin that searches my frontend code for my translate functions and grabs the first parameter — the key. That way we know which keys are used by our frontend code and can provide only these.

I couldn’t find any webpack plugin that suited my needs. Luckily it’s quite easy to write one. Here’s what I came up with.

We can install it using npm

npm install copy-text-webpack-plugin --save-dev

… and register it as a webpack plugin like this:

plugins: [
    new CopyTextPlugin({
        pattern: , // Pattern to match, required
        extension: 'js', // File extension to copy from
        allowDoubleEntries: false, // Allow same values to be saved more then once
        captureGroupNumber: 1, // Which regex group to capture
        outputFilename, strings, // Name of the newly generated file
    }),
]

Let’s keep everything default and provide a regex that will capture all our keys in the translation function:

/_\([n\s\\"']+([\w_\-.]+)[n\s"'\\]+\)+/g

When we run it we end up with all the keys in an array in a json file called strings.json. Perfect!

Pass it to the frontend

Now we need to provide the frontend with that array on page load. First let’s load the json file and actually translate the keys server side. Here’s how you might do it using php:

function getTranslations()
{
    $translationKeys = json_decode(file_get_contents("path/to/strings.json"));
    $translations = [];
    foreach($translationKeys as $key) {
        $translations[$key] = _($key);
    }
    return $translations;
}

Note that I have the same translation function on the backend _($key) except that one actually finds and translates the string.

All that’s left is to pass the translated array to the frontend

let translatedStrings = <?php echo json_encode($translations) ?>

That’s it! We’ve now provided only the translations the frontend needs without a single extra request. Quite nifty right?

Please let me know what you think about this approach. You can find me on twitter at @Isak_Berglind