@babelize/engine 0.0.0-stage → 0.1.2

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 (270) hide show
  1. package/LICENSE +202 -0
  2. package/dist/BabelizeEngine.d.ts +12 -0
  3. package/dist/BabelizeEngine.js +47 -0
  4. package/dist/analysis/analyze.d.ts +106 -0
  5. package/dist/analysis/analyze.js +323 -0
  6. package/dist/config/env.d.ts +9 -0
  7. package/dist/config/env.js +16 -0
  8. package/dist/config.d.ts +74 -0
  9. package/dist/config.js +47 -0
  10. package/dist/detection/stack.d.ts +42 -0
  11. package/dist/detection/stack.js +277 -0
  12. package/dist/django/catalog.d.ts +92 -0
  13. package/dist/django/catalog.js +677 -0
  14. package/dist/django/extract.d.ts +20 -0
  15. package/dist/django/extract.js +79 -0
  16. package/dist/django/inject-file.d.ts +6 -0
  17. package/dist/django/inject-file.js +52 -0
  18. package/dist/django/inject.d.ts +11 -0
  19. package/dist/django/inject.js +205 -0
  20. package/dist/django/keys.d.ts +21 -0
  21. package/dist/django/keys.js +63 -0
  22. package/dist/django/locale-names.d.ts +13 -0
  23. package/dist/django/locale-names.js +60 -0
  24. package/dist/django/mo-file.d.ts +6 -0
  25. package/dist/django/mo-file.js +60 -0
  26. package/dist/django/plural-forms.d.ts +34 -0
  27. package/dist/django/plural-forms.js +216 -0
  28. package/dist/django/po-file.d.ts +38 -0
  29. package/dist/django/po-file.js +273 -0
  30. package/dist/django/python-extract.d.ts +34 -0
  31. package/dist/django/python-extract.js +619 -0
  32. package/dist/django/python-lexer.d.ts +65 -0
  33. package/dist/django/python-lexer.js +398 -0
  34. package/dist/django/template-extract.d.ts +32 -0
  35. package/dist/django/template-extract.js +680 -0
  36. package/dist/django/types.d.ts +49 -0
  37. package/dist/django/types.js +15 -0
  38. package/dist/index.d.ts +59 -0
  39. package/dist/index.js +140 -0
  40. package/dist/injection/InjectionStrategy.d.ts +62 -0
  41. package/dist/injection/InjectionStrategy.js +2 -0
  42. package/dist/injection/StrategyFactory.d.ts +4 -0
  43. package/dist/injection/StrategyFactory.js +29 -0
  44. package/dist/injection/html/html-injector.d.ts +11 -0
  45. package/dist/injection/html/html-injector.js +173 -0
  46. package/dist/injection/strategies/NextIntlStrategy.d.ts +25 -0
  47. package/dist/injection/strategies/NextIntlStrategy.js +141 -0
  48. package/dist/injection/strategies/ReactI18nextStrategy.d.ts +19 -0
  49. package/dist/injection/strategies/ReactI18nextStrategy.js +116 -0
  50. package/dist/injection/strategies/VanillaStrategy.d.ts +11 -0
  51. package/dist/injection/strategies/VanillaStrategy.js +73 -0
  52. package/dist/injection/strategies/VueI18nStrategy.d.ts +11 -0
  53. package/dist/injection/strategies/VueI18nStrategy.js +84 -0
  54. package/dist/local/formatter.d.ts +26 -0
  55. package/dist/local/formatter.js +105 -0
  56. package/dist/local/git.d.ts +23 -0
  57. package/dist/local/git.js +136 -0
  58. package/dist/local/hosted-provider.d.ts +68 -0
  59. package/dist/local/hosted-provider.js +215 -0
  60. package/dist/local/index.d.ts +23 -0
  61. package/dist/local/index.js +75 -0
  62. package/dist/local/provider.d.ts +56 -0
  63. package/dist/local/provider.js +119 -0
  64. package/dist/local/pseudo-provider.d.ts +18 -0
  65. package/dist/local/pseudo-provider.js +208 -0
  66. package/dist/local/report.d.ts +177 -0
  67. package/dist/local/report.js +186 -0
  68. package/dist/local/translate-core.d.ts +218 -0
  69. package/dist/local/translate-core.js +499 -0
  70. package/dist/local/translate-messages.d.ts +49 -0
  71. package/dist/local/translate-messages.js +89 -0
  72. package/dist/local/workspace-copy.d.ts +91 -0
  73. package/dist/local/workspace-copy.js +355 -0
  74. package/dist/modules/extractor/extract.d.ts +20 -0
  75. package/dist/modules/extractor/extract.js +709 -0
  76. package/dist/modules/extractor/index.d.ts +2 -0
  77. package/dist/modules/extractor/index.js +63 -0
  78. package/dist/modules/finalization/django-finalize.d.ts +28 -0
  79. package/dist/modules/finalization/django-finalize.js +412 -0
  80. package/dist/modules/finalization/finalize.d.ts +38 -0
  81. package/dist/modules/finalization/finalize.js +745 -0
  82. package/dist/modules/finalization/index.d.ts +1 -0
  83. package/dist/modules/finalization/index.js +5 -0
  84. package/dist/modules/finalization/nextjs-finalize.d.ts +40 -0
  85. package/dist/modules/finalization/nextjs-finalize.js +328 -0
  86. package/dist/modules/finalization/static-runtime.d.ts +9 -0
  87. package/dist/modules/finalization/static-runtime.js +261 -0
  88. package/dist/modules/finalization/writes.d.ts +29 -0
  89. package/dist/modules/finalization/writes.js +78 -0
  90. package/dist/modules/format-injection/index.d.ts +19 -0
  91. package/dist/modules/format-injection/index.js +273 -0
  92. package/dist/modules/format-injection/inject-formats.d.ts +31 -0
  93. package/dist/modules/format-injection/inject-formats.js +208 -0
  94. package/dist/modules/glossary/index.d.ts +2 -0
  95. package/dist/modules/glossary/index.js +16 -0
  96. package/dist/modules/glossary/rules.d.ts +81 -0
  97. package/dist/modules/glossary/rules.js +244 -0
  98. package/dist/modules/glossary/types.d.ts +22 -0
  99. package/dist/modules/glossary/types.js +2 -0
  100. package/dist/modules/injection/index.d.ts +1 -0
  101. package/dist/modules/injection/index.js +6 -0
  102. package/dist/modules/injection/inject.d.ts +29 -0
  103. package/dist/modules/injection/inject.js +1050 -0
  104. package/dist/modules/keygen/index.d.ts +1 -0
  105. package/dist/modules/keygen/index.js +11 -0
  106. package/dist/modules/keygen/keygen.d.ts +4 -0
  107. package/dist/modules/keygen/keygen.js +123 -0
  108. package/dist/modules/keygen/locale-data.d.ts +7 -0
  109. package/dist/modules/keygen/locale-data.js +73 -0
  110. package/dist/modules/keygen/public.d.ts +2 -0
  111. package/dist/modules/keygen/public.js +12 -0
  112. package/dist/modules/locale-builder/index.d.ts +1 -0
  113. package/dist/modules/locale-builder/index.js +7 -0
  114. package/dist/modules/locale-builder/locales.d.ts +13 -0
  115. package/dist/modules/locale-builder/locales.js +130 -0
  116. package/dist/modules/lockfile/hasher.d.ts +7 -0
  117. package/dist/modules/lockfile/hasher.js +13 -0
  118. package/dist/modules/lockfile/index.d.ts +3 -0
  119. package/dist/modules/lockfile/index.js +22 -0
  120. package/dist/modules/lockfile/lockfile-manager.d.ts +99 -0
  121. package/dist/modules/lockfile/lockfile-manager.js +497 -0
  122. package/dist/modules/lockfile/schema.d.ts +196 -0
  123. package/dist/modules/lockfile/schema.js +56 -0
  124. package/dist/modules/parser/index.d.ts +2 -0
  125. package/dist/modules/parser/index.js +9 -0
  126. package/dist/modules/summary/index.d.ts +1 -0
  127. package/dist/modules/summary/index.js +7 -0
  128. package/dist/modules/summary/summary.d.ts +9 -0
  129. package/dist/modules/summary/summary.js +195 -0
  130. package/dist/modules/sync-detector/index.d.ts +2 -0
  131. package/dist/modules/sync-detector/index.js +7 -0
  132. package/dist/modules/sync-detector/reporter.d.ts +3 -0
  133. package/dist/modules/sync-detector/reporter.js +16 -0
  134. package/dist/modules/sync-detector/sync-detector.d.ts +39 -0
  135. package/dist/modules/sync-detector/sync-detector.js +374 -0
  136. package/dist/modules/translator/batch-optimizer.d.ts +12 -0
  137. package/dist/modules/translator/batch-optimizer.js +30 -0
  138. package/dist/modules/translator/client/byok.provider.d.ts +64 -0
  139. package/dist/modules/translator/client/byok.provider.js +319 -0
  140. package/dist/modules/translator/client/direct-translator.client.d.ts +12 -0
  141. package/dist/modules/translator/client/direct-translator.client.js +71 -0
  142. package/dist/modules/translator/client/gemini.provider.d.ts +1 -0
  143. package/dist/modules/translator/client/gemini.provider.js +110 -0
  144. package/dist/modules/translator/client/groq.provider.d.ts +1 -0
  145. package/dist/modules/translator/client/groq.provider.js +111 -0
  146. package/dist/modules/translator/client/request.types.d.ts +1 -0
  147. package/dist/modules/translator/client/request.types.js +2 -0
  148. package/dist/modules/translator/client/retry.d.ts +29 -0
  149. package/dist/modules/translator/client/retry.js +94 -0
  150. package/dist/modules/translator/client/test-utils/mock.client.d.ts +31 -0
  151. package/dist/modules/translator/client/test-utils/mock.client.js +59 -0
  152. package/dist/modules/translator/client/translator.interface.d.ts +1 -0
  153. package/dist/modules/translator/client/translator.interface.js +2 -0
  154. package/dist/modules/translator/icu-branches.d.ts +138 -0
  155. package/dist/modules/translator/icu-branches.js +393 -0
  156. package/dist/modules/translator/language-codes/errors.d.ts +10 -0
  157. package/dist/modules/translator/language-codes/errors.js +18 -0
  158. package/dist/modules/translator/language-codes/flores-map.d.ts +1 -0
  159. package/dist/modules/translator/language-codes/flores-map.js +107 -0
  160. package/dist/modules/translator/language-codes/index.d.ts +11 -0
  161. package/dist/modules/translator/language-codes/index.js +24 -0
  162. package/dist/modules/translator/language-codes/language-mapper.d.ts +25 -0
  163. package/dist/modules/translator/language-codes/language-mapper.js +132 -0
  164. package/dist/modules/translator/language-codes/rtl-languages.d.ts +2 -0
  165. package/dist/modules/translator/language-codes/rtl-languages.js +9 -0
  166. package/dist/modules/translator/memory/memory-matcher.d.ts +8 -0
  167. package/dist/modules/translator/memory/memory-matcher.js +218 -0
  168. package/dist/modules/translator/memory/types.d.ts +22 -0
  169. package/dist/modules/translator/memory/types.js +2 -0
  170. package/dist/modules/translator/translate.d.ts +74 -0
  171. package/dist/modules/translator/translate.js +1047 -0
  172. package/dist/modules/vue/migrate.d.ts +13 -0
  173. package/dist/modules/vue/migrate.js +40 -0
  174. package/dist/modules/vue/script-inject.d.ts +16 -0
  175. package/dist/modules/vue/script-inject.js +115 -0
  176. package/dist/modules/vue/sfc.d.ts +11 -0
  177. package/dist/modules/vue/sfc.js +51 -0
  178. package/dist/modules/vue/template-rewrite.d.ts +25 -0
  179. package/dist/modules/vue/template-rewrite.js +76 -0
  180. package/dist/modules/vue/template-scan.d.ts +29 -0
  181. package/dist/modules/vue/template-scan.js +264 -0
  182. package/dist/modules/workspace/index.d.ts +1 -0
  183. package/dist/modules/workspace/index.js +5 -0
  184. package/dist/modules/workspace/validate.d.ts +13 -0
  185. package/dist/modules/workspace/validate.js +333 -0
  186. package/dist/orchestrator.d.ts +13 -0
  187. package/dist/orchestrator.js +727 -0
  188. package/dist/providers/default-translation-provider.d.ts +20 -0
  189. package/dist/providers/default-translation-provider.js +30 -0
  190. package/dist/providers/index.d.ts +2 -0
  191. package/dist/providers/index.js +21 -0
  192. package/dist/providers/types.d.ts +153 -0
  193. package/dist/providers/types.js +2 -0
  194. package/dist/qa/check-project.d.ts +50 -0
  195. package/dist/qa/check-project.js +193 -0
  196. package/dist/qa/gettext-files.d.ts +15 -0
  197. package/dist/qa/gettext-files.js +115 -0
  198. package/dist/qa/locale-files.d.ts +44 -0
  199. package/dist/qa/locale-files.js +159 -0
  200. package/dist/qa/locale-qa.d.ts +61 -0
  201. package/dist/qa/locale-qa.js +342 -0
  202. package/dist/qa/review.d.ts +43 -0
  203. package/dist/qa/review.js +175 -0
  204. package/dist/runtime/config.d.ts +8 -0
  205. package/dist/runtime/config.js +37 -0
  206. package/dist/runtime/index.d.ts +3 -0
  207. package/dist/runtime/index.js +8 -0
  208. package/dist/runtime/types.d.ts +427 -0
  209. package/dist/runtime/types.js +38 -0
  210. package/dist/types.d.ts +134 -0
  211. package/dist/types.js +12 -0
  212. package/dist/utils/ast-helpers.d.ts +57 -0
  213. package/dist/utils/ast-helpers.js +608 -0
  214. package/dist/utils/cache-keys.d.ts +8 -0
  215. package/dist/utils/cache-keys.js +18 -0
  216. package/dist/utils/circuit-breaker.d.ts +43 -0
  217. package/dist/utils/circuit-breaker.js +119 -0
  218. package/dist/utils/concurrent-map.d.ts +4 -0
  219. package/dist/utils/concurrent-map.js +21 -0
  220. package/dist/utils/detect-format.d.ts +5 -0
  221. package/dist/utils/detect-format.js +125 -0
  222. package/dist/utils/extraction-options.d.ts +29 -0
  223. package/dist/utils/extraction-options.js +33 -0
  224. package/dist/utils/file-utils.d.ts +33 -0
  225. package/dist/utils/file-utils.js +267 -0
  226. package/dist/utils/glossary-match.d.ts +9 -0
  227. package/dist/utils/glossary-match.js +25 -0
  228. package/dist/utils/html-extractor.d.ts +8 -0
  229. package/dist/utils/html-extractor.js +317 -0
  230. package/dist/utils/i18next-icu.d.ts +38 -0
  231. package/dist/utils/i18next-icu.js +159 -0
  232. package/dist/utils/icu-message.d.ts +65 -0
  233. package/dist/utils/icu-message.js +346 -0
  234. package/dist/utils/icu-spans.d.ts +10 -0
  235. package/dist/utils/icu-spans.js +126 -0
  236. package/dist/utils/jsx-message.d.ts +93 -0
  237. package/dist/utils/jsx-message.js +628 -0
  238. package/dist/utils/key-usage.d.ts +35 -0
  239. package/dist/utils/key-usage.js +247 -0
  240. package/dist/utils/logger.d.ts +24 -0
  241. package/dist/utils/logger.js +33 -0
  242. package/dist/utils/metadata.d.ts +82 -0
  243. package/dist/utils/metadata.js +261 -0
  244. package/dist/utils/module-constants.d.ts +30 -0
  245. package/dist/utils/module-constants.js +265 -0
  246. package/dist/utils/not-injected.d.ts +6 -0
  247. package/dist/utils/not-injected.js +38 -0
  248. package/dist/utils/placeholder-protection.d.ts +74 -0
  249. package/dist/utils/placeholder-protection.js +181 -0
  250. package/dist/utils/pseudo-markers.d.ts +9 -0
  251. package/dist/utils/pseudo-markers.js +16 -0
  252. package/dist/utils/string-utils.d.ts +52 -0
  253. package/dist/utils/string-utils.js +270 -0
  254. package/dist/utils/translation-quality.d.ts +34 -0
  255. package/dist/utils/translation-quality.js +156 -0
  256. package/dist/utils/translation-sanitizer.d.ts +11 -0
  257. package/dist/utils/translation-sanitizer.js +71 -0
  258. package/dist/utils/translator-caller.d.ts +32 -0
  259. package/dist/utils/translator-caller.js +217 -0
  260. package/dist/utils/translator-load-balancer.d.ts +73 -0
  261. package/dist/utils/translator-load-balancer.js +297 -0
  262. package/dist/utils/ui-copy.d.ts +32 -0
  263. package/dist/utils/ui-copy.js +126 -0
  264. package/dist/utils/untranslated.d.ts +15 -0
  265. package/dist/utils/untranslated.js +34 -0
  266. package/dist/utils/workspace.d.ts +14 -0
  267. package/dist/utils/workspace.js +89 -0
  268. package/package.json +64 -4
  269. package/schemas/translate-report.schema.json +297 -0
  270. package/README.md +0 -3
