Who this is for. The developer planning a multi-language build. After this page you know how translations are stored, which record types have them, how to lay out language URLs, and how to build a switcher that keeps the visitor on the same content.
Language belongs in this unit because its mechanisms are the multi-brand ones: records linked to each other, URLs the project chooses, and rendering that respects the page cache. This page is the overview for the build decision; the detail is in Guide 2 and Guide 5, linked below.
A translation is a record of its own
A translated page is a separate page, with its own revisions, its own path and its own language. The translations are linked: one record is the source, and the others are its related records. Nothing else is shared between them, so each language is edited and published on its own, and each has its own cached copy because each has its own path. How the link is wired, and which record types have it, is on Translations: source and related records.
Which records have language versions
| Record | Language versions |
|---|---|
| Pages | Yes |
| Book pages | Yes |
| Blogs and blog posts | Yes |
| FAQ pages and questions | Yes |
| Books and units | No: the containers have none, while the book pages inside them do |
Language-aware URLs
A translated page's URL is its own path, like any other page's: the platform's routing adds no language prefix or language hostname of its own. Choose a convention at the start of the project, such as a parent page per language so that paths read /en/... and /es/..., and apply it consistently with ordinary pages and custom URLs. Because the language is then part of the path, the template reads the language from the record it renders, never from the visitor.
A language switcher that keeps the visitor's place
A switcher leads to the same content in the other language, not to that language's home page. getOtherLanguageVersions() on the page returns every language version, the current page included, keyed by language code, plus an x-default entry for the client's default language. It collects them from the current record, its related records and its source's related records, so it gives the same set from any version.
Print each version's own path with the shorthand fullPath, which calls the record's own method, and leave the switcher out when the list holds nothing beyond the current page and x-default: