4

假设我有一个提供一些翻译的应用程序:

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 得到相同的值。

我的浏览器是否配置错误?

4

0 回答 0