Merged the template branch into main to pick up the 7 upstream changes.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -39,6 +39,10 @@ RUN export DEBIAN_FRONTEND=noninteractive DEBCONF_NONINTERACTIVE_SEEN=true \
|
||||
&& apt-get install -y libjemalloc-dev \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Pin git to HTTP/1.1 for the dependency clones. GitHub answers the git-upload-pack POST with a 401 when it is sent
|
||||
# over HTTP/2 by the git 2.43 that Noble ships, which SPM reports as a clone failure asking for a username.
|
||||
RUN git config --global http.version HTTP/1.1
|
||||
|
||||
# Set up a build area
|
||||
WORKDIR /build
|
||||
|
||||
|
||||
@@ -60,8 +60,8 @@ Four of those are page-authored and optional. `IndexPage` supplies `canonicalURL
|
||||
| --- | --- | --- |
|
||||
| `summary` | `<meta name="description">` | The page's one-line description. |
|
||||
| `canonicalURL` | `<link rel="canonical">` | Absolute URL. `IndexPage` derives it from `site.origin` and the page's own language; an unset origin omits it (see [Language editions](#language-editions)). |
|
||||
| `socialCard` | Open Graph + Twitter `<meta>` tags | A `SocialCard` — title, summary, URL, site name, locale, share image. Scrapers require absolute URLs, so the page composes them from its own origin; `Page+Defaults` supplies the locale as `ogLocale`. |
|
||||
| `structuredData` | `<script type="application/ld+json">` | A `StructuredData` graph of schema.org nodes; `StructuredData(name:url:logo:profiles:)` builds the site-wide `Organization` + `WebSite` pair. The payload is an inert data block, so the `Content-Security-Policy` does not apply to it. |
|
||||
| `socialCard` | Open Graph + Twitter `<meta>` tags | A `SocialCard` — title, summary, URL, site name, locale, alternate locales, share image. Scrapers require absolute URLs, so the page composes them from its own origin; `Page+Defaults` supplies the locale as `ogLocale`. |
|
||||
| `structuredData` | `<script type="application/ld+json">` | A `StructuredData` graph of schema.org nodes; `StructuredData(name:url:logo:inLanguage:profiles:)` builds the site-wide `Organization` + `WebSite` pair, `inLanguage` declaring the languages the site publishes in (see [Language editions](#language-editions)). The payload is an inert data block, so the `Content-Security-Policy` does not apply to it. |
|
||||
|
||||
The fifth, `analytics`, is *configuration*-authored rather than page-authored: the executable builds an `Analytics` from the `analytics.*` keys and hands it to `RootController` and `NotFoundMiddleware`, which pass it to both pages. It renders as a `<link rel="preconnect">` plus a deferred `<script>` carrying the [Umami](https://umami.is) `data-` attributes, and — unlike the structured data — it *is* executable, so the `Content-Security-Policy` must allow its origin. It is empty by default; see [Analytics](#analytics) for how to turn it on.
|
||||
|
||||
@@ -85,6 +85,8 @@ The catalog's source language is the **default** and owns the site's bare paths;
|
||||
|
||||
Given a `site.origin`, each page then emits the `hreflang` alternates tying its editions together — one per language plus an `x-default` pointing at the default language's edition, whose bare URL negotiates the language and so is the right landing for everyone unmatched. A single-language site emits none: a set naming one edition tells a search engine nothing it cannot already see. `Page+Defaults`' `languageAlternates(origin:path:languages:)` takes the language set, so a page translated into only some of them narrows it rather than advertising an edition that does not exist.
|
||||
|
||||
The same set belongs in the site-wide structured data: `StructuredData`'s `inLanguage` declares it on the `WebSite` node, so a crawler reads the site's languages from the graph as well as from the alternates. A page's social card says the same to a scraper: its `locale` is the edition the page *is*, and `SocialCard`'s `alternateLocales` names the rest, each mapped through `ogLocales` the way `ogLocale` maps the page's.
|
||||
|
||||
`sitemap.xml` is the one part that does *not* follow the catalog: it is a static file, so a new language needs its editions added by hand — `/nl`, `/nl/<page>`, one `<loc>` each, alongside the default language's. Give each the same spelling the page's own canonical carries (the root is the bare origin, with no trailing slash), or the two disagree about which URL is canonical.
|
||||
|
||||
Visitors switch language two ways, both handled by `LocalizationMiddleware` ahead of the routes: a `?lang=` query parameter (what a language switcher links to) and the leading path segment. Either beats `Accept-Language`; a value naming no supported language is ignored. The path segment matters beyond the routed pages — it is what makes an *unrouted* path under a language's prefix answer its not-found page in that language.
|
||||
|
||||
Reference in New Issue
Block a user