2016-08-29 30 views
14

Dla jakiegoś czasu używam coś takiego dostać kraj mojego użytkownika (ISO-3166):Pierwsze regionu użytkownika z navigator.language

const region = navigator.language.split('-')[1]; // 'US' 

Zawsze Zakłada łańcuch byłby podobny do en-US - gdzie kraj posiadałby 2. pozycję tablicy.

Myślę, że to założenie jest nieprawidłowe. According to MDN docs, navigator.language zwraca: "ciąg reprezentujący wersję językową zdefiniowaną w BCP 47."Reading BCP 47, podtęga języka podstawowego jest gwarantowana jako pierwsza (np. "En"), ale kod regionu nie jest gwarantowany jako drugi podtag. Mogą istnieć podtypy poprzedzające i podążające za podzakresem regionu.

Na przykład "sr-Latn-RS" jest poprawnym BCP 47 język tag:

sr    | Latn   | RS 
primary language | script subtag | region subtag 

Czy wartość zwracana z navigator.language podzbiór BCP 47 zawierające tylko język i region? Czy istnieje biblioteka lub wyrażenie regularne, które jest powszechnie używane do wyodrębniania podznacznika regionu ze znacznika języka?

Odpowiedz

0

Regex znaleźć tutaj: https://github.com/gagle/node-bcp47/blob/master/lib/index.js

var re = /^(?:(en-GB-oed|i-ami|i-bnn|i-default|i-enochian|i-hak|i-klingon|i-lux|i-mingo|i-navajo|i-pwn|i-tao|i-tay|i-tsu|sgn-BE-FR|sgn-BE-NL|sgn-CH-DE)|(art-lojban|cel-gaulish|no-bok|no-nyn|zh-guoyu|zh-hakka|zh-min|zh-min-nan|zh-xiang))$|^((?:[a-z]{2,3}(?:(?:-[a-z]{3}){1,3})?)|[a-z]{4}|[a-z]{5,8})(?:-([a-z]{4}))?(?:-([a-z]{2}|\d{3}))?((?:-(?:[\da-z]{5,8}|\d[\da-z]{3}))*)?((?:-[\da-wy-z](?:-[\da-z]{2,8})+)*)?(-x(?:-[\da-z]{1,8})+)?$|^(x(?:-[\da-z]{1,8})+)$/i; 

let foo = re.exec('de-AT');  // German in Austria 
let bar = re.exec('zh-Hans-CN'); // Simplified Chinese using Simplified script in mainland China 

console.log(`region ${foo[5]}`); // 'region AT' 
console.log(`region ${bar[5]}`); // 'region CN' 
+0

dlaczego Regex, kiedy można po prostu użyć podziału jak poniżej: const parts = navigator.language.split ('-'); const region = parts [parts.length-1] –

+0

region nie może mieć drugiej pozycji tablicy po podzieleniu. Zobacz powyższy przykład. – Jeff

+0

To prawda. ale powyżej kodu, zawsze biorąc ostatni, niezależnie od jego aktualnej pozycji. prawda? –

2

Twoje rozwiązanie opiera się na fałszywym założeniu, że znacznik językowy przeglądarki jest niezawodnie zgodny z krajem użytkownika. Np. Ustawiłem język przeglądarki na język niemiecki, mimo że obecnie nie mieszkam w pobliżu Niemiec, ale raczej w Stanach Zjednoczonych.

Również na przykład w Chrome wiele pakietów językowych nie wymaga określenia modyfikatora regionu. Ustawianie języka wyświetlacza Chrome do Niemiecki

enter image description here

zapewnia następujące tag język:

> navigator.language 
< "de" 

No tag regionu w ogóle, i to dość powszechny język.

Podsumowując, moja konfiguracja przeglądarki skutkuje tagiem językowym de, mimo że mieszkam w Stanach Zjednoczonych.


Bardziej dokładnym i prawdopodobnie niezawodnym sposobem określenia lokalizacji użytkownika byłoby wyprowadzenie go z adresu IP powiązanego z żądaniem. Istnieje wiele usług, które oferują tę usługę. ip-api.com jest jednym z nich:

