GoFrame框架中的i18n国际化实践

532 阅读4分钟

在现代Web应用开发中,国际化(i18n)是一个非常常见的需求。不同地区的用户访问同一个应用时,希望能看到本地语言的界面,这就需要应用程序具备多语言支持能力。Go语言的国际化支持非常好,GoFrame框架也提供了完善的i18n支持,下面我们就来详细介绍一下如何在GoFrame项目中实现i18n。

安装i18n模块

GoFrame的i18n能力由g-i18n模块提供,首先需要安装该模块:

go get -u github.com/gogf/gf/v2/i18n/gi18n

配置i18n选项

在项目的配置文件(manifest/config/config.yaml)中添加i18n相关配置:

i18n:
  path: i18n
  language: zh-CN
  delimiters: ["${", "}"]

其中:

  • path 指定语言文件存储的目录路径
  • language 指定默认语言
  • delimiters 指定翻译字符串的定界符,默认为["${", "}"]

准备语言文件

i18n目录下按语言编码创建不同的语言文件,如:

  • zh-CN.toml 中文简体
  • en-US.toml 英文
  • ja-JP.toml 日文

每个语言文件中定义该语言的翻译字符串,格式为: key = "value"。如:

# zh-CN.toml
hello = "你好"
welcome = "欢迎来到GoFrame"

# en-US.toml  
hello = "Hello"
welcome = "Welcome to GoFrame"

# ja-JP.toml
hello = "こんにちは"  
welcome = "GoFrameへようこそ"

使用翻译函数

在代码中,通过调用i18n.Translate方法来翻译字符串:

package main

import (
    "github.com/gogf/gf/v2/frame/g"
    "github.com/gogf/gf/v2/i18n/gi18n"
)

func main() {
    g.I18n().SetLanguage("zh-CN")  // 设置当前语言为中文
    println(gi18n.Translate(`hello`))  // 输出: 你好 
    
    g.I18n().SetLanguage("en-US") // 切换语言为英文  
    println(gi18n.Translate(`hello`)) // 输出: Hello
}

gi18n.Translate方法会自动根据当前设置的语言,在对应的语言文件中查找翻译字符串。

g.I18n().SetLanguage用于设置当前的语言,修改该值可动态切换语言。

参数替换

翻译字符串支持参数替换,可以很方便的构造动态文本:

# zh-CN.toml
hello.name = "你好 ${name}, 年龄 ${age}"

# en-US.toml
hello.name = "Hello ${name}, age ${age}"
println(gi18n.Translate(gi18n.Translate(ctx, "{#hello.name}")))

// zh-CN: 你好 john, 年龄 18
// en-US: Hello john, age 18

在翻译字符串中使用${xxx}占位符即可。

复数规则

i18n模块支持复数规则,可以很方便的处理单复数形式:

# zh-CN.toml
book.count = "书 ${count} 本" 
book.count.plural = "书 ${count} 本"

# en-US.toml
book.count = "${count} book"
book.count.plural = "${count} books"
println(gi18n.Translate(ctx,`{#book.count}`))  
println(gi18n.Translate(ctx,`{#book.count}`))

// zh-CN: 书 1 本 、 书 2 本
// en-US: 1 book 、 2 books

通过keykey.plural来定义单复数形式的翻译字符串。中文中通常单复数形式一样,英文中则需要区分。使用时会根据count参数自动匹配单复数形式。

语言自动检测

通常i18n信息需要从HTTP请求中获取,gi18n模块对此做了很好的封装,在HTTP请求处理中可以非常方便的实现语言自动检测:

func(r *ghttp.Request) {
    lang := r.GetString("lang") // 从请求参数、Cookie、Header等获取语言
    r.SetCtx(gi18n.WithLanguage(r.Context(), lang))
    
    // 后续的翻译会自动使用该请求的语言
    r.Response.WriteTplDefault(g.Map{
        "hello": gi18n.Translate(ctx,`hello`),
    })
}

利用go context在请求间传递语言信息,使该请求后续的处理都自动使用指定的语言,不需要每次都设置。

热更新选项

在配置文件(manifest/config/config.yaml)中添加i18n.reload选项,设置为true:

i18n:
  path: i18n
  language: zh-CN
  reload: true # 开启语言文件热更新

reload选项用于控制是否开启语言文件的热更新特性,默认为false。设置为true时,会在每次翻译时自动重新加载语言文件,以保证翻译始终使用最新的语言文件内容。

调用SetPath方法

如果需要在运行时动态修改语言文件的路径,可以调用gi18n.SetPath方法:

package main

import (
    "github.com/gogf/gf/v2/frame/g"
    "github.com/gogf/gf/v2/i18n/gi18n"
)

func main() {
    // 设置语言文件目录为 i18n-new
    gi18n.SetPath("i18n-new") 
    
    // 之后的翻译会使用 i18n-new 目录下的语言文件
    println(gi18n.Translate(ctx,`hello`))
}

gi18n.SetPath方法可以在运行时动态设置语言文件的目录路径。调用该方法后,后续的翻译都会使用新设置的目录下的语言文件。

修改语言文件

开启热更新后,我们可以在运行时修改语言文件的内容,修改会立即生效,无需重启应用。

例如,我们修改en-US.toml文件:

# en-US.toml
hello = "Hello, world!" # 修改翻译内容

然后在代码中执行翻译:

println(gi18n.Translate(ctx,`hello`))
// 输出: Hello, world!

可以看到,修改后的翻译内容已经立即生效了。

注意:

  • 开启热更新会在每次翻译时重新加载语言文件,略微影响性能,建议在开发环境下开启,生产环境可以关闭。

  • gi18n.SetPath方法也会触发语言文件的重新加载。

  • 如果语言文件的格式有错误,会导致加载失败,翻译会使用上一次加载的语言文件。

其他功能

gi18n还支持:

  • 支持多种格式的语言文件(toml/ini/json/yaml等)
  • 支持语言文件分级存储
  • 支持自定义翻译加载器
  • 等等

总结

GoFrame提供了强大灵活的i18n支持,让我们能够轻松的实现Web应用的多语言支持,提升产品的国际化能力。合理的规划i18n能力,可以让我们的应用更加通用,能够服务更多区域的用户。