@@ -0,0 +1,81 @@
1
+ import type { AlwaysTranslateAsEntry, GlossaryEntryType } from './types';
2
+ /**
3
+ * Regex source matching `term` as a whole term: not preceded or followed by a
4
+ * letter, digit or underscore in any script ("Café" matches in "Café menu",
5
+ * "app" does not match in "apply" or "appé"). Use with the `u` flag.
6
+ */
7
+ export declare function termPattern(term: string): string;
8
+ /** Whether `text` contains `term` as a whole term, ignoring case. */
9
+ export declare function containsTerm(text: string, term: string): boolean;
10
+ /**
11
+ * The words of a source string a glossary rule can apply to: placeholders,
12
+ * tags, URLs, emails and code removed, and for an ICU message its argument
13
+ * names and selector keys too. "Open https://x.com/dashboard" has no
14
+ * "dashboard" a translator would translate. With `neverTranslate`, those
15
+ * terms are removed too: "Dashboard" in "Babelize Dashboard" (never
16
+ * translated) is not a use of a "Dashboard" rule.
17
+ */
18
+ export declare function translatableText(source: string, neverTranslate?: readonly string[]): string;
19
+ /**
20
+ * Whether a glossary term occurs in a source string's translatable text (see
21
+ * translatableText). Pass the never-translate terms when asking about an
22
+ * "always translate as" term: inside a never-translate term it doesn't count.
23
+ */
24
+ export declare function sourceHasTerm(source: string, term: string, neverTranslate?: readonly string[]): boolean;
25
+ /**
26
+ * BCP-47 casing for a locale code: `pt_br` / `PT-br` → `pt-BR`,
27
+ * `zh-hant` → `zh-Hant`, `es-419` stays. Anything that isn't
28
+ * language[-Script][-REGION] is returned trimmed, otherwise unchanged.
29
+ */
30
+ export declare function canonicalLocale(code: string): string;
31
+ /** Keys of a locale → value record in canonical form; on a clash the first key (in insertion order) wins. */
32
+ export declare function canonicalizeLocaleKeys(record: Record<string, string> | null | undefined): Record<string, string>;
33
+ /**
34
+ * The value for `locale` in a locale-keyed record: the exact locale (in any
35
+ * casing / separator), else its base language (`pt` serves `pt-BR`).
36
+ */
37
+ export declare function localeValue(record: Record<string, string> | null | undefined, locale: string): string | undefined;
38
+ export interface GlossaryRuleInput {
39
+ term: string;
40
+ type: GlossaryEntryType | string;
41
+ translations?: Record<string, string> | null;
42
+ }
43
+ /** A project's glossary after normalization: deduplicated, deterministic, conflicts resolved. */
44
+ export interface GlossaryRules {
45
+ neverTranslate: string[];
46
+ alwaysTranslateAs: AlwaysTranslateAsEntry[];
47
+ /** Terms that had conflicting rules, with how the conflict was resolved (for QA notes). */
48
+ conflicts: Array<{
49
+ term: string;
50
+ message: string;
51
+ }>;
52
+ }
53
+ export declare const EMPTY_GLOSSARY: GlossaryRules;
54
+ /**
55
+ * Normalize raw glossary entries. Terms match case-insensitively, so entries
56
+ * are grouped by lowercased term:
57
+ * - never-translate wins over always-translate-as for the same term (keeping
58
+ * a term as-is can't corrupt the output; a translation for the wrong sense can);
59
+ * - several always-translate-as entries merge their locales (the first entry,
60
+ * in term order, wins a locale they both define);
61
+ * - locale keys are canonicalized (`pt_br` → `pt-BR`).
62
+ * The result doesn't depend on the input order.
63
+ */
64
+ export declare function normalizeGlossary(entries: GlossaryRuleInput[]): GlossaryRules;
65
+ /** Always-translate-as terms with a translation for `locale` (exact, then base language). */
66
+ export declare function fixedTermsFor(rules: GlossaryRules, locale: string): Array<{
67
+ term: string;
68
+ translation: string;
69
+ }>;
70
+ /** Whether `source` contains an always-translate-as term that has a translation for `locale`. */
71
+ export declare function hasFixedTerm(source: string, rules: GlossaryRules, locale: string): boolean;
72
+ /**
73
+ * Fingerprint of the glossary rules that shape `source`'s translation into
74
+ * `locale`: the never-translate terms it contains and the always-translate-as
75
+ * terms it contains with their translation for the locale. Empty when no rule
76
+ * applies, so adding a rule for an unrelated term changes nothing. Stored per
77
+ * locale in the lockfile: a key is re-translated when this changes.
78
+ */
79
+ export declare function glossaryFingerprint(source: string, locale: string, rules: GlossaryRules): string;
80
+ /** QA notes for conflicting rules whose term occurs in `source`. */
81
+ export declare function conflictNotes(source: string, rules: GlossaryRules): string[];
@@ -0,0 +1,244 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.EMPTY_GLOSSARY = void 0;
4
+ exports.termPattern = termPattern;
5
+ exports.containsTerm = containsTerm;
6
+ exports.translatableText = translatableText;
7
+ exports.sourceHasTerm = sourceHasTerm;
8
+ exports.canonicalLocale = canonicalLocale;
9
+ exports.canonicalizeLocaleKeys = canonicalizeLocaleKeys;
10
+ exports.localeValue = localeValue;
11
+ exports.normalizeGlossary = normalizeGlossary;
12
+ exports.fixedTermsFor = fixedTermsFor;
13
+ exports.hasFixedTerm = hasFixedTerm;
14
+ exports.glossaryFingerprint = glossaryFingerprint;
15
+ exports.conflictNotes = conflictNotes;
16
+ /**
17
+ * Project glossary rules, shared by the translate phase, locale QA, prompt
18
+ * hints and the CLI/MCP. One place decides how a term matches, which
19
+ * translation applies to a locale, and what happens when rules conflict.
20
+ */
21
+ const crypto_1 = require("crypto");
22
+ const placeholder_protection_1 = require("../../utils/placeholder-protection");
23
+ const icu_message_1 = require("../../utils/icu-message");
24
+ function escapeRegex(s) {
25
+ return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
26
+ }
27
+ /**
28
+ * Regex source matching `term` as a whole term: not preceded or followed by a
29
+ * letter, digit or underscore in any script ("Café" matches in "Café menu",
30
+ * "app" does not match in "apply" or "appé"). Use with the `u` flag.
31
+ */
32
+ function termPattern(term) {
33
+ return `(?<![\\p{L}\\p{N}_])${escapeRegex(term)}(?![\\p{L}\\p{N}_])`;
34
+ }
35
+ const termRegexes = new Map();
36
+ /** Whether `text` contains `term` as a whole term, ignoring case. */
37
+ function containsTerm(text, term) {
38
+ if (!term.trim())
39
+ return false;
40
+ // Cheap pre-check: most (key, term) pairs share nothing.
41
+ if (!text.toLowerCase().includes(term.toLowerCase())) {
42
+ // toLowerCase can change length for a few letters (İ); fall through only then.
43
+ if (text.length === text.toLowerCase().length && term.length === term.toLowerCase().length)
44
+ return false;
45
+ }
46
+ let re = termRegexes.get(term);
47
+ if (!re) {
48
+ if (termRegexes.size > 10000)
49
+ termRegexes.clear();
50
+ re = new RegExp(termPattern(term), 'iu');
51
+ termRegexes.set(term, re);
52
+ }
53
+ return re.test(text);
54
+ }
55
+ const NO_TERMS = [];
56
+ /** Per never-translate list (by identity), source → translatable text. */
57
+ const translatableCache = new WeakMap();
58
+ /**
59
+ * The words of a source string a glossary rule can apply to: placeholders,
60
+ * tags, URLs, emails and code removed, and for an ICU message its argument
61
+ * names and selector keys too. "Open https://x.com/dashboard" has no
62
+ * "dashboard" a translator would translate. With `neverTranslate`, those
63
+ * terms are removed too: "Dashboard" in "Babelize Dashboard" (never
64
+ * translated) is not a use of a "Dashboard" rule.
65
+ */
66
+ function translatableText(source, neverTranslate = NO_TERMS) {
67
+ let cache = translatableCache.get(neverTranslate);
68
+ if (!cache) {
69
+ cache = new Map();
70
+ translatableCache.set(neverTranslate, cache);
71
+ }
72
+ const hit = cache.get(source);
73
+ if (hit !== undefined)
74
+ return hit;
75
+ let text = (0, placeholder_protection_1.protectText)(source, [...neverTranslate]).text.replace(/\[#VAR_\d+#\]/g, ' ');
76
+ if ((0, icu_message_1.isIcuMessage)(source)) {
77
+ text = text
78
+ .replace(/\{\s*[\w.]+\s*,\s*(?:plural|select|selectordinal)\s*,(?:\s*offset\s*:\s*\d+)?/g, ' ')
79
+ .replace(/(?:=\d+|[\p{L}\p{N}_]+)\s*\{/gu, ' ');
80
+ }
81
+ if (cache.size > 20000)
82
+ cache.clear();
83
+ cache.set(source, text);
84
+ return text;
85
+ }
86
+ /**
87
+ * Whether a glossary term occurs in a source string's translatable text (see
88
+ * translatableText). Pass the never-translate terms when asking about an
89
+ * "always translate as" term: inside a never-translate term it doesn't count.
90
+ */
91
+ function sourceHasTerm(source, term, neverTranslate = NO_TERMS) {
92
+ return containsTerm(translatableText(source, neverTranslate), term);
93
+ }
94
+ /**
95
+ * BCP-47 casing for a locale code: `pt_br` / `PT-br` → `pt-BR`,
96
+ * `zh-hant` → `zh-Hant`, `es-419` stays. Anything that isn't
97
+ * language[-Script][-REGION] is returned trimmed, otherwise unchanged.
98
+ */
99
+ function canonicalLocale(code) {
100
+ const parts = code.trim().replace(/_/g, '-').split('-');
101
+ if (!/^[a-z]{2,3}$/i.test(parts[0] ?? ''))
102
+ return code.trim();
103
+ const out = [parts[0].toLowerCase()];
104
+ for (let i = 1; i < parts.length; i++) {
105
+ const p = parts[i];
106
+ if (/^[a-z]{4}$/i.test(p))
107
+ out.push(p.charAt(0).toUpperCase() + p.slice(1).toLowerCase());
108
+ else if (/^[a-z]{2}$/i.test(p))
109
+ out.push(p.toUpperCase());
110
+ else if (/^\d{3}$/.test(p))
111
+ out.push(p);
112
+ else
113
+ return code.trim();
114
+ }
115
+ return out.join('-');
116
+ }
117
+ /** Keys of a locale → value record in canonical form; on a clash the first key (in insertion order) wins. */
118
+ function canonicalizeLocaleKeys(record) {
119
+ const out = {};
120
+ for (const [k, v] of Object.entries(record ?? {})) {
121
+ if (typeof v !== 'string' || !v.trim())
122
+ continue;
123
+ const key = canonicalLocale(k);
124
+ if (!(key in out))
125
+ out[key] = v;
126
+ }
127
+ return out;
128
+ }
129
+ /**
130
+ * The value for `locale` in a locale-keyed record: the exact locale (in any
131
+ * casing / separator), else its base language (`pt` serves `pt-BR`).
132
+ */
133
+ function localeValue(record, locale) {
134
+ if (!record || !locale)
135
+ return undefined;
136
+ const want = canonicalLocale(locale);
137
+ let base;
138
+ const baseLang = want.split('-')[0];
139
+ for (const [k, v] of Object.entries(record)) {
140
+ if (typeof v !== 'string' || !v.trim())
141
+ continue;
142
+ const key = canonicalLocale(k);
143
+ if (key === want)
144
+ return v;
145
+ if (key === baseLang && base === undefined)
146
+ base = v;
147
+ }
148
+ return base;
149
+ }
150
+ exports.EMPTY_GLOSSARY = { neverTranslate: [], alwaysTranslateAs: [], conflicts: [] };
151
+ /**
152
+ * Normalize raw glossary entries. Terms match case-insensitively, so entries
153
+ * are grouped by lowercased term:
154
+ * - never-translate wins over always-translate-as for the same term (keeping
155
+ * a term as-is can't corrupt the output; a translation for the wrong sense can);
156
+ * - several always-translate-as entries merge their locales (the first entry,
157
+ * in term order, wins a locale they both define);
158
+ * - locale keys are canonicalized (`pt_br` → `pt-BR`).
159
+ * The result doesn't depend on the input order.
160
+ */
161
+ function normalizeGlossary(entries) {
162
+ const groups = new Map();
163
+ for (const e of entries) {
164
+ if (!e || typeof e.term !== 'string')
165
+ continue;
166
+ const term = e.term.trim();
167
+ if (!term)
168
+ continue;
169
+ if (e.type !== 'never_translate' && e.type !== 'always_translate_as')
170
+ continue;
171
+ const k = term.toLowerCase();
172
+ const list = groups.get(k) ?? [];
173
+ list.push({ ...e, term });
174
+ groups.set(k, list);
175
+ }
176
+ const neverTranslate = [];
177
+ const alwaysTranslateAs = [];
178
+ const conflicts = [];
179
+ const byTerm = (a, b) => (a.term < b.term ? -1 : a.term > b.term ? 1 : 0);
180
+ for (const k of [...groups.keys()].sort()) {
181
+ const list = groups.get(k).slice().sort(byTerm);
182
+ const never = list.filter((e) => e.type === 'never_translate');
183
+ const always = list.filter((e) => e.type === 'always_translate_as');
184
+ if (never.length > 0) {
185
+ neverTranslate.push(never[0].term);
186
+ if (always.length > 0) {
187
+ const names = [...new Set(list.map((e) => `"${e.term}"`))].join(' / ');
188
+ conflicts.push({
189
+ term: never[0].term,
190
+ message: `Glossary: ${names} is both "never translate" and "always translate as" (terms match ignoring case); "never translate" was applied`,
191
+ });
192
+ }
193
+ continue;
194
+ }
195
+ const translations = {};
196
+ for (const e of always) {
197
+ for (const [loc, v] of Object.entries(canonicalizeLocaleKeys(e.translations))) {
198
+ if (!(loc in translations))
199
+ translations[loc] = v.trim();
200
+ }
201
+ }
202
+ alwaysTranslateAs.push({ term: always[0].term, type: 'always_translate_as', translations });
203
+ }
204
+ return { neverTranslate, alwaysTranslateAs, conflicts };
205
+ }
206
+ /** Always-translate-as terms with a translation for `locale` (exact, then base language). */
207
+ function fixedTermsFor(rules, locale) {
208
+ const out = [];
209
+ for (const e of rules.alwaysTranslateAs) {
210
+ const translation = localeValue(e.translations, locale);
211
+ if (translation)
212
+ out.push({ term: e.term, translation });
213
+ }
214
+ return out;
215
+ }
216
+ /** Whether `source` contains an always-translate-as term that has a translation for `locale`. */
217
+ function hasFixedTerm(source, rules, locale) {
218
+ return fixedTermsFor(rules, locale).some((g) => sourceHasTerm(source, g.term, rules.neverTranslate));
219
+ }
220
+ /**
221
+ * Fingerprint of the glossary rules that shape `source`'s translation into
222
+ * `locale`: the never-translate terms it contains and the always-translate-as
223
+ * terms it contains with their translation for the locale. Empty when no rule
224
+ * applies, so adding a rule for an unrelated term changes nothing. Stored per
225
+ * locale in the lockfile: a key is re-translated when this changes.
226
+ */
227
+ function glossaryFingerprint(source, locale, rules) {
228
+ const parts = [];
229
+ for (const t of rules.neverTranslate) {
230
+ if (sourceHasTerm(source, t))
231
+ parts.push(`n\u0000${t.toLowerCase()}`);
232
+ }
233
+ for (const g of fixedTermsFor(rules, locale)) {
234
+ if (sourceHasTerm(source, g.term, rules.neverTranslate))
235
+ parts.push(`a\u0000${g.term.toLowerCase()}\u0000${g.translation}`);
236
+ }
237
+ if (parts.length === 0)
238
+ return '';
239
+ return (0, crypto_1.createHash)('sha256').update(parts.sort().join('\u0001'), 'utf8').digest('hex').slice(0, 16);
240
+ }
241
+ /** QA notes for conflicting rules whose term occurs in `source`. */
242
+ function conflictNotes(source, rules) {
243
+ return rules.conflicts.filter((c) => sourceHasTerm(source, c.term)).map((c) => c.message);
244
+ }
@@ -0,0 +1,22 @@
1
+ export type GlossaryEntryType = 'never_translate' | 'always_translate_as';
2
+ export interface GlossaryEntry {
3
+ id?: string;
4
+ project_id: string;
5
+ term: string;
6
+ type: GlossaryEntryType;
7
+ /** For always_translate_as: locale code → fixed translation */
8
+ translations?: Record<string, string>;
9
+ created_at?: string;
10
+ updated_at?: string;
11
+ }
12
+ export interface BrandVoice {
13
+ name: string;
14
+ description?: string;
15
+ guidelines?: string[];
16
+ }
17
+ /** Subset used by the masker and translation pipeline */
18
+ export interface AlwaysTranslateAsEntry {
19
+ term: string;
20
+ type: 'always_translate_as';
21
+ translations: Record<string, string>;
22
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1 @@
1
+ export { injectTranslations, checkIdempotency } from './inject';
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.checkIdempotency = exports.injectTranslations = void 0;
4
+ var inject_1 = require("./inject");
5
+ Object.defineProperty(exports, "injectTranslations", { enumerable: true, get: function () { return inject_1.injectTranslations; } });
6
+ Object.defineProperty(exports, "checkIdempotency", { enumerable: true, get: function () { return inject_1.checkIdempotency; } });
@@ -0,0 +1,29 @@
1
+ import type { FileInjection, InjectionResult, WorkspaceInfo } from '../../runtime/types';
2
+ /**
3
+ * Phase 5: Injection
4
+ *
5
+ * Injects i18n into source files — JS/TS gets Babel AST injection,
6
+ * HTML files get DOM-based data-i18n attribute injection.
7
+ */
8
+ export declare function injectTranslations(workspace: WorkspaceInfo, keyMapping: Map<string, string>, // extractionId -> key
9
+ confidenceThreshold?: number, dryRun?: boolean,
10
+ /** extractionId → source offsets of the nodes extraction selected. */
11
+ positions?: Map<string, Set<number>>): Promise<InjectionResult>;
12
+ /**
13
+ * Inject translations into a single file
14
+ */
15
+ export declare function injectIntoFile(content: string, filePath: string, keyMapping: Map<string, string>, confidenceThreshold: number, framework: string, existingDeps?: Record<string, string>, forceTypeScript?: boolean,
16
+ /** extractionId → source offsets of the nodes extraction selected (see ExtractedString.offsets). */
17
+ positions?: Map<string, Set<number>>): FileInjection;
18
+ /**
19
+ * Inject translations into a Vue SFC file.
20
+ * Uses @vue/compiler-sfc to parse, vue/template-scan to find translatable
21
+ * units, vue/template-rewrite to inject $t() calls, and vue/script-inject
22
+ * to add useI18n() in <script setup>.
23
+ */
24
+ export declare function injectIntoVueFile(content: string, filePath: string, keyMapping: Map<string, string>, _confidenceThreshold: number, _framework: string, _existingDeps?: Record<string, string>): Promise<FileInjection>;
25
+ /**
26
+ * Check if injection would be idempotent
27
+ * (running again would produce the same output)
28
+ */
29
+ export declare function checkIdempotency(originalContent: string, modifiedContent: string, filePath: string, keyMapping: Map<string, string>, framework?: string): boolean;