summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/nicksnyder/go-i18n/i18n
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/nicksnyder/go-i18n/i18n')
-rw-r--r--vendor/github.com/nicksnyder/go-i18n/i18n/bundle/bundle.go101
-rw-r--r--vendor/github.com/nicksnyder/go-i18n/i18n/translation/plural_translation.go4
-rw-r--r--vendor/github.com/nicksnyder/go-i18n/i18n/translation/single_translation.go4
-rw-r--r--vendor/github.com/nicksnyder/go-i18n/i18n/translation/template.go4
-rw-r--r--vendor/github.com/nicksnyder/go-i18n/i18n/translation/translation.go1
-rw-r--r--vendor/github.com/nicksnyder/go-i18n/i18n/translations_test.go89
6 files changed, 188 insertions, 15 deletions
diff --git a/vendor/github.com/nicksnyder/go-i18n/i18n/bundle/bundle.go b/vendor/github.com/nicksnyder/go-i18n/i18n/bundle/bundle.go
index 155543bda..2ad1d7cc3 100644
--- a/vendor/github.com/nicksnyder/go-i18n/i18n/bundle/bundle.go
+++ b/vendor/github.com/nicksnyder/go-i18n/i18n/bundle/bundle.go
@@ -2,6 +2,7 @@
package bundle
import (
+ "bytes"
"encoding/json"
"fmt"
"io/ioutil"
@@ -11,6 +12,7 @@ import (
"github.com/nicksnyder/go-i18n/i18n/language"
"github.com/nicksnyder/go-i18n/i18n/translation"
+ toml "github.com/pelletier/go-toml"
"gopkg.in/yaml.v2"
)
@@ -78,34 +80,103 @@ func (b *Bundle) ParseTranslationFileBytes(filename string, buf []byte) error {
}
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)
+ if len(buf) == 0 {
+ return []translation.Translation{}, nil
}
- var translationsData []map[string]interface{}
- if len(buf) > 0 {
- if err := unmarshalFunc(buf, &translationsData); err != nil {
- return nil, fmt.Errorf("failed to load %s because %s", filename, err)
+ ext := filepath.Ext(filename)
+
+ // `github.com/pelletier/go-toml` has an Unmarshal function,
+ // that can't unmarshal to maps, so we should parse TOML format separately.
+ if ext == ".toml" {
+ tree, err := toml.LoadReader(bytes.NewReader(buf))
+ if err != nil {
+ return nil, err
}
+
+ m := make(map[string]map[string]interface{})
+ for k, v := range tree.ToMap() {
+ m[k] = v.(map[string]interface{})
+ }
+
+ return parseFlatFormat(m)
}
- translations := make([]translation.Translation, 0, len(translationsData))
- for i, translationData := range translationsData {
+ // Then parse other formats.
+ if isStandardFormat(ext, buf) {
+ var standardFormat []map[string]interface{}
+ if err := unmarshal(ext, buf, &standardFormat); err != nil {
+ return nil, fmt.Errorf("failed to unmarshal %v: %v", filename, err)
+ }
+ return parseStandardFormat(standardFormat)
+ } else {
+ var flatFormat map[string]map[string]interface{}
+ if err := unmarshal(ext, buf, &flatFormat); err != nil {
+ return nil, fmt.Errorf("failed to unmarshal %v: %v", filename, err)
+ }
+ return parseFlatFormat(flatFormat)
+ }
+}
+
+func isStandardFormat(ext string, buf []byte) bool {
+ firstRune := rune(buf[0])
+ if (ext == ".json" && firstRune == '[') || (ext == ".yaml" && firstRune == '-') {
+ return true
+ }
+ return false
+}
+
+// unmarshal finds an appropriate unmarshal function for ext
+// (extension of filename) and unmarshals buf to out. out must be a pointer.
+func unmarshal(ext string, buf []byte, out interface{}) error {
+ switch ext {
+ case ".json":
+ return json.Unmarshal(buf, out)
+ case ".yaml":
+ return yaml.Unmarshal(buf, out)
+ }
+
+ return fmt.Errorf("unsupported file extension %v", ext)
+}
+
+func parseStandardFormat(data []map[string]interface{}) ([]translation.Translation, error) {
+ translations := make([]translation.Translation, 0, len(data))
+ for i, translationData := range data {
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)
+ return nil, fmt.Errorf("unable to parse translation #%d because %s\n%v", i, err, translationData)
}
translations = append(translations, t)
}
return translations, nil
}
+// parseFlatFormat just converts data from flat format to standard format
+// and passes it to parseStandardFormat.
+//
+// Flat format logic:
+// key of data must be a string and data[key] must be always map[string]interface{},
+// but if there is only "other" key in it then it is non-plural, else plural.
+func parseFlatFormat(data map[string]map[string]interface{}) ([]translation.Translation, error) {
+ var standardFormatData []map[string]interface{}
+ for id, translationData := range data {
+ dataObject := make(map[string]interface{})
+ dataObject["id"] = id
+ if len(translationData) == 1 { // non-plural form
+ _, otherExists := translationData["other"]
+ if otherExists {
+ dataObject["translation"] = translationData["other"]
+ }
+ } else { // plural form
+ dataObject["translation"] = translationData
+ }
+
+ standardFormatData = append(standardFormatData, dataObject)
+ }
+
+ return parseStandardFormat(standardFormatData)
+}
+
// AddTranslation adds translations for a language.
//
// It is useful if your translations are in a format not supported by LoadTranslationFile.
diff --git a/vendor/github.com/nicksnyder/go-i18n/i18n/translation/plural_translation.go b/vendor/github.com/nicksnyder/go-i18n/i18n/translation/plural_translation.go
index 4f579d16a..5dd74b2f5 100644
--- a/vendor/github.com/nicksnyder/go-i18n/i18n/translation/plural_translation.go
+++ b/vendor/github.com/nicksnyder/go-i18n/i18n/translation/plural_translation.go
@@ -16,6 +16,10 @@ func (pt *pluralTranslation) MarshalInterface() interface{} {
}
}
+func (pt *pluralTranslation) MarshalFlatInterface() interface{} {
+ return pt.templates
+}
+
func (pt *pluralTranslation) ID() string {
return pt.id
}
diff --git a/vendor/github.com/nicksnyder/go-i18n/i18n/translation/single_translation.go b/vendor/github.com/nicksnyder/go-i18n/i18n/translation/single_translation.go
index 1010e5947..9fcba5a18 100644
--- a/vendor/github.com/nicksnyder/go-i18n/i18n/translation/single_translation.go
+++ b/vendor/github.com/nicksnyder/go-i18n/i18n/translation/single_translation.go
@@ -16,6 +16,10 @@ func (st *singleTranslation) MarshalInterface() interface{} {
}
}
+func (st *singleTranslation) MarshalFlatInterface() interface{} {
+ return map[string]interface{}{"other": st.template}
+}
+
func (st *singleTranslation) ID() string {
return st.id
}
diff --git a/vendor/github.com/nicksnyder/go-i18n/i18n/translation/template.go b/vendor/github.com/nicksnyder/go-i18n/i18n/translation/template.go
index c8756fa4e..3310150c0 100644
--- a/vendor/github.com/nicksnyder/go-i18n/i18n/translation/template.go
+++ b/vendor/github.com/nicksnyder/go-i18n/i18n/translation/template.go
@@ -13,6 +13,10 @@ type template struct {
}
func newTemplate(src string) (*template, error) {
+ if src == "" {
+ return new(template), nil
+ }
+
var tmpl template
err := tmpl.parseTemplate(src)
return &tmpl, err
diff --git a/vendor/github.com/nicksnyder/go-i18n/i18n/translation/translation.go b/vendor/github.com/nicksnyder/go-i18n/i18n/translation/translation.go
index fa93180b8..197514623 100644
--- a/vendor/github.com/nicksnyder/go-i18n/i18n/translation/translation.go
+++ b/vendor/github.com/nicksnyder/go-i18n/i18n/translation/translation.go
@@ -12,6 +12,7 @@ type Translation interface {
// MarshalInterface returns the object that should be used
// to serialize the translation.
MarshalInterface() interface{}
+ MarshalFlatInterface() interface{}
ID() string
Template(language.Plural) *template
UntranslatedCopy() Translation
diff --git a/vendor/github.com/nicksnyder/go-i18n/i18n/translations_test.go b/vendor/github.com/nicksnyder/go-i18n/i18n/translations_test.go
new file mode 100644
index 000000000..86c580833
--- /dev/null
+++ b/vendor/github.com/nicksnyder/go-i18n/i18n/translations_test.go
@@ -0,0 +1,89 @@
+package i18n
+
+import (
+ "testing"
+
+ "github.com/nicksnyder/go-i18n/i18n/bundle"
+)
+
+var bobMap = map[string]interface{}{"Person": "Bob"}
+var bobStruct = struct{ Person string }{Person: "Bob"}
+
+var testCases = []struct {
+ id string
+ arg interface{}
+ want string
+}{
+ {"program_greeting", nil, "Hello world"},
+ {"person_greeting", bobMap, "Hello Bob"},
+ {"person_greeting", bobStruct, "Hello Bob"},
+
+ {"your_unread_email_count", 0, "You have 0 unread emails."},
+ {"your_unread_email_count", 1, "You have 1 unread email."},
+ {"your_unread_email_count", 2, "You have 2 unread emails."},
+ {"my_height_in_meters", "1.7", "I am 1.7 meters tall."},
+
+ {"person_unread_email_count", []interface{}{0, bobMap}, "Bob has 0 unread emails."},
+ {"person_unread_email_count", []interface{}{1, bobMap}, "Bob has 1 unread email."},
+ {"person_unread_email_count", []interface{}{2, bobMap}, "Bob has 2 unread emails."},
+ {"person_unread_email_count", []interface{}{0, bobStruct}, "Bob has 0 unread emails."},
+ {"person_unread_email_count", []interface{}{1, bobStruct}, "Bob has 1 unread email."},
+ {"person_unread_email_count", []interface{}{2, bobStruct}, "Bob has 2 unread emails."},
+
+ {"person_unread_email_count_timeframe", []interface{}{3, map[string]interface{}{
+ "Person": "Bob",
+ "Timeframe": "0 days",
+ }}, "Bob has 3 unread emails in the past 0 days."},
+ {"person_unread_email_count_timeframe", []interface{}{3, map[string]interface{}{
+ "Person": "Bob",
+ "Timeframe": "1 day",
+ }}, "Bob has 3 unread emails in the past 1 day."},
+ {"person_unread_email_count_timeframe", []interface{}{3, map[string]interface{}{
+ "Person": "Bob",
+ "Timeframe": "2 days",
+ }}, "Bob has 3 unread emails in the past 2 days."},
+}
+
+func testFile(t *testing.T, path string) {
+ b := bundle.New()
+ b.MustLoadTranslationFile(path)
+
+ T, err := b.Tfunc("en-US")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ for _, tc := range testCases {
+ var args []interface{}
+ if _, ok := tc.arg.([]interface{}); ok {
+ args = tc.arg.([]interface{})
+ } else {
+ args = []interface{}{tc.arg}
+ }
+
+ got := T(tc.id, args...)
+ if got != tc.want {
+ t.Error("got: %v; want: %v", got, tc.want)
+ }
+ }
+}
+
+func TestJSONParse(t *testing.T) {
+ testFile(t, "../goi18n/testdata/expected/en-us.all.json")
+}
+
+func TestYAMLParse(t *testing.T) {
+ testFile(t, "../goi18n/testdata/en-us.yaml")
+}
+
+func TestJSONFlatParse(t *testing.T) {
+ testFile(t, "../goi18n/testdata/en-us.flat.json")
+}
+
+func TestYAMLFlatParse(t *testing.T) {
+ testFile(t, "../goi18n/testdata/en-us.flat.yaml")
+}
+
+func TestTOMLFlatParse(t *testing.T) {
+ testFile(t, "../goi18n/testdata/en-us.flat.toml")
+}