Making the Webpack i18n plugin play nicely with template strings and variables

The Webpack I18n plugin is a great little tool which allows you to create multiple language versions of your content. Using the multi-compiler feature of Webpack, it creates multiple bundles, accessing different translations depending on your config.

To put this into context, the example below shows the content of a console log would vary depending on which output you viewed, but the source JavaScript (app.js) stays the same.

app.js:

console.log(__("Hello World"));

en.json:

{
"Hello World": "Hello World"
}

nl.json:

{
"Hello World": "Hallo Wereld"
}

The output of en.output.js would read console.log("Hello World"); whereasnl.output.js would read console.log("Hallo Wereld"); Further examples can be found on their GitHub repo.

However, when using this, our team encountered a rather significant problem. The i18n plugin does not allow template strings or variables. Instead of being resolved at compile time, lines such as console.log(__(foo)) throw the error __ is not defined. This is documented in the ‘issues’ tab on GitHub, but we didn’t realise until it was too late. I found this problem particularly frustrating and took it upon myself to find a solution.

There followed weeks of researching (on and off). I came up with a few different solutions, none of which would quite work for our use cases. Eventually, I found what I was looking for, tucked away in a StackOverflow post I happened across.

The solution we’ve settled on uses the Webpack PluginProvider. This allows you to set a global variable — accessible anywhere within your bundled code.

Our Webpack config now looks a little like this:

plugins: [ 
new I18nPlugin(utils.getVocabJson(language)),
new webpack.ProvidePlugin({
__: path.resolve(__dirname, ‘bin/helpers/webpack-vocabs.js’),
}),
],

This sets up the i18n plugin, and then, using the ProvidePlugin, makes __ a globally available function. If a string is used, this will be resolved before compile time, otherwise __ will remain in the JS at runtime. This can then be resolved using the now globally available function declared above.

I wanted to declare a function within the providePlugin but it seemed to only accept a path, so I moved the simple function into a separate file. The bin/helpers/webpack-vocab.js just contains a function which looks something like:

function getVocabs(propName) { 
return getConfig().vocab[propName];
}
module.exports = getVocabs;

Hey Presto! We can now use code like

document.querySelector(`.${item}`).innerHTML = __(`${item}`_title);

without the dreaded __ is not defined error message. And, so far, it seems to be working nicely.

Hopefully, this will help if you decide to make use of the i18n plugin for your own projects.

Software Engineer at BBC News Visual Journalism. Brightonian living in London.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store