Setting up a new localization
This guide walks OTel website maintainers through every change required to onboard a new language localization. It covers both repository-level changes and GitHub organization-level setup.
For the contributor-facing side — translation guidance, drift tracking, and ongoing maintenance — see Site localization.
The canonical registry of active localization teams and their resources is in
projects/localization.md.
Prerequisites
Before starting, confirm the following with the locale team:
- A kickoff issue has been filed following the steps in New localizations.
- The ISO 639-1 language code (
LANG_ID) has been agreed upon. - GitHub handles for the mentor and initial contributors are known.
In the rest of this guide, replace every occurrence of LANG_ID with the actual
ISO 639-1 code (for example, pl for Polish).
Step 1 — Hugo language config
Add an entry for the new language in config/_default/hugo.yaml under the
languages: key:
LANG_ID:
languageName: NativeName (English name)
languageCode: LANG_ID-REGION
params:
description: <site description translated into the new language>
For example, the Polish entry looks like:
pl:
languageName: Polski (Polish)
languageCode: pl-PL
params:
description: Strona projektu OpenTelemetry
Step 2 — Hugo content mounts
Hugo uses content mounts to route locale-specific content and to fall back to
English pages for sections that have not yet been translated. Add a block for
LANG_ID in config/_default/module-template.yaml under the top-level
mounts: section (this template is rendered into module.yaml).
Base setup
Every locale requires at least the following mounts — the locale’s own content plus fallbacks for the core English sections:
## LANG_ID
- source: content/LANG_ID # locale-specific pages
target: content
sites: &LANG_ID-matrix
matrix: { languages: [LANG_ID] }
# fallback pages (serve English content where no translation exists yet)
- source: content/en/_includes
target: content/_includes
sites: *LANG_ID-matrix
- source: content/en/announcements
target: content/announcements
sites: *LANG_ID-matrix
- source: content/en/docs
target: content/docs
files: ['! specs/**'] # exclude spec fragments (too large to fall back)
sites: *LANG_ID-matrix
Additional sections (such as ecosystem) can be added as the localization
matures. For example, the pt block includes an ecosystem fallback:
## pt
- source: content/pt
target: content
sites: &pt-matrix
matrix: { languages: [pt] }
# fallback pages
- source: content/en/_includes
target: content/_includes
sites: *pt-matrix
- source: content/en/announcements
target: content/announcements
sites: *pt-matrix
- source: content/en/docs
target: content/docs
files: ['! specs/**']
sites: *pt-matrix
- source: content/en/ecosystem
target: content/ecosystem
sites: *pt-matrix
Insert the new block alongside the existing locale blocks in
config/_default/module-template.yaml, following the current ordering
convention used in that file.
Step 3 — Spell checking
3a. Check for a cspell dictionary
Search npm for an existing cspell dictionary for the language:
npm search @cspell/dict
Look for a package matching @cspell/dict-LANG_ID or the closest regional
variant (for example, @cspell/dict-pl_pl for Polish). You can also browse the
full list of available dictionaries at the
cspell-dicts repository.
3b. Install the dictionary (if available)
npm install --save-dev @cspell/dict-LANG_ID
This adds the package to package.json. Commit the updated package.json and
package-lock.json.
3c. Create the custom word list
Create an empty file for site-local technical terms:
touch .cspell/LANG_ID-words.txt
Commit the empty file. Contributors will add locale-specific technical terms here over time.
3d. Update .cspell.yml
Add three entries to .cspell.yml to enable spell checking for the new
language:
Under
import:— import the cspell dictionary for your locale:- '@cspell/dict-CSPELL_DICT_ID/cspell-ext.json'Under
dictionaryDefinitions:— register the custom word list:- name: LANG_ID-words path: .cspell/LANG_ID-words.txtUnder
dictionaries:— activate both the imported dictionary and the custom word list:- CSPELL_DICT_ID # the @cspell/dict-CSPELL_DICT_ID package - LANG_ID-words # the .cspell/LANG_ID-words.txt list
Keep entries in each section in alphabetical order by language code.
If no cspell dictionary package exists for the language, skip steps 3b and the
import and dictionaries entries. Only create the custom word list (step
3c) and register it under dictionaryDefinitions.
Also add the locale path to the ignorePaths list in .cspell.yml so
that cspell does not attempt to spell-check content it cannot validate:
ignorePaths:
- content/LANG_ID
Step 4 — Prettier (conditional)
If Prettier does not handle the language well — for example, scripts that are
right-to-left or use non-Latin characters — add an ignore entry to
.prettierignore:
content/LANG_ID/**
Check existing ignore entries in .prettierignore to see whether other
locales with similar scripts have already been excluded, and follow the same
pattern. This step is optional and should only be done when Prettier is known to
produce incorrect formatting for the language.
Step 5 — GitHub repository automation
Component label map
In .github/component-label-map.yml, add an entry that triggers the
lang:LANG_ID label on any PR touching content/LANG_ID/:
lang:LANG_ID:
- changed-files:
- any-glob-to-any-file:
- content/LANG_ID/**
Component owners
In .github/component-owners.yml, add an entry that requires review from
the locale’s approvers team and the docs maintainers:
content/LANG_ID:
- open-telemetry/docs-maintainers
- open-telemetry/docs-LANG_ID-approvers
Both files maintain alphabetical ordering by language code within their respective locale sections.
Step 6 — GitHub org-level setup
These steps happen outside the repository and require maintainer-level access to
the open-telemetry GitHub organization.
Team creation is done by opening a pull request against the
open-telemetry/admin repository (private). See
this PR for an
example of the expected format.
Team members should be added manually, since they aren’t currently being managed by this repository.
Step 7 — Slack channel
Create a channel for the locale in the CNCF Slack workspace, using the
naming convention #otel-localization-LANG_ID (for example,
#otel-localization-pl for Polish). After creating the channel, add the
OpenTelemetry Admin as a
channel manager.
Step 8 — Project tracking
Update projects/localization.md with the new locale’s information:
Add the language to the supported languages list at the top, in alphabetical order by language code:
- [NativeName - EnglishName (LANG_ID)][LANG_ID] [LANG_ID]: https://opentelemetry.io/LANG_ID/Add a team entry under Current language teams following the same structure as existing entries:
**EnglishName**: - Website: <https://opentelemetry.io/LANG_ID/> - Slack channel: [`#otel-localization-LANG_ID`](https://cloud-native.slack.com/archives/XXXXXXXXXXX) - Maintainers: `@open-telemetry/docs-LANG_ID-maintainers` - Approvers: `@open-telemetry/docs-LANG_ID-approvers`Add the
lang:LANG_IDlabel to the Labels section:- [`lang:LANG_ID`][issues-lang-LANG_ID] - EnglishName localizationWith the corresponding link definition:
[issues-lang-LANG_ID]: https://github.com/open-telemetry/opentelemetry.io/issues?q=is%3Aissue%20state%3Aopen%20label%3Alang%3ALANG_IDAdd the Slack channel link definition:
[otel-localization-LANG_ID]: https://cloud-native.slack.com/archives/CHANNEL_ID
Verification
Setup checklist
Use this checklist to confirm that every setup step is complete before requesting a review:
- Step 1 — Language entry added to
config/_default/hugo.yaml - Step 2 — Content mounts added to
config/_default/module-template.yaml - Step 3 — cSpell configured: dictionary installed (or locale added to
ignorePaths), custom word list created at.cspell/LANG_ID-words.txt, and.cspell.ymlupdated - Step 4 —
.prettierignoreupdated (if applicable for the script) - Step 5 —
.github/component-label-map.ymland.github/component-owners.ymlupdated with thelang:LANG_IDentries - Step 6 — Team PR opened against
open-telemetry/admin; team members added manually - Step 7 — Slack channel
#otel-localization-LANG_IDcreated; OpenTelemetry Admin added as channel manager - Step 8 —
projects/localization.mdupdated with the language entry, team entry, label, and Slack channel link
Automated checks
After all PRs are merged, run the following to confirm the configuration is correct:
npm run build— confirms Hugo recognizes the new language without errors.npm run check:spelling— confirms the cspell configuration is valid and that no errors are introduced by the new dictionary entries.- GitHub label automation — open a test PR that touches a file under
content/LANG_ID/and confirm thelang:LANG_IDlabel is applied automatically.