I have prepared a minimal test project at Github to demonstrate, what I have already tried myself:
My goal is to generate one bundle per supported language.
In other words, I do not want let users to switch languages at the runtime in my React app, because my real app is pretty large and country-specific.
Instead I would like to generate these 3 files and then serve them from different URLs at my backend:
- dist/index-en.js
- dist/index-de.js
- dist/index-fr.js
So I have tried to create a custom Vite plugin vite-plugin-react-localize.js, which replaces __PLACEHOLDERS__
, that can be seen in the above screenshot:
const localizedStrings = {
en: {
__YES__: "Yes",
__NO__: "No",
__CANCEL__: "Cancel",
},
de: {
__YES__: "Ja",
__NO__: "Nein",
__CANCEL__: "Abbrechen",
},
fr: {
__YES__: "Oui",
__NO__: "Non",
__CANCEL__: "Annuler",
},
};
export default function localize(lang) {
return {
name: "localize-plugin",
transform(code, id) {
console.log(lang, id);
return code.replaceAll(/__[A-Z]+__/g, function (match) {
return localizedStrings[lang][match] || match;
});
},
};
}
To activate the plugin I have added it to the vite-config.js:
const lastArg =
process.argv.length > 0 ? process.argv[process.argv.length - 1] : "";
const matches = lastArg.match(/--lang=(en|de|fr)$/);
const lang = matches ? matches[1] : "en";
export default defineConfig({
plugins: [react(), localize(lang)],
build: {
target: "es2015",
rollupOptions: {
output: {
entryFileNames: `[name].js`,
chunkFileNames: `[name].js`,
assetFileNames: `[name].[ext]`,
},
},
},
});
And finally, I have added the 3 build commands to the package.json:
"scripts": {
"dev": "vite",
"build en": "vite build -- --lang=en",
"build de": "vite build -- --lang=de",
"build fr": "vite build -- --lang=fr",
"lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0",
"preview": "vite preview"
},
My approach kind of works now and the nice thing is that even the "dev" task preview is properly localized to the default "en" language. Here a screenshot of my VS Code:
However I have not achieved the goal of being able to generate 3 different dist/index-*.js files.
And I have a feeling, that there must be a better way to approach this problem.
Ok, solved my problem by utilizing the "transform" and "generateBundle" hooks:
Here my custom vite-plugin-react-localize.js file:
It is called with the help of the modified vite.config.js file:
Now the "vite build" works as I wanted and produces 3 additional files: