import { a as LocaleDir, i as LocaleDefinition, n as defineI18nKitConfig, o as ProjectConfig, r as I18nConfig, s as LocaleFileFormat, t as I18nKitConfig } from "./define-config-BaZ1dZph.js"; //#region src/core/types.d.ts interface LocaleDirInfo { layer: string; path: string; aliasOf?: string; fileCount: number; topLevelKeys?: string[]; namespaces?: string[]; } interface MutationPreview { locale: string; key: string; value: string; } interface PlaceholderValidationIssue { locale: string; key: string; missing: string[]; extra: string[]; /** What failed: placeholder set mismatch (default) or vue-i18n plural * variant-count mismatch. Optional for backwards compatibility. */ kind?: 'placeholder' | 'plural-count'; /** Present for kind 'plural-count': variant counts of source and target. */ sourceVariants?: number; targetVariants?: number; } interface PlaceholderValidationResult { ok: boolean; placeholders: string[]; errors: PlaceholderValidationIssue[]; } interface LocaleRefInfo { code: string; language?: string; file?: string; name?: string; } /** * A locale ref in the request that matched no known locale. Its values were * not written; the keys still appear in `written` because other locales * succeeded, so this field is the only signal the write did less than asked. */ interface UnresolvedLocaleRef { ref: string; /** Keys whose value for this ref was dropped. */ keys: string[]; /** "Did you mean …?", when a near match exists. */ suggestion?: string; } interface MutationResult { applied: string[]; skipped: string[]; warnings: string[]; filesWritten: number; preview?: MutationPreview[]; placeholderValidation?: PlaceholderValidationResult; /** Present only when a ref resolved to nothing. */ unresolvedLocales?: UnresolvedLocaleRef[]; /** Present only when a ref matched several locales and precedence picked one. */ ambiguousLocales?: LocaleRefAmbiguity[]; } interface AddTranslationsResult { /** Present when dryRun=true */ dryRun?: boolean; wouldAdd?: MutationPreview[]; /** Present when dryRun=false */ added?: string[]; skipped: string[]; filesWritten?: number; warnings?: string[]; /** Present only when a locale ref resolved to nothing — see UnresolvedLocaleRef. */ unresolvedLocales?: UnresolvedLocaleRef[]; /** Present only when a locale ref matched several locales. */ ambiguousLocales?: LocaleRefAmbiguity[]; placeholderValidation?: PlaceholderValidationResult; summary?: { keysToAdd: number; keysSkipped: number; message: string; }; skippedKeys?: string[]; } interface WriteTranslationsResult { /** Present when dryRun=true */ dryRun?: boolean; wouldWrite?: MutationPreview[]; /** Present when dryRun=false */ written?: string[]; skipped: string[]; filesWritten?: number; warnings?: string[]; placeholderValidation?: PlaceholderValidationResult; /** Present only when a locale ref resolved to nothing — see UnresolvedLocaleRef. */ unresolvedLocales?: UnresolvedLocaleRef[]; /** Present only when a locale ref matched several locales. */ ambiguousLocales?: LocaleRefAmbiguity[]; summary?: { keysWritten: number; keysSkipped: number; message: string; }; skippedKeys?: string[]; } interface UpdateTranslationsResult { /** Present when dryRun=true */ dryRun?: boolean; wouldUpdate?: MutationPreview[]; /** Present when dryRun=false */ updated?: string[]; skipped: string[]; filesWritten?: number; /** Present only when a locale ref resolved to nothing — see UnresolvedLocaleRef. */ unresolvedLocales?: UnresolvedLocaleRef[]; /** Present only when a locale ref matched several locales. */ ambiguousLocales?: LocaleRefAmbiguity[]; placeholderValidation?: PlaceholderValidationResult; summary?: { keysToUpdate: number; keysSkipped: number; message: string; }; skippedKeys?: string[]; } /** * The config `init` emits. Only fields the matched adapter cannot derive: * writing a copy of what the framework already states creates a second source * of truth that drifts silently (#305). The generic path is the exception — * without localeDirs and defaultLocale nothing resolves at all. */ interface GeneratedProjectConfig { $schema: string; context: string; glossary: Record; translationPrompt: string; localeNotes: Record; /** Matches localeDirEntrySchema: a bare path, or a path bound to a layer. */ localeDirs?: Array; defaultLocale?: string; locales?: string[]; } interface InitProjectConfigResult { config: GeneratedProjectConfig; detected: { adapter: string; label: string; /** Detection score. 0 when nothing matched and generic was assumed. */ confidence: number; /** * Whether the matched adapter resolves locales, layers and the default * locale from framework config. False only for the generic adapter, which * cannot resolve without them written into `.i18n-mcp.json`. Independent * of whether this run carried locale settings forward from an existing * file under `--force`. */ derivesLocaleConfig: boolean; /** Other adapters that also scored, best first. */ runnersUp?: Array<{ name: string; confidence: number; }>; /** Present when init could not find anything to point the config at. */ note?: string; }; /** Path relative to the project dir. */ configPath: string; written: boolean; overwritten: boolean; } interface MissingTranslationsResult { /** Absent when the full report went to `reportFile` instead. */ missing?: Record>; summary: { referenceLocale: string | LocaleRefInfo; targetLocales: Array; layersScanned: string[]; totalMissingKeys: number; }; /** Present when reportOutput is configured */ reportFile?: string; } interface LocaleStatus extends LocaleRefInfo { total: number; translated: number; missing: number; /** Present but empty-string — scaffolded and never filled. */ empty: number; completion: number; /** Listed in protectedLocales: maintained by hand. */ protected?: true; /** Protected locales are reported but kept out of the overall figure. */ excludedFromOverall?: true; } interface LayerStatus { layer: string; total: number; translated: number; missing: number; empty: number; completion: number; } interface TranslationStatusSummary { referenceLocale: LocaleRefInfo; layersScanned: string[]; localesChecked: number; protectedLocales: string[]; totalKeys: number; translatedKeys: number; missingKeys: number; emptyKeys: number; /** Overall completion, protected locales excluded. Read by --fail-under. */ completionPercent: number; } interface TranslationStatusResult { locales?: LocaleStatus[]; layers?: LayerStatus[]; summary: TranslationStatusSummary; /** Present when the full breakdown went to a file instead. */ reportFile?: string; } interface EmptyTranslationsResult { /** Absent when the full report went to `reportFile` instead. */ emptyKeys?: Record>; summary: { totalEmpty: number; localesChecked: string[]; layersChecked: string[]; }; /** Present when reportOutput is configured */ reportFile?: string; } interface SearchMatch { layer: string; locale: string; key: string; value: unknown; } interface SearchTranslationsResult { matches: SearchMatch[]; totalMatches: number; } interface RemoveTranslationsPreview { locale: string; key: string; oldValue: unknown; } interface RemoveTranslationsResult { /** Present when dryRun=true */ dryRun?: boolean; wouldRemove?: RemoveTranslationsPreview[]; /** Present when dryRun=false */ removed?: string[]; removedPerLocale?: string[]; notFound?: string[]; filesWritten?: number; summary?: { keysFound: number; message: string; }; } interface RenameTranslationKeyPreview { locale: string; oldKey: string; newKey: string; value: unknown; } interface RenameTranslationKeyResult { /** Present when dryRun=true */ dryRun?: boolean; wouldRename?: RenameTranslationKeyPreview[]; /** Present when dryRun=false */ renamed?: string[]; filesWritten?: number; oldKey?: string; newKey?: string; notFoundInLocales?: string[]; conflictsInLocales?: string[]; skippedDueToConflict?: string[]; summary?: { localesAffected: number; message: string; warning?: string; }; } /** What a move does to one locale's copy of the key. */ interface MoveTranslationKeyPlanEntry { locale: string; value: unknown; /** * `move` writes the target and drops the source. `deduplicate` finds the * target already holding the same value, so only the source is dropped. */ action: 'move' | 'deduplicate'; } interface MoveTranslationKeyResult { /** Present when dryRun=true */ dryRun?: boolean; wouldMove?: MoveTranslationKeyPlanEntry[]; /** Present when dryRun=false */ movedLocales?: string[]; /** Locales where the target already held this value, so only the source was dropped. */ deduplicatedLocales?: string[]; filesWritten?: number; fromLayer?: string; toLayer?: string; key?: string; newKey?: string; /** Locales whose source layer does not define the key at all. */ notFoundInLocales?: string[]; /** Locales where the target holds a different value. Nothing is written when this is non-empty. */ conflictsInLocales?: string[]; summary?: { localesAffected: number; message: string; warning?: string; }; } /** How a translate run was (or would be) executed. */ type TranslateMode = 'provider' | 'agent' | 'dry-run'; /** Why a key could not be translated. */ type TranslateFailReason = 'provider-error' | 'omitted-by-model' | 'placeholder-mismatch' | 'plural-mismatch' | 'write-error' | 'truncated'; /** Why a key or locale was intentionally not attempted. */ type TranslateSkipReason = 'no-provider' | 'already-translated' | 'protected-locale'; interface TranslateMissingLocaleResult { mode: TranslateMode; /** Number of missing keys found for this locale. Always equals * translated + wouldTranslate + failed + skipped. */ missing: number; translated: string[]; /** Dry-run only: keys that would be translated. */ wouldTranslate?: string[]; failed: Array<{ key: string; reason: TranslateFailReason; }>; skipped: Array<{ key: string; reason: TranslateSkipReason; }>; batches?: number; model?: string; writeError?: string; placeholderValidation?: PlaceholderValidationResult; } /** One locale's digest in compact mode: counts rather than key lists. */ interface TranslateMissingCompactEntry { locale: string; mode: TranslateMode; missing: number; translated: number; failed: number; skipped: number; wouldTranslate?: number; batches?: number; model?: string; writeError?: string; } interface TranslateMissingResult { /** Absent in compact mode, which returns `summary.byLocale` instead. */ results?: Record; fallbackContexts?: Record>; summary: { /** Compact mode only: a per-locale digest in place of full `results`. */ byLocale?: TranslateMissingCompactEntry[]; mode: TranslateMode; totalTranslated: number; totalFailed: number; totalSkipped: number; totalWouldTranslate?: number; layer: string; referenceLocale: string | LocaleRefInfo; targetLocales: Array; dryRun: boolean; /** Surface-owned guidance (set by the CLI command or MCP tool, not the core). */ message?: string; }; } /** * Per-layer totals in the all-layers translate summary (`summary.byLayer`). * Field names mirror the cross-layer summary totals so consumers parse both * with the same accessors. `totalWouldTranslate` is always present (0 outside * dry runs). */ /** Aggregated summary across every locale-backed layer. */ interface TranslateAllLayersSummary { mode: TranslateMode; totalTranslated: number; totalFailed: number; totalSkipped: number; totalWouldTranslate?: number; /** Layer names that were translated. */ layers: string[]; byLayer: TranslateLayerTotals[]; dryRun: boolean; referenceLocale?: string | LocaleRefInfo; targetLocales?: Array; /** Surface-owned guidance (set by the CLI command or MCP tool). */ message?: string; } /** * All-layers mode (`--layer` omitted): one result per layer plus an aggregated * summary. Discriminate with `'layers' in result` — both members carry a * `summary`, and both summaries carry `mode`, so mode checks need no narrowing. */ interface TranslateAllLayersResult { layers: Record; summary: TranslateAllLayersSummary; } /** What translateMissing returns: depends on whether a layer was named. */ type TranslateMissingOutcome = TranslateMissingResult | TranslateAllLayersResult; interface TranslateLayerTotals { layer: string; totalTranslated: number; totalFailed: number; totalSkipped: number; totalWouldTranslate: number; } interface TranslateKeyLocaleIssue { locale: string; reason: TranslateFailReason | 'read-error'; detail?: string; } interface TranslateKeyResult { key: string; sourceLocale: LocaleRefInfo; updatedSource: boolean; mode: TranslateMode; translated: string[]; /** Dry-run only: locales that would be translated. */ wouldTranslate?: string[]; skipped: Array<{ locale: string; reason: TranslateSkipReason; }>; failed: TranslateKeyLocaleIssue[]; filesWritten: number; dryRun: boolean; model?: string; placeholderValidation: PlaceholderValidationResult; preview?: Record; fallbackContext?: Record; /** Surface-owned guidance (set by the CLI command or MCP tool, not the core). */ message?: string; } /** A key referenced only from apps outside its layer's consumption scope. */ interface MisplacedUsageRef { key: string; /** Layer the key is defined in. */ layer: string; /** Out-of-scope scan units (apps or layers) where the key was found. */ usingApps: string[]; } interface DynamicKeyRef { expression: string; /** Absent for context-free bare candidates, which have no single call site. */ file?: string; line?: number; } interface UnresolvedKeyWarningRef { expression: string; file: string; line: number; callee: string; suggestedIgnorePattern?: string; } interface FindOrphanKeysResult { /** Absent when the full report went to `reportFile` instead. */ orphanKeys?: Record; uncertainKeys?: Record; /** * Keys kept alive solely by the bare-candidate net — nothing a frontend * could call a usage references them; a dotted string somewhere (a comment, * a data structure) merely shares their name. Not orphans, but where dead * references hide. */ candidateOnlyKeys?: Record; candidateOnlyNote?: string; /** Keys used only from apps that do not consume the owning layer. */ misplacedUsages?: MisplacedUsageRef[]; misplacedUsageNote?: string; summary: { totalKeys: number; orphanCount: number; uncertainCount?: number; candidateOnlyCount?: number; misplacedCount?: number; dynamicMatchedCount?: number; ignoredCount?: number; usedCount?: number; filesScanned: number; /** Files a syntax frontend declined; pattern matching read them instead. */ filesDeclined?: number; layersChecked?: string[]; dirsScanned?: string[]; scanScope?: Record; locale?: string; message?: string; }; dynamicKeyWarning?: string; dynamicKeys?: DynamicKeyRef[]; unresolvedKeyWarnings?: UnresolvedKeyWarningRef[]; /** Present when reportOutput is configured */ reportFile?: string; } /** Where each requested key is referenced in source. */ interface CodeUsageResult { /** Absent when the full report went to `reportFile` instead. */ usages?: Record; /** Requested keys with no reference anywhere in the scanned source. */ notFoundInCode?: string[]; /** Dynamic expressions that could reach the requested keys. */ dynamicKeys?: DynamicKeyRef[]; summary: { uniqueKeysFound: number; totalReferences: number; filesScanned: number; /** Files a syntax frontend declined; pattern matching read them instead. */ filesDeclined?: number; dirsScanned?: string[]; message?: string; }; /** Present when the full report went to a file instead. */ reportFile?: string; } interface CodeUsageRef { file: string; line: number; callee: string; } interface ScanCodeUsageResult { usages: Record; summary: { uniqueKeysFound: number; totalReferences: number; filesScanned: number; /** Files a syntax frontend declined; pattern matching read them instead. */ filesDeclined?: number; dirsScanned: string[]; }; notFoundInCode?: string[]; dynamicKeys?: DynamicKeyRef[]; /** Present when reportOutput is configured */ reportFile?: string; } interface RemoveOrphanKeysResult { orphanKeys?: Record; removed?: Record; uncertainKeys?: Record; misplacedUsages?: MisplacedUsageRef[]; misplacedUsageNote?: string; summary: { dryRun?: boolean; totalKeys: number; orphanCount?: number; removedCount?: number; uncertainCount?: number; misplacedCount?: number; dynamicMatchedCount?: number; ignoredCount?: number; usedCount?: number; remainingCount?: number; filesScanned?: number; filesWritten?: number; layersChecked?: string[]; dirsScanned?: string[]; scanScope?: Record; locale?: string; message?: string; }; dynamicKeyWarning?: string; dynamicKeys?: DynamicKeyRef[]; unresolvedKeyWarnings?: UnresolvedKeyWarningRef[]; /** Present when reportOutput is configured */ reportFile?: string; } interface ScaffoldLocaleFileInfo { locale: string; layer: string; file: string; keys: number; namespace?: string; } interface ScaffoldLocaleResult { created: ScaffoldLocaleFileInfo[]; skipped: ScaffoldLocaleFileInfo[]; dryRun: boolean; } interface TranslateRequest { systemPrompt: string; userMessage: string; maxTokens: number; } interface TranslateResponse { text: string; model: string; /** True when the provider stopped early (finish/stop reason = token limit). * The response text is incomplete and must not be parsed as a full batch. */ truncated?: boolean; } type TranslateFn = (opts: TranslateRequest) => Promise; type ProgressFn = (message: string) => Promise; //# sourceMappingURL=types.d.ts.map //#endregion //#region src/core/shared.d.ts /** Fields a locale ref may match, in resolution precedence order. */ declare const LOCALE_MATCH_FIELDS: readonly ["code", "language", "file"]; type LocaleMatchField = (typeof LOCALE_MATCH_FIELDS)[number]; interface LocaleRefAmbiguity { ref: string; /** The field that matched more than one locale. */ matchedBy: LocaleMatchField; /** Codes of every locale the ref matched, in config order. */ candidates: string[]; /** The one that was used — the first candidate. */ resolvedTo: string; } declare function findLocaleImpl(config: I18nConfig, localeRef: string): LocaleDefinition | undefined; /** * Resolve the reference locale for scan operations: the requested ref or the * project default. Throws LOCALE_NOT_FOUND listing the available codes. */ //#endregion //#region src/core/ops-translate.d.ts /** * Resolve the config's `protectedLocales` entries (any locale ref: code, * language tag, or file name) against the known locales. Entries that do not * match a known locale are ignored with a warning. Returns the resolved * definitions, deduplicated by canonical code. */ declare function resolveProtectedLocales(config: I18nConfig): LocaleDefinition[]; /** * Find keys missing in target locales and translate them. * * When translateFn is provided, uses it to translate via LLM. * When translateFn is absent, returns fallback contexts for the agent. * * When `layer` is omitted, every canonical locale-backed layer is translated * in one run and the results are aggregated (see translateMissingAllLayers). */ declare function translateMissing(opts: { layer?: string; referenceLocale?: string; targetLocales?: string[]; locales?: string[]; keys?: string[]; batchSize?: number; dryRun?: boolean; compact?: boolean; projectDir?: string; translateFn?: TranslateFn; progressFn?: ProgressFn; /** Called once after the pre-scan with the computed total number of progress steps. */ onProgressTotal?: (total: number) => void; }): Promise; /** * Translate one key from a source locale into target locales. Unlike * translate_missing, this can overwrite stale existing target values. */ declare function translateKey(opts: { layer: string; key: string; sourceLocale: string; sourceValue?: string; targetLocales?: string[] | 'all'; overwrite?: boolean; dryRun?: boolean; includePreview?: boolean; projectDir?: string; translateFn?: TranslateFn; }): Promise; //# sourceMappingURL=ops-translate.d.ts.map //#endregion //#region src/core/ops-read.d.ts /** * Detect the i18n configuration from the project, always bypassing the * config cache (clears it first). */ declare function detectConfig(projectDir?: string): Promise; /** * List all i18n locale directories in the project, grouped by layer. */ declare function listLocaleDirs(projectDir?: string): Promise; /** * Get translation values for given key paths from a specific locale and layer. */ declare function getTranslations(opts: { layer: string; locale: string; keys: string[]; compact?: boolean; projectDir?: string; }): Promise>>; /** * Find translation keys that exist in the reference locale but are missing in other locales. */ declare function getMissingTranslations(opts: { layer?: string; referenceLocale?: string; targetLocales?: string[]; locales?: string[]; projectDir?: string; outputFile?: string; }): Promise; /** * Find translation keys that have empty string values in locale files. */ declare function findEmptyTranslations(opts: { layer?: string; locale?: string; projectDir?: string; outputFile?: string; }): Promise; /** * Search translation files by key pattern or value substring. */ declare function searchTranslations(opts: { query: string; searchIn?: 'keys' | 'values' | 'both'; layer?: string; locale?: string; projectDir?: string; outputFile?: string; }): Promise<{ matches: SearchMatch[]; totalMatches: number; } | { reportFile: string; summary: { totalMatches: number; }; }>; interface NamespaceNode { keyCount: number; children?: Record; } interface ListNamespacesResult { layers: Record; }>; } /** * Build a prefix tree of all translation keys grouped by layer and namespace. * Useful for agents to browse available keys without guesswork. */ declare function listNamespaces(opts: { layer?: string; locale?: string; projectDir?: string; }): Promise; //# sourceMappingURL=ops-read.d.ts.map //#endregion //#region src/core/ops-write.d.ts /** * Write translation keys to the specified layer with mode control. * * Mode: * - 'upsert' (default): Adds new keys and updates existing ones. Never skips. * - 'add': Only creates new keys, skipping existing ones. * - 'update': Only modifies existing keys, skipping missing ones. */ declare function writeTranslations(opts: { layer: string; translations: Record>; mode?: 'add' | 'update' | 'upsert'; dryRun?: boolean; projectDir?: string; }): Promise; /** * Add new translation keys to the specified layer. * * @deprecated Use writeTranslations with mode: 'add' instead. */ declare function addTranslations(opts: { layer: string; translations: Record>; dryRun?: boolean; projectDir?: string; }): Promise; /** * Update existing translation keys in the specified layer. * * @deprecated Use writeTranslations with mode: 'update' instead. */ declare function updateTranslations(opts: { layer: string; translations: Record>; dryRun?: boolean; projectDir?: string; }): Promise; /** * Remove one or more translation keys from ALL locale files in the specified layer. */ declare function removeTranslations(opts: { layer: string; keys: string[]; dryRun?: boolean; projectDir?: string; }): Promise; /** * Rename/move a translation key across ALL locale files in a layer. */ declare function renameTranslationKey(opts: { layer: string; oldKey: string; newKey: string; dryRun?: boolean; projectDir?: string; }): Promise; /** * Create empty locale files for new languages. */ declare function scaffoldLocaleFiles(opts: { locales?: string[]; layer?: string; dryRun?: boolean; projectDir?: string; }): Promise; /** * Move a key from one layer to another, carrying every locale that defines it. * * Promoting an app-layer key to the shared layer once a second app needs it is * a first-class operation in a layered monorepo, and composing it out of * get/write/remove is three calls across up to thirty locales with no way to * fail cleanly: a truncation between the write and the remove leaves the key in * both layers, which is the state `find_duplicate_keys` exists to flag (#341). * * So the whole move is planned before anything is written. A target that * already holds a *different* value is a conflict, and one conflict in one * locale writes nothing at all — a half-moved key across thirty files is worse * than a refusal. A target already holding the *same* value is not a conflict * but a duplicate the move resolves: the source copy is dropped and the locale * is reported as deduplicated. * * Locales come from the resolved config rather than from caller-supplied refs, * so there is no ref to leave unresolved (#301) — a locale the source layer * does not define is reported in `notFoundInLocales` rather than skipped * silently. */ declare function moveTranslationKey(opts: { fromLayer: string; toLayer: string; key: string; newKey?: string; dryRun?: boolean; projectDir?: string; }): Promise; //# sourceMappingURL=ops-write.d.ts.map //#endregion //#region src/core/ops-status.d.ts /** * Coverage for a project: per locale, per layer, and one overall figure. * * Protected locales are counted and reported but excluded from the overall * percentage — they are maintained by hand, so counting their gaps as project * debt makes a healthy project read as failing and moves a number nobody can * act on. */ declare function getTranslationStatus(opts: { layer?: string; referenceLocale?: string; projectDir?: string; outputFile?: string; }): Promise; //# sourceMappingURL=ops-status.d.ts.map //#endregion //#region src/scanner/frontends/types.d.ts /** * What a frontend saw at one call site, before anything decides what it means. * * Frontends read their own language with whatever parser suits it and report * call sites in these terms. The rules that turn them into usages, dynamic * keys and candidates live in one place above this, so adding a language never * means restating what counts as a translation (#332). */ interface CallSite { /** The callee as written — `t`, `$t`, `__`, `trans_choice`. */ callee: string; /** * Whether the frontend could prove this callee is the i18n function. * * `resolved` means it followed the identifier to an import from an i18n * package or a destructure of `useI18n()`. `ambiguous` means it recognised * the shape but cannot say what the name is bound to — all a regex can ever * report, and the reason the dot heuristic exists at all. */ binding: 'resolved' | 'ambiguous'; argument: CallArgument; line: number; } type CallArgument = /** A literal: `t('common.save')`. */ { kind: 'static'; value: string; } /** An interpolated template, already normalised to `${_}` slots. */ | { kind: 'template'; expression: string; } /** A literal prefix joined to something else: `t('common.' + name)`. */ | { kind: 'concat'; prefix: string; } /** Something the frontend could not read — a variable, a call, a ternary. */ | { kind: 'unknown'; }; /** Everything one file yields. Unchanged from what the scanner already consumes. */ interface FileEvidence { usages: KeyUsage[]; dynamicKeys: DynamicKeyUsage[]; bareStringCandidates: Set; } interface LanguageFrontend { /** For diagnostics and for the differential harness. */ readonly name: string; /** Whether this frontend reads that file. */ handles(filePath: string): boolean; /** * Read a file into call sites, or return null to decline it — a syntax the * parser cannot handle, a missing optional dependency. Declining is not an * error: the caller falls back to the frontend that always works. */ read(content: string, filePath: string): Promise; } //# sourceMappingURL=types.d.ts.map //#endregion //#region src/scanner/frontends/php/patterns.d.ts declare const LARAVEL_PATTERNS: ScanPatternSet; //#endregion //#region src/scanner/patterns.d.ts interface ScanPatternSet { label: string; filePatterns: string[]; ignoreDirs: string[]; /** Must capture: (1) callee, (2) quote char, (3) key */ staticKeyPatterns: RegExp[]; /** Must capture: (1) callee, (2) template content */ dynamicKeyPatterns: RegExp[]; /** Must capture: (1) callee, (2) quote char, (3) prefix */ concatKeyPatterns: RegExp[]; /** * Language family for the context-free bare-candidate collectors (#288). * 'js' (default) runs the template-literal and `+`-concat shapes; 'php' * runs the double-quoted `{$var}` interpolation shape instead. Ungated, * the PHP shape matches Vue template attributes (`v-if="$slots.header"`), * producing `${_}.header`-class candidates that suppress every key ending * in those segments. Language-neutral shapes (dotted literals, * trailing-dot prefixes) always run. */ bareShapes?: 'js' | 'php'; } declare const VUE_NUXT_PATTERNS: ScanPatternSet; /** * Maps locale file format to the appropriate scan pattern set. * 'php-array' → Laravel (PHP translation helpers in Blade/PHP files). * 'json' / undefined → Vue/Nuxt ($t / t calls in Vue/TS/JS files). */ declare function getPatternSet(format?: LocaleFileFormat): ScanPatternSet; //# sourceMappingURL=patterns.d.ts.map //#endregion //#region src/scanner/code-scanner.d.ts interface KeyUsage { key: string; file: string; line: number; callee: string; } interface DynamicKeyUsage { expression: string; file: string; line: number; callee: string; } interface ScanResult { usages: KeyUsage[]; dynamicKeys: DynamicKeyUsage[]; filesScanned: number; /** * Files an active syntax frontend handled but declined — unparseable, or a * parser that would not load — so pattern matching read them instead. A * broken parser install shows up here rather than as silently weaker scans. */ declinedFiles: string[]; uniqueKeys: Set; /** * All quoted strings containing at least one dot, extracted from source files. * These are NOT confirmed i18n keys — they must be intersected with actual * locale keys to identify bare key references (e.g., `{ name: 'common.actions.save', i18n: true }`). */ bareStringCandidates: Set; /** * Template literal expressions containing at least one dot and `${...}` interpolation, * extracted from source files regardless of i18n call context. * Format: `` `prefix.${_}.suffix` `` — ready to feed into `buildDynamicKeyRegexes`. */ bareDynamicCandidates: Set; } /** * One file's evidence through the pattern frontend — the sync contract the * scanner suites are written against. Same pipeline as every scan: the * frontend reports call sites, the rules decide what they mean. */ declare function scanSourceFiles(rootDir: string, excludeDirs?: string[], patterns?: ScanPatternSet, frontends?: LanguageFrontend[]): Promise; //#endregion //#region src/core/ops-orphans.d.ts /** * Find translation keys that exist in locale files but are not referenced in source code. */ declare function findOrphanKeys(opts: { layer?: string; locale?: string; /** * Explicit scan roots — manual scope control. When set, all layers are * checked against one combined usage set from these dirs (no per-layer * scoping, no misplaced-usage detection). When absent, a scope-aware plan * from the layer graph is used: each layer is checked against the apps * that consume it. */ scanDirs?: string[]; excludeDirs?: string[]; projectDir?: string; outputFile?: string; }): Promise; /** * Scan Vue/TS source files to find where translation keys are referenced. */ declare function scanCodeUsage(opts: { keys?: string[]; scanDirs?: string[]; excludeDirs?: string[]; projectDir?: string; outputFile?: string; }): Promise; /** * Find translation keys not referenced in source code and remove them. */ declare function removeOrphanKeys(opts: { layer?: string; locale?: string; /** Explicit scan roots — manual scope control, same semantics as {@link findOrphanKeys}. */ scanDirs?: string[]; excludeDirs?: string[]; dryRun?: boolean; projectDir?: string; outputFile?: string; /** Also write the orphan findings as a GitLab Code Quality JSON array to this path. */ codequalityOutput?: string; }): Promise; //# sourceMappingURL=ops-orphans.d.ts.map //#endregion //#region src/core/ops-duplicates.d.ts /** * Cross-layer duplicate-key detection: keys defined in both a shared layer * and a consuming child layer, compared in one reference locale. */ interface DuplicateKeyCollision { key: string; sharedLayer: string; childLayer: string; sharedValue: unknown; childValue: unknown; divergent: boolean; } /** One key carrying a duplicated value, with the layer it lives in. */ interface ValueDuplicateMember { key: string; layer: string; /** * True when this layer is one another layer falls through to at runtime, so * a key here is already reachable from the layers above it. */ shared: boolean; } /** * What to do about a group, and therefore how it sorts. `reuse` first: the * shared key already exists, so the fix costs nothing but deletions. */ type ValueDuplicateAction = 'reuse' | 'promote' | 'consolidate'; interface ValueDuplicateGroup { /** The value as written, from the first member. */ value: string; /** What the members were grouped by — trimmed, case-folded, punctuation-stripped. */ normalized: string; action: ValueDuplicateAction; members: ValueDuplicateMember[]; } interface FindDuplicateKeysSummary { totalCollisions: number; divergentCount: number; pairsChecked: number; locale: string; /** Present when value duplicates were requested. */ valueGroups?: number; reusableGroups?: number; message?: string; } interface FindDuplicateKeysResult { collisions: DuplicateKeyCollision[]; /** Present when value duplicates were requested. */ valueDuplicates?: ValueDuplicateGroup[]; guidance: string; summary: FindDuplicateKeysSummary; } /** * Find keys defined in both a shared layer and a consuming child layer, * comparing values in a single reference locale (default: the project * default locale). Pure locale-file I/O — no source scanning. */ declare function findDuplicateKeys(opts?: { locale?: string; projectDir?: string; outputFile?: string; /** * Also group keys by the value they carry. Off by default: it reads every * canonical layer rather than only the paired ones, and the existing result * shape stays exactly as it was for callers that do not ask. */ byValue?: boolean; /** Shortest value worth grouping. Below it, repetition is usually legitimate. */ minValueLength?: number; }): Promise; //# sourceMappingURL=ops-duplicates.d.ts.map //#endregion //#region src/core/ops-check.d.ts /** * Used-but-undefined key detection — the inverse of orphan scanning. * * A key referenced in source code but defined in no locale file of the * using app's consumed layers renders as a raw key at runtime. Nothing * else catches this direction (orphan scanning only computes * locale − code; this computes code − locale, per scan unit). */ interface KeyUsageLocation { /** Source file path, relative to the project dir. */ file: string; line: number; } interface UndefinedKeyFinding { key: string; /** Scan unit the usage lives in (app name, layer name, or project-root). */ app: string; /** Layers whose keys this unit can resolve — all were searched. */ searchedLayers: string[]; usages: KeyUsageLocation[]; } interface UncertainKeyFinding extends UndefinedKeyFinding { /** Why this is not a hard finding. */ reason: string; } interface CheckUndefinedKeysSummary { /** Distinct statically referenced keys across all scan units. */ usedKeysChecked: number; undefinedCount: number; uncertainCount: number; /** Unresolvable keys excluded by orphanScan ignorePatterns. */ ignoredCount: number; filesScanned: number; /** Files a syntax frontend declined; pattern matching read them instead. */ filesDeclined: number; locale: string; /** Scan unit → layers searched for that unit's key usages. */ searchedLayersByApp: Record; message: string; } interface CheckUndefinedKeysResult { undefinedKeys: UndefinedKeyFinding[]; uncertainKeys: UncertainKeyFinding[]; limitation: string; summary: CheckUndefinedKeysSummary; } /** * Find keys referenced in source code that resolve to no definition in the * using app's consumed layers (reference locale, default: project default). * * Mirrors the orphan scan's per-unit structure: with no explicit scanDirs, * the scope-aware plan from the layer graph decides which layers each scan * unit's code can resolve (the inversion of the orphan scan's * scopeByLayer — a unit resolves exactly the layers it vouches for). The * graph's degenerate semantics carry over: with no app info every layer is * resolvable everywhere, so only keys defined in NO layer are flagged. */ declare function checkUndefinedKeys(opts?: { locale?: string; /** * Explicit scan roots — manual scope control. Every layer is treated as * resolvable from every scanned dir (global behavior, no per-app scoping). */ scanDirs?: string[]; excludeDirs?: string[]; projectDir?: string; outputFile?: string; /** Also write the findings as a GitLab Code Quality JSON array to this path. */ codequalityOutput?: string; }): Promise; //# sourceMappingURL=ops-check.d.ts.map //#endregion //#region src/config/detector.d.ts declare function detectI18nConfig(projectDir: string): Promise; declare function clearConfigCache(): void; declare function getCachedConfig(): I18nConfig | null; //# sourceMappingURL=detector.d.ts.map //#endregion //#region src/config/layer-graph.d.ts /** * Queryable view over the layer topology a resolved {@link I18nConfig} * already carries: which locale dirs are canonical (alias-free), which * layer owns an aliased dir, and which apps consume which layers. * * This is a pure derivation — no filesystem access, no config-shape * changes. Cross-layer tooling (duplicate detection, scope-aware orphan * scanning) builds on these queries instead of name-matching heuristics. * * ## Degenerate-case semantics * * These are load-bearing for consumers (scope-aware scanning must never * wrongly narrow its scan scope): * * - **No app info** (`config.apps` empty or absent, e.g. hand-built * configs): consumption edges are unknowable. `appsUsingLayer` and * `layersOfApp` return `[]`, and `sharedLayers` conservatively contains * *every* canonical layer — with no ownership information, every * layer's keys must be treated as globally visible. * - **Single-app config** (generic/Laravel/Vue/React adapters, or a Nuxt * project with one app): the strict definition applies, so * `sharedLayers` is empty (no layer is consumed by more than one app) * and `appsUsingLayer` returns that one app for the layers it consumes. * Per-layer scope then equals the whole project, which is correct. * - **Canonical layer consumed by no app** (in a multi-app config): * `appsUsingLayer` returns `[]` and the layer is not in `sharedLayers`. * Callers should treat such layers conservatively (global scope). */ interface LayerGraph { /** * Alias-free locale dirs, in `config.localeDirs` order. Aliased entries * (e.g. `app-outlook` pointing at `app-shop`'s dir) are excluded. */ canonicalLayers: LocaleDir[]; /** * Resolve a layer name to the canonical layer that owns its locale dir. * Follows chained `aliasOf` links (an alias may point at a layer that * was itself demoted to an alias). Identity for canonical names and for * names unknown to `localeDirs` (e.g. layers without locale dirs). */ ownerOf: (layer: string) => string; /** * Names of apps whose consumed layers include the given layer. The * queried name and each app's layer list are alias-resolved via * {@link ownerOf} first, so querying an alias name yields the owner's * consumers. Returns `[]` when no app info exists. */ appsUsingLayer: (layer: string) => string[]; /** * Canonical layers consumed by more than one app — e.g. a shared root * layer in a multi-app monorepo, identified purely from consumption * edges (no name matching). When no app info exists, contains every * canonical layer (see degenerate-case semantics above). */ sharedLayers: LocaleDir[]; /** * Canonical layers the given app consumes (alias entries in the app's * layer list resolve to their owners; layers without locale dirs are * omitted). Returns `[]` for unknown apps or when no app info exists. */ layersOfApp: (app: string) => LocaleDir[]; } /** * Build a {@link LayerGraph} from a resolved config's `localeDirs` * (with their `aliasOf` markers) and `apps` (app → consumed-layers edges). */ declare function buildLayerGraph(config: I18nConfig): LayerGraph; /** * The graph as plain data, for surfaces that can only carry JSON. * * {@link LayerGraph} is function-valued, so it cannot be serialised directly. * This answers the question an agent actually has — *which layer does this key * belong in* — which the flat layer list `discover` returned could not: a key * used by more than one app belongs in a layer those apps share, and `shared` * names those layers outright (#342). * * The degenerate cases documented on {@link LayerGraph} survive the flattening, * because they are what keeps a consumer from wrongly narrowing scope: * a config with no app info reports *every* canonical layer as shared, and a * layer no app consumes appears in `consumers` with an empty array rather than * being left out. Absent and "none" must not look alike here. */ interface SerializedLayerGraph { /** Alias-free layer names, in `config.localeDirs` order. */ canonical: string[]; /** Canonical layers consumed by more than one app — where shared keys belong. */ shared: string[]; /** Alias layer name → the canonical layer whose locale dir it points at. */ aliases: Record; /** Canonical layer name → the apps consuming it. Every canonical layer is a key. */ consumers: Record; } /** Flatten {@link buildLayerGraph}'s view of `config` into plain JSON. */ declare function serializeLayerGraph(config: I18nConfig): SerializedLayerGraph; //# sourceMappingURL=layer-graph.d.ts.map //#endregion //#region src/scanner/frontends/oxc.d.ts declare function createOxcFrontend(): LanguageFrontend; //# sourceMappingURL=oxc.d.ts.map //#endregion //#region src/scanner/frontends/patterns.d.ts /** * The regex path as a language frontend (#332). * * Regexes frame text and report call sites; what a site means is decided once, * in the rules, the same as for every other frontend. Binding is always * `ambiguous`, because a regex can never prove what a name is bound to — which * is the entire reason the syntax frontends exist. * * This frontend never declines: it is the floor every scan can fall back to. */ declare function createPatternsFrontend(pat: ScanPatternSet): LanguageFrontend; /** * Synchronous core, so the sync `extractKeys` contract the scanner suites are * written against keeps working unchanged. */ //#endregion //#region src/scanner/frontends/php/index.d.ts declare function createPhpFrontend(): LanguageFrontend; /** * Call sites in a parsed program. Shared with the Blade frontend, which parses * lifted expressions through the same engine and interprets them identically — * a key's fate must not depend on which file type referenced it (#332). */ //#endregion //#region src/scanner/frontends/php/blade.d.ts /** * Blade, by lifting (#404, #332). * * No maintained Blade AST parser exists, and none is needed: every construct * that can carry a translation key wraps a PHP expression. The lexical pass * here finds those wrappers — echoes, `@lang`/`@choice`, `@php` blocks, raw * PHP tags — and hands the expression inside to the same parser and the same * site collection plain PHP uses. The regex frames text; it never decides * what a key is. * * A lifted chunk the parser cannot read declines the whole file to the * pattern fallback: partially-read templates would silently drop keys. */ declare function createBladeFrontend(): LanguageFrontend; //# sourceMappingURL=blade.d.ts.map //#endregion //#region src/io/locale-data.d.ts declare function readLocaleData(config: I18nConfig, layer: string, locale: LocaleDefinition): Promise>; /** * Read, mutate, and write back locale data for a locale in a layer. * * The mutation function receives the merged locale object (same shape as readLocaleData) * and may modify it in-place. After mutation: * * - Nuxt: Writes the entire object back to the single JSON file * - Laravel / Next.js / React: Splits by top-level namespace keys and writes each to its file. * New namespaces create new files. Empty namespaces delete the content (write empty object). * * Returns the set of file paths that were written. */ //#endregion //#region src/utils/errors.d.ts /** Extract a human-readable message from any thrown value. */ declare function toErrorMessage(error: unknown): string; declare class ToolError extends Error { readonly code: string; constructor(message: string, code: string); } //# sourceMappingURL=errors.d.ts.map //#endregion //#region src/utils/rename-notice.d.ts /** * The kit is renaming to the `@the-i18n-kit` scope (#315). During the window * both names publish from one source at matching versions, so nothing breaks — * but a user on the old name has no way of learning that unless the package * tells them. * * A package finds out it is the old one by reading its own `name` at runtime, * which is why this takes the name rather than deciding for itself: the same * code ships under both names, and only the manifest differs. */ /** * The notice for a package running under a legacy name, or null when it is * already running under its new one — which is the case that must stay silent, * since a notice there would be telling people to do what they have done. */ declare function renameNotice(packageName: string): string | null; //# sourceMappingURL=rename-notice.d.ts.map //#endregion //#region src/llm/providers.d.ts type LlmProvider = 'openai' | 'anthropic' | 'google'; /** How a provider failure should be handled by the caller. */ type TranslateProviderErrorKind = 'auth' | 'rate-limit' | 'provider' | 'config'; /** * A classified provider failure. `auth` errors are not retryable (the caller * should abort the run), `rate-limit` errors should be retried with backoff, * and `provider` covers everything else (server errors, network, …). * `config` marks an unusable provider setup and is raised while building the * TranslateFn, before any request exists — so it surfaces from the command * and never reaches the retry loop. */ declare class TranslateProviderError extends Error { readonly kind: TranslateProviderErrorKind; readonly status?: number; constructor(message: string, kind: TranslateProviderErrorKind, status?: number); } /** * Classify an SDK error into a TranslateProviderError: * 401/403 → auth, 429 → rate-limit, anything else → provider. * Already-classified errors pass through unchanged. */ declare function classifyProviderError(error: unknown): TranslateProviderError; interface LlmProviderConfig { provider: LlmProvider; model: string; /** Override API key. Falls back to env vars */ apiKey?: string; /** Base URL override for proxies / compatible APIs */ baseUrl?: string; } /** Environment variable carrying the provider base URL override. */ declare const BASE_URL_ENV = "I18N_BASE_URL"; /** * Resolve the provider base URL from its three sources, highest precedence * first: an explicit flag, the I18N_BASE_URL env var, then the project * config's `providerBaseUrl`. * * Blank values count as unset. Shells produce them routinely — `--baseUrl * "$UNSET"` or an exported-but-empty variable — and a blank must not shadow a * real endpoint configured further down the chain. A blank in the config file * is a different case: it cannot arise by accident, so the strict schema * rejects it at load time rather than letting it reach this function. */ declare function resolveProviderBaseUrl(sources: { flag?: string; env?: string; config?: string; }): string | undefined; /** * Create a TranslateFn from an LLM provider config. * Throws if the provider SDK is not installed or API key is missing. */ declare function createTranslateFn(config: LlmProviderConfig): Promise; //# sourceMappingURL=providers.d.ts.map //#endregion //#region src/config/project-config.d.ts /** * Load the project's declared configuration, from either place it can be * declared: `i18n-kit.config.ts` and `.i18n-mcp.json`. Both are searched from * projectDir upwards, the way ESLint, Prettier and tsconfig resolve configs. * * Returns null when neither exists — the case that must keep behaving exactly * as it did before there were two. Throws ConfigError when either file is * present but unusable, or when the two disagree. * * Every adapter funnels through here, which is what makes the typed config * work for all of them rather than for whichever one was taught about it. */ declare function loadProjectConfig(projectDir: string): Promise; //# sourceMappingURL=project-config.d.ts.map //#endregion export { AddTranslationsResult, BASE_URL_ENV, type CallArgument, type CallSite, type CheckUndefinedKeysResult, type CheckUndefinedKeysSummary, CodeUsageRef, CodeUsageResult, type DuplicateKeyCollision, DynamicKeyRef, EmptyTranslationsResult, type FileEvidence, type FindDuplicateKeysResult, type FindDuplicateKeysSummary, FindOrphanKeysResult, GeneratedProjectConfig, type I18nConfig, type I18nKitConfig, InitProjectConfigResult, type KeyUsageLocation, LARAVEL_PATTERNS, type LanguageFrontend, type LayerGraph, LayerStatus, type LlmProvider, type LlmProviderConfig, type LocaleDefinition, type LocaleDir, LocaleDirInfo, type LocaleRefAmbiguity, LocaleRefInfo, LocaleStatus, MisplacedUsageRef, MissingTranslationsResult, MoveTranslationKeyPlanEntry, MoveTranslationKeyResult, MutationPreview, MutationResult, PlaceholderValidationIssue, PlaceholderValidationResult, ProgressFn, type ProjectConfig, RemoveOrphanKeysResult, RemoveTranslationsPreview, RemoveTranslationsResult, RenameTranslationKeyPreview, RenameTranslationKeyResult, ScaffoldLocaleFileInfo, ScaffoldLocaleResult, ScanCodeUsageResult, type ScanResult, SearchMatch, SearchTranslationsResult, type SerializedLayerGraph, ToolError, TranslateAllLayersResult, TranslateAllLayersSummary, TranslateFailReason, TranslateFn, TranslateKeyLocaleIssue, TranslateKeyResult, TranslateLayerTotals, TranslateMissingCompactEntry, TranslateMissingLocaleResult, TranslateMissingOutcome, TranslateMissingResult, TranslateMode, TranslateProviderError, type TranslateProviderErrorKind, TranslateRequest, TranslateResponse, TranslateSkipReason, TranslationStatusResult, TranslationStatusSummary, type UncertainKeyFinding, type UndefinedKeyFinding, UnresolvedKeyWarningRef, UnresolvedLocaleRef, UpdateTranslationsResult, VUE_NUXT_PATTERNS, WriteTranslationsResult, addTranslations, buildLayerGraph, checkUndefinedKeys, classifyProviderError, clearConfigCache, createBladeFrontend, createOxcFrontend, createPatternsFrontend, createPhpFrontend, createTranslateFn, defineI18nKitConfig, detectConfig, detectI18nConfig, findDuplicateKeys, findEmptyTranslations, findLocaleImpl, findOrphanKeys, getCachedConfig, getMissingTranslations, getPatternSet, getTranslationStatus, getTranslations, listLocaleDirs, listNamespaces, loadProjectConfig, moveTranslationKey, readLocaleData, removeOrphanKeys, removeTranslations, renameNotice, renameTranslationKey, resolveProtectedLocales, resolveProviderBaseUrl, scaffoldLocaleFiles, scanCodeUsage, scanSourceFiles, searchTranslations, serializeLayerGraph, toErrorMessage, translateKey, translateMissing, updateTranslations, writeTranslations }; //# sourceMappingURL=index-DCG3dOdC.d.ts.map