@thor123141245r/ai-translate 0.0.0 → 1.0.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 (64) hide show
  1. package/README.md +71 -22
  2. package/dist/cli.d.ts.map +1 -1
  3. package/dist/cli.js +77 -0
  4. package/dist/cli.js.map +1 -1
  5. package/dist/i18n/align.d.ts +3 -0
  6. package/dist/i18n/align.d.ts.map +1 -0
  7. package/dist/i18n/align.js +46 -0
  8. package/dist/i18n/align.js.map +1 -0
  9. package/dist/i18n/cache.d.ts +14 -0
  10. package/dist/i18n/cache.d.ts.map +1 -0
  11. package/dist/i18n/cache.js +36 -0
  12. package/dist/i18n/cache.js.map +1 -0
  13. package/dist/i18n/command.d.ts +7 -0
  14. package/dist/i18n/command.d.ts.map +1 -0
  15. package/dist/i18n/command.js +84 -0
  16. package/dist/i18n/command.js.map +1 -0
  17. package/dist/i18n/extract.d.ts +7 -0
  18. package/dist/i18n/extract.d.ts.map +1 -0
  19. package/dist/i18n/extract.js +24 -0
  20. package/dist/i18n/extract.js.map +1 -0
  21. package/dist/i18n/json-path.d.ts +7 -0
  22. package/dist/i18n/json-path.d.ts.map +1 -0
  23. package/dist/i18n/json-path.js +61 -0
  24. package/dist/i18n/json-path.js.map +1 -0
  25. package/dist/i18n/parse.d.ts +6 -0
  26. package/dist/i18n/parse.d.ts.map +1 -0
  27. package/dist/i18n/parse.js +44 -0
  28. package/dist/i18n/parse.js.map +1 -0
  29. package/dist/i18n/placeholders.d.ts +7 -0
  30. package/dist/i18n/placeholders.d.ts.map +1 -0
  31. package/dist/i18n/placeholders.js +44 -0
  32. package/dist/i18n/placeholders.js.map +1 -0
  33. package/dist/i18n/prompt.d.ts +13 -0
  34. package/dist/i18n/prompt.d.ts.map +1 -0
  35. package/dist/i18n/prompt.js +37 -0
  36. package/dist/i18n/prompt.js.map +1 -0
  37. package/dist/i18n/translate.d.ts +29 -0
  38. package/dist/i18n/translate.d.ts.map +1 -0
  39. package/dist/i18n/translate.js +199 -0
  40. package/dist/i18n/translate.js.map +1 -0
  41. package/dist/index.d.ts +1 -0
  42. package/dist/index.d.ts.map +1 -1
  43. package/dist/index.js +1 -0
  44. package/dist/index.js.map +1 -1
  45. package/package.json +5 -1
  46. 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
  47. package/.agentdocs/code-changes/2026-01-23/CLI/345/210/206/345/217/221-npx/345/256/236/347/216/260.md +0 -18
  48. 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
  49. 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
  50. 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
  51. package/.agentdocs/plans/2026-01-23/CLI/345/210/206/345/217/221-npx/346/226/271/346/241/210.md +0 -60
  52. 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
  53. 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
  54. package/SKILL.md +0 -103
  55. package/src/asyncTransform.ts +0 -31
  56. package/src/bin/ai-translate.ts +0 -5
  57. package/src/cli.ts +0 -313
  58. package/src/index.ts +0 -9
  59. package/src/logger.ts +0 -3
  60. package/src/model.ts +0 -139
  61. package/src/prompt.ts +0 -71
  62. package/src/split.ts +0 -111
  63. package/src/utils.ts +0 -15
  64. package/tsconfig.json +0 -19
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json-path.js","sourceRoot":"","sources":["../../src/i18n/json-path.ts"],"names":[],"mappings":"AAGA,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,KAAc,EAAoC,EAAE;IAChF,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAA;IACrD,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAA;IACtC,OAAO,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,iBAAiB,CAAA;AACpE,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,IAAa,EAAE,IAAc,EAAW,EAAE;IAClE,IAAI,GAAG,GAAY,IAAI,CAAA;IACvB,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;YAC5B,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC;gBAAE,OAAO,SAAS,CAAA;YACzC,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC,CAAA;YACd,SAAQ;QACV,CAAC;QACD,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC;YAAE,OAAO,SAAS,CAAA;QACzC,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC,CAAA;IAChB,CAAC;IACD,OAAO,GAAG,CAAA;AACZ,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,IAAa,EAAE,IAAc,EAAE,KAAc,EAAE,EAAE;IACzE,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ;QAAE,OAAM;IAC7C,IAAI,GAAG,GAAQ,IAAI,CAAA;IACnB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QACzC,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAA;QACnB,MAAM,OAAO,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAA;QAC3B,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;YAC5B,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC;gBAAE,OAAM;YAC/B,IAAI,GAAG,CAAC,GAAG,CAAC,KAAK,SAAS,IAAI,GAAG,CAAC,GAAG,CAAC,KAAK,IAAI,IAAI,OAAO,GAAG,CAAC,GAAG,CAAC,KAAK,QAAQ,EAAE,CAAC;gBAChF,GAAG,CAAC,GAAG,CAAC,GAAG,OAAO,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAA;YAClD,CAAC;YACD,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC,CAAA;YACd,SAAQ;QACV,CAAC;QACD,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC;YAAE,OAAM;QAC/B,IAAI,GAAG,CAAC,GAAG,CAAC,KAAK,SAAS,IAAI,GAAG,CAAC,GAAG,CAAC,KAAK,IAAI,IAAI,OAAO,GAAG,CAAC,GAAG,CAAC,KAAK,QAAQ,EAAE,CAAC;YAChF,GAAG,CAAC,GAAG,CAAC,GAAG,OAAO,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAA;QAClD,CAAC;QACD,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC,CAAA;IAChB,CAAC;IACD,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAA;IAClC,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC7B,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC;YAAE,OAAM;QAC/B,GAAG,CAAC,IAAI,CAAC,GAAG,KAAK,CAAA;QACjB,OAAM;IACR,CAAC;IACD,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC;QAAE,OAAM;IAC/B,GAAG,CAAC,IAAI,CAAC,GAAG,KAAK,CAAA;AACnB,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,IAAc,EAAE,EAAE,CAC7C,IAAI;KACD,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;KAC1D,IAAI,CAAC,GAAG,CAAC;KACT,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,CAAA"}
@@ -0,0 +1,6 @@
1
+ export declare const extractJsonArrayText: (raw: string) => string;
2
+ export declare const parseJsonArray: (raw: string) => Array<{
3
+ id: string;
4
+ text: string;
5
+ }>;
6
+ //# sourceMappingURL=parse.d.ts.map
@@ -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"}
@@ -0,0 +1,199 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { logger } from '../logger.js';
4
+ import { alignStructure } from './align.js';
5
+ import { extractLeafStrings } from './extract.js';
6
+ import { getAtPath, setAtPath, pathToString } from './json-path.js';
7
+ import { protectPlaceholders, restorePlaceholders } from './placeholders.js';
8
+ import { TranslationCache } from './cache.js';
9
+ import { i18nBatchPromptInvoke, i18nRepairPromptInvoke } from './prompt.js';
10
+ import { parseJsonArray } from './parse.js';
11
+ import { getLanguageName } from '../prompt.js';
12
+ const log = logger('i18n');
13
+ const isNonEmptyString = (v) => typeof v === 'string' && v.trim().length > 0;
14
+ const deepClone = (v) => JSON.parse(JSON.stringify(v));
15
+ const readJsonFile = (file) => {
16
+ const raw = fs.readFileSync(file, 'utf-8');
17
+ return JSON.parse(raw);
18
+ };
19
+ const writeJsonFile = (file, obj) => {
20
+ fs.writeFileSync(file, JSON.stringify(obj, null, 2) + '\n', 'utf-8');
21
+ };
22
+ const chunkUnits = (units, maxItems, maxChars) => {
23
+ const batches = [];
24
+ let cur = [];
25
+ let curChars = 0;
26
+ const pushCur = () => {
27
+ if (!cur.length)
28
+ return;
29
+ batches.push(cur);
30
+ cur = [];
31
+ curChars = 0;
32
+ };
33
+ for (const u of units) {
34
+ const estimated = u.protectedText.length + 40;
35
+ if (cur.length >= maxItems || (cur.length > 0 && curChars + estimated > maxChars)) {
36
+ pushCur();
37
+ }
38
+ cur.push(u);
39
+ curChars += estimated;
40
+ }
41
+ pushCur();
42
+ return batches;
43
+ };
44
+ const buildCacheKey = (opts) => `${opts.sourceLang}|${opts.targetLang}|${pathToString(opts.path)}|${opts.text}`;
45
+ const translateBatch = async (opts) => {
46
+ const itemsJson = JSON.stringify(opts.items);
47
+ const messages = await i18nBatchPromptInvoke({
48
+ sourceLanguage: opts.sourceLanguage,
49
+ targetLanguage: opts.targetLanguage,
50
+ itemsJson
51
+ });
52
+ const result = await opts.model.invoke(messages);
53
+ try {
54
+ return parseJsonArray(String(result.content ?? ''));
55
+ }
56
+ catch (err) {
57
+ // One repair attempt: ask the model to output valid JSON only.
58
+ const expectedIds = opts.items.map((it) => it.id);
59
+ const repair = await i18nRepairPromptInvoke({
60
+ sourceLanguage: opts.sourceLanguage,
61
+ targetLanguage: opts.targetLanguage,
62
+ expectedIds,
63
+ badOutput: String(result.content ?? '')
64
+ });
65
+ const repaired = await opts.model.invoke(repair);
66
+ return parseJsonArray(String(repaired.content ?? ''));
67
+ }
68
+ };
69
+ export const translateI18nDir = async (opts) => {
70
+ const { baseDir, sourceLang, targets, mode, dryRun = false, fileName, batchMaxItems = 40, batchMaxChars = 6000, cacheFile } = opts.options;
71
+ if (!targets.length)
72
+ throw new Error('targets is required');
73
+ const sourceFileName = fileName || `${sourceLang}.json`;
74
+ const sourceFile = path.resolve(baseDir, sourceFileName);
75
+ if (!fs.existsSync(sourceFile)) {
76
+ throw new Error(`source file not found: ${sourceFile}`);
77
+ }
78
+ const cache = new TranslationCache(cacheFile);
79
+ cache.load();
80
+ const sourceJson = readJsonFile(sourceFile);
81
+ const sourceLeaves = extractLeafStrings(sourceJson);
82
+ const stats = [];
83
+ for (const targetLang of targets) {
84
+ const targetFileName = `${targetLang}.json`;
85
+ const targetFile = path.resolve(baseDir, targetFileName);
86
+ const targetJsonRaw = fs.existsSync(targetFile) ? readJsonFile(targetFile) : undefined;
87
+ const alignedTarget = alignStructure(sourceJson, targetJsonRaw, mode);
88
+ const targetJson = deepClone(alignedTarget);
89
+ const units = [];
90
+ let skippedExisting = 0;
91
+ let usedCache = 0;
92
+ for (let i = 0; i < sourceLeaves.length; i++) {
93
+ const { path: p, value: sourceText } = sourceLeaves[i];
94
+ if (!sourceText || sourceText.trim() === '')
95
+ continue;
96
+ const existing = getAtPath(targetJson, p);
97
+ if (mode === 'fill' && isNonEmptyString(existing)) {
98
+ skippedExisting++;
99
+ continue;
100
+ }
101
+ const cacheKey = buildCacheKey({
102
+ sourceLang,
103
+ targetLang,
104
+ path: p,
105
+ text: sourceText
106
+ });
107
+ const cached = cache.get(cacheKey);
108
+ if (cached) {
109
+ usedCache++;
110
+ setAtPath(targetJson, p, cached);
111
+ continue;
112
+ }
113
+ const { tokens, protectedText } = protectPlaceholders(sourceText);
114
+ const id = `k${String(units.length + 1).padStart(6, '0')}`;
115
+ units.push({
116
+ id,
117
+ path: p,
118
+ sourceText,
119
+ protectedText,
120
+ tokens
121
+ });
122
+ }
123
+ const totalStrings = sourceLeaves.filter((x) => x.value.trim().length > 0).length;
124
+ if (dryRun) {
125
+ stats.push({
126
+ targetLang,
127
+ sourceFile,
128
+ targetFile,
129
+ totalStrings,
130
+ skippedExisting,
131
+ toTranslate: units.length,
132
+ translated: 0,
133
+ failed: 0,
134
+ usedCache
135
+ });
136
+ continue;
137
+ }
138
+ const batches = chunkUnits(units, batchMaxItems, batchMaxChars);
139
+ let translated = 0;
140
+ let failed = 0;
141
+ for (let bi = 0; bi < batches.length; bi++) {
142
+ const batch = batches[bi];
143
+ const items = batch.map((u) => ({ id: u.id, text: u.protectedText }));
144
+ try {
145
+ const out = await translateBatch({
146
+ model: opts.model,
147
+ sourceLanguage: getLanguageName(sourceLang),
148
+ targetLanguage: getLanguageName(targetLang),
149
+ items
150
+ });
151
+ const outMap = new Map(out.map((x) => [x.id, x.text]));
152
+ for (const u of batch) {
153
+ const translatedText = outMap.get(u.id);
154
+ if (!translatedText) {
155
+ failed++;
156
+ // fall back to English to keep JSON valid and predictable
157
+ setAtPath(targetJson, u.path, u.sourceText);
158
+ continue;
159
+ }
160
+ const restored = restorePlaceholders(translatedText, u.tokens);
161
+ setAtPath(targetJson, u.path, restored);
162
+ translated++;
163
+ const cacheKey = buildCacheKey({
164
+ sourceLang,
165
+ targetLang,
166
+ path: u.path,
167
+ text: u.sourceText
168
+ });
169
+ cache.set(cacheKey, restored);
170
+ }
171
+ }
172
+ catch (err) {
173
+ log.error({ err, targetLang, batch: bi + 1, batches: batches.length });
174
+ // degrade: keep source for this batch
175
+ for (const u of batch) {
176
+ failed++;
177
+ setAtPath(targetJson, u.path, u.sourceText);
178
+ }
179
+ }
180
+ }
181
+ writeJsonFile(targetFile, targetJson);
182
+ stats.push({
183
+ targetLang,
184
+ sourceFile,
185
+ targetFile,
186
+ totalStrings,
187
+ skippedExisting,
188
+ toTranslate: units.length,
189
+ translated,
190
+ failed,
191
+ usedCache
192
+ });
193
+ }
194
+ if (!dryRun) {
195
+ cache.save();
196
+ }
197
+ return stats;
198
+ };
199
+ //# sourceMappingURL=translate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"translate.js","sourceRoot":"","sources":["../../src/i18n/translate.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  export { AiTranslateTransform, modelFactory } from './model.js';
2
2
  export { promptInvoke, languages } from './prompt.js';
