support 中文繁体

This commit is contained in:
lealife
2016-03-19 14:05:09 +08:00
parent f5538218bd
commit 2aa3f5a654
51 changed files with 1684 additions and 311 deletions

View File

@ -3,6 +3,7 @@ package controllers
import (
"encoding/json"
"github.com/leanote/leanote/app/info"
"github.com/leanote/leanote/app/lea/i18n"
"github.com/revel/revel"
"gopkg.in/mgo.v2/bson"
// . "github.com/leanote/leanote/app/lea"
@ -181,13 +182,17 @@ func (c BaseController) E404() revel.Result {
// 设置本地
func (c BaseController) SetLocale() string {
locale := string(c.Request.Locale) // zh-CN
// lang := locale
// if strings.Contains(locale, "-") {
// pos := strings.Index(locale, "-")
// lang = locale[0:pos]
// }
// if lang != "zh" && lang != "en" {
// lang = "en"
// }
lang := locale
if strings.Contains(locale, "-") {
pos := strings.Index(locale, "-")
lang = locale[0:pos]
}
if lang != "zh" && lang != "en" && lang != "fr" && lang != "pt" {
lang = "en"
if !i18n.HasLang(locale) {
lang = i18n.GetDefaultLang()
}
c.RenderArgs["locale"] = lang
c.RenderArgs["siteUrl"] = configService.GetSiteUrl()

View File

@ -1,94 +0,0 @@
package main
import (
"bufio"
"encoding/json"
"fmt"
"os"
"strings"
)
// convert revel msg to js msg
var msgBasePath = "/Users/life/Documents/Go/package2/src/github.com/leanote/leanote/messages/"
var targetBasePath = "/Users/life/Documents/Go/package2/src/github.com/leanote/leanote/public/js/i18n/"
func parse(filename string) {
file, err := os.Open(msgBasePath + filename)
reader := bufio.NewReader(file)
msg := map[string]string{}
if err != nil {
fmt.Println(err)
return
}
for true {
line, _, err := reader.ReadLine()
if err != nil {
break
}
if len(line) == 0 {
continue
}
// 对每一行进行处理
if line[0] == '#' || line[1] == '#' {
continue
}
lineStr := string(line)
// 找到第一个=位置
pos := strings.Index(lineStr, "=")
if pos < 0 {
continue
}
key := string(line[0:pos])
value := string(line[pos+1:])
// fmt.Println(lineStr)
// fmt.Println(value)
msg[key] = value
}
// JSON
b, _ := json.Marshal(msg)
str := string(b)
fmt.Println(str)
targetName := targetBasePath + filename + ".js"
file2, err2 := os.OpenFile(targetName, os.O_RDWR|os.O_CREATE, 0644)
if err2 != nil {
file2, err2 = os.Create(targetName)
}
file2.WriteString("var MSG = " + str + ";" + `
function getMsg(key, data) {
var msg = MSG[key]
if(msg) {
if(data) {
if(!isArray(data)) {
data = [data];
}
for(var i = 0; i < data.length; ++i) {
msg = msg.replace("%s", data[i]);
}
}
return msg;
}
return key;
}`)
}
// 生成js的i18n文件
func main() {
parse("msg.en")
parse("msg.zh")
parse("msg.fr")
parse("msg.pt")
parse("blog.zh")
parse("blog.en")
parse("blog.fr")
parse("blog.pt")
}

View File

@ -10,6 +10,7 @@ import (
"github.com/leanote/leanote/app/db"
. "github.com/leanote/leanote/app/lea"
_ "github.com/leanote/leanote/app/lea/binder"
"github.com/leanote/leanote/app/lea/i18n"
"github.com/leanote/leanote/app/lea/route"
"github.com/leanote/leanote/app/service"
"github.com/revel/revel"
@ -38,9 +39,10 @@ func init() {
// session.SessionFilter, // leanote session
// session.MSessionFilter, // leanote memcache session
revel.FlashFilter, // Restore and write the flash cookie.
revel.ValidationFilter, // Restore kept validation errors and save new ones from cookie.
revel.I18nFilter, // Resolve the requested language
revel.FlashFilter, // Restore and write the flash cookie.
revel.ValidationFilter, // Restore kept validation errors and save new ones from cookie.
// revel.I18nFilter, // Resolve the requested language
i18n.I18nFilter, // Resolve the requested language by leanote
revel.InterceptorFilter, // Run interceptors around the action.
revel.CompressFilter, // Compress the result.
revel.ActionInvoker, // Invoke the action.
@ -180,10 +182,18 @@ func init() {
return template.HTML(tagStr)
}
revel.TemplateFuncs["msg"] = func(renderArgs map[string]interface{}, message string, args ...interface{}) template.HTML {
str, ok := renderArgs[revel.CurrentLocaleRenderArg].(string)
if !ok {
return ""
}
return template.HTML(i18n.Message(str, message, args...))
}
// 不用revel的msg
revel.TemplateFuncs["leaMsg"] = func(renderArgs map[string]interface{}, key string) template.HTML {
locale, _ := renderArgs[revel.CurrentLocaleRenderArg].(string)
str := revel.Message(locale, key)
str := i18n.Message(locale, key)
if strings.HasPrefix(str, "???") {
str = key
}
@ -392,9 +402,9 @@ func init() {
*/
/*
{{range $i := N 1 10}}
<div>{{$i}}</div>
{{end}}
{{range $i := N 1 10}}
<div>{{$i}}</div>
{{end}}
*/
revel.TemplateFuncs["N"] = func(start, end int) (stream chan int) {
stream = make(chan int)

208
app/lea/i18n/i18n.go Normal file
View File

@ -0,0 +1,208 @@
package i18n
import (
"fmt"
"github.com/revel/revel"
"github.com/robfig/config"
"os"
"path/filepath"
"regexp"
"strings"
)
const (
CurrentLocaleRenderArg = "currentLocale" // The key for the current locale render arg value
messageFilesDirectory = "messages"
messageFilePattern = `^\w+\.[a-zA-Z]{2}\-[a-zA-Z]{2}$`
unknownValueFormat = "??? %s ???"
defaultLanguageOption = "i18n.default_language"
localeCookieConfigKey = "i18n.cookie"
)
var (
// All currently loaded message configs.
// en-us, zh-cn, zh-hk ->
messages map[string]*config.Config
)
func GetAllLangMessages() map[string]*config.Config {
return messages
}
func HasLang(lang string) bool {
_, ok := messages[lang]
return ok
}
func GetDefaultLang() string {
lang, _ := revel.Config.String(defaultLanguageOption)
return lang
}
// Return all currently loaded message languages.
func MessageLanguages() []string {
languages := make([]string, len(messages))
i := 0
for language, _ := range messages {
languages[i] = language
i++
}
return languages
}
// Perform a message look-up for the given locale and message using the given arguments.
//
// When either an unknown locale or message is detected, a specially formatted string is returned.
func Message(locale, message string, args ...interface{}) string {
language, region := parseLocale(locale)
langAndRegion := language + "-" + region
// revel.TRACE.Println(langAndRegion + " 怎么回事")
messageConfig, knownLanguage := messages[langAndRegion]
if !knownLanguage {
// revel.TRACE.Printf("Unsupported language for locale '%s' and message '%s', trying default language", locale, message)
if defaultLanguage, found := revel.Config.String(defaultLanguageOption); found {
// revel.TRACE.Printf("Using default language '%s'", defaultLanguage)
messageConfig, knownLanguage = messages[defaultLanguage]
if !knownLanguage {
// WARN.Printf("Unsupported default language for locale '%s' and message '%s'", defaultLanguage, message)
return fmt.Sprintf(unknownValueFormat, message)
}
} else {
// WARN.Printf("Unable to find default language option (%s); messages for unsupported locales will never be translated", defaultLanguageOption)
return fmt.Sprintf(unknownValueFormat, message)
}
}
// This works because unlike the goconfig documentation suggests it will actually
// try to resolve message in DEFAULT if it did not find it in the given section.
value, error := messageConfig.String(region, message)
if error != nil {
// WARN.Printf("Unknown message '%s' for locale '%s'", message, locale)
return fmt.Sprintf(unknownValueFormat, message)
}
if len(args) > 0 {
// revel.TRACE.Printf("Arguments detected, formatting '%s' with %v", value, args)
value = fmt.Sprintf(value, args...)
}
return value
}
func parseLocale(locale string) (language, region string) {
if strings.Contains(locale, "-") {
languageAndRegion := strings.Split(locale, "-")
return languageAndRegion[0], languageAndRegion[1]
}
return locale, ""
}
// Recursively read and cache all available messages from all message files on the given path.
func loadMessages(path string) {
messages = make(map[string]*config.Config)
if error := filepath.Walk(path, loadMessageFile); error != nil && !os.IsNotExist(error) {
// ERROR.Println("Error reading messages files:", error)
}
}
// Load a single message file
func loadMessageFile(path string, info os.FileInfo, osError error) error {
if osError != nil {
return osError
}
if info.IsDir() {
return nil
}
if matched, _ := regexp.MatchString(messageFilePattern, info.Name()); matched {
if config, error := parseMessagesFile(path); error != nil {
return error
} else {
locale := parseLocaleFromFileName(info.Name())
// revel.TRACE.Print(locale + "----locale")
// If we have already parsed a message file for this locale, merge both
if _, exists := messages[locale]; exists {
messages[locale].Merge(config)
revel.TRACE.Printf("Successfully merged messages for locale '%s'", locale)
} else {
messages[locale] = config
}
revel.TRACE.Println("Successfully loaded messages from file", info.Name())
}
} else {
revel.TRACE.Printf("Ignoring file %s because it did not have a valid extension", info.Name())
}
return nil
}
func parseMessagesFile(path string) (messageConfig *config.Config, error error) {
messageConfig, error = config.ReadDefault(path)
return
}
func parseLocaleFromFileName(file string) string {
extension := filepath.Ext(file)[1:]
return strings.ToLower(extension)
}
func init() {
revel.OnAppStart(func() {
loadMessages(filepath.Join(revel.BasePath, messageFilesDirectory))
})
}
func I18nFilter(c *revel.Controller, fc []revel.Filter) {
if foundCookie, cookieValue := hasLocaleCookie(c.Request); foundCookie {
revel.TRACE.Printf("Found locale cookie value: %s", cookieValue)
setCurrentLocaleControllerArguments(c, cookieValue)
} else if foundHeader, headerValue := hasAcceptLanguageHeader(c.Request); foundHeader {
revel.TRACE.Printf("Found Accept-Language header value: %s", headerValue)
setCurrentLocaleControllerArguments(c, headerValue)
} else {
revel.TRACE.Println("Unable to find locale in cookie or header, using empty string")
setCurrentLocaleControllerArguments(c, "")
}
fc[0](c, fc[1:])
}
// Set the current locale controller argument (CurrentLocaleControllerArg) with the given locale.
func setCurrentLocaleControllerArguments(c *revel.Controller, locale string) {
c.Request.Locale = locale
c.RenderArgs[CurrentLocaleRenderArg] = locale
}
// Determine whether the given request has valid Accept-Language value.
//
// Assumes that the accept languages stored in the request are sorted according to quality, with top
// quality first in the slice.
func hasAcceptLanguageHeader(request *revel.Request) (bool, string) {
if request.AcceptLanguages != nil && len(request.AcceptLanguages) > 0 {
return true, request.AcceptLanguages[0].Language
}
return false, ""
}
// Determine whether the given request has a valid language cookie value.
func hasLocaleCookie(request *revel.Request) (bool, string) {
if request != nil && request.Cookies() != nil {
name := revel.Config.StringDefault(localeCookieConfigKey, revel.CookiePrefix+"_LANG")
if cookie, error := request.Cookie(name); error == nil {
return true, cookie.Value
} else {
revel.TRACE.Printf("Unable to read locale cookie with name '%s': %s", name, error.Error())
}
}
return false, ""
}

View File

@ -41,7 +41,8 @@ function log(o) {
<a data-lang="en-us">English</a>
<a data-lang="fr-fr">Français</a>
<a data-lang="zh-cn">简体中文</a>
<a data-lang="pt-br">Portugu&ecirc;s</a>
<a data-lang="zh-hk">繁体中文</a>
<a data-lang="pt-pt">Portugu&ecirc;s</a>
</div>
<ul class="nav navbar-nav navbar-left">