Kryteria sukcesu WCAG · Level A

WCAG 3.1.1: Język strony

WCAG 3.1.1 wymaga, aby domyślny język naturalny każdej strony internetowej mógł zostać określony programowo, głównie poprzez ustawienie prawidłowego atrybutu lang w elemencie HTML. Umożliwia to technologiom asystującym, takim jak czytniki ekranu, poprawne wymawianie treści i pomaga użytkownikom z niepełnosprawnościami poznawczymi oraz związanymi z językiem w zrozumieniu strony.

Co Oznacza Ta Zasada

WCAG 3.1.1 — Język strony to kryterium sukcesu na poziomie A w ramach zasady Zrozumiałość. Wymaga ono, aby podstawowy język naturalny każdej strony internetowej był ujawniony w sposób, który technologie asystujące mogą programowo wykryć. W praktyce prawie zawsze oznacza to umieszczenie prawidłowego atrybutu lang bezpośrednio w elemencie strony <html>.

Wartość atrybutu lang musi być prawidłowym tagiem języka BCP 47. Tagi BCP 47 składają się z podstawowego podtagu języka (takiego jak en dla angielskiego, tr dla tureckiego, fr dla francuskiego) oraz opcjonalnie podtagu regionu oddzielonego łącznikiem (takiego jak en-US, tr-TR lub pt-BR). Tag języka musi dokładnie odzwierciedlać dominujący język, w którym napisana jest treść strony. Strona napisana głównie po turecku musi zadeklarować lang='tr' lub lang='tr-TR'; strona napisana po angielsku musi zadeklarować lang='en' lub wariant regionalny.

Strona spełnia to kryterium, gdy element <html> posiada atrybut lang, którego wartość jest niepustym, składniowo poprawnym tagiem języka BCP 47, który prawidłowo identyfikuje podstawowy język strony. Strona nie spełnia kryterium, gdy atrybut lang jest całkowicie nieobecny, gdy jego wartość jest pusta (lang='') lub gdy wartość nie jest rozpoznawanym tagiem języka BCP 47 (na przykład lang='turkish' lub lang='en_US' z podkreśleniem zamiast łącznika).

Dla stron XHTML serwowanych z typem MIME XML zarówno atrybut lang, jak i atrybut przestrzeni nazw XML xml:lang powinny być obecne, a ich wartości muszą być zgodne. Niezgodność między nimi — taka jak lang='en' wraz z xml:lang='tr' — stanowi naruszenie zarówno tego kryterium, jak i powiązanej reguły axe-core html-xml-lang-mismatch.

WCAG wyraźnie wskazuje jeden wyjątek: jeśli strona jest czysto dekoracyjna, jest CAPTCHA celowo pozbawioną rozpoznawalnego języka lub składa się wyłącznie z treści nielingwistycznych (na przykład strona będąca wyłącznie obrazem bez tekstu), jej język może być niemożliwy do ustalenia. Jednak ten wyjątek jest wąski, a zdecydowana większość stron w rzeczywistych zastosowaniach zawiera wystarczającą ilość tekstu, aby wymagać deklaracji języka.

Dlaczego To Ma Znaczenie

Głównymi beneficjentami prawidłowo zadeklarowanego języka strony są użytkownicy czytników ekranu, z których większość jest niewidoma lub ma poważne wady wzroku. Czytniki ekranu, takie jak NVDA, JAWS i VoiceOver, używają atrybutu lang do wyboru odpowiedniego głosu syntezy mowy (TTS) i silnika wymowy. Gdy użytkownik turecki odwiedza stronę, która prawidłowo deklaruje lang='tr', jego czytnik ekranu przełącza się na turecki głos TTS, stosując poprawną fonologię turecką, akcent i znaki diakrytyczne. Bez tej deklaracji czytnik ekranu może domyślnie użyć języka systemowego użytkownika lub całkowicie niewłaściwego języka, generując bełkotliwą wymowę, która czyni treść niezrozumiałą.

Rozważmy konkretny scenariusz: niedowidzący obywatel Turcji odwiedza stronę internetową instytucji publicznej, aby pobrać formularz urzędowy. Strona pomija atrybut lang. Instalacja NVDA użytkownika domyślnie używa profilu TTS w języku angielskim. Tureckie słowa są odczytywane z użyciem fonologii angielskiej — słowa takie jak „şehir” (miasto) czy „başvuru” (wniosek) stają się nierozpoznawalne. Użytkownik nie może wypełnić formularza bez pomocy osoby widzącej, co niweczy cały cel usługi cyfrowej.

