node - 实现多语言脚本快速生成

node - 实现多语言脚本快速生成

前言

多个项目做了多语言,需要多个多语言表(也就是.xlsx文件)来维护。前端需要从一个文件中根据key 来 读取值(值可能对应中/英两种情况),怎么将多个.xlsx 文件,合并成一个前端可以根据key 来读取的文件,这就是今天我要写的内容

配置文件

做一个 lang-config.json ,里面做input / outout 的配置文件

  1. input 配置表名/工作博
  2. output 配置 中/英 的key / value

egg:

js 复制代码
{
  "input": [
    {
      "fileName": "project1.xlsx",
      "sheetNames": ["Sheet1"]
    },
    {
      "fileName": "project2.xlsx",
      "sheetNames": ["Sheet1"]
    },
    {
      "fileName": "error-code.xlsx",
      "sheetNames": ["Sheet1"]
    }
  ],
  "output": [
    { "key": "zh-CN", "value": "中文" },
    { "key": "en-US", "value": "英文" }
  ]
}

实现流程

  1. 读取配置文件,根据配置文件中的input,获取配置文件所有的fileName
js 复制代码
[ 'project1.xlsx', 'project2.xlsx', 'error-code.xlsx']
  1. 循环fileName,为之拼接相对应的文件路径,使用xlsx.utils.sheet_to_json,根据工作簿,做文件内容读取
  • 文件路径
js 复制代码
    /Users/Desktop/vue-project/tools/lang/project1.xlsx
    /Users/Desktop/vue-project/tools/lang/project2.xlsx
    /Users/Desktop/vue-project/tools/lang/error-code.xlsx
  • 文件内容读取

主要代码

js 复制代码
xlsx.utils.sheet_to_json(workbook.Sheets[sheetName])

输入产物: sheet_to_json的产物

js 复制代码
[
 {
    key: 'error_code_502',
    '含义': '服务器无响应,请稍后重试',
    '中文': '服务器无响应,请稍后重试',
    '英文': 'The server has no response, please try it later'
  },
  {
    key: 'error_code_503',
    '含义': '服务器未就绪,请稍后重试',
    '中文': '服务器未就绪,请稍后重试',
    '英文': 'The server is not ready, please try again later'
  }
 ]

