Ana içeriğe geç

Yerelleştirme Çeviri Değildir: Türkçe Arayüzde Yapılan Hatalar

Teknik3 dk

Yerelleştirme çeviriden fazlası: tarih, para, sıralama, çoğul ve harf kuralları da hedef dile göre değişiyor. Türkçe arayüzde en kolay bozulan yerleri sırayla anlattım.

Çeviri Değil, Uyarlama

W3C iki kavramı ayırıyor. Internationalization (i18n), ürünü farklı dil ve kültürlere kolayca uyarlanabilecek şekilde tasarlamak. Localization (l10n) ise bu uyarlamanın kendisi. Çeviri bunun yalnızca bir parçası: tarih ve sayı biçimleri, para birimi, sıralama, isim sırası ve adres biçimi de yerele (locale) göre değişiyor.

i18n koda ait iş: UI metnini koddan ayırmak, Unicode kullanmak, biçimlendirmeyi yerele bırakmak. W3C bunu sonradan eklemenin pahalı olduğunu söylüyor ve Y2K'yı örnek veriyor.

Metni Bölme, Eki Tahmin Etme

Cümleyi parçalara bölüp birleştirirsen çevirmen sırayı değiştiremez. Her cümle tek bir mesaj olmalı, değişkenler yer tutucu olarak içinde durmalı. (FormatJS de aynısını öneriyor.)

// Kaçın
const greeting = t("Hoş geldin")
return `${greeting}, ${name}!`
 
// Tercih et
return t("Hoş geldin, {name}!", { name })

Türkçe'de asıl sorun değişkenden sonra gelen ek. Ek, kelimenin son harfine ve son ünlüsüne göre değişiyor:

DeğişkenYönelmeBulunmaİlgi
AhmetAhmet'eAhmet'teAhmet'in
AyşeAyşe'yeAyşe'deAyşe'nin
KarsKars'aKars'taKars'ın

{name}'e yazarsan Ayşe'e ve Kars'e çıkar. Logrus IT aynı sorunu oyun yerelleştirmesinde "Rodrigo'ya" ve "Elly'ye" örneğiyle anlatıyor.

Pratik çözüm, cümleyi değişkenden sonra ek gerekmeyecek şekilde kurmak:

// Ek gerekir
t("{name}'e mesaj gönderildi", { name })
 
// Ek gerekmez
t("Alıcı: {name}", { name })

Cümle biraz daha kuru kalıyor ama hiçbir isimde bozulmuyor.

İ ve ı

Türkçe'de iki ayrı i var: i/İ ve ı/I. JavaScript'in varsayılan büyük-küçük harf dönüşümü bunu bilmiyor (MDN):

"izmir".toUpperCase()              // "IZMIR"
"izmir".toLocaleUpperCase("tr")    // "İZMİR"
 
"ISPARTA".toLowerCase()            // "isparta"
"ISPARTA".toLocaleLowerCase("tr")  // "ısparta"

Ama her yere "tr" vermek de hata. Kullanıcıya gösterilen metinde doğru, fakat HTML etiketi, dosya uzantısı ve enum gibi makine değerlerinde yanlış sonuç verir: "TITLE".toLocaleLowerCase("tr") sonucu "tıtle" olur.

Çoğul ve Biçimler

Türkçe'de sayıdan sonra isim tekil kalır: 5 kedi, 5 kediler değil. Intl.PluralRules("tr") de yalnızca one ve other döndürüyor, yani iki dal aynı yazılıyor. Çoğul sözdizimi yine de sıfır durumu ve ileride eklenecek diller için yer açıyor:

t("{count, plural, =0 {Yorum yok} other {# yorum}}", { count })

Rusça'da one/few/many/other, Arapça'da altı kategori var (MDN).

Tarih, sayı ve para birimi de yerele göre değişiyor:

tr-TRen-US
Uzun tarih31 Ekim 2026October 31, 2026
Kısa tarih31.10.202610/31/26
Para (TRY)₺1.234,50TRY 1,234.50
Sayı1.234.567,891,234,567.89

Yüzde işareti bile yer değiştiriyor: Türkçe'de %25, İngilizce'de 25%. Intl.DateTimeFormat ve Intl.NumberFormat bu farkları kendileri uyguluyor.

Bu hataların hepsi aynı varsayımdan çıkıyor: İngilizce'nin kuralları her dilde geçerli sanılıyor. Metin kusursuz çevrilse bile ek, harf, çoğul ve biçimler kodda İngilizce'ye göre yazıldıysa arayüz bozuk kalıyor.