i18n leak detection

mandatory

Detection contract for "i18n leaks" — user-facing string literals in Koder Stack UI surfaces (Flutter widgets, templ templates, TS/ JSX components, Go CLI/TUI) that bypass canonical i18n routing. Defines what counts as a leak, the allowlist categories, per-module opt-in, the audit gate, and the Stack-wide coverage registry.

Status: v0.1.0 Draft (2026-05-28). Companion to specs/i18n/contract.kmd — that spec defines the i18n contract (locale negotiation, runtime switch, ICU keys); this spec defines how the Stack detects violations of that contract.

The audit pipeline is implemented in dev/koder-tools/cmd/koder-i18n-audit/ (Go CLI, static scan) + engines/sdk/koder_test_* (runtime audit via headless render).

R1 — Definition of "leak"

A leak is a user-facing string literal in render code that:

  1. Is not routed through any of the canonical i18n helpers:
    • Dart/Flutter: KoderL10n.t(…), Intl.message(…),

      widget-local helpers that internally call them

    • templ (Go HTML): loc.T(…)
    • TypeScript/JSX: t(…), i18next.t(…)
    • Go CLITUI: i18n.T(…), `cobra.Command.ShortLong` when

      populated from translation tables

  2. Is not in the allowlist (R2)
  3. Is not the // kds-i18n-allow operator opt-out comment
  4. Looks like prose: contains at least one whitespace OR is ≥6

    chars AND mixed case OR multi-word

The classification is best-effort heuristic; false positives are expected and fixed by extending the allowlist (R2.5) — never by loosening R1.

R2 — Allowlist categories

The allowlist lives at registries/i18n-allowlist.md. Strings matching ANY of these categories are not leaks:

R2.1 — Proper names

Brand names of products, services, and visual languages NOT translated across locales. Examples: Koder, Verge, Material, GNOME, KDE Breeze, Adwaita, Cyberpunk.

R2.2 — Koder products + services

Product names that ship with English-source identity globally: Koder Hub, Koder Talk, Koder Flow, Koder Stack, Koder Kodix, Koder Dek, Koder ID, Koder Jet.

R2.3 — Code identifiers

Classtypefunction names that appear in user-facing context for developer surfaces (KDS docs, code samples, error codes): KoderApp, KoderUIStyle, KoderSignInButton, KoderL10n.

R2.4 — Units, symbols, technical literals

B, KB, MB, GB, TB, ms, μs, ns, fps, Hz, MHz, HTTP, HTTPS, TLS, OAuth, OIDC, JSON, YAML, TOML.

R2.5 — Per-module extension

Each module's koder.toml can declare additional allowlist entries under [i18n_audit] extra_allowlist = ["…", "…"]. Used for module-specific brand/product names (e.g. Dek-specific terminology).

R2.6 — Operator opt-out comment

// kds-i18n-allow: <reason> on the line above a string literal marks it as an intentional non-translation (debug log, internal identifier). The reason text is mandatory and audited (no empty opt-outs).

R3 — Per-module opt-in

Each Koder Stack module opts into the audit by adding to its koder.toml:

[i18n_audit]
enabled = true                          # default false (opt-in per module)
extra_allowlist = ["MyProductName"]     # see R2.5
excludes = ["lib/legacy
*.dart` (Flutter), `internal/**/*.templ` (Go),
`src*.{ts,tsx}` (web), or `cmd/**/*.go` (CLI). Mirrors the
`design-gen` pattern of `--max-broken-links` (defensive gate per
ratification baseline).

## Cross-link

- [`specs/i18n/contract.kmd`](./contract.kmd) — defines the i18n
  contract this spec audits
- [`policies/headless-first.kmd`](../../policies/headless-first.kmd) —
  why runtime audit lives in `koder_test_*`
- [`registries/i18n-allowlist.md`](https://flow.koder.dev/Koder/koder/src/branch/master/meta/docs/stack/registries/i18n-allowlist.md) —
  the canonical allowlist
- `dev/koder-tools/cmd/koder-i18n-audit/` — the CLI implementation