如何在浏览器中确定用户的语言环境?

330
我有一个本地化成十几种语言的网站(Flash),我想根据用户的浏览器设置自动定义一个默认值,以便最大限度地减少访问内容的步骤。
请注意,由于代理限制,我无法使用服务器脚本,所以我想JavaScript或ActionScript可能是解决这个问题的合适方法。
问题:
1. “猜测”用户的区域设置的最佳方法是什么? 2. 是否有任何现有的简单类/函数可以帮助我(不使用复杂的本地化包)?特别是以一种聪明的方式将所有可能的语言缩减为较少的数量(我已经有了翻译)。 3. 我能够对这样的解决方案有多大的信任? 4. 是否有其他解决方法或建议?

浏览器唯一能够分享其用户和请求的元数据的方法是通过URL和头文件。获取Firefox并查看在进行请求时发送的标头。检查典型的请求和响应标头非常有趣。 - mP.
10个回答

267

正确的方法是查看发送到服务器的HTTP Accept-Language 标头。这个标头包含了用户在浏览器中配置的偏好语言的有序、加权列表。

不幸的是,JavaScript 中无法读取此标头。您只能使用navigator.language,该属性告诉您安装的本地化版本的 Web 浏览器。这并不一定是用户首选的语言。在 IE 上,您可以获取systemLanguage(操作系统安装的语言)、browserLanguage(与language相同)和userLanguage(用户配置的操作系统区域),它们都没有什么帮助。

如果我必须在这些属性之间进行选择,我会首先检测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 vs http​://www.example.com/de/site),并让用户在两者之间点击链接。有时候你确实需要一个单一的URL来支持两种语言版本,在这种情况下,你必须将设置存储在cookie中,但这可能会使不支持cookie和搜索引擎的用户代理产生困惑。


21
来自 MDN https://developer.mozilla.org/en-US/docs/Web/API/NavigatorLanguage/languages 的内容: "用户浏览器中每个 HTTP 请求中 Accept-Language HTTP 头使用与 navigator.languages 属性相同的值,除了额外的 qvalues(质量值)字段(例如,en-US;q= 0.8)以外。" - S Meaden
28
更新:现在(2020年)所有现代浏览器都支持一项实验性功能,可以返回语言偏好的数组:navigator.languages //["en-US", "zh-CN", "ja-JP"] 这应该在2020年至少适用于95%的浏览器。 - Cornelius Roemer
8
根据MDN和caniuse.com,navigator.languages现在可在所有主要浏览器中使用。如果需要最现代化且向后兼容的方法,请尝试使用体积小(约200字节)的navigator-languages包。 - mindplay.dk
天啊,为什么被接受的答案如此不准确?你们为什么不读文档呢?https://developer.mozilla.org/en-US/docs/Web/API/Navigator/language 你不需要在服务器上读取头信息,因为它与navigator.languages相同,而navigator.language是数组的第一个元素。顺便说一下,在大多数浏览器中,navigator.language早在很久以前就得到了支持。 - bora89
8
@bora89 因为被接受的答案是在2009年,也就是13年前。你知道,在那么长的时间跨度内,实现和文档往往会发生变化... - Byebye

160
在 Chrome 和 Firefox 32+ 中,Navigator.languages 包含一个以用户偏好顺序排列的区域设置数组,并且比 navigator.language 更准确,然而为了实现向后兼容性(已测试在 Chrome / IE / Firefox / Safari 上),请使用以下代码:
function getLang() {
  if (navigator.languages != undefined) 
    return navigator.languages[0]; 
  return navigator.language;
}

3
这在IE9和IE10上不起作用。对于它们,你必须检查navigator.browserLanguage。 - Matt Sgarlata
3
函数 getLang() 的作用是获取用户的浏览器语言设置,如果浏览器支持多种语言,则返回第一种语言。具体实现是通过获取 navigator.language 或者 navigator.languages[0] 来实现的。 - JorgeGarza
4
应该是return navigator.languages[0] || navigator.language;吗? - James_
35
另外,正确的“一行代码”应该是这样的:return (navigator.languages && navigator.languages.length) ? navigator.languages[0] : navigator.language;。否则,如果navigator.languages未定义或为空,将会抛出异常。 - Max Truxa
3
更加紧凑的版本如下: const getLang = () => (navigator.language || navigator.browserLanguage || (navigator.languages || ["en"])[0]); - João Miguel Brandão
显示剩余3条评论

57

这篇文章提出了以下浏览器navigator对象的属性:

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

将它们合并成一个JavaScript函数,你应该能够在大多数情况下猜到正确的语言。一定要优雅地降级,因此请使用包含语言选择链接的div,以便如果没有JavaScript或方法不起作用,则用户仍然可以进行选择。如果它确实起作用,请隐藏div。

在客户端执行此操作的唯一问题是,您必须为客户端提供所有语言,或者等待脚本运行并检测到语言后再请求正确的版本。也许默认提供最受欢迎的语言版本会使最少的人感到烦恼。