Użytkownicy z niepełnosprawnościami poznawczymi i trudnościami w uczeniu się również odnoszą korzyści. Przeglądarki używają atrybutu lang, aby oferować dokładne propozycje tłumaczenia; niektórzy użytkownicy z dysleksją polegają na narzędziach tłumaczeniowych w przeglądarce, aby konwertować treści na język, który łatwiej im przetwarzać. Nieprawidłowy lub brakujący atrybut lang powoduje, że te narzędzia błędnie identyfikują język źródłowy, generując słabe tłumaczenia lub w ogóle nie proponując tłumaczenia.

Użytkownicy z niepełnosprawnościami ruchowymi, którzy polegają na oprogramowaniu sterowania głosem, takim jak Dragon NaturallySpeaking, są zależni od tego, czy oprogramowanie poprawnie zinterpretuje język strony, aby dopasować wypowiadane komendy do tekstu na ekranie. Błędnie zidentyfikowany język strony uniemożliwia takie dopasowanie.

Poza dostępnością istnieją wymierne korzyści SEO: wyszukiwarki używają atrybutu lang jako jednego z kilku sygnałów do określenia docelowego języka i regionu strony, poprawiając dokładność zlokalizowanych wyników wyszukiwania. Prawidłowe oznaczanie języka poprawia również niezawodność funkcji sprawdzania pisowni i gramatyki w przeglądarce dla wszystkich użytkowników, nie tylko tych korzystających z technologii asystujących. Według Światowej Organizacji Zdrowia około 2,2 miliarda ludzi na świecie ma jakąś formę upośledzenia wzroku, z których znacząca część polega na czytnikach ekranu — co czyni prawidłową deklarację języka jednym z najbardziej efektywnych, a zarazem najmniej pracochłonnych usprawnień dostępności.

Powiązane Reguły Axe-core

  • html-has-lang — Ta reguła sprawdza, czy element <html> w ogóle posiada atrybut lang. Oznacza każdą stronę, na której atrybut lang jest całkowicie nieobecny w głównym znaczniku <html>, niezależnie od tego, czy atrybut pojawia się gdzie indziej w dokumencie. Jest to jedno z najczęstszych i najbardziej wpływowych automatycznych wykryć, ponieważ poprawka polega na dodaniu jednego atrybutu.
  • html-lang-valid — Ta reguła sprawdza, czy wartość atrybutu lang w elemencie <html> jest prawidłowym tagiem języka BCP 47. Oznacza wartości, które nie są rozpoznanymi kodami języków, takie jak lang='turkish' (który używa pełnej angielskiej nazwy zamiast kodu ISO 639-1 tr), lang='en_US' (który używa separatora w postaci podkreślenia zamiast łącznika) lub lang='xx' (wartość zastępcza bez przypisanego języka). Atrybut lang, który istnieje, ale zawiera nieprawidłową wartość, jest równie problematyczny jak brak atrybutu, ponieważ technologie asystujące nie mogą na nim wiarygodnie polegać.
  • html-xml-lang-mismatch — Ta reguła dotyczy konkretnie stron XHTML, które mają zarówno atrybut lang, jak i atrybut xml:lang w elemencie <html>. Oznacza przypadki, w których oba atrybuty określają różne kody języka — na przykład lang='en' i xml:lang='tr'. Gdy wartości te są sprzeczne, technologie asystujące i procesory XML otrzymują sprzeczne sygnały i mogą zachowywać się w nieprzewidywalny sposób. Obie wartości muszą określać ten sam podstawowy podtag języka.

Chociaż te trzy reguły obejmują najczęstsze programowe błędy, narzędzia automatyczne nie mogą zweryfikować poprawności semantycznej — to znaczy nie są w stanie ustalić, czy zadeklarowany język faktycznie odpowiada językowi, w którym napisana jest strona. Strona napisana w całości po turecku, ale deklarująca lang='en', przejdzie wszystkie trzy reguły axe-core, a mimo to nie spełni WCAG 3.1.1, ponieważ zadeklarowany język nie odzwierciedla rzeczywistego podstawowego języka strony. Dlatego zawsze konieczna jest ręczna weryfikacja obok skanowania automatycznego, aby potwierdzić, że zadeklarowany język jest poprawny.

