1 package saq
2
3 import (
4 "math"
5 "strconv"
6 "time"
7
8 "github.com/go-playground/locales"
9 "github.com/go-playground/locales/currency"
10 )
11
12 type saq struct {
13 locale string
14 pluralsCardinal []locales.PluralRule
15 pluralsOrdinal []locales.PluralRule
16 pluralsRange []locales.PluralRule
17 decimal string
18 group string
19 minus string
20 percent string
21 perMille string
22 timeSeparator string
23 inifinity string
24 currencies []string
25 currencyNegativePrefix string
26 currencyNegativeSuffix string
27 monthsAbbreviated []string
28 monthsNarrow []string
29 monthsWide []string
30 daysAbbreviated []string
31 daysNarrow []string
32 daysShort []string
33 daysWide []string
34 periodsAbbreviated []string
35 periodsNarrow []string
36 periodsShort []string
37 periodsWide []string
38 erasAbbreviated []string
39 erasNarrow []string
40 erasWide []string
41 timezones map[string]string
42 }
43
44
45 func New() locales.Translator {
46 return &saq{
47 locale: "saq",
48 pluralsCardinal: []locales.PluralRule{2, 6},
49 pluralsOrdinal: nil,
50 pluralsRange: nil,
51 timeSeparator: ":",
52 currencies: []string{"ADP", "AED", "AFA", "AFN", "ALK", "ALL", "AMD", "ANG", "AOA", "AOK", "AON", "AOR", "ARA", "ARL", "ARM", "ARP", "ARS", "ATS", "AUD", "AWG", "AZM", "AZN", "BAD", "BAM", "BAN", "BBD", "BDT", "BEC", "BEF", "BEL", "BGL", "BGM", "BGN", "BGO", "BHD", "BIF", "BMD", "BND", "BOB", "BOL", "BOP", "BOV", "BRB", "BRC", "BRE", "BRL", "BRN", "BRR", "BRZ", "BSD", "BTN", "BUK", "BWP", "BYB", "BYN", "BYR", "BZD", "CAD", "CDF", "CHE", "CHF", "CHW", "CLE", "CLF", "CLP", "CNH", "CNX", "CNY", "COP", "COU", "CRC", "CSD", "CSK", "CUC", "CUP", "CVE", "CYP", "CZK", "DDM", "DEM", "DJF", "DKK", "DOP", "DZD", "ECS", "ECV", "EEK", "EGP", "ERN", "ESA", "ESB", "ESP", "ETB", "EUR", "FIM", "FJD", "FKP", "FRF", "GBP", "GEK", "GEL", "GHC", "GHS", "GIP", "GMD", "GNF", "GNS", "GQE", "GRD", "GTQ", "GWE", "GWP", "GYD", "HKD", "HNL", "HRD", "HRK", "HTG", "HUF", "IDR", "IEP", "ILP", "ILR", "ILS", "INR", "IQD", "IRR", "ISJ", "ISK", "ITL", "JMD", "JOD", "JPY", "Ksh", "KGS", "KHR", "KMF", "KPW", "KRH", "KRO", "KRW", "KWD", "KYD", "KZT", "LAK", "LBP", "LKR", "LRD", "LSL", "LTL", "LTT", "LUC", "LUF", "LUL", "LVL", "LVR", "LYD", "MAD", "MAF", "MCF", "MDC", "MDL", "MGA", "MGF", "MKD", "MKN", "MLF", "MMK", "MNT", "MOP", "MRO", "MRU", "MTL", "MTP", "MUR", "MVP", "MVR", "MWK", "MXN", "MXP", "MXV", "MYR", "MZE", "MZM", "MZN", "NAD", "NGN", "NIC", "NIO", "NLG", "NOK", "NPR", "NZD", "OMR", "PAB", "PEI", "PEN", "PES", "PGK", "PHP", "PKR", "PLN", "PLZ", "PTE", "PYG", "QAR", "RHD", "ROL", "RON", "RSD", "RUB", "RUR", "RWF", "SAR", "SBD", "SCR", "SDD", "SDG", "SDP", "SEK", "SGD", "SHP", "SIT", "SKK", "SLL", "SOS", "SRD", "SRG", "SSP", "STD", "STN", "SUR", "SVC", "SYP", "SZL", "THB", "TJR", "TJS", "TMM", "TMT", "TND", "TOP", "TPE", "TRL", "TRY", "TTD", "TWD", "TZS", "UAH", "UAK", "UGS", "UGX", "USD", "USN", "USS", "UYI", "UYP", "UYU", "UYW", "UZS", "VEB", "VEF", "VES", "VND", "VNN", "VUV", "WST", "XAF", "XAG", "XAU", "XBA", "XBB", "XBC", "XBD", "XCD", "XDR", "XEU", "XFO", "XFU", "XOF", "XPD", "XPF", "XPT", "XRE", "XSU", "XTS", "XUA", "XXX", "YDD", "YER", "YUD", "YUM", "YUN", "YUR", "ZAL", "ZAR", "ZMK", "ZMW", "ZRN", "ZRZ", "ZWD", "ZWL", "ZWR"},
53 currencyNegativePrefix: "(",
54 currencyNegativeSuffix: ")",
55 monthsAbbreviated: []string{"", "Obo", "Waa", "Oku", "Ong", "Ime", "Ile", "Sap", "Isi", "Saa", "Tom", "Tob", "Tow"},
56 monthsNarrow: []string{"", "O", "W", "O", "O", "I", "I", "S", "I", "S", "T", "T", "T"},
57 monthsWide: []string{"", "Lapa le obo", "Lapa le waare", "Lapa le okuni", "Lapa le ong’wan", "Lapa le imet", "Lapa le ile", "Lapa le sapa", "Lapa le isiet", "Lapa le saal", "Lapa le tomon", "Lapa le tomon obo", "Lapa le tomon waare"},
58 daysAbbreviated: []string{"Are", "Kun", "Ong", "Ine", "Ile", "Sap", "Kwe"},
59 daysNarrow: []string{"A", "K", "O", "I", "I", "S", "K"},
60 daysWide: []string{"Mderot ee are", "Mderot ee kuni", "Mderot ee ong’wan", "Mderot ee inet", "Mderot ee ile", "Mderot ee sapa", "Mderot ee kwe"},
61 periodsAbbreviated: []string{"Tesiran", "Teipa"},
62 periodsWide: []string{"Tesiran", "Teipa"},
63 erasAbbreviated: []string{"KK", "BK"},
64 erasNarrow: []string{"", ""},
65 erasWide: []string{"Kabla ya Christo", "Baada ya Christo"},
66 timezones: map[string]string{"ACDT": "ACDT", "ACST": "ACST", "ACWDT": "ACWDT", "ACWST": "ACWST", "ADT": "ADT", "AEDT": "AEDT", "AEST": "AEST", "AKDT": "AKDT", "AKST": "AKST", "ARST": "ARST", "ART": "ART", "AST": "AST", "AWDT": "AWDT", "AWST": "AWST", "BOT": "BOT", "BT": "BT", "CAT": "CAT", "CDT": "CDT", "CHADT": "CHADT", "CHAST": "CHAST", "CLST": "CLST", "CLT": "CLT", "COST": "COST", "COT": "COT", "CST": "CST", "ChST": "ChST", "EAT": "EAT", "ECT": "ECT", "EDT": "EDT", "EST": "EST", "GFT": "GFT", "GMT": "GMT", "GST": "GST", "GYT": "GYT", "HADT": "HADT", "HAST": "HAST", "HAT": "HAT", "HECU": "HECU", "HEEG": "HEEG", "HENOMX": "HENOMX", "HEOG": "HEOG", "HEPM": "HEPM", "HEPMX": "HEPMX", "HKST": "HKST", "HKT": "HKT", "HNCU": "HNCU", "HNEG": "HNEG", "HNNOMX": "HNNOMX", "HNOG": "HNOG", "HNPM": "HNPM", "HNPMX": "HNPMX", "HNT": "HNT", "IST": "IST", "JDT": "JDT", "JST": "JST", "LHDT": "LHDT", "LHST": "LHST", "MDT": "MDT", "MESZ": "MESZ", "MEZ": "MEZ", "MST": "MST", "MYT": "MYT", "NZDT": "NZDT", "NZST": "NZST", "OESZ": "OESZ", "OEZ": "OEZ", "PDT": "PDT", "PST": "PST", "SAST": "SAST", "SGT": "SGT", "SRT": "SRT", "TMST": "TMST", "TMT": "TMT", "UYST": "UYST", "UYT": "UYT", "VET": "VET", "WARST": "WARST", "WART": "WART", "WAST": "WAST", "WAT": "WAT", "WESZ": "WESZ", "WEZ": "WEZ", "WIB": "WIB", "WIT": "WIT", "WITA": "WITA", "∅∅∅": "∅∅∅"},
67 }
68 }
69
70
71 func (saq *saq) Locale() string {
72 return saq.locale
73 }
74
75
76 func (saq *saq) PluralsCardinal() []locales.PluralRule {
77 return saq.pluralsCardinal
78 }
79
80
81 func (saq *saq) PluralsOrdinal() []locales.PluralRule {
82 return saq.pluralsOrdinal
83 }
84
85
86 func (saq *saq) PluralsRange() []locales.PluralRule {
87 return saq.pluralsRange
88 }
89
90
91 func (saq *saq) CardinalPluralRule(num float64, v uint64) locales.PluralRule {
92
93 n := math.Abs(num)
94
95 if n == 1 {
96 return locales.PluralRuleOne
97 }
98
99 return locales.PluralRuleOther
100 }
101
102
103 func (saq *saq) OrdinalPluralRule(num float64, v uint64) locales.PluralRule {
104 return locales.PluralRuleUnknown
105 }
106
107
108 func (saq *saq) RangePluralRule(num1 float64, v1 uint64, num2 float64, v2 uint64) locales.PluralRule {
109 return locales.PluralRuleUnknown
110 }
111
112
113 func (saq *saq) MonthAbbreviated(month time.Month) string {
114 return saq.monthsAbbreviated[month]
115 }
116
117
118 func (saq *saq) MonthsAbbreviated() []string {
119 return saq.monthsAbbreviated[1:]
120 }
121
122
123 func (saq *saq) MonthNarrow(month time.Month) string {
124 return saq.monthsNarrow[month]
125 }
126
127
128 func (saq *saq) MonthsNarrow() []string {
129 return saq.monthsNarrow[1:]
130 }
131
132
133 func (saq *saq) MonthWide(month time.Month) string {
134 return saq.monthsWide[month]
135 }
136
137
138 func (saq *saq) MonthsWide() []string {
139 return saq.monthsWide[1:]
140 }
141
142
143 func (saq *saq) WeekdayAbbreviated(weekday time.Weekday) string {
144 return saq.daysAbbreviated[weekday]
145 }
146
147
148 func (saq *saq) WeekdaysAbbreviated() []string {
149 return saq.daysAbbreviated
150 }
151
152
153 func (saq *saq) WeekdayNarrow(weekday time.Weekday) string {
154 return saq.daysNarrow[weekday]
155 }
156
157
158 func (saq *saq) WeekdaysNarrow() []string {
159 return saq.daysNarrow
160 }
161
162
163 func (saq *saq) WeekdayShort(weekday time.Weekday) string {
164 return saq.daysShort[weekday]
165 }
166
167
168 func (saq *saq) WeekdaysShort() []string {
169 return saq.daysShort
170 }
171
172
173 func (saq *saq) WeekdayWide(weekday time.Weekday) string {
174 return saq.daysWide[weekday]
175 }
176
177
178 func (saq *saq) WeekdaysWide() []string {
179 return saq.daysWide
180 }
181
182
183 func (saq *saq) Decimal() string {
184 return saq.decimal
185 }
186
187
188 func (saq *saq) Group() string {
189 return saq.group
190 }
191
192
193 func (saq *saq) Minus() string {
194 return saq.minus
195 }
196
197
198 func (saq *saq) FmtNumber(num float64, v uint64) string {
199
200 return strconv.FormatFloat(math.Abs(num), 'f', int(v), 64)
201 }
202
203
204
205 func (saq *saq) FmtPercent(num float64, v uint64) string {
206 return strconv.FormatFloat(math.Abs(num), 'f', int(v), 64)
207 }
208
209
210 func (saq *saq) FmtCurrency(num float64, v uint64, currency currency.Type) string {
211
212 s := strconv.FormatFloat(math.Abs(num), 'f', int(v), 64)
213 symbol := saq.currencies[currency]
214 l := len(s) + len(symbol) + 0
215 count := 0
216 inWhole := v == 0
217 b := make([]byte, 0, l)
218
219 for i := len(s) - 1; i >= 0; i-- {
220
221 if s[i] == '.' {
222 b = append(b, saq.decimal[0])
223 inWhole = true
224 continue
225 }
226
227 if inWhole {
228 if count == 3 {
229 b = append(b, saq.group[0])
230 count = 1
231 } else {
232 count++
233 }
234 }
235
236 b = append(b, s[i])
237 }
238
239 for j := len(symbol) - 1; j >= 0; j-- {
240 b = append(b, symbol[j])
241 }
242
243 if num < 0 {
244 b = append(b, saq.minus[0])
245 }
246
247
248 for i, j := 0, len(b)-1; i < j; i, j = i+1, j-1 {
249 b[i], b[j] = b[j], b[i]
250 }
251
252 if int(v) < 2 {
253
254 if v == 0 {
255 b = append(b, saq.decimal...)
256 }
257
258 for i := 0; i < 2-int(v); i++ {
259 b = append(b, '0')
260 }
261 }
262
263 return string(b)
264 }
265
266
267
268 func (saq *saq) FmtAccounting(num float64, v uint64, currency currency.Type) string {
269
270 s := strconv.FormatFloat(math.Abs(num), 'f', int(v), 64)
271 symbol := saq.currencies[currency]
272 l := len(s) + len(symbol) + 2
273 count := 0
274 inWhole := v == 0
275 b := make([]byte, 0, l)
276
277 for i := len(s) - 1; i >= 0; i-- {
278
279 if s[i] == '.' {
280 b = append(b, saq.decimal[0])
281 inWhole = true
282 continue
283 }
284
285 if inWhole {
286 if count == 3 {
287 b = append(b, saq.group[0])
288 count = 1
289 } else {
290 count++
291 }
292 }
293
294 b = append(b, s[i])
295 }
296
297 if num < 0 {
298
299 for j := len(symbol) - 1; j >= 0; j-- {
300 b = append(b, symbol[j])
301 }
302
303 b = append(b, saq.currencyNegativePrefix[0])
304
305 } else {
306
307 for j := len(symbol) - 1; j >= 0; j-- {
308 b = append(b, symbol[j])
309 }
310
311 }
312
313
314 for i, j := 0, len(b)-1; i < j; i, j = i+1, j-1 {
315 b[i], b[j] = b[j], b[i]
316 }
317
318 if int(v) < 2 {
319
320 if v == 0 {
321 b = append(b, saq.decimal...)
322 }
323
324 for i := 0; i < 2-int(v); i++ {
325 b = append(b, '0')
326 }
327 }
328
329 if num < 0 {
330 b = append(b, saq.currencyNegativeSuffix...)
331 }
332
333 return string(b)
334 }
335
336
337 func (saq *saq) FmtDateShort(t time.Time) string {
338
339 b := make([]byte, 0, 32)
340
341 if t.Day() < 10 {
342 b = append(b, '0')
343 }
344
345 b = strconv.AppendInt(b, int64(t.Day()), 10)
346 b = append(b, []byte{0x2f}...)
347
348 if t.Month() < 10 {
349 b = append(b, '0')
350 }
351
352 b = strconv.AppendInt(b, int64(t.Month()), 10)
353
354 b = append(b, []byte{0x2f}...)
355
356 if t.Year() > 0 {
357 b = strconv.AppendInt(b, int64(t.Year()), 10)
358 } else {
359 b = strconv.AppendInt(b, int64(-t.Year()), 10)
360 }
361
362 return string(b)
363 }
364
365
366 func (saq *saq) FmtDateMedium(t time.Time) string {
367
368 b := make([]byte, 0, 32)
369
370 b = strconv.AppendInt(b, int64(t.Day()), 10)
371 b = append(b, []byte{0x20}...)
372 b = append(b, saq.monthsAbbreviated[t.Month()]...)
373 b = append(b, []byte{0x20}...)
374
375 if t.Year() > 0 {
376 b = strconv.AppendInt(b, int64(t.Year()), 10)
377 } else {
378 b = strconv.AppendInt(b, int64(-t.Year()), 10)
379 }
380
381 return string(b)
382 }
383
384
385 func (saq *saq) FmtDateLong(t time.Time) string {
386
387 b := make([]byte, 0, 32)
388
389 b = strconv.AppendInt(b, int64(t.Day()), 10)
390 b = append(b, []byte{0x20}...)
391 b = append(b, saq.monthsWide[t.Month()]...)
392 b = append(b, []byte{0x20}...)
393
394 if t.Year() > 0 {
395 b = strconv.AppendInt(b, int64(t.Year()), 10)
396 } else {
397 b = strconv.AppendInt(b, int64(-t.Year()), 10)
398 }
399
400 return string(b)
401 }
402
403
404 func (saq *saq) FmtDateFull(t time.Time) string {
405
406 b := make([]byte, 0, 32)
407
408 b = append(b, saq.daysWide[t.Weekday()]...)
409 b = append(b, []byte{0x2c, 0x20}...)
410 b = strconv.AppendInt(b, int64(t.Day()), 10)
411 b = append(b, []byte{0x20}...)
412 b = append(b, saq.monthsWide[t.Month()]...)
413 b = append(b, []byte{0x20}...)
414
415 if t.Year() > 0 {
416 b = strconv.AppendInt(b, int64(t.Year()), 10)
417 } else {
418 b = strconv.AppendInt(b, int64(-t.Year()), 10)
419 }
420
421 return string(b)
422 }
423
424
425 func (saq *saq) FmtTimeShort(t time.Time) string {
426
427 b := make([]byte, 0, 32)
428
429 if t.Hour() < 10 {
430 b = append(b, '0')
431 }
432
433 b = strconv.AppendInt(b, int64(t.Hour()), 10)
434 b = append(b, saq.timeSeparator...)
435
436 if t.Minute() < 10 {
437 b = append(b, '0')
438 }
439
440 b = strconv.AppendInt(b, int64(t.Minute()), 10)
441
442 return string(b)
443 }
444
445
446 func (saq *saq) FmtTimeMedium(t time.Time) string {
447
448 b := make([]byte, 0, 32)
449
450 if t.Hour() < 10 {
451 b = append(b, '0')
452 }
453
454 b = strconv.AppendInt(b, int64(t.Hour()), 10)
455 b = append(b, saq.timeSeparator...)
456
457 if t.Minute() < 10 {
458 b = append(b, '0')
459 }
460
461 b = strconv.AppendInt(b, int64(t.Minute()), 10)
462 b = append(b, saq.timeSeparator...)
463
464 if t.Second() < 10 {
465 b = append(b, '0')
466 }
467
468 b = strconv.AppendInt(b, int64(t.Second()), 10)
469
470 return string(b)
471 }
472
473
474 func (saq *saq) FmtTimeLong(t time.Time) string {
475
476 b := make([]byte, 0, 32)
477
478 if t.Hour() < 10 {
479 b = append(b, '0')
480 }
481
482 b = strconv.AppendInt(b, int64(t.Hour()), 10)
483 b = append(b, saq.timeSeparator...)
484
485 if t.Minute() < 10 {
486 b = append(b, '0')
487 }
488
489 b = strconv.AppendInt(b, int64(t.Minute()), 10)
490 b = append(b, saq.timeSeparator...)
491
492 if t.Second() < 10 {
493 b = append(b, '0')
494 }
495
496 b = strconv.AppendInt(b, int64(t.Second()), 10)
497 b = append(b, []byte{0x20}...)
498
499 tz, _ := t.Zone()
500 b = append(b, tz...)
501
502 return string(b)
503 }
504
505
506 func (saq *saq) FmtTimeFull(t time.Time) string {
507
508 b := make([]byte, 0, 32)
509
510 if t.Hour() < 10 {
511 b = append(b, '0')
512 }
513
514 b = strconv.AppendInt(b, int64(t.Hour()), 10)
515 b = append(b, saq.timeSeparator...)
516
517 if t.Minute() < 10 {
518 b = append(b, '0')
519 }
520
521 b = strconv.AppendInt(b, int64(t.Minute()), 10)
522 b = append(b, saq.timeSeparator...)
523
524 if t.Second() < 10 {
525 b = append(b, '0')
526 }
527
528 b = strconv.AppendInt(b, int64(t.Second()), 10)
529 b = append(b, []byte{0x20}...)
530
531 tz, _ := t.Zone()
532
533 if btz, ok := saq.timezones[tz]; ok {
534 b = append(b, btz...)
535 } else {
536 b = append(b, tz...)
537 }
538
539 return string(b)
540 }
541
View as plain text