Browse Source

Add Overwrite functions for those embedding translator/translations into a library.

Dean Karn 9 năm trước cách đây
mục cha
commit
275d2293cf
4 tập tin đã thay đổi với 197 bổ sung20 xóa
  1. 1 1
      README.md
  2. 30 3
      benchmarks_test.go
  3. 59 6
      translator.go
  4. 107 10
      translator_test.go

+ 1 - 1
README.md

@@ -1,6 +1,6 @@
 ## universal-translator
 <img align="right" src="https://raw.githubusercontent.com/go-playground/universal-translator/master/logo.png">
-![Project status](https://img.shields.io/badge/version-0.9.1-green.svg)
+![Project status](https://img.shields.io/badge/version-0.10.0-green.svg)
 [![Build Status](https://semaphoreci.com/api/v1/joeybloggs/universal-translator/branches/master/badge.svg)](https://semaphoreci.com/joeybloggs/universal-translator)
 [![Coverage Status](https://coveralls.io/repos/github/go-playground/universal-translator/badge.svg?branch=master)](https://coveralls.io/github/go-playground/universal-translator?branch=master)
 [![Go Report Card](https://goreportcard.com/badge/github.com/go-playground/universal-translator)](https://goreportcard.com/report/github.com/go-playground/universal-translator)

+ 30 - 3
benchmarks_test.go

@@ -6,9 +6,36 @@ func BenchmarkBasicTranslation(b *testing.B) {
 
 	ut, _ := New("en", "en")
 	loc := ut.FindTranslator("en")
-	loc.Add("welcome", "Welcome to the site")
-	loc.Add("welcome-user", "Welcome to the site {0}")
-	loc.Add("welcome-user2", "Welcome to the site {0}, your location is {1}")
+
+	translations := []struct {
+		key      interface{}
+		trans    string
+		expected error
+	}{
+		{
+			key:      "welcome",
+			trans:    "Welcome to the site",
+			expected: nil,
+		},
+		{
+			key:      "welcome-user",
+			trans:    "Welcome to the site {0}",
+			expected: nil,
+		},
+		{
+			key:      "welcome-user2",
+			trans:    "Welcome to the site {0}, your location is {1}",
+			expected: nil,
+		},
+	}
+
+	for _, tt := range translations {
+		if err := loc.Add(tt.key, tt.trans); err != nil {
+			b.Fatalf("adding translation '%s' failed with key '%s'", tt.trans, tt.key)
+		}
+	}
+
+	b.ResetTimer()
 
 	b.Run("", func(b *testing.B) {
 		for i := 0; i < b.N; i++ {

+ 59 - 6
translator.go

@@ -24,7 +24,10 @@ type Translator interface {
 	// adds a normal translation for a particular language/locale
 	// {#} is the only replacement type accepted and are add infintium
 	// eg. one: '{0} day left' other: '{0} days left'
-	Add(key interface{}, text string)
+	Add(key interface{}, text string) error
+
+	// is the same as Add only it allows existing translations to be overridden
+	Overwrite(key interface{}, text string) error
 
 	// adds a cardinal plural translation for a particular language/locale
 	// {0} is the only replacement type accepted and only one variable is accepted as
@@ -33,6 +36,9 @@ type Translator interface {
 	// eg. in locale 'en' one: '{0} day left' other: '{0} days left'
 	AddCardinal(key interface{}, text string, rule locales.PluralRule) error
 
+	// is the same as AddCardinal only it allows existing translations to be overridden
+	OverwriteCardinal(key interface{}, text string, rule locales.PluralRule) error
+
 	// adds an ordinal plural translation for a particular language/locale
 	// {0} is the only replacement type accepted and only one variable is accepted as
 	// multiple cannot be used for a plural rule determination, unless it is a range;
@@ -41,11 +47,17 @@ type Translator interface {
 	// - 1st, 2nd, 3rd...
 	AddOrdinal(key interface{}, text string, rule locales.PluralRule) error
 
+	// is the same as AddOrdinal only it allows for existing translations to be overridden
+	OverwriteOrdinal(key interface{}, text string, rule locales.PluralRule) error
+
 	// adds a range plural translation for a particular language/locale
 	// {0} and {1} are the only replacement types accepted and only these are accepted.
 	// eg. in locale 'nl' one: '{0}-{1} day left' other: '{0}-{1} days left'
 	AddRange(key interface{}, text string, rule locales.PluralRule) error
 
+	// is the same as AddRange only allows an existing translation to be overridden
+	OverwriteRange(key interface{}, text string, rule locales.PluralRule) error
+
 	// creates the translation for the locale given the 'key' and params passed in
 	T(key interface{}, params ...string) string
 
@@ -95,7 +107,20 @@ func newTranslator(trans locales.Translator) Translator {
 // Add adds a normal translation for a particular language/locale
 // {#} is the only replacement type accepted and are add infintium
 // eg. one: '{0} day left' other: '{0} days left'
-func (t *translator) Add(key interface{}, text string) {
+func (t *translator) Add(key interface{}, text string) error {
+	return t.add(key, text, false)
+}
+
+// Overwrite is the same as Add only it allows existing translations to be overridden
+func (t *translator) Overwrite(key interface{}, text string) error {
+	return t.add(key, text, true)
+}
+
+func (t *translator) add(key interface{}, text string, overwrite bool) error {
+
+	if _, ok := t.translations[key]; ok && !overwrite {
+		return &ErrConflictingTranslation{key: key, text: text}
+	}
 
 	trans := &transText{
 		text: text,
@@ -120,6 +145,8 @@ func (t *translator) Add(key interface{}, text string) {
 	}
 
 	t.translations[key] = trans
+
+	return nil
 }
 
 // AddCardinal adds a cardinal plural translation for a particular language/locale
@@ -128,17 +155,25 @@ func (t *translator) Add(key interface{}, text string) {
 // see AddRange below.
 // eg. in locale 'en' one: '{0} day left' other: '{0} days left'
 func (t *translator) AddCardinal(key interface{}, text string, rule locales.PluralRule) error {
+	return t.addCardinal(key, text, rule, false)
+}
+
+// OverwriteCardinal is the same as AddCardinal only it allows existing translations to be overridden
+func (t *translator) OverwriteCardinal(key interface{}, text string, rule locales.PluralRule) error {
+	return t.addCardinal(key, text, rule, true)
+}
+
+func (t *translator) addCardinal(key interface{}, text string, rule locales.PluralRule, overwrite bool) error {
 
 	tarr, ok := t.cardinalTanslations[key]
 	if ok {
 		// verify not adding a conflicting record
-		if len(tarr) > 0 && tarr[rule] != nil {
+		if len(tarr) > 0 && tarr[rule] != nil && !overwrite {
 			return &ErrConflictingTranslation{key: key, rule: rule, text: text}
 		}
 
 	} else {
 		tarr = make([]*transText, 7, 7)
-		// tarr = make([]*transText, len(t.PluralsCardinal())+1, len(t.PluralsCardinal())+1)
 		t.cardinalTanslations[key] = tarr
 	}
 
@@ -167,11 +202,20 @@ func (t *translator) AddCardinal(key interface{}, text string, rule locales.Plur
 // see AddRange below.
 // eg. in locale 'en' one: '{0}st day of spring' other: '{0}nd day of spring' - 1st, 2nd, 3rd...
 func (t *translator) AddOrdinal(key interface{}, text string, rule locales.PluralRule) error {
+	return t.addOrdinal(key, text, rule, false)
+}
+
+// OverwriteOrdinal is the same as AddOrdinal only it allows for existing translations to be overridden
+func (t *translator) OverwriteOrdinal(key interface{}, text string, rule locales.PluralRule) error {
+	return t.addOrdinal(key, text, rule, true)
+}
+
+func (t *translator) addOrdinal(key interface{}, text string, rule locales.PluralRule, overwrite bool) error {
 
 	tarr, ok := t.ordinalTanslations[key]
 	if ok {
 		// verify not adding a conflicting record
-		if len(tarr) > 0 && tarr[rule] != nil {
+		if len(tarr) > 0 && tarr[rule] != nil && !overwrite {
 			return &ErrConflictingTranslation{key: key, rule: rule, text: text}
 		}
 
@@ -203,11 +247,20 @@ func (t *translator) AddOrdinal(key interface{}, text string, rule locales.Plura
 // {0} and {1} are the only replacement types accepted and only these are accepted.
 // eg. in locale 'nl' one: '{0}-{1} day left' other: '{0}-{1} days left'
 func (t *translator) AddRange(key interface{}, text string, rule locales.PluralRule) error {
+	return t.addRange(key, text, rule, false)
+}
+
+// OverwriteRange is the same as AddRange only allows an existing translation to be overridden
+func (t *translator) OverwriteRange(key interface{}, text string, rule locales.PluralRule) error {
+	return t.addRange(key, text, rule, true)
+}
+
+func (t *translator) addRange(key interface{}, text string, rule locales.PluralRule, overwrite bool) error {
 
 	tarr, ok := t.rangeTanslations[key]
 	if ok {
 		// verify not adding a conflicting record
-		if len(tarr) > 0 && tarr[rule] != nil {
+		if len(tarr) > 0 && tarr[rule] != nil && !overwrite {
 			return &ErrConflictingTranslation{key: key, rule: rule, text: text}
 		}
 

+ 107 - 10
translator_test.go

@@ -26,10 +26,64 @@ func TestBasicTranslation(t *testing.T) {
 	}
 
 	en := uni.GetTranslator("en") // or fallback if fails to find 'en'
-	en.Add("test_trans", "Welcome {0} to the {1}.")
-	en.Add("test_trans2", "{0} to the {1}.")
-	en.Add("test_trans3", "Welcome {0} to the {1}")
-	en.Add("test_trans4", "{0}{1}")
+
+	translations := []struct {
+		key           interface{}
+		trans         string
+		expected      error
+		expectedError bool
+		overwrite     bool
+	}{
+		{
+			key:      "test_trans",
+			trans:    "Welcome {0}",
+			expected: nil,
+		},
+		{
+			key:      "test_trans2",
+			trans:    "{0} to the {1}.",
+			expected: nil,
+		},
+		{
+			key:      "test_trans3",
+			trans:    "Welcome {0} to the {1}",
+			expected: nil,
+		},
+		{
+			key:      "test_trans4",
+			trans:    "{0}{1}",
+			expected: nil,
+		},
+		{
+			key:           "test_trans",
+			trans:         "{0}{1}",
+			expected:      &ErrConflictingTranslation{key: "bad_trans", text: "{0}{1}"},
+			expectedError: true,
+		},
+		{
+			key:       "test_trans",
+			trans:     "Welcome {0} to the {1}.",
+			expected:  nil,
+			overwrite: true,
+		},
+	}
+
+	for _, tt := range translations {
+
+		var err error
+
+		if tt.overwrite {
+			err = en.Overwrite(tt.key, tt.trans)
+		} else {
+			err = en.Add(tt.key, tt.trans)
+		}
+
+		if err != tt.expected {
+			if !tt.expectedError && err.Error() != tt.expected.Error() {
+				t.Errorf("Expected '%s' Got '%s'", tt.expected, err)
+			}
+		}
+	}
 
 	tests := []struct {
 		key           interface{}
@@ -91,6 +145,7 @@ func TestCardinalTranslation(t *testing.T) {
 		rule          locales.PluralRule
 		expected      error
 		expectedError bool
+		overwrite     bool
 	}{
 		// bad translation
 		{
@@ -102,7 +157,7 @@ func TestCardinalTranslation(t *testing.T) {
 		},
 		{
 			key:      "cardinal_test",
-			trans:    "You have {0} day left.",
+			trans:    "You have {0} day",
 			rule:     locales.PluralRuleOne,
 			expected: nil,
 		},
@@ -119,11 +174,25 @@ func TestCardinalTranslation(t *testing.T) {
 			expected:      &ErrConflictingTranslation{key: "cardinal_test", rule: locales.PluralRuleOther, text: "You have {0} days left."},
 			expectedError: true,
 		},
+		{
+			key:       "cardinal_test",
+			trans:     "You have {0} day left.",
+			rule:      locales.PluralRuleOne,
+			expected:  nil,
+			overwrite: true,
+		},
 	}
 
 	for _, tt := range translations {
 
-		err := en.AddCardinal(tt.key, tt.trans, tt.rule)
+		var err error
+
+		if tt.overwrite {
+			err = en.OverwriteCardinal(tt.key, tt.trans, tt.rule)
+		} else {
+			err = en.AddCardinal(tt.key, tt.trans, tt.rule)
+		}
+
 		if err != tt.expected {
 			if !tt.expectedError || err.Error() != tt.expected.Error() {
 				t.Errorf("Expected '<nil>' Got '%s'", err)
@@ -187,6 +256,7 @@ func TestOrdinalTranslation(t *testing.T) {
 		rule          locales.PluralRule
 		expected      error
 		expectedError bool
+		overwrite     bool
 	}{
 		// bad translation
 		{
@@ -198,7 +268,7 @@ func TestOrdinalTranslation(t *testing.T) {
 		},
 		{
 			key:      "day",
-			trans:    "{0}st",
+			trans:    "{0}sfefewt",
 			rule:     locales.PluralRuleOne,
 			expected: nil,
 		},
@@ -228,11 +298,25 @@ func TestOrdinalTranslation(t *testing.T) {
 			expected:      &ErrConflictingTranslation{key: "day", rule: locales.PluralRuleOther, text: "{0}th"},
 			expectedError: true,
 		},
+		{
+			key:       "day",
+			trans:     "{0}st",
+			rule:      locales.PluralRuleOne,
+			expected:  nil,
+			overwrite: true,
+		},
 	}
 
 	for _, tt := range translations {
 
-		err := en.AddOrdinal(tt.key, tt.trans, tt.rule)
+		var err error
+
+		if tt.overwrite {
+			err = en.OverwriteOrdinal(tt.key, tt.trans, tt.rule)
+		} else {
+			err = en.AddOrdinal(tt.key, tt.trans, tt.rule)
+		}
+
 		if err != tt.expected {
 			if !tt.expectedError || err.Error() != tt.expected.Error() {
 				t.Errorf("Expected '<nil>' Got '%s'", err)
@@ -325,6 +409,7 @@ func TestRangeTranslation(t *testing.T) {
 		rule          locales.PluralRule
 		expected      error
 		expectedError bool
+		overwrite     bool
 	}{
 		// bad translation
 		{
@@ -344,7 +429,7 @@ func TestRangeTranslation(t *testing.T) {
 		},
 		{
 			key:      "day",
-			trans:    "er {0}-{1} dag vertrokken",
+			trans:    "er {0}-{1} dag",
 			rule:     locales.PluralRuleOne,
 			expected: nil,
 		},
@@ -362,11 +447,23 @@ func TestRangeTranslation(t *testing.T) {
 			expected:      &ErrConflictingTranslation{key: "day", rule: locales.PluralRuleOther, text: "er zijn {0}-{1} dagen over"},
 			expectedError: true,
 		},
+		{
+			key:       "day",
+			trans:     "er {0}-{1} dag vertrokken",
+			rule:      locales.PluralRuleOne,
+			expected:  nil,
+			overwrite: true,
+		},
 	}
 
 	for _, tt := range translations {
 
-		err := nl.AddRange(tt.key, tt.trans, tt.rule)
+		if tt.overwrite {
+			err = nl.OverwriteRange(tt.key, tt.trans, tt.rule)
+		} else {
+			err = nl.AddRange(tt.key, tt.trans, tt.rule)
+		}
+
 		if err != tt.expected {
 			if !tt.expectedError || err.Error() != tt.expected.Error() {
 				t.Errorf("Expected '%#v' Got '%s'", tt.expected, err)