假设我有一个提供一些翻译的应用程序:
AVAILABLE_LOCALES = ['en_US', 'en_EN', 'de_AT']
我想根据Accept-Language
标题选择最合适的。
使用 request.accept_languages.best_match
为了获得语言环境,我会写这样的东西:
@babel.localeselector
def get_locale():
user = getattr(g, 'user', None)
if user is not None:
return user.locale
return request.accept_languages.best_match(AVAILABLE_LOCALES)
问题是,如果用户代理要求de_DE
,匹配失败并且选择回退到默认值(英语),而我de_AT
显然更愿意得到 。
注意:文档页面中的示例读取
return request.accept_languages.best_match(['de', 'fr', 'en'])
但这不允许同一语言的两个不同版本(en_EN
, en_US
)。
使用协商语言环境
在这个GitHub issue中,有人建议使用 Babel 的negotiate_locale
功能:
@babel.localeselector
def get_locale():
user = getattr(g, 'user', None)
if user is not None:
return user.locale
preferred = [x.replace('-', '_') for x in request.accept_languages.values()]
return negotiate_locale(preferred, AVAILABLE_LOCALES)
但是 AFAIU,这并不能解决所有用例。仅当用户代理询问['de_AT', 'de']
可用区域设置时的情况['en_US', 'en_EN', 'de_DE']
。但不是反过来:
negotiate_locale(['de_AT', 'de'], ['en_US', 'en_EN', 'de_DE']) # returns de_DE
negotiate_locale(['de_DE', 'de'], ['en_US', 'en_EN', 'de_AT']) # returns None
第一个有效,因为硬编码的别名列表de
指向de_DE
.
此外,浏览器只发送de_AT
而不发送的情况也de
被破坏了,但我不确定这是一个常见的配置(见下一段)。
有没有可靠的方法来解决这个问题?
现代浏览器中的典型值?
作为一个子问题,我想知道我可以从现代浏览器中获得什么样的价值。
假设现代浏览器是否安全,除非用户自定义错误,否则会像这样发送Accept-Language
[lang+territory, lang] 形式的?
['en-US', 'en']
另外,我尝试了我的 Firefox 版本来看看我会得到什么,这有点令人惊讶。
我系统上的语言环境是法语:
locale
LANG=fr_FR.UTF-8
LANGUAGE=
LC_CTYPE="fr_FR.UTF-8"
LC_NUMERIC="fr_FR.UTF-8"
LC_TIME="fr_FR.UTF-8"
LC_COLLATE="fr_FR.UTF-8"
LC_MONETARY="fr_FR.UTF-8"
LC_MESSAGES="fr_FR.UTF-8"
LC_PAPER="fr_FR.UTF-8"
LC_NAME="fr_FR.UTF-8"
LC_ADDRESS="fr_FR.UTF-8"
LC_TELEPHONE="fr_FR.UTF-8"
LC_MEASUREMENT="fr_FR.UTF-8"
LC_IDENTIFICATION="fr_FR.UTF-8"
LC_ALL=
该about:config
页面说:
general.useragent.locale: en-US
intl.accept_languages: fr, fr-fr, en-us, en
当我连接到我的测试 Flask 应用程序时,我得到
print(request.accept_languages.values())
# ['en_US', 'en']
因此建议@babel.localeselector
将返回英语语言环境。
我使用 Chromium 得到相同的值。
我的浏览器是否配置错误?