概述
Go 是静态编译的编程语言,最近很受欢迎,因为它简单、性能好而且非常适合开发云端应用。它有强大的能够 处理国际化(i18n)和本地化(l10n)的库,比如处理字符编码、文本转换还有特定地区的文本,但这个包的 文档写得不够好。让我们来看看该怎么使用这个库,并且让我们的 Go 程序能适应不同区域。
上面说的包是 golang.org/x/text ,如果用得好,在你想让应用全球化时能帮上大忙。此包带有一系列 抽象,让你翻译消息(message)、格式化、处理单复数,还有 Unicode 等更简单。
本文包大致了解 golang.org/x/text 这个包,看它提供了什么用来格式化和本地化的工具。
本文主要内容包含两部分
1.硬编码方式
2.文件加载本地化
- 消息(message)是某些想传达给用户的的内容。每条消息根据键(key)进行区分,这可以有很多形式。 比如可以这样创建一条消息:
p := message.NewPrinter(language.BritishEnglish)
p.Printf("There are %v flowers in our garden.", 1500)
当调用 NewPrinter 函数时,你要提供 语言标签 (language tag)。想指定语言时,就使用这些 语言标签 。有多种创建标签的方式,如下文内容。
语言简写
通过组合 Tag、Base、Script、Region、Variant, []Variant, Extension, []Extension 或 error。比如:
fmt.Println("国家语言简写格式-------------------")
//语言类型构建
zh, _ := language.ParseBase("zh") // 语言
CN, _ := language.ParseRegion("CN") // 地区
zhLngTag, _ := language.Compose(zh, CN)
fmt.Println(zhLngTag) // 打印 zh-CN
fmt.Println(language.Chinese)// 打印中文缩写
fmt.Println(language.SimplifiedChinese)// 打印中文缩写
fmt.Println(language.TraditionalChinese)// 打印中文缩写
fmt.Println(language.AmericanEnglish)// 打印英文缩写
如果你给了一个无效的字符串,会得到一个 Und,意思是未定义的语言标签。
fmt.Println(language.Compose(language.ParseRegion("AL")))
// 打印 Und-AL
更多语言类型资料,请参看
https://godoc.org/golang.org/x/text/language#Tag
中文简写的一些扩展知识
zh-CHS 是单纯的简体中文。
zh-CHT 是单纯的繁体中文。
zh-Hans和zh-CHS相同相对应。
zh-Hant和zh-CHT相同相对应。
以上时zh-CHS/zh-Hans 和 zh-CHT/zh-Hant的关系。
然后是
zh-CN 简体中文,*
zh-HK 繁体中文,香港特别行政区
zh-MO 繁体中文,澳门特别行政区
zh-SG 繁体中文,新加坡-
zh-SG 简体中文,新加坡
zh-TW 繁体中文,*
硬编码
这是使用解析包常用api的基础知识点,通过这里的样例我们可以知道大致的解析过程是怎么样的,方便后面更好的集成接口和服务。
package main
func init() {
message.SetString(language.Chinese, "%s went to %s.", "%s去了%s。")
message.SetString(language.AmericanEnglish, "%s went to %s.", "%s is in %s.")
message.SetString(language.Chinese, "%s has been stolen.", "%s被偷走了。")
message.SetString(language.AmericanEnglish, "%s has been stolen.", "%s has been stolen.")
message.SetString(language.Chinese, "HOW_ARE_U", "%s 你好吗?")
message.SetString(language.AmericanEnglish, "HOW_ARE_U", "%s How are you?")
}
func main() {
// 中文版
p := message.NewPrinter(language.Chinese)
p.Printf("%s went to %s.", "彼得", "英格兰")
fmt.Println()
p.Printf("%s has been stolen.", "宝石")
fmt.Println()
p.Printf("HOW_ARE_U", "竹子")
fmt.Println()
// 英文版本
p = message.NewPrinter(language.AmericanEnglish)
p.Printf("%s went to %s.", "Peter", "England")
fmt.Println()
p.Printf("%s has been stolen.", "The Gem")
fmt.Println()
p.Printf("HOW_ARE_U", "bamboo")
fmt.Println()
}
预判断出来-处理单复数
在一些情况下,你需要根据词语的单、复数而添加多个翻译后的字符串,并且要在翻译集里 加上专门的调用才能管理好单复数的情况。子包 golang.org/x/text/feature/plural 里有个 叫 SelectF 的函数用来处理文本里语法的复数形式。
下面我给个典型的 SelectF 使用案例:
package main
func init() {
//根据参数处理不同的返回语句
message.Set(language.English, "APP_COUNT",
plural.Selectf(1, "%d",
"=1", "I have an apple",
"=2", "I have two apples",
"other", "I have %[1]d apples",
))
}
func main() {
fmt.Println("placehold中的条件判断-------------------")
// 条件判断
p.Printf("APP_COUNT", 1)
fmt.Println()
p.Printf("APP_COUNT", 2)
p.Println()
}
(译者注:由于中文词语 “苹果”、“天” 既表示单数又能表示复数,而对应的英文单词是分单、复数的, 用 “汉译英” 的方式更易向读者说明这段代码的功能。因而将 原文 程序中的英文改成了中文, 希腊文换成了英文。下同。)
这里例子里,SelectF 能识别和支持几个量词,比如 zero 、 one 、 two 、 few 和 many , 此外还能匹配比较符如 >x 或 <x 。
插补字符串到消息中
还有一些情况下,你想进一步处理消息中的量词,你可以用占位符变量(placeholder variables)来 处理一些特定的语法特性。比如说,在前面我们使用复数的例子,可以改写成这样:
func init() {
message.Set(language.English, "你迟了 %d 分钟。",
catalog.Var("m", plural.Selectf(1, "%d",
"one", "minute",
"other", "minutes")),
catalog.String("You are %[1]d ${m} late."))
}
func main() {
p := message.NewPrinter(language.English)
p.Printf("你迟了 %d 分钟。", 1)
// 打印: You are 1 minute late.
fmt.Println()
p.Printf("你迟了 %d 分钟。", 10)
// 打印: You are 10 minutes late.
fmt.Println()
}
这里 catalog.Var 函数的第一个参数为字符串,即 m ,是一个特殊的标签,根据 %d 参数的值, 这个标签会被一个更准确的翻译内容替换。
格式化货币
包 golang.org/x/text/currency 处理货币格式化。
有几个有用的函数可以打印出指定地区货币的金额。下面的例子显示了几种格式化的方式:
package main
import (
"fmt"
"golang.org/x/text/currency"
"golang.org/x/text/language"
"golang.org/x/text/message"
)
func main() {
p := message.NewPrinter(language.English)
p.Printf("%d", currency.Symbol(currency.USD.Amount(0.1)))
fmt.Println()
p.Printf("%d", currency.NarrowSymbol(currency.JPY.Amount(1.6)))
fmt.Println()
p.Printf("%d", currency.ISO.Kind(currency.Cash)(currency.EUR.Amount(12.255)))
fmt.Println()
}
结果会是:
➜ go run main.go
$ 0.10
¥ 2
EUR 12.26
加载消息
当你处理本地化工作时,通常你需要事先准备好译文以便应用程序能用上它们。你可以把这些译文文件 当作静态资源。有几种部署程序和译文文件的方式:
手动设置译文字符串
最简单的方式是把译文构建到你的应用程序里。你必须手动创建一个数组,包含原文和译文的条目, 在初始化时,那些消息会被加载到默认翻译集中。在你的应用里,你只能用 NewPrinter 函数切换区域。
下面这个应用,示范了如何在初始化时加载译文:
package main
func init() {
// 以上代码和以下代码都是硬编码方式
for _, e := range msaArry {
tag := language.MustParse(e.tag)
switch msg := e.msg.(type) {
case string:
message.SetString(tag, e.key, msg)
case catalog.Message:
message.Set(tag, e.key, msg)
case []catalog.Message:
message.Set(tag, e.key, msg...)
}
}
}
func main() {
//调用硬编码中的消息 国际化
p = message.NewPrinter(language.English)
p.Printf("HELLO_WORLD","bamboo")
p.Println()
p.Printf("TASK_REM", 2)
p.Println()
}
//手工 硬编码方式
var msaArry = [...]langMsg{
{"en", "HELLO_WORLD", "%s Hello World"},
{"zh", "HELLO_WORLD", "%s 你好世界"},
{"en", "TASK_REM", plural.Selectf(1, "%d",
"=1", "One task remaining!",
"=2", "Two tasks remaining!",
"other", "[1]d tasks remaining!",
)},
{"zh", "TASK_REM", plural.Selectf(1, "%d",
"=1", "剩余一项任务!",
"=2", "剩余两项任务!",
"other", "剩余 [1]d 项任务!",
)},
}
文件加载本地化
一直以来,大多数本地化的框架都会把每个语言的译文分别存于文件里,这些文件会被动态加载。你可以把 这些文件交给翻译的人,在他们搞定后,你再把译文合并到你的应用中。
为了协助这个过程,Go 作者们开发了一个命令行小工具叫 gotext
安装:go get -u golang.org/x/text/cmd/gotext
但是本人参考该资料安装并没有成功,因此另想办法处理了,该内容部分属于个人学习创新的部分。
思路如下:1.翻译的样本,2.整理成各个语言格式的json字符串文件,3.加载相关语言文件到系统中,4.根据当前语言解析出语句
本地化语言json文本文件如下
|locales
|-el
|--messages_en.json
|--messages_zh.json
详细json内容请参考我的git地址,包含本文和相关学习的所有源码
https://github.com/BambooZhang/go-study/tree/master/go-base
源码如下
func main() {
fmt.Println("从配置文件中读取配置json解析并加载到系统中-------------------")
InitConfig("go-base/locales/el/messages_zh.json")//加载配置信息json
InitConfig("go-base/locales/el/messages_en.json")//加载配置信息json
p = message.NewPrinter(language.SimplifiedChinese)//设置语言类型
p.Printf("HELLO_1", "Peter")
fmt.Println()
p.Printf("VISITOR", "Peter","用户管理系统接口")
fmt.Println()
p = message.NewPrinter(language.AmericanEnglish)//设置语言类型
p.Printf("VISITOR", "Peter","UER MANAGE SYSTEM API")
fmt.Println()
msg := Message{"en", "HELLO_WORLD", "%s Hello World"}
p.Printf("CONFIG", msg) //传一个对象值进去
fmt.Println()
}
从配置文件中读取想关文件后,json解析出对应的message信息加载到系统中,需要使用时选择好语言,直接调用既返回对应的语言信息
学习资料地址
详细内容请参考我的git地址,包含本文和相关学习的所有源码
https://github.com/BambooZhang/go-study/tree/master/go-base
本文参考资料
[译] 手把手教你 Go 程序的国际化和本土化
https://www.colabug.com/3411106.html