Azimjon Abdurasulov

QA 25: Accessibility, Localization va Visual testing — WCAG 2.2, axe-core va o'zbek tili nozikliklari

🧪 QA Engineer — Zero to Hero

QA 25: Accessibility, Localization va Visual testing — WCAG 2.2, axe-core va o'zbek tili nozikliklari

Holat: 2026-yil oktabr. Dars WCAG 2.2 (W3C Recommendation, 2023-yil 5-oktabr; joriy tahrir 2024-yil 12-dekabr), @axe-core/playwright 4.13.0 + Playwright 1.64 va Node.js 24 (ICU 78.2, CLDR 48) asosida yozilgan. Barcha axe, Intl va screenshot natijalari haqiqiy ishga tushirishdan olingan.

Bu darsdan keyin siz: mahsulotni "hamma uchun, har tilda va har relizda bir xil ko'rinishda" ishlashini tekshira olasiz:

  • WCAG 2.2 ning POUR printsiplari va AA darajasini amalda (klaviatura, kontrast, label, screen reader) tekshirasiz;
  • axe-core'ni Playwright testlariga qo'shib, natijani o'qiysiz va avtomatlashtirish chegarasini bilasiz;
  • o'zbek tili (lotin/kirill, oʻ/gʻ, apostroflar), rus plural shakllari, sana/son/valyuta formatlarini sinaysiz;
  • toHaveScreenshot bilan visual regression testlar yozasiz;
  • Nielsen evristikalari bilan tezkor usability tahlil qilasiz.

Mundarija

  1. Nega accessibility muhim
  2. WCAG 2.2: POUR, darajalar va yangi mezonlar
  3. Qo'lda a11y tekshiruvi: klaviatura, kontrast, screen reader
  4. Avtomatik a11y: axe-core + Playwright
  5. Mobil accessibility
  6. i18n va l10n: asosiy tushunchalar
  7. O'zbek tili nozikliklari: oʻ/gʻ, lotin/kirill, alifbo islohoti
  8. Sana, son, valyuta va plural: Intl bilan tekshirish
  9. Visual testing: toHaveScreenshot va vositalar
  10. Usability asoslari: Nielsen'ning 10 evristikasi
  11. Amaliy mashqlar
  12. O'zingizni tekshiring
  13. Xulosa
  14. Manbalar

