---
name: kodadocs-i18n-docs
description: "Translate documentation into multiple languages with glossary management, RTL support, and per-locale VitePress configuration."
---

# Multi-Language Documentation

## Overview

This skill translates your existing KodaDocs documentation into multiple languages, generating a fully localized documentation site with a language switcher. It preserves markdown formatting, maintains a translation glossary for consistency, handles right-to-left languages, and produces a per-locale VitePress configuration with proper routing.

Use this skill when:
- You want to offer documentation in languages beyond English
- Your product has users in non-English-speaking markets
- You need consistent terminology across translated documents
- You want locale-specific URL paths (`/en/`, `/es/`, `/fr/`, `/ja/`) with a language switcher
- You need right-to-left support for Arabic or Hebrew documentation

## Prerequisites

Before running this skill, ensure the following:

1. **Existing English documentation:** A previous KodaDocs pipeline run must exist with articles in the manifest (`.kodadocs/run_manifest.json`).
2. **Target languages:** The user must specify which languages to translate into (e.g., `"es, fr, de, ja"`).
3. **KodaDocs manifest:** The manifest must contain the articles list, project name, brand color, and other site configuration.

## Workflow

### Step 1: Load Existing Documentation

Load the current documentation state from the manifest.

**Load the manifest:**
Call `mcp__kodadocs__load_manifest` with the project path:
```
project_path: "<project-root>"
```

**From the manifest, extract:**
- `articles` — the array of article objects (each with title, slug, content, order)
- `project_name` — used in translated site titles
- `brand_color` — preserved in all locale builds
- `screenshots_dir` — location of captured screenshots
- `output_dir` — base output directory for the site
- `discovered_routes` — the route list
- `logo_path` — the logo, if any

**Validate the articles exist:**
- At least one article must be present
- Articles must have non-empty `content` fields
- If no articles are found, stop and inform the user: "No documentation articles found in the manifest. Run the main KodaDocs pipeline first."

### Step 2: Parse and Validate Target Languages

Accept the user's language specification and validate it.

**Supported language codes (ISO 639-1):**

| Code | Language | Script Direction |
|------|----------|-----------------|
| en | English | LTR |
| es | Spanish | LTR |
| fr | French | LTR |
| de | German | LTR |
| it | Italian | LTR |
| pt | Portuguese | LTR |
| pt-BR | Brazilian Portuguese | LTR |
| nl | Dutch | LTR |
| ru | Russian | LTR |
| pl | Polish | LTR |
| uk | Ukrainian | LTR |
| zh | Chinese (Simplified) | LTR |
| zh-TW | Chinese (Traditional) | LTR |
| ja | Japanese | LTR |
| ko | Korean | LTR |
| ar | Arabic | RTL |
| he | Hebrew | RTL |
| fa | Persian | RTL |
| hi | Hindi | LTR |
| th | Thai | LTR |
| vi | Vietnamese | LTR |
| tr | Turkish | LTR |
| id | Indonesian | LTR |
| ms | Malay | LTR |
| sv | Swedish | LTR |
| da | Danish | LTR |
| fi | Finnish | LTR |
| nb | Norwegian (Bokmal) | LTR |

**Parsing the input:**
- Accept comma-separated codes: `"es, fr, de, ja"`
- Accept space-separated codes: `"es fr de ja"`
- Accept full language names: `"Spanish, French, German, Japanese"`
- Normalize to lowercase ISO 639-1 codes
- If a code is not recognized, warn: "Unrecognized language code: '<code>'. Skipping."

**The source language is always English (`en`).** The English articles serve as the source of truth for all translations.

### Step 3: Load or Initialize Translation Glossary

The glossary ensures consistent translation of project-specific terms across all articles and languages.

**Glossary location:** `.kodadocs/translations.json`

