LocaleMiddleware位置错误导致语言不切换,须确保SessionMiddleware在前、CommonMiddleware在后且USE_I18N=True;makemessages需用BCP 47格式语言码(如zh-hans),模板须{% load i18n %}并用{% translate %}或gettext_lazy。

LocaleMiddleware 位置错误导致语言不切换
页面始终显示默认语言(比如英文),不是字符串没标,而是 LocaleMiddleware 根本没生效。它不自己猜语言,只按 request.session → request.COOKIES → Accept-Language 头顺序读取,但前提是 session 和 URL 解析必须已就位。
必须满足三个硬性条件:
-
SessionMiddleware必须在LocaleMiddleware之前——否则request.session是空的,无法读用户上次选的语言 -
CommonMiddleware必须在LocaleMiddleware之后——否则 URL 解析提前终止,中间件链被截断,request.LANGUAGE_CODE压根不会被设 -
USE_I18N = True必须显式写在settings.py中(Django 4.0+ 默认为True,但老项目常被手动关掉)
正确中间件顺序示例:['django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.locale.LocaleMiddleware', 'django.middleware.common.CommonMiddleware']
makemessages -l zh-hans 报错或生成空 .po 文件
最常见报错是 CommandError: Unknown language code "zh_Hans"——Django i18n 层只认 BCP 47 格式:小写字母 + 连字符,比如 zh-hans、en-us,不接受下划线、大写或 zh_CN。
立即学习“Python免费学习笔记(深入)”;
实操要点:
- 查合法语言码:运行
python manage.py makemessages --list,输出里列出的才是可用值 -
LOCALE_PATHS必须指向locale的父目录,例如[BASE_DIR / 'locale'],不是[BASE_DIR / 'locale' / 'zh-hans'] - 必须手动创建
locale/目录(Django 不自动建) - 模板中必须先
{% load i18n %},再用{% translate "Login" %};直接写{{ _('Login') }}不会被提取
模型字段、表单、序列化器里的字符串不翻译
这些地方的字符串(如 verbose_name、help_text、error_messages)在模块加载时就执行一次。用普通 _() 会立刻求值并固化为启动时的 LANGUAGE_CODE,后续请求完全不变。
必须改用 gettext_lazy:
- 导入写法:
from django.utils.translation import gettext_lazy as _ - 模型字段示例:
name = models.CharField(verbose_name=_('姓名')) - 禁止拼接:
_('Hello') + _('World')是错的;应写成_("Hello World")或带插值的_("Hello {name}").format(name=_('World')) - 别在模块顶层或
__init__.py里直接调用_(),除非你明确要静态翻译
模板中 {% translate %} 不生效或提取不到字符串
模板里的字面量必须显式标记,且加载方式有严格限制。
关键点:
- 每份模板顶部必须有
{% load i18n %},缺一行都不行 - 推荐用
{% translate "Login" %}或{% blocktrans %}Hello {{ name }}{% endblocktrans %};{{ _('Login') }}不会被makemessages扫描到 -
{% blocktrans %}中的变量名不能是复杂表达式,比如{{ user.get_full_name }}要先赋值给简单变量再传入 - 改完
.po文件后,必须运行python manage.py compilemessages,否则新翻译不会加载
最容易被忽略的是:所有静态定义处的字符串(模型、表单、admin、序列化器)都必须用 gettext_lazy,而不仅仅是视图或模板;漏掉一个字段,整个页面就可能局部“失语”。


















