Localization
Localization is opt-in. Add a localization block to _config.yml; without it, Jigyll uses its ordinary single-site build.
url: https://example.test
baseurl: /guide
localization:
default_language: en
locales:
en:
tag: en
label: English
de:
tag: de-DE
label: Deutsch
fallbacks: [en]
Locale keys are lowercase URL-safe project identifiers. Tags are explicit BCP 47 tags. The default locale owns root routes; other locales are prefixed by their key. Set default_language_in_subdir: true to prefix the default locale too.
Content editions
Use lang to assign an edition and translation_key to relate editions. A missing lang uses the default locale. translation_key is optional, but must be a non-empty string when present.
---
lang: de
translation_key: getting-started
permalink: /erste-schritte/
---
Translation keys are scoped to pages or to one collection. Jigyll never substitutes default-language page content for a missing edition: unavailable editions are omitted from routes, lists, feeds, and language selectors.
Required translations
Set required_translations to make coverage of selected locale keys a build policy. The option is opt-in: omit it, or set it to [], to keep the existing permissive catalog behavior. Each target is a configured, non-default locale key—not a BCP 47 tag or a label.
In this project, French is required and Danish is optional:
localization:
default_language: en
locales:
en: { tag: en, label: English }
fr: { tag: fr, label: Français }
da: { tag: da, label: Dansk }
required_translations: [fr]
An included English edition with translation_key: guide needs an included French edition with the same key in the same namespace (pages or one collection):
---
lang: en
translation_key: guide
---
---
lang: fr
translation_key: guide
---
An included Danish guide edition is allowed, but it neither creates nor satisfies the required French edition. A translation set with no included English edition is also allowed.
The included default-locale edition owns each coverage obligation. For a deliberate exception, put translation_exempt on that edition and name the required locale key:
---
lang: en
translation_exempt: [fr]
---
This keyless English document is valid because French is its only required target. With more required targets, its exemption list must name all of them; a keyed document may exempt only selected targets. An exemption is not valid on a non-default edition, for an optional or unknown locale, more than once, or when an included sibling already provides that locale.
Only included, non-static documents participate. Existing exclusion, show_drafts, future, and unpublished settings decide inclusion for the active build, so hidden drafts and future or unpublished documents do not block a normal build. When the build includes them, they must meet the same policy. A missing required edition fails the build; Jigyll never publishes fallback default-language page content at that locale's route.
Data and messages
Shared _data remains visible in every locale. Put locale modules below _data/locales/<locale>/; their filenames become data keys and overlay shared data through the locale fallback chain.
_data/
settings.yml
locales/
en/messages.yml
de/messages.yml
de/settings.yml
messages.yml supplies the translate filter. Message keys are dotted paths; missing messages fail the build unless missing_messages: key is configured.
{{ "nav.home" | translate }}
{{ site.data.settings.title }}
Liquid contract
site.language is the active locale, site.languages is the configured, deterministically ordered locale list, and site.default_language is the default locale. Locale values expose key, tag, label, direction, weight, and default.
Pages expose page.language, page.translation_key, page.translations, page.all_translations, and canonical page.alternates. translations excludes the current edition; all_translations includes it.
Use translation for an edition lookup and localized_url for a page or known content route. localized_url preserves query strings and fragments. It leaves external URLs, fragments, and shared assets unchanged, and rejects unknown internal routes rather than guessing a locale prefix.
{% assign german = page | translation: "de" %}
{% if german %}<a href="{{ german.url }}">Deutsch</a>{% endif %}
<a href="{{ "/about/" | localized_url: "de" }}">Über uns</a>
Localized builds validate every route before publishing. Output is rendered to a sibling staging directory and promoted only after the complete generation succeeds; a failed localized build leaves the previous destination intact.