td-octopus 0.1.16 → 0.1.18
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/cmds/storage.js +9 -0
- package/package.json +3 -2
- package/src/back/index.js +32 -14
- package/src/check/index.js +56 -58
- package/src/storage/index.js +35 -0
package/cmds/storage.js
ADDED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "td-octopus",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.18",
|
|
4
4
|
"description": "I18N tool",
|
|
5
5
|
"author": "Anthony Li",
|
|
6
6
|
"bin": {
|
|
@@ -27,7 +27,8 @@
|
|
|
27
27
|
"update-notifier": "^4.1.0",
|
|
28
28
|
"vue-template-compiler": "^2.6.14",
|
|
29
29
|
"xlsx": "0.16.9",
|
|
30
|
-
"yargs": "^15.3.1"
|
|
30
|
+
"yargs": "^15.3.1",
|
|
31
|
+
"eslint": "^8.15.0"
|
|
31
32
|
},
|
|
32
33
|
"keywords": [
|
|
33
34
|
"I18N",
|
package/src/back/index.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* @Author: 郑泳健
|
|
4
4
|
* @Date: 2022-06-01 13:56:18
|
|
5
5
|
* @LastEditors: 郑泳健
|
|
6
|
-
* @LastEditTime:
|
|
6
|
+
* @LastEditTime: 2025-11-11 10:10:55
|
|
7
7
|
*/
|
|
8
8
|
const path = require('path')
|
|
9
9
|
const fs = require('fs')
|
|
@@ -27,8 +27,6 @@ const TEMPLATE_INNER_REGEX = /I18N\.template\(([\s\S]*?})\)/g
|
|
|
27
27
|
// 匹配{}之间的内容
|
|
28
28
|
const JSON_KEY_REGEX = /{([\s\S]*?)}/g
|
|
29
29
|
|
|
30
|
-
// 匹配{}之间的value
|
|
31
|
-
const JSON_VALYR_REGEX = /(?<=: )[^,}]+/g
|
|
32
30
|
|
|
33
31
|
/**
|
|
34
32
|
* 获取需要back的所有文件目录
|
|
@@ -61,14 +59,39 @@ function getFilePaths() {
|
|
|
61
59
|
/**
|
|
62
60
|
* 获取I18N.template里面{}每个value对应的value
|
|
63
61
|
* @param {*} str {val1: h, val2: m, val3: s}
|
|
64
|
-
* @returns
|
|
62
|
+
* @returns obj
|
|
65
63
|
*/
|
|
66
64
|
function getTemplateValue(str) {
|
|
67
65
|
try {
|
|
68
|
-
const
|
|
69
|
-
|
|
66
|
+
const result = {};
|
|
67
|
+
const regex = /(\w+)\s*:\s*/g;
|
|
68
|
+
let match;
|
|
69
|
+
|
|
70
|
+
while ((match = regex.exec(objStr)) !== null) {
|
|
71
|
+
const key = match[1].trim();
|
|
72
|
+
let valueStart = regex.lastIndex;
|
|
73
|
+
let bracketCount = 0;
|
|
74
|
+
let valueEnd = valueStart;
|
|
75
|
+
|
|
76
|
+
for (let i = valueStart; i < objStr.length; i++) {
|
|
77
|
+
const char = objStr[i];
|
|
78
|
+
if (char === '(') bracketCount++;
|
|
79
|
+
if (char === ')') bracketCount--;
|
|
80
|
+
if ((char === ',' && bracketCount === 0) || (char === '}' && bracketCount === 0)) {
|
|
81
|
+
valueEnd = i;
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const value = objStr.slice(valueStart, valueEnd).trim();
|
|
87
|
+
result[key] = value;
|
|
88
|
+
|
|
89
|
+
regex.lastIndex = valueEnd + 1; // 继续匹配下一个
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return result;
|
|
70
93
|
} catch (e) {
|
|
71
|
-
throw e;
|
|
94
|
+
throw new Error(`获取I8N.template内的变量出错: ${e.message}`);
|
|
72
95
|
}
|
|
73
96
|
}
|
|
74
97
|
|
|
@@ -89,13 +112,8 @@ function transformTemplate(filePath, code, flatObj) {
|
|
|
89
112
|
let matchList = getValueByI18N(filePath, i, flatObj) || [];
|
|
90
113
|
matchText = matchList[0] && matchList[0]['value']
|
|
91
114
|
if (matchText) {
|
|
92
|
-
matchText = matchText.replace(/{(val\d+)}/g, (
|
|
93
|
-
|
|
94
|
-
throw new Error(`${filePath}文件中的 ${highlightText(i)} 转换有问题,请手动检查`)
|
|
95
|
-
}
|
|
96
|
-
const res = '${' + keys[0].trim() + '}'
|
|
97
|
-
keys.splice(0, 1)
|
|
98
|
-
return res
|
|
115
|
+
matchText = matchText.replace(/{(val\d+)}/g, (_, transKey) => {
|
|
116
|
+
return `\${${keys[transKey]}}`;
|
|
99
117
|
})
|
|
100
118
|
|
|
101
119
|
code = code.replace(i, '`' + matchText + '`')
|
package/src/check/index.js
CHANGED
|
@@ -3,19 +3,19 @@
|
|
|
3
3
|
* @Author: 郑泳健
|
|
4
4
|
* @Date: 2024-12-12 15:00:24
|
|
5
5
|
* @LastEditors: 郑泳健
|
|
6
|
-
* @LastEditTime: 2025-
|
|
6
|
+
* @LastEditTime: 2025-11-11 09:57:48
|
|
7
7
|
*/
|
|
8
|
-
const path = require('path')
|
|
9
|
-
const fs = require('fs')
|
|
10
|
-
const
|
|
11
|
-
const
|
|
12
|
-
const syncLang = require('../utils/syncLang')
|
|
13
|
-
const { flatObject, rewriteFiles, getFileKeyValueList
|
|
14
|
-
const {
|
|
15
|
-
|
|
16
|
-
const
|
|
8
|
+
const path = require('path');
|
|
9
|
+
const fs = require('fs');
|
|
10
|
+
const { parse } = require('@babel/parser');
|
|
11
|
+
const generate = require('@babel/generator').default;
|
|
12
|
+
const syncLang = require('../utils/syncLang');
|
|
13
|
+
const { flatObject, rewriteFiles, getFileKeyValueList } = require('../utils/translate');
|
|
14
|
+
const { autoImportJSFiles } = require('../utils/index');
|
|
15
|
+
|
|
16
|
+
const { ESLint } = require('eslint');
|
|
17
17
|
|
|
18
|
-
const
|
|
18
|
+
const ora = require('ora');
|
|
19
19
|
|
|
20
20
|
const spinner = ora('开始check');
|
|
21
21
|
|
|
@@ -23,9 +23,9 @@ function extractThreeLevelI18NKeys(code) {
|
|
|
23
23
|
// 匹配恰好三级的I18N键值(I18N.xxx.xxx.xxx)
|
|
24
24
|
// 使用正则表达式确保前面不是点,后面也不是点或字母数字下划线
|
|
25
25
|
const pattern = /(?<!\.)I18N\.[a-zA-Z0-9_]+\.[a-zA-Z0-9_]+\.[a-zA-Z0-9_]+(?![a-zA-Z0-9_\.])/g;
|
|
26
|
-
|
|
26
|
+
|
|
27
27
|
const matches = code.match(pattern) || [];
|
|
28
|
-
|
|
28
|
+
|
|
29
29
|
// 去重并返回
|
|
30
30
|
return [...new Set(matches)];
|
|
31
31
|
}
|
|
@@ -33,84 +33,82 @@ function extractThreeLevelI18NKeys(code) {
|
|
|
33
33
|
// 递归读取文件夹中所有 .js 文件内容
|
|
34
34
|
function readJsFiles(folderPath) {
|
|
35
35
|
let jsContent = '';
|
|
36
|
-
|
|
36
|
+
|
|
37
37
|
const files = fs.readdirSync(folderPath); // 读取文件夹内容
|
|
38
38
|
for (const file of files) {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
39
|
+
const fullPath = path.join(folderPath, file);
|
|
40
|
+
const stats = fs.statSync(fullPath); // 获取文件或文件夹状态
|
|
41
|
+
|
|
42
|
+
if (stats.isDirectory()) {
|
|
43
|
+
// 如果是文件夹,递归处理
|
|
44
|
+
jsContent += readJsFiles(fullPath);
|
|
45
|
+
} else if (path.extname(fullPath) === '.js') {
|
|
46
|
+
// 如果是 .js 文件,读取文件内容
|
|
47
|
+
let content = fs.readFileSync(fullPath, 'utf-8');
|
|
48
|
+
const ast = parse(source, { sourceType: 'module', plugins: ['jsx', 'typescript'] });
|
|
49
|
+
const output = generate(ast, { comments: false });
|
|
50
|
+
content = output.code;
|
|
51
|
+
jsContent += `\n/* File: ${fullPath} */\n${content}\n`;
|
|
52
|
+
}
|
|
50
53
|
}
|
|
51
|
-
|
|
54
|
+
|
|
52
55
|
return jsContent;
|
|
53
|
-
|
|
56
|
+
}
|
|
54
57
|
|
|
55
58
|
// 同步不同的语言包
|
|
56
59
|
function main() {
|
|
57
60
|
(async () => {
|
|
58
|
-
const distLang = Array.isArray(CONFIG.distLangs) ? CONFIG.distLangs : []
|
|
59
61
|
const zhCN = syncLang('zh-CN');
|
|
60
62
|
const zhCNFlat = flatObject(zhCN);
|
|
61
|
-
|
|
62
|
-
const keys = Object.keys(zhCNFlat)
|
|
63
|
-
const totalText = readJsFiles(path.resolve(process.cwd(), 'src'))
|
|
63
|
+
const totalText = readJsFiles(path.resolve(process.cwd(), 'src'));
|
|
64
64
|
const totalTranslateList = extractThreeLevelI18NKeys(totalText);
|
|
65
|
-
const zhCnKey = Object.keys(zhCNFlat)
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
return
|
|
65
|
+
const zhCnKey = Object.keys(zhCNFlat);
|
|
66
|
+
const lostKey = totalTranslateList.filter((item) => !zhCnKey.includes(item.replace('I18N.', '')));
|
|
67
|
+
fs.writeFileSync(path.resolve(process.cwd(), 'lostI18N.js'), JSON.stringify(lostKey, null, 4), 'utf-8');
|
|
68
|
+
|
|
69
|
+
if (!lostKey.length) {
|
|
70
|
+
spinner.succeed('查询完毕,无丢失');
|
|
71
|
+
return;
|
|
73
72
|
}
|
|
74
|
-
|
|
75
|
-
if (!fs.existsSync(path.resolve(
|
|
73
|
+
|
|
74
|
+
if (!fs.existsSync(path.resolve(__dirname, '../octopus/zh-CN.js'))) {
|
|
76
75
|
spinner.succeed(`查询完毕,共计丢失${lostKey.length}个,请在lostI18N.js中查看`);
|
|
77
|
-
spinner.warn('
|
|
76
|
+
spinner.warn('请先执行otp storage');
|
|
78
77
|
return;
|
|
79
78
|
}
|
|
80
79
|
spinner.start(`查询完毕,共计丢失${lostKey.length}个,开始同步开始`);
|
|
81
|
-
const
|
|
82
|
-
const
|
|
83
|
-
const zhFromFlat = flatObject(zhFrom);
|
|
84
|
-
const enFromFlat = flatObject(enFrom);
|
|
80
|
+
const zhFromFlat = JSON.parse(fs.readFileSync(path.resolve(__dirname, '../octopus/zh-CN.js'), 'utf-8'));
|
|
81
|
+
const enFromFlat = JSON.parse(fs.readFileSync(path.resolve(__dirname, '../octopus/en-US.js'), 'utf-8'));
|
|
85
82
|
|
|
86
83
|
const enUS = syncLang('en-US');
|
|
87
84
|
const enUSFlat = flatObject(enUS);
|
|
88
85
|
|
|
89
86
|
const zhCNResult = lostKey.reduce((total, item) => {
|
|
90
|
-
if(zhFromFlat[item.replace('I18N.', '')]){
|
|
91
|
-
total[item.replace('I18N.', '')] = zhFromFlat[item.replace('I18N.', '')]
|
|
87
|
+
if (zhFromFlat[item.replace('I18N.', '')]) {
|
|
88
|
+
total[item.replace('I18N.', '')] = zhFromFlat[item.replace('I18N.', '')];
|
|
92
89
|
}
|
|
93
90
|
return total;
|
|
94
|
-
}, zhCNFlat)
|
|
95
|
-
|
|
91
|
+
}, zhCNFlat);
|
|
92
|
+
|
|
96
93
|
const enCNResult = lostKey.reduce((total, item) => {
|
|
97
|
-
if(enFromFlat[item.replace('I18N.', '')]){
|
|
98
|
-
total[item.replace('I18N.', '')] = enFromFlat[item.replace('I18N.', '')]
|
|
94
|
+
if (enFromFlat[item.replace('I18N.', '')]) {
|
|
95
|
+
total[item.replace('I18N.', '')] = enFromFlat[item.replace('I18N.', '')];
|
|
99
96
|
}
|
|
100
97
|
return total;
|
|
101
|
-
}, enUSFlat)
|
|
98
|
+
}, enUSFlat);
|
|
102
99
|
|
|
103
100
|
rewriteFiles(getFileKeyValueList(zhCNResult), 'zh-CN');
|
|
104
101
|
rewriteFiles(getFileKeyValueList(enCNResult), 'en-US');
|
|
105
102
|
const cnJSON = fs.readFileSync(path.resolve(process.cwd(), '.octopus/zh-CN/index.js'), 'utf-8');
|
|
106
103
|
const enJSON = fs.readFileSync(path.resolve(process.cwd(), '.octopus/en-US/index.js'), 'utf-8');
|
|
107
104
|
|
|
108
|
-
autoImportJSFiles(path.resolve(process.cwd(), '.octopus/zh-CN'), cnJSON)
|
|
109
|
-
autoImportJSFiles(path.resolve(process.cwd(), '.octopus/en-US'), enJSON)
|
|
110
|
-
|
|
111
|
-
|
|
105
|
+
autoImportJSFiles(path.resolve(process.cwd(), '.octopus/zh-CN'), cnJSON);
|
|
106
|
+
autoImportJSFiles(path.resolve(process.cwd(), '.octopus/en-US'), enJSON);
|
|
107
|
+
fs.rmSync(path.resolve(__dirname, '../octopus'), { recursive: true, force: true });
|
|
108
|
+
spinner.succeed('同步完成,如果需要重新check,请先执行otp storage');
|
|
109
|
+
})();
|
|
112
110
|
}
|
|
113
111
|
|
|
114
112
|
module.exports = {
|
|
115
113
|
main
|
|
116
|
-
}
|
|
114
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @Descripttion: 将项目中用到的中英文存储到缓存中
|
|
3
|
+
* @Author: 郑泳健
|
|
4
|
+
* @Date: 2024-12-12 15:00:24
|
|
5
|
+
* @LastEditors: 郑泳健
|
|
6
|
+
* @LastEditTime: 2025-10-13 10:55:39
|
|
7
|
+
*/
|
|
8
|
+
const path = require('path');
|
|
9
|
+
const fs = require('fs');
|
|
10
|
+
const syncLang = require('../utils/syncLang');
|
|
11
|
+
const { flatObject } = require('../utils/translate');
|
|
12
|
+
const ora = require('ora');
|
|
13
|
+
|
|
14
|
+
const spinner = ora('开始check');
|
|
15
|
+
|
|
16
|
+
// 同步不同的语言包
|
|
17
|
+
function main() {
|
|
18
|
+
(async () => {
|
|
19
|
+
const zhCN = syncLang('zh-CN');
|
|
20
|
+
const zhCNFlat = flatObject(zhCN);
|
|
21
|
+
const enUS = syncLang('en-US');
|
|
22
|
+
const enUSFlat = flatObject(enUS);
|
|
23
|
+
const outpuDir = path.resolve(__dirname, '../octopus');
|
|
24
|
+
|
|
25
|
+
fs.mkdirSync(outpuDir, { recursive: true });
|
|
26
|
+
spinner.start('开始缓存');
|
|
27
|
+
fs.writeFileSync(path.resolve(outpuDir, 'zh-CN.js'), JSON.stringify(zhCNFlat, null, 2), 'utf-8');
|
|
28
|
+
fs.writeFileSync(path.resolve(outpuDir, 'en-US.js'), JSON.stringify(enUSFlat, null, 2), 'utf-8');
|
|
29
|
+
spinner.succeed('缓存完成');
|
|
30
|
+
})();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
module.exports = {
|
|
34
|
+
main
|
|
35
|
+
};
|