**If the glossary exists, load it:**
Read the file and parse the JSON structure:
```json
{
  "meta": {
    "source_language": "en",
    "last_updated": "2026-03-01T12:00:00Z",
    "version": 1
  },
  "terms": {
    "dashboard": {
      "es": "panel de control",
      "fr": "tableau de bord",
      "de": "Dashboard",
      "ja": "ダッシュボード"
    },
    "pipeline": {
      "es": "pipeline",
      "fr": "pipeline",
      "de": "Pipeline",
      "ja": "パイプライン"
    },
    "deploy": {
      "es": "desplegar",
      "fr": "déployer",
      "de": "bereitstellen",
      "ja": "デプロイ"
    }
  },
  "ui_strings": {
    "sidebar.getting_started": {
      "es": "Primeros pasos",
      "fr": "Prise en main",
      "de": "Erste Schritte",
      "ja": "はじめに"
    },
    "nav.home": {
      "es": "Inicio",
      "fr": "Accueil",
      "de": "Startseite",
      "ja": "ホーム"
    },
    "nav.api_reference": {
      "es": "Referencia API",
      "fr": "Référence API",
      "de": "API-Referenz",
      "ja": "APIリファレンス"
    },
    "footer.powered_by": {
      "es": "Desarrollado con",
      "fr": "Propulsé par",
      "de": "Erstellt mit",
      "ja": "Powered by"
    }
  }
}
```

**If the glossary does not exist, initialize it:**
1. Scan all English articles for project-specific terms:
   - Product name and variations
   - Technical terms that appear in headings or are bolded
   - Terms in code blocks that also appear in prose (e.g., "pipeline", "deploy")
   - Brand-specific vocabulary
2. Create the initial glossary with empty translations for each target language
3. The terms will be filled in during the translation process

**Glossary rules:**
- Terms in the glossary must be translated consistently across all articles
- Some technical terms should not be translated (API names, code identifiers, CLI commands)
- The user can override any glossary entry before or after translation
- The glossary persists between runs so translations remain consistent over time

### Step 4: Identify Untranslatable Content

Before translating, mark content that should remain in English.

**Content that must NOT be translated:**

1. **Code blocks:** All fenced code blocks (` ``` `) remain untouched
2. **Inline code:** Content within backticks (`` ` ``) remains untouched
3. **URLs and links:** The URL portion of `[text](url)` is preserved; the link text IS translated
4. **File paths:** Paths like `/src/components/Button.tsx` remain in English
5. **CLI commands:** Shell commands in code blocks stay as-is
6. **Variable names and identifiers:** `API_KEY`, `user_id`, etc.
7. **Brand names and product names:** Keep the project name in its original form unless the user explicitly provides a localized name
8. **Version numbers:** `v2.1.0`, `1.0.0-beta`
9. **HTML tags and attributes:** `<div class="container">` stays unchanged
10. **Image references:** `![alt text](image.png)` — the alt text IS translated, the path is NOT

**Content markers:** Before sending text for translation, wrap untranslatable segments with markers:
- Replace code blocks with `{{CODE_BLOCK_N}}` placeholders
- Replace inline code with `{{INLINE_CODE_N}}` placeholders
- Replace URLs with `{{URL_N}}` placeholders
- After translation, restore the original content at each marker position

### Step 5: Translate Articles

Translate each article from English into every target language.

**Translation process for each article:**

1. **Extract the article content** from the manifest
2. **Apply content markers** to protect untranslatable segments (Step 4)
3. **Translate the marked content** preserving all markdown formatting:
   - Headings (`#`, `##`, `###`) must remain as headings at the same level
   - Bold (`**text**`) and italic (`*text*`) markers must wrap the translated text
   - Bullet lists must remain as bullet lists
   - Numbered lists must remain numbered (and renumbered if the language requires it)
   - Tables must retain their column structure
   - Blockquotes (`>`) must remain as blockquotes
   - Horizontal rules (`---`) are preserved as-is
4. **Apply glossary terms** to ensure consistency:
   - When a glossary term appears in the source text, use the glossary translation
   - If the glossary entry is empty for this language, translate it and add it to the glossary
