在浏览器中确定用户语言环境的最佳方法


202

我的网站(Flash)本地化为十几种语言,我想根据用户的浏览器设置自动定义默认值,以最大程度地减少访问内容的步骤。

仅供参考,由于代理限制,我无法使用服务器脚本,因此我认为JavaScript或ActionScript将适合解决此问题。

问题:

  1. “猜测”用户区域设置的最佳方法是什么?

  2. 是否有现有的简单类/函数可以帮助我(没有复杂的本地化软件包)?特别是以一种聪明的方式将所有可能的语言分解成较小的数量(我拥有的翻译版本)。

  3. 我可以信任这种解决方案的那一点?

  4. 还有其他解决方法或建议吗?


这是浏览器可以共享有关其用户的元数据的唯一方法,并且请求是通过URL和标头进行的。抓住Firefox,看看发出请求时发送的标头。检查典型的请求和响应头很有趣。
mP。

Answers:


188

正确的方法是查看发送到服务器的HTTP Accept-Language标头。它包含用户已配置其浏览器首选的语言的排序后的加权语言列表。

不幸的是,此标头不可用于在JavaScript内部读取;您所获得的是navigator.language,它告诉您安装了什么本地化版本的Web浏览器。这不一定与用户的首选语言相同。相反,在IE上,您会获得systemLanguage(与OS browserLanguage相同的安装语言),(与相同language)和userLanguage(用户配置的OS区域),它们都无济于事。

如果我必须在这些属性之间进行选择,那么我会先嗅userLanguage一下,language然后回头再看(如果那些与任何可用的语言都不匹配),browserLanguage然后再看systemLanguage

如果您可以将服务器端脚本放在网上的其他位置,则只需读取Accept-Language标头并将其作为包含标头值的字符串的JavaScript文件发回,例如:

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

那么您可以在HTML中包含指向该外部服务的<script src>,并使用JavaScript解析语言标头。不过,我不知道有任何现有的库代码可以执行此操作,因为Accept-Language解析几乎总是在服务器端完成的。

无论最终做什么,您肯定都需要用户覆盖,因为对于某些人来说,它总是会猜错。通常,最简单的方法是将语言设置放在URL中(例如,http://www.example.com/en/site与http://www.example.com/de/site),然后让用户点击两者之间的联系。有时您确实希望为两种语言版本提供一个URL,在这种情况下,您必须将设置存储在cookie中,但这可能会使用户代理混淆,而它们不支持cookie和搜索引擎。


11
从MDN developer.mozilla.org/en-US/docs/Web/API/NavigatorLanguage/... “接受语言HTTP标头从用户的浏览器的每个HTTP请求使用的navigator.languages属性的值相同,除了额外的qvalues(质量值)字段(例如en-US; q = 0.8)。”
S Meaden

3
更新:现在(2020),所有现代浏览器都支持一项实验性功能,该功能可返回一系列语言偏好设置:navigator.languages //["en-US", "zh-CN", "ja-JP"]2020
Cornelius Roemer

1
navigator.languages根据MDNcaniuse.com的说法,现在所有主要浏览器都可用-尝试使用最小的(约200字节)导航器语言包,以获得最现代且向后兼容的方法。
mindplay.dk

84

在Chrome和Firefox 32+上,navigator.languages按用户喜好顺序包含一个区域设置,并且比navigator.language更准确,但是要使其向后兼容(经过测试的Chrome / IE / Firefox / Safari),然后使用这个:

function getLang()
{
 if (navigator.languages != undefined) 
 return navigator.languages[0]; 
 else 
 return navigator.language;
}

2
这不适用于IE9和IE10。对于他们,您必须改为检查navigator.browserLanguage。
user393274 '16

2
OneLiner:function getLang(){ return ( navigator.language || navigator.languages[0] ); }
JorgeGarza '16

4
@ChStark不是return navigator.languages[0] || navigator.language;吗?
James_

23
此外,正确的 “单线”应如下所示:return (navigator.languages && navigator.languages.length) ? navigator.languages[0] : navigator.language;。否则,如果navigator.languagesundefined或为空,则会得到异常。
Max Truxa

为了更紧凑的版本const getLang = () => navigator.language || navigator.browserLanguage || ( navigator.languages || [ "en" ] ) [ 0 ]
若昂·米格尔·布兰

41

本文建议浏览器的导航器对象的以下属性:

  • navigator.language (Netscape-浏览器本地化)
  • navigator.browserLanguage(特定于IE的浏览器本地化语言)
  • navigator.systemLanguage (特定于IE的-Windows OS-本地化的语言)
  • navigator.userLanguage

将它们放入javascript函数中,在大多数情况下,您应该能够猜出正确的语言。确保降级幅度适中,因此要使div包含您的语言选择链接,这样,如果没有javascript或该方法无效,则用户仍然可以决定。如果确实有效,则只需隐藏div。

在客户端执行此操作的唯一问题是,要么为客户端提供所有语言,要么必须等待脚本运行并检测到语言,然后才能请求正确的版本。也许将最受欢迎的语言版本作为默认设置会激怒最少的人。

编辑:我第二次提出了伊凡(Ivan)的cookie建议,但要确保用户以后始终可以更改语言;并非每个人都喜欢他们的浏览器默认使用的语言。


感谢Phil的建议。关于这篇文章,它已经有6年历史了……不确定我们可以依靠它吗?
Theo.T,2009年

1
我怀疑现代浏览器都支持navigator.language。我的浏览器(在Ubuntu 8.10上为FF3)报告为“ en-GB”。如果有人仍在使用IE6(大约20%的人),那么值得考虑。IE6出现在8年前。
Phil H

IE 8不支持navigator.language。也许IE 9会?
spig 2011年

36

结合浏览器用来存储用户语言的多种方式,可以得到以下功能:

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

我们首先检查navigator.languages数组的第一个元素。
然后我们得到navigator.userLanguagenavigator.language
如果失败,我们得到navigator.browserLanguage
最后,我们将其设置为'en'其他所有操作均失败。


这是性感的一线客:

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

显然还有navigator.userLanguage(对于IE)。您可以添加它以使其完成:)
pors

