Получение региона пользователя с помощью navigator.language
Некоторое время я использовал что-то вроде этого, чтобы получить страну моего пользователя (ISO-3166):
const region = navigator.language.split('-')[1]; // 'US'
Я всегда предполагал, что строка будет похожа на en-US
- где страна будет занимать 2-ю позицию массива.
Я думаю, что это предположение неверно. Согласно документам MDN, navigator.language
возвращает: "строка, представляющая языковую версию, как определено в BCP 47". При чтении BCP 47 первичный языковой подтэг гарантированно будет первым (например, 'en'), но код региона не обязательно будет вторым подтэгом. Могут быть подтэги, которые предшествуют и следуют за подтэгом региона.
Например "sr-Latn-RS"
является действительным языковым тегом BCP 47:
sr | Latn | RS
primary language | script subtag | region subtag
Возвращено ли значение из navigator.language
подмножество BCP 47, содержащее только язык и регион? Или есть библиотека или регулярное выражение, которые обычно используются для извлечения subtag региона из языкового тега?
7 ответов
Regex находится здесь: 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'
Ваше решение основано на ложной предпосылке, что языковой тег браузера надежно соответствует стране пользователя. Например, я установил в браузере немецкий язык, хотя сейчас я живу далеко не в Германии, а в Соединенных Штатах.
Также, например, в Chrome, во многих языковых пакетах не требуется указывать модификатор региона. Настройка языка отображения Chrome на немецкий
предоставляет следующий языковой тег:
> navigator.language
< "de"
Нет тега региона, и довольно распространенный язык.
Суть в том, что моя настройка браузера приводит к языковому тегу de
хотя я живу в Соединенных Штатах.
Более точным и, возможно, надежным способом определения местоположения пользователя будет получение его из IP-адреса, связанного с запросом. Есть множество услуг, которые предлагают эту услугу. http://id-api.com/ является одним из них:
$.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>
Теперь вы можете извлечь регион из идентификатора локали, используя объект Locale в API интернационализации.
const { region } = new Intl.Locale('sr-Latn-RS') // region => 'RS'
Обратите внимание, что в настоящее время это несовместимо с Internet Explorer.
Будьте осторожны у вас есть navigator.language
а также navigator.languages
,
язык:
console.log(navigator.language); // "fr"
Языки:
console.log(navigator.languages); // ["fr", "fr-FR", "en-US", "en"]
Чтобы найти страны, смотрите Википедию по ISO 3166-1 или используйте javascript lib:
В Firefox вы можете выбрать настройки языка в настройках:
Список языков насчитывает 269 пунктов, 192 из которых не содержат код региона.
Регион полезен только тогда, когда язык имеет разные варианты в зависимости от местоположения. Таким образом, пользователи могут указать серверу, в каком языковом варианте они предпочитают ответ.
Не используйте этот подход, чтобы найти пользователя. Это слишком ненадежно, потому что пользователь не может указать какой-либо регион, или потому что пользователь мог физически находиться в другом месте.
Если вы хотите найти пользователя, вам следует использовать Geolocation API.
Как сказал @TimoSta,
Попробуй это
$.getJSON('http://freegeoip.net/json/', function(result) {
alert(result.country_code);
});
Получите от посетителей язык и код страны с помощью JavaScript (на стороне клиента). Смотрите ответ @noducks
Значение, которое вы получаете, связано с заголовком Accept-Language HTTP-запроса.
Значения заголовка могут быть довольно сложными, как
Accept-Language: da, en-GB;q=0.8, en;q=0.7
Как видно из названия, заголовок Accept-Language в основном определяет приемлемые языки, а не страны.
Языковой тег может также содержать дополнительную информацию о местоположении, как в "en-GB", но другие, например "en", этого не делают.
В случае, если нет, просто нет информации о стране.
Также не всегда возможно точно сопоставить язык, например "en", со страной. Если язык "en", страна может быть "GB", но также "US".
Что ты можешь сделать;
- Определите только страну, если она есть в языке, как в "en-GB"
- Если язык не содержит страну, у вас есть следующие варианты:
- Несколько языков используются только в одной стране, например, "да", датский, на котором говорят только в Дании (я думаю, здесь), поэтому вы можете сопоставить эти случаи.
- Вы можете использовать значение по умолчанию для других случаев, в зависимости от языка, например, сопоставить "en" с "GB"
- Вы можете использовать общее значение по умолчанию, например, "США", во всех случаях невозможно определить страну.
- Вы можете использовать дополнительную информацию, например, IP-адрес клиента, чтобы определить страну
- Наконец, вы можете попросить пользователя ввести страну
Я собрал некоторую дополнительную информацию о заголовке Accept-Language здесь