Skip to content
GitHub

Content & Localisation#

Content is plain markdown under your content directory (Content/ by convention). The directory structure is up to you; navigation references files by their path.

Translations#

Translations use a locale suffix on the filename:

Content/
├── index.md          # default language (e.g. English)
├── index.de.md       # German translation of the home page
└── guides/
    ├── configuration.md
    └── configuration.de.md

index.md and index.de.md share the same logical path (index.md), which is what navigation references. You never put the locale in a Page(...) path — Kiln resolves the right file per language.

Fallback#

When a page has no translation for a language, Kiln falls back to the default language’s content and shows a small “translation unavailable” banner — the equivalent of mkdocs-static-i18n’s fallback_to_default: true.

Try it

Most pages on this very site aren’t translated into German. Switch the language with the picker in the header and you’ll see the fallback banner in action, with the navigation and UI fully localised around the English body.

The default language is built at the site root; other languages live under /<locale>/:

site/
├── index.html              # default language
├── de/
│   └── index.html          # German
└── …

Interface strings#

The theme’s own UI strings (search box, navigation labels, error page, …) are localised per language via LocalisationConfiguration. Any string left unset falls back to Kiln’s built-in English default:

.init(.german, localisation: .init(
    searchPlaceholder: "Suchen",
    searchNoResults: "Keine Ergebnisse gefunden",
    tableOfContentsTitle: "Auf dieser Seite",
    previousPage: "Zurück",
    nextPage: "Weiter",
    editPage: "Diese Seite bearbeiten",
    notFoundTitle: "Seite nicht gefunden"
    // … and more; see LocalisationConfiguration
))

The same configuration also carries optional labels for marketing-style navigation and footers — home, store, blog, community, resources, the theme/language/version picker labels, and more — for custom themes that render them with #(strings.home). Kiln’s bundled theme doesn’t use these, so they’re purely opt-in; each falls back to its English default when unset.

Section and page titles are translated per language via each Language’s navTranslations map (keyed on the default-language title), and a language can override the whole siteName:

.init(
    .german,
    siteName: "Meine Doku",
    navTranslations: ["Guides": "Anleitungen", "Welcome": "Willkommen"]
)

Theme-defined strings#

LocalisationConfiguration covers Kiln’s built-in chrome, but a custom theme often needs strings of its own — a tagline, a “Join our chat” link, a call to action. Define those per language in customStrings and look them up in a template with the #localise("key") tag:

.init(.english, isDefault: true, customStrings: [
    "tagline": "Type-safe documentation sites, built in Swift.",
])

.init(.german, customStrings: [
    "tagline": "Typsichere Dokumentations-Websites, gebaut in Swift.",
])
<p class="tagline">#localise("tagline")</p>

A key missing from a language falls back to the default language’s value, so you can translate incrementally; a key that’s unknown everywhere renders as the key itself, making missing translations easy to spot. This site’s own footer (Theme/templates/partials/footer.leaf) uses #localise("tagline") — switch the language and watch the tagline change with it.

hreflang & the language switcher#

For every page, Kiln emits <link rel="alternate" hreflang="…"> tags for each language and renders a language switcher in the header, so search engines and readers can find the right translation.

Edit this page