{{t "key"}} 是 revel 模板中调用翻译的最简方式,等价于 {{ revel.message("key", .) }},自动根据 c.request.locale 查找对应语言文件(如 home.en),key 缺失时静默返回原文;需确保 /messages 在根目录、文件名格式正确(如 home.en)、revel.i18nfilter 位置正确且启用;key 应加模块前缀防冲突;动态切语言须在 i18nfilter 前通过自定义 filter 设置 c.request.locale。

模板里直接用 {{T "key"}} 就能翻译
Revel 模板中调用翻译最简单的方式就是 {{T "key"}},它等价于 {{ revel.Message("key", .) }},但更短、更常用。这个函数会自动读取当前请求的 c.Request.Locale,然后从对应语言文件(如 home.en)里查值。
注意:key 必须在所有语言文件中存在,否则返回原始 key 字符串(比如显示 greeting 而不是 Hello),不会报错——这是线上静默失效的常见原因。
-
{{T "greeting"}}→ 纯文本替换 -
{{T "greeting.name" .Name}}→ 支持传参,消息文件里得写成greeting.name=Hello {{.Name}} - 不支持嵌套调用,
{{T (T "key")}}会编译失败 - 若想 fallback 到英文,确保
en文件存在且被加载(Revel 不自动 fallback,必须显式匹配到)
为什么 {{T}} 有时不生效?检查三个硬性条件
模板里写了 {{T "submit.button"}} 却还是显示原文,大概率是以下某条没满足:
-
/messages目录必须在应用根目录下,不能是app/messages或conf/messages—— Revel 只认根目录的/messages - 语言文件名必须是
模块名.语言码格式,例如home.en、home.zh;home.en-US或home_zh都会被忽略 -
revel.I18nFilter必须在app/init.go的Filters列表中,且位置要在revel.ParamsFilter之后、revel.ActionInvoker之前;漏掉或顺序错,整个 i18n 流程就断了
改完配置后,开发模式下热重载会自动 reload messages,但如果你删了文件又重建,建议手动重启 revel run 确保加载干净。
多模块模板共用 key 时容易冲突
Revel 的 Message() 查找是全局 flat 的:它不管你是从 home.en 还是 news.en 加载的,只看 key 名字。所以 error.required 在两个文件里都定义,运行时以最后加载的那个为准(加载顺序由文件系统遍历决定,不可靠)。
- 推荐做法:给 key 加模块前缀,比如
home.error.required、news.error.required - 不要依赖文件加载顺序来“覆盖”翻译,那属于未定义行为
- 如果多个模块确实需要同一文案(如通用按钮),统一放到
common.en,并在所有模板中引用相同 key
这个设计意味着你没法在模板里“指定从哪个模块加载”,所有翻译都走同一个命名空间——提前规划好 key 命名规范比后期 debug 强得多。
动态切换语言要改 c.Request.Locale,且必须在 I18nFilter 前
想通过 URL 参数(如 ?lang=zh)或 Cookie 控制语言,不能在控制器里调 revel.Message 前才赋值,因为 revel.I18nFilter 已经执行完了。必须在自定义 filter 中、在 revel.I18nFilter 被调用前完成设置:
- 在
app/init.go的init()函数里注册 filter:revel.InterceptFunc(setLocale, revel.BEFORE, &Application{}) -
setLocale函数里解析参数,然后写c.Request.Locale = "zh"(不是c.Locale,没有这个字段) - 这个赋值必须发生在
revel.I18nFilter执行前,否则会被它覆盖回Accept-Language推导出的值
很多人卡在这一步:看到 c.Request.Locale = "zh" 写了,但模板还是英文——八成是 filter 注册顺序错了,或者写成了 c.Locale 这种不存在的字段。











