Najlepszy sposób na określenie lokalizacji użytkownika w przeglądarce

202

Mam witrynę internetową (Flash) zlokalizowaną w kilkunastu językach i chcę automatycznie zdefiniować wartość domyślną w zależności od ustawień przeglądarki użytkownika, aby zminimalizować liczbę kroków związanych z dostępem do treści.

Do twojej wiadomości, nie mogę używać skryptów serwera ze względu na ograniczenia proxy, więc chyba JavaScript lub ActionScript byłyby odpowiednie do rozwiązania problemu.

Pytania:

  1. Jaka byłaby najlepsza metoda „odgadnięcia” ustawień regionalnych użytkownika?

  2. Czy istnieją jakieś proste klasy / funkcje, które mogłyby mi pomóc (brak złożonych pakietów lokalizacyjnych)? Specjalnie, aby rozbić wszystkie możliwe języki na mniejszą liczbę (tłumaczenia, które mam) w inteligentny sposób.

  3. Do jakiego momentu mogę ufać takiemu rozwiązaniu?

  4. Wszelkie inne obejścia lub sugestie?

Theo.T
źródło
Jedyny sposób, w jaki przeglądarka może udostępniać metadane dotyczące swojego użytkownika, a żądanie odbywa się za pośrednictwem adresów URL i nagłówków. Chwyć Firefoksa i rzuć okiem na nagłówki wysyłane po złożeniu żądania. Bardzo interesujące jest sprawdzenie typowych nagłówków żądań i odpowiedzi.
mP.

Odpowiedzi:

188

Właściwym sposobem jest sprawdzenie nagłówka HTTP Accept-Language przesłanego do serwera. Zawiera uporządkowaną, ważoną listę języków, które użytkownik skonfigurował w swojej przeglądarce.

Niestety ten nagłówek nie jest dostępny do odczytu w JavaScript; otrzymujesz tylko informację navigator.language, która wersja zlokalizowanej przeglądarki została zainstalowana. Niekoniecznie jest to to samo, co preferowane języki użytkownika. W IE zamiast tego dostajesz systemLanguage(język instalacji systemu operacyjnego), browserLanguage(taki sam jak language) i userLanguage(region systemu operacyjnego skonfigurowany przez użytkownika), które są podobnie nieprzydatne.

Gdybym musiał wybierać między tymi właściwościami, najpierw wąchałem userLanguage, wracając do languagei dopiero potem (jeśli te nie pasowały do ​​żadnego dostępnego języka), patrząc w browserLanguagekońcu systemLanguage.

Jeśli możesz umieścić skrypt po stronie serwera w innym miejscu w sieci, które po prostu odczytuje nagłówek Accept-Language i wyrzuca go z powrotem jako plik JavaScript z wartością nagłówka w ciągu, np .:

var acceptLanguage= 'en-gb,en;q=0.7,de;q=0.3';

wtedy możesz dołączyć <skrypt src> wskazujący na tę zewnętrzną usługę w HTML i użyć JavaScript do parsowania nagłówka języka. Nie znam jednak żadnego istniejącego kodu biblioteki, ponieważ parsowanie Accept-Language jest prawie zawsze wykonywane po stronie serwera.

