Localization
Ship your docs in any language. Every string the theme renders is overridable from config.
Compose renders two kinds of text: your content, and the theme's own chrome, meaning navigation labels, search status, the code-block controls, the 404 page. Your content is already in whatever language you wrote it in. The chrome is overridable from config, so a site in German, Japanese, or Swahili needs no changes to theme source.
Setting the language
Set lang to a BCP-47 tag. It lands on <html lang> and drives date formatting through
Intl.DateTimeFormat, so month names localise automatically.
export const config = defineThemeConfig({
lang: "de",
dates: { blog: "long", default: "medium" },
});TypeScriptBecause dates go through Intl, setting lang alone gets you localised month and day
names. The Hugo theme took Go layout strings for this; the web platform does it for free.
Translating the chrome
Supply strings with the keys you want to change. It's a partial override merged over the
built-in English dictionary, so you can translate incrementally. Anything you omit keeps
its English value rather than rendering blank.
export const config = defineThemeConfig({
lang: "de",
strings: {
search_field_placeholder: "Suchen",
to_top: "Nach oben",
in_this_section: "In diesem Abschnitt",
no_results_for: "Keine Ergebnisse für „{q}“",
},
});TypeScriptKeys containing {q} or {n} are templates, and the placeholders are substituted at render
time with the query and the result count. Keep them in your translation; drop one and the
value simply won't appear.
The full key list lives in @compose/i18n. It's a typed interface, so your editor will
complete the keys and flag typos.
Why there are no bundled translations
Compose ships one maintained dictionary, English, plus this override hook, rather than a set of pre-translated locales. That's a deliberate choice, and it comes from watching the alternative fail.
The Hugo theme accepted German, Spanish, Esperanto, and Turkish translations as drive-by contributions. They rotted. By the end, the Turkish file's "back to top" string read "Retour au sommet": French, in the Turkish translation, for years, because nobody who could review it was looking. Worse, every string this port added (the 404 page, section listings, the snippet controls, search status) had no upstream translation at all. Bundling locales would mean either inventing values nobody on the project can review, or shipping a half-English interface to someone who chose their language on purpose.
A localised site supplies its own strings and gets a wholly consistent interface, reviewed by the only people qualified to review it: the ones who speak the language.
What isn't included
Multi-locale routing is not part of the theme. There are no parallel language trees
(/en/…, /de/…), no language switcher, and no per-page translation fallback. Compose
localises a site, not between sites.
If you need parallel translations of the same docs, both Astro and Next.js support this at the framework level and Compose won't fight you, but you'll be wiring the routing and the switcher yourself, and the sidebar tree is derived per-content-directory, so expect to do real work.
If parallel language trees are a hard requirement for your project, say so. It's on the roadmap behind demand, not behind difficulty.