@babelize/engine 0.0.0-stage → 0.1.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.
- package/LICENSE +202 -0
- package/dist/BabelizeEngine.d.ts +12 -0
- package/dist/BabelizeEngine.js +47 -0
- package/dist/analysis/analyze.d.ts +106 -0
- package/dist/analysis/analyze.js +323 -0
- package/dist/config/env.d.ts +9 -0
- package/dist/config/env.js +16 -0
- package/dist/config.d.ts +74 -0
- package/dist/config.js +47 -0
- package/dist/index.d.ts +54 -0
- package/dist/index.js +126 -0
- package/dist/injection/InjectionStrategy.d.ts +62 -0
- package/dist/injection/InjectionStrategy.js +2 -0
- package/dist/injection/StrategyFactory.d.ts +4 -0
- package/dist/injection/StrategyFactory.js +29 -0
- package/dist/injection/django/django-template-injector.d.ts +29 -0
- package/dist/injection/django/django-template-injector.js +216 -0
- package/dist/injection/html/html-injector.d.ts +11 -0
- package/dist/injection/html/html-injector.js +173 -0
- package/dist/injection/strategies/NextIntlStrategy.d.ts +25 -0
- package/dist/injection/strategies/NextIntlStrategy.js +141 -0
- package/dist/injection/strategies/ReactI18nextStrategy.d.ts +19 -0
- package/dist/injection/strategies/ReactI18nextStrategy.js +116 -0
- package/dist/injection/strategies/VanillaStrategy.d.ts +11 -0
- package/dist/injection/strategies/VanillaStrategy.js +73 -0
- package/dist/injection/strategies/VueI18nStrategy.d.ts +11 -0
- package/dist/injection/strategies/VueI18nStrategy.js +84 -0
- package/dist/local/formatter.d.ts +26 -0
- package/dist/local/formatter.js +105 -0
- package/dist/local/git.d.ts +23 -0
- package/dist/local/git.js +136 -0
- package/dist/local/hosted-provider.d.ts +68 -0
- package/dist/local/hosted-provider.js +215 -0
- package/dist/local/index.d.ts +23 -0
- package/dist/local/index.js +75 -0
- package/dist/local/provider.d.ts +56 -0
- package/dist/local/provider.js +119 -0
- package/dist/local/pseudo-provider.d.ts +18 -0
- package/dist/local/pseudo-provider.js +207 -0
- package/dist/local/report.d.ts +177 -0
- package/dist/local/report.js +186 -0
- package/dist/local/translate-core.d.ts +215 -0
- package/dist/local/translate-core.js +461 -0
- package/dist/local/translate-messages.d.ts +49 -0
- package/dist/local/translate-messages.js +91 -0
- package/dist/local/workspace-copy.d.ts +91 -0
- package/dist/local/workspace-copy.js +355 -0
- package/dist/modules/extractor/extract.d.ts +20 -0
- package/dist/modules/extractor/extract.js +701 -0
- package/dist/modules/extractor/index.d.ts +2 -0
- package/dist/modules/extractor/index.js +63 -0
- package/dist/modules/finalization/django-finalize.d.ts +13 -0
- package/dist/modules/finalization/django-finalize.js +275 -0
- package/dist/modules/finalization/finalize.d.ts +36 -0
- package/dist/modules/finalization/finalize.js +717 -0
- package/dist/modules/finalization/index.d.ts +1 -0
- package/dist/modules/finalization/index.js +5 -0
- package/dist/modules/finalization/nextjs-finalize.d.ts +37 -0
- package/dist/modules/finalization/nextjs-finalize.js +329 -0
- package/dist/modules/finalization/static-runtime.d.ts +9 -0
- package/dist/modules/finalization/static-runtime.js +261 -0
- package/dist/modules/format-injection/index.d.ts +19 -0
- package/dist/modules/format-injection/index.js +272 -0
- package/dist/modules/format-injection/inject-formats.d.ts +31 -0
- package/dist/modules/format-injection/inject-formats.js +208 -0
- package/dist/modules/glossary/glossary.d.ts +9 -0
- package/dist/modules/glossary/glossary.js +27 -0
- package/dist/modules/glossary/index.d.ts +3 -0
- package/dist/modules/glossary/index.js +8 -0
- package/dist/modules/glossary/masker.d.ts +23 -0
- package/dist/modules/glossary/masker.js +56 -0
- package/dist/modules/glossary/types.d.ts +22 -0
- package/dist/modules/glossary/types.js +2 -0
- package/dist/modules/injection/index.d.ts +1 -0
- package/dist/modules/injection/index.js +6 -0
- package/dist/modules/injection/inject.d.ts +29 -0
- package/dist/modules/injection/inject.js +1066 -0
- package/dist/modules/keygen/index.d.ts +1 -0
- package/dist/modules/keygen/index.js +11 -0
- package/dist/modules/keygen/keygen.d.ts +4 -0
- package/dist/modules/keygen/keygen.js +116 -0
- package/dist/modules/keygen/locale-data.d.ts +7 -0
- package/dist/modules/keygen/locale-data.js +73 -0
- package/dist/modules/keygen/public.d.ts +2 -0
- package/dist/modules/keygen/public.js +12 -0
- package/dist/modules/locale-builder/index.d.ts +1 -0
- package/dist/modules/locale-builder/index.js +7 -0
- package/dist/modules/locale-builder/locales.d.ts +13 -0
- package/dist/modules/locale-builder/locales.js +107 -0
- package/dist/modules/locale-builder/po.d.ts +33 -0
- package/dist/modules/locale-builder/po.js +131 -0
- package/dist/modules/lockfile/hasher.d.ts +7 -0
- package/dist/modules/lockfile/hasher.js +13 -0
- package/dist/modules/lockfile/index.d.ts +3 -0
- package/dist/modules/lockfile/index.js +21 -0
- package/dist/modules/lockfile/lockfile-manager.d.ts +90 -0
- package/dist/modules/lockfile/lockfile-manager.js +482 -0
- package/dist/modules/lockfile/schema.d.ts +154 -0
- package/dist/modules/lockfile/schema.js +45 -0
- package/dist/modules/parser/index.d.ts +2 -0
- package/dist/modules/parser/index.js +9 -0
- package/dist/modules/summary/index.d.ts +1 -0
- package/dist/modules/summary/index.js +7 -0
- package/dist/modules/summary/summary.d.ts +9 -0
- package/dist/modules/summary/summary.js +195 -0
- package/dist/modules/sync-detector/index.d.ts +2 -0
- package/dist/modules/sync-detector/index.js +7 -0
- package/dist/modules/sync-detector/reporter.d.ts +3 -0
- package/dist/modules/sync-detector/reporter.js +16 -0
- package/dist/modules/sync-detector/sync-detector.d.ts +39 -0
- package/dist/modules/sync-detector/sync-detector.js +374 -0
- package/dist/modules/translator/batch-optimizer.d.ts +12 -0
- package/dist/modules/translator/batch-optimizer.js +30 -0
- package/dist/modules/translator/client/byok.provider.d.ts +64 -0
- package/dist/modules/translator/client/byok.provider.js +319 -0
- package/dist/modules/translator/client/direct-translator.client.d.ts +12 -0
- package/dist/modules/translator/client/direct-translator.client.js +71 -0
- package/dist/modules/translator/client/gemini.provider.d.ts +1 -0
- package/dist/modules/translator/client/gemini.provider.js +110 -0
- package/dist/modules/translator/client/groq.provider.d.ts +1 -0
- package/dist/modules/translator/client/groq.provider.js +111 -0
- package/dist/modules/translator/client/request.types.d.ts +1 -0
- package/dist/modules/translator/client/request.types.js +2 -0
- package/dist/modules/translator/client/retry.d.ts +29 -0
- package/dist/modules/translator/client/retry.js +94 -0
- package/dist/modules/translator/client/test-utils/mock.client.d.ts +31 -0
- package/dist/modules/translator/client/test-utils/mock.client.js +59 -0
- package/dist/modules/translator/client/translator.interface.d.ts +1 -0
- package/dist/modules/translator/client/translator.interface.js +2 -0
- package/dist/modules/translator/language-codes/errors.d.ts +10 -0
- package/dist/modules/translator/language-codes/errors.js +18 -0
- package/dist/modules/translator/language-codes/flores-map.d.ts +1 -0
- package/dist/modules/translator/language-codes/flores-map.js +107 -0
- package/dist/modules/translator/language-codes/index.d.ts +11 -0
- package/dist/modules/translator/language-codes/index.js +24 -0
- package/dist/modules/translator/language-codes/language-mapper.d.ts +25 -0
- package/dist/modules/translator/language-codes/language-mapper.js +132 -0
- package/dist/modules/translator/language-codes/rtl-languages.d.ts +2 -0
- package/dist/modules/translator/language-codes/rtl-languages.js +9 -0
- package/dist/modules/translator/memory/memory-matcher.d.ts +8 -0
- package/dist/modules/translator/memory/memory-matcher.js +218 -0
- package/dist/modules/translator/memory/types.d.ts +22 -0
- package/dist/modules/translator/memory/types.js +2 -0
- package/dist/modules/translator/translate.d.ts +38 -0
- package/dist/modules/translator/translate.js +932 -0
- package/dist/modules/translator/translator.d.ts +5 -0
- package/dist/modules/translator/translator.js +46 -0
- package/dist/modules/vue/migrate.d.ts +13 -0
- package/dist/modules/vue/migrate.js +40 -0
- package/dist/modules/vue/script-inject.d.ts +16 -0
- package/dist/modules/vue/script-inject.js +115 -0
- package/dist/modules/vue/sfc.d.ts +11 -0
- package/dist/modules/vue/sfc.js +51 -0
- package/dist/modules/vue/template-rewrite.d.ts +25 -0
- package/dist/modules/vue/template-rewrite.js +76 -0
- package/dist/modules/vue/template-scan.d.ts +29 -0
- package/dist/modules/vue/template-scan.js +264 -0
- package/dist/modules/workspace/index.d.ts +1 -0
- package/dist/modules/workspace/index.js +5 -0
- package/dist/modules/workspace/validate.d.ts +13 -0
- package/dist/modules/workspace/validate.js +298 -0
- package/dist/orchestrator.d.ts +8 -0
- package/dist/orchestrator.js +616 -0
- package/dist/providers/default-translation-provider.d.ts +20 -0
- package/dist/providers/default-translation-provider.js +30 -0
- package/dist/providers/index.d.ts +2 -0
- package/dist/providers/index.js +21 -0
- package/dist/providers/types.d.ts +145 -0
- package/dist/providers/types.js +2 -0
- package/dist/qa/check-project.d.ts +49 -0
- package/dist/qa/check-project.js +150 -0
- package/dist/qa/locale-files.d.ts +44 -0
- package/dist/qa/locale-files.js +159 -0
- package/dist/qa/locale-qa.d.ts +61 -0
- package/dist/qa/locale-qa.js +325 -0
- package/dist/qa/review.d.ts +43 -0
- package/dist/qa/review.js +175 -0
- package/dist/runtime/config.d.ts +8 -0
- package/dist/runtime/config.js +36 -0
- package/dist/runtime/index.d.ts +3 -0
- package/dist/runtime/index.js +8 -0
- package/dist/runtime/types.d.ts +363 -0
- package/dist/runtime/types.js +38 -0
- package/dist/types.d.ts +134 -0
- package/dist/types.js +12 -0
- package/dist/utils/ast-helpers.d.ts +57 -0
- package/dist/utils/ast-helpers.js +608 -0
- package/dist/utils/cache-keys.d.ts +8 -0
- package/dist/utils/cache-keys.js +18 -0
- package/dist/utils/circuit-breaker.d.ts +43 -0
- package/dist/utils/circuit-breaker.js +119 -0
- package/dist/utils/concurrent-map.d.ts +4 -0
- package/dist/utils/concurrent-map.js +21 -0
- package/dist/utils/detect-format.d.ts +5 -0
- package/dist/utils/detect-format.js +125 -0
- package/dist/utils/dtl-mask.d.ts +25 -0
- package/dist/utils/dtl-mask.js +58 -0
- package/dist/utils/extraction-options.d.ts +23 -0
- package/dist/utils/extraction-options.js +23 -0
- package/dist/utils/file-utils.d.ts +33 -0
- package/dist/utils/file-utils.js +262 -0
- package/dist/utils/glossary-match.d.ts +9 -0
- package/dist/utils/glossary-match.js +25 -0
- package/dist/utils/html-extractor.d.ts +8 -0
- package/dist/utils/html-extractor.js +317 -0
- package/dist/utils/i18next-icu.d.ts +38 -0
- package/dist/utils/i18next-icu.js +159 -0
- package/dist/utils/icu-message.d.ts +65 -0
- package/dist/utils/icu-message.js +346 -0
- package/dist/utils/icu-spans.d.ts +10 -0
- package/dist/utils/icu-spans.js +126 -0
- package/dist/utils/jsx-message.d.ts +93 -0
- package/dist/utils/jsx-message.js +621 -0
- package/dist/utils/key-usage.d.ts +35 -0
- package/dist/utils/key-usage.js +247 -0
- package/dist/utils/logger.d.ts +24 -0
- package/dist/utils/logger.js +33 -0
- package/dist/utils/metadata.d.ts +80 -0
- package/dist/utils/metadata.js +255 -0
- package/dist/utils/module-constants.d.ts +30 -0
- package/dist/utils/module-constants.js +265 -0
- package/dist/utils/not-injected.d.ts +6 -0
- package/dist/utils/not-injected.js +36 -0
- package/dist/utils/placeholder-protection.d.ts +57 -0
- package/dist/utils/placeholder-protection.js +136 -0
- package/dist/utils/pseudo-markers.d.ts +9 -0
- package/dist/utils/pseudo-markers.js +16 -0
- package/dist/utils/py-extractor.d.ts +14 -0
- package/dist/utils/py-extractor.js +285 -0
- package/dist/utils/string-utils.d.ts +52 -0
- package/dist/utils/string-utils.js +270 -0
- package/dist/utils/translation-quality.d.ts +34 -0
- package/dist/utils/translation-quality.js +156 -0
- package/dist/utils/translation-sanitizer.d.ts +10 -0
- package/dist/utils/translation-sanitizer.js +57 -0
- package/dist/utils/translator-caller.d.ts +32 -0
- package/dist/utils/translator-caller.js +217 -0
- package/dist/utils/translator-load-balancer.d.ts +73 -0
- package/dist/utils/translator-load-balancer.js +293 -0
- package/dist/utils/ui-copy.d.ts +32 -0
- package/dist/utils/ui-copy.js +126 -0
- package/dist/utils/workspace.d.ts +14 -0
- package/dist/utils/workspace.js +89 -0
- package/package.json +64 -4
- package/schemas/translate-report.schema.json +297 -0
- package/README.md +0 -3
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.matchFromMemory = matchFromMemory;
|
|
4
|
+
const FUZZY_THRESHOLD = 0.9;
|
|
5
|
+
const MAX_FUZZY_MATCHES = 3;
|
|
6
|
+
const Q = 3;
|
|
7
|
+
/**
|
|
8
|
+
* Fuzzy results are suggestions only (never auto-applied) and only the top
|
|
9
|
+
* MAX_FUZZY_MATCHES are kept, so Levenshtein is run on at most this many
|
|
10
|
+
* candidates — those sharing the most q-grams with the query. Without a cap,
|
|
11
|
+
* a memory full of near-identical templated strings makes every entry a
|
|
12
|
+
* candidate.
|
|
13
|
+
*/
|
|
14
|
+
const MAX_FUZZY_CANDIDATES = 50;
|
|
15
|
+
/** Largest edit distance that still scores ≥ FUZZY_THRESHOLD (float-safe). */
|
|
16
|
+
function maxDistanceFor(maxLength) {
|
|
17
|
+
return Math.floor(maxLength - FUZZY_THRESHOLD * maxLength + 1e-9);
|
|
18
|
+
}
|
|
19
|
+
/** Multiset of the string's q-grams: gram → occurrences. */
|
|
20
|
+
function qgrams(text) {
|
|
21
|
+
const grams = new Map();
|
|
22
|
+
for (let i = 0; i + Q <= text.length; i++) {
|
|
23
|
+
const g = text.slice(i, i + Q);
|
|
24
|
+
grams.set(g, (grams.get(g) ?? 0) + 1);
|
|
25
|
+
}
|
|
26
|
+
return grams;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Levenshtein distance, or `maxDistance + 1` as soon as it is known to exceed
|
|
30
|
+
* `maxDistance`. Only cells within `maxDistance` of the diagonal can lead to
|
|
31
|
+
* an answer under the bound, so each row computes that band only, and the
|
|
32
|
+
* loop exits once a whole band row is over the bound.
|
|
33
|
+
*/
|
|
34
|
+
function boundedLevenshtein(s1, s2, maxDistance) {
|
|
35
|
+
const m = s1.length;
|
|
36
|
+
const n = s2.length;
|
|
37
|
+
const over = maxDistance + 1;
|
|
38
|
+
if (Math.abs(m - n) > maxDistance)
|
|
39
|
+
return over;
|
|
40
|
+
let prev = new Array(n + 1).fill(over);
|
|
41
|
+
let curr = new Array(n + 1).fill(over);
|
|
42
|
+
for (let j = 0; j <= Math.min(n, maxDistance); j++)
|
|
43
|
+
prev[j] = j;
|
|
44
|
+
for (let i = 1; i <= m; i++) {
|
|
45
|
+
const from = Math.max(1, i - maxDistance);
|
|
46
|
+
const to = Math.min(n, i + maxDistance);
|
|
47
|
+
curr.fill(over);
|
|
48
|
+
curr[0] = i <= maxDistance ? i : over;
|
|
49
|
+
let rowMin = curr[0];
|
|
50
|
+
for (let j = from; j <= to; j++) {
|
|
51
|
+
const cost = s1[i - 1] === s2[j - 1] ? 0 : 1;
|
|
52
|
+
curr[j] = Math.min(prev[j] + 1, curr[j - 1] + 1, prev[j - 1] + cost, over);
|
|
53
|
+
if (curr[j] < rowMin)
|
|
54
|
+
rowMin = curr[j];
|
|
55
|
+
}
|
|
56
|
+
if (rowMin > maxDistance)
|
|
57
|
+
return over;
|
|
58
|
+
[prev, curr] = [curr, prev];
|
|
59
|
+
}
|
|
60
|
+
return Math.min(prev[n], over);
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Indexes are built once per (memory array, target locale) and reused for
|
|
64
|
+
* every key in the run. The caller fetches one array per locale and matches
|
|
65
|
+
* every uncached key against it, so rebuilding (or re-hashing every entry)
|
|
66
|
+
* per key was O(keys × entries).
|
|
67
|
+
*/
|
|
68
|
+
const indexCache = new WeakMap();
|
|
69
|
+
function getIndex(entries, targetLocale) {
|
|
70
|
+
let byLocale = indexCache.get(entries);
|
|
71
|
+
if (!byLocale) {
|
|
72
|
+
byLocale = new Map();
|
|
73
|
+
indexCache.set(entries, byLocale);
|
|
74
|
+
}
|
|
75
|
+
let index = byLocale.get(targetLocale);
|
|
76
|
+
if (!index) {
|
|
77
|
+
const forLocale = entries.filter((e) => e.targetLocale === targetLocale);
|
|
78
|
+
const exact = new Map();
|
|
79
|
+
for (const e of forLocale) {
|
|
80
|
+
// Prefer a human-approved entry if the same text appears twice.
|
|
81
|
+
const existing = exact.get(e.sourceText);
|
|
82
|
+
if (!existing || (!existing.approvedAt && e.approvedAt))
|
|
83
|
+
exact.set(e.sourceText, e);
|
|
84
|
+
}
|
|
85
|
+
const lists = new Map();
|
|
86
|
+
forLocale.forEach((e, idx) => {
|
|
87
|
+
for (const [g, n] of qgrams(e.sourceText)) {
|
|
88
|
+
let list = lists.get(g);
|
|
89
|
+
if (!list)
|
|
90
|
+
lists.set(g, (list = []));
|
|
91
|
+
list.push(idx, n);
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
const postings = new Map();
|
|
95
|
+
for (const [g, list] of lists) {
|
|
96
|
+
const idx = new Int32Array(list.length / 2);
|
|
97
|
+
const count = new Uint16Array(list.length / 2);
|
|
98
|
+
for (let p = 0; p < idx.length; p++) {
|
|
99
|
+
idx[p] = list[2 * p];
|
|
100
|
+
count[p] = Math.min(list[2 * p + 1], 0xffff);
|
|
101
|
+
}
|
|
102
|
+
postings.set(g, { idx, count });
|
|
103
|
+
}
|
|
104
|
+
index = { exact, entries: forLocale, postings, shared: new Int32Array(forLocale.length) };
|
|
105
|
+
byLocale.set(targetLocale, index);
|
|
106
|
+
}
|
|
107
|
+
return index;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Match from memory with exact and fuzzy matching.
|
|
111
|
+
* Exact matches are a map lookup; fuzzy matches (≥90% similar) are only
|
|
112
|
+
* computed when there is no exact match, and only against candidates whose
|
|
113
|
+
* length could possibly reach the threshold.
|
|
114
|
+
*/
|
|
115
|
+
function matchFromMemory(entries, sourceText, targetLocale) {
|
|
116
|
+
if (!entries.length)
|
|
117
|
+
return { hit: false };
|
|
118
|
+
const index = getIndex(entries, targetLocale);
|
|
119
|
+
const exactMatch = index.exact.get(sourceText);
|
|
120
|
+
if (exactMatch) {
|
|
121
|
+
return {
|
|
122
|
+
hit: true,
|
|
123
|
+
translatedText: exactMatch.translatedText,
|
|
124
|
+
confidence: 1,
|
|
125
|
+
fromMemory: true
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
const fuzzyMatches = [];
|
|
129
|
+
const consider = (i) => {
|
|
130
|
+
const e = index.entries[i];
|
|
131
|
+
const maxLength = Math.max(sourceText.length, e.sourceText.length);
|
|
132
|
+
if (maxLength === 0)
|
|
133
|
+
return;
|
|
134
|
+
const maxDistance = maxDistanceFor(maxLength);
|
|
135
|
+
if (Math.abs(sourceText.length - e.sourceText.length) > maxDistance)
|
|
136
|
+
return;
|
|
137
|
+
const distance = boundedLevenshtein(sourceText, e.sourceText, maxDistance);
|
|
138
|
+
if (distance > maxDistance)
|
|
139
|
+
return;
|
|
140
|
+
fuzzyMatches.push({
|
|
141
|
+
translatedText: e.translatedText,
|
|
142
|
+
sourceText: e.sourceText,
|
|
143
|
+
similarity: (maxLength - distance) / maxLength,
|
|
144
|
+
});
|
|
145
|
+
};
|
|
146
|
+
if (sourceText.length <= Q + 1) {
|
|
147
|
+
// Too short for the q-gram filter to prune safely; short strings are cheap.
|
|
148
|
+
for (let i = 0; i < index.entries.length; i++)
|
|
149
|
+
consider(i);
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
// q-gram lemma: strings within edit distance d share at least
|
|
153
|
+
// max(len) - Q + 1 - Q·d q-grams. Count shared grams via the inverted
|
|
154
|
+
// index and only run Levenshtein on entries that clear that bar.
|
|
155
|
+
const { shared } = index;
|
|
156
|
+
const touched = [];
|
|
157
|
+
for (const [g, qn] of qgrams(sourceText)) {
|
|
158
|
+
const posting = index.postings.get(g);
|
|
159
|
+
if (!posting)
|
|
160
|
+
continue;
|
|
161
|
+
const { idx: ids, count: counts } = posting;
|
|
162
|
+
for (let p = 0; p < ids.length; p++) {
|
|
163
|
+
const idx = ids[p];
|
|
164
|
+
if (shared[idx] === 0)
|
|
165
|
+
touched.push(idx);
|
|
166
|
+
shared[idx] += counts[p] < qn ? counts[p] : qn;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
const candidates = [];
|
|
170
|
+
const candidateCounts = [];
|
|
171
|
+
let maxCount = 0;
|
|
172
|
+
for (const idx of touched) {
|
|
173
|
+
const count = shared[idx];
|
|
174
|
+
shared[idx] = 0;
|
|
175
|
+
const maxLength = Math.max(sourceText.length, index.entries[idx].sourceText.length);
|
|
176
|
+
if (count >= maxLength - Q + 1 - Q * maxDistanceFor(maxLength)) {
|
|
177
|
+
candidates.push(idx);
|
|
178
|
+
candidateCounts.push(count);
|
|
179
|
+
if (count > maxCount)
|
|
180
|
+
maxCount = count;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
if (candidates.length <= MAX_FUZZY_CANDIDATES) {
|
|
184
|
+
for (const idx of candidates)
|
|
185
|
+
consider(idx);
|
|
186
|
+
}
|
|
187
|
+
else {
|
|
188
|
+
// Top-K by shared count in O(n): counts are small integers, so bucket them.
|
|
189
|
+
const buckets = new Int32Array(maxCount + 1);
|
|
190
|
+
for (const c of candidateCounts)
|
|
191
|
+
buckets[c]++;
|
|
192
|
+
let cutoff = maxCount;
|
|
193
|
+
for (let taken = 0; cutoff > 0 && taken + buckets[cutoff] < MAX_FUZZY_CANDIDATES; cutoff--)
|
|
194
|
+
taken += buckets[cutoff];
|
|
195
|
+
let budget = MAX_FUZZY_CANDIDATES;
|
|
196
|
+
for (let i = 0; i < candidates.length && budget > 0; i++) {
|
|
197
|
+
if (candidateCounts[i] > cutoff) {
|
|
198
|
+
consider(candidates[i]);
|
|
199
|
+
budget--;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
for (let i = 0; i < candidates.length && budget > 0; i++) {
|
|
203
|
+
if (candidateCounts[i] === cutoff) {
|
|
204
|
+
consider(candidates[i]);
|
|
205
|
+
budget--;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
if (fuzzyMatches.length > 0) {
|
|
211
|
+
fuzzyMatches.sort((a, b) => b.similarity - a.similarity);
|
|
212
|
+
return {
|
|
213
|
+
hit: false, // Don't auto-apply fuzzy matches
|
|
214
|
+
fuzzyMatches: fuzzyMatches.slice(0, MAX_FUZZY_MATCHES),
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
return { hit: false };
|
|
218
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export interface MemoryEntry {
|
|
2
|
+
sourceText: string;
|
|
3
|
+
sourceLocale: string;
|
|
4
|
+
targetLocale: string;
|
|
5
|
+
translatedText: string;
|
|
6
|
+
projectId?: string;
|
|
7
|
+
projectName?: string;
|
|
8
|
+
approvedAt?: string;
|
|
9
|
+
isoKey?: string;
|
|
10
|
+
}
|
|
11
|
+
export interface FuzzyMatch {
|
|
12
|
+
translatedText: string;
|
|
13
|
+
similarity: number;
|
|
14
|
+
sourceText: string;
|
|
15
|
+
}
|
|
16
|
+
export interface MemoryLookupResult {
|
|
17
|
+
hit: boolean;
|
|
18
|
+
translatedText?: string;
|
|
19
|
+
confidence?: number;
|
|
20
|
+
fromMemory?: boolean;
|
|
21
|
+
fuzzyMatches?: FuzzyMatch[];
|
|
22
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { LocaleFile, WorkspaceInfo } from '../../runtime/types';
|
|
2
|
+
import type { ByokProvider } from '@babelize/types';
|
|
3
|
+
import type { EngineProviders, TranslationFailure, TranslationCache } from '../../providers/types';
|
|
4
|
+
/** QA note on keys the backup (NLLB) translator produced. */
|
|
5
|
+
export declare const FALLBACK_QA_WARNING = "translated with the backup translator; will be retried with the AI translator next run";
|
|
6
|
+
export interface TranslateOptions {
|
|
7
|
+
/**
|
|
8
|
+
* The project's runtime formats ICU (next-intl, react-i18next + i18next-icu)
|
|
9
|
+
* and the translator is an LLM: a translation may turn a count placeholder
|
|
10
|
+
* into an ICU plural. Otherwise a plain source must stay plain.
|
|
11
|
+
*/
|
|
12
|
+
targetPlurals?: boolean;
|
|
13
|
+
}
|
|
14
|
+
export declare function translateLocales(workspace: WorkspaceInfo, sourceLocale: LocaleFile, targetLocales: string[], forceTranslation?: boolean, dryRun?: boolean, projectId?: string, onProgress?: (message: string) => void, keysToTranslateByLocale?: Record<string, string[]>, cacheProvider?: TranslationCache, byokConfig?: {
|
|
15
|
+
provider: ByokProvider;
|
|
16
|
+
apiKey: string;
|
|
17
|
+
model?: string;
|
|
18
|
+
}, contextMap?: Record<string, string>, extractionContextMap?: Record<string, string>, providers?: EngineProviders, options?: TranslateOptions): Promise<{
|
|
19
|
+
translation: {
|
|
20
|
+
locales: LocaleFile[];
|
|
21
|
+
errors: {
|
|
22
|
+
locale: string;
|
|
23
|
+
error: string;
|
|
24
|
+
}[];
|
|
25
|
+
failures: TranslationFailure[];
|
|
26
|
+
};
|
|
27
|
+
stats: {
|
|
28
|
+
tmHits: number;
|
|
29
|
+
};
|
|
30
|
+
metadata: Record<string, Record<string, any>>;
|
|
31
|
+
}>;
|
|
32
|
+
/**
|
|
33
|
+
* Backfill TM from translations that were reused without calling the
|
|
34
|
+
* translator (lockfile hits). Existing TM rows are left untouched.
|
|
35
|
+
* Locales are ISO codes here; identity translations (source === target) are
|
|
36
|
+
* skipped since they mean a previous run had no working translator.
|
|
37
|
+
*/
|
|
38
|
+
export declare function backfillTranslationMemory(projectId: string, sourceLocale: string, flatSource: Record<string, string>, translationsByLocale: Record<string, Record<string, string>>, excludeKeys?: Set<string>, providers?: EngineProviders): Promise<Record<string, string[]>>;
|