为什么不简单navigator.languages[0] || navigator.userLanguage || navigator.language || navigator.browserLanguage || 'en'
Emerica

@Curse因为navigator.languages可以undefined
Zenoo

@Zenoo您知道在哪些浏览器上吗?
Emerica

(navigator.languages || [])[0] || navigator.userLanguage || navigator.language || navigator.browserLanguage || 'en'
史蒂夫·贝内特

10

用户的首选语言和系统/浏览器语言环境之间存在差异。

用户可以在浏览器中配置首选语言,这些语言将用于navigator.language(s)和从服务器请求资源时根据语言优先级列表来请求内容。

但是,浏览器的语言环境将决定如何呈现数字,日期,时间和货币。此设置可能是排名最高的语言,但不能保证。在Mac和Linux上,语言环境由系统决定,与用户语言首选项无关。在Windows上,可以选择Chrome首选列表中的语言。

通过使用Intl(https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Intl),开发人员可以覆盖/设置语言环境以呈现这些内容,但是有些元素可以不能覆盖,例如<input type="date">格式。

为了正确提取这种语言,我发现的唯一方法是:

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

Intl.NumberFormat().resolvedOptions().locale似乎也可以)

这将为默认语言环境创建一个新的NumberFormat实例,然后读回那些解析的选项的语言环境。


5

我对此进行了一些研究,并在下表中总结了到目前为止的发现。

在此处输入图片说明

因此,推荐的解决方案是编写一个服务器端脚本来解析Accept-Language标头,并将其传递给客户端以设置网站的语言。奇怪的是,为什么需要服务器来检测客户端的语言首选项,但是到目前为止就是这样。还有其他各种可用来检测语言的技巧,但是Accept-Language根据我的理解,阅读标头是推荐的解决方案。


2

您还可以尝试从文档中获取语言,这可能是您的第一个联系方式,然后回退到其他方式,因为人们通常希望他们的JS语言与文档语言相匹配。

HTML5:

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

遗产:

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

没有真正的来源一定是100%可靠的,因为人们可以简单地使用错误的语言。

有些语言检测库可能会让您根据内容确定语言。


1

我使用了所有答案并创建了一个单行解决方案:

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

console.log(getLanguage());

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.