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  }