5. **Restore content markers** by replacing `{{CODE_BLOCK_N}}`, `{{INLINE_CODE_N}}`, and `{{URL_N}}` with the original content
6. **Translate the article title** for use in navigation

**Quality guidelines:**
- Translations should sound natural in the target language, not word-for-word literal
- Technical accuracy must be preserved (do not change the meaning of instructions)
- Keep the same level of formality as the English source
- Adapt examples where culturally appropriate (e.g., date formats, name examples)
- Preserve the same paragraph structure (same number of paragraphs, same order)

**Batch processing:**
- Translate all articles for one language before moving to the next
- This ensures consistent terminology within a language
- Update the glossary after each article so subsequent articles benefit from established terms

### Step 6: Handle Right-to-Left Languages

For Arabic (`ar`), Hebrew (`he`), and Persian (`fa`), additional configuration is needed.

**RTL-specific adjustments:**

1. **VitePress config:** Set `dir: 'rtl'` in the locale configuration
2. **CSS overrides:** Add RTL-specific styles to the theme:
   ```css
   [dir="rtl"] .content {
     direction: rtl;
     text-align: right;
   }

   [dir="rtl"] code {
     direction: ltr;
     text-align: left;
     unicode-bidi: embed;
   }

   [dir="rtl"] pre {
     direction: ltr;
     text-align: left;
   }

   [dir="rtl"] table {
     direction: rtl;
   }

   [dir="rtl"] table th,
   [dir="rtl"] table td {
     text-align: right;
   }

   [dir="rtl"] .sidebar {
     right: 0;
     left: auto;
   }

   [dir="rtl"] ul,
   [dir="rtl"] ol {
     padding-right: 1.5em;
     padding-left: 0;
   }
   ```

3. **Code blocks remain LTR:** Even in RTL documents, code blocks and inline code must render left-to-right. The CSS above handles this with `direction: ltr` on code elements.

4. **Mixed directional content:** When English terms appear inline within RTL text, use Unicode bidirectional markers if needed:
   - `\u200F` (Right-to-Left Mark) before RTL text segments
   - `\u200E` (Left-to-Right Mark) before LTR text segments embedded in RTL
   - Most modern browsers handle this automatically, but explicit markers help with edge cases

5. **Screenshots for RTL:** If the application itself supports RTL (check for `dir="rtl"` or `lang="ar"` in the HTML), capture RTL screenshots. Otherwise, reuse English screenshots with translated captions.

### Step 7: Handle Screenshots

Determine the screenshot strategy for each language.

**Decision: Locale-specific screenshots vs. reused screenshots**

```
Does the application have locale support?
  Check for: i18n framework (next-intl, vue-i18n, react-i18next, django i18n)
  Check for: locale routing (/en/, /es/, locale selector in UI)
  Check for: translation files (locales/, messages/, i18n/)

  YES (app supports locales) ->
    Is the app running and accessible?
      YES -> Capture locale-specific screenshots:
             For each target language:
               1. Set the app to the target locale (via URL, cookie, or header)
               2. Call mcp__kodadocs__capture_screenshots with the localized routes
               3. Save to a language-specific directory: screenshots/<lang>/
      NO  -> Reuse English screenshots with translated captions

  NO (app is English-only) ->
    Reuse English screenshots for all languages
    Translate image alt text and captions only
    Add a note to non-English docs: "[Screenshots shown in English]"
```

**Screenshot directory structure:**
```
.kodadocs/screenshots/
  en/            # English screenshots (from original pipeline run)
    dashboard.png
    settings.png
  es/            # Spanish screenshots (locale-specific or symlinks to en/)
    dashboard.png
    settings.png
  fr/            # French screenshots
    dashboard.png
    settings.png
```

**If reusing English screenshots:**
- Create symbolic links or copy the English screenshots to each locale directory
- This avoids duplication while maintaining the correct directory structure
- In the translated articles, image paths point to the locale-specific directory

