summaryrefslogtreecommitdiffstats
path: root/Godeps/_workspace/src/github.com/nicksnyder/go-i18n/i18n/bundle/bundle.go
diff options
context:
space:
mode:
Diffstat (limited to 'Godeps/_workspace/src/github.com/nicksnyder/go-i18n/i18n/bundle/bundle.go')
-rw-r--r--Godeps/_workspace/src/github.com/nicksnyder/go-i18n/i18n/bundle/bundle.go315
1 files changed, 0 insertions, 315 deletions
diff --git a/Godeps/_workspace/src/github.com/nicksnyder/go-i18n/i18n/bundle/bundle.go b/Godeps/_workspace/src/github.com/nicksnyder/go-i18n/i18n/bundle/bundle.go
deleted file mode 100644
index e93db95d7..000000000
--- a/Godeps/_workspace/src/github.com/nicksnyder/go-i18n/i18n/bundle/bundle.go
+++ /dev/null
@@ -1,315 +0,0 @@
-// Package bundle manages translations for multiple languages.
-package bundle
-
-import (
- "encoding/json"
- "fmt"
- "gopkg.in/yaml.v2"
- "io/ioutil"
- "reflect"
-
- "path/filepath"
-
- "github.com/nicksnyder/go-i18n/i18n/language"
- "github.com/nicksnyder/go-i18n/i18n/translation"
-)
-
-// TranslateFunc is a copy of i18n.TranslateFunc to avoid a circular dependency.
-type TranslateFunc func(translationID string, args ...interface{}) string
-
-// Bundle stores the translations for multiple languages.
-type Bundle struct {
- // The primary translations for a language tag and translation id.
- translations map[string]map[string]translation.Translation
-
- // Translations that can be used when an exact language match is not possible.
- fallbackTranslations map[string]map[string]translation.Translation
-}
-
-// New returns an empty bundle.
-func New() *Bundle {
- return &Bundle{
- translations: make(map[string]map[string]translation.Translation),
- fallbackTranslations: make(map[string]map[string]translation.Translation),
- }
-}
-
-// MustLoadTranslationFile is similar to LoadTranslationFile
-// except it panics if an error happens.
-func (b *Bundle) MustLoadTranslationFile(filename string) {
- if err := b.LoadTranslationFile(filename); err != nil {
- panic(err)
- }
-}
-
-// LoadTranslationFile loads the translations from filename into memory.
-//
-// The language that the translations are associated with is parsed from the filename (e.g. en-US.json).
-//
-// Generally you should load translation files once during your program's initialization.
-func (b *Bundle) LoadTranslationFile(filename string) error {
- buf, err := ioutil.ReadFile(filename)
- if err != nil {
- return err
- }
- return b.ParseTranslationFileBytes(filename, buf)
-}
-
-// ParseTranslationFileBytes is similar to LoadTranslationFile except it parses the bytes in buf.
-//
-// It is useful for parsing translation files embedded with go-bindata.
-func (b *Bundle) ParseTranslationFileBytes(filename string, buf []byte) error {
- basename := filepath.Base(filename)
- langs := language.Parse(basename)
- switch l := len(langs); {
- case l == 0:
- return fmt.Errorf("no language found in %q", basename)
- case l > 1:
- return fmt.Errorf("multiple languages found in filename %q: %v; expected one", basename, langs)
- }
- translations, err := parseTranslations(filename, buf)
- if err != nil {
- return err
- }
- b.AddTranslation(langs[0], translations...)
- return nil
-}
-
-func parseTranslations(filename string, buf []byte) ([]translation.Translation, error) {
- var unmarshalFunc func([]byte, interface{}) error
- switch format := filepath.Ext(filename); format {
- case ".json":
- unmarshalFunc = json.Unmarshal
- case ".yaml":
- unmarshalFunc = yaml.Unmarshal
- default:
- return nil, fmt.Errorf("unsupported file extension %s", format)
- }
-
- var translationsData []map[string]interface{}
- if len(buf) > 0 {
- if err := unmarshalFunc(buf, &translationsData); err != nil {
- return nil, err
- }
- }
-
- translations := make([]translation.Translation, 0, len(translationsData))
- for i, translationData := range translationsData {
- t, err := translation.NewTranslation(translationData)
- if err != nil {
- return nil, fmt.Errorf("unable to parse translation #%d in %s because %s\n%v", i, filename, err, translationData)
- }
- translations = append(translations, t)
- }
- return translations, nil
-}
-
-// AddTranslation adds translations for a language.
-//
-// It is useful if your translations are in a format not supported by LoadTranslationFile.
-func (b *Bundle) AddTranslation(lang *language.Language, translations ...translation.Translation) {
- if b.translations[lang.Tag] == nil {
- b.translations[lang.Tag] = make(map[string]translation.Translation, len(translations))
- }
- currentTranslations := b.translations[lang.Tag]
- for _, newTranslation := range translations {
- if currentTranslation := currentTranslations[newTranslation.ID()]; currentTranslation != nil {
- currentTranslations[newTranslation.ID()] = currentTranslation.Merge(newTranslation)
- } else {
- currentTranslations[newTranslation.ID()] = newTranslation
- }
- }
-
- // lang can provide translations for less specific language tags.
- for _, tag := range lang.MatchingTags() {
- b.fallbackTranslations[tag] = currentTranslations
- }
-}
-
-// Translations returns all translations in the bundle.
-func (b *Bundle) Translations() map[string]map[string]translation.Translation {
- return b.translations
-}
-
-// LanguageTags returns the tags of all languages that that have been added.
-func (b *Bundle) LanguageTags() []string {
- var tags []string
- for k := range b.translations {
- tags = append(tags, k)
- }
- return tags
-}
-
-// LanguageTranslationIDs returns the ids of all translations that have been added for a given language.
-func (b *Bundle) LanguageTranslationIDs(languageTag string) []string {
- var ids []string
- for id := range b.translations[languageTag] {
- ids = append(ids, id)
- }
- return ids
-}
-
-// MustTfunc is similar to Tfunc except it panics if an error happens.
-func (b *Bundle) MustTfunc(pref string, prefs ...string) TranslateFunc {
- tfunc, err := b.Tfunc(pref, prefs...)
- if err != nil {
- panic(err)
- }
- return tfunc
-}
-
-// MustTfuncAndLanguage is similar to TfuncAndLanguage except it panics if an error happens.
-func (b *Bundle) MustTfuncAndLanguage(pref string, prefs ...string) (TranslateFunc, *language.Language) {
- tfunc, language, err := b.TfuncAndLanguage(pref, prefs...)
- if err != nil {
- panic(err)
- }
- return tfunc, language
-}
-
-// Tfunc is similar to TfuncAndLanguage except is doesn't return the Language.
-func (b *Bundle) Tfunc(pref string, prefs ...string) (TranslateFunc, error) {
- tfunc, _, err := b.TfuncAndLanguage(pref, prefs...)
- return tfunc, err
-}
-
-// TfuncAndLanguage returns a TranslateFunc for the first Language that
-// has a non-zero number of translations in the bundle.
-//
-// The returned Language matches the the first language preference that could be satisfied,
-// but this may not strictly match the language of the translations used to satisfy that preference.
-//
-// For example, the user may request "zh". If there are no translations for "zh" but there are translations
-// for "zh-cn", then the translations for "zh-cn" will be used but the returned Language will be "zh".
-//
-// It can parse languages from Accept-Language headers (RFC 2616),
-// but it assumes weights are monotonically decreasing.
-func (b *Bundle) TfuncAndLanguage(pref string, prefs ...string) (TranslateFunc, *language.Language, error) {
- lang := b.supportedLanguage(pref, prefs...)
- var err error
- if lang == nil {
- err = fmt.Errorf("no supported languages found %#v", append(prefs, pref))
- }
- return func(translationID string, args ...interface{}) string {
- return b.translate(lang, translationID, args...)
- }, lang, err
-}
-
-// supportedLanguage returns the first language which
-// has a non-zero number of translations in the bundle.
-func (b *Bundle) supportedLanguage(pref string, prefs ...string) *language.Language {
- lang := b.translatedLanguage(pref)
- if lang == nil {
- for _, pref := range prefs {
- lang = b.translatedLanguage(pref)
- if lang != nil {
- break
- }
- }
- }
- return lang
-}
-
-func (b *Bundle) translatedLanguage(src string) *language.Language {
- langs := language.Parse(src)
- for _, lang := range langs {
- if len(b.translations[lang.Tag]) > 0 ||
- len(b.fallbackTranslations[lang.Tag]) > 0 {
- return lang
- }
- }
- return nil
-}
-
-func (b *Bundle) translate(lang *language.Language, translationID string, args ...interface{}) string {
- if lang == nil {
- return translationID
- }
-
- translations := b.translations[lang.Tag]
- if translations == nil {
- translations = b.fallbackTranslations[lang.Tag]
- if translations == nil {
- return translationID
- }
- }
-
- translation := translations[translationID]
- if translation == nil {
- return translationID
- }
-
- var data interface{}
- var count interface{}
- if argc := len(args); argc > 0 {
- if isNumber(args[0]) {
- count = args[0]
- if argc > 1 {
- data = args[1]
- }
- } else {
- data = args[0]
- }
- }
-
- if count != nil {
- if data == nil {
- data = map[string]interface{}{"Count": count}
- } else {
- dataMap := toMap(data)
- dataMap["Count"] = count
- data = dataMap
- }
- }
-
- p, _ := lang.Plural(count)
- template := translation.Template(p)
- if template == nil {
- return translationID
- }
-
- s := template.Execute(data)
- if s == "" {
- return translationID
- }
- return s
-}
-
-func isNumber(n interface{}) bool {
- switch n.(type) {
- case int, int8, int16, int32, int64, string:
- return true
- }
- return false
-}
-
-func toMap(input interface{}) map[string]interface{} {
- if data, ok := input.(map[string]interface{}); ok {
- return data
- }
- v := reflect.ValueOf(input)
- switch v.Kind() {
- case reflect.Ptr:
- return toMap(v.Elem().Interface())
- case reflect.Struct:
- return structToMap(v)
- default:
- return nil
- }
-}
-
-// Converts the top level of a struct to a map[string]interface{}.
-// Code inspired by github.com/fatih/structs.
-func structToMap(v reflect.Value) map[string]interface{} {
- out := make(map[string]interface{})
- t := v.Type()
- for i := 0; i < t.NumField(); i++ {
- field := t.Field(i)
- if field.PkgPath != "" {
- // unexported field. skip.
- continue
- }
- out[field.Name] = v.FieldByName(field.Name).Interface()
- }
- return out
-}