github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/Unknwon/i18n/i18n.go (about) 1 // Copyright 2013 Unknwon 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"): you may 4 // not use this file except in compliance with the License. You may obtain 5 // a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 // License for the specific language governing permissions and limitations 13 // under the License. 14 15 // Package i18n is for app Internationalization and Localization. 16 package i18n 17 18 import ( 19 "errors" 20 "fmt" 21 "reflect" 22 "strings" 23 24 "github.com/vodka-contrib/i18n/libraries/ini.v1" 25 ) 26 27 var ( 28 ErrLangAlreadyExist = errors.New("Lang already exists") 29 30 locales = &localeStore{store: make(map[string]*locale)} 31 ) 32 33 type locale struct { 34 id int 35 lang string 36 langDesc string 37 message *ini.File 38 } 39 40 type localeStore struct { 41 langs []string 42 langDescs []string 43 store map[string]*locale 44 defaultLang string 45 } 46 47 // Get target language string 48 func (d *localeStore) Get(lang, section, format string) (string, bool) { 49 if locale, ok := d.store[lang]; ok { 50 if key, err := locale.message.Section(section).GetKey(format); err == nil { 51 return key.Value(), true 52 } 53 } 54 55 if len(d.defaultLang) > 0 && lang != d.defaultLang { 56 return d.Get(d.defaultLang, section, format) 57 } 58 59 return "", false 60 } 61 62 func (d *localeStore) Add(lc *locale) bool { 63 if _, ok := d.store[lc.lang]; ok { 64 return false 65 } 66 67 lc.id = len(d.langs) 68 d.langs = append(d.langs, lc.lang) 69 d.langDescs = append(d.langDescs, lc.langDesc) 70 d.store[lc.lang] = lc 71 72 return true 73 } 74 75 func (d *localeStore) Reload(langs ...string) (err error) { 76 if len(langs) == 0 { 77 for _, lc := range d.store { 78 if err = lc.message.Reload(); err != nil { 79 return err 80 } 81 } 82 } else { 83 for _, lang := range langs { 84 if lc, ok := d.store[lang]; ok { 85 if err = lc.message.Reload(); err != nil { 86 return err 87 } 88 } 89 } 90 } 91 return nil 92 } 93 94 // SetDefaultLang sets default language which is a indicator that 95 // when target language is not found, try find in default language again. 96 func SetDefaultLang(lang string) { 97 locales.defaultLang = lang 98 } 99 100 // ReloadLangs reloads locale files. 101 func ReloadLangs(langs ...string) error { 102 return locales.Reload(langs...) 103 } 104 105 // Count returns number of languages that are registered. 106 func Count() int { 107 return len(locales.langs) 108 } 109 110 // ListLangs returns list of all locale languages. 111 func ListLangs() []string { 112 langs := make([]string, len(locales.langs)) 113 copy(langs, locales.langs) 114 return langs 115 } 116 117 func ListLangDescs() []string { 118 langDescs := make([]string, len(locales.langDescs)) 119 copy(langDescs, locales.langDescs) 120 return langDescs 121 } 122 123 // IsExist returns true if given language locale exists. 124 func IsExist(lang string) bool { 125 _, ok := locales.store[lang] 126 return ok 127 } 128 129 // IndexLang returns index of language locale, 130 // it returns -1 if locale not exists. 131 func IndexLang(lang string) int { 132 if lc, ok := locales.store[lang]; ok { 133 return lc.id 134 } 135 return -1 136 } 137 138 // GetLangByIndex return language by given index. 139 func GetLangByIndex(index int) string { 140 if index < 0 || index >= len(locales.langs) { 141 return "" 142 } 143 return locales.langs[index] 144 } 145 146 func GetDescriptionByIndex(index int) string { 147 if index < 0 || index >= len(locales.langDescs) { 148 return "" 149 } 150 151 return locales.langDescs[index] 152 } 153 154 func GetDescriptionByLang(lang string) string { 155 return GetDescriptionByIndex(IndexLang(lang)) 156 } 157 158 func SetMessageWithDesc(lang, langDesc string, localeFile interface{}, otherLocaleFiles ...interface{}) error { 159 message, err := ini.Load(localeFile, otherLocaleFiles...) 160 if err == nil { 161 message.BlockMode = false 162 lc := new(locale) 163 lc.lang = lang 164 lc.langDesc = langDesc 165 lc.message = message 166 167 if locales.Add(lc) == false { 168 return ErrLangAlreadyExist 169 } 170 } 171 return err 172 } 173 174 // SetMessage sets the message file for localization. 175 func SetMessage(lang string, localeFile interface{}, otherLocaleFiles ...interface{}) error { 176 return SetMessageWithDesc(lang, lang, localeFile, otherLocaleFiles...) 177 } 178 179 // Locale represents the information of localization. 180 type Locale struct { 181 Lang string 182 } 183 184 // Tr translates content to target language. 185 func (l Locale) Tr(format string, args ...interface{}) string { 186 return Tr(l.Lang, format, args...) 187 } 188 189 // Index returns lang index of LangStore. 190 func (l Locale) Index() int { 191 return IndexLang(l.Lang) 192 } 193 194 // Tr translates content to target language. 195 func Tr(lang, format string, args ...interface{}) string { 196 var section string 197 parts := strings.SplitN(format, ".", 2) 198 if len(parts) == 2 { 199 section = parts[0] 200 format = parts[1] 201 } 202 203 value, ok := locales.Get(lang, section, format) 204 if ok { 205 format = value 206 } 207 208 if len(args) > 0 { 209 params := make([]interface{}, 0, len(args)) 210 for _, arg := range args { 211 if arg != nil { 212 val := reflect.ValueOf(arg) 213 if val.Kind() == reflect.Slice { 214 for i := 0; i < val.Len(); i++ { 215 params = append(params, val.Index(i).Interface()) 216 } 217 } else { 218 params = append(params, arg) 219 } 220 } 221 } 222 return fmt.Sprintf(format, params...) 223 } 224 return format 225 }