Oversettelsessystemet
Denne siden publiseres på 17 språk. Ikke av et team med oversettere, men av et Python-skript, en Claude Opus-modell, og en filstruktur designet slik at alt faller på plass. Her er hvordan hele systemet fungerer.
Språktreet
Section titled “Språktreet”Dokumentasjonen bor i src/content/docs/. Engelsk er roten — alle andre språk speiler den nøyaktig:
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)Hver oversatt fil er et strukturelt speilbilde av sin engelske kilde. Samme filnavn, samme undermappesti, samme frontmatter-nøkler. Den eneste forskjellen er at prosateksten er på et annet språk.
Hvorfor speiling er viktig
Section titled “Hvorfor speiling er viktig”Starlight (dokumentasjonsrammeverket) er avhengig av denne symmetrien. Når en bruker bytter språk, bytter Starlight /docs/getting-started/ med /fr/docs/getting-started/ — samme sti, ulikt lokalitetsprefiks. Hvis den franske filen ikke finnes på nøyaktig fr/getting-started.md, vil språkbytteren bryte sammen eller falle stille tilbake til engelsk.
De 17 språkene
Section titled “De 17 språkene”Språkene er sortert etter global sjakkspillerpopulasjon, basert på data fra Lichess, Chess.com og FIDE-registreringer. Engelsk kommer først som kildespråk; alt annet følger sjakkrangeringen:
| Rang | Kode | Språk | Stil |
|---|---|---|---|
| 1 | en | Engelsk | Kilde for sannhet |
| 2 | es | Spansk | Standard formelt |
| 3 | hi | Hindi | Devanagari-skrift |
| 4 | ru | Russisk | Standard formelt |
| 5 | de | Tysk | Standard formelt |
| 6 | fr | Fransk | Standard formelt |
| 7 | pt | Portugisisk | Europeisk portugisisk |
| 11 | pl | Polsk | Standard formelt |
| 12 | it | Italiensk | Standard formelt |
| 13 | uk | Ukrainsk | Standard formelt |
| 14 | tr | Tyrkisk | Standard formelt |
| 17 | ko | Koreansk | 합니다/습니다-form |
| 18 | zh | Kinesisk (forenklet) | Forenklede tegn |
| — | zh-tw | Kinesisk (tradisjonelt) | Tradisjonelle tegn |
| 23 | nb | Norsk Bokmål | Standard Bokmål |
| — | be | Hviterussisk | Standard hviterussisk |
| 34 | ja | Japansk | です/ます-form |
Kolonnen «stil» er viktig. Japansk og koreansk har formelle registervalg som påvirker hver eneste setning. Oversettelsesprompten inkluderer disse instruksjonene slik at modellen produserer naturlig, polert prosa — ikke stiv maskinoversettelse.
Denne rekkefølgen styrer også språkmenyen i nettstedets topplinje. De mest talte sjakkspråkene vises først, slik at brukere har større sjanse for å finne sitt språk uten å måtte scrolle.
Oversettelsespipelinen
Section titled “Oversettelsespipelinen”Steg 1: Skriv på engelsk
Section titled “Steg 1: Skriv på engelsk”All dokumentasjon starter som engelsk markdown i src/content/docs/. Frontmatter har en title og description:
---title: "Getting Started"description: "Install En Parlant~ and play your first game."---
Download the latest release...Steg 2: Kjør skriptet
Section titled “Steg 2: Kjør skriptet”Et Python-skript (scripts/translate-docs.py) leser hver engelske kildefil, sender den til Claude API-et, og skriver den oversatte markdownen:
python3 scripts/translate-docs.py \ --anthropic-key $ANTHROPIC_API_KEY \ --model claude-opus-4-6 \ --workers 5Skriptet bruker omtrent 60–70 minutter på å oversette alle 28 kildefiler til alle 16 målspråk (448 filer totalt). Det kjører 5 parallelle API-kall for å holde seg innenfor hastighetsbegrensningene.
For ett enkelt nytt språk tar det omtrent 4 minutter.
Steg 3: Bygg
Section titled “Steg 3: Bygg”pnpm buildAstro leser kilde-markdownen, rendrer den gjennom Starlight sine maler, og produserer statisk HTML i dist/. Byggeprosessen tar omtrent 30 sekunder for alle ~500 sider.
Steg 4: Deploy
Section titled “Steg 4: Deploy”pnpm run deployPubliserer det ferdige nettstedet til Cloudflare Workers.
Hvordan skriptet fungerer
Section titled “Hvordan skriptet fungerer”Oversettelsesskriptet er bevisst enkelt — omtrent 300 linjer Python. Her er flyten:
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐│ 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 filesPrompten forteller Claude nøyaktig hva som skal oversettes og hva som skal forbli urørt:
- Oversett: prosa, overskrifter, tabelletiketter, frontmatter-tittel og -beskrivelse
- Behold på engelsk: kodeblokker, inline-kode, kommandoeksempler, filstier, URL-er, produktnavn, personnavn, ASCII-diagrammer
Denne separasjonen er kritisk. En kommando som pnpm build må forbli pnpm build i hvert språk. Et produktnavn som “En Parlant~” eller “Stockfish” forblir uoversatt. Men “Getting Started” blir “はじめに” på japansk og “Начало работы” på russisk.
Hvorfor Opus?
Section titled “Hvorfor Opus?”Claude Opus 4.6 produserer merkbart bedre oversettelser enn raskere modeller. Forskjellen viser seg i:
- Naturlig formulering — Opus skriver som en morsmålsbruker, ikke en oversetter. Den omstrukturerer setninger når den engelske ordrekkefølgen ville hørt unaturlig ut på målspråket.
- Teknisk nøyaktighet — Sjakkterminologi, TTS-sjargong og programvarekonsepter oversettes med de korrekte domenespesifikke termene.
- Konsistens — Formelt register holdes konsistent gjennom hele teksten. Japansk bruker です/ます-form overalt, uten å veksle mellom uformelt og høflig midt i et avsnitt.
- MDX-håndtering — Opus bevarer JSX-komponenttagger (
<Card>,<CardGrid>) ogimport-setninger i.mdx-filer korrekt uten å ødelegge dem.
Kostnadsforskjellen er reell — omtrent $28 for en full nettstedsoversettelse med Opus mot $5 med Sonnet — men for 448 filer som brukere faktisk vil lese, er kvaliteten verdt det.
Arkitekturen for lokalitetsruting
Section titled “Arkitekturen for lokalitetsruting”Dette er delen som tok lengst tid å få riktig.
Problemet
Section titled “Problemet”Starlight oppdager en sides språk ved å sjekke det første segmentet i innholdets slug. Når den ser fr/docs/getting-started, vet den at det er fransk fordi fr er det første segmentet. Men den opprinnelige implementasjonen produserte slugs som docs/fr/getting-started — med lokaliteten begravet under docs/. Starlight tolket docs som det første segmentet, behandlet alt som engelsk, og genererte 7 000+ dupliserte sider i stedet for ~500.
Løsningen
Section titled “Løsningen”En tilpasset generateId-funksjon i src/content.config.ts styrer hvordan filstier blir til innholdsslugs:
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}`;}Dette plasserer lokalitetprefikset foran docs/:
| Filsti | 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/ |
Engelsk bruker defaultLocale: "root", som betyr at det ikke er noe prefiks — det bor direkte på /docs/, ikke /en/docs/.
localeKeys-arrayet
Section titled “localeKeys-arrayet”Et localeKeys-array i samme fil må liste opp hver ikke-engelske lokalitet. Hvis en lokalitet finnes i Astros konfigurasjon men ikke i dette arrayet, blir det oversatte innholdet behandlet som engelsk innhold — språkbytteren bryter sammen og sideantallet eksploderer.
Data store-cache
Section titled “Data store-cache”Astro cacher slug-tilordninger i .astro/data-store.json. Etter enhver endring i lokalitetskonfigurasjon må denne filen slettes før ombygging, ellers lykkes bygget med foreldede (feilaktige) rutinger.
Menystrukturen
Section titled “Menystrukturen”Sidepanelet er definert i astro.config.mjs. Elementer som peker til en side (slug-egenskap) bruker automatisk den oversatte sidens frontmatter-tittel — ingen manuell oversettelse nødvendig:
{ slug: "docs/getting-started" }// English: "Getting Started" (from English frontmatter)// French: "Premiers pas" (from French frontmatter)// Japanese: "はじめに" (from Japanese frontmatter)Men gruppeetiketter og eksterne lenker krever eksplisitte oversettelser:
{ 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" }, // ... ],}Syv sidepanelelementer krever manuelle oversettelser: Welcome, Features, App Menus, Setup Guides, Under the Hood, Credits og Accessibility. Å legge til et nytt språk betyr å legge til én oppføring i hver av disse syv blokkene.
Forbindelsen til appen
Section titled “Forbindelsen til appen”En Parlant~ lenker til denne dokumentasjonen fra sin Hjelp-meny. Lenken er lokalitetstilpasset — hvis du bruker appen på fransk, åpner den de franske dokumentene:
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]);Hvert språk som er tilgjengelig i appen har en tilsvarende oversettelse på nettstedet. Tilordningen er automatisk — fr_FR tilordnes til /fr/docs/, ja_JP tilordnes til /ja/docs/. Det eneste spesialtilfellet er tradisjonell kinesisk: zh_TW tilordnes til /zh-tw/docs/ (med bindestrek).
Hvorfor det er enkelt nå
Section titled “Hvorfor det er enkelt nå”De vanskelige delene er ferdige:
-
Rutingsarkitekturen er løst.
generateId-funksjonen,localeKeys-arrayet ogdefaultLocale: "root"-konfigurasjonen fungerer sammen slik at Starlight genererer den korrekte URL-strukturen. Dette var det største smertepunktet — det krevde sporing gjennom 6+ kildefiler i Starlight og Astro for å finne og fikse. -
Oversettelsesskriptet håndterer alt. Full nettstedsoversettelse, tillegg av enkeltspråk, oppdatering av enkelttfiler — alt samme skript med ulike flagg. Det prøver på nytt ved hastighetsbegrensninger, parallelliserer på tvers av workers, og rapporterer feil tydelig.
-
Å legge til et nytt språk er fire konfigurasjonsendringer og én kommando. Legg til lokaliteten i
astro.config.mjs,content.config.tsogtranslate-docs.py, legg til sidepaneloversettelser, kjør skriptet. Omtrent 10 minutters arbeid pluss 4 minutter oversettelsestid. -
Å oppdatere innhold er enda enklere. Rediger den engelske kilden, kjør skriptet med
--filesog--overwritefor bare de endrede filene, bygg på nytt. Eller for små prosaendringer, rediger de oversatte filene direkte. -
Hele pipelinen er fanget i en ferdighet. Å kjøre
/translate_docsveileder gjennom hele prosessen — hvilken modus som skal brukes, hvilke flagg som skal sendes, forhåndssjekker, verifisering etter oversettelse. Ingen institusjonell kunnskap nødvendig.
Den totale oversettelsen av 448 filer på tvers av 16 språk kostet omtrent $28 og tok omtrent 70 minutter. Et enkelt nytt språk koster omtrent $1,70. En enkelt fil omoversatt på tvers av alle språk koster omtrent $1. Dette er de løpende kostnadene for å holde dokumentasjonen oppdatert på 17 språk.