28 β i18n/l10n va accessibility¶
β¬ οΈ Oldingi: 27 β Xavfsizlik: escaping, sanitization, nonce Β· π README Β· Keyingi: 29 β Performans va tarqatish β‘οΈ
Bu bobda: professional tema ikki narsani albatta bajaradi. Birinchisi β i18n/l10n: tema interfeysidagi har bir matn (
__(),_e(),_n(),_x()orqali) tarjima qilinishga tayyor bo'lishi, shunda boshqa tildagi foydalanuvchi temani o'z tilida ko'ra olsin. Ikkinchisi β accessibility (a11y): tema sichqonchasiz (faqat klaviatura bilan), ko'rmaydigan (skrinrider bilan) yoki kam ko'radigan (past kontrast bilan) foydalanuvchi uchun ham ishlatib bo'ladigan bo'lsin. Biztext domain(tema slug, string literal bo'lishi shart),.pot/.po/.mofayllar vawp i18n make-potquvurini, hamda semantik HTML5,skip-link, ARIA, klaviatura fokusi va WCAG kontrast standartlarini ko'rib chiqamiz. i18n funksiyalari va POT/MO generatsiyasi jonli WordPress 7.0 muhitidaphp -lvawp-clibilan haqiqatan tekshirilgan.
Nega i18n va a11y β bu "majburiy", "ixtiyoriy" emas¶
Tasavvur qiling, do'kon eshigiga faqat o'zbekcha "Ochiq" deb yozdingiz. Ruscha yoki inglizcha gapiradigan mijoz nima qiladi? Va eshik faqat zinapoyali bo'lsa, aravachadagi mijoz-chi? Yaxshi do'kon hammaga eshigini ochadi. Tema ham xuddi shunday: i18n (internationalization) temani har qanday tilga tarjima qilishga tayyor qiladi, a11y (accessibility) esa har qanday foydalanuvchiga β jismoniy imkoniyatidan qat'i nazar β saytdan foydalanish imkonini beradi.
Atamalardagi raqamlar shunchaki qisqartma: i18n = "internationalization" (i + 18 harf + n), l10n = "localization" (l + 10 harf + n), a11y = "accessibility" (a + 11 harf + y). Farqi:
- i18n β kodni tarjimaga tayyorlash (matnlarni maxsus funksiyalarga o'rash). Buni dasturchi qiladi.
- l10n β aniq bir tilga tarjima qilish (
.pofaylini to'ldirish). Buni odatda tarjimon qiladi.
WordPress.org tema katalogida i18n β majburiy talab: matn "qotirilgan" (hardcoded) tema qabul qilinmaydi. A11y esa accessibility-ready tegi orqali alohida sifat belgisi. Bu bobda ikkalasini ham temaga o'rnatamiz.
i18n: matnni __() ga o'rash¶
Eng asosiy qoida: temada foydalanuvchi ko'radigan har bir matn to'g'ridan-to'g'ri yozilmasdan, tarjima funksiyasiga o'ralishi kerak.
<?php
// XATO β matn qotirilgan, hech qachon tarjima qilinmaydi:
echo 'Batafsil';
// TO'G'RI β tarjimaga tayyor:
echo __( 'Batafsil', 'mytheme' );
__() (ikki pastki chiziq) β i18n ning yuragi. U ikki argument oladi: tarjima qilinadigan matn va text domain ('mytheme'). Funksiya matnni qaytaradi (echo qilmaydi) β uni o'zgaruvchiga, sprintf ga yoki konkatenatsiyaga ishlatish mumkin.
Sahifa ochilganda WordPress text domain uchun yuklangan tarjimani qidiradi: agar mos .mo fayl bo'lsa, tarjimani qaytaradi; bo'lmasa β asl matnni o'zini qaytaradi. Shuning uchun i18n ga o'rash saytni buzmaydi β tarjima bo'lmasa ham hammasi ishlayveradi.
Tasdiqlangan natija (jonli WP 7.0): quyidagi buyruq jonli saytda ishga tushirildi:
Natija (aynan): Tarjima yuklanmagani uchun funksiyalar asl matnni qaytardi β bu kutilgan, to'g'ri xulq.
i18n funksiyalar oilasi¶
WordPress'da bir nechta tarjima funksiyasi bor β har biri aniq vazifa uchun. Hammasi jonli WP 7.0 da function_exists() bilan tasdiqlandi.
| Funksiya | Vazifa | Qaytaradi / echo |
|---|---|---|
__( $text, $domain ) |
Tarjima qiladi | qaytaradi |
_e( $text, $domain ) |
Tarjima qiladi | echo qiladi |
esc_html__( $text, $domain ) |
Tarjima + esc_html |
qaytaradi |
esc_html_e( $text, $domain ) |
Tarjima + esc_html |
echo qiladi |
esc_attr__( $text, $domain ) |
Tarjima + esc_attr |
qaytaradi |
esc_attr_e( $text, $domain ) |
Tarjima + esc_attr |
echo qiladi |
_n( $single, $plural, $n, $domain ) |
Ko'plik (1 / ko'p) | qaytaradi |
_x( $text, $context, $domain ) |
Kontekstli tarjima | qaytaradi |
_ex( $text, $context, $domain ) |
Kontekstli tarjima | echo qiladi |
esc_attr_x( $text, $context, $domain ) |
Kontekst + esc_attr |
qaytaradi |
_nx( $single, $plural, $n, $context, $domain ) |
Ko'plik + kontekst | qaytaradi |
_n_noop( $single, $plural, $domain ) |
Ko'plikni keyinroq ishlatish uchun ro'yxatga olish | massiv |
Eng muhim qoida β tarjima + escaping birga. 27-bobda "har chiqishni escape qil" deganini eslang. Tarjima qilingan matn ham chiqishdir, demak u ham escape qilinishi kerak. Shuning uchun ko'pincha
_e()o'rnigaesc_html_e(),__()o'rnigaesc_html__()ishlatiladi._e()ni faqat o'zingiz to'liq nazorat qiladigan, HTML li tarjimalarda (kamdan-kam) ishlating.
_e() va __() β qaytarish vs echo¶
Bu eng ko'p chalkashtiriladigan juftlik:
<?php
// __() qaytaradi -> o'zgaruvchiga yoki sprintf ga:
$label = __( 'Yuborish', 'mytheme' );
// _e() darhol echo qiladi -> shablon ichida qulay:
?>
<button><?php esc_html_e( 'Yuborish', 'mytheme' ); ?></button>
Qoidani eslab qolish oson: oxiridagi e β "echo" degani.
Text domain β tema slug, string LITERAL¶
Har bir i18n funksiyaning oxirgi argumenti β text domain. Bu tema tarjimalarini boshqa plagin/tema tarjimalaridan ajratuvchi noyob "kalit". Qoidasi:
- Text domain = tema papka nomi (slug). Agar tema
mytheme/papkasida bo'lsa, text domain'mytheme'bo'lishi shart. Bustyle.cssheaderidagiText Domain:maydoni bilan ham mos kelishi kerak. - U doim string LITERAL bo'lishi shart β o'zgaruvchi EMAS.
<?php
// TO'G'RI β literal string:
__( 'Salom', 'mytheme' );
// XATO β o'zgaruvchi (make-pot matnni TOPOLMAYDI):
$domain = 'mytheme';
__( 'Salom', $domain );
// XATO β konstanta ham bo'lmaydi:
__( 'Salom', MY_DOMAIN );
Nega? Chunki wp i18n make-pot matnlarni statik tahlil orqali (kodni ishga tushirmasdan) topadi. U __( '...', 'mytheme' ) ko'rinishini qidiradi. O'zgaruvchi yoki konstanta turgan joyda nimani qidirishni bilmaydi β string oddiygina o'tkazib yuboriladi va tarjima ro'yxatiga tushmaydi.
style.css headeri¶
Text Domainβ kodda ishlatadigan domen (papka nomiga teng).Domain Pathβ tarjima fayllari (.mo) turadigan papka (odatda/languages).
Tarjimani yuklash: load_theme_textdomain¶
WordPress tarjimani avtomatik topishi uchun unga aytish kerak: "mening tarjimalarim shu papkada". Buni after_setup_theme hookida qilamiz (9-bobni eslang).
<?php
add_action( 'after_setup_theme', function () {
load_theme_textdomain(
'mytheme', // text domain
get_template_directory() . '/languages' // .mo fayllar papkasi
);
} );
Bu funksiya languages/ papkasidan joriy tilga mos .mo faylni qidiradi. Til wp-admin > Sozlamalar > Umumiy > Sayt tili da tanlanadi (yoki WPLANG). Masalan ruscha tilda WordPress languages/mytheme-ru_RU.mo ni yuklaydi.
Block tema va WP 4.6+ avtomatik yuklash: WordPress.org katalogidan o'rnatilgan temalar uchun (klassik ham, block ham) WP 4.6+ tarjimani avtomatik yuklaydi β
load_theme_textdomainni chaqirish shart emas. Lekin tema katalogdan tashqarida tarqatilsa yoki lokallanguages/ichidagi tarjimalarni ishlatmoqchi bo'lsangiz, uni baribir chaqirish kerak. Eng xavfsizi β har doim chaqirib qo'yish.Block tema theme.json avtomatik tarjima. Block temada
theme.jsonichidagititlemaydonlari (color palette nomi, font o'lchami nomi, style variation nomi...) vapatterns/papkasidagi pattern sarlavhalari WordPress tomonidan avtomatik tarjima qilinadi β siz JSON ichida__()yoza olmaysiz, lekin make-pot bu matnlarni POT ga o'zi qo'shadi (text domainstyle.cssdan olinadi). Demak block temada ko'p tarjima "tekin" keladi.
_n() β ko'plik shakllari¶
Tillarda son bilan kelgan so'z shakli o'zgaradi. Inglizchada "1 comment" / "2 comments". Boshqa tillarda qoidalar murakkabroq (rus, arab tillarida bir nechta ko'plik shakli bor). _n() shuni hal qiladi:
<?php
// _n( birlik, ko'plik, son, domen )
$count = 5;
printf(
esc_html( _n( '%s ta izoh', '%s ta izoh', $count, 'mytheme' ) ),
number_format_i18n( $count )
);
_n() $count ga qarab birlik yoki ko'plik shaklini tanlaydi, lekin sonni o'zi qo'ymaydi β uni %s placeholder va printf/sprintf orqali siz qo'yasiz. Diqqat: sonni number_format_i18n() orqali formatlash kerak (ba'zi tillar minglikni boshqacha ajratadi).
Tasdiqlangan natija (jonli WP 7.0):
Ikkala holda ham to'g'ri shakl tanlandi (o'zbekcha birlik/ko'plik bir xil yozilgani uchun matn bir xil chiqadi, lekin funksiya sonni to'g'ri qabul qildi).wp eval-fileorqali ishga tushirildi:
_n_noop() β ko'plikni keyinroq tarjima qilish¶
Ba'zan ko'plik matnini bir joyda e'lon qilib, boshqa joyda (son ma'lum bo'lganda) ishlatish kerak β masalan massivda. Buning uchun _n_noop() (e'lon) + translate_nooped_plural() (ishlatish):
<?php
// E'lon (son hali noma'lum):
$comments_plural = _n_noop( '%s ta izoh', '%s ta izoh', 'mytheme' );
// Keyinroq, son ma'lum bo'lganda:
$count = 3;
printf(
translate_nooped_plural( $comments_plural, $count, 'mytheme' ),
number_format_i18n( $count )
);
Tasdiqlangan (jonli WP 7.0):
_n_noop('%s comment','%s comments','mytheme')+translate_nooped_plural($noop, 3, 'mytheme')natija:3 commentsβ to'g'ri ishladi.
_x() β kontekstli tarjima¶
Bitta inglizcha (yoki o'zbekcha) so'z turli o'rinlarda turlicha tarjima qilinishi mumkin. Masalan "Post":
- ot sifatida β "Maqola" (blog posti);
- fe'l sifatida β "Joylash" (tugma matni).
Tarjimon .po faylda faqat "Post" so'zini ko'rsa, qaysi ma'noni nazarda tutganini bilmaydi. _x() ikkinchi argument sifatida kontekst beradi:
<?php
echo esc_html_x( 'Post', 'maqola turi', 'mytheme' ); // ot: Maqola
echo esc_html_x( 'Post', 'tugma matni', 'mytheme' ); // fe'l: Joylash
Asl matn ('Post') bir xil, lekin kontekst ('maqola turi' vs 'tugma matni') ularni tarjima faylda ikki alohida yozuv qiladi. _ex() β _x() ning echo varianti, esc_attr_x() β esc_attr bilan birga (ARIA labellar uchun juda qulay).
Tasdiqlangan (jonli WP 7.0):
_x('Post','noun context','mytheme')natija:Post(tarjima yo'qligida asl matn) β to'g'ri.
sprintf / printf bilan %s placeholder¶
O'zgaruvchini (ism, son, sana) tarjima matniga qo'shganda hech qachon stringni . bilan birlashtirmang β buni sprintf/printf va placeholder bilan qiling.
<?php
// XATO β so'z tartibi tilga bog'liq, tarjimon o'rnini o'zgartira olmaydi:
echo __( 'Xush kelibsiz, ', 'mytheme' ) . esc_html( $user );
// TO'G'RI β placeholder, tarjimon %s ni xohlagan joyga qo'yadi:
printf(
/* translators: %s: foydalanuvchi ismi */
esc_html__( 'Xush kelibsiz, %s!', 'mytheme' ),
esc_html( $user )
);
Nega muhim? Boshqa tilda so'z tartibi boshqacha bo'lishi mumkin. Birlashtirsangiz, tarjimon faqat "Xush kelibsiz, " qismini tarjima qiladi va %s ni boshqa joyga ko'chira olmaydi. Placeholder bilan butun jumla bir tarjima yozuvi bo'ladi.
Bir nechta o'zgaruvchi bo'lsa β raqamli placeholder ishlating (%1$s, %2$s), shunda tarjimon tartibni o'zgartira oladi:
<?php
printf(
/* translators: 1: muallif ismi, 2: sana */
esc_html__( '%1$s tomonidan %2$s da yozilgan', 'mytheme' ),
esc_html( $author ),
esc_html( $date )
);
translators:izohi β best practice.make-potplaceholder li matnda/* translators: ... */izohini ko'rsa, uni.pofaylga qo'shadi va tarjimonga%snima ekanini tushuntiradi. Biz buni jonli sinovda ko'rdik: izohsiz matn uchun make-pot ogohlantirish berdi ("contains placeholders but has no translators: comment"). Izohni__()chaqiruvidan darhol oldingi qatorga yozing.
.pot / .po / .mo fayllar¶
Tarjima quvuri uch xil fayldan iborat:
| Fayl | Nima | Kim tahrirlaydi |
|---|---|---|
.pot |
Portable Object Template β barcha matnlar ro'yxati, tarjimasiz (msgstr ""). Shablon. |
make-pot avtomatik yaratadi |
.po |
Portable Object β bitta til uchun to'ldirilgan tarjima (matn + tarjima juftliklari). O'qiladigan matn. | tarjimon (Poedit, GlotPress) |
.mo |
Machine Object β .po ning kompilyatsiya qilingan, binar, tez varianti. |
make-mo avtomatik yaratadi |
Oqim: make-pot -> .pot -> (tarjimon) .po -> make-mo -> .mo -> WordPress yuklaydi.
Fayl nomlari muhim. Tema uchun:
languages/mytheme.potβ shablon (bitta);languages/mytheme-ru_RU.povalanguages/mytheme-ru_RU.moβ ruscha ({domain}-{locale});languages/mytheme-uz.pova.moβ o'zbekcha.
WP 6.5+ da
.moo'rniga PHP tarjima fayllari (.l10n.php) ham qo'llab-quvvatlanadi va ular tezroq yuklanadi.wp i18n make-phpularni.podan yaratadi..mohamon eng keng tarqalgan, shuning uchun biz unga e'tibor beramiz.
wp i18n make-pot β POT ni avtomatik yaratish¶
POT faylni qo'lda yozish β azob. WP-CLI buni avtomatlashtiradi: u tema fayllarini skanerlaydi, har bir __(), _e(), _n(), _x() chaqiruvidagi matnni topadi va POT ga yozadi.
# Tema papkasidan:
wp i18n make-pot . languages/mytheme.pot
# Yoki to'liq yo'l bilan:
wp i18n make-pot /path/to/themes/mytheme languages/mytheme.pot
Tasdiqlangan (jonli WP 7.0, WP-CLI 2.12.0): test temasi yaratib (
index.phpichidaesc_html__,_n,esc_attr_x,esc_html_ebilan),wp i18n make-potishga tushirildi. Natija:Success: POT file successfully generated.Hosil bo'lgan POT da matnlar to'g'ri ajratilgan edi:Diqqat qiling: ko'plik (#: index.php:4 msgid "Bizning blog" msgstr "" #: index.php:8 #, php-format msgid "%s ta maqola topildi" msgid_plural "%s ta maqola topildi" msgstr[0] "" msgstr[1] "" #: index.php:12 msgctxt "navigation" msgid "Asosiy menyu" msgstr ""msgid_plural), kontekst (msgctxt) vastyle.cssheaderidagi matnlar (Theme Name, Description...) ham avtomatik ajratildi.
wp i18n ning to'liq buyruqlar to'plami (jonli WP 7.0 da tasdiqlangan): make-pot, make-mo, make-php, make-json, update-po.
.po ni .mo ga kompilyatsiya qilish:
Tasdiqlangan (jonli WP 7.0): namuna
mytheme-uz.pofayli yaratilib,wp i18n make-moishga tushirildi. Natija:Success: Created 1 file.β.po(277 bayt) dan.mo(462 bayt, binar) hosil bo'ldi. Bu i18n quvurining oxirigacha haqiqatan ishlashini isbotlaydi.Verifikatsiya eslatmasi: bu bobdagi barcha i18n PHP misollari
php -l(PHP 8.4.0) bilan sintaksis tekshirilgan β No syntax errors detected. i18n funksiyalari vawp i18nbuyruqlari jonli WordPress 7.0 + WP-CLI 2.12.0 da ishga tushirib tasdiqlangan; soxta natija yo'q.
Accessibility (a11y): hamma uchun tema¶
i18n tilni ochsa, a11y imkoniyatni ochadi. Sayt foydalanuvchilarining bir qismi:
- sichqonchadan foydalanmaydi (faqat klaviatura yoki maxsus qurilma);
- ko'rmaydi (skrinrider β ekrandagi matnni ovozli o'qiydigan dastur);
- kam ko'radi (katta shrift, yuqori kontrast kerak);
- rang ko'rishida farq bor (rangga tayanib bo'lmaydi).
Yaxshi tema bularning hammasini hisobga oladi. WordPress.org accessibility-ready tegi shu standartni bildiradi.
1. Semantik HTML5¶
Sahifani <div> lar to'plami emas, ma'noli HTML5 elementlari bilan tuzing. Skrinrider <nav>, <main>, <article> larni tushunadi va foydalanuvchiga "asosiy kontentga o't", "navigatsiyaga o't" kabi tez yo'llarni beradi.
<?php // header.php / index.php (klassik tema) ?>
<header class="site-header">
<nav class="main-navigation" aria-label="<?php esc_attr_e( 'Asosiy menyu', 'mytheme' ); ?>">
<?php wp_nav_menu( array( 'theme_location' => 'primary' ) ); ?>
</nav>
</header>
<main id="primary" class="site-main">
<article <?php post_class(); ?>>
<h1><?php the_title(); ?></h1>
<?php the_content(); ?>
</article>
</main>
<aside class="widget-area" aria-label="<?php esc_attr_e( 'Yon panel', 'mytheme' ); ?>">
<?php dynamic_sidebar( 'sidebar-1' ); ?>
</aside>
<footer class="site-footer">
<?php // mualliflik, havolalar ?>
</footer>
Qoidalar:
- Har sahifada bitta
<h1>(asosiy sarlavha), so'ng<h2>,<h3>ketma-ketligi buzilmasin (h1'dan keyin to'g'ridan-to'g'ri h3 ga sakramang). <main id="primary">β skip-link shu yerga olib boradi.- Bir nechta
<nav>bo'lsa, har birigaaria-labelbering (skrinrider farqlay olsin).
Block temada bu markup templates/ HTML fayllarida block teglar orqali keladi (core/navigation, core/post-content...), lekin Twenty Twenty-Five kabi referens temalar shu semantik strukturani saqlaydi.
2. Skip-link β "kontentga o'tish"¶
Klaviatura bilan saytni ko'rayotgan foydalanuvchi har sahifada avval butun menyuni Tab bilan o'tishi kerak bo'lsa β charchaydi. Skip-link β sahifaning eng birinchi fokuslanadigan elementi: u to'g'ridan-to'g'ri asosiy kontentga sakraydi. Odatda yashirin turadi, faqat Tab bosilib fokus tushganda ko'rinadi.
<?php // header.php da, <body> dan keyin BIRINCHI element ?>
<a class="skip-link screen-reader-text" href="#primary">
<?php esc_html_e( 'Asosiy kontentga o\'tish', 'mytheme' ); ?>
</a>
href="#primary" β <main id="primary"> ga ishora qiladi. CSS:
.skip-link {
position: absolute;
left: -9999px;
top: 0;
z-index: 100000;
}
/* Fokus tushganda KO'RINADI: */
.skip-link:focus {
left: 8px;
top: 8px;
width: auto;
height: auto;
padding: 12px 20px;
background: #fff;
color: #1e293b;
font-size: 14px;
outline: 2px solid #2563eb;
}
3. .screen-reader-text β ko'zga yashirin, skrinriderga ko'rinadi¶
Ba'zan matn ekranda kerak emas (dizayn ikona orqali aniq), lekin skrinrider uchun zarur. Masalan qidiruv tugmasi faqat lupa ikonasi bo'lsa, ko'rmaydigan foydalanuvchi nima qilishini bilmaydi. .screen-reader-text klassi matnni vizual yashiradi, lekin skrinrider o'qiydi:
<button type="submit" class="search-submit">
<span class="screen-reader-text">Qidirish</span>
<svg aria-hidden="true"><!-- lupa ikonasi --></svg>
</button>
WordPress'ning standart CSS sinfi (Twenty Twenty-* temalardan olingan, keng qabul qilingan):
.screen-reader-text {
border: 0;
clip-path: inset(50%);
height: 1px;
width: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
position: absolute !important;
white-space: nowrap;
}
.screen-reader-text:focus {
clip-path: none;
height: auto;
width: auto;
display: block;
top: 5px;
left: 5px;
padding: 15px 23px;
background: #fff;
z-index: 100000;
}
display: noneISHLATMANG.display: noneyokivisibility: hiddenmatnni skrinriderdan ham yashiradi β bu a11y maqsadiga ziddir. Yuqoridagiclip-path+position:absoluteusuli matnni faqat ko'zdan yashiradi.
4. ARIA atributlari¶
ARIA (Accessible Rich Internet Applications) β HTML semantikasini to'ldiruvchi atributlar. Asosiy qoida: semantik HTML birinchi, ARIA β faqat zarurat bo'lganda. Eng ko'p ishlatiladiganlari:
aria-label="..."β element uchun ko'rinmaydigan nom (masalan<nav aria-label="Asosiy menyu">).aria-current="page"β joriy sahifa havolasini belgilaydi (menyuda).aria-hidden="true"β dekorativ elementni (ikona) skrinriderdan yashiradi.role="..."β element rolini bildiradi (zamonaviy HTML5 da ko'pincha shart emas, masalan<nav>o'zirole="navigation").
<?php
// Joriy menyu elementini belgilash misoli:
$current = is_front_page() ? ' aria-current="page"' : '';
printf(
'<a href="%s"%s>%s</a>',
esc_url( home_url( '/' ) ),
$current, // faqat ' aria-current="page"' yoki '' β xavfsiz
esc_html__( 'Bosh sahifa', 'mytheme' )
);
wp_nav_menu(11-bob) joriy element uchuncurrent-menu-itemklassini avtomatik qo'shadi; ARIA uchun esa zamonaviy WParia-current="page"ni navigation blokida o'zi qo'yadi.
5. Klaviatura navigatsiya va fokus ko'rinishi¶
Sichqonchasiz foydalanuvchi Tab bilan element ketma-ket o'tadi. Har bir interaktiv element (havola, tugma, input) fokusda ko'rinadigan bo'lishi shart. Eng katta xato β outline: none bilan fokus konturini o'chirish:
/* XATO β klaviatura foydalanuvchisini "ko'r" qiladi: */
a:focus, button:focus { outline: none; }
/* TO'G'RI β aniq, ko'rinadigan fokus: */
a:focus-visible,
button:focus-visible {
outline: 2px solid #2563eb;
outline-offset: 2px;
}
:focus-visible β zamonaviy selektor: u faqat klaviatura bilan fokuslanganda konturni ko'rsatadi, sichqoncha bosilganda esa ko'rsatmaydi (dizaynni buzmaydi). Tab tartibi tabiiy (HTML tartibi) bo'lsin β tabindex ning musbat qiymatlaridan (tabindex="1") qoching.
6. Rang kontrast (WCAG AA)¶
Matn va fon orasidagi kontrast yetarli bo'lmasa, kam ko'radigan foydalanuvchi o'qiy olmaydi. WCAG AA standarti:
- Oddiy matn: kamida 4.5:1;
- Yirik matn (24px+ yoki 18.66px+ qalin): kamida 3:1;
- UI elementlari va grafik chegaralar: kamida 3:1.
/* Yaxshi: to'q matn, ochiq fon β ~16:1 */
body { color: #1e293b; background: #ffffff; }
/* Yomon: ochiq kulrang matn oq fonda β ~2:1, o'qib bo'lmaydi */
.muted { color: #cbd5e1; background: #ffffff; }
Qo'shimcha qoida: rang yolg'iz axborot tashuvchi bo'lmasin. Masalan formada xatoni faqat qizil rang bilan ko'rsatmang β matn yoki ikona ham qo'shing (rang ko'rishida farqi borlar uchun).
7. Sahifa sarlavhasi β wp_get_document_title¶
Brauzer tab sarlavhasi (<title>) skrinrider foydalanuvchi sahifani aniqlashining birinchi vositasi. Klassik temada uni qo'lda yozmang β add_theme_support( 'title-tag' ) (9-bob) qo'shsangiz, WordPress <title> ni avtomatik va to'g'ri (sahifa nomi + sayt nomi) chiqaradi.
WordPress ichkarida wp_get_document_title() funksiyasidan foydalanadi (jonli WP 7.0 da mavjudligi tasdiqlangan). Kerak bo'lsa, uni document_title_parts filtri bilan moslashtirish mumkin. Block temada <title> to'liq avtomatik β qo'shimcha kod shart emas.
Hammasini birlashtirish: i18n + a11y header¶
Quyida bir faylda ikkala mavzu birga (klassik tema header.php fragmenti):
<?php
/**
* Header β i18n va a11y bilan.
*/
?>
<!DOCTYPE html>
<html <?php language_attributes(); ?>>
<head>
<meta charset="<?php bloginfo( 'charset' ); ?>">
<meta name="viewport" content="width=device-width, initial-scale=1">
<?php wp_head(); ?>
</head>
<body <?php body_class(); ?>>
<?php wp_body_open(); ?>
<a class="skip-link screen-reader-text" href="#primary">
<?php esc_html_e( 'Asosiy kontentga o\'tish', 'mytheme' ); ?>
</a>
<header class="site-header">
<div class="site-branding">
<?php if ( is_front_page() ) : ?>
<h1 class="site-title"><?php bloginfo( 'name' ); ?></h1>
<?php else : ?>
<p class="site-title">
<a href="<?php echo esc_url( home_url( '/' ) ); ?>">
<?php bloginfo( 'name' ); ?>
</a>
</p>
<?php endif; ?>
</div>
<nav class="main-navigation"
aria-label="<?php esc_attr_e( 'Asosiy menyu', 'mytheme' ); ?>">
<?php
wp_nav_menu( array(
'theme_location' => 'primary',
'container' => false,
) );
?>
</nav>
</header>
language_attributes() <html lang="uz"> ni avtomatik chiqaradi β bu skrinriderga sahifa tilini bildiradi (a11y uchun muhim) va body_class() (6-bob) yordamchi sinflar beradi.
Tez-tez uchraydigan xatolar¶
| Xato | To'g'risi |
|---|---|
Matn qotirilgan: echo 'Batafsil'; |
echo esc_html__( 'Batafsil', 'mytheme' ); |
Text domain o'zgaruvchi: __( $t, $d ) |
Literal: __( 'Matn', 'mytheme' ) |
| Har joyda har xil domen | Doim bitta = tema slug |
String birlashtirish: __('Salom ').$ism |
sprintf( __('Salom %s'), $ism ) |
Tarjima escape qilinmagan: _e() HTML chiqishda |
esc_html_e() |
outline: none |
:focus-visible { outline: 2px solid ... } |
Yashirish uchun display:none |
.screen-reader-text (clip-path) |
| Ikonali tugmada matn yo'q | <span class="screen-reader-text"> qo'shish |
Past kontrast (#cbd5e1 oqda) |
Kamida 4.5:1 (#475569 yoki to'qroq) |
<div> lar to'plami |
<header>, <main>, <nav>, <article> |
Mashqlar¶
AMALIY tema-masalalari. Kod yozadigan mashqlar uchun php -l bilan sintaksis tekshiring (i18n PHP) yoki CSS/HTML to'g'riligini ko'zdan kechiring.
Oson¶
- Matnni i18n ga o'rang. Quyidagi qatorni tarjimaga tayyorlang va chiqishda escape qiling:
echo 'Ko\'proq o\'qish';. Text domenmytheme. _evs__. Tugma matnini shablonda echo qiladigan i18n funksiyasi bilan yozing:<button>...</button>ichida "Yuborish" matni,esc_html_eishlatib.- Skip-link qo'shing.
header.phpning<body>dan keyingi birinchi elementi sifatida#primaryga olib boruvchi skip-link<a>yozing (sinflar:skip-link screen-reader-text, matn i18n bilan). aria-labelqo'shing. Quyidagi navigatsiyaga skrinrider uchun nom bering:<nav class="footer-nav"> ... </nav>. Nom "Pastki menyu",esc_attr_ebilan.
O'rta¶
- Ko'plik bilan izoh soni. Postdagi izohlar sonini ko'rsating:
$nta izoh bo'lsa,_n()bilan birlik/ko'plik shaklini tanlab,%splaceholder vanumber_format_i18norqali sonni qo'ying. Chiqishniesc_htmlqiling. - Kontekstli tarjima. "Post" so'zini ikki o'rinda kontekst bilan tarjima qiling: blog maqolasi turi ("maqola turi" konteksti) va "joylash" tugmasi ("tugma" konteksti).
esc_html_xishlating. - sprintf bilan muallif satri. Quyidagi qatorni placeholder li i18n ga o'tkazing:
echo $author . ' tomonidan ' . $date;. Raqamli placeholder (%1$s,%2$s) vatranslators:izohi bilan. .screen-reader-textCSS. Ikonali qidiruv tugmasi uchun ko'zga ko'rinmaydigan, lekin skrinrider o'qiydigan "Qidirish" matnini joylashtiring (HTML + kerakli CSS sinfi).display:noneISHLATMANG.
Qiyin¶
load_theme_textdomainsozlash.functions.phpdaafter_setup_themehookida tarjimanilanguages/papkasidan yuklaydigan kodni yozing. Text domenmytheme.php -lbilan tekshiring.- Fokus ko'rinishini tuzating. Quyidagi xato CSS ni tuzating, klaviatura foydalanuvchisi uchun ko'rinadigan, sichqoncha uchun ko'rinmaydigan fokus bering:
a:focus, button:focus { outline: none; }. - i18n + a11y header bo'lagi. Semantik HTML5
header.phpboshini yozing:language_attributes(),wp_head(),wp_body_open(), skip-link,<header>+aria-labelli<nav>. Sayt nomi bosh sahifada<h1>, boshqa sahifalarda havolali<p>.php -l. wp i18n make-potquvuri. Tushuntiring (qadam-baqadam buyruqlar bilan): temadagi matnlardan POT yaratish, uniuztili uchun.poga tarjima qilib,.moga kompilyatsiya qilish. Fayl nomlarini to'g'ri ko'rsating.- Ko'plikni keyinroq ishlatish.
_n_noop()bilan "%s ta mahsulot" ko'pligini e'lon qiling, so'ngtranslate_nooped_plural()bilan$count = 7uchun chiqaring (number_format_i18n+esc_html). - Kontrast auditi. Quyidagi CSS ni WCAG AA ga moslang va nima uchun ekanini yozing:
.note { color: #9ca3af; background: #f8fafc; font-size: 14px; }(kulrang oq-och fonda β kontrast yetmaydi).
Yechimlar¶
Yechim β 1
Matn __() ga o'raldi (tarjimaga tayyor) va esc_html bilan birga β chiqishda xavfsiz (27-bob qoidasi). Apostrof \' bilan ekran qilingan. php -l: No syntax errors detected.
Yechim β 2
esc_html_e β tarjima qiladi va echo qiladi va escape qiladi (uchchalasi birga). Oxiridagi e = echo. Shablon ichida <?php ... ?> orasida ishlatildi.
Yechim β 3
<a class="skip-link screen-reader-text" href="#primary">
<?php esc_html_e( 'Asosiy kontentga o\'tish', 'mytheme' ); ?>
</a>
Bu element <body> dan keyingi birinchi fokuslanadigan element bo'lishi kerak, shunda Tab bosilganda u birinchi chiqadi. href="#primary" <main id="primary"> ga sakraydi. .screen-reader-text uni ko'zdan yashiradi, :focus da CSS uni ko'rsatadi.
Yechim β 4
<nav class="footer-nav" aria-label="<?php esc_attr_e( 'Pastki menyu', 'mytheme' ); ?>">
<?php // menyu ?>
</nav>
aria-label atribut qiymati bo'lgani uchun esc_attr_e (esc_html emas) ishlatildi. Bir nechta <nav> bo'lsa, har biriga noyob aria-label berish skrinriderga ularni farqlash imkonini beradi.
Yechim β 5
<?php
$n = (int) get_comments_number();
printf(
/* translators: %s: izohlar soni */
esc_html( _n( '%s ta izoh', '%s ta izoh', $n, 'mytheme' ) ),
number_format_i18n( $n )
);
_n() $n ga qarab shakl tanlaydi, %s ni printf qo'yadi, number_format_i18n sonni tilga mos formatlaydi, esc_html chiqishni xavfsiz qiladi. (Jonli WP 7.0 da _n shu tartibda ishlashi tasdiqlangan.) php -l: toza.
Yechim β 6
<?php
echo esc_html_x( 'Post', 'maqola turi', 'mytheme' ); // -> "Maqola" (ot)
echo esc_html_x( 'Post', 'tugma', 'mytheme' ); // -> "Joylash" (fe'l)
Asl matn ('Post') bir xil, lekin kontekst farqli β POT/PO faylda ikki alohida msgctxt yozuvi bo'ladi va tarjimon har birini boshqacha tarjima qila oladi. esc_html_x = _x + esc_html.
Yechim β 7
<?php
printf(
/* translators: 1: muallif ismi, 2: nashr sanasi */
esc_html__( '%1$s tomonidan %2$s da', 'mytheme' ),
esc_html( $author ),
esc_html( $date )
);
Raqamli placeholder (%1$s, %2$s) tarjimonga o'rinlarni almashtirish imkonini beradi (boshqa tilda so'z tartibi boshqacha bo'lishi mumkin). translators: izohi __() dan darhol oldin β make-pot uni POT ga qo'shadi. php -l: toza.
Yechim β 8
<button type="submit" class="search-submit">
<span class="screen-reader-text">Qidirish</span>
<svg aria-hidden="true" focusable="false" width="20" height="20">
<!-- lupa ikonasi -->
</svg>
</button>
.screen-reader-text {
border: 0;
clip-path: inset(50%);
height: 1px;
width: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
position: absolute !important;
white-space: nowrap;
}
<span class="screen-reader-text"> matni ko'zga ko'rinmaydi (clip-path), lekin skrinrider o'qiydi. SVG ikona aria-hidden="true" bilan skrinriderdan yashirilgan (chunki u dekorativ, ma'no <span> da). display:none ishlatilmadi β u matnni skrinriderdan ham yashiradi.
Yechim β 9
<?php
add_action( 'after_setup_theme', function () {
load_theme_textdomain(
'mytheme',
get_template_directory() . '/languages'
);
} );
after_setup_theme β tema sozlash uchun to'g'ri hook (9-bob). get_template_directory() parent tema yo'lini beradi (child temada ham parent tarjimasi shu yerda). WordPress.org katalogidan o'rnatilgan temalar uchun bu avtomatik bo'ladi, lekin chaqirib qo'yish zarar qilmaydi. php -l: No syntax errors detected.
Yechim β 10
/* Avval (xato): a:focus, button:focus { outline: none; } */
a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible {
outline: 2px solid #2563eb;
outline-offset: 2px;
}
outline: none klaviatura foydalanuvchisini "ko'r" qiladi β u qayerdaligini bilmaydi. :focus-visible zamonaviy yechim: faqat klaviatura fokusida konturni ko'rsatadi, sichqoncha bosishida ko'rsatmaydi (shuning uchun dizaynni ham buzmaydi). outline-offset konturni elementdan biroz uzoqlashtiradi.
Yechim β 11
<?php
/**
* header.php boshi β i18n + a11y.
*/
?>
<!DOCTYPE html>
<html <?php language_attributes(); ?>>
<head>
<meta charset="<?php bloginfo( 'charset' ); ?>">
<meta name="viewport" content="width=device-width, initial-scale=1">
<?php wp_head(); ?>
</head>
<body <?php body_class(); ?>>
<?php wp_body_open(); ?>
<a class="skip-link screen-reader-text" href="#primary">
<?php esc_html_e( 'Asosiy kontentga o\'tish', 'mytheme' ); ?>
</a>
<header class="site-header">
<?php if ( is_front_page() ) : ?>
<h1 class="site-title"><?php bloginfo( 'name' ); ?></h1>
<?php else : ?>
<p class="site-title">
<a href="<?php echo esc_url( home_url( '/' ) ); ?>">
<?php bloginfo( 'name' ); ?>
</a>
</p>
<?php endif; ?>
<nav class="main-navigation"
aria-label="<?php esc_attr_e( 'Asosiy menyu', 'mytheme' ); ?>">
<?php wp_nav_menu( array( 'theme_location' => 'primary' ) ); ?>
</nav>
</header>
language_attributes() <html lang="..."> beradi (a11y: til). wp_head()/wp_body_open() majburiy (8-bob). Skip-link birinchi fokus elementi. Bosh sahifada <h1>, ichki sahifalarda havolali <p> (har sahifada bitta <h1> qoidasi β ichki sahifada <h1> postning sarlavhasi bo'ladi). <nav> ga aria-label. php -l: No syntax errors detected.
Yechim β 12
Uch qadam:
1. POT (shablon) yaratish β tema papkasidan barcha matnlarni skanerlaydi:
2. Tarjima (.po) β POT dan nusxa olib, uz tiliga to'ldiriladi. Fayl nomi {domain}-{locale}:
msgstr "" ni to'ldiradi:
3. .mo ga kompilyatsiya β WordPress o'qiydigan binar format:
languages/mytheme-uz.mo. WordPress sayt tili uz bo'lganda load_theme_textdomain orqali shuni yuklaydi.
(Jonli WP 7.0 da make-pot -> Success: POT file successfully generated, make-mo -> Success: Created 1 file ekanligi tasdiqlangan.)
Yechim β 13
<?php
// E'lon (son hali noma'lum):
$products_plural = _n_noop( '%s ta mahsulot', '%s ta mahsulot', 'mytheme' );
// Keyinroq, son ma'lum bo'lganda:
$count = 7;
printf(
esc_html( translate_nooped_plural( $products_plural, $count, 'mytheme' ) ),
number_format_i18n( $count )
);
_n_noop() ko'plik matnini "ro'yxatga oladi" (lekin tarjima qilmaydi) β uni massivda yoki konfiguratsiyada saqlash uchun qulay. translate_nooped_plural() son ma'lum bo'lganda haqiqiy tarjima/shaklni qaytaradi. (Jonli WP 7.0 da _n_noop + translate_nooped_plural zanjiri ishlashi tasdiqlangan.) php -l: toza.
Yechim β 14
/* Avval (xato): .note { color: #9ca3af; background: #f8fafc; ... }
#9ca3af oqimsi #f8fafc fonda taxminan 2.5:1 β WCAG AA (4.5:1) dan past.
Oddiy matn (14px) bu kontrastda kam ko'radigan foydalanuvchiga o'qilmaydi. */
.note {
color: #475569; /* to'q kulrang: #f8fafc fonda ~7:1 β AA dan o'tadi */
background: #f8fafc;
font-size: 14px;
}
Tuzatish: matn rangini yetarlicha to'q qildik (#475569). Oddiy matn uchun WCAG AA kamida 4.5:1 talab qiladi; #475569 ochiq fonda ~7:1 beradi (AAA ga ham yaqin). Qo'shimcha qoida: kontrastni rangli matnda emas, asosan yorqinlik (luminance) farqida ta'minlang β rang ko'rishida farqi bor foydalanuvchilar uchun.
β¬ οΈ Oldingi: 27 β Xavfsizlik: escaping, sanitization, nonce Β· π README Β· Keyingi: 29 β Performans va tarqatish β‘οΈ