You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过Webpack处理多租户XLIFF翻译文件 合并覆盖项输出可用JSON

实现方案

第一步:安装必要依赖

先装需要的工具包:

npm install xliff glob lodash.merge webpack-virtual-modules --save-dev
  • xliff:用来解析xlf格式文件为JSON
  • glob:用来遍历翻译目录下的所有xlf文件
  • lodash.merge:用来合并通用翻译和租户自定义翻译,自动覆盖重名key
  • webpack-virtual-modules:用来动态生成虚拟的翻译模块,不需要写入实际文件,支持热更监听

第二步:封装翻译聚合逻辑

先写一个工具函数,输入租户名和domain,输出聚合后的翻译JSON:

const { parse } = require('xliff');
const fs = require('fs');
const glob = require('glob');
const merge = require('lodash.merge');

// 支持的语言列表,可根据实际情况调整
const SUPPORT_LANGS = ['en', 'fr', 'es'];
// 翻译根目录
const TRANSLATION_ROOT = './translations';

function generateTranslation(tenant, domain) {
  const result = {};
  // 先加载通用翻译
  SUPPORT_LANGS.forEach(lang => {
    const commonPath = `${TRANSLATION_ROOT}/common/${domain}.${lang}.xlf`;
    if (fs.existsSync(commonPath)) {
      const commonXlf = fs.readFileSync(commonPath, 'utf8');
      const commonRes = parse(commonXlf).resources;
      // 转成key:value格式
      result[lang] = Object.fromEntries(Object.entries(commonRes).map(([k, v]) => [k, v.target]));
    }
  });
  // 再加载租户自定义翻译,覆盖通用翻译的同key值
  SUPPORT_LANGS.forEach(lang => {
    const tenantPath = `${TRANSLATION_ROOT}/${tenant}/${domain}.${lang}.xlf`;
    if (fs.existsSync(tenantPath)) {
      const tenantXlf = fs.readFileSync(tenantPath, 'utf8');
      const tenantRes = parse(tenantXlf).resources;
      const tenantMap = Object.fromEntries(Object.entries(tenantRes).map(([k, v]) => [k, v.target]));
      // 合并,租户的优先级更高
      result[lang] = merge(result[lang], tenantMap);
    }
  });
  // 如果你需要的是{key:{en:xxx, fr:xxx}}格式,取消注释这段转换代码即可
  // const keyBased = {};
  // Object.entries(result).forEach(([lang, pairs]) => {
  //   Object.entries(pairs).forEach(([key, value]) => {
  //     if (!keyBased[key]) keyBased[key] = {};
  //     keyBased[key][lang] = value;
  //   })
  // })
  // return keyBased;
  return result;
}

第三步:修改Webpack多租户配置

你现在是每个租户对应一个独立的webpack编译配置,我们给每个租户的配置加上虚拟模块和监听逻辑:

const VirtualModulesPlugin = require('webpack-virtual-modules');
const tenants = ['TenantA', 'TenantB'];
const modules = []
// 你所有的domain列表,也可以用glob自动扫描common目录下的所有domain
const DOMAINS = ['messages', 'thing'];

tenants.forEach(tenant => {
  // 为当前租户生成所有domain的虚拟翻译模块
  const virtualModules = new VirtualModulesPlugin();
  DOMAINS.forEach(domain => {
    const translationJson = generateTranslation(tenant, domain);
    // 虚拟模块路径对应你引入的路径:import translations from 'translations/messages'
    virtualModules.writeModule(`node_modules/translations/${domain}.js`, `module.exports = ${JSON.stringify(translationJson)}`);
  })

  modules.push({
    // 你原有的租户相关webpack配置:entry、output、其他loader等都保留
    entry: `./src/${tenant}/index.js`,
    output: {
      path: `./dist/${tenant}`,
      filename: 'bundle.js'
    },
    plugins: [
      // 加入虚拟模块插件
      virtualModules,
      // 其他原有插件
    ],
    // 配置监听翻译目录文件变更,触发重新编译
    watchOptions: {
      ignored: /node_modules/,
      aggregateTimeout: 300,
      poll: 1000
    },
    // 如果你用webpack 5+且开启了devServer,可以加这个配置自动监听翻译文件变更刷新
    // devServer: {
    //   watchFiles: ['./translations/**/*.xlf']
    // }
  })
})

module.exports = modules

验证使用

直接在对应租户的前端代码里引入即可:

import messages from 'translations/messages';
import thing from 'translations/thing';

// 示例使用
console.log(messages.fr['hello']); // 会优先取租户自定义的翻译,没有就用通用的

内容的提问来源于stack exchange,提问作者Pierre-Antoine Guillaume

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.14 17:06:00