我们接着上篇在线论坛的进度,由于之前所有页面和消息文本都是英文的,而我们开发的应用基本都是面向中文用户的,所以需要对项目进行本地化,今天正好借着这个入门项目给大家介绍下如何在 Go Web 应用中进行国际化和本地化编程,由于项目比较简单,我们只介绍消息提示、视图模板和日期格式的本地化,更多本地化实现留待后面本地化专题详细介绍。
注:本系列教程源码已提交到 Github:https://github.com/nonfu/chitchat,可以参照这里获取完整代码。
1、消息本地化
安装 go-i18n 扩展包
首先来看消息提示文本,消息提示文本通常包括表单验证消息、应用异常消息、接口响应消息等后端接口返回的消息字符串片段,关于这一块的本地化,可以借助 Go 官方自带的 golang.org/x/text
扩展包实现,这个扩展包扩展性好,但是上手起来有点复杂,所以今天学院君使用的是一款更容易上手的第三方扩展包 —— go-i18n
。
在使用这个扩展包之前,先在项目根目录下运行如下命令下载相关的扩展包:
go get -u github.com/nicksnyder/
下载完成后,我们可以运行 ls -l $GOPATH/bin | grep goi18n
确保 goi18n
命令已经在 $GOPATH
中了:
![238c3c1d96a732e66119de12b179ba78.png](https://i-blog.csdnimg.cn/blog_migrate/60ca5c25daa9896716d9949c2a3f5369.jpeg)
通过 go-i18n 自动生成翻译文件
接下来,我们来编写消息文本模板用于生成翻译文件。在这个项目中,只有一个消息提示文本,那就是访问的群组不存在时返回的 Cannot read thread
,因此,我们在项目根目录下创建 messages.go
,并基于 go-i18n
提供的类型编写消息模板如下:
package main
其中 ID
是消息文本的唯一标识,Other
则是对应的翻译字符串(默认是英文),然后基于 goi18n
命令自动生成翻译文件到 locales
目录(执行前先创建 locales
目录):
mkdir locales
这样,就会在 locales
目录下生成可以被 go-i18n
包识别并解析的 JSON 格式翻译文件 active.en.json
:
![66487b87cc02abbb3b4e407fc2d1b2a4.png](https://i-blog.csdnimg.cn/blog_migrate/86cb775dae12b0d68117901a3491d67d.jpeg)
编写中文版本翻译文件
然后,要进行本地化编程,可以在同级目录下创建并编辑 active.zh.json
用于存放消息文本的中文翻译:
![e0da5eac68a30e72c0dfff064fcf105e.png](https://i-blog.csdnimg.cn/blog_migrate/2142045dd0aa87a004190cd2f2670506.jpeg)
是不是像极了 Laravel 框架中的 resources/lang
翻译目录的结构?其实原理都是一样的:
![60bcfc9b8435fae0b3a7f6a309a64499.png](https://i-blog.csdnimg.cn/blog_migrate/9c809fbef1a674d688f9ae335c4b447a.jpeg)
本地配置初始化
回到在在线论坛项目,打开配置文件 config.json
,新增本地化目录和语言配置:
{
"App": {
...
"Locale": "locales",
"Language": "zh"
},
...
}
然后在 config/config.go
中新增与之映射的结构体字段,以及对应的初始化设置:
package config
注意我们在 App
结构体中新增了一个 *i18n.Bundle
类型的 LocaleBundle
字段,用于存放全局本地化 Bundle 实例,并且在 LoadConfig()
方法中以单例模式初始化该实例。
在处理器方法中返回本地消息
接下来,我们打开 handlers/helper.go
,在 init
方法中初始化 Localizer 以便被所有处理器方法使用:
package handlers
最后在 handlers/thread.go
和 handlers/post.go
中调用 errorMessage
辅助函数的地方调用 Localizer 提供的方法对消息文本进行翻译并返回给用户:
if err !=
测试消息本地化
重新启动应用,如果试图访问一个不存在的群组页面,就会返回如下中文提示信息:
![5e995b7f2c252c07df6d8f79f6055a98.png](https://i-blog.csdnimg.cn/blog_migrate/c925f6b74934f7f2e91b095fa742b99d.jpeg)
说明我们的本地化翻译生效了,当然这里只是使用了 go-i18n
提供的最基本的功能,想要了解更多使用示例,可以参考如下链接:
官方文档:https://github.com/nicksnyder/go-i18n
借助 go-i18n 更简单地实现全球化:https://zyfdegh.github.io/post/201809-translation-go-i18n/
2、视图本地化
所谓视图本地化指的是静态 HTML 视图模板的本地化,这里就不再适合使用消息文本翻译的方式实现了,最简单的方式就是为每个语言创建独立的视图模板进行本地化,然后在应用代码中通过读取全局配置、用户手动选择、客户端参数(比如 HTML 请求头中的 Accept-Language
字段)、或者域名信息来判断加载那种语言的本地化视图模板,为了简化演示流程,这里我们使用全局配置的方式,也就是我们上面配置文件中设置的 Language
字段。
创建本地化视图模板
首先,我们在 views
目录下新增 en
和 zh
两个子目录,分别用于存放英文视图模板和中文视图模板,然后将原有视图文件移动到 en
目录下,并且在 zh
目录下创建每个视图模板的中文版本,以首页 index.html
为例,对应的中文版本如下:
![e40580127b09effbdbf27583ce2c81df.png](https://i-blog.csdnimg.cn/blog_migrate/e97cb78c2727951e67d43b7e854737e9.jpeg)
其他中文视图模板也是类似,将其中的英文文本统一翻译成中文即可。
通过配置加载本地视图
打开 handlers/helper.go
,在 generateHTML
方法中通过读取全局配置加载对应的本地化视图模板:
func generateHTML(writer http.ResponseWriter, data interface{}, filenames ...string) {
非常简单,不再赘述。
注:同时移除
parseTemplateFiles
方法,并将调用该方法的地方调整为调用generateHTML
以避免维护两个地方的代码。
测试视图本地化
重启应用,访问首页,即可看到页面视图已经都是中文显示了:
![638d7d4fe4681983c8b8b3185c48822d.png](https://i-blog.csdnimg.cn/blog_migrate/2f7aa778271a38cd76d7cb5f992f2a4d.jpeg)
![e55c50f7123baf407cc7668dbcb46c7c.png](https://i-blog.csdnimg.cn/blog_migrate/e41cad82de1f45c93b61ec26c6d90ace.jpeg)
![1fca43f5f97d358d8ab8e972f9a5792d.png](https://i-blog.csdnimg.cn/blog_migrate/23dde64dca4112df9b00bb5d608038a6.jpeg)
![1c1ee80408aeec58def19d5a8592b05f.png](https://i-blog.csdnimg.cn/blog_migrate/92834f831082c25c33e35357ce3fc83c.jpeg)
3、日期时间本地化
看起来都已经 OK 了,不过还有个小问题,那就是日期时间显示还是英文风格的,对应的实现代码在 models/thread.go
中:
func (thread *Thread) CreatedAtDate() string {
我们当然可以直接修改这里来实现类似 2006-01-02 15:04:05
的日期时间格式(该时间节点是 Go 语言元年),不过,学院君这里换一种复杂一点的实现,以便顺手介绍下如何在 Go 视图模板中通过管道模式调用自定义函数。
将自定义函数应用到视图模板
打开 handlers/helper.go
,新增一个格式化日期时间的函数 formatDate
,然后在 generateHTML
方法中将这个函数通过 template.FuncMap
组装后再通过 Funcs
方法应用到视图模板中,这样,就可以在所有视图模板中通过 fdate
别名来调用 formatDate
函数了:
// 生成 HTML 模板
注:由于 Go 语言是静态编译语言,因此无法做到像 PHP 那样和 HTML 一起混合编码,在 HTML 中嵌入 PHP 脚本可以调用任意 PHP 函数和方法,也正是因为 PHP 对 HTML 的天然友好性,从而得以在 Web 编程时代中大放异彩。
调用自定义函数格式化本地日期时间
然后我们在所有视图文件中将群组创建日期渲染调整为如下方式,即通过管道连接符的方式将 .CreatedAt
变量作为参数传入 fdate
并输出返回值:
{{ .CreatedAt | fdate }}
注意这里一定要使用 .CreatedAt
,这个变量才是 time.Time
类型,而 .CreatedAtDate
是字符串类型。
再次重新启动应用,访问首页和群组详情页就可以看到格式化后的本地日期时间格式了:
![6a0290c5cd5135565b8ff3fa757460a4.png](https://i-blog.csdnimg.cn/blog_migrate/82601a9d6ecc60c9680628a32f2ba67f.jpeg)
![761e3f2812285e8313eb49995f3cbffd.png](https://i-blog.csdnimg.cn/blog_migrate/4c509b088aede729075d88324cb6404e.jpeg)
下篇教程,我们将演示如何部署 Go Web 应用作为在线论坛项目系列教程的收尾。
注:本系列教程源码已提交到 Github:https://github.com/nonfu/chitchat,可以参照这里获取完整代码。
推荐阅读
基于 Go 语言开发在线论坛(七):通过单例模式获取全局配置
喜欢本文的朋友,欢迎关注“Go语言中文网”:
Go语言中文网启用微信学习交流群,欢迎加微信:274768166,投稿亦欢迎