Kratos本身不内置MessageSource和LocaleResolver,需自行组合go-i18n等库实现:中间件从Header或Query提取locale存入context,全局初始化i18n.Bundles按语言加载资源文件,handler中通过context获取locale并调用Localize查文案。

Kratos框架里怎么配 MessageSource 和 LocaleResolver
Kratos 本身不内置 i18n 实现,得靠自己组合 Go 标准库 + 第三方包(如 golang.org/x/text)或轻量库(如 go-i18n/i18n、nikolaydubina/go-i18n)来搭。Spring Boot 那套 MessageSource/LocaleResolver 概念可以类比迁移,但不能直接搬。
关键不是“有没有”,而是“谁负责解析 Locale、谁负责查 key”。常见做法是:
- 用中间件从
HTTP Header(如Accept-Language)或 query 参数(如?lang=zh-CN)提取locale,存进context.Context; - 初始化一个全局
*i18n.Bundles(以go-i18n为例),按语言加载 JSON/TOML 文件; - 在 handler 里通过
ctx.Value()拿到当前 locale,再调bundle.Localize(&i18n.LocalizeConfig{...})查文案。
别把 bundle 做成单例全局查——不同请求 locale 不同,必须带上下文传入。否则英文用户看到中文提示,就是这个原因。
资源文件命名和路径不对,go-i18n 加载失败报什么错
典型错误是:no translation found for key "user.not_found" in locale "en-US",或者启动时 panic:open i18n/en-US.all.json: no such file or directory。
根本原因往往就三点:
- 文件名必须严格匹配 locale tag:Go 的
x/text/language对大小写敏感,en-us≠en-US,推荐统一用en-US、zh-CN这种 BCP 47 标准格式; - 路径没加进
go:embed或没被os.Stat读到——Kratos 默认不自动扫描资源目录,得显式调i18n.MustLoadAssetsFS或自己fs.ReadFile; - JSON 文件里 key 缺少顶层 namespace(比如用了
{"common":{"submit":"Submit"}}),但代码里却直接查"submit",就会查不到。
建议初始化时加个校验:遍历所有支持的 locale,尝试 bundle.MustT("test.key", locale),启动失败比运行时报错更容易定位。
动态切换语言时,grpc 请求怎么传 locale
HTTP 请求能靠 header 或 query,但 gRPC 没有标准 header 机制。Kratos 的 transport.GRPCServer 默认不透传 Accept-Language,得手动做。
两种可靠方式:
- 在 client 端发请求时,把 locale 放进 metadata:
metadata.Pairs("lang", "zh-CN"); - 在 server 端写 middleware,从
grpc.ServerStream.Context()提取 metadata,解析后塞进 context:ctx = context.WithValue(ctx, ctxKeyLocale, lang); - 后续所有 handler 都从该 context 取 locale,而不是依赖 transport 层自动绑定。
注意:gRPC metadata 是字符串 map,值不会自动 decode,"zh-CN" 就是字符串,别误当成结构体去解析。另外,别在 interceptor 里改 response body 去“注入”语言字段——破坏了 gRPC 的契约,前端 SDK 会解包失败。
中文乱码、占位符不渲染、fallback 失效这些坑怎么避
乱码基本等于编码没设对:确保所有 JSON/TOML 文件保存为 UTF-8 无 BOM;go-i18n 加载时如果用了 ioutil.ReadFile(已弃用),换成 os.ReadFile,后者默认按 UTF-8 解码。
占位符不渲染,常见于模板语法混用:go-i18n 默认用 {{.Name}},不是 {name} 或 %s;若用 golang.org/x/text/message,则要用 {Name} + message.Printf 配合 message.NewPrinter。
fallback 失效,是因为没设兜底 locale:bundle.SetDefaultLanguage("en-US") 必须调,且要在所有 LoadTranslation 之后;否则查不到 zh-CN 时,连 en-US 都不会试,直接返回空字符串或 panic。
最易忽略的是:Kratos 的 log 和 errors 模块默认不走 i18n——你写的 errors.New("用户不存在") 永远是中文。真要国际化错误提示,得封装一层 ErrUserNotFound(locale string) error,内部查 bundle 后再包装。