Jak Testować

  1. Automatyczne skanowanie za pomocą axe DevTools lub Lighthouse: Otwórz stronę w Chrome lub Firefox. Otwórz DevTools (F12), przejdź do panelu axe DevTools lub zakładki Lighthouse i uruchom pełny audyt dostępności. Szukaj w szczególności naruszeń w ramach reguł html-has-lang, html-lang-valid i html-xml-lang-mismatch. Axe podświetli element <html> i opisze konkretne naruszenie. Lighthouse wyświetli podobne problemy w swojej kategorii Accessibility. Zanotuj wszystkie oznaczone naruszenia i zalecane poprawki.
  2. Ręczna inspekcja źródła: Wyświetl źródło strony (Ctrl+U w większości przeglądarek) i zlokalizuj otwierający znacznik <html>. Sprawdź, czy zawiera on atrybut lang, czy wartość atrybutu jest prawidłowym tagiem BCP 47 (sprawdź w Rejestrze Podtagów Językowych IANA) oraz czy dokładnie odzwierciedla język, w którym napisana jest treść strony. Dla stron XHTML sprawdź również, czy każdy atrybut xml:lang ma ten sam podstawowy podtag języka co lang.
  3. Testowanie z czytnikiem ekranu NVDA i Firefox: Zainstaluj NVDA (bezpłatny, Windows) i otwórz stronę w Firefox. Naciśnij NVDA+T, aby odczytać tytuł strony i posłuchać używanego głosu TTS. Jeśli strona jest po turecku, głos powinien być tureckim głosem TTS, a tureckie słowa powinny być wymawiane poprawnie. Jeśli słyszysz głos angielski lub inny nieodpowiedni dla treści tureckiej, atrybut lang jest nieobecny lub nieprawidłowy. Powtórz test z JAWS w Chrome i VoiceOver w Safari na macOS (Cmd+F5, aby aktywować VoiceOver, następnie przejdź do strony i posłuchaj, jak wymawiany jest tekst główny).
  4. Sprawdzenie wykrywania języka przez przeglądarkę: Otwórz stronę w Chrome. Poszukaj wbudowanego paska tłumaczenia — Chrome oferuje tłumaczenie stron, które identyfikuje jako obcojęzyczne względem ustawień przeglądarki. Jeśli Chrome błędnie identyfikuje język strony lub nie oferuje tłumaczenia, gdy powinien, jest to praktyczny sygnał, że atrybut lang jest nieprawidłowy lub nieobecny. Nie jest to definitywny test dostępności, ale przydatny wskaźnik pomocniczy.
  5. Sprawdzenie poprawności semantycznej (tylko ręcznie): Przeczytaj treść strony i potwierdź, że zadeklarowana wartość lang odpowiada rzeczywistemu podstawowemu językowi strony. Narzędzia automatyczne nie są w stanie wykonać tego sprawdzenia. Zwróć szczególną uwagę na serwisy wielojęzyczne, które udostępniają różne wersje językowe pod różnymi adresami URL — strona pod każdym adresem URL powinna deklarować swój własny, poprawny język, a nie dziedziczyć jedną globalną wartość domyślną.

Jak Naprawić

Brakujący atrybut lang — Niepoprawne

<!DOCTYPE html>
<html>
  <head>
    <meta charset='UTF-8'>
    <title>Başvuru Formu</title>
  </head>
  <body>
    <h1>Hoş Geldiniz</h1>
  </body>
</html>

Brakujący atrybut lang — Poprawne

<!DOCTYPE html>
<html lang='tr'>
  <!-- lang='tr' informuje czytniki ekranu, aby użyły tureckiego głosu TTS -->
  <head>
    <meta charset='UTF-8'>
    <title>Başvuru Formu</title>
  </head>
  <body>
    <h1>Hoş Geldiniz</h1>
  </body>
</html>

Nieprawidłowa wartość atrybutu lang — Niepoprawne

<!DOCTYPE html>
<html lang='turkish'>
  <!-- 'turkish' nie jest prawidłowym tagiem BCP 47; axe oznaczy html-lang-valid -->
  <head>
    <title>Kurumsal Site</title>
  </head>
  <body>
    <p>Şirketimiz hakkında bilgi edinmek için buraya tıklayın.</p>
  </body>
</html>

