Multi-Language Sites [DONE] `PL-F1809`
I korthet
Sites can publish parallel content in 43+ FIPJP languages, with per-page translation, a language switcher in navigation, a configurable default language per site, a translation workflow that flags pages needing work with source diffs, and hreflang tags plus xhtml:link sitemap alternates emitted automatically for SEO. Editors translate page-by-page, partial coverage falls back politely, and visitors land in their language via URL prefix, Accept-Language header or remembered preference.
Så fungerar det
Multi-language support is built into the CmsPage model. Each page has a base language (`source_language`) and a translations map keyed by ISO locale (`sv`, `fr`, `de`, …) containing localized title, slug, meta and a translated copy of the block array. The CmsSite declares supported_languages and default_language; pages can be translated into any subset of the site's supported list, and partial coverage is allowed — pages without a target translation fall back to default with a polite notice for visitors who chose another language.
Localized URLs follow a `/<locale>/...` pattern except the default language, which uses clean root paths to keep canonical URLs stable. The renderer detects visitor language via the URL prefix first, then Accept-Language headers, then a sessionStorage preference; the language switcher in the navigation lets visitors change explicitly and remembers the choice across pages. The translation workflow surfaces a queue per site: when a source page is updated, every translation is automatically flagged 'needs review' with a diff against the previous source version, so translators see exactly what changed.
Translators can be different OrgNodeMembers from editors and have a `cms:translate` capability that lets them edit translations without unlocking the source. SEO hreflang tags are emitted for every available translation plus an `x-default` pointing to the site default; the sitemap includes `xhtml:link` hreflang alternates so Google indexes each language correctly. CMS-search respects the active locale and only returns results from the matching language version, with a setting to fall back to default-language matches when no localized hit exists.
Centrala funktioner
- Parallel page versions per ISO locale with localized title, slug, meta and blocks
- Per-site default and supported language configuration
- Localized `/<locale>/...` routing with clean root paths for default language
- Language switcher with sessionStorage memory and Accept-Language fallback
- Translation queue with source-diff to show what changed since last review
- Separate `cms:translate` capability for translator roles
- hreflang tags and sitemap alternates for SEO across all languages
I praktiken
Anneli at the Finnish Federation maintains the federation site in Finnish, Swedish and English. She updates the membership-fees page in Finnish to reflect new prices. The translation queue immediately flags the Swedish and English copies as 'needs review' with a side-by-side diff showing exactly the three numbers and one paragraph that changed.
She forwards the queue link to the federation's volunteer translator who edits the Swedish version that evening; the English version gets done two days later. Until then, visitors who land on the English page see the Finnish content with a 'translation in progress' badge, and Google indexes only the Finnish version because the English hreflang is suppressed for unfinished pages.
Features i detta subsystem
5| ID | Status | Funktioner |
|---|---|---|
| F18.09.01 | Levererad | Multi-language page content (parallel versions per language) ✅ PL-F1809 |
| F18.09.02 | Levererad | Language switcher in navigation ✅ PL-F1809 |
| F18.09.03 | Levererad | Default language per site ✅ PL-F1809 |
| F18.09.04 | Levererad | Translation workflow (flag pages needing translation) ✅ PL-F1809 |
| F18.09.05 | Levererad | hreflang tags for SEO ✅ PL-F1809 |