The language rule
The language rule
This repository is bilingual by design, and the line between the two languages is not a matter of taste. It is a rule with one test, and getting it wrong is the most common mistake made here — including by the agent that wrote most of this pipeline, which put Portuguese comments in seventeen Python files while CLAUDE.md said, the whole time, that comments are in English.
The test
Would a visitor to pt.newsroom.sgit.ai read this string on the site?
Yes → European Portuguese, under AO90. No → English. There is no third answer, and "it felt more natural in Portuguese" is not one.
Portuguese, because a visitor reads it
- Article prose, headlines, standfirsts, section names, the dateline, the footer, the notice.
- Entity labels — the names of people, organisations, institutions, publishers, places. These are verbatim from the frozen source, in whatever language the source used, and a transcription is a claim (see principle 2).
- The ontology: every edge verb, its named inverse, and its reading.
{s} fala em {t}is content — it is the sentence a reader hears when they walk the graph. Theenfield beside it is an annotation, not a translation of the site. - Tag labels, theme labels, section descriptions, gate messages that appear on a page.
- Everything under
conteudo/,artigos/**/artigo.md, and the prose fields ofseccoes/*/.
English, because a visitor never reads it
- All code. Every
.py,.js,.mjs,.css: identifiers, comments, docstrings, error strings, log output. Enforced by gate 34. - The back office (
/newsroom/), admin pages (/admin/), includingadmin/versions.html. Its audience is whoever operates the newsroom. - This guidance, every
ROLE.mdandMANDATE.md, every memo inbriefs/memos/. - Commit messages, branch names, run-record free text, mail between departments.
- API paths (
/api/v1/companies, not/empresas) — the intent is several languages over one set of data, and an English path is the one that does not privilege the first language. - Browser-side state:
localStoragekeys, event names, CSS class names,data-attributes, custom element tag names. - File and folder names of code. Note the exceptions below.
The two honest exceptions, and why they stay
1. The keys inside dados/*.json are Portuguese. nome, fonte, estado, afirmacoes. So are several folder names that predate this rule: dados/, fontes/congeladas/, redacao/, artigos/, seccoes/.
They stay, for now, and the reason is not inertia. The keys are the vocabulary of a Portuguese ontology, and estado: confirmada reads as one thing in a way state: confirmada does not. Renaming 374 distinct keys would touch every builder, every gate, the API and every component in one change — the kind of change that is right only when it is the only thing in the release. It is scheduled, not skipped, and until it happens the API is explicit about it: paths are English, keys are Portuguese, and /api/ says so on the page.
If you are the agent who does that migration: do it alone, in one release, with a key map published as data, and a gate that fails on any Portuguese key outside the map.
The map now exists, and so does the script. dados/en-migration.json maps 467 keys and 8 folders and states what it does not touch and why; build/migrate_to_english.py applies it, and refuses to while a blocker stands. Both came out of running the migration against a scratch clone four times, which turned up six classes of defect that a reading of the diff would not have — folder renames applied child-before-parent, a pattern that matched "dados" but not "dados/historias.json", a key map built from one folder when the data lives in five, 120 keys that came out half-translated, redacao/ being a reader URL rather than a backend folder, and Portuguese Python identifiers that a string-level rename cannot see.
It is blocked, and the blocker is a permissions decision. build/gates.py and build/entregas.py hardcode the backend folder names and 115 of the keys, and both are deny-listed: an agent that can edit the gate that stops it has no gate. The note is in the editor's inbox.
2. Evidence keeps the shape it arrived in. A frozen .snapshot is another organisation's bytes and is never touched. A transfer manifest from a sibling publication (fontes/transferidas/**) keeps its own field names, in its own language, because rewriting a manifest to our taste would mean the hash we verify no longer matches the file we quote. Our own records about it are English.
What this rule is not
It is not a claim that Portuguese is for the front and English is for the back. It is a claim about audience. The reader of this publication reads Portuguese. The operator of this newsroom — and every agent working in it — reads English. A file serves one of them, and it is almost never both.
← Working on pt.newsroom.sgit.ai: start here · The principles, and the gate that enforces each one →
This page is rendered from
docs/guidance/language.md by build/guia.py. The
markdown is the source; edit that and rebuild. Nobody hand-edits this file.
build/newsroom.py from the files in this
repository; nothing here is hand-written. The machine-readable index of the publication is at
llms.txt. Source: github.com/SGit-AI/SGit-AI__Website__Newsroom__PT · file:
newsroom/guidance/language.html · version v0.23.6.