Skip to content

feat: add translators theme option alongside authors - #427

Merged
mmcky merged 7 commits into
mainfrom
feature/translators
Aug 25, 2026
Merged

mmcky merged 7 commits into
mainfrom
feature/translators

Conversation

@mmcky

@mmcky mmcky commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

Description

Adds a translators option, parallel to the existing authors, 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_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. 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 treats authors as a bibliographic field, so a value routed through that path comes back 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. 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 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. authors is 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

  • New feature
  • Documentation update
  • Bug fix (two incidental fixes, noted below)
  • Breaking change

Testing

tests/test_translators.py adds 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/base against main, with asset digests normalised since adding SCSS necessarily changes the bundle hash:

Configuration HTML diff vs main
No authors, no translators none — every page byte-identical
authors configured rel="author" on author anchors, nothing else

Also verified: builds under language set 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 authors and translators (fixtures QuantEcon/meta#2), so the byline is under snapshot protection rather than shipping untested. FIXTURES_SHA is 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 translators and runs with --warningiserror, so it stays red until this ships in a release. The announcement banner 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 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 plain author string for linked authors, 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 authors value 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.js no longer returns early when a page has no authors paragraph. That was previously impossible and is now reachable via authors: [], 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 (, and and) 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" on target="_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 author placeholder from unknown to Author name not set, and the theme's guard still tests for the old value, so a site setting neither authors nor author prints that string in every page header. This PR touches the adjacent conditional but neither introduces nor fixes it.

Checklist

  • Tests pass locally (216 passed)
  • Pre-commit checks pass (black, flake8)
  • Documentation updated (new docs/user/authors.md, configuration.md, testing docs, CHANGELOG)
  • Visual baselines regenerated and verified
  • No breaking changes

🤖 Generated with Claude Code

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>
Copilot AI lite review requested due to automatic review settings August 25, 2026 01:22
@github-actions

github-actions Bot commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

@github-actions
github-actions Bot temporarily deployed to pull request August 25, 2026 01:23 Inactive
@codecov

codecov Bot commented Aug 25, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 81.81818% with 16 lines in your changes missing coverage. Please review.
⚠️ Please upload report for BASE (main@1c79031). Learn more about missing BASE report.

Files with missing lines Patch % Lines
src/quantecon_book_theme/__init__.py 81.81% 16 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff           @@
##             main     #427   +/-   ##
=======================================
  Coverage        ?   56.30%           
=======================================
  Files           ?        2           
  Lines           ?      547           
  Branches        ?        0           
=======================================
  Hits            ?      308           
  Misses          ?      239           
  Partials        ?        0           
Flag Coverage Δ
pytests 56.30% <81.81%> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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_label theme options (plus authors_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 include rel="noopener noreferrer" to prevent reverse-tabnabbing. Since these author links already set rel, 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 include rel="noopener noreferrer" to prevent reverse-tabnabbing. Since these author links already set rel, 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.

Comment thread src/quantecon_book_theme/__init__.py
Comment thread src/quantecon_book_theme/theme/quantecon_book_theme/layout.html
Comment thread src/quantecon_book_theme/theme/quantecon_book_theme/layout.html
@github-actions

github-actions Bot commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

🎭 Visual Regression Test Results

passed  103 passed
skipped  3 skipped

Details

stats  106 tests across 1 suite
duration  4 minutes, 3 seconds
commit  57beec9

Skipped tests

desktop-chrome › theme.spec.ts › Visual Regression Tests › prob-matrix - full page screenshot
mobile-chrome › theme.spec.ts › Visual Regression Tests › prob-matrix - full page screenshot
mobile-chrome › theme.spec.ts › Theme Features › f-string interpolation styling

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>
@github-actions
github-actions Bot temporarily deployed to pull request August 25, 2026 02:58 Inactive
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>
mmcky and others added 2 commits August 25, 2026 13:35
# 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>
@github-actions
github-actions Bot temporarily deployed to pull request August 25, 2026 03:36 Inactive
@mmcky

mmcky commented Aug 25, 2026

Copy link
Copy Markdown
Contributor Author

/update-snapshots

@github-actions

Copy link
Copy Markdown
Contributor

✅ Regenerated visual snapshots and committed 83 changed file(s) to this PR.

Built against fixtures QuantEcon/quantecon-book-theme-fixtures@ab9ba206d48870e86b822c74380546e42fcba299.

✅ Re-ran the suite against the new baselines — they reproduce.

📦 Download snapshot-update-diff artifact to review before/after images.

⚠️ The commit was pushed with GITHUB_TOKEN, which does not trigger workflows — push an empty commit to re-run CI against the new baselines. (Set a SNAPSHOT_BOT_TOKEN secret to make this automatic.)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@github-actions
github-actions Bot temporarily deployed to pull request August 25, 2026 03:48 Inactive
@mmcky
mmcky merged commit 3b011cb into main Aug 25, 2026
12 checks passed
@mmcky
mmcky deleted the feature/translators branch August 25, 2026 04:18
mmcky added a commit to QuantEcon/quantecon-book-theme-fixtures that referenced this pull request Aug 25, 2026
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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add translator attribution alongside the existing authors option

2 participants