Files
build-web-application-with-…/en/eBook/10.2.md
2014-11-11 14:00:36 -08:00

6.9 KiB
Raw Blame History

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

Various regions of the currency is not the same, is also treated with a date about the details see the following code:

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)
}

Localization views and resources

We may use Locale to show different views that contain different images, css, js and other static resources. So how to deal with these information? First we shall locale to organize file information, see the following file directory Arrangement:

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 to realize where this code:

s1, _ := template.ParseFiles("views" + lang + "index.tpl")
VV.Lang = lang
s1.Execute(os.Stdout, VV)

As for the inside of the resources inside the index.tpl set 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 this view, and the way to localize the resources, we can easily be expanded.

Summary

This section describes how to use and store local resources, sometimes through the conversion function to achieve, sometimes through lang to set up, but eventually through key-value way to store Locale corresponding data when needed remove the corresponding Locale information, if it is a text message directly to the output, if it is the date and time or money, you need to pass fmt.Printf or other formatting function to deal with, and for different views and resources Locale is the most simple, as long as increase in the path which can be achieved lang.