ADR-0163 — Translating the console
- Status: Accepted (design); implementation waits for its first language
- Date: 2026-09-24
- Settles item 3.7 of
docs/UX-AUDIT-2026-08-VAYUMAIL-VAYUTALK.md(string extraction for VayuMail and VayuTalk).
0. Where it stands
internal/i18n translates the public site: about fifteen keys, chosen by the
visitor's Accept-Language, falling back to English. The console has no
language setting, and no console string goes through a catalog.
VayuMail and VayuTalk alone render about 540 distinct text strings from Go and at least 70 from JavaScript, not counting labels, placeholders and titles.
1. Decision
The console is translated per surface, in one release per surface, and only once there is a language to translate it into. Extracting strings with no target language adds a lookup to every sentence and translates nothing, so the work starts when a first language and a person to check it exist. This ADR fixes how it is done then, so nothing built before then has to be undone.
1.1 Which language
The signed-in user's own choice, stored with the user. Without one, the
browser's Accept-Language; then English. Never the public site's language: the
person running the console and the people reading the site are different
audiences.
1.2 The catalog
The console gets its own catalog in internal/i18n, with the same fallback the
public one has (missing key → English → the key itself), under its own key
namespace (mail.*, talk.*, …). The two catalogs share the lookup code, not
their keys.
1.3 Rules for a string
- Whole sentences are keys. A sentence built by concatenation cannot be
translated, because word order differs between languages. Values go in by
name (
{mailbox}), not by position. - Counts have plural forms.
3 messagesbecomes a key per plural category (.one,.other, and more where a language needs them), chosen by that language's rule. English and the first language's rules are added together. - A translation is data, never markup. It is escaped where it is rendered,
exactly as an English literal is today. A catalog entry that contains
<b>shows<b>.
1.4 Strings used by scripts
The server renders the page's keys into a non-executing JSON block
(<script type="application/json" id="vp-i18n">), which the strict CSP
already allows, and the shell reads them through one helper. Scripts carry no
English of their own once a surface is extracted.
1.5 How it is verified
- A gate: every key a surface uses exists in English.
- A pseudo-language (accented and about 40% longer) used in the end-to-end run: any English left on the page is an unextracted string, and any overflow is a layout that will break in a real language.
2. What would change this
A first target language. Mail and Talk go first, because they are the surfaces a mailbox holder uses who may never see the rest of the console.