LocaleMiddleware未生效是页面不翻译的主因,须置于SessionMiddleware之后、CommonMiddleware之前,且USE_I18N=True必须显式开启;还需检查LOCALE_PATHS路径、执行compilemessages、确保模板正确加载i18n。

USE_I18N=True 但页面不翻译?检查 LocaleMiddleware 位置和依赖项
最常见的情况是:你写了 USE_I18N = True,也用了 gettext_lazy,但页面始终显示英文(或默认语言)。问题大概率出在 LocaleMiddleware 没生效。
它必须满足三个硬性条件:
-
SessionMiddleware必须在它之前——否则 session 为空,无法读取用户保存的语言偏好 -
CommonMiddleware必须在它之后——否则 URL 解析提前终止,中间件链被截断 -
USE_I18N = True必须显式写在settings.py中(Django 4.0+ 默认为True,但老项目或自定义配置常被关掉)
正确顺序示例:
['django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.locale.LocaleMiddleware', 'django.middleware.common.CommonMiddleware']
漏掉任一条件,request.LANGUAGE_CODE 就不会被动态更新,所有 _() 调用都 fallback 到 LANGUAGE_CODE。
立即学习“Python免费学习笔记(深入)”;
makemessages -l zh-hans 报错或生成空 .po 文件?语言码和路径必须严格匹配
报 CommandError: Unknown language code "zh_Hans" 是高频错误。Django i18n 层只认 BCP 47 格式:小写字母 + 连字符,比如 zh-hans、en-us、ja,不接受下划线或大写。
实操要点:
- 查合法值用:
python manage.py makemessages --list,输出里列出的才是可用语言码 -
LOCALE_PATHS必须指向locale的父目录,例如[BASE_DIR / 'locale'],不是[BASE_DIR / 'locale' / 'zh-hans'] - 手动创建
locale/目录(Django 不自动建) - 模板中必须用
{% load i18n %},再用{% translate "Login" %}或{% blocktrans %}Hello {{ name }}{% endblocktrans %};直接写{{ _('Login') }}不会被提取
模型字段 verbose_name 不切换语言?必须用 gettext_lazy,且不能拼接
模型、表单、序列化器等静态定义处的字符串,在模块加载时就执行一次。如果用普通 gettext,会立刻求值并固化为启动时的语言;用错拼接方式,也会提前触发求值。
错误写法:
name = _('Hello') + ' ' + _('World') # 两个 _ 都立刻求值,语言固定正确做法:
- 整个字符串用
gettext_lazy包裹:FULL_NAME = _('Hello World') - 带变量插值时,用
gettext_lazy+.format(),且所有占位符也用_():_('Hello {name}').format(name=_('World')) - 别在
__init__.py或模块顶层直接调用_(),除非你明确要静态翻译
这个陷阱在 verbose_name、error_messages、label 里特别致命——表面能跑,但切语言后完全不动。
改了 .po 文件但页面还是旧翻译?compilemessages 和 Cookie 同步缺一不可
修改 django.po 后,Django 加载的是编译后的 django.mo 文件。不运行 compilemessages,改多少都没用。
另一个隐形坑是前端语言切换逻辑:
- Django 自带的
/i18n/setlang/视图只接受 POST,前端发 GET 会直接 405 错误 - 切换后浏览器 cookie 中的
django_language值可能没更新,或被其他中间件覆盖 - 如果用了
i18n_patterns,未包进它的 URL(如/api/、/healthz/)根本不会触发语言检测
调试建议:在视图里打印 request.LANGUAGE_CODE 和 request.COOKIES.get('django_language'),确认两者一致且符合预期。

















