Multi-Language
Add translations to your site with filename-based i18n — per-language URLs, RSS, sitemaps, and discovery files.
Overview
page uses a filename-based translation system. It's fully backward compatible — single-language sites work identically with no configuration.
How It Works
Default language content uses plain filenames:
content/posts/hello-world.md → /posts/hello-world
content/pages/about.md → /about
Translations add a language suffix before the extension:
content/posts/hello-world.es.md → /es/posts/hello-world
content/pages/about.es.md → /es/about
Items with the same slug across languages are automatically linked as translations.
Configuration
Enable multi-language support by adding language sections to page.toml:
[site]
language = "en"
title = "My Site"
[languages.es]
title = "Mi Sitio"
description = "Un sitio web estático"
[languages.fr]
title = "Mon Site"
description = "Un site web statique"
Each language can override title and description. The default language is set in [site].language.
Creating Translations
Use the --lang flag with page new:
page new post "Hello World" # English (default) page new post "Hola Mundo" --lang es # Spanish translation
Or create files manually — the language suffix must match a configured language code:
about.md → English (default)
about.es.md → Spanish
about.fr.md → French
about.xx.md → Ignored (xx not configured)
Per-Language Output
When multi-language is enabled, page generates per-language versions of:
| Output | Default language | Other languages |
|---|---|---|
| Index page | dist/index.html | dist/{lang}/index.html |
| RSS feed | dist/feed.xml | dist/{lang}/feed.xml |
| LLM discovery | dist/llms.txt | dist/{lang}/llms.txt |
| Search index | dist/search-index.json | dist/{lang}/search-index.json |
| Sitemap | dist/sitemap.xml (all languages, with alternates) |
URL Structure
Non-default languages get a /{lang}/ prefix:
/posts/hello-world # English
/es/posts/hello-world # Spanish
/fr/posts/hello-world # French
hreflang Tags
All bundled themes automatically emit <link rel="alternate" hreflang="..."> tags when translations exist, helping search engines serve the right language.
Language Switcher
Bundled themes include a language switcher UI when translations is non-empty. It shows links to all available translations of the current page.
Template Variables
| Variable | Description |
|---|---|
{{ lang }} | Current page language code |
{{ translations }} | Array of {lang, url} for available translations |
{{ site.language }} | Default site language |
Use in templates:
{% if translations %} <nav class="lang-switcher"> {% for t in translations %} {% if t.lang == lang %} <strong>{{ t.lang }}</strong> {% else %} <a href="{{ t.url }}">{{ t.lang }}</a> {% endif %} {% endfor %} </nav> {% endif %}