İçeriğe geç

Çeviri Sistemi

Bu site 17 dilde yayınlanmaktadır. Bir çevirmen ekibi tarafından değil, bir Python betiği, bir Claude Opus modeli ve her şeyin yerine oturması için tasarlanmış bir dosya yapısı sayesinde. İşte tüm sistemin çalışma şekli.

Dokümantasyon src/content/docs/ dizininde yer alır. İngilizce kök dildir — diğer tüm diller bu yapıyı birebir yansıtır:

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)

Her çevrilmiş dosya, İngilizce kaynağının yapısal bir aynasıdır. Aynı dosya adı, aynı alt dizin yolu, aynı frontmatter anahtarları. Tek fark, metnin başka bir dilde olmasıdır.

Starlight (dokümantasyon çerçevesi) bu simetriye dayanır. Kullanıcı dil değiştirdiğinde, Starlight /docs/getting-started/ yolunu /fr/docs/getting-started/ ile değiştirir — aynı yol, farklı yerel ayar öneki. Fransızca dosya tam olarak fr/getting-started.md konumunda bulunmazsa, dil değiştirici bozulur veya sessizce İngilizce’ye geri döner.

Diller, Lichess, Chess.com ve FIDE kayıtlarından elde edilen verilere göre küresel satranç oynayan nüfusa göre sıralanmıştır. İngilizce kaynak dil olarak ilk sırada yer alır; diğerleri satranç sıralamalarını takip eder:

SıraKodDilStil
1enİngilizceBirincil kaynak
2esİspanyolcaStandard formal
3hiHintçeDevanagari alfabesi
4ruRusçaStandard formal
5deAlmancaStandard formal
6frFransızcaStandard formal
7ptPortekizceAvrupa Portekizcesi
11plLehçeStandard formal
12itİtalyancaStandard formal
13ukUkraynacaStandard formal
14trTürkçeStandard formal
17koKorece합니다/습니다 formu
18zhÇince (Basitleştirilmiş)Basitleştirilmiş karakterler
zh-twÇince (Geleneksel)Geleneksel karakterler
23nbNorveççe BokmålStandard Bokmål
beBelarusçaStandard Belarusça
34jaJaponcaです/ます formu

“Stil” sütunu önemlidir. Japonca ve Korece’de her cümleyi etkileyen resmi dil kayıtları (register) seçenekleri vardır. Çeviri istemi bu talimatları içerir, böylece model katı bir makine çıktısı yerine doğal ve akıcı metin üretir.

Bu sıralama ayrıca site başlığındaki dil açılır menüsünü de kontrol eder. En çok konuşulan satranç dilleri ilk sırada görünür, böylece kullanıcıların aşağı kaydırmadan kendi dillerini bulma olasılığı artar.

Tüm dokümantasyon src/content/docs/ dizininde İngilizce markdown olarak başlar. Frontmatter’da title ve description alanları bulunur:

---
title: "Getting Started"
description: "Install En Parlant~ and play your first game."
---
Download the latest release...

Bir Python betiği (scripts/translate-docs.py) her İngilizce kaynak dosyasını okur, Claude API’ye gönderir ve çevrilmiş markdown’ı yazar:

Terminal window
python3 scripts/translate-docs.py \
--anthropic-key $ANTHROPIC_API_KEY \
--model claude-opus-4-6 \
--workers 5

Betik, 28 kaynak dosyanın tamamını 16 hedef dile çevirmek için yaklaşık 60–70 dakika sürer (toplamda 448 dosya). Hız sınırlarını aşmamak için 5 paralel API çağrısı yapar.

Tek bir yeni dil için yaklaşık 4 dakika sürer.

Terminal window
pnpm build

Astro kaynak markdown dosyalarını okur, Starlight şablonları üzerinden işler ve statik HTML’yi dist/ dizinine çıktılar. Derleme, toplam ~500 sayfa için yaklaşık 30 saniye sürer.

Terminal window
pnpm run deploy

Derlenmiş siteyi Cloudflare Workers’a gönderir.

Çeviri betiği kasıtlı olarak basit tutulmuştur — yaklaşık 300 satır Python kodu. İşleyiş şöyledir:

┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ 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

İstem, Claude’a tam olarak neyi çevirmesi ve neyi olduğu gibi bırakması gerektiğini söyler:

  • Çevrilecek: düz metin, başlıklar, tablo etiketleri, frontmatter title ve description
  • İngilizce kalacak: kod blokları, satır içi kod, komut örnekleri, dosya yolları, URL’ler, ürün adları, kişi adları, ASCII diyagramlar

Bu ayrım kritik öneme sahiptir. pnpm build gibi bir komut her dilde pnpm build olarak kalmalıdır. “En Parlant~” veya “Stockfish” gibi ürün adları çevrilmez. Ancak “Getting Started” ifadesi Japonca’da “はじめに”, Rusça’da “Начало работы” olur.

Claude Opus 4.6, daha hızlı modellerden belirgin şekilde daha iyi çeviriler üretir. Fark şu noktalarda ortaya çıkar:

  • Doğal ifade — Opus, bir çevirmen gibi değil, ana dili konuşan biri gibi yazar. Hedef dilde İngilizce söz diziminin garip kaçacağı durumlarda cümleleri yeniden yapılandırır.
  • Teknik doğruluk — Satranç terminolojisi, TTS jargonu ve yazılım kavramları, doğru alana özgü terimler kullanılarak çevrilir.
  • Tutarlılık — Resmi dil kaydı (register) baştan sona tutarlı kalır. Japonca her yerde です/ます formunu kullanır; paragraf ortasında günlük ile resmi dil arasında geçiş yapmaz.
  • MDX işleme — Opus, .mdx dosyalarındaki JSX bileşen etiketlerini (<Card>, <CardGrid>) ve import ifadelerini bozmadan doğru şekilde korur.

