需自定义继承 yii\i18n\messagesource 的类并重写 loadmessages(),配置 i18n 组件指向该类,建联合索引 (language, category, message),手动缓存结果,确保语言码格式统一(如 zh-cn),trim 原文避免匹配失败。

怎么让 Yii2 的 I18N 从数据库加载翻译?
Yii2 默认只支持 PHP 文件或 MO/PO 文件的静态翻译,要动态读取数据库,必须自定义 MessageSource 类,不能只改配置就生效。
- 必须继承
yii\i18n\MessageSource,重写loadMessages()方法 - 数据库表结构至少包含
language、category、message(原文)、translation(译文)字段 - 别直接在
messages表里加索引却不加(language, category, message)联合索引——查得慢还容易漏匹配 - 缓存必须手动处理:
loadMessages()返回前建议用Yii::$app->cache->set()存,否则每次Yii::t()都查库
Yii::t() 不触发数据库查询?检查这三处
常见现象是改了数据库里的翻译,页面没变,不是缓存没清,而是根本没走到你的自定义 MessageSource。
-
config/web.php中i18n组件的class没指向你写的类,还是默认的yii\i18n\PhpMessageSource -
components['i18n']['translations']配置里用了*通配但漏写了class,导致 fallback 到默认行为 - 调用
Yii::t('app', 'Hello')时,'app'这个category没在translations配置里显式声明,Yii 直接跳过你的源
数据库翻译和文件翻译混用时,优先级怎么定?
Yii2 不会自动合并数据库和 PHP 文件的翻译结果,它按 translations 配置顺序逐个尝试,第一个返回非 null 的就用那个。
- 想优先数据库:把数据库
MessageSource的配置放在translations数组前面,例如'app*' => ['class' => 'common\components\DbMessageSource'] - 想 fallback 到文件:确保数据库源的
loadMessages()在查不到时 明确 return [](空数组),而不是null或抛异常,否则 Yii 会中断查找链 - 注意
sourceLanguage和language必须一致,否则即使数据库有记录,loadMessages()也可能被跳过
为什么中文翻译显示成英文?字符集或语言码不匹配
最常踩的坑不是逻辑错,是语言码写成了 zh-CN,但数据库里存的是 zh 或 zh_CN —— Yii2 对语言码大小写和分隔符敏感。
- 查
Yii::$app->language实际值,用var_dump()确认,别只看配置 - 数据库字段存语言码时统一用小写 + 短横(
zh-CN),避免zh_cn或ZH-CN - 如果用
gettext工具导出 PO 文件再入库,注意有些工具会把Language:字段写成zh_CN,入库前得转换 - MySQL 表字符集要是
utf8mb4,字段排序规则用utf8mb4_unicode_ci,否则带 emoji 或生僻字的翻译可能乱码或查不到
loadMessages() 方法里没做 trim() 处理——前后空格会让 message 匹配失败,而这个错误既不报错也不提示。











