i18n leak detection
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:
- 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` whenpopulated from translation tables
- Dart/Flutter:
- Is not in the allowlist (R2)
- Is not the
// kds-i18n-allowoperator opt-out comment - 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