daodou-command 1.3.0 → 1.4.0

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.
Files changed (42) hide show
  1. package/.daodourc.example +85 -0
  2. package/.idea/UniappTool.xml +10 -0
  3. package/.idea/copilot.data.migration.agent.xml +6 -0
  4. package/.idea/copilot.data.migration.ask.xml +6 -0
  5. package/.idea/copilot.data.migration.ask2agent.xml +6 -0
  6. package/.idea/copilot.data.migration.edit.xml +6 -0
  7. package/.idea/daodou-command.iml +12 -0
  8. package/.idea/editorJumperProjectSettings.xml +6 -0
  9. package/.idea/modules.xml +8 -0
  10. package/.idea/vcs.xml +6 -0
  11. package/.idea/workspace.xml +85 -0
  12. package/CHANGELOG.md +15 -3
  13. package/README.md +45 -2
  14. package/lib/commands/config.js +57 -3
  15. package/lib/commands/lang.js +2 -1
  16. package/lib/translation/TranslationService.js +214 -0
  17. package/lib/translation/engines/BaseTranslator.js +90 -0
  18. package/lib/translation/engines/ali/AliTranslator.js +316 -0
  19. package/lib/translation/engines/ali/index.js +8 -0
  20. package/lib/translation/engines/baidu/BaiduTranslator.js +209 -0
  21. package/lib/translation/engines/baidu/index.js +8 -0
  22. package/lib/translation/engines/deepl/DeeplTranslator.js +234 -0
  23. package/lib/translation/engines/deepl/index.js +8 -0
  24. package/lib/translation/engines/google/GoogleTranslator.js +251 -0
  25. package/lib/translation/engines/google/index.js +8 -0
  26. package/lib/translation/engines/index.js +69 -0
  27. package/lib/translation/engines/microsoft/MicrosoftTranslator.js +190 -0
  28. package/lib/translation/engines/microsoft/index.js +6 -0
  29. package/lib/translation/engines/microsoft/services/EdgeAuthService.js +166 -0
  30. package/lib/translation/engines/microsoft/services/HttpClient.js +93 -0
  31. package/lib/translation/engines/microsoft/services/TranslatorService.js +167 -0
  32. package/lib/translation/engines/microsoft/types/index.js +147 -0
  33. package/lib/translation/engines/openai/OpenaiTranslator.js +363 -0
  34. package/lib/translation/engines/openai/index.js +8 -0
  35. package/lib/translation/engines/youdao/YoudaoTranslator.js +361 -0
  36. package/lib/translation/engines/youdao/index.js +8 -0
  37. package/lib/translation/index.js +10 -0
  38. package/lib/utils/config.js +99 -2
  39. package/lib/utils/translation.js +58 -100
  40. package/package.json +1 -3
  41. package/.daodourc +0 -25
  42. package/lib/utils/proxy-manager.js +0 -364
