webpack-i18next-translate
18next translation plugin for Webpack
Idea
This plugin…
- automatically extracts all i18n keys and default values from HTML templates and JS files
- dynamically generates or updates the existing default translation file (and serves the updated version from memory in development)
- creates an index file to look up the name of the final translation files, so you can use content hashes and aggressive caching.
- can create a diff so you can see added/changed/removed strings that need (re-)translation
- checks your translation files for syntax errors (eg. trailing commas) that could trip up i18next.
- warns about common mistakes like:
- the same key being used for different messages
- the same message having different keys
- the message containing JS interpolation syntax (
${…}
) instead of i18next syntax ({{…}}
). - the message containing HTML markup but not being bound to the htmlcontent of the tag. (Aurelia-specific)
To add minimal build time overhead, the plugin hooks into webpack’s JS parser instead of parsing the JS files itself.
Usage
Add the plugin to your webpack config and add the included HTML loader for your HTML files.
const I18nextTranslatePlugin = require('webpack-i18next-translate');
module: {
rules: [
{test: /\.html$/i, use: [
I18nextTranslatePlugin.HtmlLoader
]},
],
},
plugins: [
new I18nextTranslatePlugin({
src: 'locales/en/translation.json',
dest: 'assets/locales/en/translation.[hash].json',
translationFilePattern: …
index: 'translation-index.json',
i18nFunctionName: 'i18n.tr',
createDiff: isProductionBuild,
duplicateWarnings: true,
excludePaths = …
}),
new CopyWebpackPlugin([
{from: 'locales/*/*.json', to: 'assets/[path][name].[hash].[ext]', context: '.', ignore: ['**/en/translation.json']},
])
],
Unfortunately, i18next’s translation function doesn’t take a default value. But it’s really useful to see the actual message next to the translation key and extract it automatically. To enable this, change all your calls to the translation function by adding the default text as the third argument:
i18next.t('form.unsavedChanged', {});
i18next.t('form.unsavedChanged', {}, 'You have unsaved changes! Do you really want to leave this page?');
The third argument is ignored by i18next, but picked up by the webpack-i18next-translate
plugin.
If you use TypeScript, it will complain that i18next.t
only requires two paramters. You might want to ignore this:
i18next.t('form.unsavedChanged', {}, 'You have unsaved changes! Do you really want to leave this page?');
Index file
The generated index file will have the following format:
{
"en": {
"translation": "assets/locales/en/translation.afd17cbce4a9ec8aa31ebf21b334a887.json"
},
"de": {
"translation": "assets/locales/de/translation.bb77d8648ff2239aee123b5363baeb84.json"
},
…
}
You can use the index file to look up the name of the current translations, if you load them from your server. For example, for the i18next-fetch-backend
, you can use:
backend: {
loadPath(language, namespace) {
const lngNamespaces = translationIndex[language];
if (!lngNamespaces) {
return null;
}
return lngNamespaces[namespace];
}
}
Diff file
If you set createDiff: true
, the plugin will create a .diff.json
file next to your default translation file. The content looks like this:
{
"new": {
"nav": {
"Charts": "Charts"
}
},
"changed": {
"discount": "Your discount"
},
"removed": {
"datepicker": {
"today": "Today"
},
"form": {
"unsavedChanged": "You have unsaved changes! Do you really want to leave this page?"
},
}
}
This lets you know what you need to change in your non-default translation files. Once you've updated them, update your default translation file (or copy the content of the translation file from the compiled bundle) to reset the diff.