$.get("http://ip-api.com/json", function(response) { 
 
    console.log(response.country);  // "United States" 
 
    console.log(response.countryCode); // "US" 
 
}, "jsonp");
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

+0

interesujące. Dla mojej aplikacji 100% wsparcia nie jest warunkiem wstępnym wysyłki. Wszystko, co muszę zrobić, to uzyskać najlepszy wynik w regionie użytkownika. Jednak w twoim przykładzie wydaje mi się, że Twój język i region są zdezorientowane. "de" jest podznacznikiem języka, a nie podzakresem regionu. Język do regionu nie jest jeden do jednego. Na przykład "de-AT" oznacza niemiecki ("de"), ponieważ jest używany w Austrii ("AT"). Być może najlepiej jest użyć kombinacji API: Geolocation, navigator.languages ​​i jakiegoś reszty punktu końcowego. Dziękuję za wkład, ale nie sądzę, że to precyzyjnie odpowiada na moje pytanie. – Jeff

0

W Firefoksie, można wybrać ustawienia języka w preferencjach:

enter image description here

Lista języków ma 269 elementów, 192 z które nie zawierają żadnego kodu regionu.

Region jest przydatny tylko wtedy, gdy język ma różne warianty w zależności od lokalizacji.W ten sposób użytkownicy mogą poinformować serwer, w którym wariancie językowym preferują odpowiedź.

Nie należy stosować tego podejścia w celu zlokalizowania użytkownika. Jest zbyt niewiarygodny, ponieważ użytkownik nie może określić żadnego regionu lub może fizycznie znajdować się w innym miejscu.

Jeśli chcesz zlokalizować użytkownika, powinieneś użyć Geolocation API.

+0

Zobacz mój komentarz w odpowiedzi TimoSta: Język! = Region, a nie 1-1. To, co mnie interesuje, to region użytkownika, a nie język. – Jeff

+0

@Jeff Tak. To, co możesz uzyskać dzięki "navigator.language", to region, w którym wypowiadany jest preferowany język użytkownika. To nie jest region, w którym znajduje się użytkownik, który można uzyskać za pomocą interfejsu API geolokacji. – Oriol

+0

Potrzebuję zgody użytkownika na pobranie lokalizacji, prawda? Wygląda na to, że kompleksowe rozwiązanie wymagałoby użycia wielu z nich i/lub umożliwienia użytkownikowi wybrania regionu. Ale tak naprawdę zastanawiałem się, czy istnieje dobry sposób na sparsowanie tagów języka BCP 47, aby wyodrębnić region, jeśli taki jest. Myślę, że była to dość powszechna potrzeba. – Jeff

0

Wartość otrzymujesz wynika z Accept-Language nagłówku żądania HTTP.

Wartości nagłówka może być dość skomplikowane jak

Accept-Language: da, en-GB;q=0.8, en;q=0.7 

Jak sama nazwa wskazuje, nagłówek Accept-Language w zasadzie definiuje dopuszczalne języków, a nie krajów.

Znacznik języka może zawierać również dodatkowe informacje o lokalizacji, np. "En-GB", ale inne, np. "En", nie.

Jeśli tak nie jest, nie ma informacji o tym kraju.

Nie zawsze można dokładnie zamapować język taki jak "en" na kraj. Jeśli językiem jest "en", kraj może oznaczać "GB", ale może również oznaczać "USA".

Co możesz zrobić;

  • Ustal kraj tylko, jeśli język zawiera jeden, jak w „en-GB”
  • Jeśli język nie zawiera kraj masz następujące opcje:
  • Kilka języki są używane tylko w jednym kraju, jak "da", duński, który jest używany tylko w Danii (zgaduję tutaj), więc możesz mapować te przypadki.
  • Możesz użyć wartości domyślnej dla innych przypadków, w zależności od języka, np. map 'en' na 'GB'
  • Możesz używać ogólnych ustawień domyślnych takich jak "USA" dla wszystkich przypadków, w których nie można określić kraju.
  • Możesz użyć dodatkowych informacji, np. adres IP klientów, aby określić kraj
  • Wreszcie może poprosić użytkownika o wjazd do kraju

Zebrałem kilka dodatkowych informacji o nagłówku Accept-Language here