Skip to content

feat: add translators theme option alongside authors - #427

Open
mmcky wants to merge 1 commit into
mainfrom
feature/translators
Open

feat: add translators theme option alongside authors#427
mmcky wants to merge 1 commit 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 below the page title so translated editions can credit the people who produced them. Closes #426.

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. 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, an explicit empty list 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/meta#360.

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 (one incidental fix, noted below)
  • Breaking change

Testing

New tests/test_translators.py (98 tests) covers 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: 180 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).

Screenshots

The header with both lines, project-level authors plus translators, and per-page localised labels (作者 / 译者):

Translators Smoke documentation
作者 Tom Sargent and John Stachurski
译者 Zhang San, Li Si, and Wang Wu

Authors render at the existing size and colour; translators sit below at 0.95rem in a muted tone (#6a6a6a, 5.3:1 on white) with --qe-dark-text-muted in dark mode. Labels are deliberately not italicised — italic on CJK text triggers synthetic oblique, which is exactly the case this feature exists for.

Nothing moves for a site that does not set the new options, so no visual baselines change.

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 snapshot 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/meta#360 since all three themes will have the same gap.

No fixtures demo is included. Adding translators to the fixtures _config.yml would give a live preview and visual coverage but invalidates a large share of the visual baselines, so it is better done on its own.

Checklist

  • Tests pass locally (180 passed)
  • Pre-commit checks pass (black, flake8)
  • Documentation updated (new docs/user/authors.md, configuration.md, testing docs, CHANGELOG)
  • 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

Copy link
Copy Markdown
Contributor

@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@ed251e9). 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        ?   53.62%           
=======================================
  Files           ?        2           
  Lines           ?      511           
  Branches        ?        0           
=======================================
  Hits            ?      274           
  Misses          ?      237           
  Partials        ?        0           
Flag Coverage Δ
pytests 53.62% <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 on lines +377 to +378
if value is None or (isinstance(value, (list, tuple, str)) and not value):
return []
{% for author in theme_authors %}
{% if loop.last and theme_authors|length >= 2 %}
and <a href="{{ author.url }}" target="_blank"><span>{{ author.name }}</span></a>
and <a href="{{ author.url }}" rel="author" target="_blank"><span>{{ author.name }}</span></a>
{%- if theme_translators_label %}<span class="qe-page__header-translators-label">{{ theme_translators_label }}</span> {% endif -%}
{%- for translator in theme_translators -%}
{%- if not loop.first %}{% if loop.last %}{% if theme_translators|length > 2 %},{% endif %} and {% else %}, {% endif %}{% endif -%}
{%- if translator.url %}<a href="{{ translator.url }}" target="_blank"><span>{{ translator.name }}</span></a>{% else %}<span>{{ translator.name }}</span>{% endif -%}
@github-actions

Copy link
Copy Markdown
Contributor

🎭 Visual Regression Test Results

passed  103 passed
skipped  3 skipped

Details

stats  106 tests across 1 suite
duration  3 minutes, 53 seconds
commit  5ee9e51

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

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