Türkçe'nin 'i' sorunu ve her projede tekrar eden üç hata
toLowerCase() bir gün beklediğinizi yapmaz. Türkçe yerelleştirmede karakter, sıralama ve arama tarafında sürekli tekrar eden hatalar ve doğru çözümleri.
Türkçe destekleyen her projede aynı üç hata tekrar ediyor. Üçü de ilk gün görünmüyor, üçü de kullanıcı sayısı arttığında ortaya çıkıyor.
1. Nokta problemi: I ↔ ı ↔ İ ↔ i
Latin alfabesini kullanan çoğu dilde I harfinin küçüğü i'dir. Türkçe'de değil. Türkçe'de dört ayrı harf var:
| Büyük | Küçük |
|---|---|
I |
ı (noktasız) |
İ |
i (noktalı) |
Bu, dilden bağımsız bir toLowerCase() çağrısının Türkçe metinde yanlış sonuç üreteceği anlamına geliyor.
"ISTANBUL".toLowerCase() // "istanbul" ← yanlış
"ISTANBUL".toLocaleLowerCase("tr") // "ıstanbul" ← doğru
"iyi".toLocaleUpperCase("tr") // "İYİ" ← doğru
"iyi".toUpperCase() // "IYI" ← yanlış
Kural: Kullanıcıya gösterilecek metinlerde her zaman toLocaleLowerCase("tr") / toLocaleUpperCase("tr") kullanın.
Ters kural, ve daha önemlisi: Sistem içi karşılaştırmalarda (kullanıcı adı, e-posta, dosya uzantısı, HTTP başlığı, protokol anahtarı) asla Türkçe yerel ayar kullanmayın. Buralarda toLowerCase() — ya da daha güvenlisi toLocaleLowerCase("en-US") — doğru olandır.
Bunun neden önemli olduğunu gösteren klasik hata:
// Bir kullanıcı sistem dili Türkçe olan bir makinede çalışıyorsa:
if (dosyaAdi.toLocaleLowerCase() === "index.html") { ... }
// "INDEX.HTML" → "ındex.html" → eşleşme yok
JavaScript'te toLowerCase() yerel ayardan etkilenmez, ama Java, C#, PHP gibi dillerde varsayılan yerel ayar sistemden gelir ve bu hata gerçek bir üretim hatasıdır. Türkiye'de sunucu işleten ekipler bunu en az bir kez yaşıyor.
2. Sıralama: alfabetik ≠ kod noktası sırası
Varsayılan sıralama, karakterlerin Unicode kod noktalarına göre yapılır. Türkçe alfabede ç harfi c'den sonra gelir; kod noktası sırasında ise bütün ASCII harflerden sonra gelir.
const iller = ["Çanakkale", "Ankara", "İzmir", "Isparta", "Adana"];
iller.sort();
// ["Adana", "Ankara", "Isparta", "Çanakkale", "İzmir"] ← yanlış
iller.sort((a, b) => a.localeCompare(b, "tr"));
// ["Adana", "Ankara", "Çanakkale", "Isparta", "İzmir"] ← doğru
Veritabanı tarafında da aynı sorun var ve orada daha sinsi, çünkü uygulamada düzeltseniz bile ORDER BY sunucunun collation ayarına göre çalışıyor. PostgreSQL'de tr_TR.UTF-8, MySQL'de utf8mb4_turkish_ci gibi bir collation seçilmemişse liste yanlış sıralanır. Bu ayarı veritabanı oluşturulurken vermek, sonradan değiştirmekten çok daha kolay.
3. Arama: kullanıcı şapkasız yazar
Kullanıcı "çigköfte" yazar, veri "Çiğ köfte" olarak kayıtlıdır ve arama sonuç vermez. Kullanıcının hatası değil — arama, aksanlara duyarsız olmalı.
Pratik çözüm, kayıt anında bir arama anahtarı alanı üretmek:
function aramaAnahtari(metin) {
const harita = { ç: "c", ğ: "g", ı: "i", ö: "o", ş: "s", ü: "u", â: "a", î: "i", û: "u" };
return metin
.toLocaleLowerCase("tr")
.replace(/[çğıöşüâîû]/g, (h) => harita[h])
.replace(/[^a-z0-9]+/g, " ")
.trim();
}
Bu alanı veritabanında saklayıp aramayı onun üzerinde yapmak, her sorguda dönüştürme yapmaktan hem hızlı hem indekslenebilir.
Alternatif olarak PostgreSQL'de unaccent eklentisi de iş görür, ancak unaccent Türkçe'ye özel ı → i eşlemesini varsayılan sözlüğünde beklediğiniz gibi ele almayabilir; kendi sözlüğünüzü tanımlamanız gerekir. Uygulama tarafında üretilen anahtar, taşınabilirliği daha yüksek bir çözüm.
Ek: slug üretimi
URL üretirken aynı dönüşüm gerekiyor, bir farkla — slug'da boşluk yerine tire kullanılıyor ve sonuç kalıcı olmalı. Slug bir kez üretilip saklanmalı; başlık düzenlendiğinde otomatik değişmemeli. Değişirse eski bağlantılar kırılır ve bunu fark etmeniz aylar sürer.
Kontrol listesi
Türkçe destekleyen bir projeye şu dört maddeyi ekleyin:
- Sistem içi karşılaştırmalarda yerel ayarsız
toLowerCase, kullanıcıya gösterimde"tr"ile. - Listelemede
localeCompare(a, b, "tr")ve veritabanında Türkçe collation. - Arama için normalize edilmiş, indeksli bir yardımcı alan.
- Slug üretimi tek bir yardımcı fonksiyonda, ve slug kalıcı.
Dördü de yarım saatlik iş. Sonradan düzeltmek yarım günlük.
- türkçe
- unicode
- yerelleştirme
- javascript