说我有一个提供一些翻译的应用程序:
AVAILABLE_LOCALES = ['en_US', 'en_EN', 'de_AT']
我想根据Accept-Language
标题选择最合适的。
要获取语言环境,我会写这样的内容:
@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
。
注意:doc page中的示例读取
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
第一个有效,因为hardcoded list of aliases使de
指向de_DE
。
此外,浏览器只发送de_AT
而不是de
的情况也会被破坏,但我不确定这是一个常见的配置(参见下一段)。
有没有可靠的方法来解决这个问题?
作为一个子问题,我想知道现代浏览器可以期待什么样的价值。
假设现代浏览器是否安全,除非用户自定义错误,否则会发送{lang + territory,lang]这样的Accept-Language
形式?
['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获得相同的值。
我的浏览器配置错误了吗?