i18n status: Partial — one source locale, one unreviewed machine translation. Reason: a human-facing surface now exists (the rendered HTML receipt), so the previous "N/A, English-only operator output" declaration no longer holds.
Declared: 2026-08-15 · Reviewer: contextsafe maintainer (Chelsea Kelly-Reif) Superseded declaration: 2026-07-16, "i18n status: N/A".
Two kinds of text leave this tool, and they are governed differently.
Machine artifacts — the receipt document, every --output file, and the
single JSON error object on stderr — stay in one fixed language. They are
hash-covered and byte-pinned across time zones, locales, hash seeds, and
platforms by tests/test_determinism.py; a payload whose wording changed with
an interface locale would produce two different payload_sha256 values for the
same evaluation. tests/test_i18n.py::test_the_machine_artifact_never_varies_by_locale
pins that no catalog string ever reaches a canonical artifact.
The rendered page — contextsafe render --receipt … --lang …, the
script-free HTML receipt from B-034 — is the localized surface. It is the only
place in the package where wording varies, and it is where a reader rather than
a hash is the consumer.
CLI help text is externalized into the catalog but rendered only in the source
locale, for the same reason: --help and usage errors are part of the byte
surface.
| Locale | Role | Review status | What a reader sees |
|---|---|---|---|
en-US |
Source. Authored, not translated. | n/a | Nothing marked. |
es-US |
Machine translation. | Unreviewed | A notice in Spanish and in English, every string marked data-cs-review="machine", and every mandated safety disclosure shown next to its en-US original. |
qps-ploc |
Generated pseudolocale. | Gate only | Never shipped to a reader. |
The Spanish catalog is a machine translation. No qualified human translator and
no community reviewer has read it. B-042 is that work, and it has not
happened. Until it does and translation_review in
src/contextsafe/locales/es-US.json names a reviewer and a date, the interface
says so on every page, in both languages, and the mandated limitations render
bilingually rather than leaving a reader alone with an unreviewed translation of
"not an approved clinical oracle".
This is a deliberate refusal to let an unreviewed translation look finished. For a product whose users are people for whom a mistranslation is a safety problem, an interface that renders machine output as though a person checked it is a defect, not a placeholder.
make i18n runs tools/i18n_gate.py, which fails on:
catalog-parity— a locale missing a key or carrying one the source lacks.placeholder-parity— a translated string whose{placeholder}set differs.message-quality— an empty string, or a source-locale entry marked as a translation.review-consistency— a catalog claiminghumanreview while containing unreviewed strings, or claiming it without naming a reviewer and a date.unreviewed-on-reviewed-surface— a surface declaringhuman_reviewedaccepting a string that has not been reviewed. Every shipped locale is pulled through a claiming surface; a machine-translated one must be refused.undisclosed-machine-translation— a rendered page whose catalog is machine translated and which does not carry the notice, or a reviewed page that carries it anyway.hardcoded-string— visible text on the pseudolocalized page that no catalog message accounts for and that does not come from the receipt document. This is how "externalize every string" is checked rather than asserted.no-catalogs— the gate examined nothing. A gate that can report success having looked at nothing is worthless, so this one refuses to.
Each rule has a negative control in tests/test_i18n.py that has been watched
to fail.
- B-042: professional Spanish translation and independent community review. Needs a person. Cannot be built.
- B-044: manual screen reader, keyboard, zoom, and high-contrast evaluation in both languages. Needs a person.
- B-053: the EN/ES cross-role comprehension study. Needs participants.
- Locale-aware number, date, and list formatting. The page currently renders no formatted number or date beyond values copied verbatim from the receipt.
- Right-to-left layout. No RTL locale is shipped and the stylesheet has not been written for one.
- Localized CLI output, if a localized operator surface is ever wanted. That needs a decision about which command output is an artifact and which is display text, and today all of it is an artifact.