feat: add translators theme option alongside authors - #427
Conversation
Adds a `translators` option, parallel to the existing `authors`, taking a
list of `{name, url}` entries and rendering them below the page title so
translated editions can credit the people who produced them.
Translators render behind a visible label because two adjacent unlabelled
name lists would be ambiguous. The label defaults to "Translated by" and
is overridable via `translators_label` so each edition renders it in its
own language. Authors keep their current label-free rendering; the
matching `authors_label` exists but defaults to empty, so a site that
sets neither option renders byte-identical HTML.
Either list can be overridden per page in MyST or notebook front matter,
which is how a team-translated edition credits whoever produced each
lecture. A page value replaces the project value rather than merging with
it, an explicit empty list leaves the block out on that page, and an
absent key inherits the project value.
Front matter is read from the source file rather than through
`app.env.metadata`. docutils treats `authors` as a bibliographic field,
so a value routed through that path arrives smart-quoted and split on
commas, and in a different shape again once `language` is set to a locale
whose bibliographic fields do not include `authors`. A feature whose
purpose is non-English editions cannot sit on a code path that changes
type when you set `language`. Verified identical across en, zh_CN, fa, es
and ja builds.
For the same reason front matter is stricter than `html_theme_options`:
only the documented list-of-mappings form counts as an override. A page
already carrying an `authors` value written for docutils or for
nbformat's notebook schema keeps the project credit instead of having it
rendered badly or dropped.
Author links now carry `rel="author"`; translator links deliberately do
not, and the two lines carry distinct classes so downstream CSS can tell
them apart. `page-header.js` no longer returns early when a page has no
authors paragraph, which is newly possible, so the landing page keeps the
styling paragraph and its accent border.
Part of the cross-theme attribution work tracked in QuantEcon/meta#360.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #427 +/- ##
=======================================
Coverage ? 56.30%
=======================================
Files ? 2
Lines ? 547
Branches ? 0
=======================================
Hits ? 308
Misses ? 239
Partials ? 0
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Pull request overview
This PR adds first-class translator attribution to the QuantEcon Book Theme, mirroring the existing authors byline while supporting per-page overrides via MyST/notebook front matter and preserving backwards-compatible output for sites that don’t configure the new options.
Changes:
- Added
translators/translators_labeltheme options (plusauthors_label) and rendered translators as a distinct, labelled byline under the page title. - Implemented front-matter reading from source files (Markdown YAML block / notebook metadata) and resolution logic so page-level values replace project-level values, with explicit empty lists suppressing output.
- Added styling for translators, adjusted landing-page header JS behavior, and introduced a comprehensive test suite for attribution behavior.
Reviewed changes
Copilot reviewed 13 out of 13 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
tests/test_translators.py |
New unit + end-to-end Sphinx-build tests covering attribution normalization, resolution, and rendering. |
src/quantecon_book_theme/theme/quantecon_book_theme/theme.conf |
Declares new theme options and defaults (authors_label, translators, translators_label). |
src/quantecon_book_theme/theme/quantecon_book_theme/layout.html |
Renders authors/translators blocks and adds rel="author" to author links. |
src/quantecon_book_theme/assets/styles/_page.scss |
Adds translators byline styling (spacing, font size, color). |
src/quantecon_book_theme/assets/styles/_dark-theme.scss |
Sets dark-mode translators text color via --qe-dark-text-muted. |
src/quantecon_book_theme/assets/scripts/page-header.js |
Ensures landing page styling paragraph is inserted even when authors are absent/suppressed. |
src/quantecon_book_theme/__init__.py |
Adds normalization + front-matter reading/caching and context resolution for authors/translators and labels. |
pyproject.toml |
Registers the new build pytest marker. |
docs/user/index.md |
Links new “Authors and Translators” user guide page. |
docs/user/configuration.md |
Documents the new translators configuration option. |
docs/user/authors.md |
New detailed documentation for authors/translators, labels, and per-page overrides. |
docs/developer/testing.md |
Documents the new attribution test module. |
CHANGELOG.md |
Notes the new feature and related fixes/behavior changes. |
Suppressed comments (2)
src/quantecon_book_theme/theme/quantecon_book_theme/layout.html:268
- Links opened with
target="_blank"should includerel="noopener noreferrer"to prevent reverse-tabnabbing. Since these author links already setrel, add the additional tokens here.
<a href="{{ author.url }}" rel="author" target="_blank"><span>{{ author.name }}</span></a>
src/quantecon_book_theme/theme/quantecon_book_theme/layout.html:270
- Links opened with
target="_blank"should includerel="noopener noreferrer"to prevent reverse-tabnabbing. Since these author links already setrel, add the additional tokens here.
<a href="{{ author.url }}" rel="author" target="_blank"><span>{{ author.name }}</span></a>,
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
🎭 Visual Regression Test ResultsDetails
Skipped testsdesktop-chrome › theme.spec.ts › Visual Regression Tests › prob-matrix - full page screenshot |
Any explicitly empty front matter value -- an empty list, a bare key parsing to null, or an empty string -- suppresses the attribution block on that page. Only the empty-list form was documented and tested, so the other two read as accidental. They are not: all three say "nobody", as distinct from a value this theme cannot read, which is left alone so the project-level credit still renders. An empty string in particular is what an interpolated template variable leaves behind. Raised by Copilot on #427. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Stacking the translators under the authors made the page header four rows tall. They now sit right-aligned on the same line as the "Last changed" control, sharing its accent rule, so crediting translators costs the header no extra vertical space. On narrow screens the two stack instead. The flex wrapper carrying the rule is emitted only when there are translators, so the accent border stays on the button and the markup is unchanged for every site that does not set the option. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
# Conflicts: # CHANGELOG.md # docs/user/index.md # src/quantecon_book_theme/__init__.py
Points FIXTURES_SHA at the fixtures #2 branch head so the visual and preview builds exercise the new byline. The theme repo installs the PR's own theme before building fixtures, so the unreleased `translators` option resolves fine here. That PR's own self-check cannot go green yet: it builds against the latest *released* theme, which does not declare `translators`, and runs with --warningiserror. The announcement demo did not hit this because `announcement` is inherited from pydata_sphinx_theme and was already a valid option. Re-pin to the merge commit once this ships in a release. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
/update-snapshots |
|
✅ Regenerated visual snapshots and committed 83 changed file(s) to this PR. Built against fixtures ✅ Re-ran the suite against the new baselines — they reproduce. 📦 Download snapshot-update-diff artifact to review before/after images.
|
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sets `authors` and `translators` at project level so every fixture page carries the full attribution block and the visual snapshots in the theme repo cover it. The translator names are placeholders; the authors are the real QuantEcon ones so the byline reads like an actual book. `translators_label` is left at its "Translated by" default, which is what an edition gets before it localises the label. Demonstrates the theme option added in QuantEcon/quantecon-book-theme#427. Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Description
Adds a
translatorsoption, parallel to the existingauthors, taking a list of{name, url}entries and rendering them in the page header so translated editions can credit the people who produced them. Closes #426.Translators render behind a visible label, because two unlabelled name lists would be ambiguous. The label defaults to "Translated by" and is overridable via
translators_labelso each edition renders it in its own language. Authors keep their current label-free rendering — the matchingauthors_labelexists but defaults to empty — so a site that sets neither option renders byte-identical HTML.Either list can be overridden per page in MyST or notebook front matter. That is the case that motivated per-page support: translation is naturally per-lecture work, so the project-level option carries the default credit and each page names whoever actually produced it. A page value replaces the project value rather than merging with it, any explicitly empty value leaves the block out on that page (the way to mark a page with no human translator yet), and an absent key inherits the project value.
Part of the cross-theme attribution work tracked in QuantEcon/project-themes#3.
Placement
Authors keep the line directly under the page title. Translators sit one row lower, right-aligned on the same line as the "Last changed" control and sharing its accent rule, so crediting them costs the header no extra vertical space. The regenerated baselines confirm this: the header grew by 3px. On narrow screens the two stack instead.
The flex wrapper that carries the accent rule is emitted only when translators are set. The rule normally lives on the "Last changed" button itself, so moving it unconditionally would have changed markup for every existing site.
Why front matter is read from the source file
Front matter is read directly from the page's source rather than through
app.env.metadata. docutils treatsauthorsas a bibliographic field, so a value routed through that path comes back smart-quoted and split on commas — and in a different shape again oncelanguageis set to a locale whose bibliographic fields do not includeauthors. Three shapes for one key, selected by configuration the theme does not control. A feature whose whole purpose is non-English editions cannot sit on a code path that changes type when you setlanguage. Verified identical across en, zh_CN, fa, es and ja builds.For the same reason front matter is stricter than
html_theme_options: only the documented list-of-mappings form counts as an override.authorsis shared ground — docutils owns it as a bibliographic field and nbformat defines it in the notebook schema — so a page already carrying one written for something else keeps the project credit rather than having it rendered badly or silently dropped.Type of Change
Testing
tests/test_translators.pyadds 102 tests covering the theme.conf declarations, the template markup, the normalisation and resolution helpers as units, the front-matter readers, and end-to-end rendering through real Sphinx builds. Full suite: 216 passed.The backwards-compatibility claim was verified by diffing real builds of
tests/sites/baseagainstmain, with asset digests normalised since adding SCSS necessarily changes the bundle hash:mainauthors, notranslatorsauthorsconfiguredrel="author"on author anchors, nothing elseAlso verified: builds under
languageset to en, zh_CN, fa, es and ja all resolve page overrides identically; the docs site builds with only its three pre-existing warnings; the landing page keeps its styling paragraph and accent border when a page suppresses its authors (checked in Chromium, not just in the markup).Visual coverage
The fixtures config now sets
authorsandtranslators(fixtures QuantEcon/meta#2), so the byline is under snapshot protection rather than shipping untested.FIXTURES_SHAis bumped accordingly and 83 baselines were regenerated and verified to reproduce.The pin points at the fixtures QuantEcon/meta#2 branch head rather than a merge commit. That PR's own self-check builds against the latest released theme, which does not declare
translatorsand runs with--warningiserror, so it stays red until this ships in a release. The announcement banner did not hit this becauseannouncementis inherited from pydata_sphinx_theme and was already a valid option. Re-pin to the merge commit once released.Of the 83 changed baselines, 26 are
*-sidebar.png— those crop the left edge of the page and catch a sliver of the header, so they moved because the fixtures config swapped the plainauthorstring for linkedauthors, not because of any layout shift.Also in this PR
Author links now carry
rel="author", which they did not before. It is invisible on screen, so it moves no visual baseline and could otherwise slip past review as a no-op.An
authorsvalue given as a bare string used to be iterated character by character, emitting one empty anchor per character. Both lists now normalise a bare string, a list of strings, or a single mapping into the documented form. This is a silent behaviour change for anyone currently passing a bare string, and strictly better.page-header.jsno longer returns early when a page has no authors paragraph. That was previously impossible and is now reachable viaauthors: [], and the early return skipped inserting the paragraph that carries the landing page's accent border — which the function's own comment says should be inserted "even if no authors for styling".Follow-ups, deliberately not in this PR
Translators are not cloned onto the landing page, where only the authors line is moved up beneath the title. Doing so means a second paragraph plus relocating the accent border, which is a real design change. Documented as a limitation.
The list connector (
,andand) stays English regardless of the configured language, so a Chinese edition reads "A, B, and C" rather than "A、B、C". Only the labels are localisable today. Worth settling cross-theme in QuantEcon/project-themes#3 since all three themes will have the same gap.Copilot flagged missing
rel="noopener noreferrer"ontarget="_blank"links. There are seven such links in the template and none carries it, so it is a pre-existing repo-wide gap rather than something this PR introduces; deferred to a single sweep in #429 so the template stays internally consistent.Separately, #428 records a pre-existing bug found while working here: Sphinx 7.4+ changed its
authorplaceholder fromunknowntoAuthor name not set, and the theme's guard still tests for the old value, so a site setting neitherauthorsnorauthorprints that string in every page header. This PR touches the adjacent conditional but neither introduces nor fixes it.Checklist
docs/user/authors.md,configuration.md, testing docs, CHANGELOG)🤖 Generated with Claude Code