/** * `auditTranslations` — data-level translation quality & parity audit. * * The richer successor to {@link validatePackageTranslations}: a pure function * over a package's locale bundles (no source scan, no I/O, deterministic, zero * false positives) that reports structured findings instead of opaque strings. * * Consumers run it in a vitest test to fail CI on drift — * `expect(auditTranslations('app', bundles).ok).toBe(true)` — or via the * `urbicon i18n parity` CLI, which formats the same findings. Key parity is the * baseline (missing/extra keys); on top of it sit the checks a structural diff * can't see: empty values, interpolation-param drift between locales, malformed * or CLDR-incomplete `_plural` objects, placeholder leftovers, and (opt-in) * not-yet-translated strings identical to the base locale. */ import { type Locale } from '../i18n/types.js'; /** A single audit check. Stable identifiers — safe to switch on in tooling/CI. */ export type TranslationFindingCode = 'missing-key' | 'extra-key' | 'empty-value' | 'wrong-type' | 'param-mismatch' | 'plural-shape-invalid' | 'plural-category-incomplete' | 'value-equals-key' | 'same-as-base' | 'invalid-locale' | 'no-translations'; export type TranslationFindingSeverity = 'error' | 'warning'; export interface TranslationFinding { /** Which check produced this finding. */ code: TranslationFindingCode; severity: TranslationFindingSeverity; /** The locale the finding belongs to (the base locale for base-only checks). */ locale: Locale; /** Dotted leaf-key path, e.g. `dialog.close`. Empty for whole-bundle findings. */ key: string; /** Human-readable message, prefixed with `[packageName]`. */ detail: string; } export interface AuditTranslationsOptions { /** Base locale every other locale is diffed against. Default: `en` if present, else the first. */ baseLocale?: Locale; /** * Per-check toggles. Unlisted checks keep their default — all on EXCEPT * `same-as-base`, which is FP-prone (brand names, "OK", shared tokens) and * opt-in. `missing-key` cannot be disabled (it is the parity floor). */ checks?: Partial>; /** Leaf-key paths to skip across all checks. Exact, or a `prefix.*` glob. */ ignoreKeys?: string[]; } export interface TranslationAuditReport { /** True when there are no `error`-severity findings (warnings do not fail). */ ok: boolean; /** All findings, sorted deterministically by locale → key → code. */ findings: TranslationFinding[]; /** The `error` subset, for a quick `expect(report.errors).toEqual([])`. */ errors: TranslationFinding[]; /** The `warning` subset. */ warnings: TranslationFinding[]; } /** * Audit a package's locale bundles for parity and translation-quality issues. * * @param packageName Used only to prefix `detail` messages (e.g. `[blocks]`). * @param translations Per-locale bundles, exactly as passed to `createPackageI18n`. */ export declare function auditTranslations(packageName: string, translations: Partial>>, options?: AuditTranslationsOptions): TranslationAuditReport;