Mert Özen Her Satırda Daha İleri
Frontend JavaScript Orta — #19

JavaScript Intl ile Yerelleştirme: Collator ile Türkçe Sıralama, PluralRules, ListFormat, Segmenter, DisplayNames ve DurationFormat

Mert Özen 15 Kas 2026 13 dk 6 görüntülenme
JavaScript Intl ile Yerelleştirme: Collator ile Türkçe Sıralama, PluralRules, ListFormat, Segmenter, DisplayNames ve DurationFormat

Türkçe sıralama için Intl.Collator("tr"), tekil/çoğul metin için PluralRules, "Dune, Emma ve The Hobbit" için ListFormat, emoji'li yorumda karakter sınırı için Segmenter ve okuma süresi için DurationFormat kullanılır. Bookstore örnekleriyle her birini, tarayıcı farklarını ve instance'ları cache'lemenin neden önemli olduğunu gerçek çıktılarla gösteriyoruz.

Sürüm notu: Bu yazıdaki kodlar ES2026 (ECMAScript 2026) ve güncel tarayıcılar (Chrome, Edge, Firefox, Safari) içindir. Örnekler Node.js 24.22 ile ve Playwright 1.65'in Chromium 158 ve WebKit motorlarında denenmiştir.

Önce Tahmin Et

Üç satır, üç küçük soru. Konsola ne yazar? Cevaplara bakmadan önce tahminini yap:

console.log(["Volume 10", "Volume 2", "Volume 1"].sort());
console.log("İSTANBUL".toLowerCase() === "istanbul");
console.log("👍🏽".length);

Birincisi ["Volume 1", "Volume 10", "Volume 2"] yazar, çünkü varsayılan sort sayıyı değil karakterleri karşılaştırır. İkincisi false: toLowerCase büyük İ'yi "i" artı birleşen nokta işaretine çevirir, sonuç 8 değil 9 karakterlik bir string olur. Üçüncüsü 4: ekranda tek bir el işareti görürsün, ama string'in içinde dört UTF-16 birimi vardır. Üçünün de çözümü Intl'de. Temel serideki string, number ve array yazılarında toLocaleUpperCase, Intl.NumberFormat ve localeCompare ile başladığımız, bir önceki yazıda Intl.DateTimeFormat ve RelativeTimeFormat ile devam ettiğimiz işi bu yazıda tamamlıyoruz.