**Translated captions for reused screenshots:**
When the screenshot shows English UI but the documentation is translated, add a translated caption below the image:
```markdown
![Dashboard overview](../screenshots/es/dashboard.png)
*Vista general del panel de control*
```

### Step 8: Generate Per-Locale VitePress Configuration

Create a VitePress configuration that supports multiple languages with a language switcher.

**Locale configuration structure:**

The VitePress i18n config uses locales to define per-language settings:

```javascript
// .vitepress/config.js
export default {
  locales: {
    en: {
      label: 'English',
      lang: 'en',
      link: '/en/',
      themeConfig: {
        nav: [
          { text: 'Home', link: '/en/' },
          { text: 'Guide', link: '/en/getting-started' },
          { text: 'API Reference', link: '/en/api-reference/overview' }
        ],
        sidebar: {
          '/en/': [
            {
              text: 'Getting Started',
              items: [
                { text: 'Introduction', link: '/en/introduction' },
                { text: 'Installation', link: '/en/installation' }
              ]
            }
          ]
        }
      }
    },
    es: {
      label: 'Espanol',
      lang: 'es',
      link: '/es/',
      themeConfig: {
        nav: [
          { text: 'Inicio', link: '/es/' },
          { text: 'Guia', link: '/es/primeros-pasos' },
          { text: 'Referencia API', link: '/es/api-reference/overview' }
        ],
        sidebar: {
          '/es/': [
            {
              text: 'Primeros pasos',
              items: [
                { text: 'Introduccion', link: '/es/introduction' },
                { text: 'Instalacion', link: '/es/installation' }
              ]
            }
          ]
        }
      }
    }
  }
}
```

**Language name mapping (native names for the language switcher):**

| Code | Native Label |
|------|-------------|
| en | English |
| es | Espanol |
| fr | Francais |
| de | Deutsch |
| it | Italiano |
| pt | Portugues |
| pt-BR | Portugues (Brasil) |
| nl | Nederlands |
| ru | Russkij |
| pl | Polski |
| uk | Ukrainska |
| zh | Zhongwen (Jianti) |
| zh-TW | Zhongwen (Fanti) |
| ja | Nihongo |
| ko | Hangugeo |
| ar | al-Arabiyyah |
| he | Ivrit |
| fa | Farsi |
| hi | Hindi |
| th | Phasathai |
| vi | Tieng Viet |
| tr | Turkce |
| id | Bahasa Indonesia |
| ms | Bahasa Melayu |
| sv | Svenska |
| da | Dansk |
| fi | Suomi |
| nb | Norsk bokmal |

**For RTL languages, add the `dir` field:**
```javascript
ar: {
  label: 'al-Arabiyyah',
  lang: 'ar',
  dir: 'rtl',
  link: '/ar/',
  // ...
}
```

**Navigation and sidebar translations:**
- Translate all navigation labels using the glossary
- Keep article slugs in English for URL consistency (e.g., `/es/getting-started` not `/es/primeros-pasos`)
- Translate sidebar group titles and item labels
- If the glossary has `ui_strings` entries, use those for navigation terms

### Step 9: Assemble the Multilingual Site

Build the complete localized documentation site.

**File structure:**

```
docs-output/
  en/
    index.md
    getting-started.md
    configuration.md
    ...
  es/
    index.md
    getting-started.md
    configuration.md
    ...
  fr/
    index.md
    getting-started.md
    configuration.md
    ...
  .vitepress/
    config.js         # Multi-locale configuration
    theme/
      style.css       # Including RTL overrides if needed
  public/
    screenshots/
      en/
      es/
      fr/
```

**For each target language:**

1. Prepare the translated articles as article objects:
   ```json
   {
     "title": "<translated title>",
     "slug": "<lang>/<original-slug>",
     "content": "<translated markdown content>",
     "order": <same order as English original>
   }
   ```

2. Call `mcp__kodadocs__assemble_vitepress` with:
   - The translated articles for this language
   - The same brand_color, project_name, and logo_path from the manifest
   - The screenshots directory for this locale
   - The output directory set to `<base-output>/<lang>/`
   - The discovered_routes from the manifest

