Localization
plasmoid is multilingual by design. Each locale is a top-level folder under the
docs root, and the site publishes one subtree per locale at
/<version>/<locale>/.
Declaring locales
List your locales in plasmoid.toml, and mark one as the default:
[site]
title = "My Project"
default_locale = "en"
locales = ["en", "es"]
default_locale must appear in locales. The default locale defines the site’s
structure — its folder tree and nav ordering — and is the fallback for any
page another locale hasn’t translated yet.
Folder layout
Mirror the default locale’s structure under each locale folder:
docs/
en/
index.md
getting-started/quickstart.md
reference/configuration.md
es/
index.md
getting-started/quickstart.md # translated
# reference/configuration.md intentionally absent → falls back to en
Per-page fallback
Navigation is built from the default locale, so the sidebar is identical across languages. For each page, plasmoid serves the locale-specific file when it exists and otherwise falls back to the default locale’s file. You can translate incrementally — an untranslated page shows the default-locale content rather than 404ing.
Switching languages
The chrome includes a locale switcher that links the equivalent path in each
configured language. Combined with per-locale URLs (/1.0/en/…, /1.0/es/…),
readers move between languages without losing their place.
What gets localized
Localizing a site is more than the page text. plasmoid handles three layers:
- Page content — the
.mdfiles (with per-page fallback, above). - Section titles — sidebar group labels, from a per-locale
_category.toml(the default locale supplies the ordering; each locale supplies its own titles). - Interface strings — the fixed labels the chrome renders around your content (search box, switchers, “On this page”, “Last updated”). These ship built in, with English as the fallback for any locale without its own table.
Because the interface strings are localized, the two generated chrome pages are emitted once per locale too:
- The not-found page —
/<locale>/404.html(plus a root/404.htmlin the default locale). The deploy recipe serves the localized page that matches the request’s URL prefix; see the nginx recipe. - The version index —
/<locale>/versions/(plus a stable root/versions/in the default locale, which existing links keep using). Each locale’s table links the same version in that locale.
Automatic language selection
When a site has more than one locale, plasmoid ships a tiny script
(/assets/locale.js, loaded only on multi-locale sites) that picks a language from
the visitor’s browser:
- On a reader’s first visit, it compares
navigator.languagesagainst your available locales (matching on the base language, soes-MXmatcheses) and, if one matches, sends them to the same page in that locale. - If no available locale matches, the reader stays on the default locale (English here) — the no-JavaScript fallback.
- Once a language is chosen — via the switcher or the step above — it is remembered
(
localStorage) and enforced on every page, so following a link back to a default-locale entry point (the brand, or/docs/) doesn’t silently drop it. Picking another language from the switcher always wins.
This is pure progressive enhancement: with JavaScript disabled, every URL still
resolves and the stable /docs/ entry always serves the default locale. Nothing
about the build is dynamic — the redirect happens client-side, on top of the same
static files.
Languages you don’t translate
You don’t have to hand-translate the whole world. Maintain the handful of locales
that deserve first-class, reviewed copy (here: English + Spanish) and let the
reader’s browser translate the rest on demand. Every modern browser offers a
one-click (or automatic) page translation, and plasmoid makes that reliable by
emitting honest lang attributes: a page is tagged with the language its content
is actually in. So a page that has fallen back to English is lang="en" even under a
non-English URL, which is exactly what makes the browser offer to translate it.
There is deliberately no built-in runtime translation widget — that would mean a runtime dependency and network calls, against plasmoid’s static, owned model. The browser already does it better, for every language, for free.
The /docs/ alias
The stable /docs/ entry alias points at the default locale of the current
version. Deep links into other locales use their explicit
/<version>/<locale>/… paths.