ai-i18n-tools 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 (260) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +157 -0
  3. package/dist/api/openrouter.d.ts +115 -0
  4. package/dist/api/openrouter.d.ts.map +1 -0
  5. package/dist/api/openrouter.js +399 -0
  6. package/dist/api/openrouter.js.map +1 -0
  7. package/dist/cli/doc-translate.d.ts +90 -0
  8. package/dist/cli/doc-translate.d.ts.map +1 -0
  9. package/dist/cli/doc-translate.js +1153 -0
  10. package/dist/cli/doc-translate.js.map +1 -0
  11. package/dist/cli/export-ui-xliff.d.ts +32 -0
  12. package/dist/cli/export-ui-xliff.d.ts.map +1 -0
  13. package/dist/cli/export-ui-xliff.js +153 -0
  14. package/dist/cli/export-ui-xliff.js.map +1 -0
  15. package/dist/cli/extract-strings.d.ts +12 -0
  16. package/dist/cli/extract-strings.d.ts.map +1 -0
  17. package/dist/cli/extract-strings.js +80 -0
  18. package/dist/cli/extract-strings.js.map +1 -0
  19. package/dist/cli/file-utils.d.ts +10 -0
  20. package/dist/cli/file-utils.d.ts.map +1 -0
  21. package/dist/cli/file-utils.js +77 -0
  22. package/dist/cli/file-utils.js.map +1 -0
  23. package/dist/cli/format.d.ts +21 -0
  24. package/dist/cli/format.d.ts.map +1 -0
  25. package/dist/cli/format.js +75 -0
  26. package/dist/cli/format.js.map +1 -0
  27. package/dist/cli/helpers.d.ts +27 -0
  28. package/dist/cli/helpers.d.ts.map +1 -0
  29. package/dist/cli/helpers.js +84 -0
  30. package/dist/cli/helpers.js.map +1 -0
  31. package/dist/cli/index.d.ts +3 -0
  32. package/dist/cli/index.d.ts.map +1 -0
  33. package/dist/cli/index.js +772 -0
  34. package/dist/cli/index.js.map +1 -0
  35. package/dist/cli/log-output.d.ts +13 -0
  36. package/dist/cli/log-output.d.ts.map +1 -0
  37. package/dist/cli/log-output.js +75 -0
  38. package/dist/cli/log-output.js.map +1 -0
  39. package/dist/cli/translate-svg.d.ts +7 -0
  40. package/dist/cli/translate-svg.d.ts.map +1 -0
  41. package/dist/cli/translate-svg.js +167 -0
  42. package/dist/cli/translate-svg.js.map +1 -0
  43. package/dist/cli/translate-ui-strings.d.ts +27 -0
  44. package/dist/cli/translate-ui-strings.d.ts.map +1 -0
  45. package/dist/cli/translate-ui-strings.js +357 -0
  46. package/dist/cli/translate-ui-strings.js.map +1 -0
  47. package/dist/core/cache-tracking-keys.d.ts +12 -0
  48. package/dist/core/cache-tracking-keys.d.ts.map +1 -0
  49. package/dist/core/cache-tracking-keys.js +20 -0
  50. package/dist/core/cache-tracking-keys.js.map +1 -0
  51. package/dist/core/cache.d.ts +153 -0
  52. package/dist/core/cache.d.ts.map +1 -0
  53. package/dist/core/cache.js +546 -0
  54. package/dist/core/cache.js.map +1 -0
  55. package/dist/core/config.d.ts +58 -0
  56. package/dist/core/config.d.ts.map +1 -0
  57. package/dist/core/config.js +392 -0
  58. package/dist/core/config.js.map +1 -0
  59. package/dist/core/doc-file-tracking.d.ts +8 -0
  60. package/dist/core/doc-file-tracking.d.ts.map +1 -0
  61. package/dist/core/doc-file-tracking.js +27 -0
  62. package/dist/core/doc-file-tracking.js.map +1 -0
  63. package/dist/core/errors.d.ts +19 -0
  64. package/dist/core/errors.d.ts.map +1 -0
  65. package/dist/core/errors.js +23 -0
  66. package/dist/core/errors.js.map +1 -0
  67. package/dist/core/locale-utils.d.ts +20 -0
  68. package/dist/core/locale-utils.d.ts.map +1 -0
  69. package/dist/core/locale-utils.js +75 -0
  70. package/dist/core/locale-utils.js.map +1 -0
  71. package/dist/core/output-paths.d.ts +22 -0
  72. package/dist/core/output-paths.d.ts.map +1 -0
  73. package/dist/core/output-paths.js +130 -0
  74. package/dist/core/output-paths.js.map +1 -0
  75. package/dist/core/prompt-builder.d.ts +62 -0
  76. package/dist/core/prompt-builder.d.ts.map +1 -0
  77. package/dist/core/prompt-builder.js +232 -0
  78. package/dist/core/prompt-builder.js.map +1 -0
  79. package/dist/core/prompts.d.ts +27 -0
  80. package/dist/core/prompts.d.ts.map +1 -0
  81. package/dist/core/prompts.js +57 -0
  82. package/dist/core/prompts.js.map +1 -0
  83. package/dist/core/svg-asset-paths.d.ts +40 -0
  84. package/dist/core/svg-asset-paths.d.ts.map +1 -0
  85. package/dist/core/svg-asset-paths.js +107 -0
  86. package/dist/core/svg-asset-paths.js.map +1 -0
  87. package/dist/core/types.d.ts +388 -0
  88. package/dist/core/types.d.ts.map +1 -0
  89. package/dist/core/types.js +265 -0
  90. package/dist/core/types.js.map +1 -0
  91. package/dist/core/ui-languages.d.ts +66 -0
  92. package/dist/core/ui-languages.d.ts.map +1 -0
  93. package/dist/core/ui-languages.js +277 -0
  94. package/dist/core/ui-languages.js.map +1 -0
  95. package/dist/core/user-edited-model.d.ts +3 -0
  96. package/dist/core/user-edited-model.d.ts.map +1 -0
  97. package/dist/core/user-edited-model.js +3 -0
  98. package/dist/core/user-edited-model.js.map +1 -0
  99. package/dist/edit-cache-app/app.js +1326 -0
  100. package/dist/edit-cache-app/index.html +287 -0
  101. package/dist/edit-cache-app/styles.css +664 -0
  102. package/dist/extractors/base-extractor.d.ts +15 -0
  103. package/dist/extractors/base-extractor.d.ts.map +1 -0
  104. package/dist/extractors/base-extractor.js +23 -0
  105. package/dist/extractors/base-extractor.js.map +1 -0
  106. package/dist/extractors/classify-segment.d.ts +6 -0
  107. package/dist/extractors/classify-segment.d.ts.map +1 -0
  108. package/dist/extractors/classify-segment.js +20 -0
  109. package/dist/extractors/classify-segment.js.map +1 -0
  110. package/dist/extractors/json-extractor.d.ts +16 -0
  111. package/dist/extractors/json-extractor.d.ts.map +1 -0
  112. package/dist/extractors/json-extractor.js +128 -0
  113. package/dist/extractors/json-extractor.js.map +1 -0
  114. package/dist/extractors/markdown-extractor.d.ts +15 -0
  115. package/dist/extractors/markdown-extractor.d.ts.map +1 -0
  116. package/dist/extractors/markdown-extractor.js +205 -0
  117. package/dist/extractors/markdown-extractor.js.map +1 -0
  118. package/dist/extractors/svg-extractor.d.ts +19 -0
  119. package/dist/extractors/svg-extractor.d.ts.map +1 -0
  120. package/dist/extractors/svg-extractor.js +132 -0
  121. package/dist/extractors/svg-extractor.js.map +1 -0
  122. package/dist/extractors/ui-string-extractor.d.ts +40 -0
  123. package/dist/extractors/ui-string-extractor.d.ts.map +1 -0
  124. package/dist/extractors/ui-string-extractor.js +146 -0
  125. package/dist/extractors/ui-string-extractor.js.map +1 -0
  126. package/dist/extractors/ui-string-locations.d.ts +23 -0
  127. package/dist/extractors/ui-string-locations.d.ts.map +1 -0
  128. package/dist/extractors/ui-string-locations.js +138 -0
  129. package/dist/extractors/ui-string-locations.js.map +1 -0
  130. package/dist/glossary/glossary.d.ts +34 -0
  131. package/dist/glossary/glossary.d.ts.map +1 -0
  132. package/dist/glossary/glossary.js +260 -0
  133. package/dist/glossary/glossary.js.map +1 -0
  134. package/dist/glossary/matcher.d.ts +10 -0
  135. package/dist/glossary/matcher.d.ts.map +1 -0
  136. package/dist/glossary/matcher.js +12 -0
  137. package/dist/glossary/matcher.js.map +1 -0
  138. package/dist/index.d.ts +44 -0
  139. package/dist/index.d.ts.map +1 -0
  140. package/dist/index.js +44 -0
  141. package/dist/index.js.map +1 -0
  142. package/dist/processors/admonition-placeholders.d.ts +8 -0
  143. package/dist/processors/admonition-placeholders.d.ts.map +1 -0
  144. package/dist/processors/admonition-placeholders.js +59 -0
  145. package/dist/processors/admonition-placeholders.js.map +1 -0
  146. package/dist/processors/anchor-placeholders.d.ts +8 -0
  147. package/dist/processors/anchor-placeholders.d.ts.map +1 -0
  148. package/dist/processors/anchor-placeholders.js +37 -0
  149. package/dist/processors/anchor-placeholders.js.map +1 -0
  150. package/dist/processors/batch-processor.d.ts +10 -0
  151. package/dist/processors/batch-processor.d.ts.map +1 -0
  152. package/dist/processors/batch-processor.js +33 -0
  153. package/dist/processors/batch-processor.js.map +1 -0
  154. package/dist/processors/bold-code-placeholders.d.ts +14 -0
  155. package/dist/processors/bold-code-placeholders.d.ts.map +1 -0
  156. package/dist/processors/bold-code-placeholders.js +116 -0
  157. package/dist/processors/bold-code-placeholders.js.map +1 -0
  158. package/dist/processors/doc-postprocess.d.ts +51 -0
  159. package/dist/processors/doc-postprocess.d.ts.map +1 -0
  160. package/dist/processors/doc-postprocess.js +215 -0
  161. package/dist/processors/doc-postprocess.js.map +1 -0
  162. package/dist/processors/emphasis-placeholders.d.ts +6 -0
  163. package/dist/processors/emphasis-placeholders.d.ts.map +1 -0
  164. package/dist/processors/emphasis-placeholders.js +262 -0
  165. package/dist/processors/emphasis-placeholders.js.map +1 -0
  166. package/dist/processors/flat-link-rewrite.d.ts +32 -0
  167. package/dist/processors/flat-link-rewrite.d.ts.map +1 -0
  168. package/dist/processors/flat-link-rewrite.js +90 -0
  169. package/dist/processors/flat-link-rewrite.js.map +1 -0
  170. package/dist/processors/glossary-force-placeholders.d.ts +12 -0
  171. package/dist/processors/glossary-force-placeholders.d.ts.map +1 -0
  172. package/dist/processors/glossary-force-placeholders.js +58 -0
  173. package/dist/processors/glossary-force-placeholders.js.map +1 -0
  174. package/dist/processors/inline-code-placeholders.d.ts +11 -0
  175. package/dist/processors/inline-code-placeholders.d.ts.map +1 -0
  176. package/dist/processors/inline-code-placeholders.js +87 -0
  177. package/dist/processors/inline-code-placeholders.js.map +1 -0
  178. package/dist/processors/placeholder-handler.d.ts +38 -0
  179. package/dist/processors/placeholder-handler.d.ts.map +1 -0
  180. package/dist/processors/placeholder-handler.js +55 -0
  181. package/dist/processors/placeholder-handler.js.map +1 -0
  182. package/dist/processors/translation-placeholder-leaks.d.ts +2 -0
  183. package/dist/processors/translation-placeholder-leaks.d.ts.map +1 -0
  184. package/dist/processors/translation-placeholder-leaks.js +9 -0
  185. package/dist/processors/translation-placeholder-leaks.js.map +1 -0
  186. package/dist/processors/url-placeholders.d.ts +10 -0
  187. package/dist/processors/url-placeholders.d.ts.map +1 -0
  188. package/dist/processors/url-placeholders.js +29 -0
  189. package/dist/processors/url-placeholders.js.map +1 -0
  190. package/dist/processors/validator.d.ts +23 -0
  191. package/dist/processors/validator.d.ts.map +1 -0
  192. package/dist/processors/validator.js +186 -0
  193. package/dist/processors/validator.js.map +1 -0
  194. package/dist/runtime/i18next-helpers.d.ts +146 -0
  195. package/dist/runtime/i18next-helpers.d.ts.map +1 -0
  196. package/dist/runtime/i18next-helpers.js +192 -0
  197. package/dist/runtime/i18next-helpers.js.map +1 -0
  198. package/dist/runtime/index.d.ts +4 -0
  199. package/dist/runtime/index.d.ts.map +1 -0
  200. package/dist/runtime/index.js +4 -0
  201. package/dist/runtime/index.js.map +1 -0
  202. package/dist/runtime/template.d.ts +21 -0
  203. package/dist/runtime/template.d.ts.map +1 -0
  204. package/dist/runtime/template.js +28 -0
  205. package/dist/runtime/template.js.map +1 -0
  206. package/dist/runtime/ui-language-display.d.ts +16 -0
  207. package/dist/runtime/ui-language-display.d.ts.map +1 -0
  208. package/dist/runtime/ui-language-display.js +26 -0
  209. package/dist/runtime/ui-language-display.js.map +1 -0
  210. package/dist/server/translation-editor.d.ts +25 -0
  211. package/dist/server/translation-editor.d.ts.map +1 -0
  212. package/dist/server/translation-editor.js +583 -0
  213. package/dist/server/translation-editor.js.map +1 -0
  214. package/dist/utils/concurrency.d.ts +31 -0
  215. package/dist/utils/concurrency.d.ts.map +1 -0
  216. package/dist/utils/concurrency.js +103 -0
  217. package/dist/utils/concurrency.js.map +1 -0
  218. package/dist/utils/hash.d.ts +5 -0
  219. package/dist/utils/hash.d.ts.map +1 -0
  220. package/dist/utils/hash.js +9 -0
  221. package/dist/utils/hash.js.map +1 -0
  222. package/dist/utils/ignore-parser.d.ts +7 -0
  223. package/dist/utils/ignore-parser.d.ts.map +1 -0
  224. package/dist/utils/ignore-parser.js +26 -0
  225. package/dist/utils/ignore-parser.js.map +1 -0
  226. package/dist/utils/logger.d.ts +45 -0
  227. package/dist/utils/logger.d.ts.map +1 -0
  228. package/dist/utils/logger.js +158 -0
  229. package/dist/utils/logger.js.map +1 -0
  230. package/docs/GETTING_STARTED.md +697 -0
  231. package/docs/PACKAGE_OVERVIEW.md +427 -0
  232. package/docs/ai-i18n-tools-context.md +481 -0
  233. package/package.json +117 -0
  234. package/translated-docs/README.de.md +157 -0
  235. package/translated-docs/README.es.md +157 -0
  236. package/translated-docs/README.fr.md +157 -0
  237. package/translated-docs/README.hi.md +157 -0
  238. package/translated-docs/README.ja.md +157 -0
  239. package/translated-docs/README.ko.md +157 -0
  240. package/translated-docs/README.pt-BR.md +157 -0
  241. package/translated-docs/README.zh-CN.md +157 -0
  242. package/translated-docs/README.zh-TW.md +157 -0
  243. package/translated-docs/docs/GETTING_STARTED.de.md +682 -0
  244. package/translated-docs/docs/GETTING_STARTED.es.md +682 -0
  245. package/translated-docs/docs/GETTING_STARTED.fr.md +682 -0
  246. package/translated-docs/docs/GETTING_STARTED.hi.md +682 -0
  247. package/translated-docs/docs/GETTING_STARTED.ja.md +682 -0
  248. package/translated-docs/docs/GETTING_STARTED.ko.md +682 -0
  249. package/translated-docs/docs/GETTING_STARTED.pt-BR.md +682 -0
  250. package/translated-docs/docs/GETTING_STARTED.zh-CN.md +682 -0
  251. package/translated-docs/docs/GETTING_STARTED.zh-TW.md +682 -0
  252. package/translated-docs/docs/PACKAGE_OVERVIEW.de.md +428 -0
  253. package/translated-docs/docs/PACKAGE_OVERVIEW.es.md +428 -0
  254. package/translated-docs/docs/PACKAGE_OVERVIEW.fr.md +428 -0
  255. package/translated-docs/docs/PACKAGE_OVERVIEW.hi.md +428 -0
  256. package/translated-docs/docs/PACKAGE_OVERVIEW.ja.md +428 -0
  257. package/translated-docs/docs/PACKAGE_OVERVIEW.ko.md +428 -0
  258. package/translated-docs/docs/PACKAGE_OVERVIEW.pt-BR.md +428 -0
  259. package/translated-docs/docs/PACKAGE_OVERVIEW.zh-CN.md +428 -0
  260. package/translated-docs/docs/PACKAGE_OVERVIEW.zh-TW.md +428 -0
@@ -0,0 +1,357 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+ import chalk from "chalk";
4
+ import { OpenRouterClient } from "../api/openrouter.js";
5
+ import { normalizeLocale, resolveUITranslationModels } from "../core/config.js";
6
+ import { resolveStringsJsonPath, writeAtomicUtf8 } from "./helpers.js";
7
+ import { timestamp, formatElapsedMmSs, printModelsTryInOrder } from "./format.js";
8
+ import { runMapWithConcurrency } from "../utils/concurrency.js";
9
+ import { Glossary } from "../glossary/glossary.js";
10
+ import { protectGlossaryForcedTerms, restoreGlossaryForcedTerms, } from "../processors/glossary-force-placeholders.js";
11
+ import { USER_EDITED_MODEL } from "../core/user-edited-model.js";
12
+ import { parse as parseCsv } from "csv-parse/sync";
13
+ const UI_CHUNK = 50;
14
+ const RULE = "-".repeat(100);
15
+ function localeEnglishLabel(config, locale) {
16
+ const n = normalizeLocale(locale);
17
+ return config.localeDisplayNames?.[n] ?? n;
18
+ }
19
+ /**
20
+ * Read `strings.json`, translate missing per-locale entries via OpenRouter (ordered models),
21
+ * write merged `strings.json` and flat `{locale}.json` maps (source → translation) under `ui.flatOutputDir`.
22
+ */
23
+ export async function runTranslateUI(config, opts) {
24
+ if (!config.features.translateUIStrings) {
25
+ throw new Error("Enable features.translateUIStrings in config");
26
+ }
27
+ const stringsPath = resolveStringsJsonPath(config, opts.cwd);
28
+ if (!fs.existsSync(stringsPath)) {
29
+ throw new Error(`strings.json not found: ${stringsPath} (run extract first)`);
30
+ }
31
+ let strings;
32
+ try {
33
+ strings = JSON.parse(fs.readFileSync(stringsPath, "utf8"));
34
+ }
35
+ catch (e) {
36
+ throw new Error(`Invalid strings.json: ${e instanceof Error ? e.message : String(e)}`);
37
+ }
38
+ const entries = Object.entries(strings);
39
+ const outDir = path.join(opts.cwd, config.ui.flatOutputDir);
40
+ fs.mkdirSync(outDir, { recursive: true });
41
+ const srcNorm = normalizeLocale(config.sourceLocale);
42
+ const targets = opts.locales.map((l) => normalizeLocale(l)).filter((l) => l !== srcNorm);
43
+ if (targets.length === 0) {
44
+ throw new Error("No target locales after excluding sourceLocale");
45
+ }
46
+ const glossaryUser = config.glossary?.userGlossary
47
+ ? path.join(opts.cwd, config.glossary.userGlossary)
48
+ : undefined;
49
+ if (config.glossary?.autoAddUserEditedToGlossary !== false && glossaryUser && !opts.dryRun) {
50
+ const headers = ["Original language string", "locale", "Translation", "Force"];
51
+ let csvRows = [];
52
+ if (fs.existsSync(glossaryUser)) {
53
+ const raw = fs.readFileSync(glossaryUser, "utf8");
54
+ const records = parseCsv(raw, {
55
+ columns: true,
56
+ skip_empty_lines: true,
57
+ trim: true,
58
+ });
59
+ csvRows = records.map((r) => [
60
+ r["Original language string"] ?? r["en"] ?? "",
61
+ r["locale"] ?? "",
62
+ r["Translation"] ?? r["translation"] ?? "",
63
+ r["Force"] ?? r["force"] ?? "",
64
+ ]);
65
+ }
66
+ const existingPairs = new Set(csvRows.map((r) => `${r[0]}\0${r[1]}`));
67
+ let addedToGlossary = 0;
68
+ for (const [, entry] of entries) {
69
+ if (!entry.source || !entry.models || !entry.translated)
70
+ continue;
71
+ for (const target of targets) {
72
+ if (entry.models[target] === USER_EDITED_MODEL) {
73
+ const translation = entry.translated[target];
74
+ if (translation && typeof translation === "string" && translation.trim() !== "") {
75
+ const pairKey = `${entry.source}\0${target}`;
76
+ const starKey = `${entry.source}\0*`;
77
+ if (!existingPairs.has(pairKey) && !existingPairs.has(starKey)) {
78
+ csvRows.push([entry.source, target, translation, ""]);
79
+ existingPairs.add(pairKey);
80
+ addedToGlossary++;
81
+ }
82
+ }
83
+ }
84
+ }
85
+ }
86
+ if (addedToGlossary > 0) {
87
+ const csvEscapeCell = (s) => {
88
+ if (/[",\n\r]/.test(s))
89
+ return `"${s.replace(/"/g, '""')}"`;
90
+ return s;
91
+ };
92
+ const lines = [
93
+ headers.map(csvEscapeCell).join(","),
94
+ ...csvRows.map((r) => r.map(csvEscapeCell).join(",")),
95
+ ];
96
+ writeAtomicUtf8(glossaryUser, `${lines.join("\n")}\n`);
97
+ console.log(chalk.green(`[user-glossary] Added ${addedToGlossary} user-edited entr${addedToGlossary === 1 ? "y" : "ies"} to ${config.glossary.userGlossary}`));
98
+ }
99
+ }
100
+ const glossary = new Glossary(undefined, glossaryUser, targets);
101
+ let client = null;
102
+ if (!opts.dryRun) {
103
+ try {
104
+ client = new OpenRouterClient({
105
+ config,
106
+ translationModels: resolveUITranslationModels(config),
107
+ });
108
+ }
109
+ catch (e) {
110
+ throw new Error(`OPENROUTER_API_KEY required for UI translation: ${e instanceof Error ? e.message : String(e)}`);
111
+ }
112
+ }
113
+ const models = client?.getConfiguredModels() ?? [];
114
+ const parallelLimit = Math.max(1, Math.floor(opts.concurrency ?? config.concurrency ?? 4));
115
+ // Header block
116
+ console.log(chalk.gray("\n\n___UI Translation________________________________________________________________________________________\n\n") + chalk.bold(`🌐 Translating UI strings to ${targets.length} locale(s)\n`));
117
+ printModelsTryInOrder(models);
118
+ console.log(chalk.cyan(`Strings: `) + chalk.magenta(`${entries.length} total entries`));
119
+ console.log(chalk.cyan(`Glossary terms: `) + chalk.magenta(`${glossary.size}`));
120
+ console.log(chalk.cyan(`Output dir: `) + chalk.magenta(outDir));
121
+ if (opts.logPath) {
122
+ console.log(chalk.cyan(`Output log: `) + chalk.magenta(opts.logPath));
123
+ }
124
+ if (targets.length > 1) {
125
+ console.log(chalk.cyan(`Parallel translations: `) +
126
+ chalk.magenta(`up to ${Math.min(parallelLimit, targets.length)}`));
127
+ }
128
+ if (opts.dryRun) {
129
+ console.log(chalk.yellow(`\n⚠️ Dry run mode - no changes will be made`));
130
+ }
131
+ console.log("");
132
+ let stringsUpdated = 0;
133
+ let inputTokens = 0;
134
+ let outputTokens = 0;
135
+ let costUsd = 0;
136
+ const wallStart = Date.now();
137
+ const langProgress = { completed: 0, total: targets.length };
138
+ const runSingleLocaleSequential = async (locale) => {
139
+ const localeStart = Date.now();
140
+ const missing = entries.filter(([_hash, entry]) => {
141
+ const src = entry.source ?? "";
142
+ if (!src.trim()) {
143
+ return false;
144
+ }
145
+ if (opts.force) {
146
+ return true;
147
+ }
148
+ const t = entry.translated?.[locale];
149
+ return t === undefined || String(t).trim() === "";
150
+ });
151
+ if (missing.length === 0) {
152
+ console.log(chalk.gray(`⏭️ ${timestamp()} - ${locale}: up to date`));
153
+ }
154
+ else {
155
+ console.log(chalk.yellow(`🔃 ${timestamp()} - ${locale}: ${missing.length} string(s) to translate`));
156
+ for (let i = 0; i < missing.length; i += UI_CHUNK) {
157
+ const chunk = missing.slice(i, i + UI_CHUNK);
158
+ const sources = chunk.map(([, v]) => v.source ?? "");
159
+ const chunkNum = Math.floor(i / UI_CHUNK) + 1;
160
+ const chunkTotal = Math.ceil(missing.length / UI_CHUNK);
161
+ if (opts.dryRun || !client) {
162
+ if (opts.verbose) {
163
+ console.log(chalk.yellow(` ${timestamp()} - [dry-run] chunk ${chunkNum}/${chunkTotal} (${chunk.length} strings)`));
164
+ }
165
+ continue;
166
+ }
167
+ if (opts.verbose) {
168
+ console.log(chalk.gray(` ${timestamp()} - Chunk ${chunkNum}/${chunkTotal} (${chunk.length} strings)`));
169
+ }
170
+ const protectedSources = [];
171
+ const glossaryReplacementsPerString = [];
172
+ for (const src of sources) {
173
+ const g = protectGlossaryForcedTerms(src, glossary, locale);
174
+ protectedSources.push(g.text);
175
+ glossaryReplacementsPerString.push(g.replacements);
176
+ }
177
+ const hints = glossary.findTermsInText(protectedSources.join("\n"), locale);
178
+ const uiBatch = await client.translateUIBatch(protectedSources, locale, {
179
+ glossaryHints: hints,
180
+ });
181
+ inputTokens += uiBatch.usage.inputTokens;
182
+ outputTokens += uiBatch.usage.outputTokens;
183
+ costUsd += uiBatch.cost ?? 0;
184
+ chunk.forEach(([h], idx) => {
185
+ let tr = uiBatch.translations[idx];
186
+ if (tr !== undefined) {
187
+ tr = restoreGlossaryForcedTerms(tr, glossaryReplacementsPerString[idx] ?? []);
188
+ }
189
+ if (tr !== undefined && strings[h]) {
190
+ if (!strings[h].translated) {
191
+ strings[h].translated = {};
192
+ }
193
+ strings[h].translated[locale] = tr;
194
+ if (!strings[h].models) {
195
+ strings[h].models = {};
196
+ }
197
+ strings[h].models[locale] = uiBatch.model;
198
+ stringsUpdated++;
199
+ }
200
+ });
201
+ }
202
+ if (!opts.dryRun && missing.length > 0) {
203
+ writeAtomicUtf8(stringsPath, `${JSON.stringify(strings, null, 2)}\n`);
204
+ }
205
+ }
206
+ const flat = {};
207
+ for (const entry of Object.values(strings)) {
208
+ const src = entry.source ?? "";
209
+ const tx = entry.translated?.[locale];
210
+ if (src && tx) {
211
+ flat[src] = tx;
212
+ }
213
+ }
214
+ const localePath = path.join(outDir, `${locale}.json`);
215
+ if (!opts.dryRun) {
216
+ writeAtomicUtf8(localePath, `${JSON.stringify(flat, null, 2)}\n`);
217
+ if (opts.verbose) {
218
+ console.log(chalk.gray(` ${timestamp()} - wrote ${Object.keys(flat).length} keys → ${localePath}`));
219
+ }
220
+ }
221
+ const localeElapsed = Date.now() - localeStart;
222
+ if (localeElapsed > 0) {
223
+ console.log(chalk.gray(` [${locale}] Time: ${formatElapsedMmSs(localeElapsed)}`));
224
+ }
225
+ langProgress.completed += 1;
226
+ };
227
+ const translateLocaleParallelWave = async (locale) => {
228
+ const localeStart = Date.now();
229
+ const missing = entries.filter(([_hash, entry]) => {
230
+ const src = entry.source ?? "";
231
+ if (!src.trim()) {
232
+ return false;
233
+ }
234
+ if (opts.force) {
235
+ return true;
236
+ }
237
+ const t = entry.translated?.[locale];
238
+ return t === undefined || String(t).trim() === "";
239
+ });
240
+ if (missing.length === 0) {
241
+ console.log(chalk.gray(`⏭️ ${timestamp()} - ${locale}: up to date`));
242
+ }
243
+ else {
244
+ console.log(chalk.yellow(`🔃 ${timestamp()} - ${locale}: ${missing.length} string(s) to translate`));
245
+ for (let i = 0; i < missing.length; i += UI_CHUNK) {
246
+ const chunk = missing.slice(i, i + UI_CHUNK);
247
+ const sources = chunk.map(([, v]) => v.source ?? "");
248
+ const chunkNum = Math.floor(i / UI_CHUNK) + 1;
249
+ const chunkTotal = Math.ceil(missing.length / UI_CHUNK);
250
+ if (opts.dryRun || !client) {
251
+ if (opts.verbose) {
252
+ console.log(chalk.yellow(` ${timestamp()} - [dry-run] chunk ${chunkNum}/${chunkTotal} (${chunk.length} strings)`));
253
+ }
254
+ continue;
255
+ }
256
+ if (opts.verbose) {
257
+ console.log(chalk.gray(` ${timestamp()} - Chunk ${chunkNum}/${chunkTotal} (${chunk.length} strings)`));
258
+ }
259
+ const protectedSources = [];
260
+ const glossaryReplacementsPerString = [];
261
+ for (const src of sources) {
262
+ const g = protectGlossaryForcedTerms(src, glossary, locale);
263
+ protectedSources.push(g.text);
264
+ glossaryReplacementsPerString.push(g.replacements);
265
+ }
266
+ const hints = glossary.findTermsInText(protectedSources.join("\n"), locale);
267
+ const uiBatch = await client.translateUIBatch(protectedSources, locale, {
268
+ glossaryHints: hints,
269
+ });
270
+ inputTokens += uiBatch.usage.inputTokens;
271
+ outputTokens += uiBatch.usage.outputTokens;
272
+ costUsd += uiBatch.cost ?? 0;
273
+ chunk.forEach(([h], idx) => {
274
+ let tr = uiBatch.translations[idx];
275
+ if (tr !== undefined) {
276
+ tr = restoreGlossaryForcedTerms(tr, glossaryReplacementsPerString[idx] ?? []);
277
+ }
278
+ if (tr !== undefined && strings[h]) {
279
+ if (!strings[h].translated) {
280
+ strings[h].translated = {};
281
+ }
282
+ strings[h].translated[locale] = tr;
283
+ if (!strings[h].models) {
284
+ strings[h].models = {};
285
+ }
286
+ strings[h].models[locale] = uiBatch.model;
287
+ stringsUpdated++;
288
+ }
289
+ });
290
+ }
291
+ }
292
+ const flat = {};
293
+ for (const entry of Object.values(strings)) {
294
+ const src = entry.source ?? "";
295
+ const tx = entry.translated?.[locale];
296
+ if (src && tx) {
297
+ flat[src] = tx;
298
+ }
299
+ }
300
+ const localePath = path.join(outDir, `${locale}.json`);
301
+ if (!opts.dryRun) {
302
+ writeAtomicUtf8(localePath, `${JSON.stringify(flat, null, 2)}\n`);
303
+ if (opts.verbose) {
304
+ console.log(chalk.gray(` ${timestamp()} - wrote ${Object.keys(flat).length} keys → ${localePath}`));
305
+ }
306
+ }
307
+ const localeElapsed = Date.now() - localeStart;
308
+ if (localeElapsed > 0) {
309
+ console.log(chalk.gray(` [${locale}] Time: ${formatElapsedMmSs(localeElapsed)}`));
310
+ }
311
+ langProgress.completed += 1;
312
+ };
313
+ if (targets.length <= 1) {
314
+ await runSingleLocaleSequential(targets[0]);
315
+ }
316
+ else {
317
+ for (let i = 0; i < targets.length; i += parallelLimit) {
318
+ const batch = targets.slice(i, i + parallelLimit);
319
+ const langList = batch
320
+ .map((loc) => `${localeEnglishLabel(config, loc)} (${loc})`)
321
+ .join(" • ");
322
+ console.log(chalk.yellow(RULE));
323
+ console.log(chalk.yellow(` 🚀 Running in parallel: ${langList} ${langProgress.completed}/${langProgress.total}`));
324
+ console.log(chalk.yellow(RULE));
325
+ await runMapWithConcurrency(batch, batch.length, async (locale) => {
326
+ await translateLocaleParallelWave(locale);
327
+ return locale;
328
+ });
329
+ if (!opts.dryRun) {
330
+ console.log(chalk.blue(`💾 Writing strings.json`));
331
+ writeAtomicUtf8(stringsPath, `${JSON.stringify(strings, null, 2)}\n`);
332
+ }
333
+ }
334
+ }
335
+ const wallElapsed = Date.now() - wallStart;
336
+ // Summary block
337
+ console.log(chalk.bold.green("\n✅ UI translation complete!\n"));
338
+ console.log(chalk.bold("📊 Summary:"));
339
+ console.log(` Total elapsed time: ${formatElapsedMmSs(wallElapsed)}`);
340
+ console.log(` Strings updated: ${stringsUpdated}`);
341
+ console.log(` Tokens used: ${(inputTokens + outputTokens).toLocaleString()} (in: ${inputTokens.toLocaleString()} / out: ${outputTokens.toLocaleString()})`);
342
+ if (costUsd > 0) {
343
+ console.log(chalk.green(` 💵 Total cost: $${costUsd.toFixed(6)}`));
344
+ }
345
+ else {
346
+ console.log(` Total cost: $0.00 (all up to date or dry-run)`);
347
+ }
348
+ console.log("");
349
+ return {
350
+ stringsUpdated,
351
+ localesTouched: targets,
352
+ inputTokens,
353
+ outputTokens,
354
+ costUsd,
355
+ };
356
+ }
357
+ //# sourceMappingURL=translate-ui-strings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"translate-ui-strings.js","sourceRoot":"","sources":["../../src/cli/translate-ui-strings.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ /** Namespace prefix for standalone SVG asset rows in `translations.filepath` / `file_tracking.filepath`. */
2
+ export declare const SVG_ASSETS_PREFIX = "svg-assets:";
3
+ /**
4
+ * Resolve a cache key stored in `translations.filepath` or `file_tracking.filepath` to an absolute
5
+ * path on disk for existence checks (`cleanup`, orphan pruning).
6
+ *
7
+ * - `doc-block:*` — documentation file tracking (see {@link resolveDocTrackingKeyToAbs})
8
+ * - `svg-assets:*` — SVG source path relative to project root
9
+ * - any other string — treated as a path relative to project root
10
+ */
11
+ export declare function resolveCacheTrackingKeyToAbs(projectRoot: string, key: string): string;
12
+ //# sourceMappingURL=cache-tracking-keys.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache-tracking-keys.d.ts","sourceRoot":"","sources":["../../src/core/cache-tracking-keys.ts"],"names":[],"mappings":"AAGA,4GAA4G;AAC5G,eAAO,MAAM,iBAAiB,gBAAgB,CAAC;AAE/C;;;;;;;GAOG;AACH,wBAAgB,4BAA4B,CAAC,WAAW,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAMrF"}
@@ -0,0 +1,20 @@
1
+ import path from "path";
2
+ import { resolveDocTrackingKeyToAbs } from "./doc-file-tracking.js";
3
+ /** Namespace prefix for standalone SVG asset rows in `translations.filepath` / `file_tracking.filepath`. */
4
+ export const SVG_ASSETS_PREFIX = "svg-assets:";
5
+ /**
6
+ * Resolve a cache key stored in `translations.filepath` or `file_tracking.filepath` to an absolute
7
+ * path on disk for existence checks (`cleanup`, orphan pruning).
8
+ *
9
+ * - `doc-block:*` — documentation file tracking (see {@link resolveDocTrackingKeyToAbs})
10
+ * - `svg-assets:*` — SVG source path relative to project root
11
+ * - any other string — treated as a path relative to project root
12
+ */
13
+ export function resolveCacheTrackingKeyToAbs(projectRoot, key) {
14
+ if (key.startsWith(SVG_ASSETS_PREFIX)) {
15
+ const rel = key.slice(SVG_ASSETS_PREFIX.length);
16
+ return path.resolve(projectRoot, rel);
17
+ }
18
+ return resolveDocTrackingKeyToAbs(projectRoot, key);
19
+ }
20
+ //# sourceMappingURL=cache-tracking-keys.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache-tracking-keys.js","sourceRoot":"","sources":["../../src/core/cache-tracking-keys.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,0BAA0B,EAAE,MAAM,wBAAwB,CAAC;AAEpE,4GAA4G;AAC5G,MAAM,CAAC,MAAM,iBAAiB,GAAG,aAAa,CAAC;AAE/C;;;;;;;GAOG;AACH,MAAM,UAAU,4BAA4B,CAAC,WAAmB,EAAE,GAAW;IAC3E,IAAI,GAAG,CAAC,UAAU,CAAC,iBAAiB,CAAC,EAAE,CAAC;QACtC,MAAM,GAAG,GAAG,GAAG,CAAC,KAAK,CAAC,iBAAiB,CAAC,MAAM,CAAC,CAAC;QAChD,OAAO,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC;IACxC,CAAC;IACD,OAAO,0BAA0B,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC;AACtD,CAAC"}
@@ -0,0 +1,153 @@
1
+ import type { CacheEntry, CleanupStats, FileTracking, TranslationRow } from "./types.js";
2
+ /**
3
+ * SQLite translation cache. `better-sqlite3` uses a single native connection per instance
4
+ * (no JS-level pool); reuse one instance per process for best throughput.
5
+ */
6
+ export declare class TranslationCache {
7
+ private db;
8
+ private readonly dbFilePath;
9
+ constructor(cachePath: string);
10
+ private applyMigrations;
11
+ /** Segment hash (normalized whitespace, SHA-256, 16 hex chars). */
12
+ static computeHash(content: string): string;
13
+ /**
14
+ * Cached segment text and model id (as stored on last successful translation).
15
+ * Updates `last_hit_at` / optional filepath tracking like {@link getSegment}.
16
+ */
17
+ getSegmentDetails(sourceHash: string, locale: string, filepath?: string, startLine?: number): {
18
+ text: string;
19
+ model: string | null;
20
+ } | null;
21
+ getSegment(sourceHash: string, locale: string, filepath?: string, startLine?: number): string | null;
22
+ setSegment(sourceHash: string, locale: string, sourceText: string, translatedText: string, model: string, filepath?: string, startLine?: number | null): void;
23
+ getFileHash(filepath: string, locale: string): string | null;
24
+ setFileStatus(filepath: string, locale: string, sourceHash: string): void;
25
+ /**
26
+ * Remove file-tracking for one path/locale so the next run does not skip the file.
27
+ * Segment rows stay keyed by `(source_hash, locale)`; `--force` bypasses segment cache reads so rows refresh on re-translate.
28
+ */
29
+ clearFile(filepath: string, locale: string): void;
30
+ getStats(): {
31
+ totalSegments: number;
32
+ totalFiles: number;
33
+ byLocale: Record<string, number>;
34
+ };
35
+ /**
36
+ * Aggregate documentation-cache stats for dashboards (stale vs active, per locale/model).
37
+ */
38
+ getDetailedStats(): {
39
+ totalSegments: number;
40
+ totalFiles: number;
41
+ staleSegments: number;
42
+ activeSegments: number;
43
+ byLocale: {
44
+ locale: string;
45
+ total: number;
46
+ stale: number;
47
+ active: number;
48
+ }[];
49
+ byModel: {
50
+ model: string;
51
+ count: number;
52
+ }[];
53
+ byModelLocale: {
54
+ model: string;
55
+ locale: string;
56
+ count: number;
57
+ }[];
58
+ uniqueFilepaths: number;
59
+ };
60
+ clear(locale?: string): void;
61
+ /**
62
+ * Set `last_hit_at = NULL` for markdown segments that were not hit this run.
63
+ * Scoped to markdown-like paths only so JSON (and other) rows are not cleared.
64
+ * @param keysHit - entries as `sourceHash|locale`.
65
+ */
66
+ resetLastHitAtForUnhitMarkdown(hitKeys: Set<string>): number;
67
+ /**
68
+ * Set `last_hit_at = NULL` for JSON UI/doc segments that were not hit this run.
69
+ * @param keysHit - entries as `sourceHash|locale`.
70
+ */
71
+ resetLastHitAtForUnhitJson(hitKeys: Set<string>): number;
72
+ private resetLastHitAtForUnhitScoped;
73
+ /**
74
+ * Like {@link resetLastHitAtForUnhitMarkdown}, but only rows whose `filepath` is in `allowedRelPaths`
75
+ * (e.g. markdown files in scope for this translate run after path filters).
76
+ */
77
+ resetLastHitAtForUnhitMarkdownInScope(hitKeys: Set<string>, allowedRelPaths: readonly string[]): number;
78
+ /**
79
+ * Like {@link resetLastHitAtForUnhitJson}, but only rows whose `filepath` is in `allowedRelPaths`.
80
+ */
81
+ resetLastHitAtForUnhitJsonInScope(hitKeys: Set<string>, allowedRelPaths: readonly string[]): number;
82
+ private resetLastHitAtForUnhitScopedWithScope;
83
+ cleanupStaleTranslations(dryRun?: boolean): {
84
+ count: number;
85
+ deletedRows: {
86
+ source_hash: string;
87
+ locale: string;
88
+ filepath: string | null;
89
+ }[];
90
+ };
91
+ listTranslations(filters?: {
92
+ filename?: string;
93
+ locale?: string;
94
+ model?: string;
95
+ source_hash?: string;
96
+ source_text?: string;
97
+ translated_text?: string;
98
+ last_hit_at_null?: boolean;
99
+ /** When true, only rows with a non-null `last_hit_at` (active). Mutually exclusive with `last_hit_at_null` in normal use. */
100
+ last_hit_at_not_null?: boolean;
101
+ limit?: number;
102
+ offset?: number;
103
+ }): {
104
+ rows: TranslationRow[];
105
+ total: number;
106
+ };
107
+ updateTranslation(sourceHash: string, locale: string, translatedText: string): void;
108
+ deleteTranslation(sourceHash: string, locale: string): void;
109
+ deleteByFilters(filters?: {
110
+ filename?: string;
111
+ locale?: string;
112
+ model?: string;
113
+ source_hash?: string;
114
+ source_text?: string;
115
+ translated_text?: string;
116
+ last_hit_at_null?: boolean;
117
+ last_hit_at_not_null?: boolean;
118
+ }): number;
119
+ /** Deletes matching rows in `translations` only (see {@link deleteFileTrackingByPath} for tracking keys). */
120
+ deleteTranslationsByFilepath(filepath: string): number;
121
+ /** Deletes all `file_tracking` rows for this cache key (all locales). */
122
+ deleteFileTrackingByPath(filepath: string): number;
123
+ /** Distinct `filepath` values in `file_tracking` (cache keys: `doc-block:…`, `svg-assets:…`, etc.). */
124
+ listFileTrackingPaths(): string[];
125
+ /**
126
+ * Remove `file_tracking` rows whose resolved path does not exist on disk under `projectRoot`.
127
+ */
128
+ pruneOrphanedFileTrackingByDisk(projectRoot: string, dryRun: boolean): number;
129
+ /**
130
+ * @deprecated Prefer {@link deleteTranslationsByFilepath} / {@link deleteFileTrackingByPath} explicitly.
131
+ * Deletes `translations` rows only (no longer deletes `file_tracking`).
132
+ */
133
+ deleteByFilepath(filepath: string): number;
134
+ getUniqueLocales(): string[];
135
+ getUniqueFilepaths(): string[];
136
+ getUniqueModels(): string[];
137
+ close(): void;
138
+ getSegmentAsync(hash: string, locale: string): Promise<string | null>;
139
+ setSegmentAsync(entry: CacheEntry): Promise<void>;
140
+ getFileStatus(filepath: string, locale: string): Promise<FileTracking | null>;
141
+ setFileStatusAsync(filepath: string, locale: string, hash: string): Promise<void>;
142
+ /**
143
+ * @param markdownKeys - `sourceHash|locale` for markdown segments hit this run (may be empty).
144
+ * @param jsonKeys - `sourceHash|locale` for JSON segments hit this run (may be empty).
145
+ */
146
+ resetLastHitAtForUnhit(markdownKeys: string[], jsonKeys: string[]): Promise<void>;
147
+ cleanup(): Promise<CleanupStats>;
148
+ /** Hot SQLite backup to another file. */
149
+ backupTo(destinationPath: string): Promise<void>;
150
+ /** Replace the on-disk DB with a copied file; closes and reopens the connection. */
151
+ restoreFrom(sourcePath: string): void;
152
+ }
153
+ //# sourceMappingURL=cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../src/core/cache.ts"],"names":[],"mappings":"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"}