**Assemble the full site by calling `mcp__kodadocs__assemble_vitepress` once with all articles (all languages combined).** Use the slug prefix (`en/`, `es/`, etc.) to organize content by locale.

### Step 10: Update the Glossary

After all translations are complete, save the updated glossary.

**Update the glossary file:**
Write the updated glossary to `.kodadocs/translations.json` with:
- All newly discovered terms added during translation
- All translations that were generated for previously empty entries
- Updated `last_updated` timestamp
- Incremented `version` number

**Glossary validation:**
- Every term must have an entry for every target language
- No entries should have empty translation values (fill any gaps)
- Terms should be sorted alphabetically for readability
- Duplicate terms (same translation for different source terms) should be flagged

### Step 11: Save Manifest and Deploy

Save the updated pipeline state and optionally deploy.

1. **Save the manifest:**
   Call `mcp__kodadocs__save_manifest` with updated metadata:
   ```json
   {
     "i18n": {
       "source_language": "en",
       "target_languages": ["es", "fr", "de", "ja"],
       "articles_per_language": 8,
       "total_translated_articles": 32,
       "glossary_terms": 45,
       "rtl_languages": [],
       "screenshot_strategy": "reused_english",
       "generated_at": "<ISO timestamp>"
     }
   }
   ```

2. **Optionally deploy:**
   Call `mcp__kodadocs__deploy_site` if the user requests it. The deployed site will include the language switcher and all locale paths.

## Decision Trees

### Source Article Availability

```
Does the manifest contain articles?
  YES -> How many articles?
           1-5   -> Proceed normally (small site)
           6-20  -> Proceed normally (standard site)
           20+   -> Warn: "Large documentation set. Translation will take significant time."
                    Offer to translate a subset first
  NO  -> Stop. "No articles found in the manifest. Run the main KodaDocs pipeline first."
```

### Glossary Handling

```
Does .kodadocs/translations.json exist?
  YES -> Load it and check for existing translations
         Are all target languages present in the glossary?
           YES -> Use existing translations, fill gaps only
           NO  -> Add new language columns and translate all terms
  NO  -> Initialize a new glossary by scanning English articles for key terms
```

### Screenshot Strategy

```
Does the application support localization?
  YES -> Is the app running and accessible?
           YES -> Capture locale-specific screenshots for each language
           NO  -> Reuse English screenshots with translated captions
  NO  -> Reuse English screenshots for all languages
         Add "[Screenshots shown in English]" notice to translated docs
```

### RTL Language Handling

```
Are any target languages RTL? (ar, he, fa)
  YES -> Add dir: 'rtl' to those locale configs
         Generate RTL CSS overrides in the theme
         Ensure code blocks remain LTR within RTL pages
         Check if app has RTL support for screenshots
  NO  -> No special handling needed
```

### Incremental Translation

```
Has translation been run before for some of these languages?
  Check the manifest for existing i18n metadata
  YES -> Which articles have changed since last run?
           Compare article content hashes from manifest
           CHANGED articles -> Re-translate only those
           UNCHANGED articles -> Skip (use existing translations)
           NEW articles -> Translate these for all languages
  NO  -> Full translation of all articles for all languages
```

### Translation Quality Verification

```
After translation, verify quality:
  Does the translated article have the same number of headings as the source? -> YES: pass
  Does the translated article have the same number of code blocks? -> YES: pass
  Does the translated article have the same number of links? -> YES: pass
  Are all glossary terms used consistently? -> YES: pass
  Any check fails? -> Flag the article for review, log which check failed
```

## Output Format

The skill produces:

1. **Translated articles** - Markdown files for each language in the output directory
2. **Per-locale VitePress config** - Multi-language site configuration with language switcher
3. **Translation glossary** (`.kodadocs/translations.json`) - Persistent term translations
4. **RTL CSS overrides** (if applicable) - Stylesheet additions for right-to-left languages
5. **Locale-specific screenshots** (if app supports i18n) - Or English screenshots with translated captions
6. **Console summary:**

