td-web-cli 0.1.23 → 0.1.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/modules/i18n/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/modules/i18n/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAOpC;;;;GAIG;AACH,wBAAsB,IAAI,CAAC,OAAO,EAAE,OAAO,iBA6E1C"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { select, Separator } from '@inquirer/prompts';
|
|
2
2
|
import { logger, loggerError } from '../../utils/index.js';
|
|
3
3
|
import { excel2json } from './excel2json/index.js';
|
|
4
|
+
import { json2excel } from './json2excel/index.js';
|
|
4
5
|
import { jsonMerge } from './jsonMerge/index.js';
|
|
5
6
|
/**
|
|
6
7
|
* 国际化模块主入口
|
|
@@ -58,6 +59,11 @@ export async function i18n(program) {
|
|
|
58
59
|
await excel2json(program);
|
|
59
60
|
logger.info(`${selectedModule.name}功能执行完成`);
|
|
60
61
|
break;
|
|
62
|
+
case 'json2excel':
|
|
63
|
+
logger.info(`${selectedModule.name}功能开始执行`);
|
|
64
|
+
await json2excel(program);
|
|
65
|
+
logger.info(`${selectedModule.name}功能执行完成`);
|
|
66
|
+
break;
|
|
61
67
|
case 'jsonMerge':
|
|
62
68
|
logger.info(`${selectedModule.name}功能开始执行`);
|
|
63
69
|
await jsonMerge(program);
|
|
@@ -1,2 +1,7 @@
|
|
|
1
|
-
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
/**
|
|
3
|
+
* JSON 转 Excel 主函数
|
|
4
|
+
* 将多语言 JSON 文件合并为一个 Excel 文件,表头使用语言名称(从配置的 langs 中取第一个)
|
|
5
|
+
*/
|
|
6
|
+
export declare function json2excel(program: Command): Promise<void>;
|
|
2
7
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/modules/i18n/json2excel/index.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/modules/i18n/json2excel/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA+CpC;;;GAGG;AACH,wBAAsB,UAAU,CAAC,OAAO,EAAE,OAAO,iBAsIhD"}
|
|
@@ -1,3 +1,157 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import { input } from '@inquirer/prompts';
|
|
2
|
+
import XLSX from 'xlsx';
|
|
3
|
+
import fs from 'fs';
|
|
4
|
+
import { fileURLToPath } from 'url';
|
|
5
|
+
import path from 'path';
|
|
6
|
+
import { getTimestamp, logger, loggerError, normalizeError, normalizeGitBashPath, } from '../../../utils/index.js';
|
|
7
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
8
|
+
const __dirname = path.dirname(__filename);
|
|
9
|
+
/**
|
|
10
|
+
* 读取并解析配置文件(同 excel2json)
|
|
11
|
+
*/
|
|
12
|
+
function loadConfig(configPath) {
|
|
13
|
+
if (!fs.existsSync(configPath)) {
|
|
14
|
+
throw new Error(`配置文件不存在:${configPath}`);
|
|
15
|
+
}
|
|
16
|
+
const content = fs.readFileSync(configPath, { encoding: 'utf-8' });
|
|
17
|
+
const json = JSON.parse(content);
|
|
18
|
+
if (!json.i18n) {
|
|
19
|
+
throw new Error('配置文件格式错误,缺少i18n');
|
|
20
|
+
}
|
|
21
|
+
if (!json.i18n.defaultKey) {
|
|
22
|
+
throw new Error('配置文件格式错误,缺少i18n.defaultKey');
|
|
23
|
+
}
|
|
24
|
+
if (!json.i18n.langs) {
|
|
25
|
+
throw new Error('配置文件格式错误,缺少i18n.langs');
|
|
26
|
+
}
|
|
27
|
+
if (!json.i18n.longCodes) {
|
|
28
|
+
throw new Error('配置文件格式错误,缺少i18n.longCodes');
|
|
29
|
+
}
|
|
30
|
+
return json.i18n;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* JSON 转 Excel 主函数
|
|
34
|
+
* 将多语言 JSON 文件合并为一个 Excel 文件,表头使用语言名称(从配置的 langs 中取第一个)
|
|
35
|
+
*/
|
|
36
|
+
export async function json2excel(program) {
|
|
37
|
+
var _a;
|
|
38
|
+
// 配置文件默认路径
|
|
39
|
+
const configPath = path.join(__dirname, '../../../../setting.json');
|
|
40
|
+
let i18nConfig;
|
|
41
|
+
// 加载配置文件
|
|
42
|
+
try {
|
|
43
|
+
logger.info(`开始加载配置文件:${configPath}`, true);
|
|
44
|
+
i18nConfig = loadConfig(configPath);
|
|
45
|
+
logger.info('配置文件加载成功', true);
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
const msg = `读取配置文件失败:${normalizeError(error).stack},程序已退出`;
|
|
49
|
+
logger.error(msg);
|
|
50
|
+
console.error('程序执行时发生异常,已记录日志,程序已退出');
|
|
51
|
+
process.exit(1);
|
|
52
|
+
}
|
|
53
|
+
// 交互式输入 JSON 根目录
|
|
54
|
+
const answer = await input({
|
|
55
|
+
message: '请输入存放多语言 JSON 的根目录:',
|
|
56
|
+
validate: (value) => {
|
|
57
|
+
const cleaned = value.trim().replace(/^['"]|['"]$/g, '');
|
|
58
|
+
if (cleaned.length === 0) {
|
|
59
|
+
return '路径不能为空';
|
|
60
|
+
}
|
|
61
|
+
const normalizedPath = normalizeGitBashPath(cleaned);
|
|
62
|
+
if (!fs.existsSync(normalizedPath)) {
|
|
63
|
+
return '目录不存在,请输入有效路径';
|
|
64
|
+
}
|
|
65
|
+
if (!fs.statSync(normalizedPath).isDirectory()) {
|
|
66
|
+
return '请输入一个目录路径';
|
|
67
|
+
}
|
|
68
|
+
return true;
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
const rootDir = normalizeGitBashPath(answer);
|
|
72
|
+
try {
|
|
73
|
+
logger.info(`开始扫描目录:${rootDir}`, true);
|
|
74
|
+
// 获取根目录下所有子目录(作为语言 KEY)
|
|
75
|
+
const subDirs = fs.readdirSync(rootDir).filter((name) => {
|
|
76
|
+
const fullPath = path.join(rootDir, name);
|
|
77
|
+
return fs.statSync(fullPath).isDirectory();
|
|
78
|
+
});
|
|
79
|
+
// 加载每个语言的翻译
|
|
80
|
+
const translations = {};
|
|
81
|
+
const availableLangs = [];
|
|
82
|
+
for (const langKey of subDirs) {
|
|
83
|
+
const jsonPath = path.join(rootDir, langKey, 'translate.json');
|
|
84
|
+
if (!fs.existsSync(jsonPath)) {
|
|
85
|
+
logger.warn(`跳过 ${langKey},不存在 translate.json`, true);
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
try {
|
|
89
|
+
const content = fs.readFileSync(jsonPath, 'utf-8');
|
|
90
|
+
const data = JSON.parse(content);
|
|
91
|
+
translations[langKey] = data;
|
|
92
|
+
availableLangs.push(langKey);
|
|
93
|
+
logger.info(`已加载语言:${langKey},词条数量:${Object.keys(data).length}`, true);
|
|
94
|
+
}
|
|
95
|
+
catch (err) {
|
|
96
|
+
logger.error(`读取 ${langKey} 的 translate.json 失败:${normalizeError(err).message}`, true);
|
|
97
|
+
process.exit(1);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
if (availableLangs.length === 0) {
|
|
101
|
+
logger.error('未找到任何有效的 translate.json 文件,程序退出', true);
|
|
102
|
+
process.exit(1);
|
|
103
|
+
}
|
|
104
|
+
// 默认语言
|
|
105
|
+
const defaultLang = i18nConfig.defaultKey;
|
|
106
|
+
if (!availableLangs.includes(defaultLang)) {
|
|
107
|
+
logger.warn(`默认语言 ${defaultLang} 不存在于已加载的语言中,将使用所有语言的 KEY 并集作为基准`, true);
|
|
108
|
+
}
|
|
109
|
+
// 收集所有 KEY 的并集(作为 Excel 第一列)
|
|
110
|
+
const allKeysSet = new Set();
|
|
111
|
+
for (const lang of availableLangs) {
|
|
112
|
+
Object.keys(translations[lang]).forEach((key) => allKeysSet.add(key));
|
|
113
|
+
}
|
|
114
|
+
const sortedKeys = Array.from(allKeysSet).sort();
|
|
115
|
+
logger.info(`共收集到 ${sortedKeys.length} 个唯一 KEY`, true);
|
|
116
|
+
// 构建表头:第一列使用默认语言的名称(从配置中获取),后面列使用其他语言的名称
|
|
117
|
+
const header = [];
|
|
118
|
+
// 第一列名称:优先使用默认语言的第一个名称,否则用 defaultKey
|
|
119
|
+
const defaultLangNames = i18nConfig.langs[defaultLang];
|
|
120
|
+
const firstColName = (defaultLangNames && defaultLangNames.length > 0)
|
|
121
|
+
? defaultLangNames[0]
|
|
122
|
+
: defaultLang;
|
|
123
|
+
header.push(firstColName);
|
|
124
|
+
const nonDefaultLangs = availableLangs.filter((lang) => lang !== defaultLang);
|
|
125
|
+
for (const lang of nonDefaultLangs) {
|
|
126
|
+
const names = i18nConfig.langs[lang];
|
|
127
|
+
const colName = (names && names.length > 0) ? names[0] : lang;
|
|
128
|
+
header.push(colName);
|
|
129
|
+
}
|
|
130
|
+
// 构建 Excel 数据行
|
|
131
|
+
const rows = [header];
|
|
132
|
+
for (const key of sortedKeys) {
|
|
133
|
+
const row = [key]; // 第一列是 KEY
|
|
134
|
+
for (const lang of nonDefaultLangs) {
|
|
135
|
+
const val = (_a = translations[lang]) === null || _a === void 0 ? void 0 : _a[key];
|
|
136
|
+
row.push(val !== undefined ? val : null); // 无翻译时留空
|
|
137
|
+
}
|
|
138
|
+
rows.push(row);
|
|
139
|
+
}
|
|
140
|
+
// 生成 Excel 文件
|
|
141
|
+
const timestamp = getTimestamp();
|
|
142
|
+
const outputFileName = `lang_merged_${timestamp}.xlsx`;
|
|
143
|
+
const outputPath = path.join(rootDir, outputFileName);
|
|
144
|
+
const wb = XLSX.utils.book_new();
|
|
145
|
+
const ws = XLSX.utils.aoa_to_sheet(rows);
|
|
146
|
+
XLSX.utils.book_append_sheet(wb, ws, 'Translations');
|
|
147
|
+
XLSX.writeFile(wb, outputPath);
|
|
148
|
+
logger.info(`Excel 文件已生成:${outputPath}`, true);
|
|
149
|
+
logger.info(`共处理语言:${availableLangs.join(', ')}`, true);
|
|
150
|
+
logger.info('转换完成', true);
|
|
151
|
+
}
|
|
152
|
+
catch (error) {
|
|
153
|
+
loggerError(error, logger);
|
|
154
|
+
console.error('程序执行时发生异常,已记录日志,程序已退出');
|
|
155
|
+
process.exit(1);
|
|
156
|
+
}
|
|
3
157
|
}
|