@c-sheep/i18n-extract-cli
Version:
这是一款能够自动将代码里的中文转成i18n国际化标记的命令行工具。当然,你也可以用它实现将中文语言包自动翻译成其他语言。适用于vue2、vue3和react
365 lines (364 loc) • 14.8 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.startSetMergeJson = exports.mergeBothLanguageData = exports.getFullLocalJsonData = exports.handleLanguageNext = exports.getMergePmoLanguageExcel = void 0;
const node_xlsx_1 = __importDefault(require("node-xlsx"));
const getAbsolutePath_1 = require("../shared/getAbsolutePath");
const glob_1 = __importDefault(require("glob"));
const getLoseLangaugeXlsx_1 = require("../shared/getLoseLangaugeXlsx");
const excelUtil_1 = require("../shared/excelUtil");
const fs_1 = __importDefault(require("fs"));
const translateMoreLanguage_1 = require("../translate/translateMoreLanguage");
const flatObjectDeep_1 = require("../shared/flatObjectDeep");
const cloneDeep_1 = __importDefault(require("lodash/cloneDeep"));
const translateMoreLanguage_2 = require("../translate/translateMoreLanguage");
const comblie_1 = require("../shared/comblie");
const util_1 = require("../shared/util");
function getLocalExcelData(str) {
const xlsxData = node_xlsx_1.default.parse((0, getAbsolutePath_1.getAbsolutePath)(process.cwd(), str))[0]
.data;
return xlsxData;
}
// 把数据按照header取排序 保证所有的顺序是一致的
function handleMergeData(result, header) {
const [_, ...xlsxHeader] = result.shift();
const xlsxHeaderMap = {};
xlsxHeader.forEach((irem, index) => {
xlsxHeaderMap[irem] = index + 1;
});
return result.map((ditem) => {
// xlsxHeaderMap
const langRows = header.map((item) => {
const relIndex = xlsxHeaderMap[item];
if (relIndex) {
return ditem[relIndex];
}
return "";
// ditem[]
});
return [ditem[0], ...langRows];
});
// const newSortHeader = header.map((item, index) => )
// {zh-cn: 1, en:2, zh-tw: 3}
}
function getAllLanguageDataArr(str, header) {
const excelPath = glob_1.default.sync(`${str}/**/*.xlsx`, {
ignore: []
});
const allExcelResult = [["字典 Key", ...header]];
excelPath.forEach((linkPath, index) => {
const result = (0, getLoseLangaugeXlsx_1.getLocalXlsxData)(linkPath);
const newResult = handleMergeData(result, header);
allExcelResult.push(...newResult);
});
return allExcelResult;
}
function getPmoExcelData(str, defaultKey, locales) {
const header = [defaultKey || "zh-cn", ...locales];
const xlsxData = getAllLanguageDataArr(str, header);
const [_, ...data] = xlsxData;
return {
xlsxData,
header,
data
};
}
function getMergePmoLanguageExcel(header, data) {
const xlsxJsonData = {};
header.forEach((key, index) => {
xlsxJsonData[key] = (xlsxJsonData[key] || {});
data.forEach((row) => {
var _a, _b;
if (!row[0] || !row[1]) {
return;
}
const keyName = (_b = (_a = row[0]) === null || _a === void 0 ? void 0 : _a.toString()) === null || _b === void 0 ? void 0 : _b.replace(/\[|\]/g, "_");
xlsxJsonData[key][keyName] = row[index + 1];
});
});
return xlsxJsonData;
}
exports.getMergePmoLanguageExcel = getMergePmoLanguageExcel;
const handleLanguageNext = (obj) => {
for (const i in obj) {
if (typeof obj[i] === "string") {
obj[i] = obj[i].trim();
}
}
return obj;
};
exports.handleLanguageNext = handleLanguageNext;
function getFullLocalJsonData(localePath, dirs, regexp) {
var _a;
const mapData = {};
for (const language of dirs) {
if (mapData[language] && ((_a = Object.values(mapData[language])) === null || _a === void 0 ? void 0 : _a.length))
continue;
const result = (0, translateMoreLanguage_1.getBaseLanguageMap)(localePath, language, regexp);
const flatResult = (0, flatObjectDeep_1.flatObjectDeep)(result);
mapData[language] = (0, exports.handleLanguageNext)(flatResult);
}
return mapData;
}
exports.getFullLocalJsonData = getFullLocalJsonData;
function transferDataToMapBykey(data, keyIndex = 0) {
const map = {};
data.forEach((item) => {
map[item[keyIndex].replace(/\[|\]/g, "_")] = item;
});
return map;
}
function genreNewLocalData(headers, mapDataInfo, excelFileName, excelPath) {
const excelBuffer = (0, excelUtil_1.buildExcel)(headers, mapDataInfo, excelFileName);
const excelFilePath = (0, getAbsolutePath_1.getAbsolutePath)(process.cwd(), excelPath);
fs_1.default.writeFileSync(excelFilePath, excelBuffer, "utf8");
}
const mergeBothLanguageData = (base, compare = {}, lang) => {
const result = {};
for (const i in base) {
const baseValue = base[i];
const compareValue = compare[i];
if (typeof baseValue === "object") {
if (typeof compareValue === "object") {
result[i] = (0, exports.mergeBothLanguageData)(baseValue, compareValue, lang);
}
else {
result[i] = (0, exports.mergeBothLanguageData)(baseValue, compare, lang);
}
}
else {
result[i] = compareValue || baseValue;
}
}
return result;
};
exports.mergeBothLanguageData = mergeBothLanguageData;
function getKeyZhData(json, result = { zhToKey: {}, keyToZh: {} }) {
// console.log(json, 'json')
for (const i in json) {
const data = json[i];
if (typeof data === "object") {
getKeyZhData(data, result);
}
else {
result.zhToKey[data] = result.zhToKey[data] || [];
result.zhToKey[data].push(i);
result.keyToZh[i] = data;
}
}
return result;
}
function getLangDataByZhJson(json, keyZh = {}, result = {}) {
for (const i in json) {
const data = json[i];
if (typeof data === "object") {
getLangDataByZhJson(data, keyZh, result);
}
else {
// ;(keyZh as any).ddd()
result[i] = data;
}
}
return result;
}
function setSameZhDataJson(json, keyMap) {
json = (0, cloneDeep_1.default)(json);
const findKeyData = (key, lang) => {
const jsonData = json[lang];
const zh = keyMap.keyToZh[key] || "";
// console.log(zh, 'zh')
const result = [];
if (zh) {
const keys = keyMap.zhToKey[zh];
for (const i of keys) {
const val = jsonData[i];
result.push(val);
}
}
return result.find((i) => i) || "";
};
for (const lang in json) {
const jsonData = json[lang];
for (const key in jsonData) {
if (!jsonData[key]) {
jsonData[key] = findKeyData(key, lang);
}
}
}
return json;
}
function removeAutoTranslate(pmoJsonData, translateJsonPath, locales, moduleNameRegex) {
const jifanPath = (0, getAbsolutePath_1.getAbsolutePath)(process.cwd(), translateJsonPath);
const autoJson = getFullLocalJsonData(translateJsonPath, locales, moduleNameRegex || /./);
// console.log(autoJson, "autoJson");
const removeSameLangData = (langData, pmoLangData, lang, index = 0) => {
if (Object.keys(langData).length) {
const result = {};
// console.log(pmoLangData, "pmoLangData");
for (const jk in langData) {
const jkJson = langData[jk.toString().trim()];
const pmoJson = pmoLangData[jk.toString().trim()];
// console.log(jk.toString(), jkJson, pmoJson);
if (typeof jkJson === "object") {
const jkResult = removeSameLangData(jkJson, typeof pmoJson === "object" ? pmoJson : {}, lang, index + 1);
if (Object.keys(jkResult).length > 0) {
result[jk] = jkResult;
}
else if (index === 0) {
(0, util_1.deleteEmptyFileAndFolder)((0, getAbsolutePath_1.getAbsolutePath)(jifanPath, lang, jk + ".json"));
}
}
if (!pmoJson) {
result[jk] = jkJson;
}
}
return result;
}
return {};
};
const genreAutoFile = (json, translateJsonPath, lang) => {
const langPath = (0, getAbsolutePath_1.getAbsolutePath)(translateJsonPath, lang);
const deepJson = (0, flatObjectDeep_1.genreObjectDeep)(json);
// console.log(deepJson, langPath, "deepJson, langPath");
(0, translateMoreLanguage_2.setLanguageModuleSave)(deepJson, langPath, true);
};
for (const lang in autoJson) {
const langFullPath = (0, getAbsolutePath_1.getAbsolutePath)(jifanPath, lang);
const removeLangJson = removeSameLangData((0, flatObjectDeep_1.genreObjectDeep)(autoJson[lang] || {}), (0, flatObjectDeep_1.genreObjectDeep)(pmoJsonData[lang]), lang);
const removeLength = Object.keys(removeLangJson).length;
// console.log(removeLangJson, translateJsonPath, lang, "removeLangJson");
if (removeLength) {
genreAutoFile(removeLangJson, translateJsonPath, lang);
}
else if (!moduleNameRegex) {
(0, comblie_1.deleteFolderRecursive)(langFullPath);
}
}
}
// function getKeyToZh(localePath: string) {
// const zhDataDeep = getBaseLanguageMap(localePath, "zh-cn");
// const flatData = flatObjectDeep(zhDataDeep);
// return getKeyZhData(flatData);
// }
function startSetMergeJson(i18nConfig) {
// let pmoJsonMapData: { [k: string]: StringObject } = {};
const { locales, translateJsonPath, localePath, sortData, formatModuleName, defaultKey } = i18nConfig;
const baseLang = defaultKey || "zh-cn";
const moduleNameRegex = formatModuleName ? new RegExp(formatModuleName) : /./;
if (!i18nConfig.transferPath) {
console.error("请先设置 transferPath");
return;
}
const genreArrayDataByObj = (obj) => {
const headers = Object.keys(obj).filter((i) => i !== baseLang);
const newObj = (0, cloneDeep_1.default)(obj);
for (const lang in newObj) {
newObj[lang] = (0, flatObjectDeep_1.flatObjectDeep)(newObj[lang]);
}
const result = [];
const zhCnData = newObj[baseLang];
for (const i in zhCnData) {
const temp = [];
temp.push(i, zhCnData[i]);
for (const j of headers) {
const langData = newObj[j];
temp.push(langData[i]);
}
result.push((0, cloneDeep_1.default)(temp));
}
return { headers: [baseLang, ...headers], result };
};
const getMapIndex = (header, buffer = 1) => {
const map = {};
const mapIndexToStr = {};
header.forEach((item, index) => {
map[item] = index + buffer;
mapIndexToStr[index + buffer] = item;
});
return { map, mapIndexToStr };
};
const { header, data: pmoArrayJsonData } = getPmoExcelData(i18nConfig.transferPath, baseLang, locales);
// const fullLocales = [baseLang, ...locales];
// for (const i of fullLocales) {
// if (!header.includes(i)) {
// console.error(`${i} 列不存在`);
// }
// }
const { map: pmoIndexMap, mapIndexToStr } = getMapIndex(header);
const pmoJsonMapData = getMergePmoLanguageExcel(header, pmoArrayJsonData);
// console.log(pmoJsonMapData, 'pmoJsonMapData');
// const excelFilePath = getAbsolutePath(process.cwd(), localePath);
const projectJson = getFullLocalJsonData(localePath, [baseLang, ...locales]);
const { headers: projectHeaders, result: projectArrayJsonData } = genreArrayDataByObj(projectJson);
const resultDeepMap = {};
projectHeaders.forEach((lang) => {
resultDeepMap[lang] = {};
});
const resultZhMap = getZhPmoData(pmoArrayJsonData);
// console.log(pmoJsonMapData, 'pmoJsonMapData');
// const ddddd = getAbsolutePath(process.cwd(), 'resultZhMap.json');
// fs.writeFileSync(ddddd, JSON.stringify(resultZhMap), "utf8");
projectArrayJsonData.forEach((pData) => {
// 遍历所有的数据
projectHeaders.forEach((lang, index) => {
const data = setEmptyData(pData[index + 1], pData, lang, pmoJsonMapData[lang] || {}, resultZhMap, sortData);
if (data) {
resultDeepMap[lang][pData[0]] = data;
}
});
});
const langResult = {};
for (const lang in resultDeepMap) {
const resultFile = {};
const file = (0, flatObjectDeep_1.genreObjectDeep)(resultDeepMap[lang]);
if (langResult[lang] === null || typeof langResult[lang] !== "object") {
langResult[lang] = {};
}
for (const key in file) {
if (moduleNameRegex.test(key)) {
resultFile[key] = file[key];
langResult[lang][key] = file[key];
}
}
const langPath = (0, getAbsolutePath_1.getAbsolutePath)(localePath, lang);
(0, translateMoreLanguage_2.setLanguageModuleSave)(resultFile, langPath);
}
// console.log(langResult, 'langResult');
removeAutoTranslate(langResult, translateJsonPath, locales, formatModuleName ? moduleNameRegex : false);
function getZhPmoData(pmoArrayJson) {
// 获取pmo给的数据 按照中文当key
const _resultZhMap = {};
pmoArrayJson.forEach((item, index) => {
const key = pmoIndexMap[baseLang];
if (!_resultZhMap[item[key]]) {
_resultZhMap[item[key]] = [];
}
const next = _resultZhMap[item[key]];
const row = {};
item.forEach((ccitem, ccindex) => {
row[mapIndexToStr[ccindex] || "key"] = ccitem;
});
next.push(row);
});
return _resultZhMap;
}
function setEmptyData(localData, rowData, lang, pmoJsonData, pmoResultZhMap, sort = ["key", "local", "zh"]) {
// 设置数据 取pmo给的数据
const key = rowData[0];
const zhText = rowData[1];
const pmoKeyContent = pmoJsonData[key];
const findTextArr = pmoResultZhMap[zhText] || [];
const pmoZhDataMap = findTextArr.find((item) => item[lang]) || {
[lang]: ""
};
const mapData = {
key: pmoKeyContent,
local: localData,
zh: pmoZhDataMap[lang]
};
return sort.map((i) => mapData[i]).find((i) => i) || "";
}
}
exports.startSetMergeJson = startSetMergeJson;