Skip to content

Internationalisation

The ecosystem's products and documentation are served in several languages. This page explains the language policy and how it is implemented technically.

Language policy

Level Languages
Mandatory Монгол (mn) · English (en)
For the main products + 中文 (zh) · Русский (ru)
For ecosystem-level documentation Mongolian + the six official UN languages

Mongolian is the source language — the original text is written in Mongolian and translated outwards.

The six official languages of the United Nations are: العربية (ar) · 中文 (zh) · English (en) · Français (fr) · Русский (ru) · Español (es). This site (ecosystem-level documentation) is served in Mongolian plus those six — seven languages in total.

Why exactly these languages?

The readers of ecosystem-level documentation are not only in-house developers: they include international partners, donor organisations, standards bodies and foreign integrators. The six UN languages give the widest global reach and are a neutral choice that privileges no single country.

The deep technical documentation of an individual platform (endpoint schemas, SDK reference) is out of scope for this policy — it stays MN + EN inside its own repository.

i18n in the products

Applications determine the user's language in this order:

  1. The user's own setting (stored in their profile),
  2. The browser's Accept-Language,
  3. The default language (mn).

The AI assistant replies in the user's language — whichever language the question arrived in.

Two dictionary layers

The dictionary lives in two places, and understanding the boundary matters:

Dictionary Where Size
Shared — login, navigation, admin, eID @gerege/ui-core 846 keys × 7 languages
Platform — the terminology of that domain lib/<platform>I18n.ts Varies per platform, usually 2–4 languages

The rule: the shared dictionary only knows the shared surface. The wallet's IBAN/statement vocabulary, the developer portal's API catalogue, Ring's business-process terminology — those belong in the app's own dictionary.

The reason is cost: put Ring's 1,104 terms into the shared dictionary and kiosk, POS and the wallet all carry them — and every language added multiplies that cost sevenfold.

A platform dictionary falls back to English for the languages it has not translated — so the interface can be available in seven languages while the marketing copy and the domain terminology exist in fewer.

Interface language ≠ content language

Growing the dictionary from four languages to seven broke every place that said Record<Lang, …>: the landing page's marketing copy, the API catalogue descriptions — these are written by humans and do not scale the way the interface does. In such places, declare the language set explicitly, as something like LANDING_LANGS.

i18n in the documentation

Each repository's documentation site uses MkDocs Material + mkdocs-static-i18n.

The suffix layout

Translations are made by adding a language code to the file name:

docs/
├── index.md        ← Монгол (default)
├── index.ar.md     ← العربية
├── index.zh.md     ← 中文
├── index.en.md     ← English
├── index.fr.md     ← Français
├── index.ru.md     ← Русский
└── index.es.md     ← Español

Configuration:

plugins:
  - i18n:
      docs_structure: suffix
      fallback_to_default: true
      reconfigure_material: true
      reconfigure_search: true
      languages:
        - locale: mn
          default: true
          name: Монгол
          build: true
        - locale: en
          name: English
          build: true
        - locale: ar
          name: العربية
          build: true
        # … zh · fr · ru · es likewise

The default language builds at the site root (/), the others under a sub-path (/en/, /ar/, /zh/, /fr/, /ru/, /es/).

Fallback

fallback_to_default: true — an untranslated page shows its content in the default language. So even with translations missing, the site stays whole and no 404 appears.

This is the practical choice: documentation grows constantly and translation lags behind. Waiting until every page is translated at once amounts to not publishing the documentation at all.

Menu labels live in mkdocs.yml rather than in page content, so they are translated separately for each locale:

        - locale: en
          nav_translations:
            Архитектур: Architecture
            Платформууд: Platforms
        - locale: ar
          nav_translations:
            Архитектур: البنية المعمارية
            Платформууд: المنصّات

If you add a page and forget to add its nav_translations entry for all six locales, that menu label stays in Mongolian — the build does not fail, so it only shows up on inspection.

Right-to-left text (RTL)

العربية reads right to left. Material recognises the ar locale, sets <html dir="rtl"> and flips the menu, headings and table flow by itself — no separate direction setting is needed.

Code blocks and ASCII diagrams, however, stay left-to-right even in RTL. That is correct: technical notation (URLs, commands, YAML) loses its meaning if its direction is reversed.

Anchors for Cyrillic headings

The standard slugify drops Cyrillic letters

Python-Markdown's default toc slugify deletes non-ASCII characters. As a result the heading ## Танилт receives an empty id and the in-page link (#танилт) stops working.

The fix is a slugify that preserves unicode:

markdown_extensions:
  - toc:
      permalink: true
      slugify: !!python/object/apply:pymdownx.slugs.slugify {kwds: {case: lower}}

This site is configured the same way.

The order of translation

When adding new documentation:

  1. Write the source text in Mongolian — the source is always Mongolian.
  2. Stabilise the Mongolian version with a strict build (links and anchors get checked).
  3. Then translate into all six languages at once. Translating a page only partly leaves the languages out of step with each other.

Finish one page in every language

It is better to work page by page than language by language: converting one document into six languages at the same time keeps the terminology, the structure and the table rows identical. Going the other way — "English for every page first" — means the languages translated later will be chasing a source text that has already changed.

What gets translated and what does not

Translated Left as-is
Body text, headings, table values Domain names (sso.gerege.mn)
Explanations, warnings, tips Repository names (template-gerege-mn)
Descriptive labels inside diagrams Code, YAML, commands, endpoint paths
Table headers Product names (eID Mongolia, G-Sign)
Status-badge text Standard names (OIDC, PKCE, RFC 3161)

File names and directory structure are never translated — it is platforms/sso.ru.md, not платформы/sso.md. That way the URL path stays the same when switching languages, and deep links keep working.

The state of this site

Every page of the ecosystem-level documentation is ready in seven languages:

Locale Language Path State
mn Монгол (default) / ✅ complete
ar العربية /ar/ ✅ complete
zh 中文 /zh/ ✅ complete
en English /en/ ✅ complete
fr Français /fr/ ✅ complete
ru Русский /ru/ ✅ complete
es Español /es/ ✅ complete

fallback_to_default remains switched on — when a new page is added and its translation lags behind, that page shows the Mongolian original and the site stays whole.

If you spot an error or an awkward phrasing, please send a PR to the repository — see This docs platform.