使用navigator.language获取用户的区域

Jef*_*eff 17 javascript locale iso-3166 ietf-bcp-47

有一段时间,我一直在使用这样的东西来获取用户的国家(ISO-3166):

const region = navigator.language.split('-')[1]; // 'US'
Run Code Online (Sandbox Code Playgroud)

我总是假设字符串类似于en-US- 国家将保持数组的第二个位置.

我认为这个假设是不正确的.根据MDN文档,navigator.language返回:"表示BCP 47中定义的语言版本的字符串." 读取BCP 47,主要语言子标签保证是第一个(例如,'en'),但区域代码不保证是第二个子标签.区域子标签之前和之后可以有子标签.

例如"sr-Latn-RS",有效的BCP 47语言标记:

sr                |  Latn           |  RS
primary language  |  script subtag  |  region subtag
Run Code Online (Sandbox Code Playgroud)

navigator.languageBCP 47的子集返回的值是否仅包含语言和区域?或者是否存在通常用于从语言标记中提取区域子标签的库或正则表达式?

Tim*_*imo 6

您的解决方案基于错误的前提,即浏览器的语言标记可靠地匹配用户的国家/地区.例如,我已经将我的浏览器语言设置为德语,尽管我现在远在德国附近,而是在美国.

此外,例如在Chrome中,许多语言包不需要您指定区域修改器.将Chrome的显示语言设置为德语

在此输入图像描述

提供以下语言标记:

> navigator.language
< "de"
Run Code Online (Sandbox Code Playgroud)

根本没有区域标签,也是一种相当常见的语言.

最重要的是,de即使我住在美国,我的浏览器设置也会产生语言标记.


确定用户位置的更准确且可能可靠的方法是从与请求相关联的IP地址导出它.有许多服务提供此服务.ip-api.com就是其中之一:

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


Wil*_* S. 5

现在,您可以使用国际化 API 中的Locale对象从区域设置标识符中提取区域。

const { region } = new Intl.Locale('sr-Latn-RS') // region => 'RS'
Run Code Online (Sandbox Code Playgroud)

请注意,这当前与 Internet Explorer 不兼容。


Jef*_*eff 2

正则表达式在这里找到: 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'
Run Code Online (Sandbox Code Playgroud)