i18n failed in Chinese locale

发现 Django i18n 的一个中文支持的 bug

如果你的浏览器的 locale 只设置了 zh-cn 的话识别中文应该是没问题的,但是如果有多个 locale,僻如我一次设置了 zh-cn, en-us, de-de,那么中文就不可能被识别出来了。

要了解这个问题,我们先看下这段代码,在 trans_real.py 里面。
主要看一个名为 get_language_from_request 的函数。
从里面打开可以看到程序的基本流程。

  1. 检测 session 中有没有设置过 django_language,如果支持这个语言,那么就返回语言代码
  2. 检测 cookies 里面有没有 django_language,如果支持这个语言,那么就返回语言代码
  3. 最后就是要从 HTTP 头中的 ACCEPT-LANGUAGE 中分析语言。就是在这一步的时候,对中文的支持就存在 bug 了。
  4. 如果都无法识别,那么从返回默认的 settings.LANGUAGE_CODE

为什么会出现多个 locale 无法识别中文的情况呢?我们来看下面的关于分析 ACCEPT_LANGUAGE 的代码:

for lang, unused in parse_accept_lang_header(accept):
    if lang == '*':
        break

    # We have a very restricted form for our language files (no encoding
    # specifier, since they all must be UTF-8 and only one possible
    # language each time. So we avoid the overhead of gettext.find() and
    # look up the MO file manually.

    normalized = locale.locale_alias.get(to_locale(lang, True))
    # 这一步会将浏览器的 locale 字符串标准化,僻如 zh-cn -> zh_CN.gb2312
    if not normalized:
        continue

    # Remove the default encoding from locale_alias
    normalized = normalized.split('.')[0]
    # 这里就把上面的的 zh_CN.gb2312 变成 zh_CN
    if normalized in _accepted:
        # We've seen this locale before and have an MO file for it, so no
        # need to check again.
        return _accepted[normalized]

    for lang in (normalized, normalized.split('_')[0]):
        # 这一步让 lang 成为 (zh_CN, zh),进而匹配 supported 这个支持的语言集合。
        # 这是出错的关键,因为无论 zh 还是 zh_CN 都是无法匹配到的。
        # 在 supported 里面只支持 zh-cn 和 zh-tw,对于 zh 和 zh_CN 是无法匹配的。
        if lang not in supported:
            continue
        langfile = os.path.join(globalpath, lang, 'LC_MESSAGES',
                'django.mo')
        if os.path.exists(langfile):
            _accepted[normalized] = lang
        return lang
return settings.LANGUAGE_CODE

Leave a comment

Please be polite and on topic. Your e-mail will never be published.