我在 Github 上准备了 一个最小的测试项目来演示我自己已经尝试过的内容:
我的目标是为每种受支持的语言生成一个捆绑包。
换句话说,我不想让用户在我的 React 应用程序中运行时切换语言,因为我真正的应用程序非常大并且特定于国家/地区。
相反,我想生成这 3 个文件,然后在我的后端从不同的 URL 提供它们:
所以我尝试创建一个自定义的Vite插件vite-plugin-react-localize.js,它取代了
__PLACEHOLDERS__
,可以在上面的截图中看到:
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;
});
},
};
}
为了激活插件,我已将其添加到 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]`,
},
},
},
});
最后,我将 3 个构建命令添加到 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"
},
我的方法现在可以工作了,好的一点是,即使是“dev”任务预览也可以正确本地化为默认的“en”语言。这是我的 VS Code 的屏幕截图:
但是我还没有达到能够生成3个不同的 dist/index-*.js 文件的目标。
我有一种感觉,一定有更好的方法来解决这个问题。
好的,通过使用 generateBundle 钩子解决了我的问题:
这是我的自定义 vite-plugin-react-localize.js 文件:
"use strict";
import fs from "fs";
import path from "path";
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() {
return {
name: "localize-plugin",
generateBundle(outputOptions, bundle) {
for (const [fileName, bundleValue] of Object.entries(bundle)) {
if (!fileName.endsWith("index.js")) {
continue;
}
const indexJsPath = path.resolve(outputOptions.dir, fileName);
console.log("\nReplacing placeholders in", indexJsPath);
for (const lang of Object.keys(localizedStrings)) {
const indexLangPath = path.resolve(
outputOptions.dir,
`index-${lang}.js`
);
console.log("Creating localized file", indexLangPath);
const replacedContent = bundleValue.code.replaceAll(
/__[A-Z]+__/g,
function (match) {
return localizedStrings[lang][match] || match;
}
);
fs.writeFileSync(indexLangPath, replacedContent);
}
}
},
};
}
它是在修改后的vite.config.js文件的帮助下调用的:
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import localize from "./vite-plugin-react-localize";
export default defineConfig({
plugins: [react(), localize()],
build: {
target: "es2015",
rollupOptions: {
output: {
entryFileNames: `[name].js`,
chunkFileNames: `[name].js`,
assetFileNames: `[name].[ext]`,
},
},
},
});