Skip to content

Localization

Muhammet Şafak edited this page Jun 13, 2026 · 4 revisions

Home / Reference / Localization

Localization

CommitBrief separates two languages that are resolved from one chain but serve different purposes (ADR-0021):

  • AI output language — the language the provider writes the review / summary / findings in. This can be any recognized language (~50, e.g. en, tr, fr, de, es, ja).
  • CLI interface language — the tool's own strings (progress lines, confirm prompts, errors). These are localized only for the languages we ship a catalog for: en (English) and tr (Türkçe). For any other output language the interface stays English.

So --lang fr gives you a French review with an English interface; --lang tr gives you Turkish for both.

Resolution order

One chain decides the language; the interface is then derived from it. The resolved language is the first recognized value in:

  1. --lang <code> CLI flag.
  2. Repo-local config (<repo>/.commitbrief/config.ymloutput.lang).
  3. Global config (~/.commitbrief/config.ymloutput.lang).
  4. Built-in default: en.

At every step a value that is empty or not a recognized language falls through to the next source — it never short-circuits to English mid-chain. So an invalid --lang xx falls through to your repo config; an invalid repo output.lang falls through to your user config; and so on.

The system locale (LANG env var) is not consulted (changed in v1.6.0, ADR-0021). Language is config-driven only, so the same repo/user config produces the same language on every machine and in CI. A setup that previously relied on LANG=tr_TR with no config now defaults to English — set output.lang or pass --lang instead.

The Resolution carries a Source field (cli flag / repo config / global config / default) which surfaces in the dry-run footer for attribution. The resolved output code (e.g. fr) is what the footer and the cache key report, even when the interface has degraded to English.

Output vs. interface (the split)

Input Output language Interface language
--lang tr Turkish Turkish (catalog shipped)
--lang fr French English (no fr catalog)
--lang de, repo output.lang: tr French? no — German (flag wins) English
--lang xx (invalid), repo output.lang: tr Turkish (flag falls through) Turkish
(nothing set) English English

The output language is preserved verbatim; the interface language is output-language-if-we-have-a-catalog-else-English.

What the interface catalog covers

Localized (text goes through the en/tr catalog):

  • CLI confirm prompts ("Continue?", "Replace COMMITBRIEF.md?", …), including the Yes/No button labels on the interactive (TTY) toggle.
  • Progress messages ("Searching for changes…", "Thinking…").
  • Doctor check labels, init / setup / providers / cache / config status lines.
  • Error prefix ("Error:") and a fixed set of common error messages.

Not localized (intentionally English):

  • The rule scaffolding in the system prompt (the "respond in " directive is set to the resolved output language, but the surrounding structure is English).
  • Tabular output (dry-run columns, compress savings table) — debug-grade.
  • %w error wrappers from internal/Go packages, and JSON schema field names.

TestKeyParity enforces that every key in messages.en.yml also exists in messages.tr.yml; CI fails on drift.

Validation

commitbrief config set output.lang <code> rejects a value that is not a recognized language (empty clears the override). A typo is caught at set-time rather than silently falling back to English at runtime.

Recognized languages

The recognized set (output languages) is the displayNames map in internal/lang/locale.go — ~50 common languages, code → display name. The interface subset is uiCatalogs ({en, tr}). A language outside the recognized set is treated as invalid and falls through the chain.

Helpers

  • lang.Resolve(flag, repo, global) Resolution — walks the chain.
  • Resolution.UICatalog() string — the interface catalog code (resolved code if shipped, else en).
  • lang.Recognized(code) bool — is this a valid output language? (used by config set validation).
  • lang.English() Resolution — the terminal fallback / a forced-English constructor (used by the eval harness).

Adding a new language

  • Output only (e.g. add Italian as an output language): add one entry to displayNames in internal/lang/locale.go. No catalog needed.
  • Interface too (ship the CLI in a new language): add messages.<code>.yml in internal/i18n/ with every key from messages.en.yml translated, and add the code to uiCatalogs. TestKeyParity + make i18n-check catch missed/stale keys.

See also

Clone this wiki locally