netcoffee.pl*po godzinach - reaktywacja

Ten blog jest kontynuacją bloga dostępnego ongiś pod adresem netcoffee.pl/pogodzinach.
Artykuły, które na to zasługują są przenoszone do nowej wersji bloga. Pozostałe wkrótce znikną.

2006-01-19

Wykrywanie języka użytkownika

Często pojawia się pytanie, jak - w wielojęzycznych serwisach - ustalić język, w którym powinna pojawić się zawartość strony. Przeszukując Internet można znaleźć kilka rozwiązań:
  • ustalać język na podstawie adresu IP
  • ustalać język na podstawie nazwy domenowej hosta
  • ustalić język użytkownika na podstawie informacji o wersji językowej przeglądarki

Niestety, każda z powyższych metod ma swoje wady: użytkownik może łączyć się przez serwer proxy, więc adres IP nie jest miarodajny, może używać przeglądarki w innej wersji językowej, niż jego język itd. Te wady można by wymieniać, ale nie o to tutaj chodzi.

Najlepszą moim zdaniem metodą wykrycia języka użytkownika, jest ustalenie go na podstawie nagłówków http wysyłanych przez przeglądarkę. Każda nowoczesna przeglądarka pozwala użytkownikowi wybrać w ustawieniach programu preferowane języki. Na wybranie języków pozwala użytkownikowi nawet Internet Explorer. Wybór ten jest następnie wysyłany do serwera w postaci nagłówka Accept-Language.

Zawartość tego nagłówka ma postać listy dwuliterowych kodów języków rozdzielonych znakiem przecinka, np:

pl,en

Kod języka może być także uzupełniony o oznaczenie dialektu:

pl,en-gb

Ten zapis oznacza, że użytkownik zna język polski i angielski (brytyjski), ale preferuje ten pierwszy.

W przypadku podania kilku języków, każdy z nich może być oznaczony dodatkowym parametrem q (quality). Parametr ten oznacza wagę danego języka. q może przyjmować wartości od 0 do 1. 0 oznacza język ignorowany. Waga języka jest zapisywana jako q=xx i oddzielona od kodu języka średnikiem (;):

pl,en;q=0.9,ru;q=0.8

Jeżeli dany język nie posiada wagi, przypisuje mu się domyślnie wagę 1. W powyższym przykładzie wagi języków wynoszą:
  • polski - 1
  • angielski - 0.9
  • rosyjski - 0.8

W PHP zawartość nagłówka Accept-Language jest dostępna w zmiennej $_SERVER['HTTP_ACCEPT_LANGUAGE'].Przy użyciu niezbyt skomplikowanej funkcji można określić język, w którym należy wyświetlić zawartość strony:


function getLanguage($sDefault, $ihSystemLang){
$sLangs = $_SERVER['HTTP_ACCEPT_LANGUAGE'];
preg_match_all(
'!([a-zA-Z]+)(?:-[a-zA-Z]+)?(?: *; *q *= *([01]\.[0-9]+))?!',
$sLangs, $shFound);
foreach($shFound[1] as $i => $sLang){
$iW = (float)$shFound[2][$i];
$ihUserLang[$sLang] = $iW > 0 ? $iW : 1;
}
$iChoiceWeight = 0;
$sChoiceLang = '';
foreach($ihSystemLang as $sLang => $iW){
if(isset($ihUserLang[$sLang])){
$iTmpChoice = $iW * $ihUserLang[$sLang];
if($iTmpChoice > $iChoiceWeight and $iTmpChoice > 0){
$iChoiceWeight = $iTmpChoice;
$sChoiceLang = $sLang;
}
}
}
return $sChoiceLang != '' ? $sChoiceLang : $sDefault;
}


Funkcja przyjmuje dwa parametry: kod domyślnego języka oraz tablicę asocjacyjną dostępnych na stronie języków wraz z ich wagami. Funkcja zwraca kod języka wybranego na podstawie ustawień przeglądarki. W czasie wyznaczania języka, ignorowane jest oznaczenie dialektu (gdyż niepotrzebnie komplikuje wybór).

Jeżeli strona jest dostępna w języku polskim i angielskim oraz posiada częściowe tłumaczenie na język francuski, wywołanie funkcji może przyjąć postać:

$sLang = getLanguage('pl', array('pl' => 1, 'en' => 0.9, 'fr' => 0.4));

Językiem podstawowym serwisu jest polski, dlatego właśnie ten język jest podany jako domyślny (pierwszy parametr funkcji) oraz na liście wag otrzymuje 1. Język angielski otrzymuje wysoką wagę 0.9, natomiast francuski tylko 0.4 (ze względu na to, że tłumaczenie jest tylko częściowe).

Wynik działania funkcji zależy od nagłówka Accept-language. Przykładowe wyniki:

Accept-language: pl,en
wynik: pl
Accept-language: fr,en
wynik: en
Accept-language: fr,en;q=0.3
wynik: fr

W przypadku, gdy w nagłówku nie ma żadnego z języków obsługiwanych przez stronę, funkcja zwróci kod domyślny (podany jako pierwszy parametr).

Na koniec kilka słów wyjaśnienia, dlaczego uważam metodę wyboru języka na podstawie nagłówka Accept-language za najlepszą. Oczywiście, jest ona tak samo zawodna jak te, które wymieniłem wcześniej. W końcu, użytkownik może korzystać z przeglądarki w której domyślnie jest ustawiony język inny niż język, którym posługuje się użytkownik. Może używać komputera w pracy za granicą itd.
Jednak powyższa metoda jest jedyną z wymienionych, w której do wykrycia języka używamy parametru, nad którym użytkownik ma całkowitą kontrolę. Przecież nie zawsze możemy wpływać na adres IP z którego łączymy się z siecią (przebywamy za granicą, używamy serwera proxy itp). Możemy używać ulubionej przeglądarki w wersji językowej innej niż nasz język gdyż nie jest jeszcze dostępne tłumaczenie. Nie zmienimy wersji językowej, ale preferowane języki możemy zmienić!

Oczywiście trudno wymagać od użytkowników aby wybierali język strony poprzez ustawienia przeglądarki - dlatego więc nie należy zapominać o udostępnieniu użytkownikowi możliwości zmiany języka na wypadek, gdyby funkcja dokonała złego wyboru.