Flask-Babel 使用 Accept-Language 标头选择正确的语言环境

Jér*_*ôme 6 python localization flask flask-babel

假设我有一个应用程序,其中有一些可用的翻译:

\n
AVAILABLE_LOCALES = [\'en_US\', \'en_EN\', \'de_AT\']\n
Run Code Online (Sandbox Code Playgroud)\n

我想根据Accept-Language标题选择最合适的。

\n

\xc2\xa0使用 request.accept_languages.best_match

\n

为了获取语言环境,我会写这样的内容:

\n
@babel.localeselector\ndef get_locale():\n    user = getattr(g, \'user\', None)\n    if user is not None:\n        return user.locale\n    return request.accept_languages.best_match(AVAILABLE_LOCALES)\n
Run Code Online (Sandbox Code Playgroud)\n

问题是,如果用户代理要求de_DE,则匹配失败并且选择会退回到默认值(英语),而de_AT显然我宁愿得到 。

\n

注意:文档页面中的示例如下

\n
return request.accept_languages.best_match([\'de\', \'fr\', \'en\'])\n
Run Code Online (Sandbox Code Playgroud)\n

但这不允许同一语言有两个不同版本(en_ENen_US)。

\n

使用negotiate_locale

\n

在这个GitHub 问题中,有人建议使用 Babel 的negotiate_locale函数:

\n
@babel.localeselector\ndef get_locale():\n    user = getattr(g, \'user\', None)\n    if user is not None:\n        return user.locale\n    preferred = [x.replace(\'-\', \'_\') for x in request.accept_languages.values()]\n    return negotiate_locale(preferred, AVAILABLE_LOCALES)\n
Run Code Online (Sandbox Code Playgroud)\n

但是 AFAIU,这并不能解决所有用例。仅当用户代理询问可用[\'de_AT\', \'de\']区域设置时[\'en_US\', \'en_EN\', \'de_DE\']。但反之则不然:

\n
negotiate_locale([\'de_AT\', \'de\'], [\'en_US\', \'en_EN\', \'de_DE\'])  #\xc2\xa0returns de_DE\nnegotiate_locale([\'de_DE\', \'de\'], [\'en_US\', \'en_EN\', \'de_AT\'])  #\xc2\xa0returns None\n
Run Code Online (Sandbox Code Playgroud)\n

第一个之所以有效,是因为硬编码的别名列表指向.dede_DE

\n

de_AT另外,浏览器只发送而不发送的情况也de被破坏,但我不确定这是一个常见的配置(请参阅下一段)。

\n

有没有可靠的方法来处理这个问题?

\n

\xc2\xa0现代浏览器中的典型值?

\n

作为一个子问题,我想知道我可以从现代浏览器中获得什么样的值。

\n

Accept-Language假设现代浏览器(除非用户错误定制)会发送[lang+territory, lang] 这样的形式,是否安全?

\n
[\'en-US\', \'en\']\n
Run Code Online (Sandbox Code Playgroud)\n

另外,我尝试了我的 Firefox 版本,看看会得到什么,结果有点令人惊讶。

\n

我的系统上的区域设置是法语:

\n
locale\nLANG=fr_FR.UTF-8\nLANGUAGE=\nLC_CTYPE="fr_FR.UTF-8"\nLC_NUMERIC="fr_FR.UTF-8"\nLC_TIME="fr_FR.UTF-8"\nLC_COLLATE="fr_FR.UTF-8"\nLC_MONETARY="fr_FR.UTF-8"\nLC_MESSAGES="fr_FR.UTF-8"\nLC_PAPER="fr_FR.UTF-8"\nLC_NAME="fr_FR.UTF-8"\nLC_ADDRESS="fr_FR.UTF-8"\nLC_TELEPHONE="fr_FR.UTF-8"\nLC_MEASUREMENT="fr_FR.UTF-8"\nLC_IDENTIFICATION="fr_FR.UTF-8"\nLC_ALL=\n
Run Code Online (Sandbox Code Playgroud)\n

about:config页面说:

\n
general.useragent.locale: en-US\nintl.accept_languages: fr, fr-fr, en-us, en\n
Run Code Online (Sandbox Code Playgroud)\n

当我连接到我的测试 Flask 应用程序时,我得到

\n
print(request.accept_languages.values())\n# [\'en_US\', \'en\']\n
Run Code Online (Sandbox Code Playgroud)\n

因此建议@babel.localeselector将返回英语语言环境。

\n

我使用 Chromium 得到相同的值。

\n

我的浏览器配置错误吗?

\n