编辑:我赞同Ivan的cookie建议,但请确保用户始终可以稍后更改语言;不是每个人都喜欢浏览器默认的语言。


谢谢Phil的建议。关于这篇文章,它已经写了6年了...不确定我们是否能够依赖它? - Theo.T
1
我怀疑现代浏览器都支持navigator.language。我的浏览器(Ubuntu 8.10上的FF3)报告为'en-GB'。如果有人仍在使用IE6 - 大约20%的人 - 那么值得考虑。IE6出现已经8年了。 - Phil H
IE 8不支持navigator.language。也许IE 9会支持? - spig

52
结合浏览器用于存储用户语言的多种方式,您可以得到这个函数:
const getNavigatorLanguage = () => {
  if (navigator.languages && navigator.languages.length) {
    return navigator.languages[0];
  } else {
    return navigator.userLanguage || navigator.language || navigator.browserLanguage || 'en';
  }
}

我们首先检查 navigator.languages 数组的第一个元素。 然后我们获取 navigator.userLanguage 或者 navigator.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' - Emeric
由于navigator.languages可能是undefined,所以会出现这种情况。 - Zenoo
@Zenoo 你知道在哪些浏览器上可以使用吗? - Emeric
2
(navigator.languages || [])[0] || navigator.userLanguage || navigator.language || navigator.browserLanguage || 'en' - Steve Bennett

49

用户的首选语言和系统/浏览器区域设置之间有所不同。

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

然而,浏览器区域设置将决定如何呈现数字、日期、时间和货币。该设置可能是最高级别的语言,但不能保证。在 Mac 和 Linux 上,无论用户语言偏好如何,区域设置都由系统决定。在 Windows 上,可以在 Chrome 中从首选列表中选择语言。

通过使用 Intl (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl),开发人员可以覆盖/设置要用于呈现这些元素的区域设置,但有些元素无法被覆盖,例如 <input type="date"> 格式。

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

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

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

这将为默认区域设置创建一个新的 NumberFormat 实例,然后读取这些已解决选项的区域设置。


3
非常重要的答案需要添加到图片中。例如,在我的Chromium中,navigator.language返回de-DE(这是我的系统设置),但所有日期和数字都以en-US格式显示(这是我的浏览器设置),这个答案正确地确定了这一点。 - Philzen
是的,我也想感谢你对这个答案的回复。一眼看过去,问题似乎是“如何在浏览器中确定用户的区域设置”,而答案都是“这是如何找到用户首选语言的方法,希望对你有所帮助”。非常感谢。 - undefined

25

我使用了所有的答案,创建了一种单行解决方案:

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

console.log(getLanguage());

这到底是什么意思?这是什么想法?为什么会选择这样组合,而不是其他方式?背后的思考是什么? - undefined

7

我对此进行了一些调查,目前我已经在下表中总结了我的发现

enter image description here

因此,建议的解决方案是编写一个服务器端脚本来解析 Accept-Language 标头并将其传递给客户端以设置网站的语言。虽然让服务器检测客户端的语言偏好可能看起来有些奇怪,但就目前而言,这是必需的。还有其他各种方法可用于检测语言,但根据我的理解,阅读 Accept-Language 标头是推荐的解决方案。


那是无法阅读的。在单独的标签页中打开它只是稍微好一点点。 - undefined

3

你可以尝试从文档中获取语言,这可能是你的首选,然后再退而求其次,因为通常人们希望他们的JS语言与文档语言相匹配。

HTML5:

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

旧版:

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

没有真正可靠的来源,因为人们可能会简单地输入错误的语言。

有一些语言检测库可以根据内容帮助你确定语言。


1

将此从JavaScript检测浏览器语言偏好移植过来

https://dev59.com/j3NA5IYBdhLWcg3wPLL-#42649975

我刚想出这个。它结合了更新的JS解构语法和一些标准操作来检索语言和区域设置。

var [lang, locale] = (
    (
        (
            navigator.userLanguage || navigator.language
        ).replace(
            '-', '_'
        )
    ).toLowerCase()
).split('_');

希望对某些人有所帮助

**更新:** 我还建议测试并结合其他答案,例如https://dev59.com/CHRB5IYBdhLWcg3wSVYI#52112155,这似乎是获取语言更健壮的方式。我们还有空值合并运算符??,因此||可能不是最好的方法。我想象这会像这样

var [lang, locale] = (
    (
        getBrowserLanguage()
            .replace('-', '_')
    ).toLowerCase()
).split('_');

请注意,我没有强制规定lang或locale的默认值,这是您可以做的。世界是如此以英语为中心,我会选择英语,但我觉得编码不会对任何人有益。我也没有将getBrowserLanguage称为getNavigatorLanguage,这是故意的。也许您使用navigator,但未来可能会出现其他情况。这确实是一种偏好。无论如何,我希望这仍然有用。

-1

3
Flash现在已经死亡。 - Liam

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接