Ders 11 / 24
Uluslararasılaştırma API'si
Sayı, tarih ve sıralamanın yerel ayara göre yapılması; yerel ayar etiketinin yapısı, biçimlemenin parçalara ayrılması, saat diliminin rolü, harf sıralamasının abeceye bağlılığı ve biçimleyicinin kurulum maliyeti.
İçindekiler
Kare içinde yapılan işin bir bölümü metin üretmektir: ölçüm değerinin yanına birimi yazmak, zaman damgasını okunur bir tarihe çevirmek, listeyi ada göre sıralamak. Bu işlemlerin hiçbiri evrensel değildir.
Ondalık ayırıcı her yerde aynı karakter değildir, tarih alanlarının sırası dile göre değişir, harflerin sıralaması abeceye bağlıdır ve Türkçede noktalı ile noktasız harf ayrı harflerdir. Elle yazılan biçimleme kodu bu farkları taşıyamaz. Tarayıcı bunun için, dil verisini kendi taşıyan bir arayüz ailesi sunar.
Bu dersteki çıktılar bir çalışma zamanında üretilmiştir. Biçimlenmiş metinlerin tam karakter dizisi çalışma zamanının taşıdığı dil verisine bağlıdır ve sürümler arasında değişebilir; değişmeyen şey işlemin kendisidir. Bu ayrım dersin son bölümünde bir kurala dönüşür.
Yerel Ayar Etiketi
Bütün bu arayüzler bir yerel ayar (locale) etiketi alır. Etiket kısa çizgiyle ayrılmış
alt etiketlerden oluşur: dil, isteğe bağlı yazı sistemi, isteğe bağlı bölge. tr yalnız
dili, tr-TR dil ile bölgeyi, sr-Latn-RS üçünü birden bildirir.
Bölge alt etiketi dili değil kuralları seçer: aynı dilin iki bölgesinde para birimi, ölçü sistemi ve tarih sırası ayrışabilir. Etiketin sonuna eklenen uzantılarla takvim, numaralandırma sistemi ve sıralama düzeni de istenebilir.
Kullanıcının tercihi tarayıcıdan okunur ve bir liste olarak gelir: birinci tercih desteklenmiyorsa ikincisi denenir. Arayüzlere de tek etiket yerine liste verilebilir; seçim, sağlanan verilerle kesişim alınarak yapılır. Hangi ayarın seçildiği ve hangi seçeneklerin geçerli olduğu, biçimleyiciden geri sorulabilir.
Sayı Biçimleme
// sayi.mjs — ayni sayinin yerel ayara gore bicimlenmesi const deger = -1234.567; for (const yerel of ["tr-TR", "en-US", "de-DE"]) { const bicim = new Intl.NumberFormat(yerel, { maximumFractionDigits: 2 }); console.log(yerel, "->", bicim.format(deger)); } const sicaklik = new Intl.NumberFormat("tr-TR", { style: "unit", unit: "celsius", unitDisplay: "short", maximumFractionDigits: 1, }); const oran = new Intl.NumberFormat("tr-TR", { style: "percent", maximumFractionDigits: 1 }); const derli = new Intl.NumberFormat("tr-TR", { notation: "compact" }); const derliMetin = derli.format(48210); console.log("sicaklik:", sicaklik.format(-4.23)); console.log("oran :", oran.format(0.0731)); console.log("derli :", derliMetin, "| kod noktalari:", [...derliMetin].map((c) => "U+" + c.codePointAt(0).toString(16).toUpperCase().padStart(4, "0")).join(" ")); // Parcalara ayirmak, bicimli metnin icinden alan secmeyi saglar. console.log(JSON.stringify(sicaklik.formatToParts(-4.23)));
tr-TR -> -1.234,57
en-US -> -1,234.57
de-DE -> -1.234,57
sicaklik: -4,2°C
oran : %7,3
derli : 48 B | kod noktalari: U+0034 U+0038 U+00A0 U+0042
[{"type":"minusSign","value":"-"},{"type":"integer","value":"4"},{"type":"decimal","value":","},{"type":"fraction","value":"2"},{"type":"unit","value":"°C"}]
İlk üç satır ondalık ve binlik ayırıcıların yer değiştirdiğini gösterir; aynı sayı üç yazımla görünür. Bir sayıyı noktayla birleştirip ekrana yazan kod, kullanıcının binlik ayırıcı sandığı bir noktayla karşılaşabilir.
Yüzde satırı ikinci bir farkı taşır: Türkçede işaret sayının önüne gelir. Birim ve işaretin nereye konacağı da dil verisinden gelir; elle birleştirme bu bilgiyi kaybeder.
Derli gösterimin kod noktaları üçüncü bir uyarı taşır. Sayı ile kısaltma arasındaki
karakter sıradan boşluk değil, Metin Etiketleri dersinde tanımlanan bölünmez boşluktur;
kod noktası listesinde U+00A0 olarak görünür. Metni boşluktan bölerek sayıyı geri almaya
çalışan kod bu karakterle karşılaşır. Biçimlenmiş metnin çözümlenmemesi gerektiğinin somut
kanıtı budur.
Son satır en kullanışlı işlemi gösterir. Biçimlenmiş metin parçalarına ayrılabilir ve her parçanın türü bildirilir. Böylece tam sayı kısmı büyük, ondalık kısmı küçük yazılabilir ya da birim ayrı bir ögeye alınabilir; bunun için metni bölmeye çalışmak gerekmez.
Biçimlemenin girdisi de dikkat ister. Sayı biçimleyici, dizgi değil sayı bekler; Depolama API’leri dersinde anılan tip kaybı burada görünür hâle gelir.
Tarih, Saat ve Saat Dilimi
// tarih.mjs — ayni anin yerel ayara ve saat dilimine gore bicimlenmesi const an = new Date("2024-02-11T06:05:00Z"); // evrensel zamanda sabit bir an for (const [yerel, dilim] of [["tr-TR", "Europe/Istanbul"], ["en-US", "America/New_York"]]) { const bicim = new Intl.DateTimeFormat(yerel, { dateStyle: "long", timeStyle: "short", timeZone: dilim, }); console.log(yerel.padEnd(6), dilim.padEnd(17), bicim.format(an)); } // Alanlari ayri ayri istemek ve parcalara ayirmak const alanli = new Intl.DateTimeFormat("tr-TR", { weekday: "long", day: "numeric", month: "long", timeZone: "Europe/Istanbul", }); console.log("alanli :", alanli.format(an)); console.log("parcalar:", alanli.formatToParts(an).map((p) => `${p.type}=${p.value}`).join(" ")); // Goreli zaman: birim ve sayi verilir, metin yerel ayardan gelir. const goreli = new Intl.RelativeTimeFormat("tr-TR", { numeric: "auto" }); for (const [sayi, birim] of [[-1, "day"], [-3, "hour"], [0, "day"], [2, "week"]]) console.log("goreli :", goreli.format(sayi, birim));
tr-TR Europe/Istanbul 11 Şubat 2024 09:05 en-US America/New_York February 11, 2024 at 1:05 AM alanli : 11 Şubat Pazar parcalar: day=11 literal= month=Şubat literal= weekday=Pazar goreli : dün goreli : 3 saat önce goreli : bugün goreli : 2 hafta sonra
İlk iki satır aynı anı gösterir. Ölçüm kaydında saklanan şey evrensel zamandaki tek bir andır; kullanıcıya gösterilen ise o anın kullanıcının saat dilimindeki karşılığıdır. Saat diliminin biçimleyiciye açıkça verilmesi, kaydın hangi dilimde okunduğunu belirsiz bırakmaz. Verilmediğinde cihazın dilimi kullanılır ve iki kullanıcı aynı kaydı farklı saatlerle görür.
Alan sırası da dilden gelir: Türkçede gün, ay, gün adı; başka bir dilde bambaşka bir sıra. Parça listesindeki ayraçlar bile dil verisinin bir parçasıdır; bu, tarihi elle birleştirmenin neden çalışmadığını gösterir.
Göreli zaman biçimleyicisi ayrı bir sorunu çözer. “Kaç birim önce” hesabı programın işidir; o hesabın metne dönüşmesi dil verisinin. Otomatik kip, karşılığı olan yerlerde sayı yerine sözcük kullanır — çıktıdaki “dün” ve “bugün” bunun sonucudur.
Sıralama ve Karşılaştırma
Dizgi karşılaştırmasının varsayılan biçimi kod noktalarını karşılaştırır. Karakter Kodlamaları dersinde tanımlanan bu sıra, hiçbir dilin abecesine karşılık gelmez.
// siralama.mjs — kod noktasi sirasi ile yerel ayara duyarli siralama const istasyonlar = ["Iğdır", "İzmir", "Isparta", "Şanlıurfa", "Sivas", "Çorum", "Ordu"]; console.log("kod noktasi:", istasyonlar.toSorted().join(" ")); console.log("tr-TR :", istasyonlar.toSorted(new Intl.Collator("tr").compare).join(" ")); console.log("en-US :", istasyonlar.toSorted(new Intl.Collator("en").compare).join(" ")); // Duyarlilik: buyuk-kucuk ve aksan farkinin esitlik sayilip sayilmayacagi const gevsek = new Intl.Collator("tr", { sensitivity: "base" }); console.log("'Izmir' ile 'İZMİR' esit mi:", gevsek.compare("Izmir", "İZMİR") === 0); // Sayisal siralama: dizgi icindeki sayilar sayi olarak karsilastirilir const kodlar = ["T-2", "T-10", "T-1", "T-21"]; console.log("dizgi olarak:", kodlar.toSorted(new Intl.Collator("tr").compare).join(" ")); console.log("sayi olarak :", kodlar.toSorted(new Intl.Collator("tr", { numeric: true }).compare).join(" ")); // Cogul kurallari: hangi kategoriye dustugu sorulur, metin yerelden gelir const cogul = new Intl.PluralRules("tr"); console.log("cogul tr :", [0, 1, 2, 11].map((n) => `${n}=${cogul.select(n)}`).join(" ")); console.log("cogul en :", [0, 1, 2, 11].map((n) => `${n}=${new Intl.PluralRules("en").select(n)}`).join(" "));
kod noktasi: Isparta Iğdır Ordu Sivas Çorum İzmir Şanlıurfa tr-TR : Çorum Iğdır Isparta İzmir Ordu Sivas Şanlıurfa en-US : Çorum Iğdır Isparta İzmir Ordu Şanlıurfa Sivas 'Izmir' ile 'İZMİR' esit mi: false dizgi olarak: T-1 T-10 T-2 T-21 sayi olarak : T-1 T-2 T-10 T-21 cogul tr : 0=other 1=one 2=other 11=other cogul en : 0=other 1=one 2=other 11=other
İlk satır kod noktası sırasının sonucudur: aksanlı harfler abecenin dışına atılmış, Ç ile
Ş listenin sonuna düşmüştür. İkinci satır Türkçe abeceyi izler.
Üçüncü satır ince bir ayrım taşır. Türkçe ile İngilizce sıralama yalnızca Ş harfinde
ayrışır: Türkçede Ş ayrı bir harftir ve S den sonra gelir, İngilizce sıralamada S in
bir çeşitlemesi sayılır ve Şanlıurfa Sivas tan önce gelir. Aynı veri, kullanıcının
diline göre farklı sıralanır.
Dördüncü satır Türkçenin bilinen tuzağını gösterir. En gevşek duyarlılıkta bile noktalı ve noktasız harf eşit sayılmaz, çünkü Türkçede bunlar aynı harfin iki biçimi değil, iki ayrı harftir. Büyük-küçük harf duyarsız arama yapan kodun bu ayrımı gözetmesi gerekir.
Beşinci ve altıncı satırlar sayısal sıralamayı gösterir: ölçüm kodları dizgi olarak
sıralandığında T-10 T-2 den önce gelir. Sayısal seçenek, dizgi içindeki sayı öbeklerini
sayı olarak karşılaştırır.
Son iki satır çoğul kurallarını gösterir. Arayüz metni yazılırken “1 ölçüm / 2 ölçüm” ayrımının hangi kategorilere göre yapılacağı dile bağlıdır; kategori adı sorulur, karşılık gelen metni uygulama sağlar. Türkçe ile İngilizcenin kategorileri bu örnekte örtüşür; başka dillerde ikiden çok kategori bulunur ve iki dallı bir koşul yetmez.
Biçimleyicinin Maliyeti ve Kararlılığı
Biçimleyici nesnesinin kurulması pahalıdır; dil verisi çözümlenir ve seçenekler uzlaştırılır. Biçimleme işleminin kendisi ise ucuzdur. Buradan tek bir kural çıkar: biçimleyici bir kez kurulur ve yeniden kullanılır. Bin satırlık bir tabloyu çizerken her hücrede yeni bir biçimleyici kuran kod, önceki dersin kare bütçesini tek başına tüketebilir.
İkinci kural çıktının kararlılığıyla ilgilidir. Üretilen metin kullanıcıya gösterilmek içindir; çözümlenmek, karşılaştırılmak ya da sunucuya gönderilmek için değil. Dil verisi sürümler arasında değişebilir; boşluk karakteri, ayraç ya da kısaltma başka bir biçim alabilir. Veri her zaman ham hâliyle saklanır ve taşınır; biçimleme yalnızca sunum katmanında yapılır. Sınamalarda da biçimlenmiş metnin tamamı bir sabitle karşılaştırılmaz; parçalara ayırma işlemi bu yüzden vardır.
Özet
- Yerel ayar etiketi dil, yazı sistemi ve bölge alt etiketlerinden oluşur; bölge dili değil biçimleme kurallarını seçer ve tercih bir liste olarak verilir.
- Ondalık ayırıcı, binlik ayırıcı ve işaretin konumu dil verisinden gelir; sayıyı elle birleştiren kod bu bilgiyi kaybeder.
- Biçimlenmiş metin parçalara ayrılabilir; alanları ayrı biçemlemek için metni bölmek gerekmez.
- Ölçüm anı evrensel zamanda saklanır ve gösterim sırasında saat dilimi açıkça verilir; verilmediğinde cihazın dilimi kullanılır.
- Kod noktası sırası hiçbir abeceye karşılık gelmez; yerele duyarlı sıralama abeceyi izler ve Türkçede noktalı ile noktasız harf en gevşek duyarlılıkta bile ayrı harftir.
- Biçimleyici bir kez kurulup yeniden kullanılır; ürettiği metin sunum içindir, veri her zaman ham hâliyle saklanır ve çözümleme girdisi olarak kullanılmaz.
Sonraki Adım
Yerel ayar, saat dilimi ve dil tercihi kullanıcının cihazından izin sorulmadan okunur; bunlar sayfanın zaten bildiği bilgilerdir. Ölçüm istasyonu sayfasının isteyeceği başka şeyler de vardır: ölçümün alındığı noktanın koordinatları, bir arıza kaydına eklenecek fotoğraf, sesli not. Bunların hiçbiri sorulmadan verilmez. Sonraki ders, izin gerektiren yetenekleri, iznin durumlarını, kullanıcı hareketine bağlılığı ve isteğin reddedilmesi durumunda sayfanın nasıl çalışmayı sürdüreceğini ele alır.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.