Configure documentation languages
Organize locale roots and map translated pages to their published URLs.
Configure navigation.languages in docs.json to publish a navigation tree for each language. Keep translated pages at matching paths within their locale roots so the language switcher can open the corresponding page.
Organize pages by locale
Give each language its own source directory. The default language can also use a directory: its source prefix is removed from published URLs, just as other locale roots are replaced by their language tags.
For example, store English and Spanish pages in separate roots beside docs.json:
docs.json
en/
index.mdx
intro.mdx
es/
index.mdx
intro.mdxThe English and Spanish intro.mdx files contain separate authored content. A locale directory does not translate pages automatically. Keep intro as the relative path in both directories even when the page titles differ.
Configure language navigation
Each entry in navigation.languages has a language tag and its own navigation children, such as groups, pages, tabs, or versions. Set directory explicitly to identify the locale root. Page references still use source paths from the documentation root, not paths relative to directory.
Add this configuration to docs.json for the file tree above:
{
"name": "Example docs",
"navigation": {
"languages": [
{
"language": "en",
"default": true,
"directory": "en",
"groups": [
{ "group": "Start", "pages": ["en/index", "en/intro"] }
]
},
{
"language": "es",
"directory": "es",
"groups": [
{ "group": "Primeros pasos", "pages": ["es/index", "es/intro"] }
]
}
]
}
}The first entry with default: true is the default locale. If none has that setting, the first entry is selected. Set it on exactly one entry so reordering languages does not change the default.
If directory is omitted, the locale root is inferred from the common directory of the entry’s page references, including references nested under versions. Explicit roots avoid changing that inference when navigation changes. A non-default locale with no derivable content directory is skipped from locale serving and produces a locale_unpartitioned warning.
Check locale and version URLs
The default locale has no language prefix. Other locales use the language tag as their first URL segment, regardless of the source directory name.
When a product version has its own directory, its version label follows the locale prefix. Configure versions inside each language’s navigation entry to give each locale its own version tree. See Configure documentation versions for the release configuration.
These paths assume English is the default locale. The versioned rows assume a version labeled v1 with a source directory of en/v1 or es/v1, respectively:
| Page | Source file | Published path |
|---|---|---|
| English, unversioned | en/intro.mdx | /intro |
| Spanish, unversioned | es/intro.mdx | /es/intro |
English, directory-backed v1 | en/v1/intro.mdx | /v1/intro |
Spanish, directory-backed v1 | es/v1/intro.mdx | /es/v1/intro |
Share the published path on your documentation site’s origin, including any site base path. Do not copy the source directory path. A default product version stored in its own directory retains its version prefix; a default product version that spans the locale root has no version prefix.
After publishing, check both page responses with your site’s base URL (including any base path):
DOCS_BASE_URL="https://docs.example.com"
curl --fail --location "$DOCS_BASE_URL/intro"
curl --fail --location "$DOCS_BASE_URL/es/intro"Both requests should return the rendered page HTML. Open the same URLs in a browser and confirm each shows the intended language and its own sidebar. For a versioned setup, also open /v1/intro and /es/v1/intro rather than reversing the locale and version segments.
Connect translated counterparts
Counterparts are matched by the page path remaining after removing locale and version prefixes. No translation-link frontmatter or component is required. In the example, /intro and /es/intro match because both have the remaining path intro. Renaming only the Spanish page to introduccion.mdx breaks that automatic match.
For versioned pages, the switcher prefers the same version label in the destination locale. If the current page belongs to the default version and that label is unavailable, matching uses the destination locale’s default version. An unversioned page remains unversioned. A non-default version absent from the destination locale does not fall back to a different release’s counterpart.
Counterpart links are checked against pages that actually exist. If a translated counterpart is missing, the language switcher points to the destination locale’s home page. When a non-default locale has no authored home page, it uses the first landing link from that locale’s navigation. Include an index.mdx in each root, as in the example, to provide a predictable destination.
Only existing counterparts receive hreflang alternates; a home-page fallback is not advertised as a translation of the current page. A locale marked hidden: true is omitted from the language selector and counterpart alternates.
Test the language switcher from intro in both directions, then repeat from a versioned page if versions are configured. Test a page with no translation too: the destination should be the locale home or navigation landing page, not a nonexistent translated URL.