将 i18n 的 json 文件转换成 excel
TIP
在开发前端 Vue 项目时,我们经常会使用 vue-i18n 这个库来实现多国语言的功能,其中会使用 json 或 js 来存储语言项的信息。但是如果里面的内容是由翻译公司给出的,那由开发人员手动一条条录入是不太现实的,所以需要一个脚本能够实现导出成 excel 和导入成 json 的功能。
用 json 存储语言的原因
原本项目内存储多语言也是用 JS 文件分模块地一个一个存储的,但是在使用的时候需要在 index 文件里将所有的语言文件都引入,然后再分别取出里面zh
、en
、…… 的语言配置项并把它们放到 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 文件内容
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();