@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 @@
1
+ export { generateKeys, keysToNestedLocale, mergeLocaleData, createKeyMapping, flattenLocaleData, unflattenLocaleData, setNestedValue, } from './public';
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.setNestedValue = exports.unflattenLocaleData = exports.flattenLocaleData = exports.createKeyMapping = exports.mergeLocaleData = exports.keysToNestedLocale = exports.generateKeys = void 0;
4
+ var public_1 = require("./public");
5
+ Object.defineProperty(exports, "generateKeys", { enumerable: true, get: function () { return public_1.generateKeys; } });
6
+ Object.defineProperty(exports, "keysToNestedLocale", { enumerable: true, get: function () { return public_1.keysToNestedLocale; } });
7
+ Object.defineProperty(exports, "mergeLocaleData", { enumerable: true, get: function () { return public_1.mergeLocaleData; } });
8
+ Object.defineProperty(exports, "createKeyMapping", { enumerable: true, get: function () { return public_1.createKeyMapping; } });
9
+ Object.defineProperty(exports, "flattenLocaleData", { enumerable: true, get: function () { return public_1.flattenLocaleData; } });
10
+ Object.defineProperty(exports, "unflattenLocaleData", { enumerable: true, get: function () { return public_1.unflattenLocaleData; } });
11
+ Object.defineProperty(exports, "setNestedValue", { enumerable: true, get: function () { return public_1.setNestedValue; } });
@@ -0,0 +1,4 @@
1
+ import type { ExtractedString, KeyGenerationResult, LocaleData } from '../../runtime/types';
2
+ export declare function generateKeys(extractedStrings: ExtractedString[], existingKeys?: LocaleData): {
3
+ keyGeneration: KeyGenerationResult;
4
+ };
@@ -0,0 +1,123 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.generateKeys = generateKeys;
4
+ const string_utils_1 = require("../../utils/string-utils");
5
+ const jsx_message_1 = require("../../utils/jsx-message");
6
+ const keys_1 = require("../../django/keys");
7
+ function generateKeys(extractedStrings, existingKeys = {}) {
8
+ const keys = [];
9
+ const duplicates = [];
10
+ const usedKeys = new Set();
11
+ collectExistingKeys(existingKeys, '', usedKeys);
12
+ const existingValues = new Map();
13
+ collectExistingValues(existingKeys, '', existingValues);
14
+ // Existing keys already given to a string this run (prefer an unclaimed one).
15
+ const claimed = new Set();
16
+ /**
17
+ * A string re-extracted on a later run (e.g. one the injector couldn't wire
18
+ * up, so the literal is still in the code) must get the key it already has,
19
+ * not a new `_2` copy. Reuse an existing key with the same base name and
20
+ * identical source text; otherwise mint a unique one.
21
+ */
22
+ const keyFor = (baseFullKey, text) => {
23
+ const candidates = [baseFullKey];
24
+ for (let n = 2; existingValues.has(`${baseFullKey}_${n}`); n++)
25
+ candidates.push(`${baseFullKey}_${n}`);
26
+ const matching = candidates.filter((k) => existingValues.get(k) === text);
27
+ const pick = matching.find((k) => !claimed.has(k)) ?? matching[0];
28
+ if (pick) {
29
+ claimed.add(pick);
30
+ return { key: pick, reused: true };
31
+ }
32
+ return { key: (0, string_utils_1.generateUniqueKey)(baseFullKey, usedKeys), reused: false };
33
+ };
34
+ // Generate locale-appropriate plural categories.
35
+ // Always use all 6 CLDR categories since target locale may be unknown at extraction time.
36
+ // The translation engine will only generate entries for categories the target locale needs.
37
+ const pluralCategories = ['zero', 'one', 'two', 'few', 'many', 'other'];
38
+ for (const extracted of extractedStrings) {
39
+ // gettext messages (Django) are looked up by their text; their keys are
40
+ // derived from the message, so they are stable without a source file.
41
+ if (extracted.gettext) {
42
+ keys.push(...(0, keys_1.gettextKeys)(extracted));
43
+ continue;
44
+ }
45
+ const namespace = (0, string_utils_1.inferNamespace)(extracted.file);
46
+ // A sentence message is named from its words: "Welcome back, {user}" → welcomeBack.
47
+ const truncatedText = (0, string_utils_1.truncateForKey)(extracted.icuMessage ? (0, jsx_message_1.messageKeyText)(extracted.text) : extracted.text, 5);
48
+ const baseKeyName = (0, string_utils_1.toCamelCase)(truncatedText);
49
+ const baseFullKey = `${namespace}.${baseKeyName}`;
50
+ // Check if this is a plural string - generate base key + 6 CLDR plural-category keys
51
+ // ICU sentence messages carry their own plural forms ({count, plural, …}).
52
+ if (!extracted.icuMessage && (0, string_utils_1.isLikelyPlural)(extracted.text)) {
53
+ // Generate the unsuffixed base key - this is what gets mapped to extractionId for code injection.
54
+ // i18next callers use the base key (e.g. t('items.count', { count })) and resolve suffixed
55
+ // variants (_one, _other, etc.) internally.
56
+ const { key: uniqueBaseKey, reused: baseReused } = keyFor(baseFullKey, extracted.text);
57
+ if (!baseReused && uniqueBaseKey !== baseFullKey)
58
+ duplicates.push({ original: baseFullKey, renamed: uniqueBaseKey });
59
+ usedKeys.add(uniqueBaseKey);
60
+ keys.push({
61
+ key: uniqueBaseKey,
62
+ namespace,
63
+ value: extracted.text,
64
+ extractionId: extracted.id,
65
+ parentContext: extracted.parentContext,
66
+ extractionContext: extracted.context,
67
+ });
68
+ // Generate the 6 CLDR plural-category keys as suffixed variants.
69
+ // Each gets a distinct extractionId so createKeyMapping keeps all 6 entries.
70
+ for (const category of pluralCategories) {
71
+ const pluralKey = `${uniqueBaseKey}_${category}`;
72
+ const uniquePluralKey = baseReused && existingValues.has(pluralKey) ? pluralKey : (0, string_utils_1.generateUniqueKey)(pluralKey, usedKeys);
73
+ if (uniquePluralKey !== pluralKey)
74
+ duplicates.push({ original: pluralKey, renamed: uniquePluralKey });
75
+ usedKeys.add(uniquePluralKey);
76
+ keys.push({
77
+ key: uniquePluralKey,
78
+ namespace,
79
+ value: extracted.text,
80
+ extractionId: `${extracted.id}_${category}`,
81
+ isPlural: true,
82
+ pluralCategory: category,
83
+ parentContext: extracted.parentContext,
84
+ extractionContext: extracted.context,
85
+ });
86
+ }
87
+ }
88
+ else {
89
+ const { key: uniqueKey, reused } = keyFor(baseFullKey, extracted.text);
90
+ if (!reused && uniqueKey !== baseFullKey)
91
+ duplicates.push({ original: baseFullKey, renamed: uniqueKey });
92
+ usedKeys.add(uniqueKey);
93
+ keys.push({
94
+ key: uniqueKey,
95
+ namespace,
96
+ value: extracted.text,
97
+ extractionId: extracted.id,
98
+ parentContext: extracted.parentContext,
99
+ extractionContext: extracted.context,
100
+ });
101
+ }
102
+ }
103
+ const keyGeneration = { keys, duplicates };
104
+ return { keyGeneration };
105
+ }
106
+ function collectExistingValues(data, prefix, out) {
107
+ for (const [key, value] of Object.entries(data)) {
108
+ const fullKey = prefix ? `${prefix}.${key}` : key;
109
+ if (typeof value === 'string')
110
+ out.set(fullKey, value);
111
+ else if (typeof value === 'object' && value !== null)
112
+ collectExistingValues(value, fullKey, out);
113
+ }
114
+ }
115
+ function collectExistingKeys(data, prefix, keys) {
116
+ for (const [key, value] of Object.entries(data)) {
117
+ const fullKey = prefix ? `${prefix}.${key}` : key;
118
+ if (typeof value === 'string')
119
+ keys.add(fullKey);
120
+ else if (typeof value === 'object' && value !== null)
121
+ collectExistingKeys(value, fullKey, keys);
122
+ }
123
+ }
@@ -0,0 +1,7 @@
1
+ import type { GeneratedKey, LocaleData } from '../../runtime/types';
2
+ export declare function keysToNestedLocale(keys: GeneratedKey[]): LocaleData;
3
+ export declare function setNestedValue(obj: LocaleData, key: string, value: string): void;
4
+ export declare function mergeLocaleData(existing: LocaleData, newData: LocaleData): LocaleData;
5
+ export declare function createKeyMapping(keys: GeneratedKey[]): Map<string, string>;
6
+ export declare function flattenLocaleData(data: LocaleData, prefix?: string): Record<string, string>;
7
+ export declare function unflattenLocaleData(flat: Record<string, string>): LocaleData;
@@ -0,0 +1,73 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.keysToNestedLocale = keysToNestedLocale;
4
+ exports.setNestedValue = setNestedValue;
5
+ exports.mergeLocaleData = mergeLocaleData;
6
+ exports.createKeyMapping = createKeyMapping;
7
+ exports.flattenLocaleData = flattenLocaleData;
8
+ exports.unflattenLocaleData = unflattenLocaleData;
9
+ function keysToNestedLocale(keys) {
10
+ const result = {};
11
+ for (const { key, value } of keys)
12
+ setNestedValue(result, key, value);
13
+ return result;
14
+ }
15
+ function setNestedValue(obj, key, value) {
16
+ const parts = key.split('.');
17
+ let current = obj;
18
+ for (let i = 0; i < parts.length - 1; i++) {
19
+ const part = parts[i];
20
+ if (!(part in current)) {
21
+ current[part] = {};
22
+ }
23
+ else if (typeof current[part] === 'string') {
24
+ // Key conflict: a flat key (e.g. "homepage") and nested key (e.g. "homepage.title")
25
+ // both exist. This is a data model error in the generated keys.
26
+ throw new Error(`Key conflict in locale data: "${key}" — intermediate key "${part}" is already a string value and cannot be an object path`);
27
+ }
28
+ current = current[part];
29
+ }
30
+ current[parts[parts.length - 1]] = value;
31
+ }
32
+ function mergeLocaleData(existing, newData) {
33
+ const result = JSON.parse(JSON.stringify(existing));
34
+ function merge(target, source) {
35
+ for (const [key, value] of Object.entries(source)) {
36
+ if (!(key in target)) {
37
+ target[key] = value;
38
+ }
39
+ else if (typeof target[key] === 'object' &&
40
+ typeof value === 'object' &&
41
+ target[key] !== null &&
42
+ value !== null) {
43
+ merge(target[key], value);
44
+ }
45
+ }
46
+ }
47
+ merge(result, newData);
48
+ return result;
49
+ }
50
+ function createKeyMapping(keys) {
51
+ const mapping = new Map();
52
+ for (const { key, extractionId } of keys)
53
+ mapping.set(extractionId, key);
54
+ return mapping;
55
+ }
56
+ function flattenLocaleData(data, prefix = '') {
57
+ const result = {};
58
+ for (const [key, value] of Object.entries(data)) {
59
+ const fullKey = prefix ? `${prefix}.${key}` : key;
60
+ if (typeof value === 'string')
61
+ result[fullKey] = value;
62
+ else if (typeof value === 'object' && value !== null)
63
+ Object.assign(result, flattenLocaleData(value, fullKey));
64
+ }
65
+ return result;
66
+ }
67
+ function unflattenLocaleData(flat) {
68
+ const result = {};
69
+ for (const [key, value] of Object.entries(flat)) {
70
+ setNestedValue(result, key, value);
71
+ }
72
+ return result;
73
+ }
@@ -0,0 +1,2 @@
1
+ export { generateKeys } from './keygen';
2
+ export { keysToNestedLocale, mergeLocaleData, createKeyMapping, flattenLocaleData, unflattenLocaleData, setNestedValue } from './locale-data';
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.setNestedValue = exports.unflattenLocaleData = exports.flattenLocaleData = exports.createKeyMapping = exports.mergeLocaleData = exports.keysToNestedLocale = exports.generateKeys = void 0;
4
+ var keygen_1 = require("./keygen");
5
+ Object.defineProperty(exports, "generateKeys", { enumerable: true, get: function () { return keygen_1.generateKeys; } });
6
+ var locale_data_1 = require("./locale-data");
7
+ Object.defineProperty(exports, "keysToNestedLocale", { enumerable: true, get: function () { return locale_data_1.keysToNestedLocale; } });
8
+ Object.defineProperty(exports, "mergeLocaleData", { enumerable: true, get: function () { return locale_data_1.mergeLocaleData; } });
9
+ Object.defineProperty(exports, "createKeyMapping", { enumerable: true, get: function () { return locale_data_1.createKeyMapping; } });
10
+ Object.defineProperty(exports, "flattenLocaleData", { enumerable: true, get: function () { return locale_data_1.flattenLocaleData; } });
11
+ Object.defineProperty(exports, "unflattenLocaleData", { enumerable: true, get: function () { return locale_data_1.unflattenLocaleData; } });
12
+ Object.defineProperty(exports, "setNestedValue", { enumerable: true, get: function () { return locale_data_1.setNestedValue; } });
@@ -0,0 +1 @@
1
+ export { handleBaseLocale, readLocaleFile, checkExistingTargetLocales } from './locales';
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.checkExistingTargetLocales = exports.readLocaleFile = exports.handleBaseLocale = void 0;
4
+ var locales_1 = require("./locales");
5
+ Object.defineProperty(exports, "handleBaseLocale", { enumerable: true, get: function () { return locales_1.handleBaseLocale; } });
6
+ Object.defineProperty(exports, "readLocaleFile", { enumerable: true, get: function () { return locales_1.readLocaleFile; } });
7
+ Object.defineProperty(exports, "checkExistingTargetLocales", { enumerable: true, get: function () { return locales_1.checkExistingTargetLocales; } });
@@ -0,0 +1,13 @@
1
+ import type { GeneratedKey, LocaleData, LocaleFile, WorkspaceInfo } from '../../runtime/types';
2
+ export declare function handleBaseLocale(workspace: WorkspaceInfo, generatedKeys: GeneratedKey[], sourceLocale?: string, dryRun?: boolean): Promise<{
3
+ localeHandling: {
4
+ sourceLocale: LocaleFile;
5
+ newKeysCount: number;
6
+ existingKeysCount: number;
7
+ };
8
+ }>;
9
+ export declare function readLocaleFile(workspace: WorkspaceInfo, locale: string): Promise<LocaleData | null>;
10
+ export declare function checkExistingTargetLocales(workspace: WorkspaceInfo, targetLocales: string[]): Promise<{
11
+ existing: string[];
12
+ missing: string[];
13
+ }>;
@@ -0,0 +1,130 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.handleBaseLocale = handleBaseLocale;
4
+ exports.readLocaleFile = readLocaleFile;
5
+ exports.checkExistingTargetLocales = checkExistingTargetLocales;
6
+ const file_utils_1 = require("../../utils/file-utils");
7
+ const keygen_1 = require("../keygen");
8
+ const language_codes_1 = require("../translator/language-codes");
9
+ function assertSafeLocale(locale) {
10
+ // Allow common locale identifiers only (examples: en, en-US, pt_BR, zh-Hant).
11
+ // Disallow path separators and other special characters to prevent path traversal.
12
+ const localePattern = /^[A-Za-z0-9]+(?:[-_][A-Za-z0-9]+)*$/;
13
+ if (!localePattern.test(locale)) {
14
+ throw new Error(`Invalid locale: ${locale}`);
15
+ }
16
+ }
17
+ async function handleBaseLocale(workspace, generatedKeys, sourceLocale = 'en', dryRun = false) {
18
+ assertSafeLocale(sourceLocale);
19
+ if (workspace.localeFormat === 'po')
20
+ return gettextSourceLocale(generatedKeys, sourceLocale);
21
+ const localePaths = (0, file_utils_1.localeFilePath)(workspace.path, workspace.publicDir, workspace.localeFormat, sourceLocale);
22
+ const localesDir = localePaths.dir;
23
+ const localeFilePathTarget = localePaths.file;
24
+ const relativeLocaleFilePath = localePaths.relativeFile;
25
+ if (!dryRun)
26
+ await (0, file_utils_1.ensureDir)(localesDir);
27
+ const exists = await (0, file_utils_1.pathExists)(localeFilePathTarget);
28
+ let existingData = {};
29
+ let existingKeysCount = 0;
30
+ if (exists) {
31
+ if (workspace.localeFormat !== 'json') {
32
+ throw new Error(`Locale format '${workspace.localeFormat}' not yet supported for base locale handling`);
33
+ }
34
+ existingData = (await (0, file_utils_1.readJsonFile)(localeFilePathTarget)) || {};
35
+ existingKeysCount = countKeys(existingData);
36
+ }
37
+ const newData = (0, keygen_1.keysToNestedLocale)(generatedKeys);
38
+ const mergedData = (0, keygen_1.mergeLocaleData)(existingData, newData);
39
+ const mergedKeysCount = countKeys(mergedData);
40
+ const newKeysCount = mergedKeysCount - existingKeysCount;
41
+ const MAX_KEYS_PER_RUN = 10000;
42
+ if (mergedKeysCount > MAX_KEYS_PER_RUN) {
43
+ throw new Error(`Project exceeds maximum keys per run (Found: ${mergedKeysCount}, Limit: ${MAX_KEYS_PER_RUN}). Please reduce project size or split into multiple runs.`);
44
+ }
45
+ // Add _meta with direction and language info.
46
+ // Spread mergedData first, then override _meta so the computed dir/language
47
+ // always takes precedence over any stale _meta already present in the file.
48
+ const existingMeta = typeof mergedData._meta === 'object' && mergedData._meta !== null
49
+ ? mergedData._meta
50
+ : {};
51
+ const dataWithMeta = {
52
+ ...mergedData,
53
+ _meta: {
54
+ ...existingMeta,
55
+ dir: (0, language_codes_1.isRTL)(sourceLocale) ? 'rtl' : 'ltr',
56
+ language: sourceLocale,
57
+ },
58
+ };
59
+ if (!dryRun)
60
+ await (0, file_utils_1.writeJsonFile)(localeFilePathTarget, dataWithMeta, true);
61
+ const sourceLocaleFile = {
62
+ locale: sourceLocale,
63
+ path: relativeLocaleFilePath,
64
+ data: dataWithMeta,
65
+ isNew: !exists,
66
+ isRTL: (0, language_codes_1.isRTL)(sourceLocale),
67
+ };
68
+ return {
69
+ localeHandling: {
70
+ sourceLocale: sourceLocaleFile,
71
+ newKeysCount,
72
+ existingKeysCount,
73
+ },
74
+ };
75
+ }
76
+ /**
77
+ * gettext (Django): the source language has no catalogue file — the msgids
78
+ * in the code are the source text. The run's keys are the source locale.
79
+ */
80
+ function gettextSourceLocale(generatedKeys, sourceLocale) {
81
+ const data = {};
82
+ for (const k of generatedKeys)
83
+ data[k.key] = k.value;
84
+ const sourceLocaleFile = {
85
+ locale: sourceLocale,
86
+ path: '',
87
+ data,
88
+ isNew: false,
89
+ isRTL: (0, language_codes_1.isRTL)(sourceLocale),
90
+ noFile: true,
91
+ };
92
+ return { localeHandling: { sourceLocale: sourceLocaleFile, newKeysCount: 0, existingKeysCount: Object.keys(data).length } };
93
+ }
94
+ function countKeys(data) {
95
+ let count = 0;
96
+ function traverse(obj) {
97
+ for (const value of Object.values(obj)) {
98
+ if (typeof value === 'string')
99
+ count++;
100
+ else if (typeof value === 'object' && value !== null)
101
+ traverse(value);
102
+ }
103
+ }
104
+ traverse(data);
105
+ return count;
106
+ }
107
+ async function readLocaleFile(workspace, locale) {
108
+ assertSafeLocale(locale);
109
+ // gettext projects have no source-locale file: the code is the catalogue.
110
+ if (workspace.localeFormat === 'po')
111
+ return null;
112
+ if (workspace.localeFormat !== 'json') {
113
+ throw new Error(`Locale format '${workspace.localeFormat}' reading not yet implemented`);
114
+ }
115
+ const { file } = (0, file_utils_1.localeFilePath)(workspace.path, workspace.publicDir, workspace.localeFormat, locale);
116
+ return (0, file_utils_1.readJsonFile)(file);
117
+ }
118
+ async function checkExistingTargetLocales(workspace, targetLocales) {
119
+ const existing = [];
120
+ const missing = [];
121
+ for (const locale of targetLocales) {
122
+ assertSafeLocale(locale);
123
+ const { file } = (0, file_utils_1.localeFilePath)(workspace.path, workspace.publicDir, workspace.localeFormat, locale);
124
+ if (await (0, file_utils_1.pathExists)(file))
125
+ existing.push(locale);
126
+ else
127
+ missing.push(locale);
128
+ }
129
+ return { existing, missing };
130
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Compute a SHA-256 hex digest of the given source string.
3
+ *
4
+ * The hash is case-sensitive and whitespace-sensitive by design,
5
+ * so "Hello" and "hello" and " Hello" all produce different hashes.
6
+ */
7
+ export declare function hashSourceString(text: string): string;
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.hashSourceString = hashSourceString;
4
+ const crypto_1 = require("crypto");
5
+ /**
6
+ * Compute a SHA-256 hex digest of the given source string.
7
+ *
8
+ * The hash is case-sensitive and whitespace-sensitive by design,
9
+ * so "Hello" and "hello" and " Hello" all produce different hashes.
10
+ */
11
+ function hashSourceString(text) {
12
+ return (0, crypto_1.createHash)('sha256').update(text, 'utf8').digest('hex');
13
+ }
@@ -0,0 +1,3 @@
1
+ export { hashSourceString } from './hasher';
2
+ export { type LockfileData, type LockfileEntry, type LockfilePartition, type LockfileStats, type PartitionedKey, createEmptyLockfile, } from './schema';
3
+ export { buildKeysToTranslateByTargetLocale, clearLockfile, removeLocaleFromLockfile, collectCachedTranslations, computeLockfileStats, getLockfilePath, loadLockfile, partitionKeys, saveLockfile, updateLockfile, lockfileChanged, dropFailedTranslations, isStalePseudoEntry, glossaryChanged, type LockfileReadOptions, } from './lockfile-manager';
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.glossaryChanged = exports.isStalePseudoEntry = exports.dropFailedTranslations = exports.lockfileChanged = exports.updateLockfile = exports.saveLockfile = exports.partitionKeys = exports.loadLockfile = exports.getLockfilePath = exports.computeLockfileStats = exports.collectCachedTranslations = exports.removeLocaleFromLockfile = exports.clearLockfile = exports.buildKeysToTranslateByTargetLocale = exports.createEmptyLockfile = exports.hashSourceString = void 0;
4
+ var hasher_1 = require("./hasher");
5
+ Object.defineProperty(exports, "hashSourceString", { enumerable: true, get: function () { return hasher_1.hashSourceString; } });
6
+ var schema_1 = require("./schema");
7
+ Object.defineProperty(exports, "createEmptyLockfile", { enumerable: true, get: function () { return schema_1.createEmptyLockfile; } });
8
+ var lockfile_manager_1 = require("./lockfile-manager");
9
+ Object.defineProperty(exports, "buildKeysToTranslateByTargetLocale", { enumerable: true, get: function () { return lockfile_manager_1.buildKeysToTranslateByTargetLocale; } });
10
+ Object.defineProperty(exports, "clearLockfile", { enumerable: true, get: function () { return lockfile_manager_1.clearLockfile; } });
11
+ Object.defineProperty(exports, "removeLocaleFromLockfile", { enumerable: true, get: function () { return lockfile_manager_1.removeLocaleFromLockfile; } });
12
+ Object.defineProperty(exports, "collectCachedTranslations", { enumerable: true, get: function () { return lockfile_manager_1.collectCachedTranslations; } });
13
+ Object.defineProperty(exports, "computeLockfileStats", { enumerable: true, get: function () { return lockfile_manager_1.computeLockfileStats; } });
14
+ Object.defineProperty(exports, "getLockfilePath", { enumerable: true, get: function () { return lockfile_manager_1.getLockfilePath; } });
15
+ Object.defineProperty(exports, "loadLockfile", { enumerable: true, get: function () { return lockfile_manager_1.loadLockfile; } });
16
+ Object.defineProperty(exports, "partitionKeys", { enumerable: true, get: function () { return lockfile_manager_1.partitionKeys; } });
17
+ Object.defineProperty(exports, "saveLockfile", { enumerable: true, get: function () { return lockfile_manager_1.saveLockfile; } });
18
+ Object.defineProperty(exports, "updateLockfile", { enumerable: true, get: function () { return lockfile_manager_1.updateLockfile; } });
19
+ Object.defineProperty(exports, "lockfileChanged", { enumerable: true, get: function () { return lockfile_manager_1.lockfileChanged; } });
20
+ Object.defineProperty(exports, "dropFailedTranslations", { enumerable: true, get: function () { return lockfile_manager_1.dropFailedTranslations; } });
21
+ Object.defineProperty(exports, "isStalePseudoEntry", { enumerable: true, get: function () { return lockfile_manager_1.isStalePseudoEntry; } });
22
+ Object.defineProperty(exports, "glossaryChanged", { enumerable: true, get: function () { return lockfile_manager_1.glossaryChanged; } });
@@ -0,0 +1,99 @@
1
+ import type { LockfileEntry } from './schema';
2
+ import { type LockfileData, type LockfilePartition, type LockfileStats, type PartitionedKey } from './schema';
3
+ /**
4
+ * For each target locale, list of translation keys that must go through the translator
5
+ * (new keys, source-changed keys, or keys missing that locale in the lockfile).
6
+ */
7
+ export declare function buildKeysToTranslateByTargetLocale(partition: LockfilePartition, targetLocales: string[]): Record<string, string[]>;
8
+ /**
9
+ * Resolve the lockfile path for a project:
10
+ * `<dataDir>/.babelize/{projectId}/babelize-lock.json`. `dataDir` defaults to
11
+ * $BABELIZE_DATA_DIR, else `process.cwd()` (the cloud backend). Local runs
12
+ * pass it explicitly so concurrent runs in one process never share it.
13
+ */
14
+ export declare function getLockfilePath(projectId: string, dataDir?: string): string;
15
+ /**
16
+ * Load and validate the lockfile from disk.
17
+ * Returns an empty lockfile if the file doesn't exist or is malformed.
18
+ */
19
+ export declare function loadLockfile(projectId: string, dataDir?: string): Promise<LockfileData>;
20
+ /**
21
+ * Persist lockfile to disk atomically (write→tmp→rename).
22
+ * Uses advisory file locking via atomic mkdir to prevent concurrent writes
23
+ * from overwriting each other (two simultaneous runs for the same project).
24
+ */
25
+ export declare function saveLockfile(projectId: string, data: LockfileData, dataDir?: string): Promise<void>;
26
+ /**
27
+ * Delete the lockfile for a project (used by "Force full re-translate").
28
+ */
29
+ export declare function clearLockfile(projectId: string, dataDir?: string): Promise<void>;
30
+ /**
31
+ * Purge a specific locale's translations from the lockfile.
32
+ * Used when a language is removed from a project so re-adding it
33
+ * triggers fresh translation instead of resurrecting stale cache.
34
+ */
35
+ export declare function removeLocaleFromLockfile(projectId: string, localeCode: string, dataDir?: string): Promise<void>;
36
+ /**
37
+ * Partition generated keys into unchanged / new / changed / missingLocales
38
+ * by comparing source hashes against the lockfile.
39
+ *
40
+ * @param lockfile - Current lockfile data
41
+ * @param keys - Flat map of translation key → source string value
42
+ * @param targetLocales - Locales the user is targeting this run
43
+ */
44
+ /** Options for reading the lockfile during a run. */
45
+ export interface LockfileReadOptions {
46
+ /** This run is pseudo-localization: pseudo entries count as done. Otherwise they count as missing. */
47
+ pseudo?: boolean;
48
+ /**
49
+ * The glossary fingerprint this run's rules give a key's source for a
50
+ * locale ('' when no rule applies). A stored translation made under a
51
+ * different fingerprint counts as missing, so glossary edits reach the
52
+ * keys they affect — and only those. Omit when the rules couldn't be loaded.
53
+ */
54
+ glossaryHash?: (source: string, locale: string) => string;
55
+ }
56
+ /** True when the glossary rules for this key and locale changed since its translation was stored. */
57
+ export declare function glossaryChanged(entry: LockfileEntry, source: string, locale: string, options?: LockfileReadOptions): boolean;
58
+ /**
59
+ * True when the stored value for `locale` is pseudo-localization and this run
60
+ * is a real one: it must be translated, never reused. Recognised by the
61
+ * `pseudo` metadata flag, or by the pseudo markers for lockfiles written
62
+ * before the flag existed.
63
+ */
64
+ export declare function isStalePseudoEntry(entry: LockfileEntry, locale: string, options?: LockfileReadOptions): boolean;
65
+ export declare function partitionKeys(lockfile: LockfileData, keys: Record<string, string>, targetLocales: string[], options?: LockfileReadOptions): LockfilePartition;
66
+ /**
67
+ * Merge newly translated values and metadata into the lockfile.
68
+ *
69
+ * @param lockfile - Current lockfile (will be mutated)
70
+ * @param keys - Flat map of key → source value (for hashing)
71
+ * @param translations - Map of locale → { key → translated string }
72
+ * @param projectId - Project identifier
73
+ * @param metadata - Map of locale → { key → metadata object }
74
+ */
75
+ /**
76
+ * Remove the stored translation of every key that failed this run.
77
+ * updateLockfile records the new source fingerprint for every key and keeps
78
+ * the previous translation where a locale produced none — for a key whose
79
+ * source text changed and then failed, that previous value translates the
80
+ * *old* text. Dropping it makes the next run treat the locale as missing and
81
+ * retry it, instead of silently reusing a stale translation.
82
+ */
83
+ export declare function dropFailedTranslations(lockfile: LockfileData, failures: Array<{
84
+ key: string;
85
+ locale: string;
86
+ }>): LockfileData;
87
+ /** True when `next` differs from `previous` in anything but timestamps worth saving. */
88
+ export declare function lockfileChanged(previous: LockfileData, next: LockfileData): boolean;
89
+ export declare function updateLockfile(lockfile: LockfileData, keys: Record<string, string>, translations: Record<string, Record<string, string>>, projectId: string, metadata?: Record<string, Record<string, any>>): LockfileData;
90
+ /**
91
+ * Extract cached translations for unchanged keys from the lockfile.
92
+ *
93
+ * @returns Map of locale → { key → translated string }
94
+ */
95
+ export declare function collectCachedTranslations(lockfile: LockfileData, unchangedKeys: PartitionedKey[], targetLocales: string[], options?: LockfileReadOptions): Record<string, Record<string, string>>;
96
+ /**
97
+ * Compute stats for the UI: X translated, Y reused, Z changed.
98
+ */
99
+ export declare function computeLockfileStats(partition: LockfilePartition): LockfileStats;