Система перекладу
Цей сайт опубліковано 17 мовами. Не командою перекладачів, а за допомогою Python-скрипта, моделі Claude Opus та файлової структури, спроектованої так, щоб все ставало на свої місця. Ось як усе це працює.
Дерево мов
Section titled “Дерево мов”Документація зберігається в src/content/docs/. Англійська — це корінь, а кожна інша мова точно її дзеркалить:
src/content/docs/├── index.mdx ← English (root)├── getting-started.md├── features/│ ├── play-chess.md│ ├── multiplayer.md│ └── ...├── setup/│ ├── tts-overview.md│ └── ...├── under-the-hood/│ ├── architecture.md│ └── ...│├── fr/ ← French│ ├── index.mdx│ ├── getting-started.md│ ├── features/│ │ ├── play-chess.md│ │ └── ...│ └── ...│├── ja/ ← Japanese│ ├── index.mdx│ ├── getting-started.md│ └── ...│└── ... (16 language directories total)Кожен перекладений файл є структурним дзеркалом свого англійського джерела. Та сама назва файлу, той самий шлях підкаталогу, ті самі ключі frontmatter. Єдина відмінність — текст написаний іншою мовою.
Чому дзеркальна структура важлива
Section titled “Чому дзеркальна структура важлива”Starlight (фреймворк документації) покладається на цю симетрію. Коли користувач перемикає мову, Starlight замінює /docs/getting-started/ на /fr/docs/getting-started/ — той самий шлях, інший префікс локалі. Якщо французький файл не існує саме за адресою fr/getting-started.md, перемикач мов ламається або мовчки повертається до англійської.
17 мов
Section titled “17 мов”Мови впорядковані за чисельністю шахової аудиторії у світі на основі даних Lichess, Chess.com та реєстрацій FIDE. Англійська йде першою як мова-джерело; решта слідують за шаховим рейтингом:
| Ранг | Код | Мова | Стиль |
|---|---|---|---|
| 1 | en | Англійська | Першоджерело |
| 2 | es | Іспанська | Стандартний формальний |
| 3 | hi | Гінді | Письмо деванаґарі |
| 4 | ru | Російська | Стандартний формальний |
| 5 | de | Німецька | Стандартний формальний |
| 6 | fr | Французька | Стандартний формальний |
| 7 | pt | Португальська | Європейська португальська |
| 11 | pl | Польська | Стандартний формальний |
| 12 | it | Італійська | Стандартний формальний |
| 13 | uk | Українська | Стандартний формальний |
| 14 | tr | Турецька | Стандартний формальний |
| 17 | ko | Корейська | Форма 합니다/습니다 |
| 18 | zh | Китайська (спрощена) | Спрощені ієрогліфи |
| — | zh-tw | Китайська (традиційна) | Традиційні ієрогліфи |
| 23 | nb | Норвезька букмол | Стандартний букмол |
| — | be | Білоруська | Стандартна білоруська |
| 34 | ja | Японська | Форма です/ます |
Колонка «стиль» має значення. Японська та корейська мають вибір формального регістру, який впливає на кожне речення. Промпт для перекладу містить ці інструкції, щоб модель створювала природний, відшліфований текст — а не механічний переклад.
Цей порядок також визначає розташування мов у випадному списку в заголовку сайту. Найпоширеніші шахові мови з’являються першими, тож користувачі швидше знаходять свою мову без прокрутки.
Конвеєр перекладу
Section titled “Конвеєр перекладу”Крок 1: Написання англійською
Section titled “Крок 1: Написання англійською”Уся документація починається як markdown-файли англійською в src/content/docs/. Frontmatter містить title та description:
---title: "Getting Started"description: "Install En Parlant~ and play your first game."---
Download the latest release...Крок 2: Запуск скрипта
Section titled “Крок 2: Запуск скрипта”Python-скрипт (scripts/translate-docs.py) зчитує кожен англійський вихідний файл, надсилає його до Claude API та записує перекладений markdown:
python3 scripts/translate-docs.py \ --anthropic-key $ANTHROPIC_API_KEY \ --model claude-opus-4-6 \ --workers 5Скрипт потребує приблизно 60–70 хвилин для перекладу всіх 28 вихідних файлів на всі 16 цільових мов (448 файлів загалом). Він виконує 5 паралельних запитів до API, щоб не перевищувати ліміти швидкості.
Для однієї нової мови — приблизно 4 хвилини.
Крок 3: Збірка
Section titled “Крок 3: Збірка”pnpm buildAstro зчитує вихідний markdown, рендерить його через шаблони Starlight і генерує статичний HTML у dist/. Збірка займає близько 30 секунд для всіх ~500 сторінок.
Крок 4: Розгортання
Section titled “Крок 4: Розгортання”pnpm run deployПублікує зібраний сайт на Cloudflare Workers.
Як працює скрипт
Section titled “Як працює скрипт”Скрипт перекладу навмисно простий — близько 300 рядків Python. Ось його логіка:
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐│ Read English │────▶│ Claude API │────▶│ Write target ││ source file │ │ (Opus 4.6) │ │ language file ││ │ │ │ │ ││ getting- │ │ "Translate into │ │ fr/getting- ││ started.md │ │ French..." │ │ started.md │└─────────────────┘ └──────────────────┘ └─────────────────┘ × 5 parallel × 16 languages × 28 filesПромпт точно вказує Claude, що перекладати, а що залишати без змін:
- Перекладати: прозу, заголовки, підписи таблиць, frontmatter title та description
- Залишати англійською: блоки коду, інлайн-код, приклади команд, шляхи до файлів, URL-адреси, назви продуктів, імена людей, ASCII-діаграми
Це розділення є критично важливим. Команда на кшталт pnpm build повинна залишатися pnpm build кожною мовою. Назва продукту як-от “En Parlant~” або “Stockfish” не перекладається. Але “Getting Started” стає “はじめに” японською та “Начало работы” російською.
Чому Opus?
Section titled “Чому Opus?”Claude Opus 4.6 дає помітно кращі переклади, ніж швидші моделі. Різниця виявляється в:
- Природне формулювання — Opus пише як носій мови, а не як перекладач. Він перебудовує речення, коли англійський порядок слів звучав би незграбно цільовою мовою.
- Технічна точність — шахова термінологія, жаргон TTS та програмні концепції перекладаються з використанням правильних вузькоспеціалізованих термінів.
- Послідовність — формальний регістр залишається однорідним усюди. Японською використовується форма です/ます скрізь, без перемикання між розмовним та ввічливим стилем посеред абзацу.
- Обробка MDX — Opus коректно зберігає JSX-теги компонентів (
<Card>,<CardGrid>) та операториimportу файлах.mdx, не спотворюючи їх.
Різниця у вартості реальна — близько $28 за повний переклад сайту з Opus проти $5 з Sonnet — але для 448 файлів, які користувачі справді читатимуть, якість того варта.
Архітектура маршрутизації локалей
Section titled “Архітектура маршрутизації локалей”Це частина, на налагодження якої пішло найбільше часу.
Проблема
Section titled “Проблема”Starlight визначає мову сторінки за першим сегментом її slug у контенті. Коли він бачить fr/docs/getting-started, він розуміє, що це французька, тому що fr — перший сегмент. Але початкова реалізація генерувала slug на кшталт docs/fr/getting-started — локаль була захована під docs/. Starlight бачив docs як перший сегмент, вважав все англійською і генерував понад 7000 дублікатів сторінок замість ~500.
Рішення
Section titled “Рішення”Спеціальна функція generateId у src/content.config.ts контролює, як шляхи файлів перетворюються на slug контенту:
generateId({ entry }) { const slug = entry.replace(/\.[^.]+$/, ""); const firstSeg = slug.split("/")[0]; if (firstSeg && localeKeys.includes(firstSeg)) { return `${firstSeg}/docs/${slug.slice(firstSeg.length + 1)}`; } return `docs/${slug}`;}Це ставить префікс локалі перед docs/:
| Шлях файлу | Slug | URL |
|---|---|---|
getting-started.md | docs/getting-started | /docs/getting-started/ |
fr/getting-started.md | fr/docs/getting-started | /fr/docs/getting-started/ |
ja/features/puzzles.md | ja/docs/features/puzzles | /ja/docs/features/puzzles/ |
Англійська використовує defaultLocale: "root", що означає відсутність префіксу — вона живе безпосередньо за адресою /docs/, а не /en/docs/.
Масив localeKeys
Section titled “Масив localeKeys”Масив localeKeys у тому ж файлі повинен перераховувати кожну неанглійську локаль. Якщо локаль існує в конфігурації Astro, але відсутня в цьому масиві, її перекладений контент буде оброблятися як англійський — перемикач мов зламається, а кількість сторінок вибухне.
Кеш сховища даних
Section titled “Кеш сховища даних”Astro кешує відповідності slug у .astro/data-store.json. Після будь-якої зміни конфігурації локалей цей файл потрібно видалити перед повторною збіркою, інакше збірка завершиться успішно із застарілою (неправильною) маршрутизацією.
Структура меню
Section titled “Структура меню”Бічна панель визначена в astro.config.mjs. Елементи, що посилаються на сторінку (властивість slug), автоматично використовують заголовок із frontmatter перекладеної сторінки — ручний переклад не потрібен:
{ slug: "docs/getting-started" }// English: "Getting Started" (from English frontmatter)// French: "Premiers pas" (from French frontmatter)// Japanese: "はじめに" (from Japanese frontmatter)Але мітки груп та зовнішні посилання потребують явних перекладів:
{ label: "Features", translations: { fr: "Fonctionnalités", es: "Características", de: "Funktionen", ja: "機能", // ... all 16 languages }, items: [ { slug: "docs/features/play-chess" }, { slug: "docs/features/multiplayer" }, // ... ],}Сім елементів бічної панелі потребують ручних перекладів: Welcome, Features, App Menus, Setup Guides, Under the Hood, Credits та Accessibility. Додавання нової мови означає додавання одного запису до кожного з цих семи блоків.
Зв’язок із застосунком
Section titled “Зв’язок із застосунком”En Parlant~ посилається на цю документацію зі свого меню «Довідка». Посилання враховує локаль — якщо ви використовуєте застосунок французькою, воно відкриває французьку документацію:
const docsLocalePrefix = useMemo(() => { const lang = i18n.language; // e.g. "fr_FR", "zh_TW" if (!lang || lang.startsWith("en")) return ""; if (lang === "zh_TW") return "/zh-tw"; return `/${lang.slice(0, 2)}`;}, [i18n.language]);Кожна мова, доступна в застосунку, має відповідний переклад на сайті. Відповідність автоматична — fr_FR відповідає /fr/docs/, ja_JP відповідає /ja/docs/. Єдиний особливий випадок — традиційна китайська: zh_TW відповідає /zh-tw/docs/ (через дефіс).
Чому тепер це просто
Section titled “Чому тепер це просто”Складні частини вже зроблені:
-
Архітектура маршрутизації вирішена. Функція
generateId, масивlocaleKeysта конфігураціяdefaultLocale: "root"працюють разом, щоб Starlight генерував правильну URL-структуру. Це був найбільший больовий пункт — довелося простежити понад 6 вихідних файлів у Starlight та Astro, щоб знайти та виправити проблему. -
Скрипт перекладу обробляє все. Повний переклад сайту, додавання однієї мови, оновлення окремих файлів — усе тим самим скриптом з різними прапорцями. Він повторює спроби при досягненні лімітів швидкості, розпаралелює роботу між воркерами та чітко повідомляє про помилки.
-
Додавання нової мови — це чотири правки конфігурації та одна команда. Додати локаль до
astro.config.mjs,content.config.tsтаtranslate-docs.py, додати переклади для бічної панелі, запустити скрипт. Приблизно 10 хвилин роботи плюс 4 хвилини на переклад. -
Оновлення контенту ще простіше. Відредагуйте англійське джерело, запустіть скрипт з
--filesта--overwriteлише для змінених файлів, перезберіть. Або для дрібних правок тексту — відредагуйте перекладені файли напряму. -
Увесь конвеєр зафіксований у навичці. Запуск
/translate_docsпроведе через весь процес — який режим використовувати, які прапорці передати, перевірки перед запуском, верифікація після перекладу. Ніяких «таємних знань» не потрібно.
Повний переклад 448 файлів на 16 мов коштував приблизно $28 і зайняв близько 70 хвилин. Одна нова мова коштує приблизно $1,70. Один файл, переперекладений на всі мови, коштує приблизно $1. Такі поточні витрати на підтримку документації актуальною 17 мовами.