Skip to content

ADR 0011 — Release notes are translated with each fragment

Status: accepted · 2026-11-08 (maintainer decision on #162)

Context

Fairmark is written for Italian analysts and SMEs. The documentation has an English source and an Italian edition tracked by scripts/i18n.py. The release notes, the document written for analysts, exist only in English: towncrier builds RELEASE_NOTES.md from changes/, scripts/docs.py renders it on the site with the unreleased draft on top, and i18n/it.yaml lists project/*.md as English only, so the Italian site links the English page. The GitHub Release body is extracted from RELEASE_NOTES.md by scripts/release_notes.py. Agents write most pull requests; the maintainer reviews in Italian. No version has been released yet, so there is nothing to translate retroactively.

Options considered

  • A. A translated fragment in each pull request. Each English fragment has a counterpart per maintained language; one towncrier configuration per language builds RELEASE_NOTES.<lang>.md. Cost: one to three sentences more per user-facing pull request. The Italian site is current after every merge.
  • B. Translation at release time. No cost per pull request. The Italian site has no current notes between releases, and the Prepare release workflow, which runs no agent, can no longer produce the release pull request on its own.
  • C. Status quo. No cost. The readers the project targets read its one analyst document in English.

Decision

  1. Option A. A pull request that adds or edits changes/<issue>.<type>.md adds or edits changes/<lang>/<issue>.<type>.md for each maintained language. The author writes it with i18n/glossary.yaml; an author who cannot labels the pull request translation-pending, the label the documentation already uses.
  2. Pairing is by file name, without hash tracking. Fragments are one to three sentences and live only until the next release. An English fragment edited without its translation is a review finding; the maintainer reads both texts in the release pull request.
  3. scripts/i18n.py check requires a translation for every English fragment and no orphan translation. It already runs in the Docs workflow, skipped with translation-pending, and in release.py ready, never skipped: a pending translation can be merged, not released.
  4. Languages are not hard-coded. Each language with release notes declares its towncrier configuration in i18n/ (translated section names, output RELEASE_NOTES.<lang>.md, the same title format as English). Adding a language remains a maintainer decision.
  5. The GitHub Release keeps one body: the English notes, then a link per language to RELEASE_NOTES.<lang>.md at the tag.
  6. The Italian site renders RELEASE_NOTES.it.md with its draft on top. The changelog stays English only.

Consequences

  • Italian readers get the analyst document in their language, as current as the English one.
  • The text is translated while its context is fresh, in a pull request the maintainer already reviews; the release pull request stays generated by the workflow.
  • Same label, check and release gate as the documentation: no new process. − Every user-facing pull request carries one more short file. External contributors can use translation-pending, which moves the work to the maintainer before the release. − Name pairing does not detect an English fragment edited after its translation; accepted, bounded by review and by the life of a fragment.

The implementation task changes: 1. i18n/it.towncrier.toml (directory changes/it) and RELEASE_NOTES.it.md with the start marker; verify that the English configuration in pyproject.toml ignores changes/<lang>/ in build and check. 2. scripts/i18n.py: fragment pairing in check, status and todo. 3. .github/workflows/prepare-release.yml and .agents/skills/release/SKILL.md: one towncrier build --config per language; the release pull request body shows every text. 4. scripts/release_notes.py: the link per language. 5. scripts/docs.py: current_notes per language, with the draft title and the empty-draft sentence from i18n/<lang>.yaml. i18n/it.yaml and translate_nav: an exception so that project/release-notes.md is no longer English only and is not tracked as a translation; docs/it/project/release-notes.md includes .generated/RELEASE_NOTES.it.md. 6. _typos.toml: exclude changes/it/ and RELEASE_NOTES.it.md. 7. changes/README.md, docs/en/project/releases.md, AGENTS.md, .agents/agents/translator.md (fragments in the work list) and the code-reviewer checklist (paired edits), with the Italian translations of the changed pages.