Nieprawidłowa wartość atrybutu lang — Poprawne

<!DOCTYPE html>
<html lang='tr'>
  <!-- Użyj dwuliterowego kodu ISO 639-1 'tr', a nie angielskiego słowa 'turkish' -->
  <head>
    <title>Kurumsal Site</title>
  </head>
  <body>
    <p>Şirketimiz hakkında bilgi edinmek için buraya tıklayın.</p>
  </body>
</html>

Niezgodność xml:lang w XHTML — Niepoprawne

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Strict//EN'
  'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd'>
<html xmlns='http://www.w3.org/1999/xhtml' lang='en' xml:lang='tr'>
  <!-- lang i xml:lang są niezgodne — naruszenie html-xml-lang-mismatch -->
  <head><title>XHTML Sayfası</title></head>
  <body><p>İçerik burada.</p></body>
</html>

Niezgodność xml:lang w XHTML — Poprawne

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Strict//EN'
  'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd'>
<html xmlns='http://www.w3.org/1999/xhtml' lang='tr' xml:lang='tr'>
  <!-- Zarówno lang, jak i xml:lang mają wartość 'tr' — spójne i prawidłowe -->
  <head><title>XHTML Sayfası</title></head>
  <body><p>İçerik burada.</p></body>
</html>

Nieprawidłowy język zadeklarowany w serwisie wielojęzycznym — Niepoprawne

<!-- Angielska wersja serwisu, ale lang globalnie ustawione na 'tr' -->
<html lang='tr'>
  <head><title>About Us</title></head>
  <body>
    <p>Welcome to our company. We specialize in accessible web solutions.</p>
  </body>
</html>

Nieprawidłowy język zadeklarowany w serwisie wielojęzycznym — Poprawne

<!-- Każda wersja językowa deklaruje własny, poprawny atrybut lang -->
<html lang='en'>
  <!-- To jest strona angielska; strona turecka pod /tr/ deklaruje lang='tr' -->
  <head><title>About Us</title></head>
  <body>
    <p>Welcome to our company. We specialize in accessible web solutions.</p>
  </body>
</html>

Typowe Błędy

  • Używanie pełnej angielskiej nazwy języka zamiast jego kodu BCP 47 — pisanie lang='turkish', lang='english' lub lang='arabic' zamiast poprawnych kodów tr, en i ar. Wartości te nie są rozpoznawane przez technologie asystujące.
  • Używanie podkreślenia jako separatora regionu — pisanie lang='en_US' lub lang='tr_TR' zamiast form z łącznikiem lang='en-US' i lang='tr-TR'. BCP 47 wymaga łączników, a nie podkreśleń.
  • Ustawianie atrybutu lang w <body> zamiast w <html> — atrybut lang musi znajdować się w głównym elemencie <html>, aby spełnić regułę axe-core html-has-lang i zapewnić technologiom asystującym kontekst języka strony, zanim zaczną parsować treść.
  • Pozostawienie lang jako pustego ciągu — ustawienie lang='' jest traktowane przez większość technologii asystujących tak samo jak brak atrybutu i zostanie oznaczone przez html-has-lang, ponieważ pusty ciąg nie jest prawidłowym tagiem języka.
  • Kopiowanie szablonu z innego projektu językowego bez aktualizacji atrybutu lang — bardzo częsty problem w tureckich procesach deweloperskich, gdy ponownie używany jest anglojęzyczny boilerplate, a lang='en' w znaczniku <html> nigdy nie zostaje zmienione na lang='tr'.
  • Deklarowanie poprawnego atrybutu lang, ale brak jego aktualizacji przy uruchamianiu nowej wersji językowej serwisu — serwisy wielojęzyczne korzystające z renderowania po stronie serwera muszą zapewnić dynamiczne ustawianie atrybutu lang dla każdej lokalizacji, a nie zakodowanie na stałe jednej wartości w współdzielonym szablonie układu.
  • Zakładanie, że CMS lub framework automatycznie poprawnie ustawia atrybut lang — wiele platform CMS (w tym niektóre konfiguracje WordPress, Joomla i niestandardowych frameworków) domyślnie nie ustawia prawidłowego atrybutu lang. Programiści muszą to zweryfikować na poziomie szablonu, a nie zakładać, że jest to obsłużone.
  • Mylenie atrybutu lang (dla HTML) z nagłówkiem HTTP Content-Language — nagłówek HTTP wpływa na buforowanie i negocjację treści, ale nie jest używany przez czytniki ekranu. Wbudowany w dokument atrybut lang w <html> jest właściwym mechanizmem zapewniającym zgodność z WCAG 3.1.1.
  • Używanie poprawnego, ale niewłaściwego podtagu regionalnego, który implikuje inny dialekt — na przykład zadeklarowanie lang='zh-TW' (chiński tradycyjny, Tajwan) na stronie napisanej uproszczonym chińskim (zh-CN) może spowodować, że czytnik ekranu wybierze niewłaściwy profil głosu i zasady wymowy.
  • Zapominanie o ustawieniu lang dla dynamicznie wstrzykiwanej treści pełnostronicowej w aplikacjach jednostronicowych (SPA) — jeśli SPA ładuje treści w wielu językach w ramach tej samej powłoki dokumentu bez aktualizacji atrybutu lang, użytkownicy przechodzący między sekcjami językowymi nie otrzymają poprawnej wymowy TTS dla nowych sekcji treści.

