Skip to content

feat(docs): automated i18n translation pipeline for v3 docs using local LLMs #5311

@leaanthony

Description

@leaanthony

Summary

Wails v2 shipped with community translations in 12+ languages (zh-Hans, ja, ru, ko, fr, pt, de, ar, tr, uk, vi and more), managed via Crowdin. The v3 docs site (Astro + Starlight) currently has zero i18n infrastructure.

This issue tracks the design and implementation of a fully automated translation pipeline that:

  • Runs local LLMs on self-hosted hardware (no commercial translation API required)
  • Is safe for MDX+JSX mixed content (the primary failure mode with Crowdin)
  • Produces verifiable-quality output via automated QA scoring
  • Integrates with the existing GitHub workflow via PRs

Current State

  • Framework: Astro 6 + Starlight 0.38, ~145 .mdx/.md content files under docs/src/content/docs/
  • i18n config: defaultLocale: "root" (English only), no locale directories, no translation content
  • Starlight i18n support: Built-in — translations go to docs/src/content/docs/<locale>/ (content) and docs/src/content/i18n/<locale>.json (UI strings). Needs enabling in astro.config.mjs.
  • v2 precedent: Crowdin project #531392, 7 official + 5 community locales. zh-Hans alone had 1,042 translated files.

Proposed Architecture

Source MDX (English)
       │
       ▼
[1. AST Parse — remark + remark-mdx + mdast-util-mdx-jsx]
       │  ← extract: text nodes + translatable JSX attrs (title, label, alt)
       │  ← preserve intact: JSX structure, code blocks, import/export, expressions
       ▼
[2. Segment Cache Check]
       │  ← SHA-256 hash per extracted segment
       │  ← look up in translation-cache.<locale>.json (committed to repo)
       │  ← skip unchanged segments — only re-translate what changed
       ▼
[3. LLM Translation — Ollama / Qwen3 on ai-master]
       │  ← batch untranslated segments with surrounding context (±1 paragraph)
       │  ← inject Wails terminology glossary (do-not-translate list + consistent mappings)
       ▼
[4. Patch back into AST → serialize MDX]
       │  ← localize relative import paths (e.g. ../../components/Foo → same relative path in locale tree)
       ▼
[5. QA Pass]
       │  ← COMET-Kiwi reference-free scoring (pip install unbabel-comet)
       │  ← flag pages with score < 0.75 for human review
       │  ← optional LLM-as-judge pass: verify technical terms not mangled
       ▼
[6. Git PR]
       └── one PR per language targeting master, reviewed by maintainer or native-speaker contributor

Tool Recommendations

Translation pipeline

Option Notes
GenAIScript continuous translations Most complete OSS solution; uses mdast-util-mdx-jsx for AST-safe JSX handling; SHA-256 segment caching; GitHub Action available; model-agnostic via OpenAI-compatible endpoint (Ollama drop-in)
astro-llm-translator Astro-specific, incremental builds, per-language term dictionaries, custom baseURL for Ollama

Recommendation: Start with astro-llm-translator since it targets Astro/Starlight natively. Fall back to GenAIScript for any MDX edge cases it can't handle.

MDX-safe parsing

  • remark + remark-mdx + mdast-util-mdx-jsx for AST traversal
  • Configure remark-rehype with passThrough: ['mdxjsEsm', 'mdxFlowExpression', 'mdxJsxFlowElement', 'mdxJsxTextElement', 'mdxTextExpression']
  • Only translate: text nodes, and JSX attributes title, label, alt, description, caption
  • Never translate: import/export statements, code block contents, expressions {...}, JSX tag names or prop names

Models (for self-hosted on ai-master)

Priority Model Ollama tag VRAM Strength
Primary Qwen3-30B (MoE, 3B active) qwen3:30b ~20 GB Best general multilingual, CJK
Fallback Qwen2.5-14B qwen2.5:14b ~10 GB Speed, lower VRAM
EU langs Mistral-Nemo-12B mistral-nemo ~8 GB FR/DE/ES/IT quality

QA scoring

  • COMET-Kiwi (Unbabel/wmt22-cometkiwi-da) — reference-free quality estimation, no human translation needed
  • LLM-as-judge — second pass with a small model (Qwen2.5-7B) checking: technical term preservation, no JSX corruption, no omissions
  • Threshold: COMET < 0.75 → flag for human review in PR review notes

Terminology Glossary (starter list)

Terms to never translate (leave in English):
Wails, WebView, Go, runtime, frontend, backend, IPC, embed, build, npm, pnpm, vite, JSX, MDX, TypeScript

Terms with consistent target translations should be defined per locale (e.g. windowウィンドウ in Japanese, 窗口 in Chinese).


Languages to Target (v2 precedent + demand)

Priority 1 (v2 official): zh-Hans, ja, ko, ru, fr, pt
Priority 2 (v2 community): de, ar, tr, uk, vi


Implementation Tasks

  • Enable Starlight i18n in astro.config.mjs (add locale list, set defaultLocale: "root")
  • Add docs/src/content/i18n/ directory and English fallback strings
  • Build/adapt translation CLI script (translate-docs.ts) using astro-llm-translator or GenAIScript
  • Implement segment cache (SHA-256 hash map, locale-scoped JSON sidecar)
  • Build Wails terminology glossary file (JSON, injected into LLM prompt)
  • Set up COMET-Kiwi QA scoring step
  • GitHub Action: on push to docs/src/content/docs/**, trigger translate → QA → open PR per language
  • Create multica translation agent on ai-master that wraps the above pipeline
  • Document process for community contributors to submit corrections to translated files

Open Questions

  1. Should translated content live in the same repo (monorepo) or a separate wails-docs-i18n repo?
  2. Who has merge authority on language-specific PRs — designated native-speaker maintainers, or any maintainer?
  3. Should the pipeline run on every doc change, or as a scheduled weekly batch?
  4. Are there languages from v2 that we should explicitly not target for v3 (maintenance burden)?

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    DocumentationImprovements or additions to documentationEnhancementNew feature or requestv3

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions