@thor123141245r/ai-translate 0.0.0 → 1.0.1
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 +161 -71
- package/README.zh-CN.md +194 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +77 -0
- package/dist/cli.js.map +1 -1
- package/dist/i18n/align.d.ts +3 -0
- package/dist/i18n/align.d.ts.map +1 -0
- package/dist/i18n/align.js +46 -0
- package/dist/i18n/align.js.map +1 -0
- package/dist/i18n/cache.d.ts +14 -0
- package/dist/i18n/cache.d.ts.map +1 -0
- package/dist/i18n/cache.js +36 -0
- package/dist/i18n/cache.js.map +1 -0
- package/dist/i18n/command.d.ts +7 -0
- package/dist/i18n/command.d.ts.map +1 -0
- package/dist/i18n/command.js +84 -0
- package/dist/i18n/command.js.map +1 -0
- package/dist/i18n/extract.d.ts +7 -0
- package/dist/i18n/extract.d.ts.map +1 -0
- package/dist/i18n/extract.js +24 -0
- package/dist/i18n/extract.js.map +1 -0
- package/dist/i18n/json-path.d.ts +7 -0
- package/dist/i18n/json-path.d.ts.map +1 -0
- package/dist/i18n/json-path.js +61 -0
- package/dist/i18n/json-path.js.map +1 -0
- package/dist/i18n/parse.d.ts +6 -0
- package/dist/i18n/parse.d.ts.map +1 -0
- package/dist/i18n/parse.js +44 -0
- package/dist/i18n/parse.js.map +1 -0
- package/dist/i18n/placeholders.d.ts +7 -0
- package/dist/i18n/placeholders.d.ts.map +1 -0
- package/dist/i18n/placeholders.js +44 -0
- package/dist/i18n/placeholders.js.map +1 -0
- package/dist/i18n/prompt.d.ts +13 -0
- package/dist/i18n/prompt.d.ts.map +1 -0
- package/dist/i18n/prompt.js +37 -0
- package/dist/i18n/prompt.js.map +1 -0
- package/dist/i18n/translate.d.ts +29 -0
- package/dist/i18n/translate.d.ts.map +1 -0
- package/dist/i18n/translate.js +199 -0
- package/dist/i18n/translate.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/package.json +6 -1
- package/.agentdocs/code-changes/2026-01-22/AI/347/277/273/350/257/221/345/231/250TS/345/256/236/347/216/260-/345/256/236/347/216/260.md +0 -22
- package/.agentdocs/code-changes/2026-01-23/CLI/345/210/206/345/217/221-npx/345/256/236/347/216/260.md +0 -18
- package/.agentdocs/code-changes/2026-01-23/sora-watermask-remover-/345/233/275/351/231/205/345/214/226/347/277/273/350/257/221-/345/256/236/347/216/260.md +0 -37
- package/.agentdocs/code-changes/2026-01-23//351/205/215/347/275/256/350/257/273/345/217/226-/347/216/257/345/242/203/345/217/230/351/207/217/344/274/230/345/205/210-/345/256/236/347/216/260.md +0 -22
- package/.agentdocs/plans/2026-01-22/AI/347/277/273/350/257/221/345/231/250TS/345/256/236/347/216/260-/344/274/230/345/214/226/346/226/271/346/241/210.md +0 -67
- package/.agentdocs/plans/2026-01-23/CLI/345/210/206/345/217/221-npx/346/226/271/346/241/210.md +0 -60
- package/.agentdocs/plans/2026-01-23/sora-watermask-remover-/345/233/275/351/231/205/345/214/226/347/277/273/350/257/221-/344/274/230/345/214/226/346/226/271/346/241/210.md +0 -51
- package/.agentdocs/plans/2026-01-23//351/205/215/347/275/256/350/257/273/345/217/226-/347/216/257/345/242/203/345/217/230/351/207/217/344/274/230/345/205/210-/344/274/230/345/214/226/346/226/271/346/241/210.md +0 -80
- package/SKILL.md +0 -103
- package/src/asyncTransform.ts +0 -31
- package/src/bin/ai-translate.ts +0 -5
- package/src/cli.ts +0 -313
- package/src/index.ts +0 -9
- package/src/logger.ts +0 -3
- package/src/model.ts +0 -139
- package/src/prompt.ts +0 -71
- package/src/split.ts +0 -111
- package/src/utils.ts +0 -15
- package/tsconfig.json +0 -19
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { isPlainObject } from './json-path.js';
|
|
2
|
+
export const alignStructure = (source, target, mode) => {
|
|
3
|
+
if (Array.isArray(source)) {
|
|
4
|
+
const tgt = Array.isArray(target) ? target : [];
|
|
5
|
+
const out = [];
|
|
6
|
+
for (let i = 0; i < source.length; i++) {
|
|
7
|
+
out[i] = alignStructure(source[i], tgt[i], mode);
|
|
8
|
+
}
|
|
9
|
+
// arrays are treated as schema-bound; "prune" for arrays is implicit
|
|
10
|
+
return out;
|
|
11
|
+
}
|
|
12
|
+
if (isPlainObject(source)) {
|
|
13
|
+
const tgt = isPlainObject(target) ? target : {};
|
|
14
|
+
const out = {};
|
|
15
|
+
for (const [k, v] of Object.entries(source)) {
|
|
16
|
+
out[k] = alignStructure(v, tgt[k], mode);
|
|
17
|
+
}
|
|
18
|
+
if (mode !== 'prune') {
|
|
19
|
+
// keep target-only keys (user may have custom keys)
|
|
20
|
+
for (const [k, v] of Object.entries(tgt)) {
|
|
21
|
+
if (!(k in out))
|
|
22
|
+
out[k] = v;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return out;
|
|
26
|
+
}
|
|
27
|
+
// leaf: keep existing target scalar if type matches; otherwise copy source
|
|
28
|
+
if (typeof source === 'string') {
|
|
29
|
+
if (typeof target === 'string')
|
|
30
|
+
return target;
|
|
31
|
+
// In fill mode, missing values should stay empty so they get translated.
|
|
32
|
+
if (mode === 'fill')
|
|
33
|
+
return '';
|
|
34
|
+
return source;
|
|
35
|
+
}
|
|
36
|
+
if (typeof source === 'number') {
|
|
37
|
+
return typeof target === 'number' ? target : source;
|
|
38
|
+
}
|
|
39
|
+
if (typeof source === 'boolean') {
|
|
40
|
+
return typeof target === 'boolean' ? target : source;
|
|
41
|
+
}
|
|
42
|
+
if (source === null)
|
|
43
|
+
return null;
|
|
44
|
+
return target ?? source;
|
|
45
|
+
};
|
|
46
|
+
//# sourceMappingURL=align.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"align.js","sourceRoot":"","sources":["../../src/i18n/align.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AAI9C,MAAM,CAAC,MAAM,cAAc,GAAG,CAC5B,MAAe,EACf,MAAe,EACf,IAAe,EACN,EAAE;IACX,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAC1B,MAAM,GAAG,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAA;QAC/C,MAAM,GAAG,GAAc,EAAE,CAAA;QACzB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACvC,GAAG,CAAC,CAAC,CAAC,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAA;QAClD,CAAC;QACD,qEAAqE;QACrE,OAAO,GAAG,CAAA;IACZ,CAAC;IAED,IAAI,aAAa,CAAC,MAAM,CAAC,EAAE,CAAC;QAC1B,MAAM,GAAG,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAA;QAC/C,MAAM,GAAG,GAA4B,EAAE,CAAA;QAEvC,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YAC5C,GAAG,CAAC,CAAC,CAAC,GAAG,cAAc,CAAC,CAAC,EAAG,GAA+B,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAA;QACvE,CAAC;QAED,IAAI,IAAI,KAAK,OAAO,EAAE,CAAC;YACrB,oDAAoD;YACpD,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;gBACzC,IAAI,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC;oBAAE,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAA;YAC7B,CAAC;QACH,CAAC;QAED,OAAO,GAAG,CAAA;IACZ,CAAC;IAED,2EAA2E;IAC3E,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;QAC/B,IAAI,OAAO,MAAM,KAAK,QAAQ;YAAE,OAAO,MAAM,CAAA;QAC7C,yEAAyE;QACzE,IAAI,IAAI,KAAK,MAAM;YAAE,OAAO,EAAE,CAAA;QAC9B,OAAO,MAAM,CAAA;IACf,CAAC;IACD,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;QAC/B,OAAO,OAAO,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAA;IACrD,CAAC;IACD,IAAI,OAAO,MAAM,KAAK,SAAS,EAAE,CAAC;QAChC,OAAO,OAAO,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAA;IACtD,CAAC;IACD,IAAI,MAAM,KAAK,IAAI;QAAE,OAAO,IAAI,CAAA;IAEhC,OAAO,MAAM,IAAI,MAAM,CAAA;AACzB,CAAC,CAAA"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export type CacheDataV1 = {
|
|
2
|
+
v: 1;
|
|
3
|
+
entries: Record<string, string>;
|
|
4
|
+
};
|
|
5
|
+
export declare class TranslationCache {
|
|
6
|
+
private readonly _file?;
|
|
7
|
+
private readonly _map;
|
|
8
|
+
constructor(file?: string);
|
|
9
|
+
load(): void;
|
|
10
|
+
get(key: string): string | undefined;
|
|
11
|
+
set(key: string, value: string): void;
|
|
12
|
+
save(): void;
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../src/i18n/cache.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,WAAW,GAAG;IACxB,CAAC,EAAE,CAAC,CAAA;IACJ,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAChC,CAAA;AAID,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAQ;IAC/B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAA4B;gBAErC,IAAI,CAAC,EAAE,MAAM;IAIzB,IAAI;IAWJ,GAAG,CAAC,GAAG,EAAE,MAAM;IAIf,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM;IAI9B,IAAI;CAKL"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
const empty = { v: 1, entries: {} };
|
|
3
|
+
export class TranslationCache {
|
|
4
|
+
_file;
|
|
5
|
+
_map = new Map();
|
|
6
|
+
constructor(file) {
|
|
7
|
+
this._file = file;
|
|
8
|
+
}
|
|
9
|
+
load() {
|
|
10
|
+
if (!this._file)
|
|
11
|
+
return;
|
|
12
|
+
if (!fs.existsSync(this._file))
|
|
13
|
+
return;
|
|
14
|
+
const raw = fs.readFileSync(this._file, 'utf-8');
|
|
15
|
+
const parsed = JSON.parse(raw);
|
|
16
|
+
if (!parsed || parsed.v !== 1 || typeof parsed.entries !== 'object')
|
|
17
|
+
return;
|
|
18
|
+
for (const [k, v] of Object.entries(parsed.entries)) {
|
|
19
|
+
if (typeof v === 'string')
|
|
20
|
+
this._map.set(k, v);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
get(key) {
|
|
24
|
+
return this._map.get(key);
|
|
25
|
+
}
|
|
26
|
+
set(key, value) {
|
|
27
|
+
this._map.set(key, value);
|
|
28
|
+
}
|
|
29
|
+
save() {
|
|
30
|
+
if (!this._file)
|
|
31
|
+
return;
|
|
32
|
+
const data = { ...empty, entries: Object.fromEntries(this._map.entries()) };
|
|
33
|
+
fs.writeFileSync(this._file, JSON.stringify(data, null, 2) + '\n', 'utf-8');
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.js","sourceRoot":"","sources":["../../src/i18n/cache.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAA;AAOxB,MAAM,KAAK,GAAgB,EAAE,CAAC,EAAE,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAA;AAEhD,MAAM,OAAO,gBAAgB;IACV,KAAK,CAAS;IACd,IAAI,GAAG,IAAI,GAAG,EAAkB,CAAA;IAEjD,YAAY,IAAa;QACvB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAA;IACnB,CAAC;IAED,IAAI;QACF,IAAI,CAAC,IAAI,CAAC,KAAK;YAAE,OAAM;QACvB,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC;YAAE,OAAM;QACtC,MAAM,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,CAAC,CAAA;QAChD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAgB,CAAA;QAC7C,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,CAAC,KAAK,CAAC,IAAI,OAAO,MAAM,CAAC,OAAO,KAAK,QAAQ;YAAE,OAAM;QAC3E,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC;YACpD,IAAI,OAAO,CAAC,KAAK,QAAQ;gBAAE,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;QAChD,CAAC;IACH,CAAC;IAED,GAAG,CAAC,GAAW;QACb,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;IAC3B,CAAC;IAED,GAAG,CAAC,GAAW,EAAE,KAAa;QAC5B,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAA;IAC3B,CAAC;IAED,IAAI;QACF,IAAI,CAAC,IAAI,CAAC,KAAK;YAAE,OAAM;QACvB,MAAM,IAAI,GAAgB,EAAE,GAAG,KAAK,EAAE,OAAO,EAAE,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,EAAE,CAAA;QACxF,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,OAAO,CAAC,CAAA;IAC7E,CAAC;CACF"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { BaseChatModel } from '@langchain/core/language_models/chat_models';
|
|
2
|
+
export declare const runI18nCommand: (opts: {
|
|
3
|
+
console: Pick<typeof console, "log" | "error">;
|
|
4
|
+
model: BaseChatModel;
|
|
5
|
+
argvOpts: Record<string, unknown>;
|
|
6
|
+
}) => Promise<void>;
|
|
7
|
+
//# sourceMappingURL=command.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"command.d.ts","sourceRoot":"","sources":["../../src/i18n/command.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6CAA6C,CAAA;AA4BhF,eAAO,MAAM,cAAc,GAAU,MAAM;IACzC,OAAO,EAAE,IAAI,CAAC,OAAO,OAAO,EAAE,KAAK,GAAG,OAAO,CAAC,CAAA;IAC9C,KAAK,EAAE,aAAa,CAAA;IACpB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAClC,kBA2DA,CAAA"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { translateI18nDir } from './translate.js';
|
|
4
|
+
const splitTargets = (raw) => {
|
|
5
|
+
if (typeof raw !== 'string')
|
|
6
|
+
return [];
|
|
7
|
+
return raw
|
|
8
|
+
.split(/[,\s]+/g)
|
|
9
|
+
.map((s) => s.trim())
|
|
10
|
+
.filter(Boolean);
|
|
11
|
+
};
|
|
12
|
+
const inferTargetsFromDir = (baseDir, sourceLang) => {
|
|
13
|
+
if (!fs.existsSync(baseDir))
|
|
14
|
+
return [];
|
|
15
|
+
const entries = fs.readdirSync(baseDir, { withFileTypes: true });
|
|
16
|
+
const langs = [];
|
|
17
|
+
for (const e of entries) {
|
|
18
|
+
if (!e.isFile())
|
|
19
|
+
continue;
|
|
20
|
+
if (!e.name.endsWith('.json'))
|
|
21
|
+
continue;
|
|
22
|
+
if (e.name.startsWith('.'))
|
|
23
|
+
continue;
|
|
24
|
+
const lang = e.name.replace(/\.json$/i, '');
|
|
25
|
+
if (!lang)
|
|
26
|
+
continue;
|
|
27
|
+
if (lang === sourceLang)
|
|
28
|
+
continue;
|
|
29
|
+
langs.push(lang);
|
|
30
|
+
}
|
|
31
|
+
return langs.sort();
|
|
32
|
+
};
|
|
33
|
+
export const runI18nCommand = async (opts) => {
|
|
34
|
+
const baseDir = String(opts.argvOpts.base || '');
|
|
35
|
+
if (!baseDir) {
|
|
36
|
+
throw new Error('missing --base DIR');
|
|
37
|
+
}
|
|
38
|
+
const resolvedBaseDir = path.resolve(process.cwd(), baseDir);
|
|
39
|
+
const sourceLang = String(opts.argvOpts.source || 'en');
|
|
40
|
+
const mode = String(opts.argvOpts.mode || 'fill');
|
|
41
|
+
if (!['fill', 'overwrite', 'prune'].includes(mode)) {
|
|
42
|
+
throw new Error('invalid --mode, expected fill|overwrite|prune');
|
|
43
|
+
}
|
|
44
|
+
const targets = splitTargets(opts.argvOpts.targets);
|
|
45
|
+
const inferredTargets = targets.length
|
|
46
|
+
? targets
|
|
47
|
+
: inferTargetsFromDir(resolvedBaseDir, sourceLang);
|
|
48
|
+
if (!inferredTargets.length) {
|
|
49
|
+
throw new Error('missing --targets, and no existing target *.json files were found');
|
|
50
|
+
}
|
|
51
|
+
const dryRun = Boolean(opts.argvOpts.dry);
|
|
52
|
+
const fileName = typeof opts.argvOpts.file === 'string' ? String(opts.argvOpts.file) : undefined;
|
|
53
|
+
const batchMaxItems = opts.argvOpts.batchMaxItems ? Number(opts.argvOpts.batchMaxItems) : undefined;
|
|
54
|
+
const batchMaxChars = opts.argvOpts.batchMaxChars ? Number(opts.argvOpts.batchMaxChars) : undefined;
|
|
55
|
+
const cacheFile = typeof opts.argvOpts.cache === 'string' && String(opts.argvOpts.cache).trim()
|
|
56
|
+
? path.resolve(resolvedBaseDir, String(opts.argvOpts.cache))
|
|
57
|
+
: path.resolve(resolvedBaseDir, '.ai-translate.cache.json');
|
|
58
|
+
const options = {
|
|
59
|
+
baseDir: resolvedBaseDir,
|
|
60
|
+
sourceLang,
|
|
61
|
+
targets: inferredTargets,
|
|
62
|
+
mode,
|
|
63
|
+
dryRun,
|
|
64
|
+
fileName,
|
|
65
|
+
batchMaxItems,
|
|
66
|
+
batchMaxChars,
|
|
67
|
+
cacheFile
|
|
68
|
+
};
|
|
69
|
+
const stats = await translateI18nDir({ model: opts.model, options });
|
|
70
|
+
for (const s of stats) {
|
|
71
|
+
opts.console.log([
|
|
72
|
+
`[i18n] target=${s.targetLang}`,
|
|
73
|
+
`total=${s.totalStrings}`,
|
|
74
|
+
`skipExisting=${s.skippedExisting}`,
|
|
75
|
+
`cache=${s.usedCache}`,
|
|
76
|
+
`toTranslate=${s.toTranslate}`,
|
|
77
|
+
`translated=${s.translated}`,
|
|
78
|
+
`failed=${s.failed}`,
|
|
79
|
+
dryRun ? 'dryRun=true' : 'dryRun=false',
|
|
80
|
+
`out=${s.targetFile}`
|
|
81
|
+
].join(' '));
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
//# sourceMappingURL=command.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"command.js","sourceRoot":"","sources":["../../src/i18n/command.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extract.d.ts","sourceRoot":"","sources":["../../src/i18n/extract.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAG9C,MAAM,MAAM,UAAU,GAAG;IACvB,IAAI,EAAE,QAAQ,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;CACd,CAAA;AAED,eAAO,MAAM,kBAAkB,GAAI,MAAM,OAAO,KAAG,UAAU,EAuB5D,CAAA"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { isPlainObject } from './json-path.js';
|
|
2
|
+
export const extractLeafStrings = (root) => {
|
|
3
|
+
const out = [];
|
|
4
|
+
const walk = (node, path) => {
|
|
5
|
+
if (typeof node === 'string') {
|
|
6
|
+
out.push({ path, value: node });
|
|
7
|
+
return;
|
|
8
|
+
}
|
|
9
|
+
if (Array.isArray(node)) {
|
|
10
|
+
for (let i = 0; i < node.length; i++) {
|
|
11
|
+
walk(node[i], path.concat(i));
|
|
12
|
+
}
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
if (isPlainObject(node)) {
|
|
16
|
+
for (const [k, v] of Object.entries(node)) {
|
|
17
|
+
walk(v, path.concat(k));
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
walk(root, []);
|
|
22
|
+
return out;
|
|
23
|
+
};
|
|
24
|
+
//# sourceMappingURL=extract.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extract.js","sourceRoot":"","sources":["../../src/i18n/extract.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AAO9C,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,IAAa,EAAgB,EAAE;IAChE,MAAM,GAAG,GAAiB,EAAE,CAAA;IAE5B,MAAM,IAAI,GAAG,CAAC,IAAa,EAAE,IAAc,EAAE,EAAE;QAC7C,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC7B,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;YAC/B,OAAM;QACR,CAAC;QACD,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;YACxB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBACrC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAA;YAC/B,CAAC;YACD,OAAM;QACR,CAAC;QACD,IAAI,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC;YACxB,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC1C,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAA;YACzB,CAAC;QACH,CAAC;IACH,CAAC,CAAA;IAED,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC,CAAA;IACd,OAAO,GAAG,CAAA;AACZ,CAAC,CAAA"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export type JsonPathSegment = string | number;
|
|
2
|
+
export type JsonPath = JsonPathSegment[];
|
|
3
|
+
export declare const isPlainObject: (value: unknown) => value is Record<string, unknown>;
|
|
4
|
+
export declare const getAtPath: (root: unknown, path: JsonPath) => unknown;
|
|
5
|
+
export declare const setAtPath: (root: unknown, path: JsonPath, value: unknown) => void;
|
|
6
|
+
export declare const pathToString: (path: JsonPath) => string;
|
|
7
|
+
//# sourceMappingURL=json-path.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json-path.d.ts","sourceRoot":"","sources":["../../src/i18n/json-path.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,MAAM,CAAA;AAC7C,MAAM,MAAM,QAAQ,GAAG,eAAe,EAAE,CAAA;AAExC,eAAO,MAAM,aAAa,GAAI,OAAO,OAAO,KAAG,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAI7E,CAAA;AAED,eAAO,MAAM,SAAS,GAAI,MAAM,OAAO,EAAE,MAAM,QAAQ,KAAG,OAYzD,CAAA;AAED,eAAO,MAAM,SAAS,GAAI,MAAM,OAAO,EAAE,MAAM,QAAQ,EAAE,OAAO,OAAO,SA4BtE,CAAA;AAED,eAAO,MAAM,YAAY,GAAI,MAAM,QAAQ,WAIjB,CAAA"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
export const isPlainObject = (value) => {
|
|
2
|
+
if (!value || typeof value !== 'object')
|
|
3
|
+
return false;
|
|
4
|
+
if (Array.isArray(value))
|
|
5
|
+
return false;
|
|
6
|
+
return Object.prototype.toString.call(value) === '[object Object]';
|
|
7
|
+
};
|
|
8
|
+
export const getAtPath = (root, path) => {
|
|
9
|
+
let cur = root;
|
|
10
|
+
for (const seg of path) {
|
|
11
|
+
if (typeof seg === 'number') {
|
|
12
|
+
if (!Array.isArray(cur))
|
|
13
|
+
return undefined;
|
|
14
|
+
cur = cur[seg];
|
|
15
|
+
continue;
|
|
16
|
+
}
|
|
17
|
+
if (!isPlainObject(cur))
|
|
18
|
+
return undefined;
|
|
19
|
+
cur = cur[seg];
|
|
20
|
+
}
|
|
21
|
+
return cur;
|
|
22
|
+
};
|
|
23
|
+
export const setAtPath = (root, path, value) => {
|
|
24
|
+
if (!root || typeof root !== 'object')
|
|
25
|
+
return;
|
|
26
|
+
let cur = root;
|
|
27
|
+
for (let i = 0; i < path.length - 1; i++) {
|
|
28
|
+
const seg = path[i];
|
|
29
|
+
const nextSeg = path[i + 1];
|
|
30
|
+
if (typeof seg === 'number') {
|
|
31
|
+
if (!Array.isArray(cur))
|
|
32
|
+
return;
|
|
33
|
+
if (cur[seg] === undefined || cur[seg] === null || typeof cur[seg] !== 'object') {
|
|
34
|
+
cur[seg] = typeof nextSeg === 'number' ? [] : {};
|
|
35
|
+
}
|
|
36
|
+
cur = cur[seg];
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
if (!isPlainObject(cur))
|
|
40
|
+
return;
|
|
41
|
+
if (cur[seg] === undefined || cur[seg] === null || typeof cur[seg] !== 'object') {
|
|
42
|
+
cur[seg] = typeof nextSeg === 'number' ? [] : {};
|
|
43
|
+
}
|
|
44
|
+
cur = cur[seg];
|
|
45
|
+
}
|
|
46
|
+
const last = path[path.length - 1];
|
|
47
|
+
if (typeof last === 'number') {
|
|
48
|
+
if (!Array.isArray(cur))
|
|
49
|
+
return;
|
|
50
|
+
cur[last] = value;
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
if (!isPlainObject(cur))
|
|
54
|
+
return;
|
|
55
|
+
cur[last] = value;
|
|
56
|
+
};
|
|
57
|
+
export const pathToString = (path) => path
|
|
58
|
+
.map((seg) => (typeof seg === 'number' ? `[${seg}]` : seg))
|
|
59
|
+
.join('.')
|
|
60
|
+
.replace(/\.\[/g, '[');
|
|
61
|
+
//# sourceMappingURL=json-path.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json-path.js","sourceRoot":"","sources":["../../src/i18n/json-path.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../../src/i18n/parse.ts"],"names":[],"mappings":"AAaA,eAAO,MAAM,oBAAoB,GAAI,KAAK,MAAM,WAM/C,CAAA;AAED,eAAO,MAAM,cAAc,GAAI,KAAK,MAAM,KAAG,KAAK,CAAC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAkB9E,CAAA"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
const stripCodeFences = (s) => {
|
|
2
|
+
const trimmed = s.trim();
|
|
3
|
+
if (!trimmed.startsWith('```'))
|
|
4
|
+
return trimmed;
|
|
5
|
+
// remove first fence line and last fence if present
|
|
6
|
+
const lines = trimmed.split('\n');
|
|
7
|
+
if (lines.length <= 2)
|
|
8
|
+
return trimmed;
|
|
9
|
+
const first = lines[0];
|
|
10
|
+
const last = lines[lines.length - 1];
|
|
11
|
+
if (!first.startsWith('```'))
|
|
12
|
+
return trimmed;
|
|
13
|
+
if (!last.startsWith('```'))
|
|
14
|
+
return trimmed;
|
|
15
|
+
return lines.slice(1, -1).join('\n').trim();
|
|
16
|
+
};
|
|
17
|
+
export const extractJsonArrayText = (raw) => {
|
|
18
|
+
const s = stripCodeFences(raw);
|
|
19
|
+
const start = s.indexOf('[');
|
|
20
|
+
const end = s.lastIndexOf(']');
|
|
21
|
+
if (start === -1 || end === -1 || end <= start)
|
|
22
|
+
return s.trim();
|
|
23
|
+
return s.slice(start, end + 1).trim();
|
|
24
|
+
};
|
|
25
|
+
export const parseJsonArray = (raw) => {
|
|
26
|
+
const text = extractJsonArrayText(raw);
|
|
27
|
+
const parsed = JSON.parse(text);
|
|
28
|
+
if (!Array.isArray(parsed)) {
|
|
29
|
+
throw new Error('model output is not a JSON array');
|
|
30
|
+
}
|
|
31
|
+
const out = [];
|
|
32
|
+
for (const item of parsed) {
|
|
33
|
+
if (!item || typeof item !== 'object') {
|
|
34
|
+
throw new Error('model output array contains non-object item');
|
|
35
|
+
}
|
|
36
|
+
const anyItem = item;
|
|
37
|
+
if (typeof anyItem.id !== 'string' || typeof anyItem.text !== 'string') {
|
|
38
|
+
throw new Error('model output item must have string id and text');
|
|
39
|
+
}
|
|
40
|
+
out.push({ id: anyItem.id, text: anyItem.text });
|
|
41
|
+
}
|
|
42
|
+
return out;
|
|
43
|
+
};
|
|
44
|
+
//# sourceMappingURL=parse.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse.js","sourceRoot":"","sources":["../../src/i18n/parse.ts"],"names":[],"mappings":"AAAA,MAAM,eAAe,GAAG,CAAC,CAAS,EAAE,EAAE;IACpC,MAAM,OAAO,GAAG,CAAC,CAAC,IAAI,EAAE,CAAA;IACxB,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC;QAAE,OAAO,OAAO,CAAA;IAC9C,oDAAoD;IACpD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;IACjC,IAAI,KAAK,CAAC,MAAM,IAAI,CAAC;QAAE,OAAO,OAAO,CAAA;IACrC,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAA;IACtB,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAA;IACpC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC;QAAE,OAAO,OAAO,CAAA;IAC5C,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC;QAAE,OAAO,OAAO,CAAA;IAC3C,OAAO,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAA;AAC7C,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,GAAW,EAAE,EAAE;IAClD,MAAM,CAAC,GAAG,eAAe,CAAC,GAAG,CAAC,CAAA;IAC9B,MAAM,KAAK,GAAG,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;IAC5B,MAAM,GAAG,GAAG,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,CAAA;IAC9B,IAAI,KAAK,KAAK,CAAC,CAAC,IAAI,GAAG,KAAK,CAAC,CAAC,IAAI,GAAG,IAAI,KAAK;QAAE,OAAO,CAAC,CAAC,IAAI,EAAE,CAAA;IAC/D,OAAO,CAAC,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAA;AACvC,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,GAAW,EAAuC,EAAE;IACjF,MAAM,IAAI,GAAG,oBAAoB,CAAC,GAAG,CAAC,CAAA;IACtC,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAY,CAAA;IAC1C,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAC3B,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAA;IACrD,CAAC;IACD,MAAM,GAAG,GAAwC,EAAE,CAAA;IACnD,KAAK,MAAM,IAAI,IAAI,MAAM,EAAE,CAAC;QAC1B,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;YACtC,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAA;QAChE,CAAC;QACD,MAAM,OAAO,GAAG,IAAW,CAAA;QAC3B,IAAI,OAAO,OAAO,CAAC,EAAE,KAAK,QAAQ,IAAI,OAAO,OAAO,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACvE,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC,CAAA;QACnE,CAAC;QACD,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,OAAO,CAAC,EAAE,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC,CAAA;IAClD,CAAC;IACD,OAAO,GAAG,CAAA;AACZ,CAAC,CAAA"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export type PlaceholderMap = {
|
|
2
|
+
tokens: Record<string, string>;
|
|
3
|
+
protectedText: string;
|
|
4
|
+
};
|
|
5
|
+
export declare const protectPlaceholders: (text: string) => PlaceholderMap;
|
|
6
|
+
export declare const restorePlaceholders: (text: string, tokens: Record<string, string>) => string;
|
|
7
|
+
//# sourceMappingURL=placeholders.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"placeholders.d.ts","sourceRoot":"","sources":["../../src/i18n/placeholders.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,cAAc,GAAG;IAC3B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC9B,aAAa,EAAE,MAAM,CAAA;CACtB,CAAA;AAqBD,eAAO,MAAM,mBAAmB,GAAI,MAAM,MAAM,KAAG,cAoBlD,CAAA;AAED,eAAO,MAAM,mBAAmB,GAAI,MAAM,MAAM,EAAE,QAAQ,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,WAQ/E,CAAA"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
const TOKEN_PREFIX = '__AI_TRANSLATE_PH_';
|
|
2
|
+
const TOKEN_SUFFIX = '__';
|
|
3
|
+
const makeToken = (n) => `${TOKEN_PREFIX}${n}${TOKEN_SUFFIX}`;
|
|
4
|
+
// Keep tokens ASCII-only and long enough to avoid accidental collisions.
|
|
5
|
+
const isToken = (s) => s.startsWith(TOKEN_PREFIX) && s.endsWith(TOKEN_SUFFIX);
|
|
6
|
+
const patterns = [
|
|
7
|
+
// handlebars-like
|
|
8
|
+
{ name: 'doubleCurly', re: /\{\{\s*[^{}]+\s*\}\}/g },
|
|
9
|
+
// single curly (avoid matching JSON braces by requiring at least 1 char and no nesting)
|
|
10
|
+
{ name: 'singleCurly', re: /\{\s*[^{}\n]+\s*\}/g },
|
|
11
|
+
// printf-style
|
|
12
|
+
{ name: 'printf', re: /%[%sdif]/g },
|
|
13
|
+
// simple HTML-like tags (no attributes parsing; keep conservative)
|
|
14
|
+
{ name: 'tag', re: /<\/?[A-Za-z][A-Za-z0-9-]*\s*>/g }
|
|
15
|
+
];
|
|
16
|
+
export const protectPlaceholders = (text) => {
|
|
17
|
+
let protectedText = text;
|
|
18
|
+
const tokens = {};
|
|
19
|
+
let n = 0;
|
|
20
|
+
const replaceAll = (re) => {
|
|
21
|
+
protectedText = protectedText.replace(re, (m) => {
|
|
22
|
+
// already tokenized
|
|
23
|
+
if (isToken(m))
|
|
24
|
+
return m;
|
|
25
|
+
const token = makeToken(n++);
|
|
26
|
+
tokens[token] = m;
|
|
27
|
+
return token;
|
|
28
|
+
});
|
|
29
|
+
};
|
|
30
|
+
for (const p of patterns) {
|
|
31
|
+
replaceAll(p.re);
|
|
32
|
+
}
|
|
33
|
+
return { tokens, protectedText };
|
|
34
|
+
};
|
|
35
|
+
export const restorePlaceholders = (text, tokens) => {
|
|
36
|
+
let out = text;
|
|
37
|
+
// Restore longer tokens first (defensive, though our tokens are unique).
|
|
38
|
+
const keys = Object.keys(tokens).sort((a, b) => b.length - a.length);
|
|
39
|
+
for (const k of keys) {
|
|
40
|
+
out = out.split(k).join(tokens[k]);
|
|
41
|
+
}
|
|
42
|
+
return out;
|
|
43
|
+
};
|
|
44
|
+
//# sourceMappingURL=placeholders.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"placeholders.js","sourceRoot":"","sources":["../../src/i18n/placeholders.ts"],"names":[],"mappings":"AAKA,MAAM,YAAY,GAAG,oBAAoB,CAAA;AACzC,MAAM,YAAY,GAAG,IAAI,CAAA;AAEzB,MAAM,SAAS,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,GAAG,YAAY,GAAG,CAAC,GAAG,YAAY,EAAE,CAAA;AAErE,yEAAyE;AACzE,MAAM,OAAO,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAA;AAErF,MAAM,QAAQ,GAAwC;IACpD,kBAAkB;IAClB,EAAE,IAAI,EAAE,aAAa,EAAE,EAAE,EAAE,uBAAuB,EAAE;IACpD,wFAAwF;IACxF,EAAE,IAAI,EAAE,aAAa,EAAE,EAAE,EAAE,qBAAqB,EAAE;IAClD,eAAe;IACf,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,WAAW,EAAE;IACnC,mEAAmE;IACnE,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,gCAAgC,EAAE;CACtD,CAAA;AAED,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,IAAY,EAAkB,EAAE;IAClE,IAAI,aAAa,GAAG,IAAI,CAAA;IACxB,MAAM,MAAM,GAA2B,EAAE,CAAA;IACzC,IAAI,CAAC,GAAG,CAAC,CAAA;IAET,MAAM,UAAU,GAAG,CAAC,EAAU,EAAE,EAAE;QAChC,aAAa,GAAG,aAAa,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE;YAC9C,oBAAoB;YACpB,IAAI,OAAO,CAAC,CAAC,CAAC;gBAAE,OAAO,CAAC,CAAA;YACxB,MAAM,KAAK,GAAG,SAAS,CAAC,CAAC,EAAE,CAAC,CAAA;YAC5B,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;YACjB,OAAO,KAAK,CAAA;QACd,CAAC,CAAC,CAAA;IACJ,CAAC,CAAA;IAED,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,CAAA;IAClB,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,CAAA;AAClC,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,IAAY,EAAE,MAA8B,EAAE,EAAE;IAClF,IAAI,GAAG,GAAG,IAAI,CAAA;IACd,yEAAyE;IACzE,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC,CAAA;IACpE,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;QACrB,GAAG,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAA;IACpC,CAAC;IACD,OAAO,GAAG,CAAA;AACZ,CAAC,CAAA"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { ChatPromptValueInterface } from '@langchain/core/prompt_values';
|
|
2
|
+
export declare const i18nBatchPromptInvoke: (opts: {
|
|
3
|
+
sourceLanguage: string;
|
|
4
|
+
targetLanguage: string;
|
|
5
|
+
itemsJson: string;
|
|
6
|
+
}) => Promise<ChatPromptValueInterface>;
|
|
7
|
+
export declare const i18nRepairPromptInvoke: (opts: {
|
|
8
|
+
sourceLanguage: string;
|
|
9
|
+
targetLanguage: string;
|
|
10
|
+
expectedIds: string[];
|
|
11
|
+
badOutput: string;
|
|
12
|
+
}) => Promise<ChatPromptValueInterface>;
|
|
13
|
+
//# sourceMappingURL=prompt.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompt.d.ts","sourceRoot":"","sources":["../../src/i18n/prompt.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAA;AAkB7E,eAAO,MAAM,qBAAqB,GAAI,MAAM;IAC1C,cAAc,EAAE,MAAM,CAAA;IACtB,cAAc,EAAE,MAAM,CAAA;IACtB,SAAS,EAAE,MAAM,CAAA;CAClB,KAAG,OAAO,CAAC,wBAAwB,CAKhC,CAAA;AAEJ,eAAO,MAAM,sBAAsB,GAAI,MAAM;IAC3C,cAAc,EAAE,MAAM,CAAA;IACtB,cAAc,EAAE,MAAM,CAAA;IACtB,WAAW,EAAE,MAAM,EAAE,CAAA;IACrB,SAAS,EAAE,MAAM,CAAA;CAClB,KAAG,OAAO,CAAC,wBAAwB,CAmBnC,CAAA"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { ChatPromptTemplate } from '@langchain/core/prompts';
|
|
2
|
+
const systemPrompt = 'You are a professional localization translator.\n' +
|
|
3
|
+
'You will receive a JSON array. Each element has fields: "id" and "text".\n' +
|
|
4
|
+
'Your task is to translate ONLY the value of "text" from "{sourceLanguage}" to "{targetLanguage}".\n' +
|
|
5
|
+
'Rules:\n' +
|
|
6
|
+
'- Preserve "id" exactly.\n' +
|
|
7
|
+
'- Return ONLY valid JSON (no markdown, no code fences, no explanations).\n' +
|
|
8
|
+
'- Keep placeholder tokens like __AI_TRANSLATE_PH_0__ unchanged.\n' +
|
|
9
|
+
'- Do not add, remove, or reorder array items.\n' +
|
|
10
|
+
'- Keep punctuation and formatting as close as possible.\n';
|
|
11
|
+
const promptTemplate = ChatPromptTemplate.fromMessages([
|
|
12
|
+
['system', systemPrompt],
|
|
13
|
+
['user', '{itemsJson}']
|
|
14
|
+
]);
|
|
15
|
+
export const i18nBatchPromptInvoke = (opts) => promptTemplate.invoke({
|
|
16
|
+
sourceLanguage: opts.sourceLanguage,
|
|
17
|
+
targetLanguage: opts.targetLanguage,
|
|
18
|
+
itemsJson: opts.itemsJson
|
|
19
|
+
});
|
|
20
|
+
export const i18nRepairPromptInvoke = (opts) => {
|
|
21
|
+
const repairSystem = 'You fix model outputs into valid JSON.\n' +
|
|
22
|
+
'Return ONLY valid JSON array of objects with fields: "id" and "text".\n' +
|
|
23
|
+
'Preserve the provided IDs exactly, and include all IDs, no extras.\n' +
|
|
24
|
+
'Keep placeholder tokens like __AI_TRANSLATE_PH_0__ unchanged.\n';
|
|
25
|
+
const repairTemplate = ChatPromptTemplate.fromMessages([
|
|
26
|
+
['system', repairSystem],
|
|
27
|
+
[
|
|
28
|
+
'user',
|
|
29
|
+
'Expected ids:\n{ids}\n\nBad output:\n{bad}\n\nReturn fixed JSON array only.'
|
|
30
|
+
]
|
|
31
|
+
]);
|
|
32
|
+
return repairTemplate.invoke({
|
|
33
|
+
ids: JSON.stringify(opts.expectedIds),
|
|
34
|
+
bad: opts.badOutput
|
|
35
|
+
});
|
|
36
|
+
};
|
|
37
|
+
//# sourceMappingURL=prompt.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompt.js","sourceRoot":"","sources":["../../src/i18n/prompt.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAG5D,MAAM,YAAY,GAChB,mDAAmD;IACnD,4EAA4E;IAC5E,qGAAqG;IACrG,UAAU;IACV,4BAA4B;IAC5B,4EAA4E;IAC5E,mEAAmE;IACnE,iDAAiD;IACjD,2DAA2D,CAAA;AAE7D,MAAM,cAAc,GAAG,kBAAkB,CAAC,YAAY,CAAC;IACrD,CAAC,QAAQ,EAAE,YAAY,CAAC;IACxB,CAAC,MAAM,EAAE,aAAa,CAAC;CACxB,CAAC,CAAA;AAEF,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,IAIrC,EAAqC,EAAE,CACtC,cAAc,CAAC,MAAM,CAAC;IACpB,cAAc,EAAE,IAAI,CAAC,cAAc;IACnC,cAAc,EAAE,IAAI,CAAC,cAAc;IACnC,SAAS,EAAE,IAAI,CAAC,SAAS;CAC1B,CAAC,CAAA;AAEJ,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,IAKtC,EAAqC,EAAE;IACtC,MAAM,YAAY,GAChB,0CAA0C;QAC1C,yEAAyE;QACzE,sEAAsE;QACtE,iEAAiE,CAAA;IAEnE,MAAM,cAAc,GAAG,kBAAkB,CAAC,YAAY,CAAC;QACrD,CAAC,QAAQ,EAAE,YAAY,CAAC;QACxB;YACE,MAAM;YACN,6EAA6E;SAC9E;KACF,CAAC,CAAA;IAEF,OAAO,cAAc,CAAC,MAAM,CAAC;QAC3B,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,WAAW,CAAC;QACrC,GAAG,EAAE,IAAI,CAAC,SAAS;KACpB,CAAC,CAAA;AACJ,CAAC,CAAA"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { BaseChatModel } from '@langchain/core/language_models/chat_models';
|
|
2
|
+
import type { AlignMode } from './align.js';
|
|
3
|
+
export type I18nTranslateOptions = {
|
|
4
|
+
baseDir: string;
|
|
5
|
+
sourceLang: string;
|
|
6
|
+
targets: string[];
|
|
7
|
+
mode: AlignMode;
|
|
8
|
+
dryRun?: boolean;
|
|
9
|
+
fileName?: string;
|
|
10
|
+
batchMaxItems?: number;
|
|
11
|
+
batchMaxChars?: number;
|
|
12
|
+
cacheFile?: string;
|
|
13
|
+
};
|
|
14
|
+
export type I18nTargetStats = {
|
|
15
|
+
targetLang: string;
|
|
16
|
+
sourceFile: string;
|
|
17
|
+
targetFile: string;
|
|
18
|
+
totalStrings: number;
|
|
19
|
+
skippedExisting: number;
|
|
20
|
+
toTranslate: number;
|
|
21
|
+
translated: number;
|
|
22
|
+
failed: number;
|
|
23
|
+
usedCache: number;
|
|
24
|
+
};
|
|
25
|
+
export declare const translateI18nDir: (opts: {
|
|
26
|
+
model: BaseChatModel;
|
|
27
|
+
options: I18nTranslateOptions;
|
|
28
|
+
}) => Promise<I18nTargetStats[]>;
|
|
29
|
+
//# sourceMappingURL=translate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"translate.d.ts","sourceRoot":"","sources":["../../src/i18n/translate.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6CAA6C,CAAA;AAEhF,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAY3C,MAAM,MAAM,oBAAoB,GAAG;IACjC,OAAO,EAAE,MAAM,CAAA;IACf,UAAU,EAAE,MAAM,CAAA;IAClB,OAAO,EAAE,MAAM,EAAE,CAAA;IACjB,IAAI,EAAE,SAAS,CAAA;IACf,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAA;AAqFD,MAAM,MAAM,eAAe,GAAG;IAC5B,UAAU,EAAE,MAAM,CAAA;IAClB,UAAU,EAAE,MAAM,CAAA;IAClB,UAAU,EAAE,MAAM,CAAA;IAClB,YAAY,EAAE,MAAM,CAAA;IACpB,eAAe,EAAE,MAAM,CAAA;IACvB,WAAW,EAAE,MAAM,CAAA;IACnB,UAAU,EAAE,MAAM,CAAA;IAClB,MAAM,EAAE,MAAM,CAAA;IACd,SAAS,EAAE,MAAM,CAAA;CAClB,CAAA;AAED,eAAO,MAAM,gBAAgB,GAAU,MAAM;IAC3C,KAAK,EAAE,aAAa,CAAA;IACpB,OAAO,EAAE,oBAAoB,CAAA;CAC9B,KAAG,OAAO,CAAC,eAAe,EAAE,CA6J5B,CAAA"}
|