Skip to content

Сістэма перакладу

Гэты сайт публікуецца на 17 мовах. Не камандай перакладчыкаў, а Python-скрыптам, мадэллю Claude Opus і файлавай структурай, дзе ўсё становіцца на свае месцы. Вось як гэта ўсё працуе.

Дакументацыя знаходзіцца ў 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, пераключальнік ламаецца або моўчкі вяртаецца да англійскай.

Мовы спарадкаваны паводле сусветнай папулярнасці шахмат, на аснове дадзеных з Lichess, Chess.com і рэгістрацый FIDE. Англійская ідзе першай як зыходная мова; усё астатняе ідзе паводле шахматнага рэйтынгу:

РангКодМоваСтыль
1enАнглійскаяКрыніца ісціны
2esІспанскаяСтандартны фармальны
3hiХіндзіПісьмо дэванагары
4ruРускаяСтандартны фармальны
5deНямецкаяСтандартны фармальны
6frФранцузскаяСтандартны фармальны
7ptПартугальскаяЕўрапейская партугальская
11plПольскаяСтандартны фармальны
12itІтальянскаяСтандартны фармальны
13ukУкраінскаяСтандартны фармальны
14trТурэцкаяСтандартны фармальны
17koКарэйскаяФорма 합니다/습니다
18zhКітайская (спрошчаная)Спрошчаныя іерогліфы
zh-twКітайская (традыцыйная)Традыцыйныя іерогліфы
23nbНарвежская (букмол)Стандартны букмол
beБеларускаяСтандартная беларуская
34jaЯпонскаяФорма です/ます

Калонка «стыль» мае значэнне. У японскай і карэйскай ёсць фармальныя рэгістры, якія ўплываюць на кожны сказ. Промпт для перакладу ўключае гэтыя інструкцыі, каб мадэль стварала натуральны, дагледжаны тэкст — а не сухі машынны вынік.

Гэты парадак таксама вызначае выпадальны спіс моў у шапцы сайта. Найбольш распаўсюджаныя шахматныя мовы ідуць першымі, каб карыстальнікі хутчэй знаходзілі сваю без пракруткі.

Крок 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:

Terminal window
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 хвілін.

Terminal window
pnpm build

Astro чытае зыходны markdown, апрацоўвае яго праз шаблоны Starlight і вывадзіць статычны HTML у dist/. Зборка займае каля 30 секунд для ўсіх ~500 старонак.

Terminal window
pnpm run deploy

Публікуе сабраны сайт на Cloudflare Workers.

Скрыпт перакладу наўмысна просты — каля 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» ператвараецца ў «はじめに» на японскай і «Начало работы» на рускай.

Claude Opus 4.6 дае прыкметна лепшыя пераклады, чым хутчэйшыя мадэлі. Розніца відаць у:

  • Натуральнасці фармулёвак — Opus піша як носьбіт мовы, а не як перакладчык. Ён перабудоўвае сказы, калі англійскі парадак слоў гучаў бы нязграбна ў мэтавай мове.
  • Тэхнічнай дакладнасці — Шахматная тэрміналогія, TTS-жаргон і праграмныя паняцці перакладаюцца з выкарыстаннем правільных даменна-спецыфічных тэрмінаў.
  • Паслядоўнасці — Фармальны рэгістр захоўваецца на працягу ўсяго тэксту. Японская ўсюды выкарыстоўвае форму です/ます, не пераключаючыся паміж размоўным і ветлівым стылем пасярод абзаца.
  • Апрацоўцы MDX — Opus правільна захоўвае тэгі JSX-кампанентаў (<Card>, <CardGrid>) і аператары import у файлах .mdx, не пашкоджваючы іх.

Розніца ў кошце рэальная — каля $28 за поўны пераклад сайта з Opus супраць $5 з Sonnet — але для 448 файлаў, якія карыстальнікі сапраўды будуць чытаць, якасць таго вартая.

Архітэктура маршрутызацыі лакалей

Section titled “Архітэктура маршрутызацыі лакалей”

