On this page
Multi-language Sites
Publish your documentation in several languages from one mkdocs.yml.
New in MkDocs NG 1.11
List the languages under languages. The first
one is the default language: it is built at the root of the site, and every
other language is built into a sub-directory named after its code.
site_name: My Project
site_url: https://example.com/
languages:
en: English
zh:
name: 简体中文
site_name: 我的项目
nav:
- 首页: index.md
- 指南: guide.md
mkdocs build builds the English site into site/ and the Chinese one into
site/zh/. mkdocs serve serves both, and reloads both when a file changes.
Translating pages
Put the translation of a page next to it, with the language code before the file extension:
docs/
index.md # English
index.zh.md # Chinese
guide.md
guide.zh.md
img/
screenshot.png
Links between pages and to images use the names without the language code,
such as [the guide](guide.md), in every language. The same goes for nav.
Any file can have a translation, so img/screenshot.zh.png replaces
img/screenshot.png on the Chinese site.
If you would rather keep each language in a directory of its own, give that
language a docs_dir, with the same file names
as the default language's:
languages:
en: English
zh:
name: 简体中文
docs_dir: docs-zh
edit_uri: edit/main/docs-zh/
Pages that aren't translated yet
A page that has no translation is built from the default language's version, so every language has every page and no link is broken. Themes can tell that a page is shown untranslated (see For theme authors) and say so to readers; Sumi shows a note at the top of the page.
To leave untranslated pages out of a language instead, set fallback: false:
languages:
en: English
zh:
name: 简体中文
fallback: false
Images and other files are always taken from the default language when a language has no version of its own.
Settings for one language
Apart from name, path and fallback, every key of a language overrides
that setting of mkdocs.yml for that language. Mappings are merged, the same
way as with INHERIT, and other
values are replaced. Typical ones are site_name, site_description, nav,
copyright, edit_uri and parts of theme or extra:
languages:
en: English
de:
name: Deutsch
site_name: Mein Projekt
copyright: Mein Projekt GmbH
theme:
logo: img/logo-de.svg
extra:
announcement: Neu in Version 2!
These are set for you:
theme.localeis the language code, unless the language setstheme.localeitself. The default language keeps atheme.localethatmkdocs.ymlsets.site_urlgets the language's path added, such ashttps://example.com/zh/.site_dirgets the language's path added, such assite/zh. It can't be set per language.
The keys that describe the language itself:
name- The name shown in the language switcher. Defaults to the code. The short
form
zh: 简体中文sets only the name. path- Where the language is built, relative to the site root. Defaults to the
language code. For example,
zh-Hans: {name: 简体中文, path: zh}is built into/zh/. The default language is always at the root. fallback- Whether pages that have no translation are built from the default
language's version. Default:
true.
Building one language
Building every language takes longer than building one. While you work on one
language, build or serve only that one with --language (or -L):
mkdocs serve --language zh
mkdocs build -L en -L zh
The language switcher
Each page links to the same page in the other languages, and to the home page
of a language that doesn't have it. Themes that read
extra.alternate,
such as Sumi and Material for MkDocs, show this switcher with no further
setup: MkDocs NG fills in extra.alternate for every page, unless you set it
yourself.
How it works
Each language is built as an ordinary MkDocs site, one after the other, each
with its own configuration and its own instances of the plugins (plugins with
on_startup are created once and run for
every language, as they do for every rebuild of mkdocs serve). A plugin sees
a normal single-language site, so plugins don't need to know about languages.
The search index, the sitemap, llms.txt and the files of plugins are made
for each language in its own directory.
For theme authors
On a multi-language site, templates get an i18n variable. It is None on
other sites.
{
"language": {"code": "zh", "name": "简体中文", "path": "zh", "default": False},
"default_language": "en",
# True if this page is the default language's version, shown because the
# current language has no translation of it.
"fallback": False,
"languages": [
{
"code": "en",
"name": "English",
"lang": "en",
# The same page in this language, relative to the site root of the
# current language: use it with the `url` filter.
"link": "../guide/",
# The full URL, if `site_url` is set (for `hreflang` links).
"url": "https://example.com/guide/",
"current": False,
# False if this language doesn't have the page; `link` then points
# to the language's home page.
"available": True,
},
...
],
}
For example, a language menu and hreflang links:
{% if i18n %}
{% for alt in i18n.languages %}
<a href="{{ alt.link | url }}" hreflang="{{ alt.lang }}"
{% if alt.current %}aria-current="true"{% endif %}>{{ alt.name }}</a>
{% endfor %}
{% endif %}
{% if i18n and page %}
{% for alt in i18n.languages if alt.available %}
<link rel="alternate" hreflang="{{ alt.lang }}" href="{{ alt.url or (alt.link | url) }}">
{% endfor %}
{% endif %}
Plugins can find the languages in config.languages, a list of
mkdocs.languages.Language objects, and the language being built with
mkdocs.languages.current(config). Both are None on a single-language site.
Coming from mkdocs-static-i18n
The mkdocs-static-i18n
plugin and languages both read page.zh.md files and docs/<language>/
directories. To switch:
- Remove the
i18nplugin fromplugins. - Move its
languageslist to the top-levellanguagessetting. The language markeddefault: truegoes first.localebecomes the key,namestays, andsite_name,nav,themeand the other overrides go in the language's entry as they are.nav_translationsbecomes anavfor that language. - With
docs_structure: folder, give each language itsdocs_dir, such asdocs_dir: docs/zh, and the default languagedocs_dir: docs/en.