...
1
2
3
4
5 package plural
6
7 import (
8 "fmt"
9 "io"
10 "reflect"
11 "strconv"
12
13 "golang.org/x/text/internal/catmsg"
14 "golang.org/x/text/internal/number"
15 "golang.org/x/text/language"
16 "golang.org/x/text/message/catalog"
17 )
18
19
20
21
22
23 type Interface interface {
24
25
26
27
28 PluralForm(t language.Tag, scale int) (f Form, n int)
29 }
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56 func Selectf(arg int, format string, cases ...interface{}) catalog.Message {
57 var p parser
58
59 fmt.Fprintf(io.Discard, format, &p)
60 m := &message{arg, kindDefault, 0, cases}
61 switch p.verb {
62 case 'g':
63 m.kind = kindPrecision
64 m.scale = p.scale
65 case 'f':
66 m.kind = kindScale
67 m.scale = p.scale
68 case 'e':
69 m.kind = kindScientific
70 m.scale = p.scale
71 case 'd':
72 m.kind = kindScale
73 m.scale = 0
74 default:
75
76 }
77 return m
78 }
79
80 type parser struct {
81 verb rune
82 scale int
83 }
84
85 func (p *parser) Format(s fmt.State, verb rune) {
86 p.verb = verb
87 p.scale = -1
88 if prec, ok := s.Precision(); ok {
89 p.scale = prec
90 }
91 }
92
93 type message struct {
94 arg int
95 kind int
96 scale int
97 cases []interface{}
98 }
99
100 const (
101
102 kindDefault = 0x80 + iota
103 kindScale
104 kindScientific
105 kindPrecision
106 )
107
108 var handle = catmsg.Register("golang.org/x/text/feature/plural:plural", execute)
109
110 func (m *message) Compile(e *catmsg.Encoder) error {
111 e.EncodeMessageType(handle)
112
113 e.EncodeUint(uint64(m.arg))
114
115 e.EncodeUint(uint64(m.kind))
116 if m.kind > kindDefault {
117 e.EncodeUint(uint64(m.scale))
118 }
119
120 forms := validForms(cardinal, e.Language())
121
122 for i := 0; i < len(m.cases); {
123 if err := compileSelector(e, forms, m.cases[i]); err != nil {
124 return err
125 }
126 if i++; i >= len(m.cases) {
127 return fmt.Errorf("plural: no message defined for selector %v", m.cases[i-1])
128 }
129 var msg catalog.Message
130 switch x := m.cases[i].(type) {
131 case string:
132 msg = catalog.String(x)
133 case catalog.Message:
134 msg = x
135 default:
136 return fmt.Errorf("plural: message of type %T; must be string or catalog.Message", x)
137 }
138 if err := e.EncodeMessage(msg); err != nil {
139 return err
140 }
141 i++
142 }
143 return nil
144 }
145
146 func compileSelector(e *catmsg.Encoder, valid []Form, selector interface{}) error {
147 form := Other
148 switch x := selector.(type) {
149 case string:
150 if x == "" {
151 return fmt.Errorf("plural: empty selector")
152 }
153 if c := x[0]; c == '=' || c == '<' {
154 val, err := strconv.ParseUint(x[1:], 10, 16)
155 if err != nil {
156 return fmt.Errorf("plural: invalid number in selector %q: %v", selector, err)
157 }
158 e.EncodeUint(uint64(c))
159 e.EncodeUint(val)
160 return nil
161 }
162 var ok bool
163 form, ok = countMap[x]
164 if !ok {
165 return fmt.Errorf("plural: invalid plural form %q", selector)
166 }
167 case Form:
168 form = x
169 default:
170 return fmt.Errorf("plural: selector of type %T; want string or Form", selector)
171 }
172
173 ok := false
174 for _, f := range valid {
175 if f == form {
176 ok = true
177 break
178 }
179 }
180 if !ok {
181 return fmt.Errorf("plural: form %q not supported for language %q", selector, e.Language())
182 }
183 e.EncodeUint(uint64(form))
184 return nil
185 }
186
187 func execute(d *catmsg.Decoder) bool {
188 lang := d.Language()
189 argN := int(d.DecodeUint())
190 kind := int(d.DecodeUint())
191 scale := -1
192 if kind > kindDefault {
193 scale = int(d.DecodeUint())
194 }
195 form := Other
196 n := -1
197 if arg := d.Arg(argN); arg == nil {
198
199 } else if x, ok := arg.(number.VisibleDigits); ok {
200 d := x.Digits(nil, lang, scale)
201 form, n = cardinal.matchDisplayDigits(lang, &d)
202 } else if x, ok := arg.(Interface); ok {
203
204 form, n = x.PluralForm(lang, scale)
205 } else {
206 var f number.Formatter
207 switch kind {
208 case kindScale:
209 f.InitDecimal(lang)
210 f.SetScale(scale)
211 case kindScientific:
212 f.InitScientific(lang)
213 f.SetScale(scale)
214 case kindPrecision:
215 f.InitDecimal(lang)
216 f.SetPrecision(scale)
217 case kindDefault:
218
219 f.InitDecimal(lang)
220 if k := reflect.TypeOf(arg).Kind(); reflect.Int <= k && k <= reflect.Uintptr {
221 f.SetScale(0)
222 } else {
223 f.SetScale(2)
224 }
225 }
226 var dec number.Decimal
227 dec.Convert(f.RoundingContext, arg)
228 v := number.FormatDigits(&dec, f.RoundingContext)
229 if !v.NaN && !v.Inf {
230 form, n = cardinal.matchDisplayDigits(d.Language(), &v)
231 }
232 }
233 for !d.Done() {
234 f := d.DecodeUint()
235 if (f == '=' && n == int(d.DecodeUint())) ||
236 (f == '<' && 0 <= n && n < int(d.DecodeUint())) ||
237 form == Form(f) ||
238 Other == Form(f) {
239 return d.ExecuteMessage()
240 }
241 d.SkipMessage()
242 }
243 return false
244 }
245
View as plain text