3
3
  export { TextSplitterStream, recursiveChunkTextSplitter, getFormatByExtension } from './split.js';
4
+ export { translateI18nDir } from './i18n/translate.js';
4
5
  export type { Metadata, ModelFactoryOptions } from './model.js';
5
6
  export type { TextSplitterParams, Separator } from './split.js';
6
7
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAC/D,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AACrD,OAAO,EACL,kBAAkB,EAClB,0BAA0B,EAC1B,oBAAoB,EACrB,MAAM,YAAY,CAAA;AACnB,YAAY,EAAE,QAAQ,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAA;AAC/D,YAAY,EAAE,kBAAkB,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAC/D,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AACrD,OAAO,EACL,kBAAkB,EAClB,0BAA0B,EAC1B,oBAAoB,EACrB,MAAM,YAAY,CAAA;AACnB,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAA;AACtD,YAAY,EAAE,QAAQ,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAA;AAC/D,YAAY,EAAE,kBAAkB,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA"}
package/dist/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  export { AiTranslateTransform, modelFactory } from './model.js';
2
2
  export { promptInvoke, languages } from './prompt.js';
3
3
  export { TextSplitterStream, recursiveChunkTextSplitter, getFormatByExtension } from './split.js';
4
+ export { translateI18nDir } from './i18n/translate.js';
4
5
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAC/D,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AACrD,OAAO,EACL,kBAAkB,EAClB,0BAA0B,EAC1B,oBAAoB,EACrB,MAAM,YAAY,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAC/D,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AACrD,OAAO,EACL,kBAAkB,EAClB,0BAA0B,EAC1B,oBAAoB,EACrB,MAAM,YAAY,CAAA;AACnB,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thor123141245r/ai-translate",
3
- "version": "0.0.0",
3
+ "version": "1.0.0",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -17,6 +17,10 @@
17
17
  "default": "./dist/index.js"