```
Multi-language documentation generated:
  Source language: English (en)
  Target languages: Spanish (es), French (fr), German (de), Japanese (ja)
  Articles translated: 8 x 4 languages = 32 total
  Glossary terms: 45 (12 new)
  Screenshot strategy: Reused English screenshots
  RTL languages: none
  Output structure:
    - /en/ (8 articles)
    - /es/ (8 articles)
    - /fr/ (8 articles)
    - /de/ (8 articles)
    - /ja/ (8 articles)
  Glossary saved to: .kodadocs/translations.json
  Site configuration: VitePress with language switcher
```

## Error Handling

### No articles in manifest
If the manifest is empty or missing articles:
- Stop immediately
- Inform the user: "No documentation articles found. Run the main KodaDocs pipeline first to generate English documentation."

### Unsupported language code
If a language code is not in the supported list:
- Warn: "Language code '<code>' is not recognized. Supported codes: en, es, fr, de, ..."
- Skip that language and continue with the others
- If ALL requested languages are unsupported, stop and list the supported codes

### Translation produces malformed markdown
If a translated article has broken markdown formatting:
- Detect issues: unclosed code fences, broken table alignment, mismatched bold/italic markers
- Attempt auto-repair: close unclosed fences, realign table columns
- If auto-repair fails, fall back to the English version for that article
- Log: "Translation of '<article>' into <language> produced malformed markdown. Using English fallback."

### Glossary conflicts
If the glossary has conflicting translations (same term, different translations in different articles):
- Use the most recent translation
- Log the conflict: "Term '<term>' has conflicting translations in <language>: '<translation1>' vs '<translation2>'. Using '<chosen>'."
- The user can manually resolve conflicts in `.kodadocs/translations.json`

### Large article translation timeout
If an article is very long (over 5000 words):
- Split it into sections for translation (by heading boundaries)
- Translate each section separately
- Rejoin the sections after translation
- Verify the reassembled article has correct structure

### Screenshot capture fails for a locale
If locale-specific screenshot capture fails:
- Fall back to English screenshots for that language
- Log: "Could not capture <language> screenshots. Using English screenshots."
- Continue with the rest of the translation process

### Manifest does not contain required fields
If the manifest is missing project_name, brand_color, or other required fields:
- Use sensible defaults: project name from the directory name, brand color `#3e8fb0`
- Warn: "Manifest is missing '<field>'. Using default value: '<default>'."

### Existing translations are outdated
If the English source has changed since the last translation run:
- Detect changes by comparing content hashes stored in the manifest
- Re-translate only the changed articles
- Preserve unchanged translations to save time
- Log: "N articles have changed since last translation. Re-translating those."

### VitePress build fails with locale config
If the generated VitePress config causes build errors:
- Validate the config structure before saving
- Ensure all locale links point to existing files
- Ensure sidebar items match actual article slugs
- If validation fails, simplify the config (fewer sidebar levels, remove broken links)

## Success Criteria

The run is successful when:
- [ ] English articles were loaded from the manifest
- [ ] Target languages were parsed and validated
- [ ] Translation glossary was loaded or initialized
- [ ] All articles were translated into all target languages
- [ ] Markdown formatting was preserved in all translations
- [ ] Glossary terms were applied consistently across articles
- [ ] Code blocks, inline code, URLs, and file paths were NOT translated
- [ ] Link text, image alt text, and headings WERE translated
- [ ] RTL languages have proper `dir: 'rtl'` config and CSS overrides (if applicable)
- [ ] Screenshot strategy was determined and applied
- [ ] Per-locale VitePress config was generated with language switcher
- [ ] All locale paths (`/en/`, `/es/`, `/fr/`, etc.) contain the correct articles
- [ ] Translation glossary was saved to `.kodadocs/translations.json`
- [ ] Manifest was updated with i18n metadata
- [ ] Console summary was printed with translation statistics
