Revel多语言适配需严格遵循框架约定:正确创建UTF-8无BOM的/messages目录及ISO 639-1命名文件,启用并准确定位I18nFilter,模板中用预绑定T函数调用,且确保传参非nil、key全局唯一。

Revel 模板多语言适配不是“加个插件就行”,而是必须严格按框架约定组织文件、启用 filter、并在模板中用 T 函数调用——漏掉任一环,{{T "key"}} 都只会原样输出 key。
messages 目录结构和文件命名不能错
Revel 只认根目录下的 /messages 子目录,且只加载其中以 ISO 639-1 短码结尾的文件(如 home.en、home.zh),不识别 en-US、zh-CN 或下划线命名。
-
/messages必须手动创建,框架不会自动建;目录不存在时 i18n filter 静默跳过,无报错 - 文件编码必须是 UTF-8 无 BOM,否则中文乱码或解析失败
- 文件内容为 goconfig 格式:每行
key=value,不支持 JSON 或 TOML - 模块名(如
home)只是文件前缀,不影响 key 查找逻辑,但建议按功能拆分便于维护
I18nFilter 启用顺序决定翻译是否生效
Revel 的 revel.I18nFilter 不是“开了就完事”,它必须出现在 app/init.go 的 Filters 列表中,且位置固定:在 revel.ParamsFilter 之后、revel.ActionInvoker 之前。
- 如果被注释掉、写错名字(如
I18nFilter拼成I18NFilter),所有Message()调用都返回原始 key - 若自定义 filter 中修改了
c.Request.Locale,必须在I18nFilter执行前赋值,否则会被覆盖 - 开发模式下热重载会自动重新加载
/messages文件,但生产模式(REVEL_RUNMODE=prod)需重启服务
模板中用 T 函数比 revel.Message 更安全
直接在模板里写 {{ revel.Message "greeting" }} 语法冗长,且每次都要传参;而预绑定 T 函数更简洁、不易出错。
- 在 Controller 的
Init或Before方法中加:c.RenderArgs["T"] = c.Message - 模板中统一用:
{{ T "submit.button" }}或带参数的{{ T "welcome.user" .User }} - 传参类型不匹配(比如
.User是 nil 或不含Name字段),Revel 不报错,而是原样输出 key —— 这是最难排查的坑之一 - key 必须全局唯一;不同模块用了相同 key(如
error.required在 home 和 auth 下都定义),后加载的会覆盖前者
批量导出翻译数据需绕过 Revel 内部封装
Revel 没有公开 API 支持“获取当前语言下某模块全部 key-value”,因为其内部 messages 映射未导出。API 场景需要批量翻译时,不能依赖 revel.Message 循环调用。
- 推荐做法:用
robfig/config库直接解析/messages/home.zh文件,得到map[string]string - 注意路径硬编码风险:Revel 的
/messages是固定路径,但你的代码需确保运行时工作目录正确 - 若需动态语言切换,别缓存 config 实例——每个语言文件需单独 parse,避免并发读写冲突
- 线上环境务必关闭热重载(
REVEL_RUNMODE=prod),否则频繁文件 I/O 可能拖慢响应
真正卡住人的从来不是“怎么写翻译”,而是 /messages 目录少一个字母、I18nFilter 位置错一位、或者模板里传了个 nil 结构体——这些地方没日志、不报错、只沉默返回 key。











