UNPKG

t-comm

Version:

专业、稳定、纯粹的工具库

195 lines (192 loc) 6.79 kB
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 };