如何使用Vite和React生成多个本地化包?

问题描述 投票:0回答:1

我在 Github 上准备了 一个最小的测试项目来演示我自己已经尝试过的内容:

我的目标是为每种受支持的语言生成一个捆绑包。

换句话说,我不想让用户在我的 React 应用程序中运行时切换语言,因为我真正的应用程序非常大并且特定于国家/地区。

相反,我想生成这 3 个文件,然后在我的后端从不同的 URL 提供它们:

  • dist/index-en.js
  • dist/index-de.js
  • dist/index-fr.js

所以我尝试创建一个自定义的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 文件的目标。

我有一种感觉,一定有更好的方法来解决这个问题。

reactjs localization vite bundle vite-plugin-development
1个回答
0
投票

好的,通过使用 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]`,
      },
    },
  },
});
© www.soinside.com 2019 - 2024. All rights reserved.