td-web-cli 0.1.21 → 0.1.23
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.
- package/dist/modules/i18n/excel2json/index.d.ts.map +1 -1
- package/dist/modules/i18n/excel2json/index.js +22 -23
- package/dist/modules/i18n/index.d.ts.map +1 -1
- package/dist/modules/i18n/index.js +6 -0
- package/dist/modules/i18n/jsonMerge/config.d.ts +20 -0
- package/dist/modules/i18n/jsonMerge/config.d.ts.map +1 -0
- package/dist/modules/i18n/jsonMerge/config.js +40 -0
- package/dist/modules/i18n/jsonMerge/index.d.ts +6 -1
- package/dist/modules/i18n/jsonMerge/index.d.ts.map +1 -1
- package/dist/modules/i18n/jsonMerge/index.js +195 -2
- package/dist/modules/tools/getHolidayTime/index.js +2 -2
- package/dist/utils/index.d.ts +12 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +27 -0
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/modules/i18n/excel2json/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/modules/i18n/excel2json/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAiLpC;;;;;;GAMG;AACH,wBAAsB,UAAU,CAAC,OAAO,EAAE,OAAO,iBAqWhD"}
|
|
@@ -3,7 +3,7 @@ import XLSX from 'xlsx';
|
|
|
3
3
|
import fs from 'fs';
|
|
4
4
|
import { fileURLToPath } from 'url';
|
|
5
5
|
import path from 'path';
|
|
6
|
-
import { getTimestamp, logger, loggerError, normalizeError, languageToolCheck, getLanguageTool, formatKey, } from '../../../utils/index.js';
|
|
6
|
+
import { getTimestamp, logger, loggerError, normalizeError, languageToolCheck, getLanguageTool, formatKey, normalizeGitBashPath, trimQuotes, } from '../../../utils/index.js';
|
|
7
7
|
// 获取当前文件目录
|
|
8
8
|
const __filename = fileURLToPath(import.meta.url);
|
|
9
9
|
const __dirname = path.dirname(__filename);
|
|
@@ -41,8 +41,9 @@ function loadConfig(configPath) {
|
|
|
41
41
|
* @returns 匹配到的语言KEY,未匹配返回null
|
|
42
42
|
*/
|
|
43
43
|
function matchLangKey(colName, langs) {
|
|
44
|
-
if (!colName)
|
|
44
|
+
if (!colName) {
|
|
45
45
|
return null;
|
|
46
|
+
}
|
|
46
47
|
const colNameLower = colName.toLowerCase();
|
|
47
48
|
// 先尝试匹配语言KEY
|
|
48
49
|
for (const langKey of Object.keys(langs)) {
|
|
@@ -58,18 +59,6 @@ function matchLangKey(colName, langs) {
|
|
|
58
59
|
}
|
|
59
60
|
return null;
|
|
60
61
|
}
|
|
61
|
-
/**
|
|
62
|
-
* 去除字符串首尾的单引号或双引号
|
|
63
|
-
* @param str 输入字符串
|
|
64
|
-
* @returns 去除引号后的字符串
|
|
65
|
-
*/
|
|
66
|
-
function trimQuotes(str) {
|
|
67
|
-
if ((str.startsWith('"') && str.endsWith('"')) ||
|
|
68
|
-
(str.startsWith("'") && str.endsWith("'"))) {
|
|
69
|
-
return str.slice(1, -1);
|
|
70
|
-
}
|
|
71
|
-
return str;
|
|
72
|
-
}
|
|
73
62
|
/**
|
|
74
63
|
* 批量检测词条文本,返回所有检测结果
|
|
75
64
|
* @param texts 词条数组
|
|
@@ -118,8 +107,9 @@ function parseCheckResultPerEntry(checkResult, texts) {
|
|
|
118
107
|
const errorOffset = match.offset;
|
|
119
108
|
// 找出错误所在的词条索引
|
|
120
109
|
const idx = positions.findIndex((range) => errorOffset >= range.start && errorOffset < range.end);
|
|
121
|
-
if (idx === -1)
|
|
110
|
+
if (idx === -1) {
|
|
122
111
|
continue;
|
|
112
|
+
}
|
|
123
113
|
// 生成错误信息字符串
|
|
124
114
|
const errMsg = `错误: ${match.message}\n出错句子: ${match.sentence}\n建议替换: ${match.replacements
|
|
125
115
|
.map((r) => r.value)
|
|
@@ -193,17 +183,22 @@ export async function excel2json(program) {
|
|
|
193
183
|
message: '请输入Excel文件路径:',
|
|
194
184
|
validate: (value) => {
|
|
195
185
|
const cleaned = value.trim().replace(/^['"]|['"]$/g, '');
|
|
196
|
-
if (cleaned.length === 0)
|
|
186
|
+
if (cleaned.length === 0) {
|
|
197
187
|
return '路径不能为空';
|
|
198
|
-
|
|
188
|
+
}
|
|
189
|
+
// 这里调用路径转换确保校验时路径正确
|
|
190
|
+
const normalizedPath = normalizeGitBashPath(cleaned);
|
|
191
|
+
if (!fs.existsSync(normalizedPath)) {
|
|
199
192
|
return '文件不存在,请输入有效路径';
|
|
200
|
-
|
|
193
|
+
}
|
|
194
|
+
if (!/\.(xls|xlsx)$/i.test(normalizedPath)) {
|
|
201
195
|
return '请输入有效的Excel文件路径(.xls或.xlsx)';
|
|
196
|
+
}
|
|
202
197
|
return true;
|
|
203
198
|
},
|
|
204
199
|
});
|
|
205
200
|
// 规范化路径,支持相对路径转绝对路径,去除首尾引号
|
|
206
|
-
const excelPath =
|
|
201
|
+
const excelPath = normalizeGitBashPath(answer);
|
|
207
202
|
try {
|
|
208
203
|
logger.info(`开始读取Excel文件:${excelPath}`, true);
|
|
209
204
|
// 读取Excel文件
|
|
@@ -263,13 +258,15 @@ export async function excel2json(program) {
|
|
|
263
258
|
for (let i = 1; i < rows.length; i++) {
|
|
264
259
|
const row = rows[i];
|
|
265
260
|
let keyCell = row[defaultColNum];
|
|
266
|
-
if (keyCell === undefined || keyCell === null || keyCell === '')
|
|
261
|
+
if (keyCell === undefined || keyCell === null || keyCell === '') {
|
|
267
262
|
continue;
|
|
263
|
+
}
|
|
268
264
|
let key = String(keyCell).trim();
|
|
269
265
|
key = trimQuotes(key); // 去除引号
|
|
270
266
|
// 跳过空KEY,避免写入无效数据
|
|
271
|
-
if (key.length === 0)
|
|
267
|
+
if (key.length === 0) {
|
|
272
268
|
continue;
|
|
269
|
+
}
|
|
273
270
|
// 判断默认语言KEY是否重复,若重复则重新编码
|
|
274
271
|
if (langKeySets[defaultLang].has(key)) {
|
|
275
272
|
key = formatKey(key);
|
|
@@ -281,8 +278,9 @@ export async function excel2json(program) {
|
|
|
281
278
|
// 其他语言词条
|
|
282
279
|
for (const [colIdxStr, langKey] of Object.entries(colIndexToLangKey)) {
|
|
283
280
|
const colIdx = Number(colIdxStr);
|
|
284
|
-
if (langKey === defaultLang)
|
|
281
|
+
if (langKey === defaultLang) {
|
|
285
282
|
continue;
|
|
283
|
+
}
|
|
286
284
|
const valCell = row[colIdx];
|
|
287
285
|
if (valCell !== undefined && valCell !== null && valCell !== '') {
|
|
288
286
|
const valStr = String(valCell);
|
|
@@ -353,8 +351,9 @@ export async function excel2json(program) {
|
|
|
353
351
|
logger.info(`开始生成语言文件,输出目录:${outputRoot}`, true);
|
|
354
352
|
// 按语言生成对应的JSON文件,默认语言的KEY=VALUE不生成文件
|
|
355
353
|
for (const [langKey, translations] of Object.entries(langTranslations)) {
|
|
356
|
-
if (Object.keys(translations).length === 0)
|
|
354
|
+
if (Object.keys(translations).length === 0) {
|
|
357
355
|
continue;
|
|
356
|
+
}
|
|
358
357
|
if (langKey === defaultLang) {
|
|
359
358
|
logger.info(`跳过默认语言(${langKey})的JSON文件生成`, true);
|
|
360
359
|
continue; // 跳过默认语言文件生成
|
|
@@ -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;AAMpC;;;;GAIG;AACH,wBAAsB,IAAI,CAAC,OAAO,EAAE,OAAO,iBAwE1C"}
|
|
@@ -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 { jsonMerge } from './jsonMerge/index.js';
|
|
4
5
|
/**
|
|
5
6
|
* 国际化模块主入口
|
|
6
7
|
* 提供多个国际化相关功能的交互式选择
|
|
@@ -57,6 +58,11 @@ export async function i18n(program) {
|
|
|
57
58
|
await excel2json(program);
|
|
58
59
|
logger.info(`${selectedModule.name}功能执行完成`);
|
|
59
60
|
break;
|
|
61
|
+
case 'jsonMerge':
|
|
62
|
+
logger.info(`${selectedModule.name}功能开始执行`);
|
|
63
|
+
await jsonMerge(program);
|
|
64
|
+
logger.info(`${selectedModule.name}功能执行完成`);
|
|
65
|
+
break;
|
|
60
66
|
default:
|
|
61
67
|
logger.warn(`${selectedModule.name}功能暂未实现,程序已退出`);
|
|
62
68
|
process.exit(0);
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 进度显示管理器
|
|
3
|
+
* 用于在同一行显示进度,避免被其他日志干扰
|
|
4
|
+
*/
|
|
5
|
+
export declare class ProgressDisplay {
|
|
6
|
+
private isActive;
|
|
7
|
+
/**
|
|
8
|
+
* 更新进度显示
|
|
9
|
+
*/
|
|
10
|
+
update(progressBar: string, current: number, total: number, key: string): void;
|
|
11
|
+
/**
|
|
12
|
+
* 完成进度显示
|
|
13
|
+
*/
|
|
14
|
+
complete(progressBar: string): void;
|
|
15
|
+
/**
|
|
16
|
+
* 强制清除当前行
|
|
17
|
+
*/
|
|
18
|
+
clearLine(): void;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../../src/modules/i18n/jsonMerge/config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,qBAAa,eAAe;IACxB,OAAO,CAAC,QAAQ,CAAkB;IAElC;;OAEG;IACH,MAAM,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM;IAWvE;;OAEG;IACH,QAAQ,CAAC,WAAW,EAAE,MAAM;IAW5B;;OAEG;IACH,SAAS;CAMV"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 进度显示管理器
|
|
3
|
+
* 用于在同一行显示进度,避免被其他日志干扰
|
|
4
|
+
*/
|
|
5
|
+
export class ProgressDisplay {
|
|
6
|
+
constructor() {
|
|
7
|
+
this.isActive = false;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* 更新进度显示
|
|
11
|
+
*/
|
|
12
|
+
update(progressBar, current, total, key) {
|
|
13
|
+
const message = ` ${progressBar} 正在处理: ${key}`;
|
|
14
|
+
if (this.isActive) {
|
|
15
|
+
process.stdout.write('\x1b[2K\r'); // 清除整行,回到行首
|
|
16
|
+
}
|
|
17
|
+
process.stdout.write(message);
|
|
18
|
+
this.isActive = true;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* 完成进度显示
|
|
22
|
+
*/
|
|
23
|
+
complete(progressBar) {
|
|
24
|
+
const message = ` ${progressBar} 处理完成`;
|
|
25
|
+
if (this.isActive) {
|
|
26
|
+
process.stdout.write('\x1b[2K\r');
|
|
27
|
+
}
|
|
28
|
+
console.log(message); // 换行显示完成信息
|
|
29
|
+
this.isActive = false;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* 强制清除当前行
|
|
33
|
+
*/
|
|
34
|
+
clearLine() {
|
|
35
|
+
if (this.isActive) {
|
|
36
|
+
process.stdout.write('\x1b[2K\r');
|
|
37
|
+
this.isActive = false;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -1,2 +1,7 @@
|
|
|
1
|
-
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
/**
|
|
3
|
+
* 主函数:合并两个目录下相同语言文件夹的JSON文件
|
|
4
|
+
* @param program commander命令行实例(暂未使用,可扩展)
|
|
5
|
+
*/
|
|
6
|
+
export declare function jsonMerge(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/jsonMerge/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/modules/i18n/jsonMerge/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAuGpC;;;GAGG;AACH,wBAAsB,SAAS,CAAC,OAAO,EAAE,OAAO,iBA4J/C"}
|
|
@@ -1,3 +1,196 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { input, select, Separator } from '@inquirer/prompts';
|
|
4
|
+
import { logger, loggerError, normalizeError, normalizeGitBashPath, } from '../../../utils/index.js';
|
|
5
|
+
/**
|
|
6
|
+
* 读取JSON文件内容,返回对象,文件不存在返回空对象
|
|
7
|
+
* @param filePath JSON文件路径
|
|
8
|
+
* @returns 解析后的对象,出错或不存在返回空对象
|
|
9
|
+
*/
|
|
10
|
+
function readJsonFile(filePath) {
|
|
11
|
+
if (!fs.existsSync(filePath)) {
|
|
12
|
+
return {};
|
|
13
|
+
}
|
|
14
|
+
try {
|
|
15
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
16
|
+
return JSON.parse(content);
|
|
17
|
+
}
|
|
18
|
+
catch (error) {
|
|
19
|
+
logger.error(`读取JSON文件失败: ${filePath},错误: ${normalizeError(error).message}`);
|
|
20
|
+
return {};
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* 写入JSON文件,格式化缩进2格
|
|
25
|
+
* @param filePath 写入文件路径
|
|
26
|
+
* @param data 写入的对象数据
|
|
27
|
+
*/
|
|
28
|
+
function writeJsonFile(filePath, data) {
|
|
29
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
30
|
+
fs.writeFileSync(filePath, JSON.stringify(data, null, 2), 'utf-8');
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* 合并两个JSON对象,检测重复key,重复时通过交互让用户选择保留哪个值
|
|
34
|
+
* @param baseObj 源JSON对象(被合并到此对象)
|
|
35
|
+
* @param mergeObj 待合并JSON对象
|
|
36
|
+
* @param langKey 当前语言标识,用于日志提示
|
|
37
|
+
* @returns 合并后的JSON对象
|
|
38
|
+
*/
|
|
39
|
+
async function mergeJsonObjects(baseObj, mergeObj, langKey) {
|
|
40
|
+
const entries = Object.entries(mergeObj);
|
|
41
|
+
for (const [key, val] of entries) {
|
|
42
|
+
if (key in baseObj) {
|
|
43
|
+
if (baseObj[key] === val) {
|
|
44
|
+
// 值相同,无需处理,继续下一个键
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
// 值不同,需要用户交互选择保留哪个值
|
|
48
|
+
logger.info(`发现冲突: 键【${key}】`, true);
|
|
49
|
+
const choice = await select({
|
|
50
|
+
message: `请选择要保留的值:`,
|
|
51
|
+
choices: [
|
|
52
|
+
{ name: `源文件值: ${baseObj[key]}`, value: 'base' },
|
|
53
|
+
{ name: `合并文件值: ${val}`, value: 'merge' },
|
|
54
|
+
new Separator(),
|
|
55
|
+
],
|
|
56
|
+
default: 'base',
|
|
57
|
+
pageSize: 10,
|
|
58
|
+
loop: true,
|
|
59
|
+
});
|
|
60
|
+
if (choice === 'merge') {
|
|
61
|
+
baseObj[key] = val;
|
|
62
|
+
}
|
|
63
|
+
// 如果选择保留base,则保持不变
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
// 新键,直接添加
|
|
67
|
+
baseObj[key] = val;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return baseObj;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* 获取指定语言文件夹下的所有JSON文件名列表
|
|
74
|
+
* @param dirPath 语言文件夹路径
|
|
75
|
+
* @returns JSON文件名数组
|
|
76
|
+
*/
|
|
77
|
+
function getJsonFilesInLangDir(dirPath) {
|
|
78
|
+
if (!fs.existsSync(dirPath)) {
|
|
79
|
+
return [];
|
|
80
|
+
}
|
|
81
|
+
return fs.readdirSync(dirPath).filter((fileName) => {
|
|
82
|
+
const fullPath = path.join(dirPath, fileName);
|
|
83
|
+
return fs.statSync(fullPath).isFile() && fileName.endsWith('.json');
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* 主函数:合并两个目录下相同语言文件夹的JSON文件
|
|
88
|
+
* @param program commander命令行实例(暂未使用,可扩展)
|
|
89
|
+
*/
|
|
90
|
+
export async function jsonMerge(program) {
|
|
91
|
+
try {
|
|
92
|
+
// 交互输入源目录路径
|
|
93
|
+
const srcDir = await input({
|
|
94
|
+
message: '请输入源JSON文件夹路径(含语言子文件夹,如cn/translate.json):',
|
|
95
|
+
validate: (value) => {
|
|
96
|
+
const cleaned = value.trim().replace(/^['"]|['"]$/g, '');
|
|
97
|
+
if (cleaned.length === 0) {
|
|
98
|
+
return '路径不能为空';
|
|
99
|
+
}
|
|
100
|
+
const normalizedPath = normalizeGitBashPath(cleaned);
|
|
101
|
+
if (!fs.existsSync(normalizedPath)) {
|
|
102
|
+
return '文件不存在,请输入有效路径';
|
|
103
|
+
}
|
|
104
|
+
return true;
|
|
105
|
+
},
|
|
106
|
+
});
|
|
107
|
+
// 交互输入待合并目录路径
|
|
108
|
+
const mergeDir = await input({
|
|
109
|
+
message: '请输入待合并JSON文件夹路径(含语言子文件夹,如cn/translate.json):',
|
|
110
|
+
validate: (value) => {
|
|
111
|
+
const cleaned = value.trim().replace(/^['"]|['"]$/g, '');
|
|
112
|
+
if (cleaned.length === 0) {
|
|
113
|
+
return '路径不能为空';
|
|
114
|
+
}
|
|
115
|
+
const normalizedPath = normalizeGitBashPath(cleaned);
|
|
116
|
+
if (!fs.existsSync(normalizedPath)) {
|
|
117
|
+
return '文件不存在,请输入有效路径';
|
|
118
|
+
}
|
|
119
|
+
return true;
|
|
120
|
+
},
|
|
121
|
+
});
|
|
122
|
+
const srcPath = normalizeGitBashPath(srcDir);
|
|
123
|
+
const mergePath = normalizeGitBashPath(mergeDir);
|
|
124
|
+
logger.info(`源目录: ${srcPath}`);
|
|
125
|
+
logger.info(`合并目录: ${mergePath}`);
|
|
126
|
+
// 获取两个目录下的一级语言子文件夹列表
|
|
127
|
+
const srcLangDirs = fs.readdirSync(srcPath).filter((f) => {
|
|
128
|
+
const fullPath = path.join(srcPath, f);
|
|
129
|
+
return fs.statSync(fullPath).isDirectory();
|
|
130
|
+
});
|
|
131
|
+
const mergeLangDirs = fs.readdirSync(mergePath).filter((f) => {
|
|
132
|
+
const fullPath = path.join(mergePath, f);
|
|
133
|
+
return fs.statSync(fullPath).isDirectory();
|
|
134
|
+
});
|
|
135
|
+
// 找出两个目录下都存在的语言文件夹
|
|
136
|
+
const commonLangDirs = srcLangDirs.filter((lang) => mergeLangDirs.includes(lang));
|
|
137
|
+
if (commonLangDirs.length === 0) {
|
|
138
|
+
logger.info('没有发现相同语言文件夹,无需合并');
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
logger.info(`发现 ${commonLangDirs.length} 个共同语言文件夹: ${commonLangDirs.join(', ')}`, true);
|
|
142
|
+
// 遍历每个共同语言文件夹进行合并
|
|
143
|
+
for (const langKey of commonLangDirs) {
|
|
144
|
+
logger.info(`${'='.repeat(60)}`, true);
|
|
145
|
+
logger.info(`处理语言: ${langKey}`, true);
|
|
146
|
+
const srcLangPath = path.join(srcPath, langKey);
|
|
147
|
+
const mergeLangPath = path.join(mergePath, langKey);
|
|
148
|
+
const srcJsonFiles = getJsonFilesInLangDir(srcLangPath);
|
|
149
|
+
const mergeJsonFiles = getJsonFilesInLangDir(mergeLangPath);
|
|
150
|
+
// 找出两个语言文件夹中共同存在的JSON文件
|
|
151
|
+
const commonJsonFiles = srcJsonFiles.filter((file) => mergeJsonFiles.includes(file));
|
|
152
|
+
if (commonJsonFiles.length === 0) {
|
|
153
|
+
logger.info(`语言【${langKey}】下没有共同的JSON文件,跳过`, true);
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
logger.info(`发现 ${commonJsonFiles.length} 个共同JSON文件: ${commonJsonFiles.join(', ')}`, true);
|
|
157
|
+
// 逐个文件合并
|
|
158
|
+
for (const jsonFile of commonJsonFiles) {
|
|
159
|
+
logger.info(`处理文件: ${jsonFile}`, true);
|
|
160
|
+
const srcFile = path.join(srcLangPath, jsonFile);
|
|
161
|
+
const mergeFile = path.join(mergeLangPath, jsonFile);
|
|
162
|
+
if (!fs.existsSync(srcFile)) {
|
|
163
|
+
logger.warn(`源目录语言文件缺失: ${srcFile},跳过`, true);
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
166
|
+
if (!fs.existsSync(mergeFile)) {
|
|
167
|
+
logger.warn(`合并目录语言文件缺失: ${mergeFile},跳过`, true);
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
logger.info(`开始合并文件 ${jsonFile}...`, true);
|
|
171
|
+
const srcJson = readJsonFile(srcFile);
|
|
172
|
+
const mergeJson = readJsonFile(mergeFile);
|
|
173
|
+
// 打印合并前后键数量
|
|
174
|
+
const srcKeyCount = Object.keys(srcJson).length;
|
|
175
|
+
const mergeKeyCount = Object.keys(mergeJson).length;
|
|
176
|
+
logger.info(`源文件键数: ${srcKeyCount}, 合并文件键数: ${mergeKeyCount}`, true);
|
|
177
|
+
const merged = await mergeJsonObjects(srcJson, mergeJson, langKey);
|
|
178
|
+
const finalKeyCount = Object.keys(merged).length;
|
|
179
|
+
logger.info(`合并后键数: ${finalKeyCount}`, true);
|
|
180
|
+
writeJsonFile(srcFile, merged);
|
|
181
|
+
logger.info(`文件 ${jsonFile} 合并完成`, true);
|
|
182
|
+
}
|
|
183
|
+
logger.info(`语言【${langKey}】全部处理完成`, true);
|
|
184
|
+
}
|
|
185
|
+
logger.info(`${'='.repeat(60)}`, true);
|
|
186
|
+
logger.info(`所有合并操作完成!`, true);
|
|
187
|
+
logger.info(`源目录: ${srcPath}`, true);
|
|
188
|
+
logger.info(`合并目录: ${mergePath}`, true);
|
|
189
|
+
logger.info(`所有修改已写回源目录`, true);
|
|
190
|
+
}
|
|
191
|
+
catch (error) {
|
|
192
|
+
loggerError(error, logger);
|
|
193
|
+
console.error('程序执行时发生异常,已记录日志,程序已退出');
|
|
194
|
+
process.exit(1);
|
|
195
|
+
}
|
|
3
196
|
}
|
|
@@ -29,7 +29,7 @@ function getNearestHolidays(data, count = 3) {
|
|
|
29
29
|
// 初始化第一个节日组
|
|
30
30
|
currentGroup = {
|
|
31
31
|
name: h.name,
|
|
32
|
-
daysUntil: Math.
|
|
32
|
+
daysUntil: Math.ceil((hd.getTime() - today.getTime()) / (1000 * 60 * 60 * 24)),
|
|
33
33
|
holidayDates: [h.date],
|
|
34
34
|
hasTransferWorkday: false,
|
|
35
35
|
transferWorkdays: [],
|
|
@@ -47,7 +47,7 @@ function getNearestHolidays(data, count = 3) {
|
|
|
47
47
|
grouped.push(currentGroup);
|
|
48
48
|
currentGroup = {
|
|
49
49
|
name: h.name,
|
|
50
|
-
daysUntil: Math.
|
|
50
|
+
daysUntil: Math.ceil((hd.getTime() - today.getTime()) / (1000 * 60 * 60 * 24)),
|
|
51
51
|
holidayDates: [h.date],
|
|
52
52
|
hasTransferWorkday: false,
|
|
53
53
|
transferWorkdays: [],
|
package/dist/utils/index.d.ts
CHANGED
|
@@ -160,5 +160,17 @@ export declare function formatKey(key: string): string;
|
|
|
160
160
|
* @returns 去除特殊编码前缀后的字符串
|
|
161
161
|
*/
|
|
162
162
|
export declare function decodeKey(key: string): string;
|
|
163
|
+
/**
|
|
164
|
+
* 将Git Bash风格的路径(如 /d/...)转换成Windows风格路径(D:/...)
|
|
165
|
+
* @param inputPath 用户输入的路径
|
|
166
|
+
* @returns 转换后的绝对路径
|
|
167
|
+
*/
|
|
168
|
+
export declare function normalizeGitBashPath(inputPath: string): string;
|
|
169
|
+
/**
|
|
170
|
+
* 去除字符串首尾的单引号或双引号
|
|
171
|
+
* @param str 输入字符串
|
|
172
|
+
* @returns 去除引号后的字符串
|
|
173
|
+
*/
|
|
174
|
+
export declare function trimQuotes(str: string): string;
|
|
163
175
|
export {};
|
|
164
176
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"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"}
|
package/dist/utils/index.js
CHANGED
|
@@ -288,3 +288,30 @@ export function decodeKey(key) {
|
|
|
288
288
|
// 去除前缀
|
|
289
289
|
return key.replace(prefixRegex, '');
|
|
290
290
|
}
|
|
291
|
+
/**
|
|
292
|
+
* 将Git Bash风格的路径(如 /d/...)转换成Windows风格路径(D:/...)
|
|
293
|
+
* @param inputPath 用户输入的路径
|
|
294
|
+
* @returns 转换后的绝对路径
|
|
295
|
+
*/
|
|
296
|
+
export function normalizeGitBashPath(inputPath) {
|
|
297
|
+
let cleaned = inputPath.trim().replace(/^['"]|['"]$/g, '');
|
|
298
|
+
// 如果路径是 /d/... 格式,转换成 D:/...
|
|
299
|
+
if (/^\/[a-zA-Z]\//.test(cleaned)) {
|
|
300
|
+
cleaned = cleaned.replace(/^\/([a-zA-Z])\//, '$1:/');
|
|
301
|
+
}
|
|
302
|
+
// 使用 path.resolve 转成绝对路径(相对于当前工作目录)
|
|
303
|
+
const absolutePath = path.resolve(process.cwd(), cleaned);
|
|
304
|
+
return absolutePath;
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* 去除字符串首尾的单引号或双引号
|
|
308
|
+
* @param str 输入字符串
|
|
309
|
+
* @returns 去除引号后的字符串
|
|
310
|
+
*/
|
|
311
|
+
export function trimQuotes(str) {
|
|
312
|
+
if ((str.startsWith('"') && str.endsWith('"')) ||
|
|
313
|
+
(str.startsWith("'") && str.endsWith("'"))) {
|
|
314
|
+
return str.slice(1, -1);
|
|
315
|
+
}
|
|
316
|
+
return str;
|
|
317
|
+
}
|