Maliyet farkı gerçektir — Opus ile tam site çevirisi yaklaşık 28$, Sonnet ile 5$ civarıdır — ancak kullanıcıların gerçekten okuyacağı 448 dosya için kalite buna değer.

Doğru şekilde çalıştırılması en uzun süren kısım burasıydı.

Starlight, bir sayfanın dilini içerik slug’ının ilk segmentini kontrol ederek algılar. fr/docs/getting-started gördüğünde, fr ilk segment olduğu için bunun Fransızca olduğunu anlar. Ancak ilk uygulamada docs/fr/getting-started gibi slug’lar üretiliyordu — yerel ayar docs/’un altına gömülmüştü. Starlight ilk segment olarak docs’u görüyor, her şeyi İngilizce olarak değerlendiriyor ve ~500 yerine 7.000’den fazla yinelenen sayfa oluşturuyordu.

src/content.config.ts dosyasındaki özel bir generateId fonksiyonu, dosya yollarının içerik slug’larına nasıl dönüştürüleceğini kontrol eder:

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}`;
}

Bu, yerel ayar önekini docs/’un öncesine yerleştirir:

Dosya yoluSlugURL
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/

İngilizce defaultLocale: "root" kullanır; bu, önek olmadığı anlamına gelir — /en/docs/ değil, doğrudan /docs/ altında yer alır.

Aynı dosyadaki localeKeys dizisi, İngilizce dışındaki her yerel ayarı listelemelidir. Bir yerel ayar Astro yapılandırmasında mevcut olup bu dizide yoksa, çevrilmiş içerik İngilizce içerik olarak değerlendirilir — dil değiştirici bozulur ve sayfa sayısı patlar.

Astro slug eşlemelerini .astro/data-store.json dosyasında önbelleğe alır. Herhangi bir yerel ayar yapılandırma değişikliğinden sonra, yeniden derleme öncesinde bu dosyanın silinmesi gerekir; aksi takdirde derleme başarılı olur ancak eski (yanlış) yönlendirme kullanılır.

Kenar çubuğu astro.config.mjs dosyasında tanımlanır. Bir sayfaya işaret eden öğeler (slug özelliği) otomatik olarak çevrilmiş sayfanın frontmatter başlığını kullanır — elle çeviri gerekmez:

{ slug: "docs/getting-started" }
// English: "Getting Started" (from English frontmatter)
// French: "Premiers pas" (from French frontmatter)
// Japanese: "はじめに" (from Japanese frontmatter)

Ancak grup etiketleri ve harici bağlantılar açık çeviri gerektirir:

{
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" },
// ...
],
}

Yedi kenar çubuğu öğesi elle çeviri gerektirir: Welcome, Features, App Menus, Setup Guides, Under the Hood, Credits ve Accessibility. Yeni bir dil eklemek, bu yedi bloğun her birine birer giriş eklenmesi anlamına gelir.

En Parlant~, Yardım menüsünden bu dokümantasyona bağlantı verir. Bağlantı yerel ayar duyarlıdır — uygulamayı Fransızca kullanıyorsanız, Fransızca dokümantasyon açılır:

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]);

Uygulamada mevcut olan her dilin sitede karşılık gelen bir çevirisi vardır. Eşleme otomatiktir — fr_FR, /fr/docs/ ile; ja_JP, /ja/docs/ ile eşleşir. Tek istisna Geleneksel Çince’dir: zh_TW, /zh-tw/docs/ ile eşleşir (tire ile ayrılmış).

Zor kısımlar tamamlandı:

  1. Yönlendirme mimarisi çözüldü. generateId fonksiyonu, localeKeys dizisi ve defaultLocale: "root" yapılandırması birlikte çalışarak Starlight’ın doğru URL yapısını oluşturmasını sağlar. Bu en büyük sorun noktasıydı — Starlight ve Astro’daki 6’dan fazla kaynak dosya izlenerek bulunup düzeltildi.

  2. Çeviri betiği her şeyi halleder. Tüm sitenin yeniden çevirisi, tek dil eklenmesi, bireysel dosya güncellemeleri — hepsi aynı betik, farklı bayraklarla. Hız sınırlarında yeniden dener, işçiler arasında paralel çalışır ve hataları net şekilde raporlar.

  3. Yeni bir dil eklemek dört yapılandırma düzenlemesi ve tek bir komuttur. Yerel ayarı astro.config.mjs, content.config.ts ve translate-docs.py dosyalarına ekleyin, kenar çubuğu çevirilerini ekleyin, betiği çalıştırın. Yaklaşık 10 dakikalık çalışma artı 4 dakikalık çeviri süresi.

  4. İçerik güncellemek daha da basittir. İngilizce kaynağı düzenleyin, yalnızca değişen dosyalar için betiği --files ve --overwrite bayraklarıyla çalıştırın, yeniden derleyin. Ya da küçük metin düzeltmeleri için çevrilmiş dosyaları doğrudan düzenleyin.

  5. Tüm süreç bir beceri (skill) olarak kayıtlıdır. /translate_docs çalıştırıldığında tüm süreç adım adım anlatılır — hangi mod kullanılacak, hangi bayraklar geçilecek, uçuş öncesi kontroller, çeviri sonrası doğrulama. Kurumsal bilgi birikimi gerektirmez.

16 dilde toplam 448 dosyanın çevirisi yaklaşık 28$‘a mal oldu ve yaklaşık 70 dakika sürdü. Tek bir yeni dil yaklaşık 1,70$‘a mal olur. Tek bir dosyanın tüm dillere yeniden çevrimi yaklaşık 1$‘a mal olur. Bunlar, dokümantasyonun 17 dilde güncel tutulmasının süregelen maliyetleridir.