i18n
是英文单词internationalization
的首末字符i和n,18为中间的字符数,是“国际化”的简称,类似规则产生的简称还有k8s
。
开门见山,这篇文章主要是灌水,仓库里有详细的使用说明和介绍。仓库地址:https://github.com/jjonline/i18n-stringer
一、go实用哲学
下面罗列一些go语言的伪哲学思想,山非山水非水,最终山还是山水还是水,颇有一股一本正经胡说八道的意味。
一切皆接口
长得像鸭子像鸭子一样呱呱叫的就是鸭子,接口interface
就是鸭子规则在go语言里的体现。
当然一切皆接口
真要较真理解也不是完全准确的,这个抽象的核心是理解鸭子类型(duck typing
)的深层次原理和由此而带来的收益。是一种取舍折中,go官方早先提的少即是多(Less is more)或者翻译后的:大道至简,仁者见仁智者见智咯。
这里要提一笔的是:go1.18引入了any
关键字,后续版本any
或等价于interface
或是一个超集,拭目以待。
只要error不要exception
go语言本身没有exception
这种说法,当然panic
你也可以理解为一种异常,但是go语言本身又并不提供try {} catch {}
语法,当然你也可以配合recover
实现一种并不推荐使用的伪try-catch的机制。按照语言本身的机制发生panic
就是一种流程行进不下去的恐慌
是需要修复的,而exception机制更多的是一种中断机制以实现流程转向的目的。
这种机制也就导致了代码段的方法、函数流程中出现了非预期的结果就需要使用error来标识。go语言内置了error
类型(https://github.com/golang/go/blob/master/src/builtin/builtin.go#L270),是一个interface
,只要实现了Error() string
方法的就是一个error,所以可以自定义错误。
枚举常量用数值类型
这里数值类型是多个类型的集合称呼,罗列出来就是int、uint、int8、uint8等等这些。
Go语言中的常量使用关键字const
定义,用于存储不会改变的数据,常量是在编译时被创建的,即使定义在函数内部也是如此,常量允许布尔型、数值型(整数型、浮点型和复数)和字符串型。当然这3种类型的派生自定义类型也是阔以的。
作为业务开发中常见的枚举值一般是推荐使用数值型,当然简单的非是即否的用布尔型也没问题,超过2个待选的枚举集合你要用字符串是可以的。
二、i18n-stringer
这个工具是因工作中的项目需要,单独定义的翻译文件可以直接丢给PM去填,是一个甩锅卷KPI的开源项目----这段是吹水。该工具参考了go官方的tool工具stringer:https://github.com/golang/tools/tree/master/cmd/stringer
基于上述3个伪哲学:我们的接口一般会使用错误码来做一些场景辨识,那错误码就是自定义数值类型的枚举值;而go没有异常只有error,一切皆接口我们的错误码同时也实现buitin.error
接口也可当做错误在方法体代码段传递返回。
i18n-stringer
是一个使用TOML文件配置多语言文案支持国际化多语言的自动生成代码的工具,用于自动为自定义数值类型的枚举常量的类型实现fmt.Stringer
、buitin.error
接口,即为自定义数值类型添加Error() string
和String() string
等方法,不需要手动实现这些代码,当枚举值集合被修改时也无需同时修改多处代码,一切用工具自动生成即可。go语言本身提供了工具链go generate
配合源码里的//go:generate
打头的注释指令,即可go generate
一键执行,参考这里https://blog.jjonline.cn/golang/257.html的介绍不再赘述。
i18n-stringer
不是被你的代码所依赖的包,而是要被编译安装到GOBIN目录的命令行指令程序。因使用了1.16新增的一些文件操作方法编译安装仅支持1.16及其以上的go环境,生成的代码因使用了context上下文,可用于1.7及其以上的环境。go语言对go1的兼容性保证,历史代码一般均可无缝使用新版本,建议跟随官方永远使用最新版本。
自动生成的代码方法概要
// 自动生成的代码导出方法列表 String() string Error() string Wrap(err error, locale string, args ..._T_) *I18nError_T_Wrap WrapWithContext(ctx context.Context, err error, args ..._T_) *I18n_T_ErrorWrap IsLocaleSupport(locale string) bool Lang(ctx context.Context, args ..._T_) string Trans(locale string, args ..._T_) string // 自动生成的代码里还会提供一个错误包装结构体 // 结构体名称形如:I18nError_T_Wrap // 也会提供一些导出方法列表 Translate() string String() string Error() string Format() string Value() _T_ Unwrap() error // 以上 _T_ 指代你的数值类型的自定义类型名称
因为项目本身的README文件介绍的已经很详细,具体使用方法请参考仓库README.md
介绍,下面罗列一些要点:
- 使用TOML文件定义多语言,多语言类型使用文件名或目录名自动生成不需要额外指定;
-
自动为你的自定义类型实现
fmt.Stringer
、buitin.error
两个接口,并自动生成一个包装类型便于包装其他错误; - 支持通过context.Context自动取需要语言类型标识符;
- 自带检查TOML文件中缺失或无效键值对功能,通过指令参数自取;
TOML语言文件取语言类型标识规则
因为定义多语言的翻译文本通过toml格式文件单独配置,识别需要支持的多语言通过目录名或文件名实现。具体而言语言包目录下的toml文件的文件名被作为语言标识符,语言包目录下的文件夹名称也会被当做语言标识符,这种惯例约定可以减少很多不必要的配置麻烦,按惯例定义toml后缀的翻译文件即可,举个栗子:
. ├── i18n │ └── en.toml │ ├── zh_cn.toml │ └── zh_hk │ │ ├── user.toml │ │ └── merchant.toml └── pill.go
上述目录结构中i18n
目录即为定义多语言TOML文件的根目录,其下有两个toml格式的直接文件en.toml
、zh_cn.toml
,所以两个文件的文件名将被提取为两个语言类型标记:en
、zh_cn
,然后还有一个文件夹zh_hk
,文件夹内还有toml文件,所以该文件夹名也被提取一个语言标记:zh_hk
,所以上述目录结构定义了3种类型的语言翻译。
有些项目语言定义文件需要分模块按功能分多个toml文件来定义,所以上述zh_hk
文件夹下全部用于定义zh_hk
的翻译文本,该目录下的toml后缀的文件的文件名可以任意定义且文件数量不限制,该目录下也还可以有子目录且子目录名可以任意定义。关于重复:上述例子中如果还有个叫en
的子目录且子目录有toml后缀格式的文件会怎样?当然是自动合并均作为en
类型的翻译文本啦。
关于编译后二进制文件是否要将TOML文件包含?
先给答案:不需要!
因为定义的TOML文件仅在自动生成代码时使用,属于编译前依赖,代码生成时将这些TOML文件中定义的键值对硬编码至了代码中,业务代码调用时不需要再去读取TOML文件,所以你的业务代码编译成的二进制可执行程序不需要包含这些TOML文件。
----
注意:go语言里并没有buitin
包,文中buitin.error
是为了便于说明而这么写的。
----
使用示例参考:https://github.com/jjonline/i18n-stringer/tree/master/example
感谢分享 赞一个