Cokolwiek zrobisz, na pewno potrzebujesz zastąpienia przez użytkownika, ponieważ dla niektórych osób zawsze będzie to błędne odgadnięcie. Często najłatwiej jest umieścić ustawienie języka w adresie URL (np. Http: //www.example.com/en/site vs. http: //www.example.com/de/site) i pozwolić użytkownikowi kliknąć powiązania między nimi. Czasami potrzebujesz jednego adresu URL dla obu wersji językowych, w takim przypadku musisz zapisać to ustawienie w plikach cookie, ale może to dezorientować agentów użytkownika bez obsługi plików cookie i wyszukiwarek.

Bobin
źródło
11
Od MDN developer.mozilla.org/en-US/docs/Web/API/NavigatorLanguage/… „Nagłówek HTTP Accept-Language w każdym żądaniu HTTP z przeglądarki użytkownika używa tej samej wartości dla właściwości navigator.languages ​​z wyjątkiem dodatkowych pole qvalues ​​(wartości jakości) (np. en-US; q = 0,8). ”
S Meaden
3
Aktualizacja: dostępna jest teraz (2020) funkcja eksperymentalna obsługiwana przez wszystkie nowoczesne przeglądarki, która zwraca szereg preferencji językowych: navigator.languages //["en-US", "zh-CN", "ja-JP"]Powinna działać w co najmniej 95% przeglądarek w 2020 roku.
Cornelius Roemer
1
navigator.languages, zarówno według MDN, jak i caniuse.com , jest teraz dostępny we wszystkich głównych przeglądarkach - wypróbuj mały (~ 200 bajtów) pakiet języków nawigacyjnych , aby uzyskać najnowocześniejsze i kompatybilne wstecz.
mindplay.dk
84

W przeglądarkach Chrome i Firefox 32+ navigator.languages ​​zawiera szereg ustawień narodowych w kolejności preferencji użytkownika i jest bardziej dokładny niż navigator.language, jednak w celu zapewnienia kompatybilności wstecznej (przetestowany Chrome / IE / Firefox / Safari), a następnie użyj to:

function getLang()
{
 if (navigator.languages != undefined) 
 return navigator.languages[0]; 
 else 
 return navigator.language;
}
Fiach Reid
źródło
2
To nie działa dla IE9 i IE10. Dla nich musisz zamiast tego sprawdzić navigator.browserLanguage.
user393274,
2
OneLiner:function getLang(){ return ( navigator.language || navigator.languages[0] ); }
JorgeGarza
4
@ChStark Nie powinno być return navigator.languages[0] || navigator.language;?
James_
23
Również poprawne „one-liner” będzie wyglądać następująco: return (navigator.languages && navigator.languages.length) ? navigator.languages[0] : navigator.language;. W przeciwnym razie otrzymasz wyjątek, jeśli navigator.languagesjest niezdefiniowany lub pusty.
Max Truxa,
Dla jeszcze bardziej kompaktowej wersjiconst getLang = () => navigator.language || navigator.browserLanguage || ( navigator.languages || [ "en" ] ) [ 0 ]
João Miguel Brandão
41

W tym artykule zaproponowano następujące właściwości obiektu nawigatora przeglądarki :

  • navigator.language (Netscape - lokalizacja przeglądarki)
  • navigator.browserLanguage (specyficzny dla IE - język zlokalizowany w przeglądarce)
  • navigator.systemLanguage (Dotyczy tylko IE - Windows OS - język zlokalizowany)
  • navigator.userLanguage

Rzuć je na funkcję javascript, a w większości przypadków powinieneś odgadnąć właściwy język. Pamiętaj, aby degradować z wdziękiem, więc div powinien zawierać linki do wyboru języka, dzięki czemu jeśli nie ma javascript lub metoda nie działa, użytkownik nadal może zdecydować. Jeśli to działa, po prostu ukryj div.

Jedynym problemem związanym z robieniem tego po stronie klienta jest to, że albo podajesz wszystkie języki klientowi, albo musisz poczekać, aż skrypt się uruchomi i wykryje język, zanim poprosi o odpowiednią wersję. Być może podanie domyślnej najpopularniejszej wersji językowej irytowałoby najmniej osób.

Edycja: poparłbym sugestię Ivana dotyczącą plików cookie, ale upewnij się, że użytkownik zawsze może później zmienić język; nie wszyscy preferują język domyślny dla swojej przeglądarki.

Phil H.
źródło
Dzięki Phil za twoje sugestie. Jeśli chodzi o artykuł, ma on 6 lat ... nie jesteś pewien, czy możemy na nim polegać?
Theo.T
1
Podejrzewam, że wszystkie nowoczesne przeglądarki obsługują navigator.language. Moja przeglądarka (FF3 na Ubuntu 8.10) zgłasza „en-GB”. Jeśli ktoś nadal używa IE6 - około 20% osób - warto na to pozwolić. IE6 pojawił się 8 lat temu.
Phil H
IE 8 nie obsługuje navigator.language. Być może będzie to IE 9?
spig
36

Łącząc wiele sposobów, w jakie przeglądarki używają do przechowywania języka użytkownika, otrzymujesz tę funkcję:

const getNavigatorLanguage = () => {
  if (navigator.languages && navigator.languages.length) {
    return navigator.languages[0];
  } else {
    return navigator.userLanguage || navigator.language || navigator.browserLanguage || 'en';
  }
}

Najpierw sprawdzamy navigator.languagestablicę pod kątem pierwszego elementu.
Następnie otrzymujemy albo navigator.userLanguagealbo navigator.language.
Jeśli to się nie powiedzie, otrzymamy navigator.browserLanguage.
Wreszcie ustawiamy na, 'en'jeśli wszystko inne zawiedzie.


A oto seksowny jednowarstwowy:

const getNavigatorLanguage = () => (navigator.languages && navigator.languages.length) ? navigator.languages[0] : navigator.userLanguage || navigator.language || navigator.browserLanguage || 'en';
Zenoo
źródło
najwyraźniej jest też coś takiego jak navigator.userLanguage(dla IE). Możesz to dodać, aby było kompletne :)
pors
Dlaczego nie po prostu navigator.languages[0] || navigator.userLanguage || navigator.language || navigator.browserLanguage || 'en'?
Emerica
@ Curse Bo navigator.languagesmoże byćundefined
Zenoo,
@Zenoo Czy wiesz, w których przeglądarkach?
Emerica,
(navigator.languages || [])[0] || navigator.userLanguage || navigator.language || navigator.browserLanguage || 'en'
Steve Bennett
10

