为了适应经济的全球一体化,做为开发者,咱们须要开发出支持多国语言、国际化的Web应用,即一样的页面在不一样的语言环境下须要显示不一样的效果,也就是说应用程序在运行时可以根据请求所来自的地域与语言的不一样而显示不一样的用户界面。这样,当须要在应用程序中添加对新的语言的支持时,无需修改应用程序的代码,只须要增长语言包便可实现。javascript
国际化与本地化(Internationalization and localization,一般用i18n和L10N表示),国际化是将针对某个地区设计的程序进行重构,以使它可以在更多地区使用,本地化是指在一个面向国际化的程序中增长对新地区的支持。css
所谓的国际化:就是根据特定的locale信息,提取与之相应的字符串或其它一些东西(好比时间和货币的格式)等等。这涉及到三个问题:java
一、如何肯定locale。jquery
二、如何保存与locale相关的字符串或其它信息。git
三、如何根据locale提取字符串和其它相应的信息。github
什么是Localegolang
Locale是一组描述世界上某一特定区域文本格式和语言习惯的设置的集合。locale名一般由三个部分组成:第一部分,是一个强制性的,表示语言的缩写,例如"en"表示英文或"zh"表示中文。第二部分,跟在一个下划线以后,是一个可选的国家说明符,用于区分讲同一种语言的不一样国家,例如"en_US"表示美国英语,而"en_UK"表示英国英语。最后一部分,跟在一个句点以后,是可选的字符集说明符,例如"zh_CN.gb2312"表示中国使用gb2312字符集。web
前面咱们介绍了如何设置Locale,设置好Locale以后咱们须要解决的问题就是如何存储相应的Locale对应的信息呢?这里面的信息包括:文本信息、时间和日期、货币值、图片、包含文件以及视图等资源。那么接下来咱们将对这些信息一一进行介绍,Go语言中咱们把这些格式信息存储在JSON中,而后经过合适的方式展示出来json
文本信息是编写Web应用中最经常使用到的,也是本地化资源中最多的信息,想要以适合本地语言的方式来显示文本信息,可行的一种方案是:创建须要的语言相应的map来维护一个key-value的关系,在输出以前按需从适合的map中去获取相应的文本。bootstrap
有些时候仅是key-value替换是不能知足须要的,例如"I am 30 years old",中文表达是"我今年30岁了",而此处的30是一个变量,该怎么办呢?这个时候,咱们能够结合fmt.Printf函数来实现,请看下面的代码:
en["how old"] ="I am %d years old" cn["how old"] ="我今年%d岁了" fmt.Printf(msg(lang, "how old"), 30)
由于时区的关系,同一时刻,在不一样的地区,表示是不同的,并且由于Locale的关系,时间格式也不尽相同,例如中文环境下可能显示:2012年10月24日 星期三 23时11分13秒 CST,而在英文环境下可能显示:Wed Oct 24 23:11:13 CST 2012。这里面咱们须要解决两点:
咱们可能会根据Locale的不一样来展现视图,这些视图包含不一样的图片、css、js等各类静态资源。那么应如何来处理这些信息呢?首先咱们应按locale来组织文件信息,请看下面的文件目录安排:
views |--en //英文模板 |--images //存储图片信息 |--js //存储JS文件 |--css //存储css文件 index.tpl //用户首页 login.tpl //登录首页 |--zh-CN //中文模板 |--images |--js |--css index.tpl login.tpl
有了这个目录结构后咱们就能够在渲染的地方这样来实现代码:
s1, _ := template.ParseFiles("views/"+lang+"/index.tpl") VV.Lang=lang s1.Execute(os.Stdout, VV)
而对于里面的index.tpl里面的资源设置以下:
// js文件 <script type="text/javascript" src="views/{{.Lang}}/js/jquery/jquery-1.8.0.min.js"></script> // css文件 <link href="views/{{.Lang}}/css/bootstrap-responsive.min.css" rel="stylesheet"> // 图片文件 <img src="views/{{.Lang}}/images/btn.png">
采用这种方式来本地化视图以及资源时,咱们就能够很容易的进行扩展了。
使用及存储本地资源,有时须要经过转换函数来实现,有时经过lang来设置,可是最终都是经过key-value的方式来存储Locale对应的数据,在须要时取出相应于Locale的信息后,若是是文本信息就直接输出,若是是时间日期或者货币,则须要先经过fmt.Printf或其余格式化函数来处理,而对于不一样Locale的视图和资源则是最简单的,只要在路径里面增长lang就能够实现了。
前面介绍了如何处理本地化资源,即Locale一个相应的配置文件,那么若是处理多个的本地化资源呢?而对于一些咱们常常用到的例如:简单的文本翻译、时间日期、数字等若是处理呢?本小节将一一解决这些问题。
在开发一个应用的时候,首先咱们要决定是只支持一种语言,仍是多种语言,若是要支持多种语言,咱们则须要制定一个组织结构,以方便未来更多语言的添加。在此咱们设计以下:Locale有关的文件放置在config/locales下,假设你要支持中文和英文,那么你须要在这个文件夹下放置en.json和zh.json。
上面咱们介绍了如何自动加载自定义语言包,其实go-i18n库已经预加载了不少默认的格式信息.
上面实现了多个语言包的管理和加载,而一些函数的实现是基于逻辑层的,例如:"Tr.Translate"、"Tr.Time"、"Tr.Money"等,虽然咱们在逻辑层能够利用这些函数把须要的参数进行转换后在模板层渲染的时候直接输出,可是若是咱们想在模版层直接使用这些函数该怎么实现呢?不知你是否还记得,在前面介绍模板的时候说过:Go语言的模板支持自定义模板函数,下面是咱们实现的方便操做的mapfunc:
文本信息
文本信息调用Tr.Translate来实现相应的信息转换,mapFunc的实现以下:
func I18nT(args ...interface{}) string { ok := false var s string if len(args) == 1 { s, ok = args[0].(string) } if !ok { s = fmt.Sprint(args...) } return Tr.Translate(s) }
注册函数以下:
t.Funcs(template.FuncMap{"T": I18nT})
模板中使用以下:
{{.V.Submit | T}}
如何实现一个多语言包的Web应用,经过自定义语言包咱们能够方便的实现多语言,并且经过配置文件可以很是方便的扩充多语言,默认状况下,go-i18n会自定加载一些公共的配置信息,例如时间、货币等,咱们就能够很是方便的使用,同时为了支持在模板中使用这些函数,也实现了相应的模板函数,这样就容许咱们在开发Web应用的时候直接在模板中经过pipeline的方式来操做多语言包。