1 // Copyright 2015 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
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"
19 type formatFunc func(s fmt.State, v rune)
21 func (f formatFunc) Format(s fmt.State, v rune) { f(s, v) }
23 func TestBinding(t *testing.T) {
24 testCases := []struct {
31 { // Language is passed.
33 formatFunc(func(fs fmt.State, v rune) {
34 s := fs.(format.State)
35 io.WriteString(s, s.Language().String())
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)
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)
53 func TestLocalization(t *testing.T) {
60 args := func(x ...interface{}) []interface{} { return x }
61 empty := []interface{}{}
62 joe := []interface{}{"Joe"}
63 joeAndMary := []interface{}{"Joe", "Mary"}
65 testCases := []struct {
72 {"en", "key", empty, "key"},
73 {"en", "", empty, ""},
74 {"nl", "", empty, ""},
77 desc: "hierarchical languages",
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!"},
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!"},
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!"},
104 {"en", "hello", "Hello!"},
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"},
113 desc: "zero substitution", // work around limitation of fmt
115 {"en", "hello %s", "Hello!"},
116 {"en", "hi %s and %s", "Hello %[2]s!"},
119 {"en", "hello %s", joe, "Hello!"},
120 {"en", "hello %s", joeAndMary, "Hello!"},
121 {"en", "hi %s and %s", joeAndMary, "Hello Mary!"},
122 // The following tests resolve to the fallback string.
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)"},
131 desc: "number formatting", // work around limitation of fmt
133 {"und", "files", "%d files left"},
134 {"und", "meters", "%.2f meters"},
135 {"de", "files", "%d Dateien übrig"},
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"},
146 for _, tc := range testCases {
147 cat, _ := initCat(tc.cat)
149 for i, pt := range tc.test {
150 t.Run(fmt.Sprintf("%s:%d", tc.desc, i), func(t *testing.T) {
151 p := NewPrinter(language.MustParse(pt.tag), Catalog(cat))
153 if got := p.Sprintf(pt.key, pt.args...); got != pt.want {
154 t.Errorf("Sprintf(%q, %v) = %s; want %s",
155 pt.key, pt.args, got, pt.want)
156 return // Next error will likely be the same.
160 p.Fprintf(w, pt.key, pt.args...)
161 if got := w.String(); got != pt.want {
162 t.Errorf("Fprintf(%q, %v) = %s; want %s",
163 pt.key, pt.args, got, pt.want)
170 type entry struct{ tag, key, msg string }
172 func initCat(entries []entry) (*catalog.Catalog, []language.Tag) {
173 tags := []language.Tag{}
175 for _, e := range entries {
176 tag := language.MustParse(e.tag)
177 tags = append(tags, tag)
178 cat.SetString(tag, e.key, e.msg)
180 return cat, internal.UniqueTags(tags)