Merging other languages
This commit is contained in:
274
en/10.2.md
274
en/10.2.md
@@ -1,134 +1,140 @@
|
||||
# 10.2 本地化资源
|
||||
前面小节我们介绍了如何设置Locale,设置好Locale之后我们需要解决的问题就是如何存储相应的Locale对应的信息呢?这里面的信息包括:文本信息、时间和日期、货币值、图片、包含文件以及视图等资源。那么接下来我们将对这些信息一一进行介绍,Go语言中我们把这些格式信息存储在JSON中,然后通过合适的方式展现出来。(接下来以中文和英文两种语言对比举例,存储格式文件en.json和zh-CN.json)
|
||||
## 本地化文本消息
|
||||
文本信息是编写Web应用中最常用到的,也是本地化资源中最多的信息,想要以适合本地语言的方式来显示文本信息,可行的一种方案是:建立需要的语言相应的map来维护一个key-value的关系,在输出之前按需从适合的map中去获取相应的文本,如下是一个简单的示例:
|
||||
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
var locales map[string]map[string]string
|
||||
|
||||
func main() {
|
||||
locales = make(map[string]map[string]string, 2)
|
||||
en := make(map[string]string, 10)
|
||||
en["pea"] = "pea"
|
||||
en["bean"] = "bean"
|
||||
locales["en"] = en
|
||||
cn := make(map[string]string, 10)
|
||||
cn["pea"] = "豌豆"
|
||||
cn["bean"] = "毛豆"
|
||||
locales["zh-CN"] = cn
|
||||
lang := "zh-CN"
|
||||
fmt.Println(msg(lang, "pea"))
|
||||
fmt.Println(msg(lang, "bean"))
|
||||
}
|
||||
|
||||
func msg(locale, key string) string {
|
||||
if v, ok := locales[locale]; ok {
|
||||
if v2, ok := v[key]; ok {
|
||||
return v2
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
|
||||
上面示例演示了不同locale的文本翻译,实现了中文和英文对于同一个key显示不同语言的实现,上面实现了中文的文本消息,如果想切换到英文版本,只需要把lang设置为en即可。
|
||||
|
||||
有些时候仅是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)
|
||||
|
||||
上面的示例代码仅用以演示内部的实现方案,而实际数据是存储在JSON里面的,所以我们可以通过`json.Unmarshal`来为相应的map填充数据。
|
||||
|
||||
## 本地化日期和时间
|
||||
因为时区的关系,同一时刻,在不同的地区,表示是不一样的,而且因为Locale的关系,时间格式也不尽相同,例如中文环境下可能显示:`2012年10月24日 星期三 23时11分13秒 CST`,而在英文环境下可能显示:`Wed Oct 24 23:11:13 CST 2012`。这里面我们需要解决两点:
|
||||
|
||||
1. 时区问题
|
||||
2. 格式问题
|
||||
|
||||
$GOROOT/lib/time包中的timeinfo.zip含有locale对应的时区的定义,为了获得对应于当前locale的时间,我们应首先使用`time.LoadLocation(name string)`获取相应于地区的locale,比如`Asia/Shanghai`或`America/Chicago`对应的时区信息,然后再利用此信息与调用`time.Now`获得的Time对象协作来获得最终的时间。详细的请看下面的例子(该例子采用上面例子的一些变量):
|
||||
|
||||
en["time_zone"]="America/Chicago"
|
||||
cn["time_zone"]="Asia/Shanghai"
|
||||
|
||||
loc,_:=time.LoadLocation(msg(lang,"time_zone"))
|
||||
t:=time.Now()
|
||||
t = t.In(loc)
|
||||
fmt.Println(t.Format(time.RFC3339))
|
||||
|
||||
我们可以通过类似处理文本格式的方式来解决时间格式的问题,举例如下:
|
||||
|
||||
en["date_format"]="%Y-%m-%d %H:%M:%S"
|
||||
cn["date_format"]="%Y年%m月%d日 %H时%M分%S秒"
|
||||
|
||||
fmt.Println(date(msg(lang,"date_format"),t))
|
||||
|
||||
func date(fomate string,t time.Time) string{
|
||||
year, month, day = t.Date()
|
||||
hour, min, sec = t.Clock()
|
||||
//解析相应的%Y %m %d %H %M %S然后返回信息
|
||||
//%Y 替换成2012
|
||||
//%m 替换成10
|
||||
//%d 替换成24
|
||||
}
|
||||
|
||||
## 本地化货币值
|
||||
各个地区的货币表示也不一样,处理方式也与日期差不多,细节请看下面代码:
|
||||
|
||||
en["money"] ="USD %d"
|
||||
cn["money"] ="¥%d元"
|
||||
|
||||
fmt.Println(date(msg(lang,"date_format"),100))
|
||||
|
||||
func money_format(fomate string,money int64) string{
|
||||
return fmt.Sprintf(fomate,money)
|
||||
}
|
||||
|
||||
|
||||
## 本地化视图和资源
|
||||
我们可能会根据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/{{.VV.Lang}}/js/jquery/jquery-1.8.0.min.js"></script>
|
||||
// css文件
|
||||
<link href="views/{{.VV.Lang}}/css/bootstrap-responsive.min.css" rel="stylesheet">
|
||||
// 图片文件
|
||||
<img src="views/{{.VV.Lang}}/images/btn.png">
|
||||
|
||||
采用这种方式来本地化视图以及资源时,我们就可以很容易的进行扩展了。
|
||||
|
||||
## 总结
|
||||
本小节介绍了如何使用及存储本地资源,有时需要通过转换函数来实现,有时通过lang来设置,但是最终都是通过key-value的方式来存储Locale对应的数据,在需要时取出相应于Locale的信息后,如果是文本信息就直接输出,如果是时间日期或者货币,则需要先通过`fmt.Printf`或其他格式化函数来处理,而对于不同Locale的视图和资源则是最简单的,只要在路径里面增加lang就可以实现了。
|
||||
|
||||
## links
|
||||
* [目录](<preface.md>)
|
||||
* 上一节: [设置默认地区](<10.1.md>)
|
||||
* 下一节: [国际化站点](<10.3.md>)
|
||||
# 10.2 Localized Resources
|
||||
|
||||
The previous section described how to set locales. After the locale has been set, we then need to address the problem of storing the information corresponding to specific locales. This information can include: textual content, time and date, currency values , pictures, specific files and other view resources. In Go, all of this contextual information is stored in JSON format on our backend, to be called upon and injected into our views when users from specific regions visit our website. For example, English and Chinese content would be stored in en.json and zh-CN.json files, respectively.
|
||||
|
||||
## Localized textual content
|
||||
|
||||
Plain text is the most common way of representing information in web applications, and the bulk of your localized content will likely take this form. The goal is to provide textual content that is both idiomatic to regional expressions and feels natural for foreign users of your site. One solution is to create a nested map of locales, native language strings and their local counterparts. When clients request pages with some textual content, we first check their desired locale, then retrieve the corresponding strings from the appropriate map. The following snippet is a simple example of this process:
|
||||
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
var locales map[string]map[string]string
|
||||
|
||||
func main() {
|
||||
locales = make(map[string]map[string]string, 2)
|
||||
en := make(map[string]string, 10)
|
||||
en["pea"] = "pea"
|
||||
en["bean"] = "bean"
|
||||
locales["en"] = en
|
||||
cn := make(map[string]string, 10)
|
||||
cn["pea"] = "豌豆"
|
||||
cn["bean"] = "毛豆"
|
||||
locales["zh-CN"] = cn
|
||||
lang := "zh-CN"
|
||||
fmt.Println(msg(lang, "pea"))
|
||||
fmt.Println(msg(lang, "bean"))
|
||||
}
|
||||
|
||||
func msg(locale, key string) string {
|
||||
if v, ok := locales[locale]; ok {
|
||||
if v2, ok := v[key]; ok {
|
||||
return v2
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
The above example sets up maps of translated strings for different locales (in this case, the Chinese and English locales). We map our `cn` translations to the same English language keys so that we can reconstruct our English text message in Chinese. If we wanted to switch our text to any other locale we may have implemented, it'd be a simple matter of setting one `lang` variable.
|
||||
|
||||
Simple key-value substitutions can sometimes be inadequate for our needs. For example, if we had a phrase such as "I am 30 years old" where 30 is a variable, how would we localize it? In cases like these, we can combine use the `fmt.Printf` function to achieve the desired result:
|
||||
|
||||
en["how old"] = "I am %d years old"
|
||||
cn["how old"] = "我今年%d岁了"
|
||||
|
||||
fmt.Printf(msg(lang, "how old"), 30)
|
||||
|
||||
The example code above is only for the purpose of demonstration; actual locale data is typically stored in JSON format in our database, allowing us to execute a simple `json.Unmarshal` to populate map locales with our string translations.
|
||||
|
||||
## Localized date and time
|
||||
|
||||
Because of our time zone conventions, the time in one region of the world can be different than the time in another region. Similarly, the way in which time is represented can also vary from locale to locale. For example, a Chinese environment may read `2012年10月24日 星期三 23时11分13秒 CST`, while in English, it might be: `Wed Oct 24 23:11:13 CST 2012`. Not only are there variations in language, but there are differences in formatting also. So, when it comes to localizing dates and times, we need to address the following two points:
|
||||
|
||||
1. time zones
|
||||
2. formatting issues
|
||||
|
||||
The `$GOROOT/lib/time/package/timeinfo.zip` directory contains locales corresponding to time zone definitions. In order to obtain the time corresponding to a user's current locale, we should first use `time.LoadLocation(name string)` to get a Location object corresponding to our locale, passing in a string representing the locale such as `Asia/Shanghai` or `America/Chicago`. We can then use this Location object in conjunction with a Time object (obtained by calling `time.Now`) to get the final time using the Time object's `In` method. A detailed look at this process can be seen below (this example uses some of the variables from the example above):
|
||||
|
||||
en["time_zone"] = "America/Chicago"
|
||||
cn["time_zone"] = "Asia/Shanghai"
|
||||
|
||||
loc, _ := time.LoadLocation(msg(lang, "time_zone"))
|
||||
t := time.Now()
|
||||
t = t.In(loc)
|
||||
fmt.Println(t.Format(time.RFC3339))
|
||||
|
||||
We can handle text formatting in a similar way to solve our time formatting problem:
|
||||
|
||||
en["date_format"]="%Y-%m-%d %H:%M:%S"
|
||||
cn["date_format"]="%Y年%m月%d日 %H时%M分%S秒"
|
||||
|
||||
fmt.Println(date(msg(lang,"date_format"),t))
|
||||
|
||||
func date(fomat string, t time.Time) string{
|
||||
year, month, day = t.Date()
|
||||
hour, min, sec = t.Clock()
|
||||
//Parsing the corresponding %Y%m%d%H%M%S and then returning the information
|
||||
//%Y replaced by 2012
|
||||
//%m replaced by 10
|
||||
//%d replaced by 24
|
||||
}
|
||||
|
||||
## Localized currency value
|
||||
|
||||
Obviously, currency differs from region to region also. We can treat it the same way we treated our dates:
|
||||
|
||||
en["money"] ="USD %d"
|
||||
cn["money"] ="¥%d元"
|
||||
|
||||
fmt.Println(date(msg(lang,"date_format"),100))
|
||||
|
||||
func money_format(fomat string, money int64) string{
|
||||
return fmt.Sprintf(fomat, money)
|
||||
}
|
||||
|
||||
|
||||
## Localization of views and resources
|
||||
|
||||
We can serve customized views with different images, css, js and other static resources depending on the current locale. One way to accomplish this is by organizing these files into their respective locales. Here's an example:
|
||||
|
||||
views
|
||||
|--en //English Templates
|
||||
|--images //store picture information
|
||||
|--js //JS files
|
||||
|--css //CSS files
|
||||
index.tpl //User Home
|
||||
login.tpl //Log Home
|
||||
|--zh-CN //Chinese Templates
|
||||
|--images
|
||||
|--js
|
||||
|--css
|
||||
index.tpl
|
||||
login.tpl
|
||||
|
||||
With this directory structure, we can render locale-specific views like so:
|
||||
|
||||
s1, _ := template.ParseFiles("views" + lang + "index.tpl")
|
||||
VV.Lang = lang
|
||||
s1.Execute(os.Stdout, VV)
|
||||
|
||||
The resources referenced in the `index.tpl` file can be dealt with as follows:
|
||||
|
||||
// js file
|
||||
<script type="text/javascript" src="views/{{.VV.Lang}}/js/jquery/jquery-1.8.0.min.js"></script>
|
||||
// css file
|
||||
<link href="views/{{.VV.Lang}}/css/bootstrap-responsive.min.css" rel="stylesheet">
|
||||
// Picture files
|
||||
<img src="views/{{.VV.Lang}}/images/btn.png">
|
||||
|
||||
With dynamic views and the way we've localized our resources, we will be able to add more locales without much effort.
|
||||
|
||||
## Summary
|
||||
|
||||
This section described how to use and store local resources. We learned that we can use conversion functions and string interpolation for this, and saw that maps can be an effective way of storing locale-specific data. For the latter, we could simply extract the corresponding locale information when needed -if it was textual content we desired, our mapped translations and idioms could be piped directly to the output. If it was something more sophisticated like time or currency, we simply used the `fmt.Printf` function to format it before-hand. Localizing our views and resources was the easiest case, and simply involved organizing our files into their respective locales, then referencing them from their locale relative paths.
|
||||
|
||||
## Links
|
||||
|
||||
- [Directory](preface.md)
|
||||
- Previous section: [Time zone](10.1.md)
|
||||
- Next section: [[International sites](10.3.md)
|
||||
|
||||
Reference in New Issue
Block a user