10 "github.com/go-playground/locales"
11 "github.com/go-playground/locales/en"
12 "github.com/go-playground/locales/nl"
16 // - Run "go test" to run tests
17 // - Run "gocov test | gocov report" to report on test converage by file
18 // - Run "gocov test | gocov annotate -" to report on all code and functions, those ,marked with "MISS" were never called
22 // -- may be a good idea to change to output path to somewherelike /tmp
23 // go test -coverprofile cover.out && go tool cover -html=cover.out -o cover.html
26 func TestExportImportBasic(t *testing.T) {
30 en, found := uni.GetTranslator("en") // or fallback if fails to find 'en'
32 t.Fatalf("Expected '%t' Got '%t'", true, found)
35 translations := []struct {
54 trans: "{0} to the {1}.",
59 trans: "Welcome {0} to the {1}",
70 expected: &ErrConflictingTranslation{locale: en.Locale(), key: "test_trans", text: "{0}{1}"},
76 expected: &ErrConflictingTranslation{locale: en.Locale(), key: -1, text: "{0}{1}"},
81 trans: "Welcome {0} to the {1}.",
87 for _, tt := range translations {
89 err := en.Add(tt.key, tt.trans, tt.override)
90 if err != tt.expected {
91 if !tt.expectedError {
92 t.Errorf("Expected '%s' Got '%s'", tt.expected, err)
94 if err.Error() != tt.expected.Error() {
95 t.Errorf("Expected '%s' Got '%s'", tt.expected.Error(), err.Error())
101 dirname := "testdata/translations"
102 defer os.RemoveAll(dirname)
104 err := uni.Export(FormatJSON, dirname)
106 t.Fatalf("Expected '%v' Got '%s'", nil, err)
111 err = uni.Import(FormatJSON, dirname)
113 t.Fatalf("Expected '%v' Got '%s'", nil, err)
116 en, found = uni.GetTranslator("en") // or fallback if fails to find 'en'
118 t.Fatalf("Expected '%t' Got '%t'", true, found)
129 params: []string{"Joeybloggs", "The Test"},
130 expected: "Welcome Joeybloggs to the The Test.",
134 params: []string{"Joeybloggs", "The Test"},
135 expected: "Joeybloggs to the The Test.",
139 params: []string{"Joeybloggs", "The Test"},
140 expected: "Welcome Joeybloggs to the The Test",
144 params: []string{"Joeybloggs", "The Test"},
145 expected: "JoeybloggsThe Test",
149 key: "non-existant-key",
150 params: []string{"Joeybloggs", "The Test"},
156 for _, tt := range tests {
158 s, err := en.T(tt.key, tt.params...)
159 if s != tt.expected {
160 if !tt.expectedError || (tt.expectedError && err != ErrUnknowTranslation) {
161 t.Errorf("Expected '%s' Got '%s'", tt.expected, s)
167 func TestExportImportCardinal(t *testing.T) {
171 en, found := uni.GetTranslator("en")
173 t.Fatalf("Expected '%t' Got '%t'", true, found)
176 translations := []struct {
179 rule locales.PluralRule
186 key: "cardinal_test",
187 trans: "You have a day left.",
188 rule: locales.PluralRuleOne,
189 expected: &ErrCardinalTranslation{text: fmt.Sprintf("error: parameter '%s' not found, may want to use 'Add' instead of 'AddCardinal'. locale: '%s' key: '%v' text: '%s'", paramZero, en.Locale(), "cardinal_test", "You have a day left.")},
193 key: "cardinal_test",
194 trans: "You have {0} day",
195 rule: locales.PluralRuleOne,
199 key: "cardinal_test",
200 trans: "You have {0} days left.",
201 rule: locales.PluralRuleOther,
205 key: "cardinal_test",
206 trans: "You have {0} days left.",
207 rule: locales.PluralRuleOther,
208 expected: &ErrConflictingTranslation{locale: en.Locale(), key: "cardinal_test", rule: locales.PluralRuleOther, text: "You have {0} days left."},
212 key: "cardinal_test",
213 trans: "You have {0} day left.",
214 rule: locales.PluralRuleOne,
220 for _, tt := range translations {
222 err := en.AddCardinal(tt.key, tt.trans, tt.rule, tt.override)
223 if err != tt.expected {
224 if !tt.expectedError || err.Error() != tt.expected.Error() {
225 t.Errorf("Expected '%s' Got '%s'", tt.expected, err)
230 dirname := "testdata/translations"
231 defer os.RemoveAll(dirname)
233 err := uni.Export(FormatJSON, dirname)
235 t.Fatalf("Expected '%v' Got '%s'", nil, err)
240 err = uni.Import(FormatJSON, dirname)
242 t.Fatalf("Expected '%v' Got '%s'", nil, err)
245 en, found = uni.GetTranslator("en") // or fallback if fails to find 'en'
247 t.Fatalf("Expected '%t' Got '%t'", true, found)
259 key: "cardinal_test",
262 param: string(en.FmtNumber(1, 0)),
263 expected: "You have 1 day left.",
265 // bad translation key
270 param: string(en.FmtNumber(1, 0)),
276 for _, tt := range tests {
278 s, err := en.C(tt.key, tt.num, tt.digits, tt.param)
280 if !tt.expectedError && err != ErrUnknowTranslation {
281 t.Errorf("Expected '<nil>' Got '%s'", err)
285 if s != tt.expected {
286 t.Errorf("Expected '%s' Got '%s'", tt.expected, s)
291 func TestExportImportOrdinal(t *testing.T) {
295 en, found := uni.GetTranslator("en")
297 t.Fatalf("Expected '%t' Got '%t'", true, found)
300 translations := []struct {
303 rule locales.PluralRule
312 rule: locales.PluralRuleOne,
313 expected: &ErrOrdinalTranslation{text: fmt.Sprintf("error: parameter '%s' not found, may want to use 'Add' instead of 'AddOrdinal'. locale: '%s' key: '%v' text: '%s'", paramZero, en.Locale(), "day", "st")},
319 rule: locales.PluralRuleOne,
325 rule: locales.PluralRuleTwo,
331 rule: locales.PluralRuleFew,
337 rule: locales.PluralRuleOther,
344 rule: locales.PluralRuleOther,
345 expected: &ErrConflictingTranslation{locale: en.Locale(), key: "day", rule: locales.PluralRuleOther, text: "{0}th"},
351 rule: locales.PluralRuleOne,
357 for _, tt := range translations {
359 err := en.AddOrdinal(tt.key, tt.trans, tt.rule, tt.override)
360 if err != tt.expected {
361 if !tt.expectedError || err.Error() != tt.expected.Error() {
362 t.Errorf("Expected '<nil>' Got '%s'", err)
367 dirname := "testdata/translations"
368 defer os.RemoveAll(dirname)
370 err := uni.Export(FormatJSON, dirname)
372 t.Fatalf("Expected '%v' Got '%s'", nil, err)
377 err = uni.Import(FormatJSON, dirname)
379 t.Fatalf("Expected '%v' Got '%s'", nil, err)
382 en, found = uni.GetTranslator("en") // or fallback if fails to find 'en'
384 t.Fatalf("Expected '%t' Got '%t'", true, found)
399 param: string(en.FmtNumber(1, 0)),
406 param: string(en.FmtNumber(2, 0)),
413 param: string(en.FmtNumber(3, 0)),
420 param: string(en.FmtNumber(4, 0)),
427 param: string(en.FmtNumber(10258.43, 0)),
428 expected: "10,258th",
435 param: string(en.FmtNumber(10258.43, 0)),
441 for _, tt := range tests {
443 s, err := en.O(tt.key, tt.num, tt.digits, tt.param)
445 if !tt.expectedError && err != ErrUnknowTranslation {
446 t.Errorf("Expected '<nil>' Got '%s'", err)
450 if s != tt.expected {
451 t.Errorf("Expected '%s' Got '%s'", tt.expected, s)
456 func TestExportImportRange(t *testing.T) {
462 nl, found := uni.GetTranslator("nl")
464 t.Fatalf("Expected '%t' Got '%t'", true, found)
467 translations := []struct {
470 rule locales.PluralRule
478 trans: "er -{1} dag vertrokken",
479 rule: locales.PluralRuleOne,
480 expected: &ErrRangeTranslation{text: fmt.Sprintf("error: parameter '%s' not found, are you sure you're adding a Range Translation? locale: '%s' key: '%s' text: '%s'", paramZero, nl.Locale(), "day", "er -{1} dag vertrokken")},
486 trans: "er {0}- dag vertrokken",
487 rule: locales.PluralRuleOne,
488 expected: &ErrRangeTranslation{text: fmt.Sprintf("error: parameter '%s' not found, a Range Translation requires two parameters. locale: '%s' key: '%s' text: '%s'", paramOne, nl.Locale(), "day", "er {0}- dag vertrokken")},
493 trans: "er {0}-{1} dag",
494 rule: locales.PluralRuleOne,
499 trans: "er zijn {0}-{1} dagen over",
500 rule: locales.PluralRuleOther,
506 trans: "er zijn {0}-{1} dagen over",
507 rule: locales.PluralRuleOther,
508 expected: &ErrConflictingTranslation{locale: nl.Locale(), key: "day", rule: locales.PluralRuleOther, text: "er zijn {0}-{1} dagen over"},
513 trans: "er {0}-{1} dag vertrokken",
514 rule: locales.PluralRuleOne,
520 for _, tt := range translations {
522 err := nl.AddRange(tt.key, tt.trans, tt.rule, tt.override)
523 if err != tt.expected {
524 if !tt.expectedError || err.Error() != tt.expected.Error() {
525 t.Errorf("Expected '%#v' Got '%s'", tt.expected, err)
530 dirname := "testdata/translations"
531 defer os.RemoveAll(dirname)
533 err := uni.Export(FormatJSON, dirname)
535 t.Fatalf("Expected '%v' Got '%s'", nil, err)
540 err = uni.Import(FormatJSON, dirname)
542 t.Fatalf("Expected '%v' Got '%s'", nil, err)
545 nl, found = uni.GetTranslator("nl") // or fallback if fails to find 'en'
547 t.Fatalf("Expected '%t' Got '%t'", true, found)
567 param1: string(nl.FmtNumber(1, 0)),
568 param2: string(nl.FmtNumber(2, 0)),
569 expected: "er zijn 1-2 dagen over",
577 param1: string(nl.FmtNumber(0, 0)),
578 param2: string(nl.FmtNumber(1, 0)),
579 expected: "er 0-1 dag vertrokken",
587 param1: string(nl.FmtNumber(0, 0)),
588 param2: string(nl.FmtNumber(2, 0)),
589 expected: "er zijn 0-2 dagen over",
591 // bad translations from here
598 param1: string(nl.FmtNumber(0, 0)),
599 param2: string(nl.FmtNumber(2, 0)),
605 for _, tt := range tests {
607 s, err := nl.R(tt.key, tt.num1, tt.digits1, tt.num2, tt.digits2, tt.param1, tt.param2)
609 if !tt.expectedError && err != ErrUnknowTranslation {
610 t.Errorf("Expected '<nil>' Got '%s'", err)
614 if s != tt.expected {
615 t.Errorf("Expected '%s' Got '%s'", tt.expected, s)
620 func TestImportRecursive(t *testing.T) {
625 dirname := "testdata/nested1"
626 err := uni.Import(FormatJSON, dirname)
628 t.Fatalf("Expected '%v' Got '%s'", nil, err)
631 en, found := uni.GetTranslator("en") // or fallback if fails to find 'en'
633 t.Fatalf("Expected '%t' Got '%t'", true, found)
644 params: []string{"Joeybloggs", "The Test"},
645 expected: "Welcome Joeybloggs to the The Test.",
649 params: []string{"Joeybloggs", "The Test"},
650 expected: "Joeybloggs to the The Test.",
654 params: []string{"Joeybloggs", "The Test"},
655 expected: "Welcome Joeybloggs to the The Test",
659 params: []string{"Joeybloggs", "The Test"},
660 expected: "JoeybloggsThe Test",
664 key: "non-existant-key",
665 params: []string{"Joeybloggs", "The Test"},
671 for _, tt := range tests {
673 s, err := en.T(tt.key, tt.params...)
674 if s != tt.expected {
675 if !tt.expectedError || (tt.expectedError && err != ErrUnknowTranslation) {
676 t.Errorf("Expected '%s' Got '%s'", tt.expected, s)
682 func TestBadImport(t *testing.T) {
684 // test non existant file
688 filename := "testdata/non-existant-file.json"
689 expected := "stat testdata/non-existant-file.json: no such file or directory"
690 err := uni.Import(FormatJSON, filename)
691 if err == nil || err.Error() != expected {
692 t.Fatalf("Expected '%s' Got '%s'", expected, err)
695 // test bad parameter basic translation
696 filename = "testdata/bad-translation1.json"
697 expected = "error: bad parameter syntax, missing parameter '{0}' in translation. locale: 'en' key: 'test_trans3' text: 'Welcome {lettersnotpermitted} to the {1}'"
698 err = uni.Import(FormatJSON, filename)
699 if err == nil || err.Error() != expected {
700 t.Fatalf("Expected '%s' Got '%s'", expected, err)
703 // test missing bracket basic translation
704 filename = "testdata/bad-translation2.json"
705 expected = "error: missing bracket '{}', in translation. locale: 'en' key: 'test_trans3' text: 'Welcome {0 to the {1}'"
706 err = uni.Import(FormatJSON, filename)
707 if err == nil || err.Error() != expected {
708 t.Fatalf("Expected '%s' Got '%s'", expected, err)
711 // test missing locale basic translation
712 filename = "testdata/bad-translation3.json"
713 expected = "error: locale 'nl' not registered."
714 err = uni.Import(FormatJSON, filename)
715 if err == nil || err.Error() != expected {
716 t.Fatalf("Expected '%s' Got '%s'", expected, err)
719 // test bad plural definition
720 filename = "testdata/bad-translation4.json"
721 expected = "error: bad plural definition 'ut.translation{Locale:\"en\", Key:\"cardinal_test\", Translation:\"You have {0} day left.\", PluralType:\"NotAPluralType\", PluralRule:\"One\", OverrideExisting:false}'"
722 err = uni.Import(FormatJSON, filename)
723 if err == nil || err.Error() != expected {
724 t.Fatalf("Expected '%s' Got '%s'", expected, err)
727 // test bad plural rule for locale
728 filename = "testdata/bad-translation5.json"
729 expected = "error: cardinal plural rule 'Many' does not exist for locale 'en' key: 'cardinal_test' text: 'You have {0} day left.'"
730 err = uni.Import(FormatJSON, filename)
731 if err == nil || err.Error() != expected {
732 t.Fatalf("Expected '%s' Got '%s'", expected, err)
736 filename = "testdata/bad-translation6.json"
737 expected = "invalid character ']' after object key:value pair"
738 err = uni.Import(FormatJSON, filename)
739 if err == nil || err.Error() != expected {
740 t.Fatalf("Expected '%s' Got '%s'", expected, err)
743 // test bad io.Reader
744 f, err := os.Open(filename)
746 t.Fatalf("Expected '%v' Got '%s'", nil, err)
750 expected = "read testdata/bad-translation6.json: bad file descriptor"
751 err = uni.ImportByReader(FormatJSON, f)
752 if err == nil || err.Error() != expected {
753 t.Fatalf("Expected '%s' Got '%s'", expected, err)
757 func TestBadExport(t *testing.T) {
759 // test readonly directory
763 en, found := uni.GetTranslator("en") // or fallback if fails to find 'en'
765 t.Fatalf("Expected '%t' Got '%t'", true, found)
768 dirname := "testdata/readonly"
769 err := os.Mkdir(dirname, 0444)
771 t.Fatalf("Expected '%v' Got '%s'", nil, err)
773 defer os.RemoveAll(dirname)
775 en.Add("day", "this is a day", false)
777 expected := "open testdata/readonly/en.json: permission denied"
778 err = uni.Export(FormatJSON, dirname)
779 if err == nil || err.Error() != expected {
780 t.Fatalf("Expected '%s' Got '%s'", expected, err)
783 // test exporting into directory inside readonly directory
784 expected = "stat testdata/readonly/inner: permission denied"
785 err = uni.Export(FormatJSON, filepath.Join(dirname, "inner"))
786 if err == nil || err.Error() != expected {
787 t.Fatalf("Expected '%s' Got '%s'", expected, err)