t-comm
Version:
专业、稳定、纯粹的工具库
195 lines (192 loc) • 6.79 kB
JavaScript
import _slicedToArray from '@babel/runtime/helpers/slicedToArray';
import _toConsumableArray from '@babel/runtime/helpers/toConsumableArray';
import { getPath } from '../nodejs/path.mjs';
import { jsonToExcel } from '../sheet/sheet.mjs';
import { getXlsx } from '../third-party/xlsx.mjs';
import { LANG_NAME_TO_TI18N_KEY, TI18N_KEYS } from './config.mjs';
export { LANG_NAME_TO_TI18N_KEY, TI18N_KEYS } from './config.mjs';
import '../nodejs/fs.mjs';
/**
* 将语言名称映射为 ti18n key
* @param name Excel 首行的语言名称
* @param langNameMapping 语言名称到 ti18n key 的映射表,默认使用 LANG_NAME_TO_TI18N_KEY
* @returns 对应的 ti18n key,无法识别返回 null
* @example
* ```ts
* mapLangNameToKey('中文'); // 'zh'
* mapLangNameToKey('English'); // 'en'
* mapLangNameToKey('未知'); // null
*
* // 自定义映射
* mapLangNameToKey('日语', { '日语': 'ja' }); // 'ja'
* ```
*/
function mapLangNameToKey(name) {
var langNameMapping = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : LANG_NAME_TO_TI18N_KEY;
if (!name || typeof name !== 'string') return null;
var normalized = name.trim().toLowerCase();
return langNameMapping[normalized] || null;
}
/**
* 读取 Excel,替换首行 key 为 ti18n 标准 key,输出新 Excel
* @param inputPath 输入 Excel 路径
* @param outputPath 输出 Excel 路径
* @param options 转换配置选项
* @returns 转换结果,包含 jsonData 和 activeKeys
* @example
* ```ts
* // 使用默认配置
* convertExcelToTi18n('./input.xlsx', './output.xlsx');
*
* // 自定义支持的语言列表
* convertExcelToTi18n('./input.xlsx', './output.xlsx', {
* ti18nKeys: ['zh', 'en', 'ja', 'ko'], // 只支持中英日韩
* });
*
* // 自定义语言名称映射
* convertExcelToTi18n('./input.xlsx', './output.xlsx', {
* langNameMapping: {
* ...DEFAULT_LANG_NAME_TO_TI18N_KEY,
* '日语': 'ja',
* 'japanese': 'ja',
* '韩语': 'ko',
* 'korean': 'ko',
* },
* });
*
* // 完全自定义配置
* convertExcelToTi18n('./input.xlsx', './output.xlsx', {
* ti18nKeys: ['zh', 'en', 'ja'],
* langNameMapping: {
* 'zh': 'zh',
* 'en': 'en',
* 'ja': 'ja',
* '中文': 'zh',
* '英文': 'en',
* '日文': 'ja',
* },
* });
* ```
*/
function convertExcelToTi18n(inputPath, outputPath) {
var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
var _options$ti18nKeys = options.ti18nKeys,
ti18nKeys = _options$ti18nKeys === void 0 ? TI18N_KEYS : _options$ti18nKeys,
_options$langNameMapp = options.langNameMapping,
langNameMapping = _options$langNameMapp === void 0 ? LANG_NAME_TO_TI18N_KEY : _options$langNameMapp;
var wb = getXlsx().readFile(inputPath);
var ws = wb.Sheets[wb.SheetNames[0]];
var ref = ws['!ref'];
if (!ref) {
throw new Error('Excel 文件为空');
}
var range = getXlsx().utils.decode_range(ref);
var totalCols = range.e.c + 1;
var totalRows = range.e.r + 1;
console.log("[INFO] \u6587\u4EF6: ".concat(getPath().basename(inputPath)));
console.log("[INFO] \u603B\u884C\u6570: ".concat(totalRows, ", \u603B\u5217\u6570: ").concat(totalCols));
// 1. 读取首行,建立列号 → ti18n key 的映射
var colMapping = {};
var unmappedCols = [];
for (var c = 0; c <= range.e.c; c++) {
var cell = ws[getXlsx().utils.encode_cell({
r: 0,
c: c
})];
var headerName = cell ? String(cell.v) : null;
var ti18nKey = mapLangNameToKey(headerName, langNameMapping);
if (ti18nKey) {
// 避免重复映射(如合并单元格导致重复)
if (!Object.values(colMapping).includes(ti18nKey)) {
colMapping[c] = ti18nKey;
console.log("[MAP] \u5217 ".concat(c, " \"").concat(headerName, "\" \u2192 \"").concat(ti18nKey, "\""));
} else {
console.log("[SKIP] \u5217 ".concat(c, " \"").concat(headerName, "\" \u2192 \"").concat(ti18nKey, "\" (\u5DF2\u5B58\u5728\uFF0C\u8DF3\u8FC7)"));
}
} else {
unmappedCols.push({
col: c,
name: headerName
});
}
}
if (unmappedCols.length > 0) {
console.log('[INFO] 以下列未被映射(将被忽略):');
unmappedCols.forEach(function (_ref) {
var col = _ref.col,
name = _ref.name;
console.log(" \u5217 ".concat(col, ": ").concat(name || '(空)'));
});
}
// 2. 按照 ti18n key 的顺序,提取数据
// 首先确保 zh 在最前面,然后按 ti18nKeys 顺序排列
var orderedKeys = ['zh'].concat(_toConsumableArray(ti18nKeys.filter(function (k) {
return k !== 'zh';
})));
var activeKeys = orderedKeys.filter(function (key) {
return Object.values(colMapping).includes(key);
});
console.log("\n[INFO] \u6700\u7EC8\u8F93\u51FA\u7684 ti18n key \u5217: ".concat(activeKeys.join(', ')));
// 建立 ti18nKey → colIndex 的反向映射
var keyToCol = {};
Object.entries(colMapping).forEach(function (_ref2) {
var _ref3 = _slicedToArray(_ref2, 2),
col = _ref3[0],
key = _ref3[1];
keyToCol[key] = Number(col);
});
// 3. 读取数据行(跳过首行标题)
var jsonData = [];
var _loop = function _loop(r) {
var row = {};
var hasData = false;
activeKeys.forEach(function (key) {
var c = keyToCol[key];
var cell = ws[getXlsx().utils.encode_cell({
r: r,
c: c
})];
var value = cell ? String(cell.v) : '';
row[key] = value;
if (value) hasData = true;
});
// 只保留有数据的行
if (hasData) {
jsonData.push(row);
}
};
for (var r = 1; r <= range.e.r; r++) {
_loop(r);
}
console.log("[INFO] \u6709\u6548\u6570\u636E\u884C\u6570: ".concat(jsonData.length));
// 4. 输出新 Excel
jsonToExcel({
jsonData: jsonData,
outputPath: outputPath,
options: {
header: activeKeys
}
});
console.log("\n[SUCCESS] \u5DF2\u8F93\u51FA\u5230: ".concat(outputPath));
return {
jsonData: jsonData,
activeKeys: activeKeys
};
}
// // 作为命令行工具使用
// const isMain = process.argv[1] && (
// process.argv[1].endsWith('convert-excel-to-ti18n.ts')
// || process.argv[1].endsWith('convert-excel-to-ti18n.js')
// );
// if (isMain) {
// const inputPath = process.argv[2];
// if (!inputPath) {
// console.error('用法: npx ts-node convert-excel-to-ti18n.ts <输入的xlsx文件路径> [输出的xlsx文件路径]');
// process.exit(1);
// }
// const resolvedInput = getPath().resolve(inputPath);
// const outputPath = process.argv[3]
// || getPath().resolve(__dirname, `./log/ti18n_${Date.now()}.xlsx`);
// convertExcelToTi18n(resolvedInput, outputPath);
// }
export { convertExcelToTi18n, mapLangNameToKey };