- Created by 郭强, last modified on May 28, 2021
对象创建
单例对象
大多数场景下,我们推荐使用g.I18n
单例对象,并可自定义配置不同的单例对象,但是需要注意的是,单例对象的配置修改是全局有效的。例如:
g.I18n().T(context.TODO(), "{#hello} {#world}")
在所有的转译方法中,第一个参数都要求输入Context
上下文变量参数,用于上下文变量的传递、翻译语言的指定、后续的可扩展能力。该参数虽然直接传递nil
也是可以的,但是为保证程序的严谨性,我们建议您当不知道传递什么或者没有特殊要求的时候传递context.TODO()
或者context.Background()
来替代。
独立对象
其次,我们也可以模块化独立使用gi18n
模块,通过gi18n.New()
方法创建独立的i18n
对象,然后开发者自行进行管理。例如:
i18n := gi18n.New() i18n.T(context.TODO(), "{#hello} {#world}")
语言设置
设置转译语言有两种方式,一种是通过SetLanguage
方法设置当前I18N
对象统一的转译语言,另一种是通过上下文设置当前执行转译的语言。
SetLanguage
例如,我们通过g.I18n().SetLanguage("zh-CN")
即可设置当前转译对象的转译语言,随后使用该对象都将使用zh-CN
进行转译。需要注意的是,组件的配置方法往往都不是并发安全的,该方法也同样如此,需要在程序初始化时进行设置,随后不能在运行时进行更改。
WithLanguage
WithLanguage
方法可以创建一个新的上下文变量,并临时设置您当前转译的语言,由于该方法作用于Context
上下文,因此是并发安全的,常用于运行时转译语言设置。我们来看一个例子:
ctx := gi18n.WithLanguage(context.TODO(), "zh-CN") i18n.Translate(ctx, `hello`)
其中WithLanguage
方法定义如下:
// WithLanguage append language setting to the context and returns a new context. func WithLanguage(ctx context.Context, language string) context.Context
用于将转译语言设置到上下文变量中,并返回一个新的上下文变量,该变量可用于后续的转译方法。
常用方法
T
方法
T
方法为Translate
方法的别名,也是大多数时候我们推荐使用的方法名称。T
方法可以给定关键字名称,也可以直接给定模板内容,将会被自动转译并返回转译后的字符串内容。
此外,T
方法可以通过第二个语言参数指定需要转译的目标语言名称,该名称需要和配置文件/路径中的名称一致,往往是标准化的国际化语言缩写名称例如:en/ja/ru/zh-CN/zh-TW
等等。否则,将会自动使用Manager
转译对象中设置的语言进行转译。
方法定义:
// T translates <content> with configured language and returns the translated content. func T(ctx context.Context, content string)
关键字转译
关键字的转译直接给T
方法传递关键字即可,例如:T(context.TODO(), "hello")
、T(context.TODO(), "world")
。I18N
组件将会优先将给定的关键字进行转译,转译成后返回转译后的内容,否则直接展示原内容。
模板内容转译
T
方法支持模板内容转换,模板中的关键字默认使用{#
和}
标签进行包含,模板解析时将会自动替换该标签中的关键字内容。使用示例:
1、转译文件
ja.toml
hello = "こんにちは" world = "世界"
ru.toml
hello = "Привет" world = "мир"
zh-CN.toml
hello = "你好" world = "世界"
2、示例代码
package main import ( "context" "fmt" "github.com/gogf/gf/i18n/gi18n" ) func main() { i18n := gi18n.New() i18n.SetLanguage("en") fmt.Println(i18n.Translate(context.TODO(), `hello`)) fmt.Println(i18n.Translate(context.TODO(), `GF says: {#hello}{#world}!`)) i18n.SetLanguage("ja") fmt.Println(i18n.Translate(context.TODO(), `hello`)) fmt.Println(i18n.Translate(context.TODO(), `GF says: {#hello}{#world}!`)) i18n.SetLanguage("ru") fmt.Println(i18n.Translate(context.TODO(), `hello`)) fmt.Println(i18n.Translate(context.TODO(), `GF says: {#hello}{#world}!`)) ctx := gi18n.WithLanguage(context.TODO(), "zh-CN") fmt.Println(i18n.Translate(ctx, `hello`)) fmt.Println(i18n.Translate(ctx, `GF says: {#hello}{#world}!`)) }
执行后,终端输出为:
Hello GF says: HelloWorld! こんにちは GF says: こんにちは世界! Привет GF says: Приветмир! 你好 GF says: 你好世界!
Tf
方法
我们都知道,模板内容中也会存在一些变量,这些变量可以通过Tf
方法进行转译。
Tf
为TranslateFormat
的别名,该方法支持格式化转译内容,字符串格式化语法参考标准库fmt
包的Sprintf
方法。
方法定义:
// Tf translates, formats and returns the <format> with configured language
// and given <values>.
func Tf(ctx context.Context, format string, values ...interface{}) string
我们来看一个简单的示例。
1)转译文件
en.toml
OrderPaid = "You have successfully complete order #%d payment, paid amount: ¥%0.2f."
zh-CN.toml
OrderPaid = "您已成功完成订单号 #%d 支付,支付金额¥%.2f。"
2)示例代码
package main import ( "fmt" "github.com/gogf/gf/i18n/gi18n" ) func main() { var ( orderId = 865271654 orderAmount = 99.8 ) i18n := gi18n.New() t.SetLanguage("en") fmt.Println(i18n.Tf(`{#OrderPaid}`, orderId, orderAmount)) t.SetLanguage("zh-CN") fmt.Println(i18n.Tf(`{#OrderPaid}`, orderId, orderAmount)) }
执行后,终端输出为:
You have successfully complete order #865271654 payment, paid amount: ¥99.80.
您已成功完成订单号 #865271654 支付,支付金额¥99.80。
为方便演示,该示例中对支付金额的处理比较简单,在实际项目中往往需要在业务代码中对支付金额的单位按照区域做自动转换,再渲染i18n
显示内容。
上下文设置转译语言
我们将上面的示例做些改动来演示。
1、转译文件
en.toml
OrderPaid = "You have successfully complete order #%d payment, paid amount: ¥%0.2f."
zh-CN.toml
OrderPaid = "您已成功完成订单号 #%d 支付,支付金额¥%.2f。"
2、示例代码
package main import ( "context" "fmt" "github.com/gogf/gf/frame/g" "github.com/gogf/gf/i18n/gi18n" ) func main() { var ( orderId = 865271654 orderAmount = 99.8 ) fmt.Println(g.I18n().Tf( gi18n.WithLanguage(context.TODO(), `en`), `{#OrderPaid}`, orderId, orderAmount, )) fmt.Println(g.I18n().Tf( gi18n.WithLanguage(context.TODO(), `zh-CN`), `{#OrderPaid}`, orderId, orderAmount, )) }
执行后,终端输出为:
You have successfully complete order #865271654 payment, paid amount: ¥99.80. 您已成功完成订单号 #865271654 支付,支付金额¥99.80。
为方便演示,该示例中对支付金额的处理比较简单,在实际项目中往往需要在业务代码中对支付金额的单位按照区域做自动转换,再渲染i18n
显示内容。
I18N
与视图引擎
gi18n
默认已经集成到了GoFrame
框架的视图引擎中,直接在模板文件/内容中使用gi18n
的关键字标签即可。我们同样可以通过上下文变量的形式来设置当前请求的转译语言。
此外,我们也可以通过设置模板变量I18nLanguage
设置当前模板的解析语言,该变量可以控制不同的模板内容按照不同的国际化语言进行解析。
使用示例:
package main import ( "github.com/gogf/gf/frame/g" "github.com/gogf/gf/i18n/gi18n" "github.com/gogf/gf/net/ghttp" ) func main() { s := g.Server() s.Group("/", func(group *ghttp.RouterGroup) { group.Middleware(func(r *ghttp.Request) { r.SetCtx(gi18n.WithLanguage(r.Context(), r.GetString("lang", "zh-CN"))) r.Middleware.Next() }) group.ALL("/", func(r *ghttp.Request) { r.Response.WriteTplContent(`{#hello}{#world}!`) }) }) s.SetPort(8199) s.Run() }
执行后,访问以下页面,将会输出:
- http://127.0.0.1:8199
你好世界!
- http://127.0.0.1:8199/?lang=ja
こんにちは世界!
- No labels
5 Comments
Ricco
不明白既然初始时设置了WithLanguage,为何转译时还要设置上下文context,感觉有点画蛇添足
郭强
一个是全局设置,一个是局部设置。比如不同的用户可能设置了不同的语言,仅靠一个
i18n
对象是不行的,可以使用ctx
来实现。Ricco
感谢回复,我也是一个Phper转过来的,在php中,可以很方便的使用__CLASS__及__METHOD__定义存储翻译文件的位置(如 i18n/语言Locale代码/后台/控制器名.toml),不知道在go中,除了用反射,是否有还别的处理方法?
郭强
Go里面可能没有,你可以看看这个模块 gdebug (调试功能)
黄胜铉
我看manager的init方法里有注册对文件的监听来实现热更新,不过监听的path是不是有问题?不是m.options.Path吗?