Skip to content

Commit 275d229

Browse files
Dean KarnDean Karn
authored andcommitted
Add Overwrite functions for those embedding translator/translations into a library.
1 parent ac8d2ce commit 275d229

File tree

4 files changed

+197
-20
lines changed

4 files changed

+197
-20
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
## universal-translator
22
<img align="right" src="https://raw.githubusercontent.com/go-playground/universal-translator/master/logo.png">
3-
![Project status](https://img.shields.io/badge/version-0.9.1-green.svg)
3+
![Project status](https://img.shields.io/badge/version-0.10.0-green.svg)
44
[![Build Status](https://semaphoreci.com/api/v1/joeybloggs/universal-translator/branches/master/badge.svg)](https://semaphoreci.com/joeybloggs/universal-translator)
55
[![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)
66
[![Go Report Card](https://goreportcard.com/badge/github.com/go-playground/universal-translator)](https://goreportcard.com/report/github.com/go-playground/universal-translator)

benchmarks_test.go

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,36 @@ func BenchmarkBasicTranslation(b *testing.B) {
66

77
ut, _ := New("en", "en")
88
loc := ut.FindTranslator("en")
9-
loc.Add("welcome", "Welcome to the site")
10-
loc.Add("welcome-user", "Welcome to the site {0}")
11-
loc.Add("welcome-user2", "Welcome to the site {0}, your location is {1}")
9+
10+
translations := []struct {
11+
key interface{}
12+
trans string
13+
expected error
14+
}{
15+
{
16+
key: "welcome",
17+
trans: "Welcome to the site",
18+
expected: nil,
19+
},
20+
{
21+
key: "welcome-user",
22+
trans: "Welcome to the site {0}",
23+
expected: nil,
24+
},
25+
{
26+
key: "welcome-user2",
27+
trans: "Welcome to the site {0}, your location is {1}",
28+
expected: nil,
29+
},
30+
}
31+
32+
for _, tt := range translations {
33+
if err := loc.Add(tt.key, tt.trans); err != nil {
34+
b.Fatalf("adding translation '%s' failed with key '%s'", tt.trans, tt.key)
35+
}
36+
}
37+
38+
b.ResetTimer()
1239

1340
b.Run("", func(b *testing.B) {
1441
for i := 0; i < b.N; i++ {

translator.go

Lines changed: 59 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,10 @@ type Translator interface {
2424
// adds a normal translation for a particular language/locale
2525
// {#} is the only replacement type accepted and are add infintium
2626
// eg. one: '{0} day left' other: '{0} days left'
27-
Add(key interface{}, text string)
27+
Add(key interface{}, text string) error
28+
29+
// is the same as Add only it allows existing translations to be overridden
30+
Overwrite(key interface{}, text string) error
2831

2932
// adds a cardinal plural translation for a particular language/locale
3033
// {0} is the only replacement type accepted and only one variable is accepted as
@@ -33,6 +36,9 @@ type Translator interface {
3336
// eg. in locale 'en' one: '{0} day left' other: '{0} days left'
3437
AddCardinal(key interface{}, text string, rule locales.PluralRule) error
3538

39+
// is the same as AddCardinal only it allows existing translations to be overridden
40+
OverwriteCardinal(key interface{}, text string, rule locales.PluralRule) error
41+
3642
// adds an ordinal plural translation for a particular language/locale
3743
// {0} is the only replacement type accepted and only one variable is accepted as
3844
// multiple cannot be used for a plural rule determination, unless it is a range;
@@ -41,11 +47,17 @@ type Translator interface {
4147
// - 1st, 2nd, 3rd...
4248
AddOrdinal(key interface{}, text string, rule locales.PluralRule) error
4349

50+
// is the same as AddOrdinal only it allows for existing translations to be overridden
51+
OverwriteOrdinal(key interface{}, text string, rule locales.PluralRule) error
52+
4453
// adds a range plural translation for a particular language/locale
4554
// {0} and {1} are the only replacement types accepted and only these are accepted.
4655
// eg. in locale 'nl' one: '{0}-{1} day left' other: '{0}-{1} days left'
4756
AddRange(key interface{}, text string, rule locales.PluralRule) error
4857

58+
// is the same as AddRange only allows an existing translation to be overridden
59+
OverwriteRange(key interface{}, text string, rule locales.PluralRule) error
60+
4961
// creates the translation for the locale given the 'key' and params passed in
5062
T(key interface{}, params ...string) string
5163

@@ -95,7 +107,20 @@ func newTranslator(trans locales.Translator) Translator {
95107
// Add adds a normal translation for a particular language/locale
96108
// {#} is the only replacement type accepted and are add infintium
97109
// eg. one: '{0} day left' other: '{0} days left'
98-
func (t *translator) Add(key interface{}, text string) {
110+
func (t *translator) Add(key interface{}, text string) error {
111+
return t.add(key, text, false)
112+
}
113+
114+
// Overwrite is the same as Add only it allows existing translations to be overridden
115+
func (t *translator) Overwrite(key interface{}, text string) error {
116+
return t.add(key, text, true)
117+
}
118+
119+
func (t *translator) add(key interface{}, text string, overwrite bool) error {
120+
121+
if _, ok := t.translations[key]; ok && !overwrite {
122+
return &ErrConflictingTranslation{key: key, text: text}
123+
}
99124

100125
trans := &transText{
101126
text: text,
@@ -120,6 +145,8 @@ func (t *translator) Add(key interface{}, text string) {
120145
}
121146

122147
t.translations[key] = trans
148+
149+
return nil
123150
}
124151

125152
// AddCardinal adds a cardinal plural translation for a particular language/locale
@@ -128,17 +155,25 @@ func (t *translator) Add(key interface{}, text string) {
128155
// see AddRange below.
129156
// eg. in locale 'en' one: '{0} day left' other: '{0} days left'
130157
func (t *translator) AddCardinal(key interface{}, text string, rule locales.PluralRule) error {
158+
return t.addCardinal(key, text, rule, false)
159+
}
160+
161+
// OverwriteCardinal is the same as AddCardinal only it allows existing translations to be overridden
162+
func (t *translator) OverwriteCardinal(key interface{}, text string, rule locales.PluralRule) error {
163+
return t.addCardinal(key, text, rule, true)
164+
}
165+
166+
func (t *translator) addCardinal(key interface{}, text string, rule locales.PluralRule, overwrite bool) error {
131167

132168
tarr, ok := t.cardinalTanslations[key]
133169
if ok {
134170
// verify not adding a conflicting record
135-
if len(tarr) > 0 && tarr[rule] != nil {
171+
if len(tarr) > 0 && tarr[rule] != nil && !overwrite {
136172
return &ErrConflictingTranslation{key: key, rule: rule, text: text}
137173
}
138174

139175
} else {
140176
tarr = make([]*transText, 7, 7)
141-
// tarr = make([]*transText, len(t.PluralsCardinal())+1, len(t.PluralsCardinal())+1)
142177
t.cardinalTanslations[key] = tarr
143178
}
144179

@@ -167,11 +202,20 @@ func (t *translator) AddCardinal(key interface{}, text string, rule locales.Plur
167202
// see AddRange below.
168203
// eg. in locale 'en' one: '{0}st day of spring' other: '{0}nd day of spring' - 1st, 2nd, 3rd...
169204
func (t *translator) AddOrdinal(key interface{}, text string, rule locales.PluralRule) error {
205+
return t.addOrdinal(key, text, rule, false)
206+
}
207+
208+
// OverwriteOrdinal is the same as AddOrdinal only it allows for existing translations to be overridden
209+
func (t *translator) OverwriteOrdinal(key interface{}, text string, rule locales.PluralRule) error {
210+
return t.addOrdinal(key, text, rule, true)
211+
}
212+
213+
func (t *translator) addOrdinal(key interface{}, text string, rule locales.PluralRule, overwrite bool) error {
170214

171215
tarr, ok := t.ordinalTanslations[key]
172216
if ok {
173217
// verify not adding a conflicting record
174-
if len(tarr) > 0 && tarr[rule] != nil {
218+
if len(tarr) > 0 && tarr[rule] != nil && !overwrite {
175219
return &ErrConflictingTranslation{key: key, rule: rule, text: text}
176220
}
177221

@@ -203,11 +247,20 @@ func (t *translator) AddOrdinal(key interface{}, text string, rule locales.Plura
203247
// {0} and {1} are the only replacement types accepted and only these are accepted.
204248
// eg. in locale 'nl' one: '{0}-{1} day left' other: '{0}-{1} days left'
205249
func (t *translator) AddRange(key interface{}, text string, rule locales.PluralRule) error {
250+
return t.addRange(key, text, rule, false)
251+
}
252+
253+
// OverwriteRange is the same as AddRange only allows an existing translation to be overridden
254+
func (t *translator) OverwriteRange(key interface{}, text string, rule locales.PluralRule) error {
255+
return t.addRange(key, text, rule, true)
256+
}
257+
258+
func (t *translator) addRange(key interface{}, text string, rule locales.PluralRule, overwrite bool) error {
206259

207260
tarr, ok := t.rangeTanslations[key]
208261
if ok {
209262
// verify not adding a conflicting record
210-
if len(tarr) > 0 && tarr[rule] != nil {
263+
if len(tarr) > 0 && tarr[rule] != nil && !overwrite {
211264
return &ErrConflictingTranslation{key: key, rule: rule, text: text}
212265
}
213266

translator_test.go

Lines changed: 107 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,64 @@ func TestBasicTranslation(t *testing.T) {
2626
}
2727

2828
en := uni.GetTranslator("en") // or fallback if fails to find 'en'
29-
en.Add("test_trans", "Welcome {0} to the {1}.")
30-
en.Add("test_trans2", "{0} to the {1}.")
31-
en.Add("test_trans3", "Welcome {0} to the {1}")
32-
en.Add("test_trans4", "{0}{1}")
29+
30+
translations := []struct {
31+
key interface{}
32+
trans string
33+
expected error
34+
expectedError bool
35+
overwrite bool
36+
}{
37+
{
38+
key: "test_trans",
39+
trans: "Welcome {0}",
40+
expected: nil,
41+
},
42+
{
43+
key: "test_trans2",
44+
trans: "{0} to the {1}.",
45+
expected: nil,
46+
},
47+
{
48+
key: "test_trans3",
49+
trans: "Welcome {0} to the {1}",
50+
expected: nil,
51+
},
52+
{
53+
key: "test_trans4",
54+
trans: "{0}{1}",
55+
expected: nil,
56+
},
57+
{
58+
key: "test_trans",
59+
trans: "{0}{1}",
60+
expected: &ErrConflictingTranslation{key: "bad_trans", text: "{0}{1}"},
61+
expectedError: true,
62+
},
63+
{
64+
key: "test_trans",
65+
trans: "Welcome {0} to the {1}.",
66+
expected: nil,
67+
overwrite: true,
68+
},
69+
}
70+
71+
for _, tt := range translations {
72+
73+
var err error
74+
75+
if tt.overwrite {
76+
err = en.Overwrite(tt.key, tt.trans)
77+
} else {
78+
err = en.Add(tt.key, tt.trans)
79+
}
80+
81+
if err != tt.expected {
82+
if !tt.expectedError && err.Error() != tt.expected.Error() {
83+
t.Errorf("Expected '%s' Got '%s'", tt.expected, err)
84+
}
85+
}
86+
}
3387

3488
tests := []struct {
3589
key interface{}
@@ -91,6 +145,7 @@ func TestCardinalTranslation(t *testing.T) {
91145
rule locales.PluralRule
92146
expected error
93147
expectedError bool
148+
overwrite bool
94149
}{
95150
// bad translation
96151
{
@@ -102,7 +157,7 @@ func TestCardinalTranslation(t *testing.T) {
102157
},
103158
{
104159
key: "cardinal_test",
105-
trans: "You have {0} day left.",
160+
trans: "You have {0} day",
106161
rule: locales.PluralRuleOne,
107162
expected: nil,
108163
},
@@ -119,11 +174,25 @@ func TestCardinalTranslation(t *testing.T) {
119174
expected: &ErrConflictingTranslation{key: "cardinal_test", rule: locales.PluralRuleOther, text: "You have {0} days left."},
120175
expectedError: true,
121176
},
177+
{
178+
key: "cardinal_test",
179+
trans: "You have {0} day left.",
180+
rule: locales.PluralRuleOne,
181+
expected: nil,
182+
overwrite: true,
183+
},
122184
}
123185

124186
for _, tt := range translations {
125187

126-
err := en.AddCardinal(tt.key, tt.trans, tt.rule)
188+
var err error
189+
190+
if tt.overwrite {
191+
err = en.OverwriteCardinal(tt.key, tt.trans, tt.rule)
192+
} else {
193+
err = en.AddCardinal(tt.key, tt.trans, tt.rule)
194+
}
195+
127196
if err != tt.expected {
128197
if !tt.expectedError || err.Error() != tt.expected.Error() {
129198
t.Errorf("Expected '<nil>' Got '%s'", err)
@@ -187,6 +256,7 @@ func TestOrdinalTranslation(t *testing.T) {
187256
rule locales.PluralRule
188257
expected error
189258
expectedError bool
259+
overwrite bool
190260
}{
191261
// bad translation
192262
{
@@ -198,7 +268,7 @@ func TestOrdinalTranslation(t *testing.T) {
198268
},
199269
{
200270
key: "day",
201-
trans: "{0}st",
271+
trans: "{0}sfefewt",
202272
rule: locales.PluralRuleOne,
203273
expected: nil,
204274
},
@@ -228,11 +298,25 @@ func TestOrdinalTranslation(t *testing.T) {
228298
expected: &ErrConflictingTranslation{key: "day", rule: locales.PluralRuleOther, text: "{0}th"},
229299
expectedError: true,
230300
},
301+
{
302+
key: "day",
303+
trans: "{0}st",
304+
rule: locales.PluralRuleOne,
305+
expected: nil,
306+
overwrite: true,
307+
},
231308
}
232309

233310
for _, tt := range translations {
234311

235-
err := en.AddOrdinal(tt.key, tt.trans, tt.rule)
312+
var err error
313+
314+
if tt.overwrite {
315+
err = en.OverwriteOrdinal(tt.key, tt.trans, tt.rule)
316+
} else {
317+
err = en.AddOrdinal(tt.key, tt.trans, tt.rule)
318+
}
319+
236320
if err != tt.expected {
237321
if !tt.expectedError || err.Error() != tt.expected.Error() {
238322
t.Errorf("Expected '<nil>' Got '%s'", err)
@@ -325,6 +409,7 @@ func TestRangeTranslation(t *testing.T) {
325409
rule locales.PluralRule
326410
expected error
327411
expectedError bool
412+
overwrite bool
328413
}{
329414
// bad translation
330415
{
@@ -344,7 +429,7 @@ func TestRangeTranslation(t *testing.T) {
344429
},
345430
{
346431
key: "day",
347-
trans: "er {0}-{1} dag vertrokken",
432+
trans: "er {0}-{1} dag",
348433
rule: locales.PluralRuleOne,
349434
expected: nil,
350435
},
@@ -362,11 +447,23 @@ func TestRangeTranslation(t *testing.T) {
362447
expected: &ErrConflictingTranslation{key: "day", rule: locales.PluralRuleOther, text: "er zijn {0}-{1} dagen over"},
363448
expectedError: true,
364449
},
450+
{
451+
key: "day",
452+
trans: "er {0}-{1} dag vertrokken",
453+
rule: locales.PluralRuleOne,
454+
expected: nil,
455+
overwrite: true,
456+
},
365457
}
366458

367459
for _, tt := range translations {
368460

369-
err := nl.AddRange(tt.key, tt.trans, tt.rule)
461+
if tt.overwrite {
462+
err = nl.OverwriteRange(tt.key, tt.trans, tt.rule)
463+
} else {
464+
err = nl.AddRange(tt.key, tt.trans, tt.rule)
465+
}
466+
370467
if err != tt.expected {
371468
if !tt.expectedError || err.Error() != tt.expected.Error() {
372469
t.Errorf("Expected '%#v' Got '%s'", tt.expected, err)

0 commit comments

Comments
 (0)