Intl'in kuralları ECMA-402'de (Intl API'sinin standardı; son baskısı Haziran 2026'da yayımlanan 13. baskı) tanımlı. Hangi dilde hangi kelimenin, hangi sıranın kullanılacağı ise engine'in içindeki dil verisinden gelir. Bu veri CLDR'dan (Unicode Common Locale Data Repository; dillerin sıralama, çoğul ve biçim kurallarını tutan ortak veri) gelir; çoğu engine onu ICU (International Components for Unicode; bu kuralları uygulayan C/C++ library'si) üzerinden kullanır. Bu yazıdaki Node.js 24.22, ICU 78.3 ve CLDR 48 ile geliyor.

Intl.Collator ile Türkçe Sıralama

Sitedeki serilerin ortak örnek uygulaması Bookstore'un (bir online kitapçı) katalogunda Türk yazarlar için bir "Yazara göre" sıralaması yapıyoruz. Önce varsayılan sort, sonra Türkçe ve İngilizce kurallar:

const authors = ["Orhan Pamuk", "Çetin Altan", "Ömer Seyfettin", "İlhan Berk",
  "Işıl Özgentürk", "Sait Faik", "Şebnem İşigüzel", "Cemal Süreya"];

console.log([...authors].sort());
// ["Cemal Süreya", "Işıl Özgentürk", "Orhan Pamuk", "Sait Faik", "Çetin Altan", "Ömer Seyfettin", "İlhan Berk", "Şebnem İşigüzel"]

const trCollator = new Intl.Collator("tr");
console.log([...authors].sort(trCollator.compare));
// ["Cemal Süreya", "Çetin Altan", "Işıl Özgentürk", "İlhan Berk", "Orhan Pamuk", "Ömer Seyfettin", "Sait Faik", "Şebnem İşigüzel"]

console.log([...authors].sort(new Intl.Collator("en").compare));
// ["Cemal Süreya", "Çetin Altan", "İlhan Berk", "Işıl Özgentürk", "Ömer Seyfettin", "Orhan Pamuk", "Sait Faik", "Şebnem İşigüzel"]

Varsayılan sıralama UTF-16 kod birimlerine bakar; Ç, Ö, İ ve Ş ASCII harflerinin hepsinden büyük olduğu için listenin sonuna düşer. Intl.Collator("tr") Türk alfabesini bilir: C'den sonra Ç, I'dan sonra İ, O'dan sonra Ö gelir. İngilizce kurallar da Ç'yi C'nin yanına koyar ama farkı ikinci sıraya bırakır. Ö'yü O'nun bir aksanlı hâli sayar, bu yüzden "Ömer" "Orhan"ın önüne geçer. I ile İ'yi de aynı harf gibi görür ve sonraki harflere bakar ("l", "ş"'den önce gelir). Aynı veri, iki doğru ama farklı sıralama. Hangi dilin kuralını kullanacağını içeriğin dili belirler, arayüzün dili değil: Bookstore'un İngilizce arayüzünde de Türk yazarlarının listesi Türk alfabesine göre sıralanmalı.

compare bir bound function olduğu için sort'a doğrudan verebilirsin; a.localeCompare(b, "tr") ile aynı sonucu verir. Fark, localeCompare'in her çağrıda dil ayarlarını yeniden çözmesi; bunun maliyetine Üretimde Dikkat bölümünde bakacağız.

numeric ve sensitivity: Cilt Numaraları ve Arama

Collator'ın iki seçeneği günlük işin çoğunu çözer. numeric: true, string içindeki rakamları sayı olarak karşılaştırır. sensitivity ise iki string'in hangi farkla "farklı" sayılacağını belirler: "base" yalnız temel harfe bakar, "accent" aksanı da, "case" büyük-küçüğü de hesaba katar; varsayılan "variant" her şeye bakar:

const volumes = ["Volume 10", "Volume 2", "Volume 1"];
const numericCollator = new Intl.Collator("en", { numeric: true });
console.log(volumes.toSorted(numericCollator.compare)); // ["Volume 1", "Volume 2", "Volume 10"]

const trBase = new Intl.Collator("tr", { sensitivity: "base" });
const enBase = new Intl.Collator("en", { sensitivity: "base" });

console.log(trBase.compare("Dune", "dune"));         // 0
console.log(trBase.compare("istanbul", "İSTANBUL")); // 0
console.log(trBase.compare("çeşme", "cesme"));       // 1
console.log(enBase.compare("çeşme", "cesme"));       // 0

Son iki satır önemli. İngilizce kurallarda ç, c'nin aksanlı hâlidir; "base" onu yok sayar ve iki kelime eşit çıkar. Türkçede ç ayrı bir harftir, aksan değil; "base" ile bile "çeşme" ile "cesme" farklıdır. Türkçe klavyesi olmayan bir müşteri "cesme" yazarak "Çeşme" adlı bir kitabı bulsun istiyorsan Türkçe collator bunu yapmaz; aramayı İngilizce kurallarla ya da ayrı bir normalleştirme adımıyla yapman gerekir.

Collator iki string'i baştan sona karşılaştırır; "içinde geçiyor mu" sorusuna cevap vermez. Katalog aramasında en sık yapılan iş, iki tarafı aynı dilin kurallarıyla küçük harfe çevirip includes ile bakmak:

function matchesQuery(title, query) {
  return title.toLocaleLowerCase("tr").includes(query.toLocaleLowerCase("tr"));
}

console.log(matchesQuery("Üç İstanbul", "İSTANBUL"));            // true
console.log("Üç İstanbul".toLowerCase().includes("istanbul"));  // false

Tahmin bölümündeki ikinci satırın cevabı da burada: toLowerCase dilden bağımsız çalıştığı için İ'yi "i" ve birleşen bir nokta işaretine çevirir, "istanbul" aranan metnin içinde hiç geçmez.

Intl.PluralRules: "1 Book", "3 Books"

Sepet rozetinin altındaki metin İngilizcede kitap sayısına göre değişir: "1 book", "3 books". Bunu count === 1 ile çözmek İngilizce için yeter, ama başka dillerde çoğul kuralları çok daha karışık olabilir. Intl.PluralRules bir sayının o dilde hangi çoğul kategorisine düştüğünü söyler; metni sen seçersin:

const cartMessages = {
  en: { one: "{count} book in your cart", other: "{count} books in your cart" },
  tr: { one: "Sepetinizde {count} kitap var", other: "Sepetinizde {count} kitap var" }
};
const pluralRules = { en: new Intl.PluralRules("en"), tr: new Intl.PluralRules("tr") };

function cartLabel(lang, count) {
  const category = pluralRules[lang].select(count);
  return cartMessages[lang][category].replace("{count}", count);
}

console.log(cartLabel("en", 1)); // "1 book in your cart"
console.log(cartLabel("en", 3)); // "3 books in your cart"
console.log(cartLabel("en", 0)); // "0 books in your cart"
console.log(cartLabel("tr", 3)); // "Sepetinizde 3 kitap var"
console.log(pluralRules.tr.resolvedOptions().pluralCategories); // ["one", "other"]

Son satır şaşırtıcı gelebilir: Türkçede sayıdan sonra isim çoğul eki almaz ("3 kitap"), ama CLDR Türkçe için de one ve other diye iki kategori tanımlar. Bu yüzden Türkçe mesajlarda iki kategoriye aynı metni koyduk. Kategoriyi kodda if ile değil, mesaj object'inde key olarak tutmak, çevirmenin kategori başına metin girebilmesini sağlar.

type: "ordinal" sıra sayılarını verir. Çok satanlar listesindeki "1st", "22nd" gibi etiketler için:

const enOrdinal = new Intl.PluralRules("en", { type: "ordinal" });
const suffixes = { one: "st", two: "nd", few: "rd", other: "th" };
const rankLabel = (n) => `${n}${suffixes[enOrdinal.select(n)]}`;

console.log([1, 2, 3, 4, 11, 12, 13, 21, 22, 23].map(rankLabel));
// ["1st", "2nd", "3rd", "4th", "11th", "12th", "13th", "21st", "22nd", "23rd"]

console.log(new Intl.PluralRules("tr", { type: "ordinal" }).resolvedOptions().pluralCategories);
// ["other"]

İngilizcede 11, 12 ve 13'ün istisna olduğunu sen yazmadın, kurallar biliyor. Türkçede ise tek kategori var; Türkçe arayüzde sıra sayısını "1." ya da "1'inci" gibi kendi kuralınla yazarsın, çünkü ek, sayının okunuşuna göre değişir.

Intl.ListFormat ve Intl.DisplayNames

Sipariş özetindeki "Dune, Emma ve The Hobbit" cümlesini join(", ") ile kurmaya kalkınca son virgülü "ve"ye çevirmek için ayrı kod yazarsın; İngilizcede de Oxford virgülü işin içine girer. Intl.ListFormat bunu dile göre yapar:

const cartTitles = ["Dune", "Emma", "The Hobbit"];

console.log(new Intl.ListFormat("tr").format(cartTitles));    // "Dune, Emma ve The Hobbit"
console.log(new Intl.ListFormat("en").format(cartTitles));    // "Dune, Emma, and The Hobbit"
console.log(new Intl.ListFormat("en-GB").format(cartTitles)); // "Dune, Emma and The Hobbit"
console.log(new Intl.ListFormat("tr", { type: "disjunction" }).format(["Dune", "Emma"])); // "Dune veya Emma"
console.log(new Intl.ListFormat("en", { type: "disjunction" }).format(["Dune", "Emma"])); // "Dune or Emma"

Amerikan İngilizcesi son "and"den önce virgül koyar, İngiliz İngilizcesi koymaz; bunu da dil verisi biliyor. type: "unit" ise "2 hr 15 min" gibi birim listeleri için var.

Intl.DisplayNames, dil, ülke ve para birimi kodlarını okunur isimlere çevirir. Dil seçicide her dilin adını kendi dilinde göstermek, teslimat formundaki ülke listesi ve fiyatın yanındaki para birimi adı için kullanırsın. Intl.Locale da bir dil etiketini parçalarına ayırır:

const languageCodes = ["tr", "en"];
console.log(languageCodes.map((code) => new Intl.DisplayNames([code], { type: "language" }).of(code)));
// ["Türkçe", "English"]

const trRegions = new Intl.DisplayNames(["tr"], { type: "region" });
console.log(["TR", "DE", "US"].map((code) => trRegions.of(code)));
// ["Türkiye", "Almanya", "Amerika Birleşik Devletleri"]

console.log(new Intl.DisplayNames(["en"], { type: "currency" }).of("TRY")); // "Turkish Lira"
console.log(new Intl.DisplayNames(["tr"], { type: "currency" }).of("TRY")); // "Türk lirası"
console.log(new Intl.DisplayNames(["en"], { type: "region" }).of("XX"));    // "XX"
console.log(new Intl.DisplayNames(["en"], { type: "region", fallback: "none" }).of("XX")); // undefined

const trLocale = new Intl.Locale("tr-TR");
console.log(trLocale.language, trLocale.region, trLocale.baseName); // tr TR tr-TR

Bilinmeyen bir kod geldiğinde varsayılan davranış kodun kendisini döndürmek. fallback: "none" ile undefined alırsın ve "bu kodu tanımıyorum" durumunu kendin ele alırsın. Ülke ve dil adlarını elle bir JSON dosyasında tutmak yerine bu API'yi kullanmak, sayfa boyutunu da küçültür.

Intl.Segmenter: Kullanıcının Gördüğü Karakterler

Kitap yorumlarına 500 karakter sınırı koyuyoruz. Temel serideki string yazısında "😀".length'in 2 olduğunu ve for...of'un onu tek karakter saydığını görmüştük. for...of code point sayar; ten rengi, aile emojisi ve bayrak gibi birden çok code point'ten oluşan işaretlerde o da yanılır. Kullanıcının tek karakter olarak gördüğü birime grapheme denir. Intl.Segmenter metni grapheme, kelime ya da cümle sınırlarından böler:

const graphemes = new Intl.Segmenter("en", { granularity: "grapheme" });

function visibleLength(text) {
  let count = 0;
  for (const _ of graphemes.segment(text)) count++;
  return count;
}

const review = "Great book 👍🏽";
console.log(review.length, [...review].length, visibleLength(review)); // 15 13 12

const family = "👨‍👩‍👧🇹🇷";
console.log(family.length, [...family].length, visibleLength(family)); // 12 7 2

Aile emojisi beş code point'ten (üç kişi, aralarında iki birleştirici karakter), bayrak iki code point'ten oluşur; ekranda iki işaret görünür. Sınırı length ile koyarsan emoji kullanan müşteri 500 karakter yazamadan "çok uzun" uyarısı alır. Metni kısaltırken de aynı sorun var: slice bir emojinin ortasından keserse ekranda bozuk bir işaret kalır. Kısaltmayı grapheme'lerle yap:

function truncate(text, max) {
  const parts = Array.from(graphemes.segment(text), (s) => s.segment);
  return parts.length <= max ? text : parts.slice(0, max).join("") + "…";
}

const shortReview = "Loved it 👨‍👩‍👧 so much";
console.log(JSON.stringify(shortReview.slice(0, 10))); // "Loved it \ud83d"
console.log(truncate(shortReview, 10));                 // "Loved it 👨‍👩‍👧…"

Kelime sayısı için granularity: "word" kullanırsın. Her parçada isWordLike property'si var; boşluk ve noktalama parçalarında false döner:

const trWords = new Intl.Segmenter("tr", { granularity: "word" });
const wordCount = (text) => [...trWords.segment(text)].filter((s) => s.isWordLike).length;

console.log(wordCount("Dune'u iki günde bitirdim, harika!")); // 5

"Dune'u" tek kelime sayıldı; split(" ") ise "bitirdim," ve "harika!" parçalarını noktalamayla birlikte verirdi. Intl.Segmenter, web-features explorer'a göre Firefox 125 ile Nisan 2024'te Baseline oldu ve Ekim 2026'dan beri widely available (bütün güncel tarayıcılarda 30 aydır destekleniyor).

Intl.DurationFormat: Okuma Süresi

Kitap sayfasında tahmini okuma süresini gösteriyoruz. Dakikayı saat ve dakikaya bölmek kolay; "2 sa. 15 dk." ve "2 hr, 15 min" gibi dile uygun metni kurmak ise Intl.DurationFormat'ın işi:

const shortDuration = {
  tr: new Intl.DurationFormat("tr", { style: "short" }),
  en: new Intl.DurationFormat("en", { style: "short" })
};

function readingTime(lang, totalMinutes) {
  const duration = { hours: Math.floor(totalMinutes / 60), minutes: totalMinutes % 60 };
  return shortDuration[lang].format(duration);
}

console.log(readingTime("tr", 135)); // "2 sa. 15 dk."
console.log(readingTime("en", 135)); // "2 hr, 15 min"
console.log(readingTime("en", 60));  // "1 hr"
console.log(new Intl.DurationFormat("en").format({ minutes: 135 })); // "135 min"
console.log(new Intl.DurationFormat("tr", { style: "long" }).format({ hours: 12, minutes: 40 })); // "12 saat 40 dakika"
console.log(new Intl.DurationFormat("en", { style: "digital" }).format({ hours: 2, minutes: 15 })); // "2:15:00"

Üç ayrıntı var. Birincisi, DurationFormat birimleri birbirine çevirmez: 135 dakikayı "135 min" diye yazar, saate bölmek senin işin. İkincisi, değeri sıfır olan birimler varsayılan olarak yazılmaz ("1 hr"). Üçüncüsü, format düz bir object kabul eder; bir önceki yazıda ön bakışını yaptığımız Temporal'ın Duration object'ini de kabul eder. Değerler tam sayı olmalı; { minutes: 2.5 } bir RangeError fırlatır.

style için "long", "short" (varsayılan), "narrow" ve "digital" var. Burada iki tarayıcı farkı gördüm. Türkçe "narrow" stilinde Chromium 158 ve Node.js "2s 15d", WebKit ise "2sa 15d" yazdı. "short" stilinde metin aynı görünse de WebKit sayı ile birim arasına normal boşluk yerine U+202F (dar ve satır sonunda bölünmeyen boşluk) koydu. Web-features explorer'a göre Intl.DurationFormat Mart 2025'te Firefox 136 ile Baseline oldu (Chrome 129, Safari 16.4); widely available olması Eylül 2027'de bekleniyor. Daha eski tarayıcıları destekliyorsan typeof Intl.DurationFormat === "function" kontrolüyle basit bir yedek metin hazırla.

Üretimde Dikkat

Bir Intl instance'ı oluşturmak, onu kullanmaktan çok daha pahalı: engine dil etiketini çözer, CLDR verisini yükler, seçenekleri hazırlar. 40.000 kitap başlığını üç yolla sıraladım:

const sampleWords = ["Dune", "Emma", "Middlemarch", "Hobbit", "Frankenstein", "Pride", "Prejudice", "Persuasion", "Ulysses", "Walden"];
const manyTitles = Array.from({ length: 40000 }, (_, i) => `${sampleWords[i % 10]} ${sampleWords[(i * 7) % 10]} ${i}`);

console.time("localeCompare");
[...manyTitles].sort((a, b) => a.localeCompare(b, "tr"));
console.timeEnd("localeCompare");

console.time("one Collator");
[...manyTitles].sort(trCollator.compare);
console.timeEnd("one Collator");

console.time("new Collator per comparison");
[...manyTitles].sort((a, b) => new Intl.Collator("tr").compare(a, b));
console.timeEnd("new Collator per comparison");

Benim koşularımda Node.js 24'te tek Collator 12–23 ms, localeCompare(b, "tr") 27–34 ms, her karşılaştırmada yeni Collator 450–490 ms sürdü. Chromium 158'de sırasıyla 11–19, 27–33 ve 347–370 ms; WebKit'te 10–12, 10–13 ve 221–224 ms ölçtüm. Yani localeCompare ile tek Collator arasındaki fark V8'de iki kattan az, WebKit'te yok denecek kadar küçük; ama her karşılaştırmada yeni instance oluşturmak her engine'de en az 20 kat yavaş. MDN'nin localeCompare sayfası da büyük array'leri sıralarken bir Intl.Collator oluşturup onun compare method'unu kullanmayı öneriyor.

Bir component her render'da new Intl.NumberFormat(...) yazıyorsa aynı bedeli her render'da ödersin. Çözüm, instance'ları dil ve seçeneklere göre bir kez oluşturup saklamak:

const intlCache = new Map();

function getIntl(Ctor, locale, options = {}) {
  const key = `${Ctor.name}|${locale}|${JSON.stringify(options)}`;
  let instance = intlCache.get(key);
  if (!instance) {
    instance = new Ctor(locale, options);
    intlCache.set(key, instance);
  }
  return instance;
}

console.log(getIntl(Intl.Collator, "tr") === getIntl(Intl.Collator, "tr")); // true
console.log(getIntl(Intl.ListFormat, "en").format(["Dune", "Emma"]));     // "Dune and Emma"

İkinci konu dil verisinin sürümü. Çıktılar CLDR güncellendikçe değişebilir; bir tarayıcıda "sa." yazan kısaltma bir sonraki sürümde değişebilir, Node.js ile tarayıcı farklı ICU sürümleri taşıyabilir. Bu yüzden testlerde biçimlendirilmiş metni sabit bir string'le karşılaştırma; ya aynı Intl çağrısının sonucuyla karşılaştır ya da yalnız sayıyı ve sırayı doğrula. Sunucuda HTML üretiyorsan dili açıkça ver ("tr"), varsayılan dile güvenme: sunucunun dili ile müşterininki aynı değildir.

Üçüncüsü dil seçimi. Kullanıcının tercihini navigator.languages verir; ama iki dilli bir sitede dil zaten URL'de ya da ayarlarda seçiliyse Intl'e o dili ver. Tarayıcının dili ile sayfanın dili farklıysa sayfadaki metinler bir dilde, tarihler başka bir dilde görünür.

Sık Düşülen Tuzaklar

Türkçe aramada toLowerCase() kullanmak. "İSTANBUL" araması "Üç İstanbul"u bulamaz, çünkü dilden bağımsız kural İ'yi "i" ve ayrı bir nokta işaretine çevirir. İçeriğin dili belliyse toLocaleLowerCase("tr") kullan.

Karakter sınırını string.length ile koymak. length UTF-16 birimi sayar; emoji'li bir yorum sınırın çok altında "çok uzun" görünür, slice ile kısaltılan metin bozuk bir işaretle biter. Kullanıcının gördüğü karakter için Intl.Segmenter kullan. Sunucu tarafındaki sınır da aynı kuralla sayılmalı; yoksa tarayıcının kabul ettiği yorumu API reddeder.

Her render'da ya da her karşılaştırmada yeni Intl instance'ı oluşturmak. Yukarıdaki ölçümde bu, sıralamayı 20 kattan fazla yavaşlattı. Instance'ı dışarıda bir kez oluştur ya da cache'le.

sensitivity: "base" ile Türkçede "ç = c" beklemek. Türkçe kurallarda ç, ğ, ı, ö, ş, ü ayrı harflerdir. Klavye farkını tolere eden bir arama istiyorsan bunu ayrı bir kural olarak yaz.

Sıralamada arayüzün dilini kullanmak. Türkçe başlıklı bir listeyi İngilizce arayüzde "en" kurallarıyla sıralarsan Ö'lü yazarlar O'luların arasına karışır. Sıralama dili içeriğin dilidir.

Küçük Bir Deneme

★☆☆ authors listesine "çağan", "Çağla" ve "cem" ekle ve new Intl.Collator("tr", { caseFirst: "upper" }) ile sırala. Aynı harfle başlayan büyük ve küçük harfli adlar nasıl diziliyor? caseFirst vermeden sonuç ne?

★★☆ cartLabel'ı genişlet: sepetteki başlıkları da Intl.ListFormat ile eklesin ve "3 books in your cart: Dune, Emma, and The Hobbit" ile "Sepetinizde 3 kitap var: Dune, Emma ve The Hobbit" metinlerini üretsin. Bütün Intl instance'larını getIntl ile al.

★★★ Bir yorum alanı yap: input event'inde visibleLength ile "12/500" sayacını güncellesin, 500'ü geçince gönder butonunu kapatsın. Metne aile emojisi ve bayrak yapıştırıp sayacın length ile değil grapheme ile saydığını doğrula. Sayacın metnini de seçili dile göre (tr/en) Intl.NumberFormat ile yaz.

Böylece Orta seriyi bitirdik. Modern syntax'tan closure'lara, promise'lerden Fetch'e, module'lerden tarihlere ve iki dilli arayüzlere kadar dilin günlük işte kullandığın her köşesini gördün. İleri seride işin iç yüzüne bakıyoruz: prototype zincirinin gerçekte nasıl işlediği, event loop'un microtask ve render adımlarıyla anatomisi, bellek yönetimi, performans ölçümü, Web Worker'lar, Web Components, Temporal ve son olarak element.animate ile animasyon ve kaydırma API'leri.