Гэта тая частка, на якую спатрэбілася найбольш часу.

Starlight вызначае мову старонкі, правяраючы першы сегмент слага змесціва. Калі ён бачыць fr/docs/getting-started, ён разумее, што гэта французская, бо fr — першы сегмент. Але першапачатковая рэалізацыя стварала слагі накшталт docs/fr/getting-started — лакаль была схаваная пад docs/. Starlight бачыў docs як першы сегмент, лічыў усё англійскай і генераваў 7 000+ дублікатаў старонак замест ~500.

Карыстальніцкая функцыя generateId у src/content.config.ts кіруе тым, як шляхі файлаў ператвараюцца ў слагі змесціва:

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/:

Шлях файлаСлагURL
getting-started.mddocs/getting-started/docs/getting-started/
fr/getting-started.mdfr/docs/getting-started/fr/docs/getting-started/
ja/features/puzzles.mdja/docs/features/puzzles/ja/docs/features/puzzles/

Англійская выкарыстоўвае defaultLocale: "root", што азначае адсутнасць прэфікса — яна жыве непасрэдна на /docs/, а не на /en/docs/.

Масіў localeKeys у тым жа файле павінен утрымліваць кожную неангельскую лакаль. Калі лакаль ёсць у канфігурацыі Astro, але адсутнічае ў гэтым масіве, яе перакладзены кантэнт лічыцца англійскім — пераключальнік моў ламаецца, а колькасць старонак выбухае.

Astro кэшуе адпаведнасці слагаў у .astro/data-store.json. Пасля любых змен канфігурацыі лакалей гэты файл трэба выдаліць перад перазборкай, інакш зборка пройдзе паспяхова з састарэлай (няправільнай) маршрутызацыяй.

Бакавая панэль вызначаецца ў 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. Дадаванне новай мовы азначае дадаванне аднаго запісу ў кожны з гэтых сямі блокаў.

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/ (праз дэфіс).

Складаныя часткі ўжо зроблены:

  1. Архітэктура маршрутызацыі вырашана. Функцыя generateId, масіў localeKeys і канфігурацыя defaultLocale: "root" працуюць разам, каб Starlight генераваў правільную URL-структуру. Гэта была найбольшая праблема — спатрэбілася прасачыць больш за 6 зыходных файлаў у Starlight і Astro, каб знайсці і выправіць.

  2. Скрыпт перакладу апрацоўвае ўсё. Поўны перапераклад сайта, дадаванне адной мовы, абнаўленне асобных файлаў — усё робіцца адным скрыптам з рознымі сцягамі. Ён паўтарае спробы пры перавышэнні лімітаў, размяркоўвае задачы паміж воркерамі і выразна паведамляе пра памылкі.

  3. Дадаванне новай мовы — гэта чатыры правкі ў канфігурацыі і адна каманда. Дадайце лакаль у astro.config.mjs, content.config.ts і translate-docs.py, дадайце пераклады бакавой панэлі, запусціце скрыпт. Каля 10 хвілін працы плюс 4 хвіліны перакладу.

  4. Абнаўленне кантэнту яшчэ прасцей. Адрэдагуйце англійскую крыніцу, запусціце скрыпт з --files і --overwrite толькі для змененых файлаў, перазбярыце. Альбо для дробных тэкставых выпраўленняў рэдагуйце перакладзеныя файлы напрамую.

  5. Увесь канвеер захаваны як навык. Запуск /translate_docs правядзе вас праз увесь працэс — які рэжым выкарыстоўваць, якія сцягі перадаць, папярэднія праверкі, верыфікацыя пасля перакладу. Ніякіх інстытуцыйных ведаў не патрабуецца.

Поўны пераклад 448 файлаў на 16 моў каштаваў каля $28 і заняў каля 70 хвілін. Адна новая мова каштуе каля $1,70. Адзін файл, перакладзены на ўсе мовы, каштуе каля $1. Гэта бягучыя выдаткі на падтрыманне дакументацыі актуальнай на 17 мовах.