1. Nega accessibility muhim {#nega-a11y}

Accessibility (a11y) — mahsulotdan imkoniyati cheklangan odamlar ham to'liq foydalana olishi: ko'zi ojiz yoki zaif ko'radiganlar (screen reader, kattalashtirish), rang ajratishda qiynaladiganlar, qo'l harakati cheklanganlar (faqat klaviatura yoki switch qurilma), eshitishi zaiflar (subtitr), kognitiv qiyinchiligi borlar.

Bundan tashqari vaziyatli cheklovlar ham bor: quyosh ostida ekran yomon ko'rinadi, bir qo'lda bola ko'tarib telefon ishlatiladi, shovqinli metroda video ovozsiz ko'riladi. A11y uchun qilingan har bir yaxshilanish hammaga foyda beradi.

Qonuniy kontekst. Yevropa Ittifoqining European Accessibility Act (Direktiva 2019/882) 2025-yil 28-iyundan keyin bozorga chiqarilgan mahsulotlar va iste'molchilarga ko'rsatiladigan xizmatlarga qo'llanadi — ro'yxatda e-commerce, bank xizmatlari, elektron kitoblar, smartfon va kompyuterlar bor. DemoBozor Yevropa mijozlariga sotsa yoki ilova xalqaro bozorga chiqsa, bu to'g'ridan-to'g'ri talabga aylanadi.

QA'ning roli — a11y'ni reliz oxirida "bir marta audit" qilish emas, har feature'ning Definition of Done'iga qo'shish: klaviatura bilan o'tib chiqish, avtomatik skaner, kerak bo'lsa screen reader bilan tekshiruv.

🎯 Intervyuda: Accessibility testlashni qanday tashkil qilasiz? — Uch qatlam: (1) har PR'da avtomatik skaner (axe) — tez topiladigan xatolar uchun; (2) har feature'da qo'lda tekshiruv — klaviatura, fokus, kontrast, label'lar, 200% zoom; (3) muhim ssenariylarni screen reader (VoiceOver, NVDA, TalkBack) bilan tekshirish. Mezon — WCAG 2.2 AA.


2. WCAG 2.2: POUR, darajalar va yangi mezonlar {#wcag}

WCAG (Web Content Accessibility Guidelines) — W3C'ning WAI guruhi chiqargan xalqaro standart. WCAG 2.2 2023-yil 5-oktabrda W3C Recommendation bo'ldi (joriy tahrir — 2024-yil 12-dekabr). Muhim jihati: WCAG 2.2 ga mos kontent WCAG 2.1 va 2.0 ga ham mos keladi.

WCAG 2.2 ning to'rt printsipi: Perceivable, Operable, Understandable, Robust va muvofiqlik darajalari

Tuzilma: printsip → guideline → success criterion

  • 4 printsip (POUR): Perceivable, Operable, Understandable, Robust.
  • Har printsip ostida guideline'lar, ular ostida tekshiriladigan success criterion (SC)'lar bor — masalan, 1.4.3 Contrast (Minimum).
  • Har SC'ning darajasi: A, AA yoki AAA. Amalda maqsad odatda AA (A + AA mezonlari). W3C'ning o'zi butun sayt uchun AAA'ni umumiy talab qilib qo'yishni tavsiya etmaydi — ba'zi kontent uchun barcha AAA mezonlarini bajarib bo'lmaydi.

QA eng ko'p tekshiradigan mezonlar

SCNomiDarajaQisqacha
1.1.1Non-text ContentARasm/ikonkada mazmunli muqobil matn
1.3.1Info and RelationshipsASarlavhalar, ro'yxatlar, jadvallar, label'lar kodda ham to'g'ri
1.4.3Contrast (Minimum)AAMatn ≥ 4.5:1; katta matn (≥ 18pt yoki ≥ 14pt bold) ≥ 3:1
1.4.10ReflowAA320 CSS px kenglikda ikki yo'nalishli scroll'siz ishlaydi
1.4.11Non-text ContrastAAUI komponentlar va muhim grafika ≥ 3:1
2.1.1KeyboardAHamma funksiya klaviaturadan
2.1.2No Keyboard TrapAFokus biror joyda "qamalib" qolmaydi
2.4.3Focus OrderAFokus tartibi mantiqiy
2.4.7Focus VisibleAAFokus ko'rinib turadi
3.1.1Language of PageA<html lang="uz">
3.3.1Error IdentificationAXato aniqlanib, matn bilan tushuntiriladi
3.3.2Labels or InstructionsAMaydonlarda label yoki ko'rsatma
4.1.2Name, Role, ValueAHar boshqaruv elementining nomi, roli, holati bor

WCAG 2.2 da qo'shilgan 9 ta mezon

SCNomiDarajaQA nimani tekshiradi
2.4.11Focus Not Obscured (Minimum)AAFokusdagi element sticky header/banner ostida to'liq yashirinib qolmaydi
2.4.12Focus Not Obscured (Enhanced)AAAFokusdagi element umuman yopilmaydi
2.4.13Focus AppearanceAAAFokus indikatori yetarlicha katta va kontrastli
2.5.7Dragging MovementsAASudrash (drag) bilan qilinadigan amalning bir bosishli muqobili bor
2.5.8Target Size (Minimum)AABosiladigan nishon kamida 24×24 CSS px (istisnolar bor)
3.2.6Consistent HelpAYordam havolasi har sahifada bir xil joyda
3.3.7Redundant EntryABir jarayonda kiritilgan ma'lumot qayta so'ralmaydi
3.3.8Accessible Authentication (Minimum)AALogin uchun "eslab qolish yoki hisoblash" testi majburiy emas (parol menejeri, nusxa ko'chirish ishlaydi)
3.3.9Accessible Authentication (Enhanced)AAAYuqoridagining qat'iyroq varianti

4.1.1 Parsing esa eskirgan deb WCAG 2.2 dan olib tashlangan.

🇺🇿 Mahalliy kontekst: DemoBozor'da SMS kod maydoni: 3.3.8 nuqtai nazaridan foydalanuvchi kodni nusxalab qo'ya olishi va telefon SMS kodini avtomatik taklif qilishi (autofill) ishlashi kerak. 6 ta alohida katakchali OTP maydonlari ko'pincha aynan shu joyda buziladi.

WCAG 3.0 haqida

WCAG 3.0 hozircha Working Draft (oxirgi qoralama — 2026-yil 10-sentabr). Hujjatning o'zida u WCAG 2 ni almashtirmasligi va ishlar hali bir necha yil davom etishi aytilgan. Amaliy testlash uchun mezon — WCAG 2.2 AA.

ARIA'ning birinchi qoidasi

W3C'ning "Using ARIA" hujjati: kerakli semantika va xatti-harakat allaqachon mavjud bo'lgan native HTML element yoki atribut bo'lsa — ARIA qo'shish o'rniga o'sha native elementni ishlating. Ya'ni <div role="button" tabindex="0"> emas, <button>. QA uchun signal: kodda role="button" ko'p bo'lsa, klaviatura (Enter/Space), fokus va screen reader'ni ayniqsa sinchiklab tekshiring.


3. Qo'lda a11y tekshiruvi: klaviatura, kontrast, screen reader {#manual-a11y}

5 daqiqalik klaviatura testi

Sichqonchani chetga qo'ying va DemoBozor checkout sahifasini faqat klaviatura bilan bajaring:

QadamTekshiruvKutilgan natija
Tab / Shift+TabHamma interaktiv elementga yetib borasizmi?Ha, mantiqiy tartibda (2.4.3)
FokusHozir qayerda turganingiz ko'rinadimi?Aniq ko'rinadigan fokus halqasi (2.4.7)
Sticky headerFokusdagi element header ostida qolib ketmaydimi?Ko'rinadi (2.4.11)
Enter / SpaceTugma va havolalar ishlaydimi?Ha
Modal oynaFokus modal ichida qoladimi, Esc yopadimi, yopilgach fokus qaytadimi?Ha
ChiqishBiror joyda fokus "qamalib" qolmaydimi?Yo'q (2.1.2)
"Kontentga o'tish" havolasiSahifa boshida bormi?Uzun menyuli sahifalarda tavsiya etiladi

Kontrast

  • Normal matn: kamida 4.5:1; katta matn (≥ 18pt yoki ≥ 14pt bold): 3:1; UI komponent chegaralari va ikonkalar: 3:1.
  • Tekshirish: WebAIM Contrast Checker yoki Chrome DevTools'dagi rang tanlagich (u kontrast nisbatini ko'rsatadi).
  • Faqat rang bilan ma'no berilmasin (1.4.1): "Qizil maydonlar — xato" emas, xato matni ham bo'lsin.

Zoom va reflow

  • Brauzerni 200% ga kattalashtiring: matn kesilmaydi, tugmalar ustma-ust tushmaydi.
  • Oynani 320 CSS px kenglikka toraytiring (taxminan 400% zoom): faqat vertikal scroll bo'lishi kerak (1.4.10).

Formalar

  • Har maydonning ko'rinadigan label'i bor. W3C WAI forms qo'llanmasi: placeholder — foydali ko'rsatma, lekin label o'rnini bosmaydi; yozishni boshlaganingizda u yo'qoladi.
  • Xato maydon bilan bog'langan va matnli: "Telefon raqam +998 dan keyin 9 ta raqamdan iborat bo'lishi kerak".
  • Majburiy maydonlar faqat rang yoki * bilan emas, matn yoki atribut bilan ham belgilangan.

Screen reader bilan tekshiruv

PlatformaScreen readerYoqish
macOSVoiceOverCmd + F5
iOS / iPadOSVoiceOverSettings → Accessibility → VoiceOver
WindowsNVDA (bepul)O'rnatib, ishga tushirish
AndroidTalkBackSettings → Accessibility → TalkBack

Nimalarni eshitishingiz kerak: sahifa sarlavhasi; sarlavhalar bo'yicha navigatsiya; har maydonning nomi ("Telefon raqam, matn maydoni"); tugma nomlari ("Savatchaga qo'shish, tugma" — "tugma, tugma" emas); rasmlarning mazmuni; xato va "Savatchaga qo'shildi" kabi status xabarlari (4.1.3).


4. Avtomatik a11y: axe-core + Playwright {#axe}

axe-core (Deque) — ochiq kodli a11y qoidalar dvigateli. Chrome Lighthouse'ning accessibility bahosi ham axe'ning foydalanuvchiga ta'sir baholariga asoslangan og'irliklardan foydalanadi. Playwright bilan integratsiya — @axe-core/playwright.

npm i -D @playwright/test @axe-core/playwright
npx playwright install chromium
// playwright.config.ts
import { defineConfig, devices } from "@playwright/test";

export default defineConfig({
  testDir: "./tests",
  reporter: "list",
  use: {
    baseURL: "https://www.saucedemo.com",
    testIdAttribute: "data-test",
  },
  projects: [{ name: "chromium", use: { ...devices["Desktop Chrome"] } }],
});
// tests/a11y.spec.ts
import { test, expect } from "@playwright/test";
import AxeBuilder from "@axe-core/playwright";

const WCAG_TAGS = ["wcag2a", "wcag2aa", "wcag21a", "wcag21aa", "wcag22aa"];

test("login sahifasida WCAG A/AA buzilishlari yo'q", async ({
  page,
}, testInfo) => {
  await page.goto("/");

  const results = await new AxeBuilder({ page }).withTags(WCAG_TAGS).analyze();

  // to'liq natija HTML hisobotga ilova bo'ladi
  await testInfo.attach("axe-violations", {
    body: JSON.stringify(results.violations, null, 2),
    contentType: "application/json",
  });
  expect(results.violations).toEqual([]);
});

test("DemoBozor mini sahifa: axe xatolarni topadi", async ({ page }) => {
  await page.setContent(`
    <html lang="uz"><body>
      <h1>DemoBozor</h1>
      <img src="choynak.png">
      <span>Telefon raqam</span> <input type="tel" id="phone">
      <input type="text" placeholder="Promo-kod">
      <button><svg width="16" height="16"></svg></button>
      <p style="color:#aaaaaa;background:#ffffff">Yetkazib berish bepul</p>
    </body></html>`);

  const results = await new AxeBuilder({ page }).withTags(WCAG_TAGS).analyze();
  const ids = results.violations.map((v) => v.id).sort();

  expect(ids).toEqual([
    "button-name",
    "color-contrast",
    "document-title",
    "image-alt",
    "label",
  ]);
});

test("faqat login formasi, bitta qoida o'chirilgan holda", async ({ page }) => {
  await page.goto("/");
  const results = await new AxeBuilder({ page })
    .include("#login_button_container")
    .disableRules(["color-contrast"])
    .analyze();

  expect(results.violations).toEqual([]);
});

Uchala test ham o'tadi (2026-yil oktabr). Ikkinchi testdan muhim saboqlar:

Elementaxe qoidasiMuammo
<img src="choynak.png">image-altalt yo'q
<input type="tel"> (yonida oddiy <span>)labelMatn ko'rinadi, lekin maydonga bog'lanmagan
<button><svg></button>button-nameTugma nomsiz — screen reader faqat "tugma" deydi
#aaaaaa matn oq fondacolor-contrast2.32:1 < 4.5:1
<title> yo'qdocument-titleSahifa sarlavhasi yo'q

⚠️ Diqqat: Faqat placeholder'i bor "Promo-kod" maydoni uchun axe xato bermadi: placeholder accessible name hisoblashda zaxira manba bo'lishi mumkin. Saucedemo login'i ham axe'dan 0 xato bilan o'tadi — uning maydonlarida aria-label va placeholder bor, lekin ko'rinadigan label yo'q. Avtomatik skaner "o'tdi" degani — hali "foydalanuvchi uchun qulay" degani emas; buni qo'lda tekshirish (3-bo'lim) topadi.

Haqiqiy topilmalar: TodoMVC

test("TodoMVC: jiddiy buzilishlar", async ({ page }) => {
  await page.goto("https://demo.playwright.dev/todomvc/");
  await page
    .getByPlaceholder("What needs to be done?")
    .fill("Choynak sotib olish");
  await page.getByPlaceholder("What needs to be done?").press("Enter");

  const { violations } = await new AxeBuilder({ page })
    .withTags(WCAG_TAGS)
    .analyze();
  const serious = violations.filter(
    (v) => v.impact === "serious" || v.impact === "critical",
  );

  for (const v of serious) {
    for (const node of v.nodes) {
      console.log(
        `${v.impact} | ${v.id} | ${node.target.join(" ")} | ${node.any[0]?.message}`,
      );
    }
  }
  expect(serious, "jiddiy a11y buzilishlari bo'lmasligi kerak").toEqual([]);
});

2026-yil oktabrdagi ishga tushirishda bu test yiqildi va konsolga quyidagilar chiqdi (qisqartirilgan; sayt o'zgarsa, natija ham o'zgaradi):

serious | color-contrast | h1 | ... contrast of 1.26 (foreground color: #ebd7d7, background color: #f5f5f5, font size: 75.0pt (100px) ...). Expected contrast ratio of 3:1
serious | color-contrast | .selected | ... contrast of 4.47 (foreground color: #777777, background color: #ffffff, font size: 10.5pt (14px) ...). Expected contrast ratio of 4.5:1
serious | color-contrast | p:nth-child(1) | ... contrast of 1.68 (foreground color: #bfbfbf, background color: #f5f5f5, font size: 7.5pt (10px) ...). Expected contrast ratio of 4.5:1

E'tibor bering: .selected filtrining kontrasti 4.47 — chegaraga juda yaqin, lekin baribir fail. Katta (100px) sarlavha uchun talab 3:1, kichik matn uchun 4.5:1 — axe shriftga qarab to'g'ri chegarani o'zi tanlaydi.

axe natijasini o'qish

  • violations — buzilishlar: id (qoida), impact (minor / moderate / serious / critical), help, helpUrl, nodes (har biri target selector va failureSummary bilan).
  • passes — o'tgan tekshiruvlar; incomplete — axe aniq hal qila olmagan, qo'lda ko'rish kerak bo'lganlar; inapplicable — sahifaga taalluqli bo'lmagan qoidalar.

Avtomatlashtirish chegarasi

Ko'p mezonlar inson baholashini talab qiladi: alt matni mazmunlimi, fokus tartibi mantiqiymi, xato xabari tushunarlimi. Deque'ning 2021-yildagi tadqiqoti (vendor tadqiqoti, mustaqil emas) avtomatik testlar topilgan muammolar hajmining taxminan 57% ini aniqlaganini ko'rsatgan — qolgan qismi baribir qo'lda topiladi. Lighthouse'da 100 ball ham "to'liq accessible" degani emas.

💡 Maslahat: CI'da axe'ni muhim sahifalarda ishlating va serious/critical buzilishlarda pipeline'ni yiqiting. Eski (ma'lum) muammolar ko'p bo'lsa — ularni alohida ticket'larga ajratib, yangi buzilish qo'shilishiga yo'l qo'ymaslik siyosatini qo'llang.


5. Mobil accessibility {#mobil-a11y}

TekshiruviOSAndroid
Screen readerVoiceOver: har element nomi, roli, holati o'qiladimiTalkBack: xuddi shunday
Shrift kattaligiDynamic Type'ning eng katta (accessibility) o'lchamlariFont size / Display size maksimal
Bosish nishoniApple HIG: tugma bosish maydoni kamida 44×44 pt (visionOS'da 60×60 pt)Google: kamida 48×48 dp, oralig'i ≥ 8 dp
HarakatReduce Motion yoqilganda animatsiyalar kamayadiAnimatsiya sozlamalari
KontrastIncrease Contrast, Bold TextHigh contrast text
Avtomatik auditXcode Accessibility InspectorAccessibility Scanner ilovasi

DemoBozor uchun tipik mobil a11y bug'lari:

  • savatcha ikonkasidagi badge VoiceOver'da "3" deb o'qiladi — "Savatcha, 3 ta mahsulot" bo'lishi kerak;
  • Dynamic Type maksimal o'lchamda "Buyurtma berish" tugmasi ekrandan chiqib ketadi;
  • mahsulot rasmi karuseli faqat swipe bilan ishlaydi — VoiceOver foydalanuvchisi uchun muqobil yo'q;
  • OTP katakchalari har biri alohida o'qiladi va SMS kod autofill ishlamaydi.

🧠 Esda tuting: accessibilityIdentifier (iOS) / testTag (Compose) — avtomatik testlar uchun, foydalanuvchiga o'qilmaydi. VoiceOver o'qiydigan matn — accessibilityLabel / contentDescription. Ikkalasi ham kerak, lekin vazifasi har xil (QA 22). Mobil testlash checklisti: QA 14.


6. i18n va l10n: asosiy tushunchalar {#i18n}

  • Internationalization (i18n) — mahsulotni turli tillarga moslashtirish mumkin qilib qurish: matnlar koddan tashqarida (resurs fayllar), Unicode, locale'ga qarab formatlash, egiluvchan layout.
  • Localization (l10n) — aniq bir locale uchun moslashtirish: tarjima, sana/son/valyuta formatlari, madaniy jihatlar, huquqiy matnlar.

DemoBozor 4 locale bilan ishlaydi: uz-Latn, uz-Cyrl, ru, en.

Tipik l10n bug'lari

BugMisolSabab
Tarjima qilinmagan matnRus tilida "Out of stock"Hardcoded string yoki backend xatosi
Gap bo'laklardan yig'ilgan"Savatchada " + n + " ta mahsulot"Tillarda so'z tartibi va qo'shimchalar boshqacha
Noto'g'ri plural"5 товара" (to'g'risi "5 товаров")Plural qoidalari hisobga olinmagan
Kesilgan matn"Buyurtma be..."Tarjima uzunroq, tugma kengligi qat'iy
Rasm ichidagi matnBanner faqat o'zbekchaMatn rasmga "yopishtirilgan"
Noaniq sana09/10/2026 — 9-oktabrmi yoki 10-sentabrmi?Format talabda belgilanmagan
Shriftda belgi yo'qʻ o'rnida bo'sh kvadratShriftda U+02BB glif yo'q
Backend xabari tarjimasizAPI inglizcha xato qaytaradiXato kodlari o'rniga matn

Matn kengayishi

W3C'ning "Text size in translation" maqolasida keltirilgan IBM yo'riqnomasiga ko'ra, ingliz tilidan Yevropa tillariga tarjimada qisqa matnlar eng ko'p uzayadi: 10 belgigacha bo'lgan matnlar 200–300% gacha, 70 belgidan uzunlari esa taxminan 130% gacha. Tugma, tab va menyu nomlari — eng xavfli joylar.

Pseudo-localization

Haqiqiy tarjimani kutmasdan, matnlarni sun'iy ravishda "chet tilga o'xshatish" usuli: harflarni diakritikali variantlarga almashtirish va uzaytirish, masalan Savatcha → [Šàvàtçhà ~~~~]. Natijada hardcoded matnlar (o'zgarmay qolganlari) va kesilish joylari darhol ko'rinadi.

RTL tillar

Arab yoki fors tilini qo'shish rejasi bo'lsa: dir="rtl", layout ko'zgu kabi aylanadi, CSS'da margin-left o'rniga mantiqiy margin-inline-start. Node 24'da tekshirish: new Intl.Locale('ar').getTextInfo() → { direction: 'rtl' }.


7. O'zbek tili nozikliklari: oʻ/gʻ, lotin/kirill, alifbo islohoti {#ozbek-tili}

Apostroflarning besh xil ko'rinishi

O'zbek lotin alifbosidagi Oʻ va Gʻ harflari uchun to'g'ri belgi — **ʻ (U+02BB, MODIFIER LETTER TURNED COMMA)**; tutuq belgisi uchun — ʼ (U+02BC). Amalda esa klaviaturada qulay bo'lgani uchun boshqa belgilar ishlatiladi:

YozilishiBelgiUnicode
o'zbekASCII apostrofU+0027
oʻzbekModifier letter turned commaU+02BB
o‘zbekLeft single quotation markU+2018
o’zbekRight single quotation markU+2019
ozbek`BacktickU+0060

Inson uchun beshalasi "bir xil so'z", kompyuter uchun esa — besh xil satr. Natijada qidiruv, takrorlarni topish, saralash va login (masalan, foydalanuvchi nomi) buziladi.

Qidiruvni tekshirish va tuzatish

// Qidiruv kaliti: barcha apostrof variantlarini bitta belgiga (U+02BB) keltiramiz
const APOSTROPHES = /['`‘’ʼ]/g;

export function searchKey(text) {
  return text
    .normalize("NFC")
    .replace(APOSTROPHES, "ʻ")
    .toLocaleLowerCase("uz");
}

const products = [
  "Oʻzbek atlasi",
  "O'zbek do'ppisi",
  "O‘zbekcha choynak",
  "Gʻijduvon kosasi",
];
const query = "o'zbek";

const naive = products.filter((p) => p.toLowerCase().includes(query));
const smart = products.filter((p) => searchKey(p).includes(searchKey(query)));

console.log("oddiy qidiruv:", naive);
console.log("normallashtirilgan:", smart);

Node 24 natijasi:

oddiy qidiruv: [ "O'zbek do'ppisi" ]
normallashtirilgan: [ 'Oʻzbek atlasi', "O'zbek do'ppisi", 'O‘zbekcha choynak' ]

Oddiy qidiruv 3 ta mos mahsulotdan faqat bittasini topdi. searchKey — faqat qidiruv indeksi uchun kalit: ekranda matn foydalanuvchi yozgandek qoladi.

QA test g'oyalari: har bir apostrof varianti bilan qidirish; nomida ʻ bo'lgan mahsulotni ' bilan qidirish va aksincha; ro'yxatdan o'tishda bir xil ism turli apostrof bilan "boshqa odam" bo'lib qolmaydimi; shriftlarda ʻ glifi bormi.

Saralash (collation)

O'zbek alifbosida Oʻ, Gʻ, Sh, Ch harflari Z dan keyin keladi. Oddiy sort() esa kod nuqtalari bo'yicha saralaydi:

const words = [
  "shakar",
  "sabzi",
  "olma",
  "oʻrik",
  "gʻisht",
  "gilos",
  "chinni",
  "tuz",
];
console.log("sort():          ", [...words].sort().join(", "));
console.log(
  "Collator('uz'):  ",
  [...words].sort(new Intl.Collator("uz").compare).join(", "),
);
sort():           chinni, gilos, gʻisht, olma, oʻrik, sabzi, shakar, tuz
Collator('uz'):   gilos, olma, sabzi, tuz, oʻrik, gʻisht, shakar, chinni

Shahar, toifa yoki brend ro'yxatlari alifbo tartibida chiqsa — locale'ga mos saralash talabda belgilanganmi, tekshiring.

Lotin va kirill

Ikkala yozuv ham faol ishlatiladi. Tekshiruvlar: ilova tanlangan yozuvda izchil ko'rsatiladimi (bir ekranda aralash emas); foydalanuvchi ism yoki manzilni kirillda kiritsa, saqlanadi va to'g'ri ko'rinadimi; qidiruv qaysi yozuvlarda ishlashi talabda yozilganmi.

🇺🇿 Mahalliy kontekst: Alifbo islohoti. O'zbek lotin alifbosini takomillashtirish haqidagi qonun loyihasini Senat 2026-yil 10-sentabrda ma'qulladi va Prezidentga yubordi. Xabarlarga ko'ra yangi alifboda 28 harf va bitta apostrof bo'ladi: Oʻ → Ö, Gʻ → Ğ, Sh → Ş, Ch → Ç. Rasmiy xabarda raqamli texnologiyalar bo'yicha yagona texnik standart ishlab chiqilayotgani va qidiruv mexanizmlari yangi harflarga moslashtirilayotgani aytilgan. Qonun kuchga kirsa, o'tish davrida ilovalar ikkala imloni ham to'g'ri qidirishi va saqlashi kerak bo'ladi (oʻrik va örik). Holatni rasmiy manbalardan kuzatib boring.


8. Sana, son, valyuta va plural: Intl bilan tekshirish {#intl}

JavaScript'ning Intl API'si CLDR ma'lumotlari asosida formatlaydi. Quyidagi natijalar Node.js 24 (ICU 78.2, CLDR 48) da olingan; brauzer va OS versiyasiga qarab biroz farq qilishi mumkin.

KodNatija
new Intl.NumberFormat('uz-UZ').format(1250000)1 250 000
... ('uz-UZ', { style: 'currency', currency: 'UZS' })1 250 000,00 soʻm
... + maximumFractionDigits: 01 250 000 soʻm
... ('uz-Cyrl-UZ', ...)1 250 000 сўм
... ('ru-RU', ...)1 250 000 UZS
... ('en-US', ...)UZS 1,250,000
new Intl.DateTimeFormat('uz-UZ', { timeZone: 'Asia/Tashkent' })09/10/2026
... ('uz-UZ', { dateStyle: 'long', timeStyle: 'short', ... })9-oktabr, 2026, 14:30
... ('ru-RU', ...)9 октября 2026 г. в 14:30
... ('en-US', ...)October 9, 2026 at 2:30 PM

(Sana: 2026-10-09T09:30:00Z — Toshkentda 14:30.)

Bu jadvaldan uchta muhim QA xulosasi:

  1. Format — mahsulot qarori. uz-UZ ning standart qisqa formati 09/10/2026, O'zbekistonda esa hujjatlarda ko'pincha 09.10.2026 yoziladi. Talabda qaysi format ekanini aniq yozdiring va hamma ekranda izchilligini tekshiring.
  2. **CLDR soʻm da U+02BB ishlatadi**, ko'p dizayn maketlarida esa so'm (U+0027) yozilgan. Matnni aynan taqqoslaydigan testlar shu yerda yiqiladi.
  3. Bo'shliqlar oddiy probel emas. Raqam guruhlari va valyuta oldidagi bo'shliq — NBSP (U+00A0):
const price = new Intl.NumberFormat("uz-UZ", {
  style: "currency",
  currency: "UZS",
  maximumFractionDigits: 0,
}).format(1250000);

console.log(price); // 1 250 000 soʻm
console.log(price === "1 250 000 soʻm"); // false — bo'shliqlar NBSP (U+00A0)
console.log(price.replace(/[  ]/g, " ") === "1 250 000 soʻm"); // true

Playwright'ning web-first assertion'i toHaveText satr bilan solishtirganda bo'shliqlarni normallashtiradi, shuning uchun await expect(locator).toHaveText('1 250 000 soʻm') o'tadi; lekin textContent() ni toBe bilan solishtirsangiz — yiqiladi. Bu "flaky emas, lekin tushunarsiz" testlarning klassik sababi.

Plural qoidalari

CLDR bo'yicha o'zbek tilida plural kategoriyalari ikkita: one, other. Rus tilida to'rtta: one, few, many, other.

const messages = {
  uz: { one: "{n} ta mahsulot", other: "{n} ta mahsulot" },
  ru: {
    one: "{n} товар",
    few: "{n} товара",
    many: "{n} товаров",
    other: "{n} товара",
  },
};

function cartLabel(locale, n) {
  const category = new Intl.PluralRules(locale).select(n); // 'one' | 'few' | 'many' | 'other'
  return messages[locale][category].replace("{n}", String(n));
}

for (const n of [1, 2, 5, 11, 21, 22, 25]) {
  console.log(`${n}: ${cartLabel("ru", n)} | ${cartLabel("uz", n)}`);
}
1: 1 товар | 1 ta mahsulot
2: 2 товара | 2 ta mahsulot
5: 5 товаров | 5 ta mahsulot
11: 11 товаров | 11 ta mahsulot
21: 21 товар | 21 ta mahsulot
22: 22 товара | 22 ta mahsulot
25: 25 товаров | 25 ta mahsulot

Rus tili uchun test qiymatlari: 0, 1, 2, 5, 11, 12, 21, 22, 25, 101, 111 — ayniqsa 11–14 (har doim many) va 21, 22 (yana one, few) chegaralari. Bu — QA 5 dagi equivalence partitioning'ning tilga xos qo'llanilishi.

Vaqt zonasi

Asia/Tashkent — UTC+5, yozgi vaqtga o'tish yo'q: Node 24'da yanvar va iyul uchun ham GMT+5 chiqadi. Tekshiruvlar: server UTC'da saqlab, ekranda Toshkent vaqtida ko'rsatadimi; promo-kod "bugun 23:59 gacha" Toshkent vaqti bo'yicha tugaydimi; chet eldagi foydalanuvchi uchun buyurtma vaqti qanday ko'rinadi.


9. Visual testing: toHaveScreenshot va vositalar {#visual}

Visual regression testing — sahifa yoki komponentning skrinshotini oldindan tasdiqlangan baseline bilan solishtirish. Funksional assertion'lar "tugma bor va bosiladi" deydi, visual test esa "tugma o'z joyida, to'g'ri rangda, matn kesilmagan" ekanini ushlaydi.

YondashuvQanday ishlaydiMisollar
Pixel diffPiksellarni solishtiradiPlaywright toHaveScreenshot
Bulutli vizual xizmatlarBaseline'larni saqlaydi, review UI beradiPercy (BrowserStack), Chromatic (Storybook komponentlari uchun)
AI asosidagi taqqoslashInson ko'ziga sezilmaydigan farqlarni filtrlashga urinadiApplitools Eyes

Playwright bilan

// tests/visual.spec.ts
import { test, expect } from "@playwright/test";

const PRICE_COLOR = process.env.PRICE_COLOR ?? "#0F766E";

const productCard = (updatedAt: string) => `
  <html lang="uz"><head><title>DemoBozor</title><style>
    body { font-family: Arial, sans-serif; margin: 24px; }
    .card { width: 280px; padding: 16px; border: 1px solid #ddd; border-radius: 12px; }
    .price { color: ${PRICE_COLOR}; font-size: 22px; font-weight: bold; }
    .spinner { width: 16px; height: 16px; border: 3px solid #ccc; border-top-color: #333;
               border-radius: 50%; animation: spin 1s linear infinite; }
    @keyframes spin { to { transform: rotate(360deg); } }
  </style></head><body>
    <div class="card" data-test="product-card">
      <h2>Elektr choynak</h2>
      <p class="price">349 000 so'm</p>
      <p data-test="updated-at">Yangilandi: ${updatedAt}</p>
      <div class="spinner"></div>
      <button>Savatchaga qo'shish</button>
    </div>
  </body></html>`;

test("mahsulot kartasi vizual ko'rinishi", async ({ page }) => {
  await page.setViewportSize({ width: 400, height: 360 });
  await page.setContent(productCard(new Date().toISOString()));

  await expect(page.getByTestId("product-card")).toHaveScreenshot(
    "product-card.png",
    {
      mask: [page.getByTestId("updated-at")], // har safar o'zgaradigan vaqt
      animations: "disabled", // spinner to'xtatiladi
      maxDiffPixels: 50, // kichik farqlarga ruxsat
    },
  );
});

Haqiqiy ish oqimi (Playwright 1.64, macOS):

# 1) Birinchi ishga tushirish — baseline yo'q, test yiqiladi:
npx playwright test tests/visual.spec.ts
#    Error: A snapshot doesn't exist at .../visual.spec.ts-snapshots/product-card-chromium-darwin.png, writing actual.

# 2) Baseline yaratish (natijani ko'z bilan tekshirib, commit qiling):
npx playwright test tests/visual.spec.ts --update-snapshots

# 3) Keyingi ishga tushirishlar baseline bilan solishtiradi — o'tadi.

# 4) Narx rangi o'zgarsa (PRICE_COLOR='#DC2626'):
#    Error: expect(locator).toHaveScreenshot(expected) failed
#      669 pixels (ratio 0.01 of all image pixels) are different.
#    test-results/ papkasida: product-card-expected.png, -actual.png, -diff.png

Muhim jihatlar:

  • Baseline nomida brauzer va platforma bor (-chromium-darwin.png). Playwright hujjati: render OS, versiya, sozlamalar, apparat va headless rejimga qarab farq qiladi — baseline'lar qayerda yaratilgan bo'lsa, testlar ham o'sha muhitda ishlashi kerak. Amalda baseline'larni CI bilan bir xil muhitda (masalan, Linux konteynerida) yarating (QA 21).
  • mask — vaqt, tasodifiy reklama, avatar kabi o'zgaruvchan joylarni yopadi; animations: 'disabled' — CSS animatsiyalarini to'xtatadi; maxDiffPixels / threshold — sezgirlik; stylePath — skrinshot paytida maxsus CSS (masalan, iframe'larni yashirish).
  • Komponent darajasidagi kichik skrinshotlar butun sahifadan barqarorroq.
  • Responsive tekshiruv: bir xil test 375 / 768 / 1280 px kengliklarda.
  • Diff'ni PR'da ko'rib tasdiqlash jarayoni bo'lsin: --update-snapshots ni o'ylamasdan ishga tushirish — bug'ni baseline'ga "muhrlab qo'yish" demakdir.

Batafsil Playwright amaliyoti: QA 19.


10. Usability asoslari: Nielsen'ning 10 evristikasi {#usability}

Jakob Nielsen'ning 10 ta usability evristikasi (1994) — interfeysni tez baholash uchun tekshiruv ro'yxati:

#EvristikaDemoBozor'dagi buzilish misoli
1Visibility of System Status"To'lash" bosilgach hech narsa o'zgarmaydi — yuklanish ko'rsatkichi yo'q
2Match Between the System and the Real World"SKU qoldig'i: 0" — xaridor uchun "Sotuvda yo'q" bo'lishi kerak
3User Control and FreedomSavatchadan o'chirilgan mahsulotni qaytarib bo'lmaydi
4Consistency and StandardsBir ekranda "Savatcha", boshqasida "Korzina"
5Error PreventionMuddatli to'lov formasida yosh chegarasi oldindan ko'rsatilmaydi
6Recognition Rather than RecallCheckout'da avvalgi manzillar taklif qilinmaydi
7Flexibility and Efficiency of UseDoimiy mijoz uchun "qayta buyurtma" tugmasi yo'q
8Aesthetic and Minimalist DesignMahsulot sahifasida 5 ta bir-biriga o'xshash banner
9Help Users Recognize, Diagnose, and Recover from Errors"Xato 4012" — nima qilish kerakligi yozilmagan
10Help and DocumentationQaytarish qoidalari faqat ofertaning 20-sahifasida

"5 ta foydalanuvchi" qoidasi

Nielsen'ning 2000-yildagi maqolasiga ko'ra, bir xil turdagi 5 ta foydalanuvchi bilan test taxminan 85% usability muammolarini topadi (bitta foydalanuvchi o'rtacha ~31% ni topadi degan modelga asoslangan). Muallifning o'zi qo'shgan shartlar: bitta katta test o'rniga bir nechta kichik testlar (har redizayndan keyin), foydalanuvchilar guruhlari juda farq qilsa — har guruhdan alohida, miqdoriy (metrikali) tadqiqotlar uchun esa ko'proq ishtirokchi kerak. Bu — qat'iy qonun emas, amaliy "rule of thumb".


11. Amaliy mashqlar {#mashqlar}

Mashq 1: Kontrastni tuzating

axe TodoMVC'da .selected filtri uchun quyidagini chiqardi: contrast of 4.47 (foreground color: #777777, background color: #ffffff, font size: 10.5pt (14px)...). Expected contrast ratio of 4.5:1. (a) Bu qaysi SC? (b) Nega 4.47 yetmaydi? (c) Eng kam o'zgarish bilan qaysi rangni taklif qilasiz?

<details> <summary>💡 Javobni ko'rish</summary>

  • (a) 1.4.3 Contrast (Minimum), AA.
  • (b) 14px oddiy matn "katta matn" emas (≥ 18pt yoki ≥ 14pt bold emas), shuning uchun talab 4.5:1. 4.47 < 4.5 — chegaraga yaqin bo'lsa ham fail.
  • (c) Bir pog'ona to'qroq kulrang: #767676 oq fonda ≈ 4.54:1 — talabdan o'tadi (hisob WCAG formulasi bo'yicha). Kattaroq zaxira kerak bo'lsa #6B6B6B (≈ 5.33:1). Dizayner bilan kelishib, design token'ni o'zgartirish kerak — bitta ekranni emas.

</details>

Mashq 2: Modal oyna klaviatura testi

DemoBozor'da "Manzil qo'shish" modal oynasi bor (maydonlar: shahar, ko'cha, uy, izoh; tugmalar: "Saqlash", "Bekor qilish", yopish ✕). Klaviatura bo'yicha test case'larni yozing.

<details> <summary>💡 Javobni ko'rish</summary>

#QadamKutilgan natija
1Modalni klaviatura bilan ochish (Enter)Modal ochiladi, fokus birinchi maydonga (yoki sarlavhaga) o'tadi
2Tab bilan aylanishFokus faqat modal ichida aylanadi, orqadagi sahifaga chiqmaydi
3Har elementdaFokus aniq ko'rinadi (2.4.7)
4Yopish ✕ tugmasiScreen reader uni "Yopish, tugma" deb o'qiydi (nomli)
5EscModal yopiladi
6Yopilgandan keyinFokus modalni ochgan tugmaga qaytadi
7Bo'sh maydon bilan "Saqlash"Xato matni maydon yonida, screen reader o'qiydi
8200% zoomModal kontenti kesilmaydi, scroll qilinadi

</details>

Mashq 3: Rus plural test qiymatlari

Savatcha sarlavhasi: "В корзине N товар/товара/товаров". Equivalence partitioning bilan minimal, lekin to'liq qamrovli test qiymatlarini tanlang va kutilgan shaklni yozing.

<details> <summary>💡 Javobni ko'rish</summary>

NKategoriya (Intl.PluralRules('ru'))Kutilgan
1one1 товар
2few2 товара
5many5 товаров
11many11 товаров (11–14 — istisno!)
12many12 товаров
21one21 товар
22few22 товара
25many25 товаров
101one101 товар
111many111 товаров

0 qiymati uchun alohida xabar ("Корзина пуста") talabda bormi — tekshiring. Kodda shakllarni qo'lda if bilan emas, Intl.PluralRules (yoki i18n kutubxonasi) bilan tanlash kerak.

</details>

Mashq 4: Qidiruv uchun test to'plami

DemoBozor katalogida "Gʻijduvon kosasi" (U+02BB bilan) bor. Apostrof muammosini ushlaydigan qidiruv test'larini yozing va searchKey funksiyasi bilan kutilgan natijani ayting.

<details> <summary>💡 Javobni ko'rish</summary>

Qidiruv so'roviIshlatilgan belgiKutilgan
gʻijduvonU+02BBTopiladi
g'ijduvonU+0027Topiladi
g‘ijduvonU+2018Topiladi
g’ijduvonU+2019Topiladi
gijduvon`U+0060Topiladi
GʻIJDUVONKatta harflarTopiladi
гиждувонKirillTalabga qarab (yozuvlararo qidiruv bormi?)

searchKey barcha apostrof variantlarini U+02BB ga keltirib, kichik harfga o'tkazgani uchun dastlabki 6 holatda ham kalitlar teng bo'ladi. Kirill → lotin moslashtirish alohida talab va alohida algoritm (transliteratsiya) talab qiladi.

</details>

Mashq 5: L10n bug'larini toping

Rus tilidagi buyurtma ekrani tavsifi: sarlavha "Ваш заказ", tugma "Buyurtma berish", matn "В корзине 5 товара", narx "1250000 so'm", sana "10/09/2026", yetkazib berish izohi kesilgan: "Бесплатная доставка от 300 000 сў...", xato xabari "Promo code expired". Bug'larni sanang.

<details> <summary>💡 Javobni ko'rish</summary>

  1. "Buyurtma berish" — tugma tarjima qilinmagan (hardcoded yoki kalit yo'q).
  2. "5 товара" — noto'g'ri plural, to'g'risi "5 товаров".
  3. "1250000 so'm" — guruhlash yo'q va valyuta locale'ga mos emas (rus interfeysida Intl UZS beradi yoki mahsulot talabidagi rus yozuvi kerak).
  4. "10/09/2026" — noaniq format; rus locale'da odatda 10.09.2026, umuman olganda talab bo'yicha bitta izchil format.
  5. "сў..." — rus matni ichida o'zbek kirill valyuta nomi va matn kesilgan (kenglik/uzunlik muammosi).
  6. "Promo code expired" — backend xabari tarjima qilinmagan; API xato kodini qaytarishi, matnni esa mijoz locale bo'yicha ko'rsatishi kerak.

</details>

Mashq 6: Beqaror visual test

toHaveScreenshot testi lokal kompyuterda o'tadi, CI'da esa doim yiqiladi; ba'zan lokalda ham har 5 ishga tushirishda bir marta yiqiladi. Kamida 4 ta ehtimoliy sababni va yechimini yozing.

<details> <summary>💡 Javobni ko'rish</summary>

SababYechim
Baseline macOS'da yaratilgan, CI — Linux (-darwin vs -linux)Baseline'larni CI bilan bir xil muhitda (konteynerda) yaratish
Sahifada vaqt, tasodifiy banner, avatarmask yoki test data'ni qotirish
Animatsiya/karuselanimations: 'disabled', karuselni to'xtatish
Shrift kech yuklanadiShriftlarni lokal ulash, yuklanishini kutish
Ma'lumot o'zgaradi (narx, reyting)Mock/route bilan barqaror ma'lumot (QA 19)
Juda katta (butun sahifa) skrinshotKomponent darajasidagi kichik skrinshotlar

</details>

Mashq 7: Evristik tahlil

Quyidagi DemoBozor kuzatuvlarini Nielsen evristikalariga bog'lang: (a) to'lov 8 soniya davom etadi, ekran o'zgarmaydi; (b) xato: "ERR_PAYMENT_DECLINED_51"; (c) savatchadan mahsulot tasdiqsiz va qaytarib bo'lmaydigan tarzda o'chadi; (d) iOS'da "Orqaga" yuqori chapda, Android versiyasida esa pastki o'ngda.

<details> <summary>💡 Javobni ko'rish</summary>

  • (a) #1 Visibility of System Status — yuklanish holati ko'rsatilishi kerak.
  • (b) #9 Help Users Recognize, Diagnose, and Recover from Errors (va #2) — oddiy tilda: "Karta to'lovni rad etdi. Boshqa karta bilan urinib ko'ring yoki bank bilan bog'laning."
  • (c) #3 User Control and Freedom (va #5 Error Prevention) — "Bekor qilish" imkoniyati yoki tasdiq.
  • (d) #4 Consistency and Standards — lekin ehtiyot bo'ling: har platformaning o'z standarti bor; platforma konventsiyasiga mos kelishi muhimroq.

</details>


12. O'zingizni tekshiring {#checklist}

  • [ ] POUR printsiplarini va AA darajasini misollar bilan tushuntira olaman
  • [ ] WCAG 2.2 da qo'shilgan mezonlardan kamida 5 tasini aytib bera olaman
  • [ ] Sahifani faqat klaviatura bilan tekshirib, fokus muammolarini topa olaman
  • [ ] @axe-core/playwright testini yozib, violations ni o'qiy olaman
  • [ ] Avtomatik a11y skanerining chegarasini tushuntira olaman
  • [ ] O'zbek apostroflari, saralash va plural bo'yicha test g'oyalarini bera olaman
  • [ ] Intl natijasidagi NBSP muammosini bilaman
  • [ ] toHaveScreenshot bilan baseline yaratib, diff'ni tahlil qila olaman

Xulosa {#xulosa}

  • Accessibility — WCAG 2.2 AA: POUR printsiplari; QA har feature'da klaviatura, fokus, kontrast, label va screen reader'ni tekshiradi.
  • WCAG 2.2 9 ta yangi mezon qo'shdi (fokus yashirinmasligi, 24×24 px nishon, sudrash muqobili, accessible authentication va boshqalar) va 4.1.1 Parsing'ni olib tashladi.
  • axe-core tez topiladigan xatolarni ushlaydi, lekin "0 violations" — "accessible" degani emas: placeholder-label, mazmunsiz alt kabi muammolarni inson topadi.
  • L10n bug'larining ko'pi oldindan bashorat qilinadi: hardcoded matn, plural, kesilish, sana/valyuta formati, backend xabarlari.
  • O'zbek tilida: apostrofning 5 xil ko'rinishi qidiruvni buzadi, Oʻ/Gʻ alifboda Z dan keyin keladi, lotin va kirill parallel; alifbo islohoti holatini kuzatib boring.
  • Intl natijasida NBSP va U+02BB bor — testlarda buni hisobga oling.
  • Visual testlar: barqaror ma'lumot, mask, animations: 'disabled', CI bilan bir xil muhitdagi baseline va PR'da diff review.
  • Keyingi dars: QA 26: AI va QA (2026) — LLM bilan test dizayn, Playwright Agents, MCP va AI tizimlarini testlash

Manbalar {#manbalar}

  1. W3C — WCAG 2.2
  2. W3C WAI — What's New in WCAG 2.2
  3. W3C WAI — Understanding SC 2.5.8 Target Size (Minimum)
  4. W3C WAI — WCAG 2.2 Quick Reference
  5. W3C WAI — Accessibility Principles
  6. W3C — WCAG 3.0 Working Draft
  7. W3C — Using ARIA
  8. W3C WAI — ARIA Authoring Practices Guide
  9. W3C WAI — Forms tutorial: Instructions (placeholder)
  10. European Commission — European Accessibility Act
  11. EUR-Lex — Directive (EU) 2019/882
  12. Playwright — Accessibility testing
  13. Playwright — Visual comparisons
  14. dequelabs/axe-core — GitHub
  15. Deque — Automated testing study (57%)
  16. Chrome — Lighthouse accessibility scoring
  17. WebAIM — Contrast Checker
  18. WAVE — WebAIM
  19. NV Access — NVDA
  20. Apple HIG — Buttons
  21. Apple HIG — Accessibility
  22. Apple — Accessibility Inspector
  23. Google — Accessibility Scanner va touch target tavsiyasi
  24. W3C Internationalization — Text size in translation
  25. Unicode CLDR — Language Plural Rules
  26. Wikipedia — Uzbek alphabet
  27. UzA — Senate approves changes to Uzbek alphabet (2026-09-10)
  28. The Times of Central Asia — Uzbekistan Latin alphabet changes
  29. Kun.uz — Lower house passes bill to revise Uzbek alphabet (2026-07-07)
  30. Percy — BrowserStack
  31. Applitools
  32. Chromatic
  33. NN/g — 10 Usability Heuristics
  34. NN/g — Why You Only Need to Test with 5 Users

Markdown manba

iOS Lessons