aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/gitea.com/macaron/i18n/i18n.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/gitea.com/macaron/i18n/i18n.go')
-rw-r--r--vendor/gitea.com/macaron/i18n/i18n.go227
1 files changed, 227 insertions, 0 deletions
diff --git a/vendor/gitea.com/macaron/i18n/i18n.go b/vendor/gitea.com/macaron/i18n/i18n.go
new file mode 100644
index 0000000000..fd114a5bf7
--- /dev/null
+++ b/vendor/gitea.com/macaron/i18n/i18n.go
@@ -0,0 +1,227 @@
+// Copyright 2014 The Macaron Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+// Package i18n is a middleware that provides app Internationalization and Localization of Macaron.
+package i18n
+
+import (
+ "fmt"
+ "path"
+ "strings"
+
+ "gitea.com/macaron/macaron"
+ "github.com/unknwon/com"
+ "github.com/unknwon/i18n"
+ "golang.org/x/text/language"
+)
+
+const _VERSION = "0.4.0"
+
+func Version() string {
+ return _VERSION
+}
+
+// initLocales initializes language type list and Accept-Language header matcher.
+func initLocales(opt Options) language.Matcher {
+ tags := make([]language.Tag, len(opt.Langs))
+ for i, lang := range opt.Langs {
+ tags[i] = language.Raw.Make(lang)
+ fname := fmt.Sprintf(opt.Format, lang)
+ // Append custom locale file.
+ custom := []interface{}{}
+ customPath := path.Join(opt.CustomDirectory, fname)
+ if com.IsFile(customPath) {
+ custom = append(custom, customPath)
+ }
+
+ var locale interface{}
+ if data, ok := opt.Files[fname]; ok {
+ locale = data
+ } else {
+ locale = path.Join(opt.Directory, fname)
+ }
+
+ err := i18n.SetMessageWithDesc(lang, opt.Names[i], locale, custom...)
+ if err != nil && err != i18n.ErrLangAlreadyExist {
+ panic(fmt.Errorf("fail to set message file(%s): %v", lang, err))
+ }
+ }
+ return language.NewMatcher(tags)
+}
+
+// A Locale describles the information of localization.
+type Locale struct {
+ i18n.Locale
+}
+
+// Language returns language current locale represents.
+func (l Locale) Language() string {
+ return l.Lang
+}
+
+// Options represents a struct for specifying configuration options for the i18n middleware.
+type Options struct {
+ // Suburl of path. Default is empty.
+ SubURL string
+ // Directory to load locale files. Default is "conf/locale"
+ Directory string
+ // File stores actual data of locale files. Used for in-memory purpose.
+ Files map[string][]byte
+ // Custom directory to overload locale files. Default is "custom/conf/locale"
+ CustomDirectory string
+ // Langauges that will be supported, order is meaningful.
+ Langs []string
+ // Human friendly names corresponding to Langs list.
+ Names []string
+ // Default language locale, leave empty to remain unset.
+ DefaultLang string
+ // Locale file naming style. Default is "locale_%s.ini".
+ Format string
+ // Name of language parameter name in URL. Default is "lang".
+ Parameter string
+ // Redirect when user uses get parameter to specify language.
+ Redirect bool
+ // Name that maps into template variable. Default is "i18n".
+ TmplName string
+ // Configuration section name. Default is "i18n".
+ Section string
+ // Domain used for `lang` cookie. Default is ""
+ CookieDomain string
+}
+
+func prepareOptions(options []Options) Options {
+ var opt Options
+ if len(options) > 0 {
+ opt = options[0]
+ }
+
+ if len(opt.Section) == 0 {
+ opt.Section = "i18n"
+ }
+ sec := macaron.Config().Section(opt.Section)
+
+ opt.SubURL = strings.TrimSuffix(opt.SubURL, "/")
+
+ if len(opt.Langs) == 0 {
+ opt.Langs = sec.Key("LANGS").Strings(",")
+ }
+ if len(opt.Names) == 0 {
+ opt.Names = sec.Key("NAMES").Strings(",")
+ }
+ if len(opt.Langs) == 0 {
+ panic("no language is specified")
+ } else if len(opt.Langs) != len(opt.Names) {
+ panic("length of langs is not same as length of names")
+ }
+ i18n.SetDefaultLang(opt.DefaultLang)
+
+ if len(opt.Directory) == 0 {
+ opt.Directory = sec.Key("DIRECTORY").MustString("conf/locale")
+ }
+ if len(opt.CustomDirectory) == 0 {
+ opt.CustomDirectory = sec.Key("CUSTOM_DIRECTORY").MustString("custom/conf/locale")
+ }
+ if len(opt.Format) == 0 {
+ opt.Format = sec.Key("FORMAT").MustString("locale_%s.ini")
+ }
+ if len(opt.Parameter) == 0 {
+ opt.Parameter = sec.Key("PARAMETER").MustString("lang")
+ }
+ if !opt.Redirect {
+ opt.Redirect = sec.Key("REDIRECT").MustBool()
+ }
+ if len(opt.TmplName) == 0 {
+ opt.TmplName = sec.Key("TMPL_NAME").MustString("i18n")
+ }
+
+ return opt
+}
+
+type LangType struct {
+ Lang, Name string
+}
+
+// I18n is a middleware provides localization layer for your application.
+// Paramenter langs must be in the form of "en-US", "zh-CN", etc.
+// Otherwise it may not recognize browser input.
+func I18n(options ...Options) macaron.Handler {
+ opt := prepareOptions(options)
+ m := initLocales(opt)
+ return func(ctx *macaron.Context) {
+ isNeedRedir := false
+ hasCookie := false
+
+ // 1. Check URL arguments.
+ lang := ctx.Query(opt.Parameter)
+
+ // 2. Get language information from cookies.
+ if len(lang) == 0 {
+ lang = ctx.GetCookie("lang")
+ hasCookie = true
+ } else {
+ isNeedRedir = true
+ }
+
+ // Check again in case someone modify by purpose.
+ if !i18n.IsExist(lang) {
+ lang = ""
+ isNeedRedir = false
+ hasCookie = false
+ }
+
+ // 3. Get language information from 'Accept-Language'.
+ // The first element in the list is chosen to be the default language automatically.
+ if len(lang) == 0 {
+ tags, _, _ := language.ParseAcceptLanguage(ctx.Req.Header.Get("Accept-Language"))
+ tag, _, _ := m.Match(tags...)
+ lang = tag.String()
+ isNeedRedir = false
+ }
+
+ curLang := LangType{
+ Lang: lang,
+ }
+
+ // Save language information in cookies.
+ if !hasCookie {
+ ctx.SetCookie("lang", curLang.Lang, 1<<31-1, "/"+strings.TrimPrefix(opt.SubURL, "/"), opt.CookieDomain)
+ }
+
+ restLangs := make([]LangType, 0, i18n.Count()-1)
+ langs := i18n.ListLangs()
+ names := i18n.ListLangDescs()
+ for i, v := range langs {
+ if lang != v {
+ restLangs = append(restLangs, LangType{v, names[i]})
+ } else {
+ curLang.Name = names[i]
+ }
+ }
+
+ // Set language properties.
+ locale := Locale{i18n.Locale{lang}}
+ ctx.Map(locale)
+ ctx.Locale = locale
+ ctx.Data[opt.TmplName] = locale
+ ctx.Data["Tr"] = i18n.Tr
+ ctx.Data["Lang"] = locale.Lang
+ ctx.Data["LangName"] = curLang.Name
+ ctx.Data["AllLangs"] = append([]LangType{curLang}, restLangs...)
+ ctx.Data["RestLangs"] = restLangs
+
+ if opt.Redirect && isNeedRedir {
+ ctx.Redirect(opt.SubURL + ctx.Req.RequestURI[:strings.Index(ctx.Req.RequestURI, "?")])
+ }
+ }
+}