将 i18n 的 json 文件转换成 excel

TIP

在开发前端 Vue 项目时,我们经常会使用 vue-i18n 这个库来实现多国语言的功能,其中会使用 json 或 js 来存储语言项的信息。但是如果里面的内容是由翻译公司给出的,那由开发人员手动一条条录入是不太现实的,所以需要一个脚本能够实现导出成 excel 和导入成 json 的功能。

用 json 存储语言的原因

原本项目内存储多语言也是用 JS 文件分模块地一个一个存储的,但是在使用的时候需要在 index 文件里将所有的语言文件都引入,然后再分别取出里面zhen、…… 的语言配置项并把它们放到 VueI18n 库的 messages里。

就想这样下面的代码这样。

const i18n = new VueI18n({
  locale: "zh",
  messages: {
    zh: { ...A.zh, ...B.zh, ...C.zh },
    en: { ...A.en, ...B.en, ...C.en },
    jp: { ...A.jp, ...B.jp, ...C.jp },
  },
});

这样的存储方式确实会很清晰,但是每次新增一个语言项时都要写更多的代码,而且难免会有文件太多了,导致写了相同的变量名造成被覆盖的情况。
我是因为为了脚本简单些,所以将所有的语言项都用一个 json 文件来存储,这样在 json 内就能排除掉相同变量名的情况,而且脚本也不用考虑遍历文件夹的情况了。

json 文件的内容。

{
  "zh": {
    "common": {
      "close": "关闭"
    }
  },
  "en": {
    "common": {
      "close": "close"
    }
  }
}

jsonToExcel

将代码里使用的语言内容转换成 Excel 文件,然后给到翻译公司去做翻译。

是基于 nodejs 运行的脚本,需要使用到exceljS这个第三方库。

// Lib
const ExcelJS = require("exceljs");
// Lang json
const common = require("./i18n.json");

// Formatting lang variables
function formatter(val, pathArray) {
  for (let key in val) {
    // Check each property
    if (Object.prototype.toString.call(val[key]) === "[object Object]") {
      // Object need to handle again
      formatter(val[key], pathArray.concat([key]));
    } else {
      // Find other lang variables by the same path
      let tempEn = lang["en"];
      for (let i = 0; i < pathArray.length; i += 1) {
        tempEn = tempEn[pathArray[i]];
      }

      formattedLangArray.push({
        fullPath: pathArray.join("."),
        refName: key,
        zh: val[key],
        en: tempEn[key],
      });
    }
  }
}

formatter(lang["zh"], []);

// Create Excel
const workbook = new ExcelJS.Workbook();
workbook.creator = "cclc";
workbook.views = [
  {
    x: 0,
    y: 0,
    width: 10000,
    height: 20000,
    firstSheet: 0,
    activeTab: 1,
    visibility: "visible",
  },
];

const sheet = workbook.addWorksheet("I18n");
// Add column headers and define column keys and widths
sheet.columns = [
  { header: "CodePath", key: "fullPath", width: 15 },
  { header: "RefName", key: "refName", width: 15 },
  { header: "Chinese", key: "zh", width: 15 },
  { header: "English", key: "en", width: 15 },
];

// Add an array of rows
sheet.addRows(formattedLangArray);

const filePath = "./i18n.xlsx";
workbook.xlsx.writeFile(filePath);

console.log("finish");

Excel 文件内容
1

excelToJson

从翻译公司获得译文后,从 Excel 文件转成 json 文件供代码使用。

// Lib
const ExcelJS = require("exceljs");
const fs = require("fs");

const excelPath = "./i18n.xlsx";

const jsonPath = "./i18n.json";
const workbook = new ExcelJS.Workbook();
const langKinds = ["zh", "en"];
let langJson = {
  zh: {},
  en: {},
};

async function main() {
  const localWorkbook = await workbook.xlsx.readFile(excelPath);
  const worksheet = localWorkbook.getWorksheet("I18n");
  const rows = worksheet.getRows(1, worksheet.actualRowCount);

  // convert excel to json
  for (let i = 1; i < rows.length; i += 1) {
    generateLangJson(rows[i].values);
  }

  // generate json file
  generateJsonFile();
  console.log("finish");
}

function generateLangJson(rowsValue) {
  // rowsValue = […, 'common', 'feedback', '意见反馈', 'Feedback']
  // Index start at 1
  const path = rowsValue[1];
  const keyName = rowsValue[2];

  for (let i = 0; i < langKinds.length; i += 1) {
    let tempObj = langJson[langKinds[i]];
    if (path.indexOf(".") > -1) {
      // Multilayer
      const pathList = path.split(".");
      for (let j = 0; j < pathList.length; j += 1) {
        if (!tempObj.hasOwnProperty(pathList[j])) {
          // Add property
          tempObj[pathList[j]] = {};
        }
        // Enter
        tempObj = tempObj[pathList[j]];
      }
      // Add new property at current layer
      tempObj[keyName] = rowsValue[i + 3];
    } else {
      if (!tempObj.hasOwnProperty(path)) {
        // Add property at root layer
        tempObj[path] = {};
      }
      tempObj[path][keyName] = rowsValue[i + 3];
    }
  }
}

function generateJsonFile() {
  if (fs.existsSync(jsonPath)) {
    // Exist
    // Delete file
    fs.unlinkSync(jsonPath);
  }
  fs.writeFileSync(jsonPath, JSON.stringify(langJson));
}

main();