@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,186 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.BABELIZE_GITIGNORE = exports.DEFAULT_REPORT_FILE = exports.TRANSLATE_REPORT_SCHEMA_ID = exports.TRANSLATE_REPORT_SCHEMA_VERSION = void 0;
|
|
37
|
+
exports.buildTranslateReport = buildTranslateReport;
|
|
38
|
+
exports.writeTranslateReport = writeTranslateReport;
|
|
39
|
+
exports.ensureReportGitignored = ensureReportGitignored;
|
|
40
|
+
const promises_1 = require("node:fs/promises");
|
|
41
|
+
const path = __importStar(require("node:path"));
|
|
42
|
+
/**
|
|
43
|
+
* The QA report of a local translate run: what `babelize translate --json`
|
|
44
|
+
* prints and what it writes to `.babelize/local/report.json`. One schema for
|
|
45
|
+
* both, described by `schemas/translate-report.schema.json` in this package.
|
|
46
|
+
* Every per-key list is complete (no caps), unlike the MCP tool's response.
|
|
47
|
+
*/
|
|
48
|
+
exports.TRANSLATE_REPORT_SCHEMA_VERSION = 1;
|
|
49
|
+
exports.TRANSLATE_REPORT_SCHEMA_ID = 'https://babelize.co/schemas/translate-report.v1.json';
|
|
50
|
+
/** Default report location, relative to the project root. */
|
|
51
|
+
exports.DEFAULT_REPORT_FILE = '.babelize/local/report.json';
|
|
52
|
+
/** Keeps the report out of git while the lockfile next to it stays committed. */
|
|
53
|
+
exports.BABELIZE_GITIGNORE = '.babelize/.gitignore';
|
|
54
|
+
const GITIGNORE_ENTRY = 'local/report.json';
|
|
55
|
+
/** The report of a finished run (`r` from runLocalTranslate). */
|
|
56
|
+
function buildTranslateReport(r) {
|
|
57
|
+
const failures = r.translationFailures.map((f) => ({
|
|
58
|
+
locale: f.locale,
|
|
59
|
+
key: f.key,
|
|
60
|
+
source: f.source,
|
|
61
|
+
reason: f.reason,
|
|
62
|
+
retryable: f.retryable,
|
|
63
|
+
...(f.message ? { message: f.message } : {}),
|
|
64
|
+
}));
|
|
65
|
+
const failedBy = new Map(failures.map((f) => [`${f.locale}\0${f.key}`, f]));
|
|
66
|
+
const qaItems = r.locales.flatMap((l) => l.qa.map((q) => ({ locale: l.locale, key: q.key, warnings: q.warnings })));
|
|
67
|
+
const qaBy = new Map(qaItems.map((q) => [`${q.locale}\0${q.key}`, q.warnings]));
|
|
68
|
+
const missing = r.locales.flatMap((l) => l.missing.filter((k) => !failedBy.has(`${l.locale}\0${k}`)).map((key) => ({ locale: l.locale, key })));
|
|
69
|
+
const unchanged = r.locales.flatMap((l) => l.sameAsSource.map((key) => ({ locale: l.locale, key, value: r.results.targets[l.locale]?.[key] ?? '' })));
|
|
70
|
+
const unchangedBy = new Set(unchanged.map((u) => `${u.locale}\0${u.key}`));
|
|
71
|
+
const keys = Object.entries(r.results.source).map(([key, source]) => {
|
|
72
|
+
const locales = {};
|
|
73
|
+
for (const l of r.locales) {
|
|
74
|
+
const id = `${l.locale}\0${key}`;
|
|
75
|
+
const value = r.results.targets[l.locale]?.[key];
|
|
76
|
+
const failed = failedBy.get(id);
|
|
77
|
+
const warnings = qaBy.get(id);
|
|
78
|
+
let entry;
|
|
79
|
+
if (failed) {
|
|
80
|
+
entry = { status: 'failed', reason: failed.reason, retryable: failed.retryable, ...(failed.message ? { message: failed.message } : {}) };
|
|
81
|
+
// A failed re-translation keeps the earlier value on disk.
|
|
82
|
+
if (value)
|
|
83
|
+
entry.value = value;
|
|
84
|
+
}
|
|
85
|
+
else if (value === undefined || value === '')
|
|
86
|
+
entry = { status: 'missing' };
|
|
87
|
+
else if (warnings)
|
|
88
|
+
entry = { status: 'warning', value, warnings };
|
|
89
|
+
else if (unchangedBy.has(id))
|
|
90
|
+
entry = { status: 'unchanged', value };
|
|
91
|
+
else
|
|
92
|
+
entry = { status: 'translated', value };
|
|
93
|
+
locales[l.locale] = entry;
|
|
94
|
+
}
|
|
95
|
+
return { key, source, locales };
|
|
96
|
+
});
|
|
97
|
+
const translations = r.locales.reduce((n, l) => n + l.translated, 0);
|
|
98
|
+
const newTranslations = Math.min(r.stats.translatedThisRun ?? r.stats.keysSentToTranslator, translations);
|
|
99
|
+
const started = Number.isFinite(r.startedAt) ? r.startedAt : Date.now() - r.durationMs;
|
|
100
|
+
return {
|
|
101
|
+
$schema: exports.TRANSLATE_REPORT_SCHEMA_ID,
|
|
102
|
+
schemaVersion: exports.TRANSLATE_REPORT_SCHEMA_VERSION,
|
|
103
|
+
ok: failures.length === 0,
|
|
104
|
+
startedAt: new Date(started).toISOString(),
|
|
105
|
+
finishedAt: new Date(started + r.durationMs).toISOString(),
|
|
106
|
+
durationMs: r.durationMs,
|
|
107
|
+
framework: r.framework,
|
|
108
|
+
frameworkStatus: r.frameworkStatus,
|
|
109
|
+
provider: r.provider ? { provider: r.provider.provider, name: r.provider.name, ...(r.provider.model ? { model: r.provider.model } : {}) } : null,
|
|
110
|
+
sourceLocale: r.sourceLocale,
|
|
111
|
+
targetLocales: r.targetLocales,
|
|
112
|
+
keptLocales: r.keptLocales,
|
|
113
|
+
droppedLocales: r.droppedLocales,
|
|
114
|
+
dryRun: r.dryRun,
|
|
115
|
+
applied: r.applied,
|
|
116
|
+
filesChanged: { added: r.changes.added, modified: r.changes.modified, deleted: r.changes.deleted },
|
|
117
|
+
diffSummary: r.diffStat,
|
|
118
|
+
...(r.diff !== undefined ? { diff: r.diff } : {}),
|
|
119
|
+
stats: r.stats,
|
|
120
|
+
summary: {
|
|
121
|
+
sourceKeys: Object.keys(r.results.source).length,
|
|
122
|
+
translations,
|
|
123
|
+
newTranslations,
|
|
124
|
+
reused: Math.max(0, translations - newTranslations),
|
|
125
|
+
failed: failures.length,
|
|
126
|
+
qaWarnings: qaItems.length,
|
|
127
|
+
missing: missing.length,
|
|
128
|
+
unchanged: unchanged.length,
|
|
129
|
+
notInjected: r.notInjected.length,
|
|
130
|
+
},
|
|
131
|
+
locales: r.locales.map((l) => {
|
|
132
|
+
const failed = l.failed.length;
|
|
133
|
+
const otherMissing = l.missing.filter((k) => !failedBy.has(`${l.locale}\0${k}`)).length;
|
|
134
|
+
return {
|
|
135
|
+
locale: l.locale,
|
|
136
|
+
status: failed > 0 ? 'failed' : l.qa.length > 0 || otherMissing > 0 ? 'warning' : 'ok',
|
|
137
|
+
total: l.total,
|
|
138
|
+
translated: l.translated,
|
|
139
|
+
missing: l.missing.length,
|
|
140
|
+
failed,
|
|
141
|
+
qaWarnings: l.qa.length,
|
|
142
|
+
sameAsSource: l.sameAsSource.length,
|
|
143
|
+
};
|
|
144
|
+
}),
|
|
145
|
+
failures: { total: failures.length, items: failures },
|
|
146
|
+
qaWarnings: { total: qaItems.length, items: qaItems },
|
|
147
|
+
missing: { total: missing.length, items: missing },
|
|
148
|
+
unchanged: { total: unchanged.length, items: unchanged },
|
|
149
|
+
notInjected: { total: r.notInjected.length, items: r.notInjected },
|
|
150
|
+
unusedKeys: { total: r.unusedKeys.length, items: r.unusedKeys },
|
|
151
|
+
dynamicKeyFiles: r.dynamicKeyFiles,
|
|
152
|
+
keys,
|
|
153
|
+
warnings: r.warnings.map((w) => ({ type: w.type, file: w.file, ...(w.line !== undefined ? { line: w.line } : {}), message: w.message })),
|
|
154
|
+
notes: r.notes,
|
|
155
|
+
engineLog: r.engineLog,
|
|
156
|
+
...(r.formatter ? { formatter: r.formatter } : {}),
|
|
157
|
+
lockfile: r.lockfile,
|
|
158
|
+
lockfileIgnored: r.lockfileIgnored,
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Write the report as JSON. `file` is resolved against `projectDir`
|
|
163
|
+
* (default {@link DEFAULT_REPORT_FILE}); returns the absolute path written.
|
|
164
|
+
*/
|
|
165
|
+
async function writeTranslateReport(projectDir, report, file = exports.DEFAULT_REPORT_FILE) {
|
|
166
|
+
const abs = path.resolve(projectDir, file);
|
|
167
|
+
await (0, promises_1.mkdir)(path.dirname(abs), { recursive: true });
|
|
168
|
+
await (0, promises_1.writeFile)(abs, `${JSON.stringify(report, null, 2)}\n`);
|
|
169
|
+
return abs;
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Make `.babelize/.gitignore` (in `root`) ignore the report, creating the
|
|
173
|
+
* file if needed. Returns true when it changed. The lockfile in the same
|
|
174
|
+
* folder stays committed.
|
|
175
|
+
*/
|
|
176
|
+
async function ensureReportGitignored(root) {
|
|
177
|
+
const file = path.join(root, exports.BABELIZE_GITIGNORE);
|
|
178
|
+
const current = await (0, promises_1.readFile)(file, 'utf8').catch(() => null);
|
|
179
|
+
if (current !== null && current.split(/\r?\n/).some((line) => line.trim().replace(/^\//, '') === GITIGNORE_ENTRY))
|
|
180
|
+
return false;
|
|
181
|
+
await (0, promises_1.mkdir)(path.dirname(file), { recursive: true });
|
|
182
|
+
const header = '# Babelize: the QA report of the last local run (the lockfile next to it is committed).\n';
|
|
183
|
+
const next = current === null ? `${header}${GITIGNORE_ENTRY}\n` : `${current.replace(/\n?$/, '\n')}${GITIGNORE_ENTRY}\n`;
|
|
184
|
+
await (0, promises_1.writeFile)(file, next);
|
|
185
|
+
return true;
|
|
186
|
+
}
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import type { EngineConfigV2, EngineResultV2 } from '../runtime/types';
|
|
2
|
+
import type { TranslationFailure, TranslationProvider } from '../providers/types';
|
|
3
|
+
import { type ByokProvider } from '@babelize/types';
|
|
4
|
+
import type { HostedTranslationProvider } from './hosted-provider';
|
|
5
|
+
import { type FormatResult } from './formatter';
|
|
6
|
+
import { type FileDiffStat, type ApplyIo, type WorkspaceChanges } from './workspace-copy';
|
|
7
|
+
/** Lockfile scope for local runs: `.babelize/local/babelize-lock.json` in the project root. */
|
|
8
|
+
export declare const LOCAL_PROJECT_ID = "local";
|
|
9
|
+
export declare const LOCAL_LOCKFILE = ".babelize/local/babelize-lock.json";
|
|
10
|
+
export declare const SUPPORTED_LOCAL_FRAMEWORKS: readonly ["react", "nextjs"];
|
|
11
|
+
export declare const BETA_LOCAL_FRAMEWORKS: readonly ["vue", "static"];
|
|
12
|
+
export interface LocalTranslateOptions {
|
|
13
|
+
projectDir: string;
|
|
14
|
+
sourceLocale: string;
|
|
15
|
+
targetLocales: string[];
|
|
16
|
+
/** Compute and return the diff; write nothing to the project. */
|
|
17
|
+
dryRun: boolean;
|
|
18
|
+
/** Allow running on a dirty git tree. */
|
|
19
|
+
force: boolean;
|
|
20
|
+
/** The user's LLM key. Required unless `deps.translator` is injected. */
|
|
21
|
+
byok?: {
|
|
22
|
+
provider: ByokProvider;
|
|
23
|
+
apiKey: string;
|
|
24
|
+
model?: string;
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Treat `targetLocales` as the complete list: locales translated earlier
|
|
28
|
+
* but not listed are removed. Default false: earlier locales are kept and
|
|
29
|
+
* brought up to date (from the lockfile, so only new strings cost tokens).
|
|
30
|
+
*/
|
|
31
|
+
replace?: boolean;
|
|
32
|
+
}
|
|
33
|
+
export interface LocalTranslateDeps {
|
|
34
|
+
/** Replaces the BYOK translator (tests). */
|
|
35
|
+
translator?: TranslationProvider;
|
|
36
|
+
/**
|
|
37
|
+
* Babelize-hosted translation (BABELIZE_API_KEY). Used as the translator;
|
|
38
|
+
* its model is shown in the report and a bad key or empty balance stops
|
|
39
|
+
* the run with an actionable error.
|
|
40
|
+
*/
|
|
41
|
+
hosted?: HostedTranslationProvider;
|
|
42
|
+
/** Engine entry point; injectable for tests. */
|
|
43
|
+
runEngine?: (config: EngineConfigV2) => Promise<EngineResultV2>;
|
|
44
|
+
/** Engine progress; `status` is running/success/warning/error. */
|
|
45
|
+
onProgress?: (message: string, phase?: string, status?: string) => void;
|
|
46
|
+
/** Called once the framework is known, before any LLM call. */
|
|
47
|
+
onFramework?: (framework: string, status: FrameworkStatus) => void;
|
|
48
|
+
/** Parent dir for the temp copy (defaults to the OS temp dir). */
|
|
49
|
+
tmpRoot?: string;
|
|
50
|
+
/** File operations for applying changes; injectable to simulate disk failures. */
|
|
51
|
+
applyIo?: ApplyIo;
|
|
52
|
+
/**
|
|
53
|
+
* How to name an injected `translator` in the report (e.g. the
|
|
54
|
+
* pseudo-localization provider). Without it the report has no provider.
|
|
55
|
+
*/
|
|
56
|
+
translatorInfo?: {
|
|
57
|
+
provider: ReportProviderId;
|
|
58
|
+
name: string;
|
|
59
|
+
model?: string;
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
/** Provider ids a report can name: BYOK providers, Babelize-hosted, or pseudo-localization. */
|
|
63
|
+
export type ReportProviderId = ByokProvider | 'babelize' | 'pseudo';
|
|
64
|
+
export type FrameworkStatus = 'supported' | 'beta';
|
|
65
|
+
export type LocalTranslateErrorCode = 'not_a_repo' | 'git_missing' | 'dirty' | 'invalid_locale' | 'no_translator' | 'unsupported_framework' | 'translator_unreachable'
|
|
66
|
+
/** BABELIZE_API_KEY rejected. */
|
|
67
|
+
| 'hosted_auth'
|
|
68
|
+
/** Babelize account out of AI credits. */
|
|
69
|
+
| 'hosted_credits' | 'engine_failed' | 'incomplete_translation'
|
|
70
|
+
/** Writing to the project failed; see `changedFiles` for what is left changed. */
|
|
71
|
+
| 'apply_failed'
|
|
72
|
+
/** Project files changed while the run was in progress; nothing was applied. */
|
|
73
|
+
| 'project_changed';
|
|
74
|
+
export declare class LocalTranslateError extends Error {
|
|
75
|
+
readonly code: LocalTranslateErrorCode;
|
|
76
|
+
/** Files left changed in the project (only for a failed, un-rolled-back apply). */
|
|
77
|
+
readonly changedFiles: string[];
|
|
78
|
+
constructor(message: string, code: LocalTranslateErrorCode,
|
|
79
|
+
/** Files left changed in the project (only for a failed, un-rolled-back apply). */
|
|
80
|
+
changedFiles?: string[]);
|
|
81
|
+
}
|
|
82
|
+
/** Per-locale outcome. `missing` and `sameAsSource` are what a reviewer should look at. */
|
|
83
|
+
export interface LocaleReport {
|
|
84
|
+
locale: string;
|
|
85
|
+
/** Keys in the source locale. */
|
|
86
|
+
total: number;
|
|
87
|
+
/** Keys with a value (including values identical to the source, see `sameAsSource`). */
|
|
88
|
+
translated: number;
|
|
89
|
+
/** Keys with no value in this locale (the app will show the fallback). */
|
|
90
|
+
missing: string[];
|
|
91
|
+
/** Keys the engine could not translate this run, with the reason (subset of `missing`). */
|
|
92
|
+
failed: Array<{
|
|
93
|
+
key: string;
|
|
94
|
+
reason: string;
|
|
95
|
+
message?: string;
|
|
96
|
+
retryable: boolean;
|
|
97
|
+
}>;
|
|
98
|
+
/** Keys translated with QA warnings from the engine (glossary, length, …). */
|
|
99
|
+
qa: Array<{
|
|
100
|
+
key: string;
|
|
101
|
+
warnings: string[];
|
|
102
|
+
}>;
|
|
103
|
+
/**
|
|
104
|
+
* Keys whose value is identical to the source text. The engine already
|
|
105
|
+
* rejects untranslated output, so this is only a review hint (brand names,
|
|
106
|
+
* "OK", or a cached value from before that check existed).
|
|
107
|
+
*/
|
|
108
|
+
sameAsSource: string[];
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Everything a run produced. Structured so a per-key QA report (#237) can be
|
|
112
|
+
* rendered from it without re-running anything.
|
|
113
|
+
*/
|
|
114
|
+
export interface LocalTranslateReport {
|
|
115
|
+
framework: string;
|
|
116
|
+
frameworkStatus: FrameworkStatus;
|
|
117
|
+
/** `model` is absent for hosted runs where the server didn't report one. */
|
|
118
|
+
provider?: {
|
|
119
|
+
provider: ReportProviderId;
|
|
120
|
+
name: string;
|
|
121
|
+
model?: string;
|
|
122
|
+
};
|
|
123
|
+
sourceLocale: string;
|
|
124
|
+
/** Locales translated in this run: `--to` plus earlier locales (unless replace). */
|
|
125
|
+
targetLocales: string[];
|
|
126
|
+
/** Earlier locales that were kept and updated although not in `--to`. */
|
|
127
|
+
keptLocales: string[];
|
|
128
|
+
/** Earlier locales removed by `--replace` (files and lockfile entries). */
|
|
129
|
+
droppedLocales: string[];
|
|
130
|
+
/**
|
|
131
|
+
* Source keys with no t() reference found by a heuristic scan. Advisory
|
|
132
|
+
* only: they are still translated, kept and written like any other key.
|
|
133
|
+
*/
|
|
134
|
+
unusedKeys: string[];
|
|
135
|
+
/** Strings extracted (and translated) but not wired into the code. */
|
|
136
|
+
notInjected: Array<{
|
|
137
|
+
file: string;
|
|
138
|
+
key: string;
|
|
139
|
+
text: string;
|
|
140
|
+
reason: string;
|
|
141
|
+
}>;
|
|
142
|
+
/** Files whose non-literal t() keys made every key count as used. */
|
|
143
|
+
dynamicKeyFiles: string[];
|
|
144
|
+
dryRun: boolean;
|
|
145
|
+
/** True when changes were written to the project. */
|
|
146
|
+
applied: boolean;
|
|
147
|
+
changes: WorkspaceChanges;
|
|
148
|
+
/** Unified diff of `changes` (always computed for --dry-run). */
|
|
149
|
+
diff?: string;
|
|
150
|
+
/** Lines added/removed per changed file, from old vs new content. */
|
|
151
|
+
diffStat: FileDiffStat[];
|
|
152
|
+
stats: {
|
|
153
|
+
filesScanned: number;
|
|
154
|
+
stringsExtracted: number;
|
|
155
|
+
keysExtracted: number;
|
|
156
|
+
injectionsApplied: number;
|
|
157
|
+
keysFromLockfile: number;
|
|
158
|
+
keysSentToTranslator: number;
|
|
159
|
+
/** (key, locale) translations produced by the translator this run (billable). */
|
|
160
|
+
translatedThisRun?: number;
|
|
161
|
+
};
|
|
162
|
+
locales: LocaleReport[];
|
|
163
|
+
/** Every key that failed, across locales. Non-empty means the run is partial. */
|
|
164
|
+
translationFailures: TranslationFailure[];
|
|
165
|
+
warnings: Array<{
|
|
166
|
+
type: string;
|
|
167
|
+
file: string;
|
|
168
|
+
line?: number;
|
|
169
|
+
message: string;
|
|
170
|
+
}>;
|
|
171
|
+
/** Finalization notes (dependencies added, config created, …). */
|
|
172
|
+
notes: string[];
|
|
173
|
+
/** The project's prettier/biome run on changed files, if it has one. */
|
|
174
|
+
formatter?: FormatResult;
|
|
175
|
+
/** Warnings/errors the engine logged while running. */
|
|
176
|
+
engineLog: Array<{
|
|
177
|
+
level: 'warn' | 'error';
|
|
178
|
+
message: string;
|
|
179
|
+
}>;
|
|
180
|
+
lockfile: string;
|
|
181
|
+
/**
|
|
182
|
+
* True when the lockfile is gitignored (`babelize init` adds `.babelize/`):
|
|
183
|
+
* it still works locally, but teammates and CI won't get it.
|
|
184
|
+
*/
|
|
185
|
+
lockfileIgnored: boolean;
|
|
186
|
+
/** Per-key engine metadata (confidence, TM/lockfile origin) by locale. */
|
|
187
|
+
metadata: Record<string, Record<string, unknown>>;
|
|
188
|
+
/** source key → source text, and locale → key → translated text. */
|
|
189
|
+
results: {
|
|
190
|
+
source: Record<string, string>;
|
|
191
|
+
targets: Record<string, Record<string, string>>;
|
|
192
|
+
};
|
|
193
|
+
/** Epoch ms when the run started. */
|
|
194
|
+
startedAt: number;
|
|
195
|
+
durationMs: number;
|
|
196
|
+
}
|
|
197
|
+
/** Normalise `--to fr,de , ja` into a deduped list without the source locale. */
|
|
198
|
+
export declare function parseLocales(raw: string | string[] | undefined, sourceLocale: string): string[];
|
|
199
|
+
export declare function validateLocales(sourceLocale: string, targetLocales: string[]): void;
|
|
200
|
+
/**
|
|
201
|
+
* Engine log lines that are wrong or redundant for a local run: the
|
|
202
|
+
* TRANSLATOR_URL check doesn't know about BYOK/injected providers, and the
|
|
203
|
+
* "run your install" hint is already a finalization note in the summary.
|
|
204
|
+
*/
|
|
205
|
+
/** `msg` as one sentence: trailing dots/spaces trimmed, exactly one period added. */
|
|
206
|
+
export declare function sentence(msg: string): string;
|
|
207
|
+
export declare function isEngineLogNoise(message: string): boolean;
|
|
208
|
+
export declare function buildLocaleReports(targetLocales: string[], source: Record<string, string>, targets: Record<string, Record<string, string>>, failures?: TranslationFailure[], metadata?: Record<string, Record<string, unknown>>): LocaleReport[];
|
|
209
|
+
/**
|
|
210
|
+
* Run the Babelize engine on a temp copy of `projectDir` and, unless
|
|
211
|
+
* `dryRun`, apply the result back to the working tree. The project is never
|
|
212
|
+
* touched until the engine has finished successfully and every target locale
|
|
213
|
+
* has translations.
|
|
214
|
+
*/
|
|
215
|
+
export declare function runLocalTranslate(opts: LocalTranslateOptions, deps?: LocalTranslateDeps): Promise<LocalTranslateReport>;
|