@@ -0,0 +1,361 @@
1
+ /**
2
+ * 有道翻译引擎实现
3
+ * 基于有道翻译API的付费翻译服务
4
+ */
5
+ const BaseTranslator = require('../BaseTranslator');
6
+ const axios = require('axios');
7
+ const crypto = require('crypto');
8
+
9
+ class YoudaoTranslator extends BaseTranslator {
10
+ constructor(config = {}) {
11
+ super(config);
12
+ this.name = 'Youdao Translator';
13
+ this.priority = 5;
14
+ this.intervalLimit = 1000; // 1秒间隔限制
15
+ this.contentLengthLimit = 2000; // 2KB内容长度限制
16
+
17
+ // 有道翻译API配置
18
+ this.baseUrl = 'https://openapi.youdao.com/api';
19
+ this.appId = config.appId || '';
20
+ this.appKey = config.appKey || '';
21
+ }
22
+
23
+ /**
24
+ * 获取翻译器名称
25
+ */
26
+ getName() {
27
+ return this.name;
28
+ }
29
+
30
+ /**
31
+ * 获取优先级
32
+ */
33
+ getPriority() {
34
+ return this.priority;
35
+ }
36
+
37
+ /**
38
+ * 检查翻译器是否可用
39
+ */
40
+ async isAvailable() {
41
+ if (!this.appId || !this.appKey) {
42
+ return false;
43
+ }
44
+
45
+ try {
46
+ // 尝试翻译一个简单的测试文本
47
+ const testResult = await this.translate('hello', 'en', 'zh');
48
+ return testResult && testResult.success;
49
+ } catch (error) {
50
+ return false;
51
+ }
52
+ }
53
+
54
+ /**
55
+ * 翻译文本
56
+ */
57
+ async translate(text, sourceLang, targetLang, options = {}) {
58
+ if (!text || !targetLang) {
59
+ throw new Error('文本和目标语言不能为空');
60
+ }
61
+
62
+ if (!this.appId || !this.appKey) {
63
+ throw new Error('有道翻译需要配置App ID和App Key');
64
+ }
65
+
66
+ return await this.withRetry(async () => {
67
+ try {
68
+ // 语言代码转换
69
+ const youdaoSourceLang = this.convertLangCode(sourceLang);
70
+ const youdaoTargetLang = this.convertLangCode(targetLang);
71
+
72
+ // 生成签名
73
+ const salt = Date.now().toString();
74
+ const curtime = Math.round(Date.now() / 1000).toString();
75
+ const signStr = this.appId + this.truncate(text) + salt + curtime + this.appKey;
76
+ const sign = crypto.createHash('sha256').update(signStr).digest('hex');
77
+
78
+ // 构建请求参数
79
+ const params = {
80
+ q: text,
81
+ from: youdaoSourceLang,
82
+ to: youdaoTargetLang,
83
+ appKey: this.appId,
84
+ salt: salt,
85
+ sign: sign,
86
+ signType: 'v3',
87
+ curtime: curtime
88
+ };
89
+
90
+ // 发送请求
91
+ const response = await axios.post(this.baseUrl, params, {
92
+ headers: {
93
+ 'Content-Type': 'application/x-www-form-urlencoded'
94
+ },
95
+ timeout: 10000
96
+ });
97
+
98
+ if (!response.data) {
99
+ throw new Error('有道翻译返回数据为空');
100
+ }
101
+
102
+ const result = response.data;
103
+
104
+ // 检查错误码
105
+ if (result.errorCode && result.errorCode !== '0') {
106
+ const errorMsg = this.getErrorMessage(result.errorCode);
107
+ throw new Error(`有道翻译错误 (${result.errorCode}): ${errorMsg}`);
108
+ }
109
+
110
+ if (!result.translation || !Array.isArray(result.translation)) {
111
+ throw new Error('有道翻译结果格式错误');
112
+ }
113
+
114
+ const translation = result.translation[0];
115
+ if (!translation) {
116
+ throw new Error('有道翻译结果为空');
117
+ }
118
+
119
+ return {
120
+ text: translation || text,
121
+ sourceLang: sourceLang,
122
+ targetLang: targetLang,
123
+ engine: this.name,
124
+ success: true,
125
+ confidence: 1.0,
126
+ alternatives: []
127
+ };
128
+
129
+ } catch (error) {
130
+ if (error.response) {
131
+ const status = error.response.status;
132
+ if (status === 429) {
133
+ throw new Error('有道翻译请求过于频繁,请稍后重试');
134
+ } else if (status === 403) {
135
+ throw new Error('有道翻译API密钥无效');
136
+ }
137
+ }
138
+ throw new Error(`有道翻译失败: ${error.message}`);
139
+ }
140
+ });
141
+ }
142
+
143
+ /**
144
+ * 截断文本(有道API要求)
145
+ */
146
+ truncate(text) {
147
+ if (text.length <= 20) {
148
+ return text;
149
+ }
150
+ return text.substring(0, 10) + text.length + text.substring(text.length - 10);
151
+ }
152
+
153
+ /**
154
+ * 获取支持的语言列表
155
+ */
156
+ async getSupportedLanguages() {
157
+ // 有道支持的语言列表
158
+ return [
159
+ 'auto', 'zh-CHS', 'zh-CHT', 'en', 'ja', 'ko', 'fr', 'es', 'pt', 'it', 'ru', 'vi', 'de', 'ar', 'id', 'af',
160
+ 'bs', 'bg', 'ca', 'cs', 'cy', 'da', 'el', 'et', 'fa', 'fi', 'fr', 'gl', 'gu', 'he', 'hi', 'hr', 'ht', 'hu',
161
+ 'is', 'ja', 'ko', 'lt', 'lv', 'ms', 'mt', 'mww', 'nl', 'no', 'pl', 'pt', 'ro', 'ru', 'sk', 'sl', 'sr', 'sv',
162
+ 'sw', 'th', 'tr', 'uk', 'ur', 'vi', 'zh-CHS', 'zh-CHT'
163
+ ];
164
+ }
165
+
166
+ /**
167
+ * 语言代码转换
168
+ * 将标准语言代码转换为有道翻译支持的语言代码
169
+ */
170
+ convertLangCode(langCode) {
171
+ const langMap = {
172
+ 'zh': 'zh-CHS',
173
+ 'zh-CN': 'zh-CHS',
174
+ 'zh-TW': 'zh-CHT',
175
+ 'en': 'en',
176
+ 'ja': 'ja',
177
+ 'ko': 'ko',
178
+ 'fr': 'fr',
179
+ 'es': 'es',
180
+ 'pt': 'pt',
181
+ 'it': 'it',
182
+ 'ru': 'ru',
183
+ 'vi': 'vi',
184
+ 'de': 'de',
185
+ 'ar': 'ar',
186
+ 'id': 'id',
187
+ 'af': 'af',
188
+ 'bs': 'bs',
189
+ 'bg': 'bg',
190
+ 'ca': 'ca',
191
+ 'cs': 'cs',
192
+ 'cy': 'cy',
193
+ 'da': 'da',
194
+ 'el': 'el',
195
+ 'et': 'et',
196
+ 'fa': 'fa',
197
+ 'fi': 'fi',
198
+ 'gl': 'gl',
199
+ 'gu': 'gu',
200
+ 'he': 'he',
201
+ 'hi': 'hi',
202
+ 'hr': 'hr',
203
+ 'ht': 'ht',
204
+ 'hu': 'hu',
205
+ 'is': 'is',
206
+ 'lt': 'lt',
207
+ 'lv': 'lv',
208
+ 'ms': 'ms',
209
+ 'mt': 'mt',
210
+ 'mww': 'mww',
211
+ 'nl': 'nl',
212
+ 'no': 'no',
213
+ 'pl': 'pl',
214
+ 'ro': 'ro',
215
+ 'sk': 'sk',
216
+ 'sl': 'sl',
217
+ 'sr': 'sr',
218
+ 'sv': 'sv',
219
+ 'sw': 'sw',
220
+ 'th': 'th',
221
+ 'tr': 'tr',
222
+ 'uk': 'uk',
223
+ 'ur': 'ur',
224
+ 'auto': 'auto'
225
+ };
226
+
227
+ return langMap[langCode] || langCode.toLowerCase();
228
+ }
229
+
230
+ /**
231
+ * 获取错误信息
232
+ */
233
+ getErrorMessage(errorCode) {
234
+ const errorMessages = {
235
+ '101': '缺少必填的参数',
236
+ '102': '不支持的语言类型',
237
+ '103': '翻译文本过长',
238
+ '104': '不支持的API类型',
239
+ '105': '不支持的签名类型',
240
+ '106': '不支持的响应类型',
241
+ '107': '不支持的传输协议',
242
+ '108': 'appKey无效',
243
+ '109': 'batchLog格式不正确',
244
+ '110': '无相关服务的有效实例',
245
+ '111': '开发者账号无效',
246
+ '201': '请求被拒绝',
247
+ '202': '请求被拒绝',
248
+ '203': '请求被拒绝',
249
+ '301': '词典查询失败',
250
+ '302': '翻译查询失败',
251
+ '303': '服务端的其他异常',
252
+ '401': '账户余额不足',
253
+ '411': '访问频率受限',
254
+ '412': '请求长度受限',
255
+ '1001': '无效的apikey',
256
+ '1002': 'apikey已过期',
257
+ '1003': 'apikey已过期',
258
+ '1004': 'apikey已过期',
259
+ '1005': 'apikey已过期',
260
+ '1006': 'apikey已过期',
261
+ '1007': 'apikey已过期',
262
+ '1008': 'apikey已过期',
263
+ '1009': 'apikey已过期',
264
+ '1010': 'apikey已过期',
265
+ '1011': 'apikey已过期',
266
+ '1012': 'apikey已过期',
267
+ '1013': 'apikey已过期',
268
+ '1014': 'apikey已过期',
269
+ '1015': 'apikey已过期',
270
+ '1016': 'apikey已过期',
271
+ '1017': 'apikey已过期',
272
+ '1018': 'apikey已过期',
273
+ '1019': 'apikey已过期',
274
+ '1020': 'apikey已过期',
275
+ '1021': 'apikey已过期',
276
+ '1022': 'apikey已过期',
277
+ '1023': 'apikey已过期',
278
+ '1024': 'apikey已过期',
279
+ '1025': 'apikey已过期',
280
+ '1026': 'apikey已过期',
281
+ '1027': 'apikey已过期',
282
+ '1028': 'apikey已过期',
283
+ '1029': 'apikey已过期',
284
+ '1030': 'apikey已过期',
285
+ '1031': 'apikey已过期',
286
+ '1032': 'apikey已过期',
287
+ '1033': 'apikey已过期',
288
+ '1034': 'apikey已过期',
289
+ '1035': 'apikey已过期',
290
+ '1036': 'apikey已过期',
291
+ '1037': 'apikey已过期',
292
+ '1038': 'apikey已过期',
293
+ '1039': 'apikey已过期',
294
+ '1040': 'apikey已过期',
295
+ '1041': 'apikey已过期',
296
+ '1042': 'apikey已过期',
297
+ '1043': 'apikey已过期',
298
+ '1044': 'apikey已过期',
299
+ '1045': 'apikey已过期',
300
+ '1046': 'apikey已过期',
301
+ '1047': 'apikey已过期',
302
+ '1048': 'apikey已过期',
303
+ '1049': 'apikey已过期',
304
+ '1050': 'apikey已过期',
305
+ '1051': 'apikey已过期',
306
+ '1052': 'apikey已过期',
307
+ '1053': 'apikey已过期',
308
+ '1054': 'apikey已过期',
309
+ '1055': 'apikey已过期',
310
+ '1056': 'apikey已过期',
311
+ '1057': 'apikey已过期',
312
+ '1058': 'apikey已过期',
313
+ '1059': 'apikey已过期',
314
+ '1060': 'apikey已过期',
315
+ '1061': 'apikey已过期',
316
+ '1062': 'apikey已过期',
317
+ '1063': 'apikey已过期',
318
+ '1064': 'apikey已过期',
319
+ '1065': 'apikey已过期',
320
+ '1066': 'apikey已过期',
321
+ '1067': 'apikey已过期',
322
+ '1068': 'apikey已过期',
323
+ '1069': 'apikey已过期',
324
+ '1070': 'apikey已过期',
325
+ '1071': 'apikey已过期',
326
+ '1072': 'apikey已过期',
327
+ '1073': 'apikey已过期',
328
+ '1074': 'apikey已过期',
329
+ '1075': 'apikey已过期',
330
+ '1076': 'apikey已过期',
331
+ '1077': 'apikey已过期',
332
+ '1078': 'apikey已过期',
333
+ '1079': 'apikey已过期',
334
+ '1080': 'apikey已过期',
335
+ '1081': 'apikey已过期',
336
+ '1082': 'apikey已过期',
337
+ '1083': 'apikey已过期',
338
+ '1084': 'apikey已过期',
339
+ '1085': 'apikey已过期',
340
+ '1086': 'apikey已过期',
341
+ '1087': 'apikey已过期',
342
+ '1088': 'apikey已过期',
343
+ '1089': 'apikey已过期',
344
+ '1090': 'apikey已过期',
345
+ '1091': 'apikey已过期',
346
+ '1092': 'apikey已过期',
347
+ '1093': 'apikey已过期',
348
+ '1094': 'apikey已过期',
349
+ '1095': 'apikey已过期',
350
+ '1096': 'apikey已过期',
351
+ '1097': 'apikey已过期',
352
+ '1098': 'apikey已过期',
353
+ '1099': 'apikey已过期',
354
+ '1100': 'apikey已过期'
355
+ };
356
+
357
+ return errorMessages[errorCode] || '未知错误';
358
+ }
359
+ }
360
+
361
+ module.exports = YoudaoTranslator;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * 有道翻译引擎注册
3
+ */
4
+ const YoudaoTranslator = require('./YoudaoTranslator');
5
+
6
+ module.exports = {
7
+ YoudaoTranslator
8
+ };
@@ -0,0 +1,10 @@
1
+ /**
2
+ * 翻译服务统一入口
3
+ */
4
+ const TranslationService = require('./TranslationService');
5
+
6
+ module.exports = {
7
+ TranslationService,
8
+ // 便捷方法
9
+ createTranslationService: (config = {}) => new TranslationService(config)
10
+ };
@@ -206,7 +206,64 @@ class ConfigManager {
206
206
  lang: {
207
207
  defaultLang: "en",
208
208
  defaultDir: "./public/locales",
209
- fileName: "common.json"
209
+ fileName: "common.json",
210
+
211
+ // 翻译引擎配置
212
+ translation: {
213
+ // 默认翻译引擎 (microsoft, google, baidu, ali, youdao, deepl, openai)
214
+ defaultEngine: "microsoft",
215
+
216
+ // 引擎优先级列表(按顺序尝试)
217
+ enginePriority: ["microsoft", "google", "baidu", "ali", "youdao", "deepl", "openai"],
218
+
219
+ // 各引擎API配置
220
+ engines: {
221
+ // 微软翻译(免费,无需配置)
222
+ microsoft: {
223
+ enabled: true
224
+ },
225
+
226
+ // Google翻译(免费,无需配置)
227
+ google: {
228
+ enabled: true
229
+ },
230
+
231
+ // 百度翻译(需要API密钥)
232
+ baidu: {
233
+ enabled: false,
234
+ appId: "", // 百度翻译API App ID
235
+ appKey: "" // 百度翻译API App Key
236
+ },
237
+
238
+ // 阿里云翻译(需要API密钥)
239
+ ali: {
240
+ enabled: false,
241
+ accessKeyId: "", // 阿里云AccessKey ID
242
+ accessKeySecret: "" // 阿里云AccessKey Secret
243
+ },
244
+
245
+ // 有道翻译(需要API密钥)
246
+ youdao: {
247
+ enabled: false,
248
+ appId: "", // 有道翻译API App ID
249
+ appKey: "" // 有道翻译API App Key
250
+ },
251
+
252
+ // DeepL翻译(需要API密钥)
253
+ deepl: {
254
+ enabled: false,
255
+ apiKey: "" // DeepL API Key
256
+ },
257
+
258
+ // OpenAI翻译(需要API密钥)
259
+ openai: {
260
+ enabled: false,
261
+ apiKey: "", // OpenAI API Key
262
+ model: "gpt-3.5-turbo", // 使用的模型
263
+ baseUrl: "https://api.openai.com/v1" // API基础URL
264
+ }
265
+ }
266
+ }
210
267
  }
211
268
  }`;
212
269
 
@@ -218,7 +275,20 @@ class ConfigManager {
218
275
  lang: {
219
276
  defaultLang: "en",
220
277
  defaultDir: "./public/locales",
221
- fileName: "common.json"
278
+ fileName: "common.json",
279
+ translation: {
280
+ defaultEngine: "microsoft",
281
+ enginePriority: ["microsoft", "google", "baidu", "ali", "youdao", "deepl", "openai"],
282
+ engines: {
283
+ microsoft: { enabled: true },
284
+ google: { enabled: true },
285
+ baidu: { enabled: false, appId: "", appKey: "" },
286
+ ali: { enabled: false, accessKeyId: "", accessKeySecret: "" },
287
+ youdao: { enabled: false, appId: "", appKey: "" },
288
+ deepl: { enabled: false, apiKey: "" },
289
+ openai: { enabled: false, apiKey: "", model: "gpt-3.5-turbo", baseUrl: "https://api.openai.com/v1" }
290
+ }
291
+ }
222
292
  }
223
293
  };
224
294
 
@@ -330,6 +400,33 @@ class ConfigManager {
330
400
  return this.getCommandConfig('lang');
331
401
  }
332
402
 
403
+ /**
404
+ * 获取翻译配置
405
+ */
406
+ getTranslationConfig() {
407
+ const langConfig = this.getCommandConfig('lang');
408
+ return langConfig?.translation || {};
409
+ }
410
+
411
+ /**
412
+ * 获取指定引擎的配置
413
+ */
414
+ getEngineConfig(engineName) {
415
+ const translationConfig = this.getTranslationConfig();
416
+ return translationConfig?.engines?.[engineName] || {};
417
+ }
418
+
419
+ /**
420
+ * 获取启用的引擎列表(按enginePriority顺序)
421
+ */
422
+ getEnabledEngines() {
423
+ const translationConfig = this.getTranslationConfig();
424
+ const engines = translationConfig?.engines || {};
425
+ const enginePriority = translationConfig?.enginePriority || [];
426
+
427
+ return enginePriority.filter(engineName => engines[engineName]?.enabled);
428
+ }
429
+
333
430
  /**
334
431
  * 获取Jenkins配置(向后兼容)
335
432
  */