Związek z Tureckimi Regulacjami Dotyczącymi Dostępności

WCAG 3.1.1 Język strony ma bezpośrednie umocowanie prawne w Turcji na mocy Okrężnika Prezydenckiego 2025/10, opublikowanego w Dzienniku Urzędowym nr 32933 w dniu 21 czerwca 2025 r. Okrężnik ten ustanawia obowiązkowe wymagania dotyczące dostępności stron internetowych zgodne z WCAG 2.2 i wyznacza zgodność na poziomie A jako minimalny obowiązkowy standard dla wszystkich objętych podmiotów.

Okrężnik obejmuje szeroki zakres organizacji zarówno sektora publicznego, jak i prywatnego. Instytucje publiczne — w tym ministerstwa, gminy, uniwersytety państwowe, szpitale publiczne oraz wszystkie centralne i lokalne organy administracji — są zobowiązane do osiągnięcia pełnej zgodności na poziomie A w ciągu jednego roku od publikacji okrężnika. Podmioty sektora prywatnego objęte regulacją mają dwuletni okres na dostosowanie i obejmują platformy e-commerce, banki i instytucje finansowe, prywatne szpitale i świadczeniodawców opieki zdrowotnej, operatorów telekomunikacyjnych z 200 000 lub większą liczbą abonentów, biura podróży, prywatne firmy transportowe oraz szkoły prywatne działające na podstawie zezwolenia Ministerstwa Edukacji Narodowej (MoNE).

Ponieważ WCAG 3.1.1 jest kryterium poziomu A, wchodzi w skład obowiązkowej podstawy dla każdego podmiotu objętego okrężnikiem. Strona internetowa tureckiej instytucji publicznej, która pomija lang='tr' w swoim elemencie <html> — lub deklaruje nieprawidłowy bądź nieważny tag języka — pozostaje w bezpośredniej niezgodności z prawnie wymaganym standardem. Dla podmiotów sektora prywatnego, takich jak banki i platformy e-commerce, ten sam błąd w okresie dostosowawczym stanowi naruszenie regulacyjne.

Praktyczne konsekwencje dla tureckich zespołów webowych są znaczące: każdy szablon strony, każdy układ CMS, każda powłoka SPA i każda dynamicznie generowana strona muszą zostać poddane audytowi w celu potwierdzenia obecności prawidłowego lang='tr' (lub odpowiedniego wariantu) w głównym elemencie HTML. Nie jest to jedynie zalecenie dobrych praktyk — na mocy Okrężnika 2025/10 jest to obowiązek prawny. Biorąc pod uwagę, że reguły axe-core html-has-lang i html-lang-valid mogą automatycznie wykryć większość takich błędów, nie istnieje techniczna bariera uniemożliwiająca zidentyfikowanie i usunięcie tego problemu przed upływem terminów zgodności.

Organizacje objęte okrężnikiem powinny traktować zgodność z WCAG 3.1.1 jako zadanie naprawcze najwyższego priorytetu: jest to jedno z najłatwiejszych do poprawienia kryteriów (jeden atrybut w jednym elemencie), a jednocześnie ma nieproporcjonalnie duży wpływ na dostępność każdej strony dla użytkowników czytników ekranu — grupy, której prawa regulacja ta ma w najbardziej bezpośredni sposób chronić.