vite-plugin-ai-i18n 1.0.3 → 1.0.5
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/index.js +163 -123
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +109 -93
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1,20 +1,50 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
Object.defineProperty
|
|
4
|
-
|
|
5
|
-
var
|
|
6
|
-
var
|
|
7
|
-
var
|
|
8
|
-
var
|
|
9
|
-
var
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
10
29
|
|
|
11
|
-
|
|
30
|
+
// src/index.ts
|
|
31
|
+
var index_exports = {};
|
|
32
|
+
__export(index_exports, {
|
|
33
|
+
default: () => index_default,
|
|
34
|
+
vitePluginAII18n: () => vitePluginAII18n
|
|
35
|
+
});
|
|
36
|
+
module.exports = __toCommonJS(index_exports);
|
|
37
|
+
var import_fs4 = __toESM(require("fs"));
|
|
38
|
+
var import_path4 = __toESM(require("path"));
|
|
39
|
+
var import_picocolors3 = __toESM(require("picocolors"));
|
|
12
40
|
|
|
13
|
-
|
|
14
|
-
var
|
|
15
|
-
var
|
|
41
|
+
// src/scanner.ts
|
|
42
|
+
var import_fs2 = __toESM(require("fs"));
|
|
43
|
+
var import_path2 = __toESM(require("path"));
|
|
16
44
|
|
|
17
|
-
// src/
|
|
45
|
+
// src/utils.ts
|
|
46
|
+
var import_fs = __toESM(require("fs"));
|
|
47
|
+
var import_path = __toESM(require("path"));
|
|
18
48
|
async function glob(patterns, excludePatterns) {
|
|
19
49
|
const results = [];
|
|
20
50
|
const cwd = process.cwd();
|
|
@@ -23,7 +53,7 @@ async function glob(patterns, excludePatterns) {
|
|
|
23
53
|
results.push(...files);
|
|
24
54
|
}
|
|
25
55
|
return results.filter((file) => {
|
|
26
|
-
const relativePath =
|
|
56
|
+
const relativePath = import_path.default.relative(cwd, file);
|
|
27
57
|
return !excludePatterns.some((p) => matchGlob(relativePath, p));
|
|
28
58
|
});
|
|
29
59
|
}
|
|
@@ -34,20 +64,20 @@ async function matchPattern(pattern, cwd) {
|
|
|
34
64
|
if (hasGlobstar) {
|
|
35
65
|
const baseDir = parts.slice(0, parts.indexOf("**")).join("/") || ".";
|
|
36
66
|
const filePattern = parts.slice(parts.indexOf("**") + 1).join("/");
|
|
37
|
-
await walkDir(
|
|
67
|
+
await walkDir(import_path.default.join(cwd, baseDir), filePattern, results);
|
|
38
68
|
} else {
|
|
39
|
-
const fullPath =
|
|
40
|
-
if (
|
|
69
|
+
const fullPath = import_path.default.join(cwd, pattern);
|
|
70
|
+
if (import_fs.default.existsSync(fullPath)) {
|
|
41
71
|
results.push(fullPath);
|
|
42
72
|
}
|
|
43
73
|
}
|
|
44
74
|
return results;
|
|
45
75
|
}
|
|
46
76
|
async function walkDir(dir, pattern, results) {
|
|
47
|
-
if (!
|
|
48
|
-
const entries =
|
|
77
|
+
if (!import_fs.default.existsSync(dir)) return;
|
|
78
|
+
const entries = import_fs.default.readdirSync(dir, { withFileTypes: true });
|
|
49
79
|
for (const entry of entries) {
|
|
50
|
-
const fullPath =
|
|
80
|
+
const fullPath = import_path.default.join(dir, entry.name);
|
|
51
81
|
if (entry.isDirectory()) {
|
|
52
82
|
if (entry.name === "node_modules" || entry.name.startsWith(".")) {
|
|
53
83
|
continue;
|
|
@@ -98,9 +128,9 @@ var I18nScanner = class {
|
|
|
98
128
|
* 扫描单个文件
|
|
99
129
|
*/
|
|
100
130
|
scanFile(filePath) {
|
|
101
|
-
if (!
|
|
102
|
-
const content =
|
|
103
|
-
const ext =
|
|
131
|
+
if (!import_fs2.default.existsSync(filePath)) return [];
|
|
132
|
+
const content = import_fs2.default.readFileSync(filePath, "utf-8");
|
|
133
|
+
const ext = import_path2.default.extname(filePath);
|
|
104
134
|
let texts = [];
|
|
105
135
|
if (ext === ".vue") {
|
|
106
136
|
texts = this.scanVueFile(content);
|
|
@@ -261,83 +291,88 @@ var I18nScanner = class {
|
|
|
261
291
|
isValidText(text) {
|
|
262
292
|
const debug = this.options.debug;
|
|
263
293
|
if (text.length < 2) {
|
|
264
|
-
if (debug) console.log(`[
|
|
294
|
+
if (debug) console.log(`[过滤] "${text}" - 原因: 文本太短`);
|
|
265
295
|
return false;
|
|
266
296
|
}
|
|
267
297
|
if (!/[\u4e00-\u9fa5]/.test(text)) {
|
|
268
|
-
if (debug) console.log(`[
|
|
298
|
+
if (debug) console.log(`[过滤] "${text}" - 原因: 不包含中文`);
|
|
269
299
|
return false;
|
|
270
300
|
}
|
|
271
301
|
if (/^\s*$/.test(text)) {
|
|
272
|
-
if (debug) console.log(`[
|
|
302
|
+
if (debug) console.log(`[过滤] "${text}" - 原因: 纯空格`);
|
|
273
303
|
return false;
|
|
274
304
|
}
|
|
275
305
|
if (/^\$t\(|^t\(|^i18n\.|_uni_app$|^[a-z_]+_[a-z_]+$/.test(text)) {
|
|
276
|
-
if (debug) console.log(`[
|
|
306
|
+
if (debug) console.log(`[过滤] "${text}" - 原因: i18n key`);
|
|
277
307
|
return false;
|
|
278
308
|
}
|
|
279
309
|
if (/^[⚠️❌✅🔍📝💡🎯🚀🔧📊]/.test(text)) {
|
|
280
|
-
if (debug) console.log(`[
|
|
310
|
+
if (debug) console.log(`[过滤] "${text}" - 原因: 系统提示`);
|
|
281
311
|
return false;
|
|
282
312
|
}
|
|
283
313
|
if (/\.(json|js|ts|vue|md|txt|html|css|jsx|tsx)\s*(文件|不存在|已|错误)/.test(
|
|
284
314
|
text
|
|
285
315
|
)) {
|
|
286
|
-
if (debug) console.log(`[
|
|
316
|
+
if (debug) console.log(`[过滤] "${text}" - 原因: 技术术语`);
|
|
287
317
|
return false;
|
|
288
318
|
}
|
|
289
319
|
if (/^[a-zA-Z0-9_\-\.]+\s*(文件|不存在|错误|失败)/.test(text)) {
|
|
290
|
-
if (debug) console.log(`[
|
|
320
|
+
if (debug) console.log(`[过滤] "${text}" - 原因: 技术错误信息`);
|
|
291
321
|
return false;
|
|
292
322
|
}
|
|
293
323
|
if (/^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(text)) {
|
|
294
|
-
if (debug) console.log(`[
|
|
324
|
+
if (debug) console.log(`[过滤] "${text}" - 原因: 变量名`);
|
|
295
325
|
return false;
|
|
296
326
|
}
|
|
297
327
|
if (/^\/[a-zA-Z0-9_\-\/]*$/.test(text)) {
|
|
298
|
-
if (debug) console.log(`[
|
|
328
|
+
if (debug) console.log(`[过滤] "${text}" - 原因: 路径`);
|
|
299
329
|
return false;
|
|
300
330
|
}
|
|
301
331
|
if (/^https?:\/\//.test(text)) {
|
|
302
|
-
if (debug) console.log(`[
|
|
332
|
+
if (debug) console.log(`[过滤] "${text}" - 原因: URL`);
|
|
303
333
|
return false;
|
|
304
334
|
}
|
|
305
335
|
if (/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/.test(text)) {
|
|
306
|
-
if (debug) console.log(`[
|
|
336
|
+
if (debug) console.log(`[过滤] "${text}" - 原因: 邮箱`);
|
|
307
337
|
return false;
|
|
308
338
|
}
|
|
309
339
|
if (/^\d+$/.test(text)) {
|
|
310
|
-
if (debug) console.log(`[
|
|
340
|
+
if (debug) console.log(`[过滤] "${text}" - 原因: 纯数字`);
|
|
311
341
|
return false;
|
|
312
342
|
}
|
|
313
343
|
if (/^\d{4}-\d{2}-\d{2}/.test(text)) {
|
|
314
|
-
if (debug) console.log(`[
|
|
344
|
+
if (debug) console.log(`[过滤] "${text}" - 原因: 日期`);
|
|
315
345
|
return false;
|
|
316
346
|
}
|
|
317
347
|
if (/^(const|let|var|function|class|import|export|return)\s/.test(text)) {
|
|
318
|
-
if (debug) console.log(`[
|
|
348
|
+
if (debug) console.log(`[过滤] "${text}" - 原因: 代码片段`);
|
|
319
349
|
return false;
|
|
320
350
|
}
|
|
321
351
|
if (text.length > 100) {
|
|
322
|
-
if (debug) console.log(`[
|
|
352
|
+
if (debug) console.log(`[过滤] "${text}" - 原因: 文本过长`);
|
|
323
353
|
return false;
|
|
324
354
|
}
|
|
325
355
|
const specialCharCount = (text.match(/[^\u4e00-\u9fa5a-zA-Z0-9\s,。!?、;:""''()《》]/g) || []).length;
|
|
326
356
|
if (specialCharCount > text.length * 0.3) {
|
|
327
357
|
if (debug)
|
|
328
|
-
console.log(`[
|
|
358
|
+
console.log(`[过滤] "${text}" - 原因: 特殊字符过多 (${specialCharCount})`);
|
|
329
359
|
return false;
|
|
330
360
|
}
|
|
331
|
-
if (debug) console.log(`[
|
|
361
|
+
if (debug) console.log(`[保留] "${text}"`);
|
|
332
362
|
return true;
|
|
333
363
|
}
|
|
334
364
|
};
|
|
365
|
+
|
|
366
|
+
// src/translator.ts
|
|
367
|
+
var import_openai = require("@langchain/openai");
|
|
368
|
+
var import_messages = require("@langchain/core/messages");
|
|
369
|
+
var import_picocolors = __toESM(require("picocolors"));
|
|
335
370
|
var I18nTranslator = class {
|
|
336
371
|
constructor(options) {
|
|
337
372
|
this.llm = null;
|
|
338
373
|
this.options = options;
|
|
339
374
|
if (options.apiKey) {
|
|
340
|
-
this.llm = new
|
|
375
|
+
this.llm = new import_openai.ChatOpenAI({
|
|
341
376
|
openAIApiKey: options.apiKey,
|
|
342
377
|
configuration: { baseURL: options.apiUrl },
|
|
343
378
|
modelName: options.model,
|
|
@@ -351,7 +386,7 @@ var I18nTranslator = class {
|
|
|
351
386
|
*/
|
|
352
387
|
async translate(texts, sourceLocale, targetLocale, existingTranslations) {
|
|
353
388
|
if (!this.llm) {
|
|
354
|
-
console.warn(
|
|
389
|
+
console.warn(import_picocolors.default.yellow("⚠️ 未配置 API Key,跳过翻译"));
|
|
355
390
|
const results2 = /* @__PURE__ */ new Map();
|
|
356
391
|
for (const [file, fileTexts] of texts) {
|
|
357
392
|
const textMap = /* @__PURE__ */ new Map();
|
|
@@ -374,19 +409,19 @@ var I18nTranslator = class {
|
|
|
374
409
|
textsToTranslate.push(text);
|
|
375
410
|
}
|
|
376
411
|
});
|
|
377
|
-
console.log(
|
|
378
|
-
console.log(`
|
|
412
|
+
console.log(import_picocolors.default.blue("📊 翻译统计:"));
|
|
413
|
+
console.log(` 总计: ${import_picocolors.default.cyan(uniqueTexts.length.toString())} 条`);
|
|
379
414
|
console.log(
|
|
380
|
-
`
|
|
415
|
+
` ✅ 已有: ${import_picocolors.default.green(cachedTranslations.size.toString())} 条`
|
|
381
416
|
);
|
|
382
417
|
console.log(
|
|
383
|
-
`
|
|
418
|
+
` 🆕 新增: ${import_picocolors.default.yellow(textsToTranslate.length.toString())} 条`
|
|
384
419
|
);
|
|
385
420
|
try {
|
|
386
421
|
let newTranslations = [];
|
|
387
422
|
if (textsToTranslate.length > 0) {
|
|
388
|
-
console.log(
|
|
389
|
-
|
|
423
|
+
console.log(import_picocolors.default.cyan(`
|
|
424
|
+
🤖 正在翻译新增文本...`));
|
|
390
425
|
newTranslations = await this.batchTranslate(
|
|
391
426
|
textsToTranslate,
|
|
392
427
|
sourceLocale,
|
|
@@ -406,7 +441,7 @@ var I18nTranslator = class {
|
|
|
406
441
|
}
|
|
407
442
|
return results;
|
|
408
443
|
} catch (error) {
|
|
409
|
-
console.error(
|
|
444
|
+
console.error(import_picocolors.default.red("❌ 翻译失败:"), error.message);
|
|
410
445
|
const results2 = /* @__PURE__ */ new Map();
|
|
411
446
|
for (const [file, fileTexts] of texts) {
|
|
412
447
|
const textMap = /* @__PURE__ */ new Map();
|
|
@@ -456,8 +491,8 @@ var I18nTranslator = class {
|
|
|
456
491
|
results.push(...translated);
|
|
457
492
|
const progress = Math.min(i + batchSize, texts.length);
|
|
458
493
|
console.log(
|
|
459
|
-
|
|
460
|
-
`
|
|
494
|
+
import_picocolors.default.gray(
|
|
495
|
+
` 📊 翻译进度: ${import_picocolors.default.cyan(progress.toString())}/${import_picocolors.default.cyan(
|
|
461
496
|
texts.length.toString()
|
|
462
497
|
)}`
|
|
463
498
|
)
|
|
@@ -470,19 +505,19 @@ var I18nTranslator = class {
|
|
|
470
505
|
*/
|
|
471
506
|
async translateBatch(texts, sourceLocale, targetLocale) {
|
|
472
507
|
const localeName = this.getLocaleName(targetLocale);
|
|
473
|
-
const systemPrompt = new
|
|
474
|
-
|
|
508
|
+
const systemPrompt = new import_messages.SystemMessage(
|
|
509
|
+
`你是专业的软件本地化翻译专家。请将以下${this.getLocaleName(
|
|
475
510
|
sourceLocale
|
|
476
|
-
)}
|
|
477
|
-
|
|
478
|
-
1.
|
|
479
|
-
2.
|
|
480
|
-
3.
|
|
481
|
-
4.
|
|
482
|
-
5.
|
|
483
|
-
6.
|
|
511
|
+
)}文本翻译成${localeName}。
|
|
512
|
+
要求:
|
|
513
|
+
1. 保持专业术语的准确性
|
|
514
|
+
2. 翻译要自然流畅,符合目标语言习惯
|
|
515
|
+
3. 保留原文中的变量占位符(如 {name}、%s 等)
|
|
516
|
+
4. 每行一个翻译,与输入顺序严格对应
|
|
517
|
+
5. 只输出翻译结果,不要解释
|
|
518
|
+
6. 如果原文包含换行,翻译也保持相同的换行`
|
|
484
519
|
);
|
|
485
|
-
const userPrompt = new
|
|
520
|
+
const userPrompt = new import_messages.HumanMessage(
|
|
486
521
|
texts.map((t, i) => `${i + 1}. ${t}`).join("\n")
|
|
487
522
|
);
|
|
488
523
|
const response = await this.llm.invoke([systemPrompt, userPrompt]);
|
|
@@ -504,21 +539,26 @@ var I18nTranslator = class {
|
|
|
504
539
|
*/
|
|
505
540
|
getLocaleName(locale) {
|
|
506
541
|
const names = {
|
|
507
|
-
"zh-CN": "
|
|
508
|
-
"zh-TW": "
|
|
509
|
-
"en-US": "
|
|
510
|
-
"ja-JP": "
|
|
511
|
-
"ko-KR": "
|
|
512
|
-
"fr-FR": "
|
|
513
|
-
"de-DE": "
|
|
514
|
-
"es-ES": "
|
|
515
|
-
"pt-BR": "
|
|
516
|
-
"ru-RU": "
|
|
517
|
-
"ar-SA": "
|
|
542
|
+
"zh-CN": "简体中文",
|
|
543
|
+
"zh-TW": "繁体中文",
|
|
544
|
+
"en-US": "英语",
|
|
545
|
+
"ja-JP": "日语",
|
|
546
|
+
"ko-KR": "韩语",
|
|
547
|
+
"fr-FR": "法语",
|
|
548
|
+
"de-DE": "德语",
|
|
549
|
+
"es-ES": "西班牙语",
|
|
550
|
+
"pt-BR": "葡萄牙语",
|
|
551
|
+
"ru-RU": "俄语",
|
|
552
|
+
"ar-SA": "阿拉伯语"
|
|
518
553
|
};
|
|
519
554
|
return names[locale] || locale;
|
|
520
555
|
}
|
|
521
556
|
};
|
|
557
|
+
|
|
558
|
+
// src/generator.ts
|
|
559
|
+
var import_fs3 = __toESM(require("fs"));
|
|
560
|
+
var import_path3 = __toESM(require("path"));
|
|
561
|
+
var import_picocolors2 = __toESM(require("picocolors"));
|
|
522
562
|
var I18nGenerator = class {
|
|
523
563
|
constructor(options) {
|
|
524
564
|
this.options = options;
|
|
@@ -528,16 +568,16 @@ var I18nGenerator = class {
|
|
|
528
568
|
*/
|
|
529
569
|
async generate(texts, locale) {
|
|
530
570
|
const { localesDir } = this.options;
|
|
531
|
-
if (!
|
|
532
|
-
|
|
571
|
+
if (!import_fs3.default.existsSync(localesDir)) {
|
|
572
|
+
import_fs3.default.mkdirSync(localesDir, { recursive: true });
|
|
533
573
|
}
|
|
534
|
-
const filePath =
|
|
574
|
+
const filePath = import_path3.default.join(localesDir, `${locale}.json`);
|
|
535
575
|
let existing = {};
|
|
536
|
-
if (
|
|
576
|
+
if (import_fs3.default.existsSync(filePath)) {
|
|
537
577
|
try {
|
|
538
|
-
existing = JSON.parse(
|
|
578
|
+
existing = JSON.parse(import_fs3.default.readFileSync(filePath, "utf-8"));
|
|
539
579
|
} catch (e) {
|
|
540
|
-
console.warn(
|
|
580
|
+
console.warn(import_picocolors2.default.yellow(`⚠️ 无法解析现有语言文件: ${filePath}`));
|
|
541
581
|
}
|
|
542
582
|
}
|
|
543
583
|
const translations = { ...existing };
|
|
@@ -555,10 +595,10 @@ var I18nGenerator = class {
|
|
|
555
595
|
obj[key] = translations[key];
|
|
556
596
|
return obj;
|
|
557
597
|
}, {});
|
|
558
|
-
|
|
559
|
-
console.log(
|
|
598
|
+
import_fs3.default.writeFileSync(filePath, JSON.stringify(sorted, null, 2), "utf-8");
|
|
599
|
+
console.log(import_picocolors2.default.green(`✅ 已更新 ${import_picocolors2.default.cyan(locale)} 语言文件: ${import_picocolors2.default.gray(filePath)}`));
|
|
560
600
|
if (newCount > 0) {
|
|
561
|
-
console.log(
|
|
601
|
+
console.log(import_picocolors2.default.gray(` 新增 ${import_picocolors2.default.yellow(newCount.toString())} 条翻译`));
|
|
562
602
|
}
|
|
563
603
|
}
|
|
564
604
|
/**
|
|
@@ -566,16 +606,16 @@ var I18nGenerator = class {
|
|
|
566
606
|
*/
|
|
567
607
|
async generateTranslated(originalTexts, translations, locale) {
|
|
568
608
|
const { localesDir } = this.options;
|
|
569
|
-
if (!
|
|
570
|
-
|
|
609
|
+
if (!import_fs3.default.existsSync(localesDir)) {
|
|
610
|
+
import_fs3.default.mkdirSync(localesDir, { recursive: true });
|
|
571
611
|
}
|
|
572
|
-
const filePath =
|
|
612
|
+
const filePath = import_path3.default.join(localesDir, `${locale}.json`);
|
|
573
613
|
let existing = {};
|
|
574
|
-
if (
|
|
614
|
+
if (import_fs3.default.existsSync(filePath)) {
|
|
575
615
|
try {
|
|
576
|
-
existing = JSON.parse(
|
|
616
|
+
existing = JSON.parse(import_fs3.default.readFileSync(filePath, "utf-8"));
|
|
577
617
|
} catch (e) {
|
|
578
|
-
console.warn(
|
|
618
|
+
console.warn(import_picocolors2.default.yellow(`⚠️ 无法解析现有语言文件: ${filePath}`));
|
|
579
619
|
}
|
|
580
620
|
}
|
|
581
621
|
const translationsObj = { ...existing };
|
|
@@ -596,13 +636,13 @@ var I18nGenerator = class {
|
|
|
596
636
|
obj[key] = translationsObj[key];
|
|
597
637
|
return obj;
|
|
598
638
|
}, {});
|
|
599
|
-
|
|
600
|
-
console.log(
|
|
639
|
+
import_fs3.default.writeFileSync(filePath, JSON.stringify(sorted, null, 2), "utf-8");
|
|
640
|
+
console.log(import_picocolors2.default.green(`✅ 已更新 ${import_picocolors2.default.cyan(locale)} 语言文件: ${import_picocolors2.default.gray(filePath)}`));
|
|
601
641
|
if (newCount > 0) {
|
|
602
|
-
console.log(
|
|
642
|
+
console.log(import_picocolors2.default.gray(` ✨ 新增 ${import_picocolors2.default.yellow(newCount.toString())} 条翻译`));
|
|
603
643
|
}
|
|
604
644
|
if (skippedCount > 0) {
|
|
605
|
-
console.log(
|
|
645
|
+
console.log(import_picocolors2.default.gray(` ⏭️ 跳过 ${import_picocolors2.default.blue(skippedCount.toString())} 条已有翻译`));
|
|
606
646
|
}
|
|
607
647
|
}
|
|
608
648
|
/**
|
|
@@ -610,12 +650,12 @@ var I18nGenerator = class {
|
|
|
610
650
|
*/
|
|
611
651
|
loadExistingTranslations(locale) {
|
|
612
652
|
const { localesDir } = this.options;
|
|
613
|
-
const filePath =
|
|
614
|
-
if (
|
|
653
|
+
const filePath = import_path3.default.join(localesDir, `${locale}.json`);
|
|
654
|
+
if (import_fs3.default.existsSync(filePath)) {
|
|
615
655
|
try {
|
|
616
|
-
return JSON.parse(
|
|
656
|
+
return JSON.parse(import_fs3.default.readFileSync(filePath, "utf-8"));
|
|
617
657
|
} catch (e) {
|
|
618
|
-
console.warn(
|
|
658
|
+
console.warn(import_picocolors2.default.yellow(`⚠️ 无法解析现有语言文件: ${filePath}`));
|
|
619
659
|
}
|
|
620
660
|
}
|
|
621
661
|
return {};
|
|
@@ -668,52 +708,52 @@ function vitePluginAII18n(options = {}) {
|
|
|
668
708
|
name: "vite-plugin-ai-i18n",
|
|
669
709
|
enforce: "pre",
|
|
670
710
|
configResolved(config) {
|
|
671
|
-
const fullLocalesDir =
|
|
672
|
-
if (!
|
|
673
|
-
|
|
711
|
+
const fullLocalesDir = import_path4.default.resolve(config.root, localesDir);
|
|
712
|
+
if (!import_fs4.default.existsSync(fullLocalesDir)) {
|
|
713
|
+
import_fs4.default.mkdirSync(fullLocalesDir, { recursive: true });
|
|
674
714
|
}
|
|
675
715
|
const allLocales = [defaultLocale, ...targetLocales];
|
|
676
716
|
for (const locale of allLocales) {
|
|
677
|
-
const filePath =
|
|
678
|
-
if (!
|
|
679
|
-
|
|
717
|
+
const filePath = import_path4.default.join(fullLocalesDir, `${locale}.json`);
|
|
718
|
+
if (!import_fs4.default.existsSync(filePath)) {
|
|
719
|
+
import_fs4.default.writeFileSync(filePath, "{}", "utf-8");
|
|
680
720
|
console.log(
|
|
681
|
-
|
|
682
|
-
|
|
721
|
+
import_picocolors3.default.green(
|
|
722
|
+
`✅ 已生成 ${import_picocolors3.default.cyan(locale)} 语言文件: ${import_picocolors3.default.gray(
|
|
683
723
|
`src\\locales\\${locale}.json`
|
|
684
724
|
)}`
|
|
685
725
|
)
|
|
686
726
|
);
|
|
687
727
|
}
|
|
688
728
|
}
|
|
689
|
-
console.log(
|
|
690
|
-
console.log(
|
|
691
|
-
console.log(
|
|
692
|
-
console.log(
|
|
693
|
-
console.log(
|
|
729
|
+
console.log(import_picocolors3.default.cyan("\n🌍 AI 国际化助手已启动..."));
|
|
730
|
+
console.log(`📂 语言文件目录: ${import_picocolors3.default.yellow(localesDir)}`);
|
|
731
|
+
console.log(`🔤 默认语言: ${import_picocolors3.default.cyan(defaultLocale)}`);
|
|
732
|
+
console.log(`🎯 目标语言: ${import_picocolors3.default.cyan(targetLocales.join(", "))}`);
|
|
733
|
+
console.log(`🔍 自动扫描: ${autoScan ? import_picocolors3.default.green("✅") : import_picocolors3.default.red("❌")}`);
|
|
694
734
|
console.log(
|
|
695
|
-
|
|
735
|
+
`🤖 自动翻译: ${autoTranslate ? import_picocolors3.default.green("✅") : import_picocolors3.default.red("❌")}`
|
|
696
736
|
);
|
|
697
737
|
console.log(
|
|
698
|
-
|
|
738
|
+
`🔑 API Key: ${apiKey ? import_picocolors3.default.green("已配置") : import_picocolors3.default.yellow("未配置")}
|
|
699
739
|
`
|
|
700
740
|
);
|
|
701
741
|
},
|
|
702
742
|
async buildStart() {
|
|
703
743
|
if (!autoScan) return;
|
|
704
|
-
console.log(
|
|
744
|
+
console.log(import_picocolors3.default.cyan("🔍 正在扫描中文文本...\n"));
|
|
705
745
|
scannedTexts = await scanner.scan();
|
|
706
746
|
const totalTexts = Array.from(scannedTexts.values()).flat().length;
|
|
707
747
|
console.log(
|
|
708
|
-
|
|
748
|
+
import_picocolors3.default.blue(`📝 发现 ${import_picocolors3.default.yellow(totalTexts.toString())} 条待翻译文本
|
|
709
749
|
`)
|
|
710
750
|
);
|
|
711
751
|
if (totalTexts === 0) return;
|
|
712
752
|
await generator.generate(scannedTexts, defaultLocale);
|
|
713
753
|
if (autoTranslate && apiKey) {
|
|
714
754
|
for (const locale of targetLocales) {
|
|
715
|
-
console.log(
|
|
716
|
-
|
|
755
|
+
console.log(import_picocolors3.default.cyan(`
|
|
756
|
+
🌐 正在翻译到 ${import_picocolors3.default.yellow(locale)}...`));
|
|
717
757
|
const existingTranslations = generator.loadExistingTranslations(locale);
|
|
718
758
|
const translations = await translator.translate(
|
|
719
759
|
scannedTexts,
|
|
@@ -728,7 +768,7 @@ function vitePluginAII18n(options = {}) {
|
|
|
728
768
|
);
|
|
729
769
|
}
|
|
730
770
|
}
|
|
731
|
-
console.log(
|
|
771
|
+
console.log(import_picocolors3.default.green("\n✨ 国际化处理完成\n"));
|
|
732
772
|
},
|
|
733
773
|
// 监听文件变化,增量更新
|
|
734
774
|
async handleHotUpdate({ file, server }) {
|
|
@@ -736,10 +776,10 @@ function vitePluginAII18n(options = {}) {
|
|
|
736
776
|
if (!file.match(/\.(vue|ts|tsx)$/)) return;
|
|
737
777
|
if (file.includes("node_modules") || file.includes(localesDir)) return;
|
|
738
778
|
console.log(`
|
|
739
|
-
|
|
779
|
+
🔄 检测到文件变化: ${file}`);
|
|
740
780
|
const texts = scanner.scanFile(file);
|
|
741
781
|
if (texts.length > 0) {
|
|
742
|
-
console.log(
|
|
782
|
+
console.log(`📝 发现 ${texts.length} 条新文本`);
|
|
743
783
|
scannedTexts.set(file, texts);
|
|
744
784
|
await generator.generate(scannedTexts, defaultLocale);
|
|
745
785
|
if (autoTranslate && apiKey) {
|
|
@@ -764,8 +804,8 @@ function vitePluginAII18n(options = {}) {
|
|
|
764
804
|
};
|
|
765
805
|
}
|
|
766
806
|
var index_default = vitePluginAII18n;
|
|
767
|
-
|
|
768
|
-
exports
|
|
769
|
-
|
|
770
|
-
|
|
807
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
808
|
+
0 && (module.exports = {
|
|
809
|
+
vitePluginAII18n
|
|
810
|
+
});
|
|
771
811
|
//# sourceMappingURL=index.js.map
|