# Site localization

> Creating and maintaining site pages in non-English localizations.

---

LLMS index: [llms.txt](/llms.txt)

---

The OTel website uses Hugo's [multilingual framework][] to support page
localizations. English is the default language, with US English as the default
(implicit) localization. A growing number of other localizations are supported,
as can be seen from the languages dropdown menu in the top nav.

## Translation guidance

When translating website pages from English, we recommend that you follow the
guidance offered in this section.

### Summary

#### ✅ Do {#do}

<div class="border-start border-success bg-success-subtle">

- **Translate**:
  - Page content, including:
    - Mermaid [diagram](#images) text fields
    - Code comments from code excerpts (optional)
  - [Front matter][] field values for `title`, `linkTitle`, and `description`
  - **All** page content and front matter unless indicated otherwise
- **Preserve** the _content_, _meaning_, and _style_ of the original text
- **Submit work _incrementally_** via [small pull requests](#small-prs)
- **Ask** [maintainers][] if you have any doubts or questions through:
  - [Slack][] `#otel-docs-localization` or `#otel-comms` channels
  - [Discussion][], issue, or PR comment

[Discussion]:
  https://github.com/open-telemetry/opentelemetry.io/discussions?discussions_q=is%3Aopen+label%3Ai18n

</div>

#### ❌ Do NOT {#do-not}

<div class="border-start border-warning bg-warning-subtle">

- **Translate**:
  - [Alert types](../style-guide/#alerts) such as `TIP`, `WARNING`, etc.
  - Code, including code blocks and inline code (like this
    `inline code example`)
  - **File or directory** names of resources in this repository
  - [Front matter][] fields other than those listed in [Do](#do). In particular,
    do not translate `aliases`. When in doubt, ask maintainers.
  - [Links](#links), this includes [heading IDs](#headings) [^*]
  - Markdown elements marked as `notranslate` (usually as a CSS class), in
    particular for [headings](#headings)
- Create **copies of images**, unless you [localize text in the images](#images)
- Add new or change:
  - **Content** that would be different from the originally intended meaning
  - Presentation **style**, including: _formatting_, _layout_, and _design_
    style (typography, letter case, and spacing for example).

[^*]: For a possible exception, see [Links](#links).

</div>

#### Use of AI tools {#ai-tools}

If you use generative AI tools (such as ChatGPT, Gemini, or similar) to assist
with translations, you must follow the OpenTelemetry [Generative AI Contribution
Policy][genai-policy] and the Linux Foundation [Generative AI
Policy][lf-ai-policy]. In particular:

- **Disclose** that you used AI by checking the appropriate box in the [pull
  request template][].
- **Review and validate** all AI-generated translations for accuracy. You are
  responsible for the content you submit.
- **Do not submit** AI-generated translations that you cannot review and verify
  yourself (e.g., submissions in languages you are not proficient in). This
  creates a significant review bottleneck, and your PR may be closed to protect
  maintainer bandwidth.

[genai-policy]:
  https://github.com/open-telemetry/community/blob/main/policies/genai.md
[lf-ai-policy]: https://www.linuxfoundation.org/legal/generative-ai
[pull request template]:
  https://github.com/open-telemetry/opentelemetry.io/blob/main/.github/PULL_REQUEST_TEMPLATE.md

### Heading IDs {#headings}

To ensure that heading anchor targets are uniform across localizations, when
translating headings:

- Preserve the heading's explicit ID if it has one. [Heading ID syntax][] is
  written after the heading text using syntax like `{ #some-id }`.
- Otherwise, explicitly declare a heading ID corresponding to the autogenerated
  ID of the original English heading.

[Heading ID syntax]:
  https://github.com/yuin/goldmark/blob/master/README.md#headings

### Links {#links}

Do **not** translate link references. This holds true for external links, and
paths to website pages and section-local resources such as [images](#images).

The only exception is for links to external pages (such as
<https://en.wikipedia.org>) that have a version specific to your local. Often
this means replacing the `en` in the URL by your locale's language code.

> [!NOTE]
>
> The OTel website repository has a custom render-link hook that Hugo uses to
> convert absolute link paths referring to documentation pages. **Links of the
> form `/docs/some-page` are made locale specific** by prefixing the path with
> the page language code when rendering the link. For example, the previous
> sample path would become `/ja/docs/some-page` when rendered from a Japanese
> page.

### Link definition labels {#link-labels}

Locale authors can choose or not to translate [labels][] of Markdown [link
definitions][]. If you choose to keep the English label, then follow the
guidance given in this section.

For example, consider the following Markdown:

```markdown
[Hello], world! Welcome to the [OTel website][].

[hello]: https://code.org/helloworld
[OTel website]: https://opentelemetry.io
```

This would be translated in French as:

```markdown
[Bonjour][hello], le monde! Bienvenue sur le [site OTel][OTel website].

[hello]: https://code.org/helloworld
[OTel website]: https://opentelemetry.io
```

[labels]: https://spec.commonmark.org/0.31.2/#link-label
[link definitions]:
  https://spec.commonmark.org/0.31.2/#link-reference-definitions

### Images and diagrams {#images}

Do **not** make copies of image files unless you localize text in the image
itself[^shared-images].

**Do** translate text in [Mermaid][] diagrams.

[^shared-images]:
    Hugo is smart about the way that it renders image files that are shared
    across site localizations. That is, Hugo will output a _single_ image file
    and share it across locales.

[Mermaid]: https://mermaid.js.org

### Include files {#includes}

**Do** translate page fragments found under `_includes` directories just as you
would translate any other page content.

### Shortcodes

> [!NOTE]
>
> As of February 2025, we are in the process of migrating from shortcodes to
> [include files](#includes) as a means of supporting shared-page content.

Some of the base shortcodes contain English text that you might need to localize
-- this is particularly true of those contained in [layouts/_shortcodes/docs][].

If you need to create a localized version of a shortcode, place it under
`layouts/_shortcodes/xx`, where `xx` is your localization's language code. From
there, use the same relative path as the original base shortcode.

[layouts/_shortcodes/docs]:
  https://github.com/open-telemetry/opentelemetry.io/tree/main/layouts/_shortcodes/docs

## Keeping track of localized-page drift {#track-changes}

One of the main challenges of maintaining localized pages, is identifying when
the corresponding English language pages have been updated. This section
explains how we handle this.

### The `default_lang_commit` front-matter field

When a localized page is written, such as `content/zh/<some-path>/page.md`, this
translation is based on a specific [`main` branch commit][main] of the
corresponding English language version of the page at
`content/en/<some-path>/page.md`. In this repository, every localized page
identifies the English page commit in the localized page's front matter as
follows:

```markdown
---
title: Your localized page title
# ...
default_lang_commit: <most-recent-commit-hash-of-default-language-page>
---
```

The front matter above would be in `content/zh/<some-path>/page.md`. The commit
hash would correspond to the latest commit of `content/en/<some-path>/page.md`
from the `main` branch.

### Tracking changes to English pages

As updates are made to English language pages, you can keep track of the
corresponding localized pages that need updating by running the following
command:

```console
$ npm run check:i18n
1       1       content/en/docs/platforms/kubernetes/_index.md - content/zh/docs/platforms/kubernetes/_index.md
...
```

You can restrict the target pages to one or more localizations by providing
path(s) like this:

```sh
npm run check:i18n -- content/zh
```

### Viewing change details

For any given localized pages that need updating, you can see the diff details
of the corresponding English language pages by using the `-d` flag and providing
the paths to your localized pages, or omit the paths to see all. For example:

```console
$ npm run check:i18n -- -d content/zh/docs/platforms/kubernetes
diff --git a/content/en/docs/platforms/kubernetes/_index.md b/content/en/docs/platforms/kubernetes/_index.md
index 3592df5d..c7980653 100644
--- a/content/en/docs/platforms/kubernetes/_index.md
+++ b/content/en/docs/platforms/kubernetes/_index.md
@@ -1,7 +1,7 @@
 ---
 title: OpenTelemetry with Kubernetes
 linkTitle: Kubernetes
-weight: 11
+weight: 350
 description: Using OpenTelemetry with Kubernetes
 ---
```

### Adding `default_lang_commit` to new pages

As you create pages for your localization, remember to add `default_lang_commit`
to the page front matter along with an appropriate commit hash from `main`.

If your page translation is based on an English page in `main` at `<hash>`, then
run the following command to automatically add `default_lang_commit` to your
page file's front matter using the commit `<hash>`. You can specify `HEAD` as an
argument if your pages are now synced with `main` at `HEAD`. For example:

```sh
npm run check:i18n -- -n -c 1ca30b4d content/ja
npm run check:i18n -- -n -c HEAD content/zh/docs/concepts
```

To list localization page files with missing hash keys, run:

```sh
npm run check:i18n -- -n
```

### Updating `default_lang_commit` for existing pages

As you update your localized pages to match changes made to the corresponding
English language page, ensure that you also update the `default_lang_commit`
commit hash.

> [!TIP]
>
> If your localized page now corresponds to the English language version in
> `main` at `HEAD`, then erase the commit hash value in the front matter, and
> run the **add** command given in the previous section to automatically refresh
> the `default_lang_commit` field value.

If you have batch updated all of your localization pages that had drifted, you
can update the commit hash of these files using the `-c` flag followed by a
commit hash or 'HEAD' to use `main@HEAD`.

```sh
npm run check:i18n -- -c <hash> <PATH-TO-YOUR-NEW-FILES>
npm run check:i18n -- -c HEAD <PATH-TO-YOUR-NEW-FILES>
```

> [!IMPORTANT]
>
> When you use `HEAD` as a hash specifier, the script will use the hash of
> `main` at HEAD in your **local environment**. Make sure that you fetch and
> pull `main`, if you want HEAD to correspond to `main` in GitHub.

### Drift status

Run `npm run fix:i18n:status` to add a front-matter field `drifted_from_default`
to those target localization pages that have drifted. This field will soon be
used to display a banner at the top of pages that have drifted relative to their
English counterparts.

### Script help

For more details about the script, run `npm run check:i18n -- -h`.

## New localizations

Interested in starting a new localization for the OTel website? Reach out to
maintainers to express your interest, for example through a GitHub discussion or
via the Slack `#otel-docs-localization` channel. This section explains the steps
involved in starting a new localization.

> [!NOTE]
>
> You don't have to be an existing contributor to the OpenTelemetry project to
> start a new localization. However, you cannot be added as a member of the
> [OpenTelemetry GitHub organization](https://github.com/open-telemetry/) or as
> a member of the approvers group for your localization until you satisfy the
> requirements for becoming an established member and approver as outlined in
> the [membership guidelines][].
>
> Before you earn approver status, you can indicate your approval of a
> localization PR by adding an "LGTM" (Looks Good To Me) comment. During this
> startup phase, maintainers will treat your reviews as if you are an approver
> already.

[membership guidelines]:
  https://github.com/open-telemetry/community/blob/main/guides/contributor/membership.md

### 1. Assemble a localization team {#team}

Creating a localization is about growing an active and supportive community. To
start a new localization for the OpenTelemetry website you need:

1. A **localization mentor** who is familiar with your language, such as an
   [active approver][] of the [CNCF Glossary][] or the [Kubernetes website][].
2. At least two potential contributors.

[active approver]: https://github.com/cncf/glossary/blob/main/CODEOWNERS
[CNCF Glossary]: https://glossary.cncf.io/
[Kubernetes website]: https://github.com/kubernetes/website

### 2. Localization kickoff: create an issue {#kickoff}

With a [localization team](#team) in place or coming together, create an issue
with the task list given below:

1. Look up the official [ISO 639-1 code][] for the language you want to add.
   We'll refer to this language code as `LANG_ID` in the remainder of this
   section. If you have doubts about which tag to use, especially when it comes
   to choosing a subregion, ask maintainers.

   [ISO 639-1 code]: https://en.wikipedia.org/wiki/ISO_639-1

2. Identify the GitHub handles of the
   [mentor and potential contributors](#team).

3. Create a [new issue][] containing the following task list in the opening
   comment:

   ```markdown
   - [ ] Language info:
     - ISO 639-1 language code: `LANG_ID`
     - Language name: ADD_NAME_HERE
   - [ ] Locale team info:
     - [ ] Locale mentor: @GITHUB_HANDLE1, @GITHUB_HANDLE2, ...
     - [ ] Contributors: @GITHUB_HANDLE1, @GITHUB_HANDLE2, ...
   - [ ] Read through
         [Localization](https://opentelemetry.io/docs/contributing/localization/)
         and all other pages in the Contributing section
   - [ ] Localize site homepage (only) to YOUR_LANGUAGE_NAME and submit a PR.
         For details, see
         [Localize the homepage](https://opentelemetry.io/docs/contributing/localization/#homepage).
   - [ ] OTel maintainers:
     - [ ] Update Hugo config for `LANG_ID`
     - [ ] Configure cSpell and other tooling support
     - [ ] Create an issue label for `lang:LANG_ID`
     - [ ] Create org-level group for `LANG_ID` approvers
     - [ ] Update components owners for `content/LANG_ID`
   - [ ] Create an issue to track the localization of the **glossary**. Add the
         issue number here. For details, see
         [Localize the glossary](https://opentelemetry.io/docs/contributing/localization/#glossary).
   ```

### 3. Localize the homepage {#homepage}

[Submit a pull request](../pull-requests/) with a translation of the website
[homepage][], and _nothing else_, in the file `content/LANG_ID/_index.md`.
Ensure that maintainers have the necessary permissions to edit your PR, since
they will add additional changes to your PR that are required to get your
localization project started.

[homepage]:
  https://github.com/open-telemetry/opentelemetry.io/blob/main/content/en/_index.md

After your first PR is merged, maintainers will set up the issue label, the
org-level group and the component owners.

### 4. Localize the glossary {#glossary}

The second page to localize is the [Glossary](/docs/concepts/glossary/). This is
a **critical** page for localized readers, since it defines the key terms used
in observability and OpenTelemetry in particular. This is especially critical if
no such terms exist in your language.

For guidance, see the [video][ali-d-youtube] of Ali Dowair's talk at Write the
Docs 2024: [The art of translation: How to localize technical
content][ali-dowair-2024].

[ali-dowair-2024]:
  https://www.writethedocs.org/conf/atlantic/2024/speakers/#speaker-ali-dowair-what-s-in-a-word-lessons-from-localizing-kubernetes-documentation-to-arabic-ali-dowair
[ali-d-youtube]: https://youtu.be/HY3LZOQqdig

### 5. Localize remaining site pages in small increments {#rest}

With terminology established, you can now localize the remaining site pages.

> [!IMPORTANT] Submit small PRs <a id="small-prs"></a>
>
> Localization teams should submit their work in **small increments**. That is,
> keep [PRs][] small, preferably limited to one or a few small files. Smaller
> PRs are easier to review and so typically get merged more quickly.

### OTel maintainer checklist

#### Hugo

Update Hugo config for `LANG_ID`. Add appropriate entries for `LANG_ID` under:

- `languages` in `config/_default/hugo.yaml`
- `module.mounts` via `config/_default/module-template.yaml`. At a minimum, add
  a single `source`-`target` entry for `content`. Consider adding entries for
  `en` fallback pages only once the locale has enough content.

#### Spelling

Look for [cSpell dictionaries][] available as NPM packages
[@cspell/dict-LANG_ID][]. If a dictionary isn't available for your dialect or
region, choose the closest region.

If no dictionary is available, then skip the rest of this subsection. Otherwise:

- Add the NPM package as a dev dependency, for example:
  `npm install --save-dev @cspell/dict-bn`.
- Create `.cspell/LANG_ID-words.txt` as the site-local dictionary words for
  `LANG_ID`.
- In `.cspell.yml`, add entries for:
  - `import`
  - `dictionaryDefinitions`
  - `dictionaries`: add two entries here, one for `LANG_ID` and one for
    `LANG_ID-words.txt`

[cSpell dictionaries]: https://github.com/streetsidesoftware/cspell-dicts
[@cspell/dict-LANG_ID]: https://www.npmjs.com/search?q=%40cspell%2Fdict

#### Other tooling support

- Prettier support: if `LANG_ID` isn't well supported by Prettier, add ignore
  rules to `.prettierignore`

## Approver and maintainer guidance

### PRs with semantic changes should not span locales {#prs-should-not-span-locales}

Approvers should ensure that [PRs][] making **semantic** changes to doc pages do
not span multiple locales. A semantic change is one that impacts the _meaning_
of the page content. Our docs [localization process](.) ensures that locale
approvers will, in time, review the English-language edits to determine if the
changes are appropriate for their locale, and how best to incorporate them into
their locale. If changes are necessary, the locale approvers will make them via
their own locale-specific PRs.

### Purely editorial changes across locales are OK {#patch-locale-links}

**Purely editorial** page updates are changes that **do not** affect the
existing content and can span multiple locales. These include:

- **Link maintenance**: Fixing broken link paths when pages are moved or
  deleted.
- **Resource updates**: Updating links to moved external resources.
- **Targeted content additions**: Adding specific new definitions or sections to
  files that have drifted, when updating the entire file isn't feasible.

#### Link fixes and resource updates {#link-fixes-and-resource-updates}

For example, sometimes changes to English language documentation can result in
link-check failures for non-English locales. This happens when documentation
pages are moved or deleted.

In such situations, make the following updates to each non-English page that has
a path that fails link checking:

- Update the link reference to the new page path.
- Add the `# patched` YAML comment at the end of the line for the
  `default_lang_commit` front matter line.
- Make no other changes to the file.
- Rerun `npm run check:links` and ensure that no link failures remain.

When an _external link_ to a **moved** (but otherwise semantically
**unchanged**) resource (such as a GitHub file) results in a link-check failure,
consider:

- Removing the broken link from the refcache
- Updating the link across all locales using the method described earlier in
  this section.

#### Targeted content additions to drifted files {#targeted-content-additions}

When adding specific new content to a localized file that has drifted from the
English version, you may choose to make a targeted update rather than updating
the entire file. For example, when a new glossary term such as "cardinality" is
added to the English glossary, you can add just that term to the localized
glossary without addressing other drifted content.

Here's an example of the workflow for this targeted update:

- Add only the "cardinality" definition block to the localized glossary file
- Update the front matter by adding `# patched` as a comment at the end of the
  `default_lang_commit` line
- Leave all other existing content unchanged
- In the PR description, clearly document:
  - The specific content added ("cardinality" definition)
  - That the file remains drifted for other content
  - The rationale for the targeted update (e.g., "Providing critical new
    terminology to localized readers without requiring full file
    synchronization")

This approach enables incremental improvements to localized content while
maintaining awareness that the file still requires future attention for complete
synchronization with the English version.

[front matter]: https://gohugo.io/content-management/front-matter/
[main]: https://github.com/open-telemetry/opentelemetry.io/commits/main/
[maintainers]: https://github.com/orgs/open-telemetry/teams/docs-maintainers
[multilingual framework]: https://gohugo.io/content-management/multilingual/
[new issue]: https://github.com/open-telemetry/opentelemetry.io/issues/new
[PRs]: ../pull-requests/
[slack]: https://slack.cncf.io/
