Context
The language switcher shipped across the lecture-python-programming series today — English plus fa, fr and zh-cn, all four live and cross-linking. See QuantEcon/lecture-python-programming#490 and its three counterparts.
The theme builds every switcher link and every hreflang alternate as {language_url}/{pagename}.html, unconditionally, for every configured language. It has no notion of whether a page exists in a given edition, and no way to acquire one — it is a presentation layer with no access to what other sites contain.
So whenever the editions diverge, the switcher offers links that 404. That is not a hypothetical: polars was added to the English source on 2026-07-30 and was 404 on all four sites until they were published together earlier today. Translation review is fast (sync PRs merge within the hour), but a new lecture still exists in English before it exists anywhere else, and editions do not publish in lockstep.
Proposal
The theme ships no 404 template at all today — src/quantecon_book_theme/theme/quantecon_book_theme/ contains only layout.html, static and theme.conf. Add one, and make it language-aware: when a reader lands on a page this edition does not have, recognise the path and offer the same lecture in the languages that do have it, starting with English.
Why this is the right layer
It was tempting to solve this by suppressing the links at the source — have each site emit a switcher entry only for pages the target edition actually has. That needs per-language page coverage computed somewhere, shipped into every repo, and kept fresh; and "does the target have this page" really means "has the target published it", which is the part that changes most often. I opened QuantEcon/action-translation#239 along those lines and then rewrote it after measuring, because the cost is disproportionate to a window that is usually hours.
A 404 page inverts the problem and is strictly cheaper:
- No cross-repo coordination. Each site knows its own page set perfectly, at build time, with no manifest and no staleness.
- Correct by construction. It cannot advertise a page that does not exist, because it only runs when one does not.
- Wider catchment. It also helps readers arriving from search results, bookmarks and shared links — none of which the switcher touches, and all of which outnumber switcher clicks.
- Useful to every site using the theme, not only the translated ones.
Design questions worth settling first
- How does the page know which languages exist? The simplest answer is the
languages list already in html_theme_options — it is right there, and the 404 page can offer all of them and let the reader pick, without needing to know which actually has the page. Optimistic links are acceptable here in a way they are not in hreflang, because the reader has already landed on an error page and any onward link is an improvement.
- What does it say when the theme has no
languages configured? It should degrade to an ordinary, useful 404 rather than assuming a translated context.
- Localisation. The 404 text on the
fa site should presumably be in Farsi, which means the strings need to come from somewhere — possibly language/current_language, possibly a new option. RTL applies on fa too.
- GitHub Pages serves
404.html from the site root, which suits these repos; anyone hosting elsewhere may need different wiring. Worth confirming Sphinx emits it where each host expects.
Not urgent
Nothing is broken right now — all four editions are in sync as of today. This matters at the next divergence, so it is worth doing before the next new lecture rather than after.
Context
The language switcher shipped across the
lecture-python-programmingseries today — English plusfa,frandzh-cn, all four live and cross-linking. See QuantEcon/lecture-python-programming#490 and its three counterparts.The theme builds every switcher link and every
hreflangalternate as{language_url}/{pagename}.html, unconditionally, for every configured language. It has no notion of whether a page exists in a given edition, and no way to acquire one — it is a presentation layer with no access to what other sites contain.So whenever the editions diverge, the switcher offers links that 404. That is not a hypothetical:
polarswas added to the English source on 2026-07-30 and was 404 on all four sites until they were published together earlier today. Translation review is fast (sync PRs merge within the hour), but a new lecture still exists in English before it exists anywhere else, and editions do not publish in lockstep.Proposal
The theme ships no 404 template at all today —
src/quantecon_book_theme/theme/quantecon_book_theme/contains onlylayout.html,staticandtheme.conf. Add one, and make it language-aware: when a reader lands on a page this edition does not have, recognise the path and offer the same lecture in the languages that do have it, starting with English.Why this is the right layer
It was tempting to solve this by suppressing the links at the source — have each site emit a switcher entry only for pages the target edition actually has. That needs per-language page coverage computed somewhere, shipped into every repo, and kept fresh; and "does the target have this page" really means "has the target published it", which is the part that changes most often. I opened QuantEcon/action-translation#239 along those lines and then rewrote it after measuring, because the cost is disproportionate to a window that is usually hours.
A 404 page inverts the problem and is strictly cheaper:
Design questions worth settling first
languageslist already inhtml_theme_options— it is right there, and the 404 page can offer all of them and let the reader pick, without needing to know which actually has the page. Optimistic links are acceptable here in a way they are not inhreflang, because the reader has already landed on an error page and any onward link is an improvement.languagesconfigured? It should degrade to an ordinary, useful 404 rather than assuming a translated context.fasite should presumably be in Farsi, which means the strings need to come from somewhere — possiblylanguage/current_language, possibly a new option. RTL applies onfatoo.404.htmlfrom the site root, which suits these repos; anyone hosting elsewhere may need different wiring. Worth confirming Sphinx emits it where each host expects.Not urgent
Nothing is broken right now — all four editions are in sync as of today. This matters at the next divergence, so it is worth doing before the next new lecture rather than after.