18
18
  }
19
19
  },
20
+ "files": [
21
+ "dist",
22
+ "README.md"
23
+ ],
20
24
  "scripts": {
21
25
  "build": "tsc -p tsconfig.json",
22
26
  "dev:cli": "tsx src/bin/ai-translate.ts",
@@ -1,22 +0,0 @@
1
- 作者:Codex|创建时间:2026-01-22 23:35
2
-
3
- # 变更概述
4
- 基于方案实现 TypeScript 版本的 AI 翻译器:按官方库结构复刻核心流程,补齐模块分层、CLI 入口、配置与日志策略,并提供最小验证脚本与中文说明。
5
-
6
- # 变更清单
7
- - [x] 引入并对齐 ai-translate 的核心 API 与流程
8
- - [x] 新增 TypeScript 目录结构与模块实现
9
- - [x] 新增 CLI 或脚本入口
10
- - [x] 配置与日志策略落地
11
- - [x] 中文使用文档更新
12
- - [x] 最小测试或验证脚本补齐
13
-
14
- # 关键设计对齐
15
- - 模块分层:配置解析层、翻译执行层、文件读写层、日志层
16
- - 复用优先:最大限度遵循官方库结构与命名
17
- - 日志策略:开发环境整对象打印,生产环境精简敏感信息
18
-
19
- # 待确认事项状态
20
- - 是否要求完全对齐官方库的所有导出与命令参数:未确认
21
- - 是否需要发布为独立 npm 包:未确认
22
- - 是否要兼容现有 Python 脚本的输入格式:未确认
@@ -1,18 +0,0 @@
1
- 作者:Codex|创建时间:2026-01-23 04:18
2
-
3
- # 变更概述
4
- 为 CLI 增加可通过 npx/pnpx 直接执行的分发配置,更新包名与发布设置,并补充中文使用说明。
5
-
6
- # 变更清单
7
- - [x] package.json 发布与 bin 配置调整
8
- - [x] README 增加 npx/pnpx 使用说明
9
- - [x] 本地构建与验证
10
-
11
- # 关键设计对齐
12
- - bin 入口保持 ai-translate
13
- - npm 包名为 @thor123141245r/ai-translate
14
- - 发布为 public
15
-
16
- # 待确认事项状态
17
- - 采用哪个 npm 包名:@thor123141245r/ai-translate(已确认)
18
- - 是否允许发布到 npm:允许,public(已确认)
@@ -1,37 +0,0 @@
1
- 作者: Codex | 创建时间: 2026-01-23 21:35
2
-
3
- # sora-watermask-remover 国际化翻译实现
4
-
5
- ## 变更概述
6
- - 使用脚本 `sentence_json_translator.py` 基于 `en.json` 翻译并覆盖目录内全部语言文件
7
- - 保持受保护关键词 `sora watermask remover` 原样
8
- - 保留专有名词与产品名:Sora、Sora2 Cloud、OpenAI Pro、HD、15s
9
-
10
- ## 执行方式
11
- - 脚本位置:`/Users/thor/.codex/skills/i18n-copywriter/scripts/sentence_json_translator.py`
12
- - 目标目录:`/Users/thor/Github/sora2.cloud-main/src/i18n/pages/sora-watermask-remover`
13
- - 运行参数要点:
14
- - `--overwrite` 全量覆盖
15
- - `--protected-terms "sora watermask remover,Sora,Sora2 Cloud,OpenAI Pro,HD,15s"`
16
- - 由于接口偶发 SSL 握手失败,启用 `CONTENT_LOCALIZE_INSECURE=1` 并提高重试次数
17
-
18
- ## 涉及文件
19
- - `/Users/thor/Github/sora2.cloud-main/src/i18n/pages/sora-watermask-remover/ar.json`
20
- - `/Users/thor/Github/sora2.cloud-main/src/i18n/pages/sora-watermask-remover/de.json`
21
- - `/Users/thor/Github/sora2.cloud-main/src/i18n/pages/sora-watermask-remover/es.json`
22
- - `/Users/thor/Github/sora2.cloud-main/src/i18n/pages/sora-watermask-remover/fr.json`
23
- - `/Users/thor/Github/sora2.cloud-main/src/i18n/pages/sora-watermask-remover/he.json`
24
- - `/Users/thor/Github/sora2.cloud-main/src/i18n/pages/sora-watermask-remover/hi.json`
25
- - `/Users/thor/Github/sora2.cloud-main/src/i18n/pages/sora-watermask-remover/id.json`
26
- - `/Users/thor/Github/sora2.cloud-main/src/i18n/pages/sora-watermask-remover/ja.json`
27
- - `/Users/thor/Github/sora2.cloud-main/src/i18n/pages/sora-watermask-remover/km.json`
28
- - `/Users/thor/Github/sora2.cloud-main/src/i18n/pages/sora-watermask-remover/ru.json`
29
- - `/Users/thor/Github/sora2.cloud-main/src/i18n/pages/sora-watermask-remover/th.json`
30
- - `/Users/thor/Github/sora2.cloud-main/src/i18n/pages/sora-watermask-remover/zh.json`
31
-
32
- ## 验证
33
- - JSON 解析检查通过
34
- - key 集合与 `en.json` 完全一致
35
-
36
- ## 备注
37
- - 本次翻译为脚本输出结果,如需人工润色可在此基础上微调
@@ -1,22 +0,0 @@
1
- 作者:Codex|创建时间:2026-01-23 21:06
2
-
3
- # 实现说明
4
- - 新增运行时配置解析 让 apiKey 与 baseUrl 优先取环境变量
5
- - 调整模型工厂 避免空 apiKey 覆盖 SDK 默认环境变量读取
6
- - README 增补环境变量优先级与变量名说明
7
-
8
- # 变更清单
9
- - src/cli.ts
10
- - 新增 baseUrl schema
11
- - 新增 resolveRuntimeConfig 处理环境变量优先级
12
- - src/model.ts
13
- - apiKey baseUrl 仅在有效值时注入
14
- - openai deepseek 使用 configuration baseURL
15
- - ollama 使用 baseUrl
16
- - README.md
17
- - 增加环境变量优先级与变量列表
18
-
19
- # 自测要点
20
- - 设置环境变量后 即使配置文件不同仍以环境变量为准
21
- - 未设置环境变量时 使用配置文件
22
- - 不设置 apiKey 时 SDK 自动读取自身环境变量