现在已经根据配置文件(input配置),将所有的xlsx 读取完毕。接下来就是怎样将这些数据,输入到en-us.ts/zh-us.ts 文件中,那自然是根据output配置了

  1. 输出文件数据配置,需要哪些字段 ?
  • key(en-us/zh-us): (因为要用key,做输出文件路径的后缀
  • value(中文/英文): 来和sheet_to_json的产物 做匹配。如果是中文文件,匹配sheet_to_json里的中文,英文文件,匹配sheet_to_json里的英文文,
  • path: 输出的文件,要存放的位置
  • object: 输出文件的内容

输出产物: 根据output 文件输出的产物

js 复制代码
[
  {
    key: 'zh-CN',
    value: '中文',
    path: '/Users/Desktop/vue-project/src/generated/lang/zh-CN.ts',
    object: {}
  },
  {
    key: 'en-US',
    value: '英文',
    path: '/Users/Desktop/vue-project/src/generated/lang/en-US.ts',
    object: {}
  }
]
  1. 如何将输入产物,放到指定的输出产物里呢?
  • 输入产物和输出产物,都是两个数组对象,最粗暴的方式,就是对二者进行双重for 循环。 将输入产物的key 作为输出产物的key,根据输出产物的value 去和输入产物的中文/英文做匹配

主要代码

js 复制代码
jsonData.forEach((json)=>{
    result.forEach((item)=>{
        item.object[json['key']] =  json[item.value] // ⚠️⚠️⚠️⚠️
    })
})

产物

js 复制代码
[
  {
    key: 'zh-CN',
    value: '中文',
    path: '/Users/Desktop/vue-project/src/generated/lang/zh-CN.ts',
    object: {
      error_code_502: '服务器无响应,请稍后重试',
      error_code_502: '服务器未就绪,请稍后重试',
    },
  {
    key: 'en-US',
    value: '英文',
    path: '/Users/Desktop/vue-project/src/generated/lang/zh-CN.ts',
    object: {
      error_code_502: 'The server has no response, please try it later',
      error_code_503: 'The server is not ready, please try again later',
   },
]
  1. 如何将这个输出产物,导出为 en-US.ts / zh-US.ts 文件呢?

主要代码

js 复制代码
result.forEach((config) => {
    const { key, value, path, object } = config;
    //const content = `export default\n{ \n${toSingleQuotedValues(object)}};`;
     const content = `export default ${JSON.stringify(object, null, 2)};`;
    fs.writeFileSync(path, content);
  });

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

边界/细节处理

如何导出en-US.ts/zh-US.ts 文件格式怎么处理

我们要读取en-US.ts/zh-US.ts ,里面需要导出一个对象:export default {},对象里面是key:value。 说到底,.ts 也是一个文件,里面的文件内容,自己做拼接就好

可以使用 JSON.stringify

export default ${JSON.stringify(object, null, 2)};

也可以自己做一层数据格式转换

js 复制代码
`export default\n{ \n${toSingleQuotedValues(object)}};`

const entries = Object.entries(obj).map(([key, value]) => {
  const quotedValue = `'${value}'`;
  return `  ${key}: ${quotedValue}`;
});
return entries.join(',\n');
}

多语言如何传参数

动态传参,在多语言中是必不可少的。比如还有xx天过期。没必要还有 天过期分开做多语言,直接使用 还有${params}天过期 ,参数按照项目定义即可,比如我们用的是 %1$@代表参数

在赋值的时候,只需要将item.value 根据正则匹配,做一个替换即可

js 复制代码
jsonData.forEach((json)=>{
   let newValue = json[item.value] // +++
   newValue = newValue.replace( // +++
           /%(\d+)\$@/g,
           (match, index) => `{param${index}}`
         );
   result.forEach((item)=>{
       item.object[json['key']] =  json[newValue] // +++
   })
})

vue-i18n中 动态传值,采用{}即可

egg:

{ "welcome": "Welcome, {username}!" } 如果是多个变量呢,

{ "welcome": "Welcome, {username1} {username1} {username3}!" }

我们可以利用 replace的第个参数,对每一个特殊参数进行匹配替换,为保证参数唯一性,可以拼接 index

重复key 问题

在excel 文件中,由于多人协作,可能会出现重复key的情况,那就会出现覆盖,导致key 设置的value 不生效,我们在脚本中对这种情况也要做处理

js 复制代码
// 存储已处理的 key
const processedKeys = new Set();
// 在循环json 数据的时候,要一个判断,如果已经存在了key,则chalk抛异常
if (processedKeys.has(json['key'])) {
        handleError(
          chalk.red.bold(
            `文件 ${fileName} 的工作表 ${sheetName} 存在重复的 key: ${json['key']}`
          )
        );
      }
      // 否则就将key 添加到map 结构中
processedKeys.add(json['key']);

异常终中断

出现异常,终断process.exit(1); 当前进程 退出

js 复制代码
/**
 * 异常处理
 * @param errorMessage
 */
function handleError(errorMessage) {
  spinner.fail(chalk.red.bold(errorMessage));
  process.exit(1);
}

文件读取异常处理

js 复制代码
let directoryPath = path.dirname(outputPath)
/**
 * 辅助函数,确保输出目录存在,不存在则创建
 * @param directoryPath 路径
 */
function ensureDirectoryExists(directoryPath) {
  try {
    fs.mkdirSync(directoryPath, { recursive: true });
  } catch (error) {
    handleError(chalk.red.bold(`创建目录失败: ${directoryPath}: ${error}`));
  }
}

显示脚本进度条和任务状态

js 复制代码
import ora from 'ora';
const spinner = ora()
spinner.start();
spinner.text = 'language脚本生成中...';
// ora('language脚本生成中...').start()

给脚本增加彩色样式(成功/ 失败 )特殊提示

js 复制代码
import chalk from 'chalk';
import ora from 'ora';
const spinner = ora()

spinner.succeed(chalk.green.bold(`文件已保存:${path}`))
spinner.succeed(chalk.red(`文件已保存:${path}`))

相关三方插件

更多详细内容,可根据插件详细配置

项目地址

欢迎 Star ⭐️⭐️⭐️⭐️

gitee.com/Big_Cat-AK-...

相关推荐
崔庆才丨静觅8 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60619 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了9 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅9 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅9 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅10 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment10 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅10 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊10 小时前
jwt介绍
前端
爱敲代码的小鱼10 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax