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 的函数。
从里面打开可以看到程序的基本流程。
- 检测 session 中有没有设置过 django_language,如果支持这个语言,那么就返回语言代码
- 检测 cookies 里面有没有 django_language,如果支持这个语言,那么就返回语言代码
- 最后就是要从 HTTP 头中的 ACCEPT-LANGUAGE 中分析语言。就是在这一步的时候,对中文的支持就存在 bug 了。
- 如果都无法识别,那么从返回默认的 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