td-web-cli 0.1.14 → 0.1.16
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/README.md +18 -18
- package/dist/api/interface.d.ts +1 -0
- package/dist/api/interface.d.ts.map +1 -1
- package/dist/api/interface.js +3 -2
- package/dist/index.js +12 -1
- package/dist/modules/i18n/excel2json/index.d.ts +3 -3
- package/dist/modules/i18n/excel2json/index.d.ts.map +1 -1
- package/dist/modules/i18n/excel2json/index.js +38 -38
- package/dist/modules/i18n/index.js +7 -7
- package/dist/modules/i18n/json2excel/index.js +1 -1
- package/dist/modules/i18n/jsonMerge/index.js +1 -1
- package/dist/modules/tools/getHolidayTime/index.d.ts +6 -0
- package/dist/modules/tools/getHolidayTime/index.d.ts.map +1 -0
- package/dist/modules/tools/getHolidayTime/index.js +111 -0
- package/dist/modules/tools/holidayTime/index.d.ts +13 -0
- package/dist/modules/tools/holidayTime/index.d.ts.map +1 -0
- package/dist/modules/tools/holidayTime/index.js +116 -0
- package/dist/modules/tools/index.d.ts +8 -0
- package/dist/modules/tools/index.d.ts.map +1 -0
- package/dist/modules/tools/index.js +56 -0
- package/dist/modules/tools/printFish/index.d.ts +2 -0
- package/dist/modules/tools/printFish/index.d.ts.map +1 -0
- package/dist/modules/tools/printFish/index.js +46 -0
- package/docs/i18n/excel2json.md +23 -23
- package/package.json +4 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# 项目名称
|
|
2
2
|
|
|
3
|
-
一个基于
|
|
3
|
+
一个基于 Node.js 和 TypeScript 的高效 CLI 工具,用于提升工作效率。
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -18,11 +18,11 @@
|
|
|
18
18
|
|
|
19
19
|
## 环境要求
|
|
20
20
|
|
|
21
|
-
-
|
|
21
|
+
- Node.js >= 20.x(推荐使用 22.x 或更高版本)
|
|
22
22
|
- npm >= 10.x
|
|
23
|
-
-
|
|
23
|
+
- TypeScript >= 5.x
|
|
24
24
|
|
|
25
|
-
> **注意**:部分依赖可能要求
|
|
25
|
+
> **注意**:部分依赖可能要求 Node.js 20 及以上版本,请根据实际情况调整。
|
|
26
26
|
|
|
27
27
|
---
|
|
28
28
|
|
|
@@ -31,8 +31,8 @@
|
|
|
31
31
|
1. 克隆仓库
|
|
32
32
|
|
|
33
33
|
```bash
|
|
34
|
-
git clone
|
|
35
|
-
cd
|
|
34
|
+
git clone https://github.com/qianyuzzf/td-web-cli.git
|
|
35
|
+
cd td-web-cli
|
|
36
36
|
```
|
|
37
37
|
|
|
38
38
|
2. 安装依赖
|
|
@@ -47,8 +47,8 @@ npm install
|
|
|
47
47
|
|
|
48
48
|
### 代码结构
|
|
49
49
|
|
|
50
|
-
- `src/` -
|
|
51
|
-
- `dist/` - 编译后的
|
|
50
|
+
- `src/` - TypeScript 源代码目录
|
|
51
|
+
- `dist/` - 编译后的 JavaScript 输出目录
|
|
52
52
|
- `release.js` - 发布脚本(可直接运行或编译后运行)
|
|
53
53
|
|
|
54
54
|
### 运行开发环境
|
|
@@ -59,7 +59,7 @@ npm link
|
|
|
59
59
|
td-web-cli # 确保本机未全局安装该工具
|
|
60
60
|
```
|
|
61
61
|
|
|
62
|
-
通过 `npm link`,本地调试
|
|
62
|
+
通过 `npm link`,本地调试 CLI 命令 `td-web-cli`。
|
|
63
63
|
|
|
64
64
|
---
|
|
65
65
|
|
|
@@ -67,7 +67,7 @@ td-web-cli # 确保本机未全局安装该工具
|
|
|
67
67
|
|
|
68
68
|
### 命令行执行
|
|
69
69
|
|
|
70
|
-
执行
|
|
70
|
+
执行 CLI 工具:
|
|
71
71
|
|
|
72
72
|
```bash
|
|
73
73
|
td-web-cli
|
|
@@ -75,13 +75,13 @@ td-web-cli
|
|
|
75
75
|
|
|
76
76
|
### 功能说明
|
|
77
77
|
|
|
78
|
-
- 多语言
|
|
78
|
+
- 多语言 Excel 转 JSON 工具。[详细功能说明请点击这里](https://github.com/qianyuzzf/td-web-cli/blob/master/docs/i18n/excel2json.md)
|
|
79
79
|
|
|
80
80
|
---
|
|
81
81
|
|
|
82
82
|
## 构建
|
|
83
83
|
|
|
84
|
-
使用
|
|
84
|
+
使用 TypeScript 编译项目:
|
|
85
85
|
|
|
86
86
|
```bash
|
|
87
87
|
npm run build
|
|
@@ -105,7 +105,7 @@ npm run release
|
|
|
105
105
|
- 依赖安装
|
|
106
106
|
- 项目构建
|
|
107
107
|
- 发布到 npm
|
|
108
|
-
- 提交并推送
|
|
108
|
+
- 提交并推送 Git 代码
|
|
109
109
|
|
|
110
110
|
---
|
|
111
111
|
|
|
@@ -113,17 +113,17 @@ npm run release
|
|
|
113
113
|
|
|
114
114
|
```
|
|
115
115
|
.
|
|
116
|
-
├── src/ #
|
|
116
|
+
├── src/ # TypeScript 源代码
|
|
117
117
|
│ └── index.ts # 入口文件
|
|
118
118
|
├── dist/ # 编译输出目录
|
|
119
119
|
├── release.js # 发布脚本
|
|
120
120
|
├── setting.json # 配置文件
|
|
121
121
|
├── package.json # 项目配置
|
|
122
|
-
├── tsconfig.json #
|
|
122
|
+
├── tsconfig.json # TypeScript 配置
|
|
123
123
|
├── README.md # 项目说明文件
|
|
124
|
-
├── .gitignore #
|
|
125
|
-
├── .prettierignore #
|
|
126
|
-
├── .prettierrc #
|
|
124
|
+
├── .gitignore # Git 忽略文件
|
|
125
|
+
├── .prettierignore # Prettier 忽略文件
|
|
126
|
+
├── .prettierrc # Prettier 配置文件
|
|
127
127
|
└── package-lock.json # 依赖锁定文件
|
|
128
128
|
```
|
|
129
129
|
|
package/dist/api/interface.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"interface.d.ts","sourceRoot":"","sources":["../../src/api/interface.ts"],"names":[],"mappings":"AAAA,QAAA,MAAM,GAAG
|
|
1
|
+
{"version":3,"file":"interface.d.ts","sourceRoot":"","sources":["../../src/api/interface.ts"],"names":[],"mappings":"AAAA,QAAA,MAAM,GAAG;;;;CAIR,CAAC;AAEF,eAAe,GAAG,CAAC"}
|
package/dist/api/interface.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const api = {
|
|
2
|
-
LANGUAGE_TOOL_V2_LANGUAGES: 'https://api.languagetool.org/v2/languages',
|
|
3
|
-
LANGUAGE_TOOL_V2_CHECK: 'https://api.languagetool.org/v2/check',
|
|
2
|
+
LANGUAGE_TOOL_V2_LANGUAGES: 'https://api.languagetool.org/v2/languages', // 获取支持的语言列表
|
|
3
|
+
LANGUAGE_TOOL_V2_CHECK: 'https://api.languagetool.org/v2/check', // 调用语言检测接口,检测文本中的语言错误
|
|
4
|
+
UNPKG_HOLIDAY_CALENDAR: 'https://unpkg.com/holiday-calendar@1.3.0/data/CN', // 获取假期日历数据
|
|
4
5
|
};
|
|
5
6
|
export default api;
|
package/dist/index.js
CHANGED
|
@@ -5,8 +5,9 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { Command } from 'commander';
|
|
7
7
|
import { select, Separator } from '@inquirer/prompts';
|
|
8
|
-
import { i18n } from './modules/i18n/index.js';
|
|
9
8
|
import { logger, loggerError } from './utils/index.js';
|
|
9
|
+
import { i18n } from './modules/i18n/index.js';
|
|
10
|
+
import { tools } from './modules/tools/index.js';
|
|
10
11
|
const program = new Command();
|
|
11
12
|
/**
|
|
12
13
|
* 主程序入口函数
|
|
@@ -25,6 +26,11 @@ async function main() {
|
|
|
25
26
|
value: 'i18n',
|
|
26
27
|
description: '国际化相关功能',
|
|
27
28
|
},
|
|
29
|
+
{
|
|
30
|
+
name: '小工具',
|
|
31
|
+
value: 'tools',
|
|
32
|
+
description: '小工具相关功能',
|
|
33
|
+
},
|
|
28
34
|
];
|
|
29
35
|
// 交互式选择模块
|
|
30
36
|
const answer = await select({
|
|
@@ -51,6 +57,11 @@ async function main() {
|
|
|
51
57
|
await i18n(program);
|
|
52
58
|
logger.info(`${selectedModule.name}模块执行完成`);
|
|
53
59
|
break;
|
|
60
|
+
case 'tools':
|
|
61
|
+
logger.info(`${selectedModule.name}模块开始执行`);
|
|
62
|
+
await tools(program);
|
|
63
|
+
logger.info(`${selectedModule.name}模块执行完成`);
|
|
64
|
+
break;
|
|
54
65
|
default:
|
|
55
66
|
logger.warn(`${selectedModule.name}模块暂未实现,程序已退出`);
|
|
56
67
|
process.exit(0);
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { Command } from 'commander';
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
4
|
-
* 读取用户输入的
|
|
3
|
+
* Excel转JSON功能主函数
|
|
4
|
+
* 读取用户输入的Excel路径,解析内容,根据配置生成多语言JSON文件
|
|
5
5
|
* 并对配置文件中所有语言对应的词条进行语言检测
|
|
6
|
-
* 如果有相同的
|
|
6
|
+
* 如果有相同的JSON KEY,则在KEY前面加上6位编码,保证唯一性
|
|
7
7
|
* @param program Commander命令行实例
|
|
8
8
|
*/
|
|
9
9
|
export declare function excel2json(program: Command): Promise<void>;
|
|
@@ -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;AA0LpC;;;;;;GAMG;AACH,wBAAsB,UAAU,CAAC,OAAO,EAAE,OAAO,
|
|
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;AA0LpC;;;;;;GAMG;AACH,wBAAsB,UAAU,CAAC,OAAO,EAAE,OAAO,iBAsVhD"}
|
|
@@ -34,17 +34,17 @@ function loadConfig(configPath) {
|
|
|
34
34
|
return json.i18n;
|
|
35
35
|
}
|
|
36
36
|
/**
|
|
37
|
-
* 匹配
|
|
38
|
-
* 先匹配语言
|
|
37
|
+
* 匹配Excel表头列名对应的语言KEY,支持大小写不敏感匹配
|
|
38
|
+
* 先匹配语言KEY本身,再匹配语言名称数组(包含关系)
|
|
39
39
|
* @param colName 表头列名
|
|
40
40
|
* @param langs 语言映射
|
|
41
|
-
* @returns 匹配到的语言
|
|
41
|
+
* @returns 匹配到的语言KEY,未匹配返回null
|
|
42
42
|
*/
|
|
43
43
|
function matchLangKey(colName, langs) {
|
|
44
44
|
if (!colName)
|
|
45
45
|
return null;
|
|
46
46
|
const colNameLower = colName.toLowerCase();
|
|
47
|
-
// 先尝试匹配语言
|
|
47
|
+
// 先尝试匹配语言KEY
|
|
48
48
|
for (const langKey of Object.keys(langs)) {
|
|
49
49
|
if (langKey.toLowerCase() === colNameLower) {
|
|
50
50
|
return langKey;
|
|
@@ -135,10 +135,10 @@ function parseCheckResultPerEntry(checkResult, texts) {
|
|
|
135
135
|
return entryErrors;
|
|
136
136
|
}
|
|
137
137
|
/**
|
|
138
|
-
*
|
|
139
|
-
* 读取用户输入的
|
|
138
|
+
* Excel转JSON功能主函数
|
|
139
|
+
* 读取用户输入的Excel路径,解析内容,根据配置生成多语言JSON文件
|
|
140
140
|
* 并对配置文件中所有语言对应的词条进行语言检测
|
|
141
|
-
* 如果有相同的
|
|
141
|
+
* 如果有相同的JSON KEY,则在KEY前面加上6位编码,保证唯一性
|
|
142
142
|
* @param program Commander命令行实例
|
|
143
143
|
*/
|
|
144
144
|
export async function excel2json(program) {
|
|
@@ -173,7 +173,7 @@ export async function excel2json(program) {
|
|
|
173
173
|
});
|
|
174
174
|
}
|
|
175
175
|
for (const lang of languageTools) {
|
|
176
|
-
// 尝试根据语言名称匹配配置中的语言
|
|
176
|
+
// 尝试根据语言名称匹配配置中的语言KEY
|
|
177
177
|
const lowerName = lang.name.toLowerCase();
|
|
178
178
|
const matchedKey = langNameToKey[lowerName] ||
|
|
179
179
|
Object.keys(i18nConfig.langs).find((k) => k.toLowerCase() === lowerName);
|
|
@@ -188,9 +188,9 @@ export async function excel2json(program) {
|
|
|
188
188
|
logger.warn(`获取在线语言列表失败,使用本地配置 longCodes,错误:${normalizeError(error).stack}`);
|
|
189
189
|
console.warn('获取在线语言列表失败,使用本地配置 longCodes');
|
|
190
190
|
}
|
|
191
|
-
// 交互式输入
|
|
191
|
+
// 交互式输入Excel文件路径并校验
|
|
192
192
|
const answer = await input({
|
|
193
|
-
message: '请输入
|
|
193
|
+
message: '请输入Excel文件路径:',
|
|
194
194
|
validate: (value) => {
|
|
195
195
|
const cleaned = value.trim().replace(/^['"]|['"]$/g, '');
|
|
196
196
|
if (cleaned.length === 0)
|
|
@@ -198,19 +198,19 @@ export async function excel2json(program) {
|
|
|
198
198
|
if (!fs.existsSync(cleaned))
|
|
199
199
|
return '文件不存在,请输入有效路径';
|
|
200
200
|
if (!/\.(xls|xlsx)$/i.test(cleaned))
|
|
201
|
-
return '请输入有效的
|
|
201
|
+
return '请输入有效的Excel文件路径(.xls或.xlsx)';
|
|
202
202
|
return true;
|
|
203
203
|
},
|
|
204
204
|
});
|
|
205
205
|
// 规范化路径,支持相对路径转绝对路径,去除首尾引号
|
|
206
206
|
const excelPath = path.resolve(process.cwd(), answer.trim().replace(/^['"]|['"]$/g, ''));
|
|
207
207
|
try {
|
|
208
|
-
logger.info(`开始读取
|
|
209
|
-
// 读取
|
|
208
|
+
logger.info(`开始读取Excel文件:${excelPath}`, true);
|
|
209
|
+
// 读取Excel文件
|
|
210
210
|
const workbook = XLSX.readFile(excelPath);
|
|
211
211
|
const firstSheetName = workbook.SheetNames[0];
|
|
212
212
|
if (!firstSheetName) {
|
|
213
|
-
logger.error('
|
|
213
|
+
logger.error('Excel文件没有任何工作表,程序已退出');
|
|
214
214
|
console.error('程序执行时发生异常,已记录日志,程序已退出');
|
|
215
215
|
process.exit(1);
|
|
216
216
|
}
|
|
@@ -225,7 +225,7 @@ export async function excel2json(program) {
|
|
|
225
225
|
logger.info('开始解析表头', true);
|
|
226
226
|
// 处理表头行,去除空格,转成字符串
|
|
227
227
|
const headerRow = rows[0].map((cell) => (cell ? String(cell).trim() : ''));
|
|
228
|
-
// 根据表头匹配语言列,建立列索引到语言
|
|
228
|
+
// 根据表头匹配语言列,建立列索引到语言KEY的映射
|
|
229
229
|
const colIndexToLangKey = {};
|
|
230
230
|
headerRow.forEach((colName, idx) => {
|
|
231
231
|
const langKey = matchLangKey(colName, i18nConfig.langs);
|
|
@@ -243,20 +243,20 @@ export async function excel2json(program) {
|
|
|
243
243
|
}
|
|
244
244
|
const defaultColNum = Number(defaultColIndex);
|
|
245
245
|
// 初始化所有语言词条对象(包括默认语言)
|
|
246
|
-
// 用于存储最终的翻译
|
|
246
|
+
// 用于存储最终的翻译KEY-VALUE对,KEY可能会被重新编码以避免重复
|
|
247
247
|
const langTranslations = {};
|
|
248
248
|
Object.values(colIndexToLangKey).forEach((langKey) => {
|
|
249
249
|
langTranslations[langKey] = {};
|
|
250
250
|
});
|
|
251
251
|
logger.info('开始解析数据行', true);
|
|
252
|
-
// 记录所有出现过的
|
|
252
|
+
// 记录所有出现过的KEY,检测重复,格式:langKey => Set of keys
|
|
253
253
|
const langKeySets = {};
|
|
254
254
|
Object.keys(langTranslations).forEach((langKey) => {
|
|
255
255
|
langKeySets[langKey] = new Set();
|
|
256
256
|
});
|
|
257
257
|
// 遍历数据行,提取所有语言词条
|
|
258
|
-
//
|
|
259
|
-
const langKeysMap = {}; // 语言
|
|
258
|
+
// KEY统一用默认语言列的值,其他语言对应的列为翻译内容
|
|
259
|
+
const langKeysMap = {}; // 语言KEY => 词条数组(用于检测)
|
|
260
260
|
Object.keys(langTranslations).forEach((langKey) => {
|
|
261
261
|
langKeysMap[langKey] = [];
|
|
262
262
|
});
|
|
@@ -267,15 +267,15 @@ export async function excel2json(program) {
|
|
|
267
267
|
continue;
|
|
268
268
|
let key = String(keyCell).trim();
|
|
269
269
|
key = trimQuotes(key); // 去除引号
|
|
270
|
-
// 跳过空
|
|
270
|
+
// 跳过空KEY,避免写入无效数据
|
|
271
271
|
if (key.length === 0)
|
|
272
272
|
continue;
|
|
273
|
-
// 判断默认语言
|
|
273
|
+
// 判断默认语言KEY是否重复,若重复则重新编码
|
|
274
274
|
if (langKeySets[defaultLang].has(key)) {
|
|
275
275
|
key = formatKey(key);
|
|
276
276
|
}
|
|
277
277
|
langKeySets[defaultLang].add(key);
|
|
278
|
-
// 默认语言的词条即
|
|
278
|
+
// 默认语言的词条即KEY本身
|
|
279
279
|
langTranslations[defaultLang][key] = key;
|
|
280
280
|
langKeysMap[defaultLang].push(key);
|
|
281
281
|
// 其他语言词条
|
|
@@ -286,7 +286,7 @@ export async function excel2json(program) {
|
|
|
286
286
|
const valCell = row[colIdx];
|
|
287
287
|
if (valCell !== undefined && valCell !== null && valCell !== '') {
|
|
288
288
|
const valStr = String(valCell);
|
|
289
|
-
// 判断该语言的
|
|
289
|
+
// 判断该语言的KEY是否重复,若重复则重新编码KEY
|
|
290
290
|
let finalKey = key;
|
|
291
291
|
if (langKeySets[langKey].has(finalKey)) {
|
|
292
292
|
finalKey = formatKey(finalKey);
|
|
@@ -301,7 +301,7 @@ export async function excel2json(program) {
|
|
|
301
301
|
}
|
|
302
302
|
}
|
|
303
303
|
}
|
|
304
|
-
// 语言检测结果映射,语言
|
|
304
|
+
// 语言检测结果映射,语言KEY => 每条词条的错误描述数组
|
|
305
305
|
const langCheckErrorsMap = {};
|
|
306
306
|
// 对所有语言词条批量进行语言检测(包括默认语言)
|
|
307
307
|
const langKeysEntries = Object.entries(langKeysMap);
|
|
@@ -343,7 +343,7 @@ export async function excel2json(program) {
|
|
|
343
343
|
}
|
|
344
344
|
}
|
|
345
345
|
}
|
|
346
|
-
// 输出目录:
|
|
346
|
+
// 输出目录:Excel文件所在目录下的“lang_时间戳”文件夹
|
|
347
347
|
const excelDir = path.dirname(excelPath);
|
|
348
348
|
const timestamp = getTimestamp();
|
|
349
349
|
const outputRoot = path.join(excelDir, `lang_${timestamp}`);
|
|
@@ -351,12 +351,12 @@ export async function excel2json(program) {
|
|
|
351
351
|
fs.mkdirSync(outputRoot, { recursive: true });
|
|
352
352
|
}
|
|
353
353
|
logger.info(`开始生成语言文件,输出目录:${outputRoot}`, true);
|
|
354
|
-
// 按语言生成对应的
|
|
354
|
+
// 按语言生成对应的JSON文件,默认语言的KEY=VALUE不生成文件
|
|
355
355
|
for (const [langKey, translations] of Object.entries(langTranslations)) {
|
|
356
356
|
if (Object.keys(translations).length === 0)
|
|
357
357
|
continue;
|
|
358
358
|
if (langKey === defaultLang) {
|
|
359
|
-
logger.info(`跳过默认语言(${langKey})的
|
|
359
|
+
logger.info(`跳过默认语言(${langKey})的JSON文件生成`, true);
|
|
360
360
|
continue; // 跳过默认语言文件生成
|
|
361
361
|
}
|
|
362
362
|
const langDir = path.join(outputRoot, langKey);
|
|
@@ -369,21 +369,21 @@ export async function excel2json(program) {
|
|
|
369
369
|
});
|
|
370
370
|
logger.info(`已生成语言文件:${filePath}`, true);
|
|
371
371
|
}
|
|
372
|
-
// 生成语言检测结果
|
|
373
|
-
logger.info('开始生成语言检测结果
|
|
374
|
-
// 构造检测结果
|
|
375
|
-
// 这里表头用原
|
|
372
|
+
// 生成语言检测结果Excel文件
|
|
373
|
+
logger.info('开始生成语言检测结果Excel文件', true);
|
|
374
|
+
// 构造检测结果Excel的表头:默认语言列 + 其他语言列(对应原文列名)
|
|
375
|
+
// 这里表头用原Excel的表头中对应语言列的值
|
|
376
376
|
const errorSheetHeader = [];
|
|
377
|
-
// 按列索引顺序遍历,匹配语言
|
|
377
|
+
// 按列索引顺序遍历,匹配语言KEY,构造表头
|
|
378
378
|
Object.entries(colIndexToLangKey)
|
|
379
379
|
.sort((a, b) => Number(a[0]) - Number(b[0]))
|
|
380
380
|
.forEach(([colIdxStr, langKey]) => {
|
|
381
381
|
const colIdx = Number(colIdxStr);
|
|
382
|
-
// 表头为原
|
|
382
|
+
// 表头为原Excel表头中对应列的文字
|
|
383
383
|
errorSheetHeader.push(headerRow[colIdx]);
|
|
384
384
|
});
|
|
385
|
-
// 构造检测结果
|
|
386
|
-
// 每行对应原
|
|
385
|
+
// 构造检测结果Excel的内容,每一列对应语言检测错误描述
|
|
386
|
+
// 每行对应原Excel中一条数据行
|
|
387
387
|
const dataRowCount = rows.length - 1;
|
|
388
388
|
const errorSheetData = [errorSheetHeader];
|
|
389
389
|
for (let i = 0; i < dataRowCount; i++) {
|
|
@@ -405,14 +405,14 @@ export async function excel2json(program) {
|
|
|
405
405
|
});
|
|
406
406
|
errorSheetData.push(rowErrors);
|
|
407
407
|
}
|
|
408
|
-
// 生成
|
|
408
|
+
// 生成Excel工作簿和工作表
|
|
409
409
|
const errorWorkbook = XLSX.utils.book_new();
|
|
410
410
|
const errorSheet = XLSX.utils.aoa_to_sheet(errorSheetData);
|
|
411
411
|
XLSX.utils.book_append_sheet(errorWorkbook, errorSheet, 'LanguageCheckResults');
|
|
412
|
-
// 写入检测结果
|
|
412
|
+
// 写入检测结果Excel文件,固定文件名 lang_check_results.xlsx
|
|
413
413
|
const errorExcelPath = path.join(outputRoot, `lang_check_results.xlsx`);
|
|
414
414
|
XLSX.writeFile(errorWorkbook, errorExcelPath);
|
|
415
|
-
logger.info(`语言检测结果
|
|
415
|
+
logger.info(`语言检测结果Excel文件已生成:${errorExcelPath}`, true);
|
|
416
416
|
// 最终完成提示,包含输出目录
|
|
417
417
|
logger.info(`全部转换完成,语言文件输出目录:${outputRoot}`, true);
|
|
418
418
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { select, Separator } from '@inquirer/prompts';
|
|
2
|
-
import { excel2json } from './excel2json/index.js';
|
|
3
2
|
import { logger, loggerError } from '../../utils/index.js';
|
|
3
|
+
import { excel2json } from './excel2json/index.js';
|
|
4
4
|
/**
|
|
5
5
|
* 国际化模块主入口
|
|
6
6
|
* 提供多个国际化相关功能的交互式选择
|
|
@@ -17,19 +17,19 @@ export async function i18n(program) {
|
|
|
17
17
|
description: '从所给路径中提取词条信息',
|
|
18
18
|
},
|
|
19
19
|
{
|
|
20
|
-
name: '
|
|
20
|
+
name: 'JSON转Excel',
|
|
21
21
|
value: 'json2excel',
|
|
22
|
-
description: '将
|
|
22
|
+
description: '将JSON格式的词条信息转换为Excel表格',
|
|
23
23
|
},
|
|
24
24
|
{
|
|
25
|
-
name: '
|
|
25
|
+
name: 'Excel转JSON',
|
|
26
26
|
value: 'excel2json',
|
|
27
|
-
description: '将
|
|
27
|
+
description: '将Excel表格转换为JSON格式的词条信息',
|
|
28
28
|
},
|
|
29
29
|
{
|
|
30
|
-
name: '
|
|
30
|
+
name: 'JSON合并',
|
|
31
31
|
value: 'jsonMerge',
|
|
32
|
-
description: '合并多个
|
|
32
|
+
description: '合并多个JSON格式的词条信息文件',
|
|
33
33
|
},
|
|
34
34
|
];
|
|
35
35
|
// 交互式选择需要执行的功能
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/modules/tools/getHolidayTime/index.ts"],"names":[],"mappings":"AA6HA;;;GAGG;AACH,wBAAsB,cAAc,kBAoCnC"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { getData } from '../../../api/index.js';
|
|
2
|
+
import api from '../../../api/interface.js';
|
|
3
|
+
import { logger, loggerError } from '../../../utils/index.js';
|
|
4
|
+
/**
|
|
5
|
+
* 计算从今天起最近的几个节假日信息
|
|
6
|
+
* @param data 节假日数据
|
|
7
|
+
* @param count 需要返回的节假日数量,默认3
|
|
8
|
+
* @returns 最近count个节假日的汇总信息数组
|
|
9
|
+
*/
|
|
10
|
+
function getNearestHolidays(data, count = 3) {
|
|
11
|
+
const today = new Date();
|
|
12
|
+
// 过滤出所有节假日和调休日
|
|
13
|
+
const holidays = data.dates.filter((d) => d.type.toLowerCase() === 'public_holiday');
|
|
14
|
+
const transferWorkdays = data.dates.filter((d) => d.type.toLowerCase() === 'transfer_workday');
|
|
15
|
+
// 解析日期字符串为Date对象,确保时区正确
|
|
16
|
+
function parseDate(dateStr) {
|
|
17
|
+
return new Date(dateStr + 'T00:00:00');
|
|
18
|
+
}
|
|
19
|
+
// 按日期升序排序节假日
|
|
20
|
+
holidays.sort((a, b) => parseDate(a.date).getTime() - parseDate(b.date).getTime());
|
|
21
|
+
// 筛选今天及以后日期的节假日
|
|
22
|
+
const upcomingHolidays = holidays.filter((h) => parseDate(h.date) >= today);
|
|
23
|
+
// 将连续日期且名称相同的节假日合并为一个节日区间
|
|
24
|
+
const grouped = [];
|
|
25
|
+
let currentGroup = null;
|
|
26
|
+
for (const h of upcomingHolidays) {
|
|
27
|
+
const hd = parseDate(h.date);
|
|
28
|
+
if (!currentGroup) {
|
|
29
|
+
// 初始化第一个节日组
|
|
30
|
+
currentGroup = {
|
|
31
|
+
name: h.name,
|
|
32
|
+
daysUntil: Math.floor((hd.getTime() - today.getTime()) / (1000 * 60 * 60 * 24)),
|
|
33
|
+
holidayDates: [h.date],
|
|
34
|
+
hasTransferWorkday: false,
|
|
35
|
+
transferWorkdays: [],
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
// 判断是否是连续日期且名称相同,合并到当前组
|
|
40
|
+
const lastDate = parseDate(currentGroup.holidayDates[currentGroup.holidayDates.length - 1]);
|
|
41
|
+
const diffDays = (hd.getTime() - lastDate.getTime()) / (1000 * 60 * 60 * 24);
|
|
42
|
+
if (diffDays === 1 && h.name === currentGroup.name) {
|
|
43
|
+
currentGroup.holidayDates.push(h.date);
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
// 不连续或名称不同,保存当前组,开启新组
|
|
47
|
+
grouped.push(currentGroup);
|
|
48
|
+
currentGroup = {
|
|
49
|
+
name: h.name,
|
|
50
|
+
daysUntil: Math.floor((hd.getTime() - today.getTime()) / (1000 * 60 * 60 * 24)),
|
|
51
|
+
holidayDates: [h.date],
|
|
52
|
+
hasTransferWorkday: false,
|
|
53
|
+
transferWorkdays: [],
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
if (currentGroup) {
|
|
59
|
+
grouped.push(currentGroup);
|
|
60
|
+
}
|
|
61
|
+
// 为每个节假日组匹配调休日(调休日距离节假日区间前后7天内视为相关)
|
|
62
|
+
for (const group of grouped) {
|
|
63
|
+
const start = parseDate(group.holidayDates[0]);
|
|
64
|
+
const end = parseDate(group.holidayDates[group.holidayDates.length - 1]);
|
|
65
|
+
const relatedTransfers = transferWorkdays.filter((t) => {
|
|
66
|
+
const td = parseDate(t.date);
|
|
67
|
+
return (Math.abs(td.getTime() - start.getTime()) <= 7 * 24 * 60 * 60 * 1000 ||
|
|
68
|
+
Math.abs(td.getTime() - end.getTime()) <= 7 * 24 * 60 * 60 * 1000);
|
|
69
|
+
});
|
|
70
|
+
if (relatedTransfers.length > 0) {
|
|
71
|
+
group.hasTransferWorkday = true;
|
|
72
|
+
group.transferWorkdays = relatedTransfers.map((t) => t.date);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
// 返回最近count个节假日
|
|
76
|
+
return grouped.slice(0, count);
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* 获取节假日信息并打印最近三个节假日详情,节假日名称黄色,序号无颜色
|
|
80
|
+
* 并打印请求和处理进度提示
|
|
81
|
+
*/
|
|
82
|
+
export async function getHolidayTime() {
|
|
83
|
+
try {
|
|
84
|
+
logger.info('开始获取节假日数据...', true);
|
|
85
|
+
const year = new Date().getFullYear();
|
|
86
|
+
const url = api.UNPKG_HOLIDAY_CALENDAR + `/${year}.json`;
|
|
87
|
+
const data = await getData(url);
|
|
88
|
+
logger.info('节假日数据请求成功,开始计算最近节假日...', true);
|
|
89
|
+
const nearest = getNearestHolidays(data, 3);
|
|
90
|
+
console.log('\x1b[36m%s\x1b[0m', '=== 最近三个节假日信息 ==='); // 青色标题
|
|
91
|
+
nearest.forEach((holiday, index) => {
|
|
92
|
+
console.log(`第${index + 1}个节假日: \x1b[33m\x1b[1m${holiday.name}\x1b[0m`); // 节假日名称黄色加粗
|
|
93
|
+
console.log(`距离今天还有: \x1b[32m${holiday.daysUntil} 天\x1b[0m`); // 绿色天数
|
|
94
|
+
console.log(`放假日期: \x1b[35m${holiday.holidayDates.join(', ')}\x1b[0m`); // 紫色日期
|
|
95
|
+
if (holiday.hasTransferWorkday) {
|
|
96
|
+
console.log(`包含调休日期: \x1b[31m${holiday.transferWorkdays.join(', ')}\x1b[0m`); // 红色调休日
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
console.log('\x1b[37m无调休\x1b[0m'); // 白色无调休
|
|
100
|
+
}
|
|
101
|
+
console.log('\x1b[90m---------------------\x1b[0m'); // 灰色分割线
|
|
102
|
+
});
|
|
103
|
+
logger.info('节假日信息打印完成。', true);
|
|
104
|
+
}
|
|
105
|
+
catch (error) {
|
|
106
|
+
// 记录错误日志,方便排查
|
|
107
|
+
loggerError(error, logger);
|
|
108
|
+
console.error('程序执行时发生异常,已记录日志,程序已退出');
|
|
109
|
+
process.exit(1);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
type HolidayInfo = {
|
|
2
|
+
name: string;
|
|
3
|
+
start: Date;
|
|
4
|
+
end: Date;
|
|
5
|
+
daysLeft: number;
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* 获取最近两个节假日放假时间和距离天数
|
|
9
|
+
*/
|
|
10
|
+
export declare function getHolidayTime(currentDate?: Date): Promise<HolidayInfo[]>;
|
|
11
|
+
export declare function holidayTime(): Promise<void>;
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/modules/tools/holidayTime/index.ts"],"names":[],"mappings":"AAGA,KAAK,WAAW,GAAG;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,IAAI,CAAC;IACZ,GAAG,EAAE,IAAI,CAAC;IACV,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAuEF;;GAEG;AACH,wBAAsB,cAAc,CAClC,WAAW,OAAa,GACvB,OAAO,CAAC,WAAW,EAAE,CAAC,CA+DxB;AAED,wBAAsB,WAAW,kBAUhC"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import axios from 'axios';
|
|
2
|
+
import { Lunar } from 'lunar-javascript';
|
|
3
|
+
const lunarHolidays = [
|
|
4
|
+
{ name: '春节', lunarMonth: 1, lunarDay: 1, duration: 7 },
|
|
5
|
+
{ name: '端午节', lunarMonth: 5, lunarDay: 5, duration: 3 },
|
|
6
|
+
{ name: '中秋节', lunarMonth: 8, lunarDay: 15, duration: 3 },
|
|
7
|
+
];
|
|
8
|
+
/**
|
|
9
|
+
* 解析 yyyy-mm-dd 字符串成 Date(00:00:00)
|
|
10
|
+
*/
|
|
11
|
+
function parseDate(dateStr) {
|
|
12
|
+
return new Date(dateStr + 'T00:00:00');
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* 获取农历节日对应当年公历放假起止日期
|
|
16
|
+
*/
|
|
17
|
+
function getLunarHolidayDates(year) {
|
|
18
|
+
return lunarHolidays.map((h) => {
|
|
19
|
+
const lunar = Lunar.fromYmd(year, h.lunarMonth, h.lunarDay);
|
|
20
|
+
const start = lunar.getSolar().toDate();
|
|
21
|
+
const end = new Date(start);
|
|
22
|
+
end.setDate(start.getDate() + h.duration - 1);
|
|
23
|
+
return { name: h.name, start, end, daysLeft: 0 };
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* 合并连续且同名的节假日日期区间
|
|
28
|
+
*/
|
|
29
|
+
function mergeHolidays(holidays) {
|
|
30
|
+
if (holidays.length === 0)
|
|
31
|
+
return [];
|
|
32
|
+
holidays.sort((a, b) => a.start.getTime() - b.start.getTime());
|
|
33
|
+
const merged = [];
|
|
34
|
+
for (const h of holidays) {
|
|
35
|
+
const last = merged[merged.length - 1];
|
|
36
|
+
if (last &&
|
|
37
|
+
h.name === last.name &&
|
|
38
|
+
h.start.getTime() === last.end.getTime() + 86400000) {
|
|
39
|
+
// 连续且同名,延长结束日期
|
|
40
|
+
last.end = h.end;
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
merged.push({ ...h });
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return merged;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* 计算两个日期相差天数(date2 - date1)
|
|
50
|
+
*/
|
|
51
|
+
function daysBetween(date1, date2) {
|
|
52
|
+
const msPerDay = 1000 * 60 * 60 * 24;
|
|
53
|
+
return Math.floor((date2.getTime() - date1.getTime()) / msPerDay);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* 获取最近两个节假日放假时间和距离天数
|
|
57
|
+
*/
|
|
58
|
+
export async function getHolidayTime(currentDate = new Date()) {
|
|
59
|
+
const year = currentDate.getFullYear();
|
|
60
|
+
const today = new Date(currentDate.toDateString());
|
|
61
|
+
// 1. 获取当年官方节假日数据(含调休)
|
|
62
|
+
const res = await axios.get(`http://timor.tech/api/holiday/year`);
|
|
63
|
+
if (res.status !== 200) {
|
|
64
|
+
throw new Error('获取节假日数据失败');
|
|
65
|
+
}
|
|
66
|
+
const data = res.data;
|
|
67
|
+
// 2. 从API数据中筛选放假日期(holiday=true)
|
|
68
|
+
const apiHolidaysRaw = Object.entries(data.holiday)
|
|
69
|
+
.filter(([_, info]) => info.holiday)
|
|
70
|
+
.map(([date, info]) => ({
|
|
71
|
+
name: info.name,
|
|
72
|
+
start: parseDate(date),
|
|
73
|
+
end: parseDate(date),
|
|
74
|
+
daysLeft: 0,
|
|
75
|
+
}));
|
|
76
|
+
// 3. 合并连续放假日期(同名且连续)
|
|
77
|
+
const apiHolidays = mergeHolidays(apiHolidaysRaw);
|
|
78
|
+
// 4. 计算农历节日对应公历日期,补充可能遗漏的节日
|
|
79
|
+
const lunarHols = getLunarHolidayDates(year);
|
|
80
|
+
// 5. 合并API节假日和农历节假日(避免重复)
|
|
81
|
+
const allHolidays = [...apiHolidays];
|
|
82
|
+
lunarHols.forEach((lh) => {
|
|
83
|
+
const exists = allHolidays.some((h) => h.name === lh.name &&
|
|
84
|
+
h.start.getTime() === lh.start.getTime() &&
|
|
85
|
+
h.end.getTime() === lh.end.getTime());
|
|
86
|
+
if (!exists) {
|
|
87
|
+
allHolidays.push(lh);
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
// 6. 计算距离今天的天数,如果节日已过则计算下一年对应日期距离
|
|
91
|
+
const futureHolidays = allHolidays.map((h) => {
|
|
92
|
+
let daysLeft = daysBetween(today, h.start);
|
|
93
|
+
if (daysLeft < 0) {
|
|
94
|
+
// 节日已过,计算下一年对应节日日期
|
|
95
|
+
const nextYearStart = new Date(h.start);
|
|
96
|
+
nextYearStart.setFullYear(nextYearStart.getFullYear() + 1);
|
|
97
|
+
const nextYearEnd = new Date(h.end);
|
|
98
|
+
nextYearEnd.setFullYear(nextYearEnd.getFullYear() + 1);
|
|
99
|
+
daysLeft = daysBetween(today, nextYearStart);
|
|
100
|
+
return { name: h.name, start: nextYearStart, end: nextYearEnd, daysLeft };
|
|
101
|
+
}
|
|
102
|
+
return { ...h, daysLeft };
|
|
103
|
+
});
|
|
104
|
+
// 7. 按距离排序,返回最近两个节日
|
|
105
|
+
futureHolidays.sort((a, b) => a.daysLeft - b.daysLeft);
|
|
106
|
+
return futureHolidays.slice(0, 2);
|
|
107
|
+
}
|
|
108
|
+
export async function holidayTime() {
|
|
109
|
+
return getHolidayTime().then((holidays) => {
|
|
110
|
+
holidays.forEach((h) => {
|
|
111
|
+
console.log(`距离${h.name}放假还有 ${h.daysLeft} 天,放假时间:${h.start
|
|
112
|
+
.toISOString()
|
|
113
|
+
.slice(0, 10)} 至 ${h.end.toISOString().slice(0, 10)}`);
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/modules/tools/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKpC;;;;GAIG;AACH,wBAAsB,KAAK,CAAC,OAAO,EAAE,OAAO,iBAoD3C"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { select, Separator } from '@inquirer/prompts';
|
|
2
|
+
import { logger, loggerError } from '../../utils/index.js';
|
|
3
|
+
import { getHolidayTime } from './getHolidayTime/index.js';
|
|
4
|
+
/**
|
|
5
|
+
* 小工具模块主入口
|
|
6
|
+
* 提供多个小工具相关功能的交互式选择
|
|
7
|
+
* @param program Commander命令行实例,用于传递参数和配置
|
|
8
|
+
*/
|
|
9
|
+
export async function tools(program) {
|
|
10
|
+
try {
|
|
11
|
+
logger.info('小工具模块启动,等待用户选择功能');
|
|
12
|
+
// 定义可用功能选项
|
|
13
|
+
const moduleChoices = [
|
|
14
|
+
{
|
|
15
|
+
name: '获取假期时间',
|
|
16
|
+
value: 'getHolidayTime',
|
|
17
|
+
description: '获取今年的假期时间列表',
|
|
18
|
+
},
|
|
19
|
+
];
|
|
20
|
+
// 交互式选择需要执行的功能
|
|
21
|
+
const answer = await select({
|
|
22
|
+
message: '请选择要执行的功能:',
|
|
23
|
+
choices: [
|
|
24
|
+
...moduleChoices,
|
|
25
|
+
new Separator(), // 分割线,方便未来扩展更多功能
|
|
26
|
+
],
|
|
27
|
+
default: 'getHolidayTime', // 默认选项
|
|
28
|
+
pageSize: 10, // 最大显示选项数
|
|
29
|
+
loop: true, // 是否循环滚动选项
|
|
30
|
+
});
|
|
31
|
+
// 查找选择功能的名称,方便日志输出
|
|
32
|
+
const selectedModule = moduleChoices.find((item) => item.value === answer);
|
|
33
|
+
if (!selectedModule) {
|
|
34
|
+
logger.warn('未选择有效功能,程序已退出');
|
|
35
|
+
process.exit(0);
|
|
36
|
+
}
|
|
37
|
+
logger.info(`用户选择功能:${selectedModule.name}`);
|
|
38
|
+
// 根据选择执行对应功能
|
|
39
|
+
switch (answer) {
|
|
40
|
+
case 'getHolidayTime':
|
|
41
|
+
logger.info(`${selectedModule.name}功能开始执行`);
|
|
42
|
+
await getHolidayTime();
|
|
43
|
+
logger.info(`${selectedModule.name}功能执行完成`);
|
|
44
|
+
break;
|
|
45
|
+
default:
|
|
46
|
+
logger.warn(`${selectedModule.name}功能暂未实现,程序已退出`);
|
|
47
|
+
process.exit(0);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
// 记录错误日志,方便排查
|
|
52
|
+
loggerError(error, logger);
|
|
53
|
+
console.error('程序执行时发生异常,已记录日志,程序已退出');
|
|
54
|
+
process.exit(1);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/modules/tools/printFish/index.ts"],"names":[],"mappings":"AAAA,wBAAgB,SAAS,IAAI,IAAI,CA6ChC"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
export function printFish() {
|
|
2
|
+
console.log(`
|
|
3
|
+
╔══════════════════════════════════════════════════════════════╗
|
|
4
|
+
║ 🐟✨ 摸 鱼 盛 宴 ✨🐟 ║
|
|
5
|
+
╠══════════════════════════════════════════════════════════════╣
|
|
6
|
+
║ ║
|
|
7
|
+
║ ~~~~~ ~~~ ~~~~~~~~ ~~~~~ ~~~ ║
|
|
8
|
+
║ ~~~~ ~~~ ~~~~~~~~ ~~ ~~~~ ~~~ ~~~ ║
|
|
9
|
+
║ ~~~ ~~~~~~~~~~ ~~~~~ ~~~~~~~~~~ ║
|
|
10
|
+
║ ║
|
|
11
|
+
║ ╭─────────╮ ║
|
|
12
|
+
║ │ 👤 │ ║
|
|
13
|
+
║ │ /|\\ │ ║
|
|
14
|
+
║ │ / \\ │ ║
|
|
15
|
+
║ ╰────┬────╯ ║
|
|
16
|
+
║ │ ║
|
|
17
|
+
║ │ ║
|
|
18
|
+
║ │ 🎣 ║
|
|
19
|
+
║ ↓ ║
|
|
20
|
+
║ ║
|
|
21
|
+
║ ╭────────────────────────────────────╮ ║
|
|
22
|
+
║ │ ░░░░░░░░░░░░░░░░░░░░░░░░ │ ║
|
|
23
|
+
║ │ ░░ 🌊 湖 塘 🌊 ░░ │ ║
|
|
24
|
+
║ │ ░ ░ │ ║
|
|
25
|
+
║ │ ░ 🐠 🐟 🐡 ░ │ ║
|
|
26
|
+
║ │░ /≻\\ />\\ <\\≺ ░ │ ║
|
|
27
|
+
║ │░ / \\ /___\\ / \\ ░ │ ║
|
|
28
|
+
║ │░ o >< ))> (🐟 ) <) >< o ░ │ ║
|
|
29
|
+
║ │░ \\__/ \\_/ \\__/ ░ │ ║
|
|
30
|
+
║ │ ░ ░ │ ║
|
|
31
|
+
║ │ ░░ ░░ │ ║
|
|
32
|
+
║ │ ░░░░░░░░░░░░░░░░░░░░░░░░ │ ║
|
|
33
|
+
║ ╰────────────────────────────────────╯ ║
|
|
34
|
+
║ ║
|
|
35
|
+
║ ~~~ ~~~~~~~~~~ ~~~~~ ~~~~~~~~~~ ║
|
|
36
|
+
║ ~~~~ ~~~ ~~~~~~~~ ~~ ~~~~ ~~~ ~~~ ║
|
|
37
|
+
║ ~~~~~ ~~~ ~~~~~~~~ ~~~~~ ~~~ ║
|
|
38
|
+
║ ║
|
|
39
|
+
║ 💬 "老板不在家,摸鱼乐哈哈!" ║
|
|
40
|
+
║ 📈 摸鱼指数:███████████░░░░░░░ 75% ║
|
|
41
|
+
║ ⚡ 摸鱼效率:██████████████░░░░ 85% ║
|
|
42
|
+
║ 🛡️ 隐蔽指数:██████████████████ 100% ║
|
|
43
|
+
║ ║
|
|
44
|
+
╚══════════════════════════════════════════════════════════════╝
|
|
45
|
+
`);
|
|
46
|
+
}
|
package/docs/i18n/excel2json.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
# 多语言
|
|
1
|
+
# 多语言 Excel 转 JSON 工具
|
|
2
2
|
|
|
3
|
-
该工具基于配置文件,实现将多语言
|
|
3
|
+
该工具基于配置文件,实现将多语言 Excel 文件转换为对应的 JSON 翻译文件,并支持语言检测和重复 Key 处理,方便多语言项目的词条管理与质量控制。
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -9,58 +9,58 @@
|
|
|
9
9
|
1. **配置文件读取与解析**
|
|
10
10
|
- 从本地 `setting.json` 文件读取国际化配置,包括默认语言、语言映射和语言长代码。
|
|
11
11
|
|
|
12
|
-
2. **
|
|
13
|
-
- 根据配置自动识别
|
|
12
|
+
2. **Excel 表头语言列匹配**
|
|
13
|
+
- 根据配置自动识别 Excel 表头中的语言列,支持大小写不敏感匹配和语言名称模糊匹配。
|
|
14
14
|
|
|
15
|
-
3. **
|
|
16
|
-
- 读取用户指定路径的
|
|
15
|
+
3. **Excel 文件读取与数据解析**
|
|
16
|
+
- 读取用户指定路径的 Excel 文件,提取第一个工作表的内容。
|
|
17
17
|
- 解析表头和数据行,提取多语言词条。
|
|
18
18
|
|
|
19
|
-
4. **重复
|
|
20
|
-
- 对默认语言列的
|
|
21
|
-
- 其他语言的
|
|
19
|
+
4. **重复 JSON Key 处理**
|
|
20
|
+
- 对默认语言列的 Key 进行去重处理,若存在重复,则在 Key 前添加随机生成的6位编码前缀,确保 JSON Key 唯一。
|
|
21
|
+
- 其他语言的 Key 也进行同样处理,避免冲突。
|
|
22
22
|
|
|
23
23
|
5. **批量语言检测**
|
|
24
24
|
- 将所有语言词条拼接成字符串,一次性调用语言检测接口,减少请求次数,提高检测效率。
|
|
25
25
|
- 解析检测结果,拆分到每条词条对应的错误信息。
|
|
26
26
|
|
|
27
|
-
6. **生成多语言
|
|
28
|
-
- 为每个语言生成对应的
|
|
27
|
+
6. **生成多语言 JSON 文件**
|
|
28
|
+
- 为每个语言生成对应的 JSON 翻译文件,默认语言文件不生成。
|
|
29
29
|
|
|
30
|
-
7. **生成语言检测结果
|
|
31
|
-
- 生成包含所有语言检测错误信息的
|
|
30
|
+
7. **生成语言检测结果 Excel 文件**
|
|
31
|
+
- 生成包含所有语言检测错误信息的 Excel 文件,方便查看和修正。
|
|
32
32
|
|
|
33
33
|
8. **命令行交互与日志记录**
|
|
34
|
-
- 通过命令行交互输入
|
|
34
|
+
- 通过命令行交互输入 Excel 文件路径。
|
|
35
35
|
- 详细日志记录执行过程、错误和警告,便于排查问题。
|
|
36
36
|
|
|
37
37
|
---
|
|
38
38
|
|
|
39
39
|
## 使用说明
|
|
40
40
|
|
|
41
|
-
1. 准备好符合格式的
|
|
41
|
+
1. 准备好符合格式的 Excel 文件,第一行为表头,包含语言列(如 `en`, `zh-CN` 等)。
|
|
42
42
|
2. 配置好 `setting.json`,包含国际化相关配置。
|
|
43
|
-
3. 运行工具,输入
|
|
44
|
-
4. 程序将自动解析
|
|
45
|
-
5. 结果文件输出在
|
|
43
|
+
3. 运行工具,输入 Excel 文件路径。
|
|
44
|
+
4. 程序将自动解析 Excel,生成多语言 JSON 文件和语言检测结果 Excel。
|
|
45
|
+
5. 结果文件输出在 Excel 文件所在目录的 `lang_时间戳` 文件夹中。
|
|
46
46
|
|
|
47
47
|
---
|
|
48
48
|
|
|
49
49
|
## 代码结构简述
|
|
50
50
|
|
|
51
|
-
- `formatKey` / `decodeKey`:处理重复
|
|
51
|
+
- `formatKey` / `decodeKey`:处理重复 Key,添加或去除随机编码前缀。
|
|
52
52
|
- `loadConfig`:读取并校验配置文件。
|
|
53
|
-
- `matchLangKey`:匹配
|
|
53
|
+
- `matchLangKey`:匹配 Excel 表头语言列。
|
|
54
54
|
- `batchCheckTexts` / `parseCheckResultPerEntry`:批量调用语言检测并解析结果。
|
|
55
|
-
- `excel2json`:主函数,完成
|
|
55
|
+
- `excel2json`:主函数,完成 Excel 读取、解析、语言检测、文件生成等流程。
|
|
56
56
|
|
|
57
57
|
---
|
|
58
58
|
|
|
59
59
|
## 备注
|
|
60
60
|
|
|
61
|
-
- 默认语言的
|
|
61
|
+
- 默认语言的 JSON 文件不会生成,默认语言词条作为 Key 使用。
|
|
62
62
|
- 语言检测依赖在线服务,若获取语言列表失败则使用本地配置。
|
|
63
|
-
- 重复
|
|
63
|
+
- 重复 Key 处理确保生成的 JSON 文件中不会有冲突的键名。
|
|
64
64
|
|
|
65
65
|
---
|
|
66
66
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "td-web-cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.16",
|
|
4
4
|
"description": "A CLI tool for efficiency",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -17,6 +17,9 @@
|
|
|
17
17
|
"format": "prettier --write \"src/**/*.{js,ts,tsx,json,md}\"",
|
|
18
18
|
"release": "node ./release.js"
|
|
19
19
|
},
|
|
20
|
+
"engines": {
|
|
21
|
+
"node": ">=20"
|
|
22
|
+
},
|
|
20
23
|
"keywords": [],
|
|
21
24
|
"author": "",
|
|
22
25
|
"license": "ISC",
|