Skip to content

Add a language-aware 404 page — the switcher can link to pages an edition does not have #421

Description

@mmcky

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions