Translations are made in Weblate only: the rule, the documents that contradict it, and what a commit does with a string #706

Closed
opened 2026-10-03 01:59:14 +00:00 by tiagoagueda · 1 comment
Owner

From the list: “All further translations must be made using Weblate.” The documents that tell people how to translate, and the instructions to anyone working on the code, say the opposite: edit the .po file and open a pull request, or write the translation in the commit. This issue states the rule in those documents and settles what a commit does when the rule meets a string; what it cannot yet do is switched on by #349's round trip, and this issue says exactly which parts wait for it.

What exists today

  • The translator's handbook sends people to the repository. docs/TRANSLATING.md:181-190 (Editing a catalogue): “Edit src/postulo/locale/<locale>/LC_MESSAGES/django.po … Open a pull request.” Adding a language ends the same way (:252-253); reviewing a draft means “reading it and deleting the flag” in the file (:138-143). The file never mentions Weblate. Nor do README.md, CONTRIBUTING.md or the wiki; the only documents that do are docs/PLAN.md:342 and the changelog.
  • The contributor guide does the same. CONTRIBUTING.md:295-299: “French and Portuguese catalogues exist and are waiting for contributors”, pointing at that handbook; :348-351 (Making a release): “Ordinary work translates English, French and European Portuguese”, and the release gate is where the rest are swept up.
  • The assistant's instructions say to write translations in the commit. CLAUDE.md:46-48: after changing a string, run scripts/messages.py extract “so every catalogue gets its slot; a new translation carries the draft flag until a speaker reviews it”. The per-commit check is a convention: CI runs extract --check and check (.forgejo/workflows/ci.yml:104-105) and holds no language complete on a commit; the only completeness test is the release-marked tests/test_translations.py::test_every_european_union_language_stays_complete (:155).
  • The decision #347 builds (open): a development build needs every string in en-GB, fr-FR and pt-PT, a draft counting; a release needs its selected languages; every language is scaffolded. #269 records the maintainer's decision of 2026-10-01.
  • Weblate exists and is not part of the loop. translate.tiagoagueda.com, one project with 23 components, brought level with every repository on 2026-10-01 (comment on #349). It “has merged nothing since the day it was set up”: AUTO_UPDATE is off, no repository has a webhook, and a translation made there rewrites the catalogue's header, so merging main conflicts. A translation made in Weblate reaches the repository only when the maintainer takes it by hand (the one that has, “Token da API”, is in the changelog, CHANGELOG.md:93). #349 lists what a working round trip needs: out on push, in as a pull request that CI judges, one format written by two writers, the draft flag mapped to a Weblate state, and who may translate and on what terms.
  • What Weblate can do about a new string, verified in its documentation on 2026-10-02: an Automatic translation add-on fills new strings from machine translation services or from other components and can mark each result as needing editing, and a Flag new translations as needing rewriting add-on exists; Weblate supports opening pull requests on Gitea (Forgejo is not named in the page read, and compatibility is not verified here).
  • Tool facts that bear on it. scripts/messages.py extract keeps every translation and drops what the source lost (docs/TRANSLATING.md:164-165, tests/test_messages_tool.py:100): a commit that renames a string discards its translations in the repository, including any that exist only in Weblate. tests/test_translations.py::test_the_catalogues_are_what_a_fresh_extraction_writes (:221) is the test that says whether Weblate's output and the tool's agree.
  • docs/TRANSLATING.md:47-55 still has the table of phases by release that #347 replaces; stale against #269.

Checked against main at f09b6010b.

Proposal

  1. State the rule in docs/TRANSLATING.md, CONTRIBUTING.md (Translations) and CLAUDE.md: a translation, a correction and the review of a draft are made in Weblate and nowhere else; nobody translates by editing a .po file; a pull request that does is asked to be redone there. Say what is not a translation: the English source in the code, the slots extract writes, and a mechanical rename carried out by a script.
  2. Rewrite Editing a catalogue, Drafts and Adding a new language for a speaker in Weblate: where it is, how to get an account and under what licence the translation comes in (#349, #346), what the states mean, and what happens to what they type. Until the round trip exists the page says plainly that the maintainer brings Weblate's work into the repository by hand.
  3. Say what a commit does with a string (below): a new string, a changed English string, a renamed or removed string, and a string waiting in Weblate.
  4. Change the per-commit instruction in CLAUDE.md and CONTRIBUTING.md to whatever the decisions below choose, and say so on #347 so its development gate is written for the same rule.
  5. Replace the table of phases with the five points of the decision (#347), as that issue already asks.

Decisions

  • How the three working languages are filled for a development build. #347's gate needs en-GB, fr-FR and pt-PT present for every string, a draft counting. (a) The author, or an assistant, writes a first draft of the fr-FR and pt-PT translation in the commit, flagged draft, and every later change is made in Weblate; (b) the commit carries only the English and Weblate's Automatic translation add-on fills the other two, which arrive as a pull request. Recommended: (a) for now. (b) cannot satisfy a per-commit gate, because the pull request lands after the commit; it would turn every development image red until the round trip has run, and it needs a machine translation service configured and paid for. Revisit when #349 works and merges on its own. This is a narrow carve-out from “all further translations”, not a way around it, and the maintainer should confirm that reading.
  • What a commit does with a string that is waiting in Weblate. A translation made in Weblate and not yet in the repository is lost if a commit renames or removes its string, and it conflicts if the catalogue's header moved. Recommended: the rule is procedural until #349 lands: before a commit that renames or removes strings in bulk (such as the sweep in #705), Weblate's pending work is taken into the repository and the components are reset to upstream, as was done on 2026-10-01; after #349, Weblate's pull requests are merged first and that step disappears.
  • Which edits remain legitimate outside Weblate. The English source, extract's slots, a scripted rename that carries translations to the new ids, and a seed for a new variant (as pt-BR was seeded from pt-PT, #110), which Weblate then holds. Recommended: exactly those, each said in the handbook so nobody guesses.
  • Plugins. Every plugin ships its own catalogues and core never translates plugin strings (settled). Recommended: the rule is stated once, for every catalogue set, and each plugin repository's own issue (#349's list) applies it; no change to which repository owns which strings.
  • Where an assistant stands. CLAUDE.md tells an assistant to write translations. Recommended: it writes the draft of (a) and nothing else, and says in the commit that the drafts are awaiting review in Weblate.

What is blocked until #349's round trip exists

  • Removing the “edit the file and open a pull request” path. A speaker cannot be told “Weblate only” while what they type there does not come back (Weblate merges nothing today, and a header rewrite conflicts). The handbook can state the rule now; it cannot drop the old path until a translation made in Weblate arrives as a pull request that passes CI.
  • Sending contributors to Weblate at all. Who may sign in, and the licence their translations come in under, are open in #349 and #346.
  • The draft flag's meaning in Weblate. A draft arriving from a commit has to show there as needing a reader, and a speaker approving it has to clear the flag here (#349).
  • A per-commit gate that counts what is waiting. The gate in #347 can only look at the repository.

None of the five proposals above is blocked: the rule, the rewritten pages with their stated interim, and the commit rules can all be written now.

Builds on

Issues #349 (the round trip, and the other repositories' twins), #347 (the gates), #269 (the languages and the decision of 2026-10-01), #346 (the licence a contribution comes in under), #337 (language codes). Related: #705 (a rename sweep that has to meet this rule).

Done when

  • docs/TRANSLATING.md, CONTRIBUTING.md and CLAUDE.md state the rule, the exceptions and the commit rules, and no longer tell anyone to translate by editing a .po file or open a pull request for it; the handbook says plainly what is interim until #349.
  • The wiki says the same where it speaks of translating (the wiki's own translation is #352).
  • A small test beside tests/test_translations.py holds the three documents to the rule: none still contains the instruction to open a pull request for a translation, and docs/TRANSLATING.md names Weblate. The catalogue tests keep passing on a commit that follows (a): scripts/messages.py extract --check and check.
  • #347 carries a comment saying its development gate follows the chosen reading of (a).
  • No record type is added, so no format changes (archive 29, candidate 4 at f09b6010b); new strings, if any, are in the working catalogues (en-GB, fr-FR, pt-PT as drafts) and Weblate.

From the list of improvements of 2026-10-02.

From the list: “All further translations must be made using Weblate.” The documents that tell people how to translate, and the instructions to anyone working on the code, say the opposite: edit the `.po` file and open a pull request, or write the translation in the commit. This issue states the rule in those documents and settles what a commit does when the rule meets a string; what it cannot yet do is switched on by #349's round trip, and this issue says exactly which parts wait for it. ## What exists today - **The translator's handbook sends people to the repository.** `docs/TRANSLATING.md:181-190` (*Editing a catalogue*): “Edit `src/postulo/locale/<locale>/LC_MESSAGES/django.po` … Open a pull request.” Adding a language ends the same way (`:252-253`); reviewing a draft means “reading it and deleting the flag” in the file (`:138-143`). The file never mentions Weblate. Nor do `README.md`, `CONTRIBUTING.md` or the wiki; the only documents that do are `docs/PLAN.md:342` and the changelog. - **The contributor guide does the same.** `CONTRIBUTING.md:295-299`: “French and Portuguese catalogues exist and are waiting for contributors”, pointing at that handbook; `:348-351` (*Making a release*): “Ordinary work translates English, French and European Portuguese”, and the release gate is where the rest are swept up. - **The assistant's instructions say to write translations in the commit.** `CLAUDE.md:46-48`: after changing a string, run `scripts/messages.py extract` “so every catalogue gets its slot; a new translation carries the `draft` flag until a speaker reviews it”. The per-commit check is a convention: CI runs `extract --check` and `check` (`.forgejo/workflows/ci.yml:104-105`) and holds no language complete on a commit; the only completeness test is the release-marked `tests/test_translations.py::test_every_european_union_language_stays_complete` (`:155`). - **The decision #347 builds** (open): a development build needs every string in en-GB, fr-FR and pt-PT, a draft counting; a release needs its selected languages; every language is scaffolded. #269 records the maintainer's decision of 2026-10-01. - **Weblate exists and is not part of the loop.** `translate.tiagoagueda.com`, one project with 23 components, brought level with every repository on 2026-10-01 (comment on #349). It “has merged nothing since the day it was set up”: `AUTO_UPDATE` is off, no repository has a webhook, and a translation made there rewrites the catalogue's header, so merging `main` conflicts. A translation made in Weblate reaches the repository only when the maintainer takes it by hand (the one that has, “Token da API”, is in the changelog, `CHANGELOG.md:93`). #349 lists what a working round trip needs: out on push, in as a pull request that CI judges, one format written by two writers, the `draft` flag mapped to a Weblate state, and who may translate and on what terms. - **What Weblate can do about a new string, verified in its documentation on 2026-10-02:** an *Automatic translation* add-on fills new strings from machine translation services or from other components and can mark each result as needing editing, and a *Flag new translations as needing rewriting* add-on exists; Weblate supports opening pull requests on Gitea (Forgejo is not named in the page read, and compatibility is not verified here). - **Tool facts that bear on it.** `scripts/messages.py extract` keeps every translation and drops what the source lost (`docs/TRANSLATING.md:164-165`, `tests/test_messages_tool.py:100`): a commit that renames a string discards its translations in the repository, including any that exist only in Weblate. `tests/test_translations.py::test_the_catalogues_are_what_a_fresh_extraction_writes` (`:221`) is the test that says whether Weblate's output and the tool's agree. - `docs/TRANSLATING.md:47-55` still has the table of phases by release that #347 replaces; stale against #269. Checked against `main` at `f09b6010b`. ## Proposal 1. **State the rule** in `docs/TRANSLATING.md`, `CONTRIBUTING.md` (*Translations*) and `CLAUDE.md`: a translation, a correction and the review of a draft are made in Weblate and nowhere else; nobody translates by editing a `.po` file; a pull request that does is asked to be redone there. Say what is not a translation: the English source in the code, the slots `extract` writes, and a mechanical rename carried out by a script. 2. **Rewrite *Editing a catalogue*, *Drafts* and *Adding a new language* for a speaker in Weblate**: where it is, how to get an account and under what licence the translation comes in (#349, #346), what the states mean, and what happens to what they type. Until the round trip exists the page says plainly that the maintainer brings Weblate's work into the repository by hand. 3. **Say what a commit does with a string** (below): a new string, a changed English string, a renamed or removed string, and a string waiting in Weblate. 4. **Change the per-commit instruction** in `CLAUDE.md` and `CONTRIBUTING.md` to whatever the decisions below choose, and say so on #347 so its development gate is written for the same rule. 5. **Replace the table of phases** with the five points of the decision (#347), as that issue already asks. ## Decisions - **How the three working languages are filled for a development build.** #347's gate needs en-GB, fr-FR and pt-PT present for every string, a draft counting. (a) The author, or an assistant, writes a first draft of the fr-FR and pt-PT translation in the commit, flagged `draft`, and every later change is made in Weblate; (b) the commit carries only the English and Weblate's *Automatic translation* add-on fills the other two, which arrive as a pull request. **Recommended: (a) for now.** (b) cannot satisfy a per-commit gate, because the pull request lands after the commit; it would turn every development image red until the round trip has run, and it needs a machine translation service configured and paid for. Revisit when #349 works and merges on its own. This is a narrow carve-out from “all further translations”, not a way around it, and the maintainer should confirm that reading. - **What a commit does with a string that is waiting in Weblate.** A translation made in Weblate and not yet in the repository is lost if a commit renames or removes its string, and it conflicts if the catalogue's header moved. **Recommended: the rule is procedural until #349 lands**: before a commit that renames or removes strings in bulk (such as the sweep in #705), Weblate's pending work is taken into the repository and the components are reset to upstream, as was done on 2026-10-01; after #349, Weblate's pull requests are merged first and that step disappears. - **Which edits remain legitimate outside Weblate.** The English source, `extract`'s slots, a scripted rename that carries translations to the new ids, and a seed for a new variant (as pt-BR was seeded from pt-PT, #110), which Weblate then holds. **Recommended: exactly those**, each said in the handbook so nobody guesses. - **Plugins.** Every plugin ships its own catalogues and core never translates plugin strings (settled). **Recommended: the rule is stated once, for every catalogue set**, and each plugin repository's own issue (#349's list) applies it; no change to which repository owns which strings. - **Where an assistant stands.** `CLAUDE.md` tells an assistant to write translations. **Recommended: it writes the draft of (a) and nothing else**, and says in the commit that the drafts are awaiting review in Weblate. ## What is blocked until #349's round trip exists - **Removing the “edit the file and open a pull request” path.** A speaker cannot be told “Weblate only” while what they type there does not come back (Weblate merges nothing today, and a header rewrite conflicts). The handbook can state the rule now; it cannot drop the old path until a translation made in Weblate arrives as a pull request that passes CI. - **Sending contributors to Weblate at all.** Who may sign in, and the licence their translations come in under, are open in #349 and #346. - **The `draft` flag's meaning in Weblate.** A draft arriving from a commit has to show there as needing a reader, and a speaker approving it has to clear the flag here (#349). - **A per-commit gate that counts what is waiting.** The gate in #347 can only look at the repository. None of the five proposals above is blocked: the rule, the rewritten pages with their stated interim, and the commit rules can all be written now. ## Builds on Issues #349 (the round trip, and the other repositories' twins), #347 (the gates), #269 (the languages and the decision of 2026-10-01), #346 (the licence a contribution comes in under), #337 (language codes). Related: #705 (a rename sweep that has to meet this rule). ## Done when - `docs/TRANSLATING.md`, `CONTRIBUTING.md` and `CLAUDE.md` state the rule, the exceptions and the commit rules, and no longer tell anyone to translate by editing a `.po` file or open a pull request for it; the handbook says plainly what is interim until #349. - The wiki says the same where it speaks of translating (the wiki's own translation is #352). - A small test beside `tests/test_translations.py` holds the three documents to the rule: none still contains the instruction to open a pull request for a translation, and `docs/TRANSLATING.md` names Weblate. The catalogue tests keep passing on a commit that follows (a): `scripts/messages.py extract --check` and `check`. - #347 carries a comment saying its development gate follows the chosen reading of (a). - No record type is added, so no format changes (archive 29, candidate 4 at `f09b6010b`); new strings, if any, are in the working catalogues (en-GB, fr-FR, pt-PT as drafts) and Weblate. From the list of improvements of 2026-10-02.
tiagoagueda added this to the 0.5.0 milestone 2026-10-03 01:59:14 +00:00
Author
Owner

Done. Translations are made in Weblate only: docs/TRANSLATING.md, CONTRIBUTING.md, CLAUDE.md, README and the wiki say so and say what a commit may do with a string (925e3e9cd), tests/test_translation_docs.py holds them to it, and scripts/messages.py guard refuses in CI and before a commit any translation written outside Weblate (e014152fc). No test pins a translated word. The interim the issue foresaw is gone: the round trip of #349 works, proven by Weblate's first pull request #829, merged as 8c3d03570 with every CI job green.

Done. Translations are made in Weblate only: docs/TRANSLATING.md, CONTRIBUTING.md, CLAUDE.md, README and the wiki say so and say what a commit may do with a string (925e3e9cd), tests/test_translation_docs.py holds them to it, and `scripts/messages.py guard` refuses in CI and before a commit any translation written outside Weblate (e014152fc). No test pins a translated word. The interim the issue foresaw is gone: the round trip of #349 works, proven by Weblate's first pull request #829, merged as 8c3d03570 with every CI job green.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Postulo/postulo#706
No description provided.