1 package locales
2 3 import (
4 "strconv"
5 "time"
6 7 "github.com/go-playground/locales/currency"
8 )
9 10 // // ErrBadNumberValue is returned when the number passed for
11 // // plural rule determination cannot be parsed
12 // type ErrBadNumberValue struct {
13 // NumberValue string
14 // InnerError error
15 // }
16 17 // // Error returns ErrBadNumberValue error string
18 // func (e *ErrBadNumberValue) Error() string {
19 // return fmt.Sprintf("Invalid Number Value '%s' %s", e.NumberValue, e.InnerError)
20 // }
21 22 // var _ error = new(ErrBadNumberValue)
23 24 // PluralRule denotes the type of plural rules
25 type PluralRule int
26 27 // PluralRule's
28 const (
29 PluralRuleUnknown PluralRule = iota
30 PluralRuleZero // zero
31 PluralRuleOne // one - singular
32 PluralRuleTwo // two - dual
33 PluralRuleFew // few - paucal
34 PluralRuleMany // many - also used for fractions if they have a separate class
35 PluralRuleOther // other - required—general plural form—also used if the language only has a single form
36 )
37 38 const (
39 pluralsString = "UnknownZeroOneTwoFewManyOther"
40 )
41 42 // Translator encapsulates an instance of a locale
43 // NOTE: some values are returned as a []byte just in case the caller
44 // wishes to add more and can help avoid allocations; otherwise just cast as string
45 type Translator interface {
46 47 // The following Functions are for overriding, debugging or developing
48 // with a Translator Locale
49 50 // Locale returns the string value of the translator
51 Locale() string
52 53 // returns an array of cardinal plural rules associated
54 // with this translator
55 PluralsCardinal() []PluralRule
56 57 // returns an array of ordinal plural rules associated
58 // with this translator
59 PluralsOrdinal() []PluralRule
60 61 // returns an array of range plural rules associated
62 // with this translator
63 PluralsRange() []PluralRule
64 65 // returns the cardinal PluralRule given 'num' and digits/precision of 'v' for locale
66 CardinalPluralRule(num float64, v uint64) PluralRule
67 68 // returns the ordinal PluralRule given 'num' and digits/precision of 'v' for locale
69 OrdinalPluralRule(num float64, v uint64) PluralRule
70 71 // returns the ordinal PluralRule given 'num1', 'num2' and digits/precision of 'v1' and 'v2' for locale
72 RangePluralRule(num1 float64, v1 uint64, num2 float64, v2 uint64) PluralRule
73 74 // returns the locales abbreviated month given the 'month' provided
75 MonthAbbreviated(month time.Month) string
76 77 // returns the locales abbreviated months
78 MonthsAbbreviated() []string
79 80 // returns the locales narrow month given the 'month' provided
81 MonthNarrow(month time.Month) string
82 83 // returns the locales narrow months
84 MonthsNarrow() []string
85 86 // returns the locales wide month given the 'month' provided
87 MonthWide(month time.Month) string
88 89 // returns the locales wide months
90 MonthsWide() []string
91 92 // returns the locales abbreviated weekday given the 'weekday' provided
93 WeekdayAbbreviated(weekday time.Weekday) string
94 95 // returns the locales abbreviated weekdays
96 WeekdaysAbbreviated() []string
97 98 // returns the locales narrow weekday given the 'weekday' provided
99 WeekdayNarrow(weekday time.Weekday) string
100 101 // WeekdaysNarrowreturns the locales narrow weekdays
102 WeekdaysNarrow() []string
103 104 // returns the locales short weekday given the 'weekday' provided
105 WeekdayShort(weekday time.Weekday) string
106 107 // returns the locales short weekdays
108 WeekdaysShort() []string
109 110 // returns the locales wide weekday given the 'weekday' provided
111 WeekdayWide(weekday time.Weekday) string
112 113 // returns the locales wide weekdays
114 WeekdaysWide() []string
115 116 // The following Functions are common Formatting functionsfor the Translator's Locale
117 118 // returns 'num' with digits/precision of 'v' for locale and handles both Whole and Real numbers based on 'v'
119 FmtNumber(num float64, v uint64) string
120 121 // returns 'num' with digits/precision of 'v' for locale and handles both Whole and Real numbers based on 'v'
122 // NOTE: 'num' passed into FmtPercent is assumed to be in percent already
123 FmtPercent(num float64, v uint64) string
124 125 // returns the currency representation of 'num' with digits/precision of 'v' for locale
126 FmtCurrency(num float64, v uint64, currency currency.Type) string
127 128 // returns the currency representation of 'num' with digits/precision of 'v' for locale
129 // in accounting notation.
130 FmtAccounting(num float64, v uint64, currency currency.Type) string
131 132 // returns the short date representation of 't' for locale
133 FmtDateShort(t time.Time) string
134 135 // returns the medium date representation of 't' for locale
136 FmtDateMedium(t time.Time) string
137 138 // returns the long date representation of 't' for locale
139 FmtDateLong(t time.Time) string
140 141 // returns the full date representation of 't' for locale
142 FmtDateFull(t time.Time) string
143 144 // returns the short time representation of 't' for locale
145 FmtTimeShort(t time.Time) string
146 147 // returns the medium time representation of 't' for locale
148 FmtTimeMedium(t time.Time) string
149 150 // returns the long time representation of 't' for locale
151 FmtTimeLong(t time.Time) string
152 153 // returns the full time representation of 't' for locale
154 FmtTimeFull(t time.Time) string
155 }
156 157 // String returns the string value of PluralRule
158 func (p PluralRule) String() string {
159 160 switch p {
161 case PluralRuleZero:
162 return pluralsString[7:11]
163 case PluralRuleOne:
164 return pluralsString[11:14]
165 case PluralRuleTwo:
166 return pluralsString[14:17]
167 case PluralRuleFew:
168 return pluralsString[17:20]
169 case PluralRuleMany:
170 return pluralsString[20:24]
171 case PluralRuleOther:
172 return pluralsString[24:]
173 default:
174 return pluralsString[:7]
175 }
176 }
177 178 //
179 // Precision Notes:
180 //
181 // must specify a precision >= 0, and here is why https://play.golang.org/p/LyL90U0Vyh
182 //
183 // v := float64(3.141)
184 // i := float64(int64(v))
185 //
186 // fmt.Println(v - i)
187 //
188 // or
189 //
190 // s := strconv.FormatFloat(v-i, 'f', -1, 64)
191 // fmt.Println(s)
192 //
193 // these will not print what you'd expect: 0.14100000000000001
194 // and so this library requires a precision to be specified, or
195 // inaccurate plural rules could be applied.
196 //
197 //
198 //
199 // n - absolute value of the source number (integer and decimals).
200 // i - integer digits of n.
201 // v - number of visible fraction digits in n, with trailing zeros.
202 // w - number of visible fraction digits in n, without trailing zeros.
203 // f - visible fractional digits in n, with trailing zeros.
204 // t - visible fractional digits in n, without trailing zeros.
205 //
206 //
207 // Func(num float64, v uint64) // v = digits/precision and prevents -1 as a special case as this can lead to very unexpected behaviour, see precision note's above.
208 //
209 // n := math.Abs(num)
210 // i := int64(n)
211 // v := v
212 //
213 //
214 // w := strconv.FormatFloat(num-float64(i), 'f', int(v), 64) // then parse backwards on string until no more zero's....
215 // f := strconv.FormatFloat(n, 'f', int(v), 64) // then turn everything after decimal into an int64
216 // t := strconv.FormatFloat(n, 'f', int(v), 64) // then parse backwards on string until no more zero's....
217 //
218 //
219 //
220 // General Inclusion Rules
221 // - v will always be available inherently
222 // - all require n
223 // - w requires i
224 //
225 226 // W returns the number of visible fraction digits in N, without trailing zeros.
227 func W(n float64, v uint64) (w int64) {
228 229 s := strconv.FormatFloat(n-float64(int64(n)), 'f', int(v), 64)
230 231 // with either be '0' or '0.xxxx', so if 1 then w will be zero
232 // otherwise need to parse
233 if len(s) != 1 {
234 235 s = s[2:]
236 end := len(s) + 1
237 238 for i := end; i >= 0; i-- {
239 if s[i] != '0' {
240 end = i + 1
241 break
242 }
243 }
244 245 w = int64(len(s[:end]))
246 }
247 248 return
249 }
250 251 // F returns the visible fractional digits in N, with trailing zeros.
252 func F(n float64, v uint64) (f int64) {
253 254 s := strconv.FormatFloat(n-float64(int64(n)), 'f', int(v), 64)
255 256 // with either be '0' or '0.xxxx', so if 1 then f will be zero
257 // otherwise need to parse
258 if len(s) != 1 {
259 260 // ignoring error, because it can't fail as we generated
261 // the string internally from a real number
262 f, _ = strconv.ParseInt(s[2:], 10, 64)
263 }
264 265 return
266 }
267 268 // T returns the visible fractional digits in N, without trailing zeros.
269 func T(n float64, v uint64) (t int64) {
270 271 s := strconv.FormatFloat(n-float64(int64(n)), 'f', int(v), 64)
272 273 // with either be '0' or '0.xxxx', so if 1 then t will be zero
274 // otherwise need to parse
275 if len(s) != 1 {
276 277 s = s[2:]
278 end := len(s) + 1
279 280 for i := end; i >= 0; i-- {
281 if s[i] != '0' {
282 end = i + 1
283 break
284 }
285 }
286 287 // ignoring error, because it can't fail as we generated
288 // the string internally from a real number
289 t, _ = strconv.ParseInt(s[:end], 10, 64)
290 }
291 292 return
293 }
294