support 中文繁体
This commit is contained in:
@ -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()
|
||||
|
@ -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")
|
||||
}
|
24
app/init.go
24
app/init.go
@ -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
208
app/lea/i18n/i18n.go
Normal 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, ""
|
||||
}
|
@ -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ês</a>
|
||||
<a data-lang="zh-hk">繁体中文</a>
|
||||
<a data-lang="pt-pt">Português</a>
|
||||
</div>
|
||||
|
||||
<ul class="nav navbar-nav navbar-left">
|
||||
|
Reference in New Issue
Block a user