plasmoid
EN

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 .md files (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.html in 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.languages against your available locales (matching on the base language, so es-MX matches es) 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.

Last updated: 2026-06-26