Istnieje różnica między preferowanymi językami użytkownika a ustawieniami systemu / przeglądarki.

Użytkownik może skonfigurować preferowane języki w przeglądarce, które będą używane navigator.language(s)i używane podczas żądania zasobów z serwera w celu żądania treści zgodnie z listą priorytetów językowych.

Jednak ustawienia regionalne przeglądarki decydują o sposobie renderowania liczby, daty, godziny i waluty. To ustawienie jest prawdopodobnie językiem o najwyższym rankingu, ale nie ma gwarancji. W systemach Mac i Linux o lokalizacji decyduje system, niezależnie od preferencji językowych użytkownika. W systemie Windows można wybrać spośród języków z preferowanej listy w Chrome.

Korzystając z Intl ( https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl ), programiści mogą przesłonić / ustawić ustawienia regionalne w celu renderowania tych rzeczy, ale istnieją elementy, które nie można zastąpić, na przykład <input type="date">format.

Aby poprawnie wyodrębnić ten język, jedynym sposobem, jaki znalazłem, jest:

(new Intl.NumberFormat()).resolvedOptions().locale

( Intl.NumberFormat().resolvedOptions().localewydaje się również działać)

Spowoduje to utworzenie nowej instancji NumberFormat dla domyślnych ustawień regionalnych, a następnie odczytanie ustawień regionalnych tych rozwiązanych opcji.

Patrik Kullman - Neovici
źródło
5

Przeprowadziłem trochę badań na ten temat i podsumowałem dotychczasowe ustalenia w poniższej tabeli

wprowadź opis zdjęcia tutaj

Zalecanym rozwiązaniem jest więc napisanie skryptu po stronie serwera, aby przeanalizować Accept-Languagenagłówek i przekazać go klientowi w celu ustawienia języka witryny. To dziwne, dlaczego serwer byłby potrzebny do wykrycia preferencji językowych klienta, ale tak właśnie jest Obecnie dostępne są inne różne hacki do wykrywania języka, ale przeczytanie Accept-Languagenagłówka jest zalecanym rozwiązaniem według mojego zrozumienia.

Abhishek V.
źródło
2

Możesz także spróbować pobrać język z dokumentu, który może być pierwszym portem zawinięcia, a następnie powrócić do innych środków, ponieważ często ludzie będą chcieli, aby język JS był zgodny z językiem dokumentu.

HTML5:

document.querySelector('html').getAttribute('lang')

Dziedzictwo:

document.querySelector('meta[http-equiv=content-language]').getAttribute('content')

Żadne prawdziwe źródło niekoniecznie jest w 100% niezawodne, ponieważ ludzie mogą po prostu pisać w niewłaściwym języku.

Istnieją biblioteki do wykrywania języka, które mogą umożliwić określenie języka według zawartości.

jgmjgm
źródło
1

Użyłem wszystkich odpowiedzi i stworzyłem rozwiązanie jednowierszowe:

const getLanguage = () => navigator.userLanguage || (navigator.languages && navigator.languages.length && navigator.languages[0]) || navigator.language || navigator.browserLanguage || navigator.systemLanguage || 'en';

console.log(getLanguage());
Caio Santos
źródło