1
2
3
4
5 package message
6
7 import (
8 "bytes"
9 "fmt"
10 "io"
11 "testing"
12
13 "golang.org/x/text/internal"
14 "golang.org/x/text/internal/format"
15 "golang.org/x/text/language"
16 "golang.org/x/text/message/catalog"
17 )
18
19 type formatFunc func(s fmt.State, v rune)
20
21 func (f formatFunc) Format(s fmt.State, v rune) { f(s, v) }
22
23 func TestBinding(t *testing.T) {
24 testCases := []struct {
25 tag string
26 value interface{}
27 want string
28 }{
29 {"en", 1, "1"},
30 {"en", "2", "2"},
31 {
32 "en",
33 formatFunc(func(fs fmt.State, v rune) {
34 s := fs.(format.State)
35 io.WriteString(s, s.Language().String())
36 }),
37 "en",
38 },
39 }
40 for i, tc := range testCases {
41 p := NewPrinter(language.MustParse(tc.tag))
42 if got := p.Sprint(tc.value); got != tc.want {
43 t.Errorf("%d:%s:Sprint(%v) = %q; want %q", i, tc.tag, tc.value, got, tc.want)
44 }
45 var buf bytes.Buffer
46 p.Fprint(&buf, tc.value)
47 if got := buf.String(); got != tc.want {
48 t.Errorf("%d:%s:Fprint(%v) = %q; want %q", i, tc.tag, tc.value, got, tc.want)
49 }
50 }
51 }
52
53 func TestLocalization(t *testing.T) {
54 type test struct {
55 tag string
56 key Reference
57 args []interface{}
58 want string
59 }
60 args := func(x ...interface{}) []interface{} { return x }
61 empty := []interface{}{}
62 joe := []interface{}{"Joe"}
63 joeAndMary := []interface{}{"Joe", "Mary"}
64
65 testCases := []struct {
66 desc string
67 cat []entry
68 test []test
69 }{{
70 desc: "empty",
71 test: []test{
72 {"en", "key", empty, "key"},
73 {"en", "", empty, ""},
74 {"nl", "", empty, ""},
75 },
76 }, {
77 desc: "hierarchical languages",
78 cat: []entry{
79 {"en", "hello %s", "Hello %s!"},
80 {"en-GB", "hello %s", "Hellø %s!"},
81 {"en-US", "hello %s", "Howdy %s!"},
82 {"en", "greetings %s and %s", "Greetings %s and %s!"},
83 },
84 test: []test{
85 {"und", "hello %s", joe, "hello Joe"},
86 {"nl", "hello %s", joe, "hello Joe"},
87 {"en", "hello %s", joe, "Hello Joe!"},
88 {"en-US", "hello %s", joe, "Howdy Joe!"},
89 {"en-GB", "hello %s", joe, "Hellø Joe!"},
90 {"en-oxendict", "hello %s", joe, "Hello Joe!"},
91 {"en-US-oxendict-u-ms-metric", "hello %s", joe, "Howdy Joe!"},
92
93 {"und", "greetings %s and %s", joeAndMary, "greetings Joe and Mary"},
94 {"nl", "greetings %s and %s", joeAndMary, "greetings Joe and Mary"},
95 {"en", "greetings %s and %s", joeAndMary, "Greetings Joe and Mary!"},
96 {"en-US", "greetings %s and %s", joeAndMary, "Greetings Joe and Mary!"},
97 {"en-GB", "greetings %s and %s", joeAndMary, "Greetings Joe and Mary!"},
98 {"en-oxendict", "greetings %s and %s", joeAndMary, "Greetings Joe and Mary!"},
99 {"en-US-oxendict-u-ms-metric", "greetings %s and %s", joeAndMary, "Greetings Joe and Mary!"},
100 },
101 }, {
102 desc: "references",
103 cat: []entry{
104 {"en", "hello", "Hello!"},
105 },
106 test: []test{
107 {"en", "hello", empty, "Hello!"},
108 {"en", Key("hello", "fallback"), empty, "Hello!"},
109 {"en", Key("xxx", "fallback"), empty, "fallback"},
110 {"und", Key("hello", "fallback"), empty, "fallback"},
111 },
112 }, {
113 desc: "zero substitution",
114 cat: []entry{
115 {"en", "hello %s", "Hello!"},
116 {"en", "hi %s and %s", "Hello %[2]s!"},
117 },
118 test: []test{
119 {"en", "hello %s", joe, "Hello!"},
120 {"en", "hello %s", joeAndMary, "Hello!"},
121 {"en", "hi %s and %s", joeAndMary, "Hello Mary!"},
122
123 {"und", "hello", joeAndMary, "hello"},
124 {"und", "hello %%%%", joeAndMary, "hello %%"},
125 {"und", "hello %#%%4.2% ", joeAndMary, "hello %% "},
126 {"und", "hello %s", joeAndMary, "hello Joe%!(EXTRA string=Mary)"},
127 {"und", "hello %+%%s", joeAndMary, "hello %Joe%!(EXTRA string=Mary)"},
128 {"und", "hello %-42%%s ", joeAndMary, "hello %Joe %!(EXTRA string=Mary)"},
129 },
130 }, {
131 desc: "number formatting",
132 cat: []entry{
133 {"und", "files", "%d files left"},
134 {"und", "meters", "%.2f meters"},
135 {"de", "files", "%d Dateien übrig"},
136 },
137 test: []test{
138 {"en", "meters", args(3000.2), "3,000.20 meters"},
139 {"en-u-nu-gujr", "files", args(123456), "૧૨૩,૪૫૬ files left"},
140 {"de", "files", args(1234), "1.234 Dateien übrig"},
141 {"de-CH", "files", args(1234), "1’234 Dateien übrig"},
142 {"de-CH-u-nu-mong", "files", args(1234), "᠑’᠒᠓᠔ Dateien übrig"},
143 },
144 }, {
145 desc: "substitute translation",
146 cat: []entry{
147 {"en", "google", "Google"},
148 {"en", "sub", "%s"},
149 {"en", "visit", "Lookup: %m."},
150 },
151 test: []test{
152 {"en", "visit", args("google"), "Lookup: Google."},
153 {"en", "visit", args("sub"), "Lookup: %s."},
154 },
155 }}
156
157 for _, tc := range testCases {
158 cat, _ := initCat(tc.cat)
159
160 for i, pt := range tc.test {
161 t.Run(fmt.Sprintf("%s:%d", tc.desc, i), func(t *testing.T) {
162 p := NewPrinter(language.MustParse(pt.tag), Catalog(cat))
163
164 if got := p.Sprintf(pt.key, pt.args...); got != pt.want {
165 t.Errorf("Sprintf(%q, %v) = %s; want %s",
166 pt.key, pt.args, got, pt.want)
167 return
168 }
169
170 w := &bytes.Buffer{}
171 p.Fprintf(w, pt.key, pt.args...)
172 if got := w.String(); got != pt.want {
173 t.Errorf("Fprintf(%q, %v) = %s; want %s",
174 pt.key, pt.args, got, pt.want)
175 }
176 })
177 }
178 }
179 }
180
181 type entry struct{ tag, key, msg string }
182
183 func initCat(entries []entry) (*catalog.Builder, []language.Tag) {
184 tags := []language.Tag{}
185 cat := catalog.NewBuilder()
186 for _, e := range entries {
187 tag := language.MustParse(e.tag)
188 tags = append(tags, tag)
189 cat.SetString(tag, e.key, e.msg)
190 }
191 return cat, internal.UniqueTags(tags)
192 }
193
View as plain text