@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
package/dist/index.js
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Babelize Engine v2 — public API.
|
|
4
|
+
*
|
|
5
|
+
* This folder is introduced alongside the existing v1 engine (phases/*) using a
|
|
6
|
+
* strangler-fig approach. Nothing outside v2 should import internal modules
|
|
7
|
+
* directly — only this file re-exports the public surface.
|
|
8
|
+
*/
|
|
9
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
12
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
13
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
14
|
+
}
|
|
15
|
+
Object.defineProperty(o, k2, desc);
|
|
16
|
+
}) : (function(o, m, k, k2) {
|
|
17
|
+
if (k2 === undefined) k2 = k;
|
|
18
|
+
o[k2] = m[k];
|
|
19
|
+
}));
|
|
20
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
21
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
22
|
+
};
|
|
23
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
24
|
+
exports.tallyLocaleIssues = exports.flattenLocaleMessages = exports.checkLocalePair = exports.frameworkSupport = exports.analyzeWorkspace = exports.analyzeProject = exports.localeExtension = exports.getCircuitBreaker = exports.CircuitState = exports.CircuitBreaker = exports.validateBatchQuality = exports.validateTranslationQuality = exports.translatorLoadBalancer = exports.warmupTranslator = exports.checkTranslatorHealth = exports.callTranslator = exports.requiredPluralCategories = exports.parseIcu = exports.isIcuMessage = exports.compareIcuMessages = exports.sameProtectedSpans = exports.restoreText = exports.protectText = exports.hasNothingToTranslate = exports.checkTokens = exports.validateRawTokens = exports.sanitizeTranslation = exports.restorePlaceholders = exports.protectPlaceholders = exports.hashString = exports.hasICUSyntax = exports.extractPlaceholders = exports.parseCode = exports.saveProjectConfig = exports.saveCachedStrings = exports.getProjectInfo = exports.getBabelizeSummary = exports.detectProjectInfo = exports.addBabelToHistory = exports.formatSyncNotificationMessage = exports.detectSyncIssues = exports.matchFromMemory = exports.setEngineLogger = exports.runWithEngineLogger = exports.validateWorkspace = exports.scanKeyReferences = exports.validateEngineConfigV2 = exports.runEngineV2 = exports.loadBabelizeConfig = exports.BabelizeEngine = void 0;
|
|
25
|
+
exports.TRANSLATION_CACHE_TTL_SECONDS = exports.translationCacheKey = exports.hashText = exports.readProjectLocaleConfig = exports.localeIssueFile = exports.checkProjectLocales = exports.ReviewError = exports.reviewLocaleChanges = exports.loadLocale = exports.isLocaleCode = exports.isIgnoredLocalePath = exports.groupLocaleFiles = exports.findLocaleFileSets = exports.DEFAULT_LOCALE_IGNORE_DIRS = void 0;
|
|
26
|
+
var BabelizeEngine_1 = require("./BabelizeEngine");
|
|
27
|
+
Object.defineProperty(exports, "BabelizeEngine", { enumerable: true, get: function () { return BabelizeEngine_1.BabelizeEngine; } });
|
|
28
|
+
var config_1 = require("./config");
|
|
29
|
+
Object.defineProperty(exports, "loadBabelizeConfig", { enumerable: true, get: function () { return config_1.loadBabelizeConfig; } });
|
|
30
|
+
// Backend runtime surface (workers/controllers).
|
|
31
|
+
var runtime_1 = require("./runtime");
|
|
32
|
+
Object.defineProperty(exports, "runEngineV2", { enumerable: true, get: function () { return runtime_1.runEngineV2; } });
|
|
33
|
+
Object.defineProperty(exports, "validateEngineConfigV2", { enumerable: true, get: function () { return runtime_1.validateEngineConfigV2; } });
|
|
34
|
+
var key_usage_1 = require("./utils/key-usage");
|
|
35
|
+
Object.defineProperty(exports, "scanKeyReferences", { enumerable: true, get: function () { return key_usage_1.scanKeyReferences; } });
|
|
36
|
+
// Framework detection without running the pipeline (CLI `translate` uses it
|
|
37
|
+
// to refuse unsupported projects before spending any LLM calls).
|
|
38
|
+
var workspace_1 = require("./modules/workspace");
|
|
39
|
+
Object.defineProperty(exports, "validateWorkspace", { enumerable: true, get: function () { return workspace_1.validateWorkspace; } });
|
|
40
|
+
// ── Providers (infrastructure the host injects) ──────────────
|
|
41
|
+
__exportStar(require("./providers"), exports);
|
|
42
|
+
var logger_1 = require("./utils/logger");
|
|
43
|
+
Object.defineProperty(exports, "runWithEngineLogger", { enumerable: true, get: function () { return logger_1.runWithEngineLogger; } });
|
|
44
|
+
Object.defineProperty(exports, "setEngineLogger", { enumerable: true, get: function () { return logger_1.setEngineLogger; } });
|
|
45
|
+
// ── Pipeline pieces the backend uses directly ────────────────
|
|
46
|
+
__exportStar(require("./modules/lockfile"), exports);
|
|
47
|
+
__exportStar(require("./modules/translator/language-codes"), exports);
|
|
48
|
+
var memory_matcher_1 = require("./modules/translator/memory/memory-matcher");
|
|
49
|
+
Object.defineProperty(exports, "matchFromMemory", { enumerable: true, get: function () { return memory_matcher_1.matchFromMemory; } });
|
|
50
|
+
var sync_detector_1 = require("./modules/sync-detector");
|
|
51
|
+
Object.defineProperty(exports, "detectSyncIssues", { enumerable: true, get: function () { return sync_detector_1.detectSyncIssues; } });
|
|
52
|
+
Object.defineProperty(exports, "formatSyncNotificationMessage", { enumerable: true, get: function () { return sync_detector_1.formatSyncNotificationMessage; } });
|
|
53
|
+
// ── Utilities shared with the backend ────────────────────────
|
|
54
|
+
var metadata_1 = require("./utils/metadata");
|
|
55
|
+
Object.defineProperty(exports, "addBabelToHistory", { enumerable: true, get: function () { return metadata_1.addBabelToHistory; } });
|
|
56
|
+
Object.defineProperty(exports, "detectProjectInfo", { enumerable: true, get: function () { return metadata_1.detectProjectInfo; } });
|
|
57
|
+
Object.defineProperty(exports, "getBabelizeSummary", { enumerable: true, get: function () { return metadata_1.getBabelizeSummary; } });
|
|
58
|
+
Object.defineProperty(exports, "getProjectInfo", { enumerable: true, get: function () { return metadata_1.getProjectInfo; } });
|
|
59
|
+
Object.defineProperty(exports, "saveCachedStrings", { enumerable: true, get: function () { return metadata_1.saveCachedStrings; } });
|
|
60
|
+
Object.defineProperty(exports, "saveProjectConfig", { enumerable: true, get: function () { return metadata_1.saveProjectConfig; } });
|
|
61
|
+
var ast_helpers_1 = require("./utils/ast-helpers");
|
|
62
|
+
Object.defineProperty(exports, "parseCode", { enumerable: true, get: function () { return ast_helpers_1.parseCode; } });
|
|
63
|
+
var string_utils_1 = require("./utils/string-utils");
|
|
64
|
+
Object.defineProperty(exports, "extractPlaceholders", { enumerable: true, get: function () { return string_utils_1.extractPlaceholders; } });
|
|
65
|
+
Object.defineProperty(exports, "hasICUSyntax", { enumerable: true, get: function () { return string_utils_1.hasICUSyntax; } });
|
|
66
|
+
Object.defineProperty(exports, "hashString", { enumerable: true, get: function () { return string_utils_1.hashString; } });
|
|
67
|
+
Object.defineProperty(exports, "protectPlaceholders", { enumerable: true, get: function () { return string_utils_1.protectPlaceholders; } });
|
|
68
|
+
Object.defineProperty(exports, "restorePlaceholders", { enumerable: true, get: function () { return string_utils_1.restorePlaceholders; } });
|
|
69
|
+
var translation_sanitizer_1 = require("./utils/translation-sanitizer");
|
|
70
|
+
Object.defineProperty(exports, "sanitizeTranslation", { enumerable: true, get: function () { return translation_sanitizer_1.sanitizeTranslation; } });
|
|
71
|
+
Object.defineProperty(exports, "validateRawTokens", { enumerable: true, get: function () { return translation_sanitizer_1.validateRawTokens; } });
|
|
72
|
+
var placeholder_protection_1 = require("./utils/placeholder-protection");
|
|
73
|
+
Object.defineProperty(exports, "checkTokens", { enumerable: true, get: function () { return placeholder_protection_1.checkTokens; } });
|
|
74
|
+
Object.defineProperty(exports, "hasNothingToTranslate", { enumerable: true, get: function () { return placeholder_protection_1.hasNothingToTranslate; } });
|
|
75
|
+
Object.defineProperty(exports, "protectText", { enumerable: true, get: function () { return placeholder_protection_1.protectText; } });
|
|
76
|
+
Object.defineProperty(exports, "restoreText", { enumerable: true, get: function () { return placeholder_protection_1.restoreText; } });
|
|
77
|
+
Object.defineProperty(exports, "sameProtectedSpans", { enumerable: true, get: function () { return placeholder_protection_1.sameProtectedSpans; } });
|
|
78
|
+
var icu_message_1 = require("./utils/icu-message");
|
|
79
|
+
Object.defineProperty(exports, "compareIcuMessages", { enumerable: true, get: function () { return icu_message_1.compareIcuMessages; } });
|
|
80
|
+
Object.defineProperty(exports, "isIcuMessage", { enumerable: true, get: function () { return icu_message_1.isIcuMessage; } });
|
|
81
|
+
Object.defineProperty(exports, "parseIcu", { enumerable: true, get: function () { return icu_message_1.parseIcu; } });
|
|
82
|
+
Object.defineProperty(exports, "requiredPluralCategories", { enumerable: true, get: function () { return icu_message_1.requiredPluralCategories; } });
|
|
83
|
+
var translator_caller_1 = require("./utils/translator-caller");
|
|
84
|
+
Object.defineProperty(exports, "callTranslator", { enumerable: true, get: function () { return translator_caller_1.callTranslator; } });
|
|
85
|
+
Object.defineProperty(exports, "checkTranslatorHealth", { enumerable: true, get: function () { return translator_caller_1.checkTranslatorHealth; } });
|
|
86
|
+
Object.defineProperty(exports, "warmupTranslator", { enumerable: true, get: function () { return translator_caller_1.warmupTranslator; } });
|
|
87
|
+
var translator_load_balancer_1 = require("./utils/translator-load-balancer");
|
|
88
|
+
Object.defineProperty(exports, "translatorLoadBalancer", { enumerable: true, get: function () { return translator_load_balancer_1.translatorLoadBalancer; } });
|
|
89
|
+
var translation_quality_1 = require("./utils/translation-quality");
|
|
90
|
+
Object.defineProperty(exports, "validateTranslationQuality", { enumerable: true, get: function () { return translation_quality_1.validateTranslationQuality; } });
|
|
91
|
+
Object.defineProperty(exports, "validateBatchQuality", { enumerable: true, get: function () { return translation_quality_1.validateBatchQuality; } });
|
|
92
|
+
var circuit_breaker_1 = require("./utils/circuit-breaker");
|
|
93
|
+
Object.defineProperty(exports, "CircuitBreaker", { enumerable: true, get: function () { return circuit_breaker_1.CircuitBreaker; } });
|
|
94
|
+
Object.defineProperty(exports, "CircuitState", { enumerable: true, get: function () { return circuit_breaker_1.CircuitState; } });
|
|
95
|
+
Object.defineProperty(exports, "getCircuitBreaker", { enumerable: true, get: function () { return circuit_breaker_1.getCircuitBreaker; } });
|
|
96
|
+
var file_utils_1 = require("./utils/file-utils");
|
|
97
|
+
Object.defineProperty(exports, "localeExtension", { enumerable: true, get: function () { return file_utils_1.localeExtension; } });
|
|
98
|
+
// ── Local analysis and locale QA (no translation, no network) ──
|
|
99
|
+
var analyze_1 = require("./analysis/analyze");
|
|
100
|
+
Object.defineProperty(exports, "analyzeProject", { enumerable: true, get: function () { return analyze_1.analyzeProject; } });
|
|
101
|
+
Object.defineProperty(exports, "analyzeWorkspace", { enumerable: true, get: function () { return analyze_1.analyzeWorkspace; } });
|
|
102
|
+
Object.defineProperty(exports, "frameworkSupport", { enumerable: true, get: function () { return analyze_1.frameworkSupport; } });
|
|
103
|
+
var locale_qa_1 = require("./qa/locale-qa");
|
|
104
|
+
Object.defineProperty(exports, "checkLocalePair", { enumerable: true, get: function () { return locale_qa_1.checkLocalePair; } });
|
|
105
|
+
Object.defineProperty(exports, "flattenLocaleMessages", { enumerable: true, get: function () { return locale_qa_1.flattenLocaleMessages; } });
|
|
106
|
+
Object.defineProperty(exports, "tallyLocaleIssues", { enumerable: true, get: function () { return locale_qa_1.tallyLocaleIssues; } });
|
|
107
|
+
var locale_files_1 = require("./qa/locale-files");
|
|
108
|
+
Object.defineProperty(exports, "DEFAULT_LOCALE_IGNORE_DIRS", { enumerable: true, get: function () { return locale_files_1.DEFAULT_LOCALE_IGNORE_DIRS; } });
|
|
109
|
+
Object.defineProperty(exports, "findLocaleFileSets", { enumerable: true, get: function () { return locale_files_1.findLocaleFileSets; } });
|
|
110
|
+
Object.defineProperty(exports, "groupLocaleFiles", { enumerable: true, get: function () { return locale_files_1.groupLocaleFiles; } });
|
|
111
|
+
Object.defineProperty(exports, "isIgnoredLocalePath", { enumerable: true, get: function () { return locale_files_1.isIgnoredLocalePath; } });
|
|
112
|
+
Object.defineProperty(exports, "isLocaleCode", { enumerable: true, get: function () { return locale_files_1.isLocaleCode; } });
|
|
113
|
+
Object.defineProperty(exports, "loadLocale", { enumerable: true, get: function () { return locale_files_1.loadLocale; } });
|
|
114
|
+
var review_1 = require("./qa/review");
|
|
115
|
+
Object.defineProperty(exports, "reviewLocaleChanges", { enumerable: true, get: function () { return review_1.reviewLocaleChanges; } });
|
|
116
|
+
Object.defineProperty(exports, "ReviewError", { enumerable: true, get: function () { return review_1.ReviewError; } });
|
|
117
|
+
var check_project_1 = require("./qa/check-project");
|
|
118
|
+
Object.defineProperty(exports, "checkProjectLocales", { enumerable: true, get: function () { return check_project_1.checkProjectLocales; } });
|
|
119
|
+
Object.defineProperty(exports, "localeIssueFile", { enumerable: true, get: function () { return check_project_1.localeIssueFile; } });
|
|
120
|
+
Object.defineProperty(exports, "readProjectLocaleConfig", { enumerable: true, get: function () { return check_project_1.readProjectLocaleConfig; } });
|
|
121
|
+
var cache_keys_1 = require("./utils/cache-keys");
|
|
122
|
+
Object.defineProperty(exports, "hashText", { enumerable: true, get: function () { return cache_keys_1.hashText; } });
|
|
123
|
+
Object.defineProperty(exports, "translationCacheKey", { enumerable: true, get: function () { return cache_keys_1.translationCacheKey; } });
|
|
124
|
+
Object.defineProperty(exports, "TRANSLATION_CACHE_TTL_SECONDS", { enumerable: true, get: function () { return cache_keys_1.TRANSLATION_CACHE_TTL_SECONDS; } });
|
|
125
|
+
// ── Local translation runner (CLI `babelize translate`, MCP `babelize_translate`) ──
|
|
126
|
+
__exportStar(require("./local"), exports);
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import * as t from '@babel/types';
|
|
2
|
+
import type { JsxMessage } from '../utils/jsx-message';
|
|
3
|
+
export interface MessageOptions {
|
|
4
|
+
/** Local name for react-i18next's Trans (`BabelizeTrans` when the file already binds `Trans`). */
|
|
5
|
+
transName?: string;
|
|
6
|
+
}
|
|
7
|
+
/** What a strategy renders for a JSX sentence message. */
|
|
8
|
+
export interface MessageRendering {
|
|
9
|
+
/** Replaces the element's children. */
|
|
10
|
+
node: t.JSXExpressionContainer | t.JSXElement;
|
|
11
|
+
/** Named imports the rendering needs, e.g. `Trans` from react-i18next (`local` when aliased). */
|
|
12
|
+
imports?: Array<{
|
|
13
|
+
source: string;
|
|
14
|
+
name: string;
|
|
15
|
+
local?: string;
|
|
16
|
+
}>;
|
|
17
|
+
}
|
|
18
|
+
export interface InjectionContext {
|
|
19
|
+
filePath: string;
|
|
20
|
+
isComponent: boolean;
|
|
21
|
+
hasUseClient: boolean;
|
|
22
|
+
/** The component the hook goes into is already `async` (set per component). */
|
|
23
|
+
isAsyncComponent?: boolean;
|
|
24
|
+
}
|
|
25
|
+
export interface InjectionStrategy {
|
|
26
|
+
/**
|
|
27
|
+
* Framework identifier
|
|
28
|
+
*/
|
|
29
|
+
id: string;
|
|
30
|
+
/**
|
|
31
|
+
* Determine if an import is already present in the AST
|
|
32
|
+
*/
|
|
33
|
+
hasImport(ast: t.File): boolean;
|
|
34
|
+
/**
|
|
35
|
+
* Create the AST node for the import declaration
|
|
36
|
+
*/
|
|
37
|
+
createImport(context?: InjectionContext): t.ImportDeclaration;
|
|
38
|
+
/**
|
|
39
|
+
* Determine if the hook/setup is already present in the component body
|
|
40
|
+
*/
|
|
41
|
+
hasHook(componentPath: any): boolean;
|
|
42
|
+
/**
|
|
43
|
+
* Create the AST node(s) for the hook declaration
|
|
44
|
+
* Context allows handling async/await for server components
|
|
45
|
+
*/
|
|
46
|
+
createHook(context: InjectionContext): t.Statement[];
|
|
47
|
+
/**
|
|
48
|
+
* Return the identifier name used for translation (typically 't')
|
|
49
|
+
*/
|
|
50
|
+
getTranslationFunctionName(): string;
|
|
51
|
+
/**
|
|
52
|
+
* Does the hook require the component function to be async?
|
|
53
|
+
*/
|
|
54
|
+
requiresAsyncComponent(context: InjectionContext): boolean;
|
|
55
|
+
/**
|
|
56
|
+
* Render a JSX sentence (named placeholders, inline tags) for `key`, e.g.
|
|
57
|
+
* `{t("key", { user })}`. Null when the strategy can't express it (rich
|
|
58
|
+
* text without a component API) — the sentence is then left as is and
|
|
59
|
+
* reported as not injected. Strategies without it render placeholders only.
|
|
60
|
+
*/
|
|
61
|
+
createMessage?(key: string, message: JsxMessage, options?: MessageOptions): MessageRendering | null;
|
|
62
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.StrategyFactory = void 0;
|
|
4
|
+
const ReactI18nextStrategy_1 = require("./strategies/ReactI18nextStrategy");
|
|
5
|
+
const NextIntlStrategy_1 = require("./strategies/NextIntlStrategy");
|
|
6
|
+
const VanillaStrategy_1 = require("./strategies/VanillaStrategy");
|
|
7
|
+
const VueI18nStrategy_1 = require("./strategies/VueI18nStrategy");
|
|
8
|
+
class StrategyFactory {
|
|
9
|
+
static getStrategy(framework, existingDeps) {
|
|
10
|
+
if (existingDeps?.['react-i18next']) {
|
|
11
|
+
return new ReactI18nextStrategy_1.ReactI18nextStrategy();
|
|
12
|
+
}
|
|
13
|
+
if (existingDeps?.['next-intl']) {
|
|
14
|
+
return new NextIntlStrategy_1.NextIntlStrategy();
|
|
15
|
+
}
|
|
16
|
+
switch (framework) {
|
|
17
|
+
case 'nextjs':
|
|
18
|
+
return new NextIntlStrategy_1.NextIntlStrategy();
|
|
19
|
+
case 'react':
|
|
20
|
+
return new ReactI18nextStrategy_1.ReactI18nextStrategy();
|
|
21
|
+
case 'vue':
|
|
22
|
+
return new VueI18nStrategy_1.VueI18nStrategy();
|
|
23
|
+
case 'unknown':
|
|
24
|
+
default:
|
|
25
|
+
return new VanillaStrategy_1.VanillaStrategy();
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
exports.StrategyFactory = StrategyFactory;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { FileInjection } from '../../runtime/types';
|
|
2
|
+
export interface DjangoInjectorOptions {
|
|
3
|
+
/** The masked HTML content after standard HTML injection has run */
|
|
4
|
+
maskedContent: string;
|
|
5
|
+
/** The restore function from dtl-mask to undo masking */
|
|
6
|
+
restore: (masked: string) => string;
|
|
7
|
+
/** Path of the file being processed */
|
|
8
|
+
filePath: string;
|
|
9
|
+
/** Mapping from extraction ID to translation key */
|
|
10
|
+
keyMapping: Map<string, string>;
|
|
11
|
+
/** Original unmodified source content for comparison */
|
|
12
|
+
sourceContent: string;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Convert data-i18n attributes to Django {% trans %} tags.
|
|
16
|
+
*
|
|
17
|
+
* For pure text elements:
|
|
18
|
+
* <p data-i18n="hello">Hello</p> → <p>{% trans "hello" %}</p>
|
|
19
|
+
*
|
|
20
|
+
* For mixed content (elements with both text and child elements):
|
|
21
|
+
* <p data-i18n="hello">Hello <em>world</em></p> →
|
|
22
|
+
* <p>{% blocktrans %}Hello <em>world</em>{% endblocktrans %}</p>
|
|
23
|
+
* (blocktrans wraps the raw inner HTML)
|
|
24
|
+
*
|
|
25
|
+
* For attribute translations:
|
|
26
|
+
* <input data-i18n-placeholder="ph_key" placeholder="Search..."> →
|
|
27
|
+
* <input placeholder="{% trans "ph_key" %}">
|
|
28
|
+
*/
|
|
29
|
+
export declare function injectDjangoTemplates(options: DjangoInjectorOptions): Promise<FileInjection>;
|
|
@@ -0,0 +1,216 @@
|
|
|
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.injectDjangoTemplates = injectDjangoTemplates;
|
|
37
|
+
function asElement(node) {
|
|
38
|
+
return node.nodeType === 1 ? node : null;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Convert data-i18n attributes to Django {% trans %} tags.
|
|
42
|
+
*
|
|
43
|
+
* For pure text elements:
|
|
44
|
+
* <p data-i18n="hello">Hello</p> → <p>{% trans "hello" %}</p>
|
|
45
|
+
*
|
|
46
|
+
* For mixed content (elements with both text and child elements):
|
|
47
|
+
* <p data-i18n="hello">Hello <em>world</em></p> →
|
|
48
|
+
* <p>{% blocktrans %}Hello <em>world</em>{% endblocktrans %}</p>
|
|
49
|
+
* (blocktrans wraps the raw inner HTML)
|
|
50
|
+
*
|
|
51
|
+
* For attribute translations:
|
|
52
|
+
* <input data-i18n-placeholder="ph_key" placeholder="Search..."> →
|
|
53
|
+
* <input placeholder="{% trans "ph_key" %}">
|
|
54
|
+
*/
|
|
55
|
+
async function injectDjangoTemplates(options) {
|
|
56
|
+
const { maskedContent, restore, filePath, keyMapping } = options;
|
|
57
|
+
const { parse } = await Promise.resolve().then(() => __importStar(require('node-html-parser')));
|
|
58
|
+
const injections = [];
|
|
59
|
+
const importAdded = false;
|
|
60
|
+
const hookAdded = false;
|
|
61
|
+
// Parse the masked + injected HTML
|
|
62
|
+
const root = parse(maskedContent, {
|
|
63
|
+
comment: false,
|
|
64
|
+
blockTextElements: { script: true, style: true, noscript: true, pre: true },
|
|
65
|
+
});
|
|
66
|
+
const htmlEl = root.querySelector('html');
|
|
67
|
+
if (!htmlEl) {
|
|
68
|
+
return {
|
|
69
|
+
file: filePath,
|
|
70
|
+
originalContent: options.sourceContent,
|
|
71
|
+
modifiedContent: restore(maskedContent),
|
|
72
|
+
injections,
|
|
73
|
+
importAdded,
|
|
74
|
+
hookAdded,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
walkAndInject(htmlEl, filePath, options.sourceContent, keyMapping, injections);
|
|
78
|
+
let modifiedContent = root.toString();
|
|
79
|
+
// Remove the i18n.js script tag injected by HTML pipeline — Django uses {% trans %} not client JS
|
|
80
|
+
modifiedContent = modifiedContent.replace(/<script[^>]*src\s*=\s*["']i18n\.js["'][^>]*>\s*<\/script>\s*\n?/g, '');
|
|
81
|
+
// Add {% load i18n %} after any {% extends %} tag (DTL requires extends first)
|
|
82
|
+
modifiedContent = ensureI18nLoad(modifiedContent);
|
|
83
|
+
// Restore template tags
|
|
84
|
+
modifiedContent = restore(modifiedContent);
|
|
85
|
+
return {
|
|
86
|
+
file: filePath,
|
|
87
|
+
originalContent: options.sourceContent,
|
|
88
|
+
modifiedContent,
|
|
89
|
+
injections,
|
|
90
|
+
importAdded,
|
|
91
|
+
hookAdded,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
function walkAndInject(node, filePath, sourceContent, keyMapping, injections) {
|
|
95
|
+
const element = asElement(node);
|
|
96
|
+
if (!element)
|
|
97
|
+
return;
|
|
98
|
+
const rawTagName = element.rawTagName?.toLowerCase();
|
|
99
|
+
if (!rawTagName)
|
|
100
|
+
return;
|
|
101
|
+
if (['script', 'style', 'noscript', 'code', 'pre', 'svg'].includes(rawTagName))
|
|
102
|
+
return;
|
|
103
|
+
// Handle data-i18n on this element
|
|
104
|
+
const i18nKey = element.getAttribute('data-i18n');
|
|
105
|
+
if (i18nKey) {
|
|
106
|
+
convertDataI18nToTransTag(element, i18nKey, filePath, sourceContent, injections);
|
|
107
|
+
}
|
|
108
|
+
// Handle data-i18n-{attr} for attribute translations
|
|
109
|
+
convertDataI18nAttrTags(element, filePath, sourceContent, injections);
|
|
110
|
+
// Recurse into children
|
|
111
|
+
for (const child of node.childNodes || []) {
|
|
112
|
+
if (child.nodeType === 1) {
|
|
113
|
+
walkAndInject(child, filePath, sourceContent, keyMapping, injections);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
function convertDataI18nToTransTag(element, key, filePath, sourceContent, injections) {
|
|
118
|
+
const line = element.range
|
|
119
|
+
? (sourceContent.slice(0, element.range[0]).match(/\n/g) || []).length + 1
|
|
120
|
+
: 0;
|
|
121
|
+
// Remove the data-i18n attribute
|
|
122
|
+
element.removeAttribute('data-i18n');
|
|
123
|
+
const children = element.childNodes || [];
|
|
124
|
+
const hasElementChildren = children.some((c) => c.nodeType === 1);
|
|
125
|
+
if (hasElementChildren) {
|
|
126
|
+
// Mixed content: use blocktrans / endblocktrans
|
|
127
|
+
// Preserve inner HTML and wrap with blocktrans
|
|
128
|
+
const innerHtml = children
|
|
129
|
+
.map((c) => (c.nodeType === 1 ? c.toString() : c.toString()))
|
|
130
|
+
.join('');
|
|
131
|
+
// Replace children with raw blocktrans content
|
|
132
|
+
element.childNodes = [];
|
|
133
|
+
// node-html-parser doesn't support raw HTML children directly,
|
|
134
|
+
// so we set innerHTML which parses and inserts
|
|
135
|
+
element.innerHTML = `{% blocktrans %}${innerHtml}{% endblocktrans %}`;
|
|
136
|
+
injections.push({
|
|
137
|
+
file: filePath,
|
|
138
|
+
line,
|
|
139
|
+
column: 0,
|
|
140
|
+
original: innerHtml.trim(),
|
|
141
|
+
replacement: `{% blocktrans %}${innerHtml}{% endblocktrans %}`,
|
|
142
|
+
key,
|
|
143
|
+
confidence: 100,
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
// Pure text content: use {% trans "key" %}
|
|
148
|
+
const text = children
|
|
149
|
+
.map((c) => c.toString())
|
|
150
|
+
.join('')
|
|
151
|
+
.trim();
|
|
152
|
+
element.childNodes = [];
|
|
153
|
+
element.innerHTML = `{% trans "${key}" %}`;
|
|
154
|
+
injections.push({
|
|
155
|
+
file: filePath,
|
|
156
|
+
line,
|
|
157
|
+
column: 0,
|
|
158
|
+
original: text,
|
|
159
|
+
replacement: `{% trans "${key}" %}`,
|
|
160
|
+
key,
|
|
161
|
+
confidence: 100,
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
function convertDataI18nAttrTags(element, filePath, sourceContent, injections) {
|
|
166
|
+
const i18nAttrs = [
|
|
167
|
+
'data-i18n-title',
|
|
168
|
+
'data-i18n-placeholder',
|
|
169
|
+
'data-i18n-alt',
|
|
170
|
+
'data-i18n-aria-label',
|
|
171
|
+
'data-i18n-aria-description',
|
|
172
|
+
];
|
|
173
|
+
for (const dataAttr of i18nAttrs) {
|
|
174
|
+
const key = element.getAttribute(dataAttr);
|
|
175
|
+
if (!key)
|
|
176
|
+
continue;
|
|
177
|
+
// Extract the target attribute name: "data-i18n-placeholder" → "placeholder"
|
|
178
|
+
const attrSuffix = dataAttr.replace('data-i18n-', '');
|
|
179
|
+
const originalValue = element.getAttribute(attrSuffix) || '';
|
|
180
|
+
element.removeAttribute(dataAttr);
|
|
181
|
+
const line = element.range
|
|
182
|
+
? (sourceContent.slice(0, element.range[0]).match(/\n/g) || []).length + 1
|
|
183
|
+
: 0;
|
|
184
|
+
// Replace attribute value with {% trans "key" %}
|
|
185
|
+
element.setAttribute(attrSuffix, `{% trans "${key}" %}`);
|
|
186
|
+
injections.push({
|
|
187
|
+
file: filePath,
|
|
188
|
+
line,
|
|
189
|
+
column: 0,
|
|
190
|
+
original: originalValue,
|
|
191
|
+
replacement: `{% trans "${key}" %}`,
|
|
192
|
+
key,
|
|
193
|
+
confidence: 100,
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Ensure {% load i18n %} is present in the template.
|
|
199
|
+
* DTL requires it after any {% extends %} tag (at the top of the template
|
|
200
|
+
* but after extends).
|
|
201
|
+
*/
|
|
202
|
+
function ensureI18nLoad(content) {
|
|
203
|
+
if (/{%\s*load\s+i18n\s*%}/i.test(content)) {
|
|
204
|
+
return content;
|
|
205
|
+
}
|
|
206
|
+
// If there's an extends tag, insert load right after the last extends
|
|
207
|
+
const extendsMatch = content.match(/({%\s*extends\s+.*?%\})\s*\n?/s);
|
|
208
|
+
if (extendsMatch) {
|
|
209
|
+
const lastExtendsEnd = content.indexOf(extendsMatch[0]) + extendsMatch[0].length;
|
|
210
|
+
return (content.slice(0, lastExtendsEnd) +
|
|
211
|
+
'\n{% load i18n %}\n' +
|
|
212
|
+
content.slice(lastExtendsEnd));
|
|
213
|
+
}
|
|
214
|
+
// No extends: insert at the very top
|
|
215
|
+
return '{% load i18n %}\n' + content;
|
|
216
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { FileInjection } from '../../runtime/types';
|
|
2
|
+
interface HtmlInjectOptions {
|
|
3
|
+
content: string;
|
|
4
|
+
filePath: string;
|
|
5
|
+
keyMapping: Map<string, string>;
|
|
6
|
+
injectSwitcher?: boolean;
|
|
7
|
+
targetLocales?: string[];
|
|
8
|
+
sourceLocale?: string;
|
|
9
|
+
}
|
|
10
|
+
export declare function injectHtml(options: HtmlInjectOptions): Promise<FileInjection>;
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,173 @@
|
|
|
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.injectHtml = injectHtml;
|
|
37
|
+
const string_utils_1 = require("../../utils/string-utils");
|
|
38
|
+
const html_extractor_1 = require("../../utils/html-extractor");
|
|
39
|
+
function asElement(node) {
|
|
40
|
+
return node.nodeType === 1 ? node : null;
|
|
41
|
+
}
|
|
42
|
+
function walkHtmlNode(node, filePath, content, keyMapping, matchedIds, injections) {
|
|
43
|
+
const tagName = node.rawTagName?.toLowerCase();
|
|
44
|
+
if (!tagName)
|
|
45
|
+
return;
|
|
46
|
+
if (['script', 'style', 'noscript', 'code', 'pre', 'svg'].includes(tagName))
|
|
47
|
+
return;
|
|
48
|
+
const translatableAttrs = ['alt', 'title', 'placeholder', 'aria-label', 'aria-description'];
|
|
49
|
+
const children = node.childNodes || [];
|
|
50
|
+
let textChild = null;
|
|
51
|
+
let nonTextChild = false;
|
|
52
|
+
for (const child of children) {
|
|
53
|
+
if ((0, html_extractor_1.isTextNode)(child)) {
|
|
54
|
+
if (child.text.trim()) {
|
|
55
|
+
textChild = child;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
nonTextChild = true;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
const element = asElement(node);
|
|
63
|
+
if (textChild && !nonTextChild && element && !element.getAttribute('data-i18n')) {
|
|
64
|
+
const text = textChild.text.trim();
|
|
65
|
+
if (node.range) {
|
|
66
|
+
const line = (content.slice(0, node.range[0]).match(/\n/g) || []).length + 1;
|
|
67
|
+
const id = `${filePath}:${line}:${(0, string_utils_1.hashString)(text)}`;
|
|
68
|
+
if (matchedIds.has(id)) {
|
|
69
|
+
const key = keyMapping.get(id);
|
|
70
|
+
if (key) {
|
|
71
|
+
element.setAttribute('data-i18n', key);
|
|
72
|
+
injections.push({
|
|
73
|
+
file: filePath,
|
|
74
|
+
line,
|
|
75
|
+
column: 0,
|
|
76
|
+
original: text,
|
|
77
|
+
replacement: `data-i18n="${key}"`,
|
|
78
|
+
key,
|
|
79
|
+
confidence: 100,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
else if (nonTextChild && element && !element.getAttribute('data-i18n')) {
|
|
86
|
+
for (const child of children) {
|
|
87
|
+
if (!(0, html_extractor_1.isTextNode)(child) || !child.text.trim())
|
|
88
|
+
continue;
|
|
89
|
+
const text = child.text.trim();
|
|
90
|
+
if (node.range) {
|
|
91
|
+
const line = (content.slice(0, node.range[0]).match(/\n/g) || []).length + 1;
|
|
92
|
+
const id = `${filePath}:${line}:${(0, string_utils_1.hashString)(text)}`;
|
|
93
|
+
if (matchedIds.has(id)) {
|
|
94
|
+
const key = keyMapping.get(id);
|
|
95
|
+
if (key) {
|
|
96
|
+
element.setAttribute('data-i18n', key);
|
|
97
|
+
injections.push({
|
|
98
|
+
file: filePath,
|
|
99
|
+
line,
|
|
100
|
+
column: 0,
|
|
101
|
+
original: text,
|
|
102
|
+
replacement: `data-i18n="${key}"`,
|
|
103
|
+
key,
|
|
104
|
+
confidence: 100,
|
|
105
|
+
});
|
|
106
|
+
break;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
if (!element)
|
|
113
|
+
return;
|
|
114
|
+
for (const attr of translatableAttrs) {
|
|
115
|
+
const value = element.getAttribute(attr);
|
|
116
|
+
if (!value)
|
|
117
|
+
continue;
|
|
118
|
+
if (element.getAttribute(`data-i18n-${attr}`))
|
|
119
|
+
continue;
|
|
120
|
+
if (!node.range)
|
|
121
|
+
continue;
|
|
122
|
+
const line = (content.slice(0, node.range[0]).match(/\n/g) || []).length + 1;
|
|
123
|
+
const id = `${filePath}:${line}:${(0, string_utils_1.hashString)(value)}`;
|
|
124
|
+
if (matchedIds.has(id)) {
|
|
125
|
+
const key = keyMapping.get(id);
|
|
126
|
+
if (key) {
|
|
127
|
+
element.setAttribute(`data-i18n-${attr}`, key);
|
|
128
|
+
injections.push({
|
|
129
|
+
file: filePath,
|
|
130
|
+
line,
|
|
131
|
+
column: 0,
|
|
132
|
+
original: value,
|
|
133
|
+
replacement: `data-i18n-${attr}="${key}"`,
|
|
134
|
+
key,
|
|
135
|
+
confidence: 100,
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
for (const child of children) {
|
|
141
|
+
if (child.nodeType === 1) {
|
|
142
|
+
walkHtmlNode(child, filePath, content, keyMapping, matchedIds, injections);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
async function injectHtml(options) {
|
|
147
|
+
const { content, filePath, keyMapping } = options;
|
|
148
|
+
const { parse } = await Promise.resolve().then(() => __importStar(require('node-html-parser')));
|
|
149
|
+
const injections = [];
|
|
150
|
+
let importAdded = false;
|
|
151
|
+
const root = parse(content, {
|
|
152
|
+
comment: false,
|
|
153
|
+
blockTextElements: { script: true, style: true, noscript: true, pre: true },
|
|
154
|
+
});
|
|
155
|
+
const htmlEl = root.querySelector('html');
|
|
156
|
+
if (!htmlEl) {
|
|
157
|
+
return { file: filePath, originalContent: content, modifiedContent: content, injections, importAdded, hookAdded: false };
|
|
158
|
+
}
|
|
159
|
+
const matchedIds = new Set(keyMapping.keys());
|
|
160
|
+
walkHtmlNode(htmlEl, filePath, content, keyMapping, matchedIds, injections);
|
|
161
|
+
let modifiedContent = root.toString();
|
|
162
|
+
const hasScript = /<script[^>]*src\s*=\s*["']i18n\.js["'][^>]*>/.test(modifiedContent);
|
|
163
|
+
if (!hasScript) {
|
|
164
|
+
if (modifiedContent.includes('</body>')) {
|
|
165
|
+
modifiedContent = modifiedContent.replace('</body>', ' <script src="i18n.js"></script>\n</body>');
|
|
166
|
+
}
|
|
167
|
+
else {
|
|
168
|
+
modifiedContent = modifiedContent.replace('</head>', ' <script src="i18n.js"></script>\n</head>');
|
|
169
|
+
}
|
|
170
|
+
importAdded = true;
|
|
171
|
+
}
|
|
172
|
+
return { file: filePath, originalContent: content, modifiedContent, injections, importAdded, hookAdded: false };
|
|
173
|
+
}
|