/** * Türkçe-güvenli metin normalizasyonu, arama ve sıralama yardımcıları. * * JavaScript'in locale-bağımsız `toLowerCase()`'i Türkçe `İ/I/ı/i` * karakterlerini bozar: `"İ".toLowerCase()` → `"i̇"` (U+0069 U+0307 * combining dot above). Bu, `toLowerCase().includes()` tabanlı aramada * Türkçe girdileri eşleşmez kılar. * * Saf fonksiyonlar — yan etki ve bağımlılık yok. * * @module shared/utils/turkishText */ /** NFD ile katlanmayan Türkçe harfler için açık eşleme. */ const TR_FOLD: Readonly> = { ı: "i", ş: "s", ğ: "g", ü: "u", ö: "o", ç: "c", }; /** * Aksan-duyarsız, Türkçe-güvenli arama anahtarı üretir. * `"İstanbul"` ve `"istanbul"` → `"istanbul"`; `"Şarj"` → `"sarj"`. * Baştaki ve sondaki boşluklar kırpılır. */ export function normalizeForSearch(input: string | null | undefined): string { if (!input) return ""; let s = input.toLocaleLowerCase("tr"); // İ→i, I→ı (Türkçe-güvenli) s = s.replace(/[ışğüöç]/g, (ch) => TR_FOLD[ch] ?? ch); // açık Türkçe fold s = s.normalize("NFD").replace(/[̀-ͯ]/g, ""); // kalan aksanları sil return s.trim(); } /** * `text`, `query`'yi (aksan-duyarsız, Türkçe-güvenli) içeriyor mu? * Boş sorgu her zaman `true` döner. */ export function matchesSearch( text: string | null | undefined, query: string | null | undefined ): boolean { const q = normalizeForSearch(query); if (!q) return true; return normalizeForSearch(text).includes(q); } const trCollator = new Intl.Collator("tr", { sensitivity: "base", numeric: true, }); /** * Kullanıcı-görünür listeler için Türkçe alfabe + sayısal-duyarlı * karşılaştırma. `Array.prototype.sort` ile doğrudan kullanılabilir. * * `sensitivity: "base"` kullanıldığından aksan/büyük-küçük harf varyantları * sıralama açısından eşit sayılır — örneğin `"Şehir"` ile `"şehir"` berabere * gelir. Bu karşılaştırıcı görsel liste sıralaması içindir, kesin * aksan-farklılaştırmalı sıralama için değil. */ export function compareTr(a: string | null | undefined, b: string | null | undefined): number { return trCollator.compare(a ?? "", b ?? ""); }