1package gv
2
3import (
4	"math"
5	"strconv"
6	"time"
7
8	"github.com/go-playground/locales"
9	"github.com/go-playground/locales/currency"
10)
11
12type gv 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 // idx = enum of currency code
25	monthsAbbreviated  []string
26	monthsNarrow       []string
27	monthsWide         []string
28	daysAbbreviated    []string
29	daysNarrow         []string
30	daysShort          []string
31	daysWide           []string
32	periodsAbbreviated []string
33	periodsNarrow      []string
34	periodsShort       []string
35	periodsWide        []string
36	erasAbbreviated    []string
37	erasNarrow         []string
38	erasWide           []string
39	timezones          map[string]string
40}
41
42// New returns a new instance of translator for the 'gv' locale
43func New() locales.Translator {
44	return &gv{
45		locale:             "gv",
46		pluralsCardinal:    []locales.PluralRule{2, 3, 4, 5, 6},
47		pluralsOrdinal:     nil,
48		pluralsRange:       nil,
49		timeSeparator:      ":",
50		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", "KES", "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", "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", "UZS", "VEB", "VEF", "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"},
51		monthsAbbreviated:  []string{"", "J-guer", "T-arree", "Mayrnt", "Avrril", "Boaldyn", "M-souree", "J-souree", "Luanistyn", "M-fouyir", "J-fouyir", "M-Houney", "M-Nollick"},
52		monthsWide:         []string{"", "Jerrey-geuree", "Toshiaght-arree", "Mayrnt", "Averil", "Boaldyn", "Mean-souree", "Jerrey-souree", "Luanistyn", "Mean-fouyir", "Jerrey-fouyir", "Mee Houney", "Mee ny Nollick"},
53		daysAbbreviated:    []string{"Jed", "Jel", "Jem", "Jerc", "Jerd", "Jeh", "Jes"},
54		daysWide:           []string{"Jedoonee", "Jelhein", "Jemayrt", "Jercean", "Jerdein", "Jeheiney", "Jesarn"},
55		periodsAbbreviated: []string{"a.m.", "p.m."},
56		periodsWide:        []string{"a.m.", "p.m."},
57		erasAbbreviated:    []string{"RC", "AD"},
58		erasNarrow:         []string{"", ""},
59		erasWide:           []string{"", ""},
60		timezones:          map[string]string{"BOT": "BOT", "VET": "VET", "HNNOMX": "HNNOMX", "COT": "COT", "COST": "COST", "UYST": "UYST", "SAST": "SAST", "WAT": "WAT", "GFT": "GFT", "AKST": "AKST", "CLT": "CLT", "HNCU": "HNCU", "CST": "CST", "MYT": "MYT", "JST": "JST", "HNOG": "HNOG", "WARST": "WARST", "CHAST": "CHAST", "HEPMX": "HEPMX", "WESZ": "WESZ", "BT": "BT", "ACST": "ACST", "ACWST": "ACWST", "WIT": "WIT", "AWDT": "AWDT", "AST": "AST", "NZST": "NZST", "JDT": "JDT", "EST": "EST", "HKST": "HKST", "LHDT": "LHDT", "HAT": "HAT", "CDT": "CDT", "HNEG": "HNEG", "HEEG": "HEEG", "WART": "WART", "HENOMX": "HENOMX", "SRT": "SRT", "HADT": "HADT", "MDT": "MDT", "HNPMX": "HNPMX", "MESZ": "MESZ", "WITA": "WITA", "CLST": "CLST", "TMT": "TMT", "ART": "ART", "PST": "PST", "MST": "MST", "NZDT": "NZDT", "HEOG": "HEOG", "IST": "IST", "HEPM": "HEPM", "HAST": "HAST", "CHADT": "CHADT", "AEDT": "AEDT", "ACDT": "ACDT", "ACWDT": "ACWDT", "MEZ": "MEZ", "CAT": "CAT", "AWST": "AWST", "PDT": "PDT", "WEZ": "WEZ", "HNT": "HNT", "OESZ": "OESZ", "ARST": "ARST", "GMT": "GMT", "GYT": "GYT", "∅∅∅": "∅∅∅", "ADT": "ADT", "SGT": "SGT", "HNPM": "HNPM", "ChST": "ChST", "UYT": "UYT", "LHST": "LHST", "AEST": "AEST", "WIB": "WIB", "ECT": "ECT", "EDT": "EDT", "EAT": "EAT", "OEZ": "OEZ", "HECU": "HECU", "TMST": "TMST", "HKT": "HKT", "AKDT": "AKDT", "WAST": "WAST"},
61	}
62}
63
64// Locale returns the current translators string locale
65func (gv *gv) Locale() string {
66	return gv.locale
67}
68
69// PluralsCardinal returns the list of cardinal plural rules associated with 'gv'
70func (gv *gv) PluralsCardinal() []locales.PluralRule {
71	return gv.pluralsCardinal
72}
73
74// PluralsOrdinal returns the list of ordinal plural rules associated with 'gv'
75func (gv *gv) PluralsOrdinal() []locales.PluralRule {
76	return gv.pluralsOrdinal
77}
78
79// PluralsRange returns the list of range plural rules associated with 'gv'
80func (gv *gv) PluralsRange() []locales.PluralRule {
81	return gv.pluralsRange
82}
83
84// CardinalPluralRule returns the cardinal PluralRule given 'num' and digits/precision of 'v' for 'gv'
85func (gv *gv) CardinalPluralRule(num float64, v uint64) locales.PluralRule {
86
87	n := math.Abs(num)
88	i := int64(n)
89	iMod10 := i % 10
90	iMod100 := i % 100
91
92	if v == 0 && iMod10 == 1 {
93		return locales.PluralRuleOne
94	} else if v == 0 && iMod10 == 2 {
95		return locales.PluralRuleTwo
96	} else if v == 0 && (iMod100 == 0 || iMod100 == 20 || iMod100 == 40 || iMod100 == 60 || iMod100 == 80) {
97		return locales.PluralRuleFew
98	} else if v != 0 {
99		return locales.PluralRuleMany
100	}
101
102	return locales.PluralRuleOther
103}
104
105// OrdinalPluralRule returns the ordinal PluralRule given 'num' and digits/precision of 'v' for 'gv'
106func (gv *gv) OrdinalPluralRule(num float64, v uint64) locales.PluralRule {
107	return locales.PluralRuleUnknown
108}
109
110// RangePluralRule returns the ordinal PluralRule given 'num1', 'num2' and digits/precision of 'v1' and 'v2' for 'gv'
111func (gv *gv) RangePluralRule(num1 float64, v1 uint64, num2 float64, v2 uint64) locales.PluralRule {
112	return locales.PluralRuleUnknown
113}
114
115// MonthAbbreviated returns the locales abbreviated month given the 'month' provided
116func (gv *gv) MonthAbbreviated(month time.Month) string {
117	return gv.monthsAbbreviated[month]
118}
119
120// MonthsAbbreviated returns the locales abbreviated months
121func (gv *gv) MonthsAbbreviated() []string {
122	return gv.monthsAbbreviated[1:]
123}
124
125// MonthNarrow returns the locales narrow month given the 'month' provided
126func (gv *gv) MonthNarrow(month time.Month) string {
127	return gv.monthsNarrow[month]
128}
129
130// MonthsNarrow returns the locales narrow months
131func (gv *gv) MonthsNarrow() []string {
132	return nil
133}
134
135// MonthWide returns the locales wide month given the 'month' provided
136func (gv *gv) MonthWide(month time.Month) string {
137	return gv.monthsWide[month]
138}
139
140// MonthsWide returns the locales wide months
141func (gv *gv) MonthsWide() []string {
142	return gv.monthsWide[1:]
143}
144
145// WeekdayAbbreviated returns the locales abbreviated weekday given the 'weekday' provided
146func (gv *gv) WeekdayAbbreviated(weekday time.Weekday) string {
147	return gv.daysAbbreviated[weekday]
148}
149
150// WeekdaysAbbreviated returns the locales abbreviated weekdays
151func (gv *gv) WeekdaysAbbreviated() []string {
152	return gv.daysAbbreviated
153}
154
155// WeekdayNarrow returns the locales narrow weekday given the 'weekday' provided
156func (gv *gv) WeekdayNarrow(weekday time.Weekday) string {
157	return gv.daysNarrow[weekday]
158}
159
160// WeekdaysNarrow returns the locales narrow weekdays
161func (gv *gv) WeekdaysNarrow() []string {
162	return gv.daysNarrow
163}
164
165// WeekdayShort returns the locales short weekday given the 'weekday' provided
166func (gv *gv) WeekdayShort(weekday time.Weekday) string {
167	return gv.daysShort[weekday]
168}
169
170// WeekdaysShort returns the locales short weekdays
171func (gv *gv) WeekdaysShort() []string {
172	return gv.daysShort
173}
174
175// WeekdayWide returns the locales wide weekday given the 'weekday' provided
176func (gv *gv) WeekdayWide(weekday time.Weekday) string {
177	return gv.daysWide[weekday]
178}
179
180// WeekdaysWide returns the locales wide weekdays
181func (gv *gv) WeekdaysWide() []string {
182	return gv.daysWide
183}
184
185// Decimal returns the decimal point of number
186func (gv *gv) Decimal() string {
187	return gv.decimal
188}
189
190// Group returns the group of number
191func (gv *gv) Group() string {
192	return gv.group
193}
194
195// Group returns the minus sign of number
196func (gv *gv) Minus() string {
197	return gv.minus
198}
199
200// FmtNumber returns 'num' with digits/precision of 'v' for 'gv' and handles both Whole and Real numbers based on 'v'
201func (gv *gv) FmtNumber(num float64, v uint64) string {
202
203	return strconv.FormatFloat(math.Abs(num), 'f', int(v), 64)
204}
205
206// FmtPercent returns 'num' with digits/precision of 'v' for 'gv' and handles both Whole and Real numbers based on 'v'
207// NOTE: 'num' passed into FmtPercent is assumed to be in percent already
208func (gv *gv) FmtPercent(num float64, v uint64) string {
209	return strconv.FormatFloat(math.Abs(num), 'f', int(v), 64)
210}
211
212// FmtCurrency returns the currency representation of 'num' with digits/precision of 'v' for 'gv'
213func (gv *gv) FmtCurrency(num float64, v uint64, currency currency.Type) string {
214
215	s := strconv.FormatFloat(math.Abs(num), 'f', int(v), 64)
216	symbol := gv.currencies[currency]
217	l := len(s) + len(symbol) + 0
218	count := 0
219	inWhole := v == 0
220	b := make([]byte, 0, l)
221
222	for i := len(s) - 1; i >= 0; i-- {
223
224		if s[i] == '.' {
225			b = append(b, gv.decimal[0])
226			inWhole = true
227			continue
228		}
229
230		if inWhole {
231			if count == 3 {
232				b = append(b, gv.group[0])
233				count = 1
234			} else {
235				count++
236			}
237		}
238
239		b = append(b, s[i])
240	}
241
242	for j := len(symbol) - 1; j >= 0; j-- {
243		b = append(b, symbol[j])
244	}
245
246	if num < 0 {
247		b = append(b, gv.minus[0])
248	}
249
250	// reverse
251	for i, j := 0, len(b)-1; i < j; i, j = i+1, j-1 {
252		b[i], b[j] = b[j], b[i]
253	}
254
255	if int(v) < 2 {
256
257		if v == 0 {
258			b = append(b, gv.decimal...)
259		}
260
261		for i := 0; i < 2-int(v); i++ {
262			b = append(b, '0')
263		}
264	}
265
266	return string(b)
267}
268
269// FmtAccounting returns the currency representation of 'num' with digits/precision of 'v' for 'gv'
270// in accounting notation.
271func (gv *gv) FmtAccounting(num float64, v uint64, currency currency.Type) string {
272
273	s := strconv.FormatFloat(math.Abs(num), 'f', int(v), 64)
274	symbol := gv.currencies[currency]
275	l := len(s) + len(symbol) + 0
276	count := 0
277	inWhole := v == 0
278	b := make([]byte, 0, l)
279
280	for i := len(s) - 1; i >= 0; i-- {
281
282		if s[i] == '.' {
283			b = append(b, gv.decimal[0])
284			inWhole = true
285			continue
286		}
287
288		if inWhole {
289			if count == 3 {
290				b = append(b, gv.group[0])
291				count = 1
292			} else {
293				count++
294			}
295		}
296
297		b = append(b, s[i])
298	}
299
300	if num < 0 {
301
302		for j := len(symbol) - 1; j >= 0; j-- {
303			b = append(b, symbol[j])
304		}
305
306		b = append(b, gv.minus[0])
307
308	} else {
309
310		for j := len(symbol) - 1; j >= 0; j-- {
311			b = append(b, symbol[j])
312		}
313
314	}
315
316	// reverse
317	for i, j := 0, len(b)-1; i < j; i, j = i+1, j-1 {
318		b[i], b[j] = b[j], b[i]
319	}
320
321	if int(v) < 2 {
322
323		if v == 0 {
324			b = append(b, gv.decimal...)
325		}
326
327		for i := 0; i < 2-int(v); i++ {
328			b = append(b, '0')
329		}
330	}
331
332	return string(b)
333}
334
335// FmtDateShort returns the short date representation of 't' for 'gv'
336func (gv *gv) FmtDateShort(t time.Time) string {
337
338	b := make([]byte, 0, 32)
339
340	if t.Day() < 10 {
341		b = append(b, '0')
342	}
343
344	b = strconv.AppendInt(b, int64(t.Day()), 10)
345	b = append(b, []byte{0x2f}...)
346
347	if t.Month() < 10 {
348		b = append(b, '0')
349	}
350
351	b = strconv.AppendInt(b, int64(t.Month()), 10)
352
353	b = append(b, []byte{0x2f}...)
354
355	if t.Year() > 9 {
356		b = append(b, strconv.Itoa(t.Year())[2:]...)
357	} else {
358		b = append(b, strconv.Itoa(t.Year())[1:]...)
359	}
360
361	return string(b)
362}
363
364// FmtDateMedium returns the medium date representation of 't' for 'gv'
365func (gv *gv) FmtDateMedium(t time.Time) string {
366
367	b := make([]byte, 0, 32)
368
369	b = append(b, gv.monthsAbbreviated[t.Month()]...)
370	b = append(b, []byte{0x20}...)
371
372	if t.Day() < 10 {
373		b = append(b, '0')
374	}
375
376	b = strconv.AppendInt(b, int64(t.Day()), 10)
377	b = append(b, []byte{0x2c, 0x20}...)
378
379	if t.Year() > 0 {
380		b = strconv.AppendInt(b, int64(t.Year()), 10)
381	} else {
382		b = strconv.AppendInt(b, int64(-t.Year()), 10)
383	}
384
385	return string(b)
386}
387
388// FmtDateLong returns the long date representation of 't' for 'gv'
389func (gv *gv) FmtDateLong(t time.Time) string {
390
391	b := make([]byte, 0, 32)
392
393	if t.Day() < 10 {
394		b = append(b, '0')
395	}
396
397	b = strconv.AppendInt(b, int64(t.Day()), 10)
398	b = append(b, []byte{0x20}...)
399	b = append(b, gv.monthsWide[t.Month()]...)
400	b = append(b, []byte{0x20}...)
401
402	if t.Year() > 0 {
403		b = strconv.AppendInt(b, int64(t.Year()), 10)
404	} else {
405		b = strconv.AppendInt(b, int64(-t.Year()), 10)
406	}
407
408	return string(b)
409}
410
411// FmtDateFull returns the full date representation of 't' for 'gv'
412func (gv *gv) FmtDateFull(t time.Time) string {
413
414	b := make([]byte, 0, 32)
415
416	b = append(b, gv.daysWide[t.Weekday()]...)
417	b = append(b, []byte{0x20}...)
418
419	if t.Day() < 10 {
420		b = append(b, '0')
421	}
422
423	b = strconv.AppendInt(b, int64(t.Day()), 10)
424	b = append(b, []byte{0x20}...)
425	b = append(b, gv.monthsWide[t.Month()]...)
426	b = append(b, []byte{0x20}...)
427
428	if t.Year() > 0 {
429		b = strconv.AppendInt(b, int64(t.Year()), 10)
430	} else {
431		b = strconv.AppendInt(b, int64(-t.Year()), 10)
432	}
433
434	return string(b)
435}
436
437// FmtTimeShort returns the short time representation of 't' for 'gv'
438func (gv *gv) FmtTimeShort(t time.Time) string {
439
440	b := make([]byte, 0, 32)
441
442	if t.Hour() < 10 {
443		b = append(b, '0')
444	}
445
446	b = strconv.AppendInt(b, int64(t.Hour()), 10)
447	b = append(b, gv.timeSeparator...)
448
449	if t.Minute() < 10 {
450		b = append(b, '0')
451	}
452
453	b = strconv.AppendInt(b, int64(t.Minute()), 10)
454
455	return string(b)
456}
457
458// FmtTimeMedium returns the medium time representation of 't' for 'gv'
459func (gv *gv) FmtTimeMedium(t time.Time) string {
460
461	b := make([]byte, 0, 32)
462
463	if t.Hour() < 10 {
464		b = append(b, '0')
465	}
466
467	b = strconv.AppendInt(b, int64(t.Hour()), 10)
468	b = append(b, gv.timeSeparator...)
469
470	if t.Minute() < 10 {
471		b = append(b, '0')
472	}
473
474	b = strconv.AppendInt(b, int64(t.Minute()), 10)
475	b = append(b, gv.timeSeparator...)
476
477	if t.Second() < 10 {
478		b = append(b, '0')
479	}
480
481	b = strconv.AppendInt(b, int64(t.Second()), 10)
482
483	return string(b)
484}
485
486// FmtTimeLong returns the long time representation of 't' for 'gv'
487func (gv *gv) FmtTimeLong(t time.Time) string {
488
489	b := make([]byte, 0, 32)
490
491	if t.Hour() < 10 {
492		b = append(b, '0')
493	}
494
495	b = strconv.AppendInt(b, int64(t.Hour()), 10)
496	b = append(b, gv.timeSeparator...)
497
498	if t.Minute() < 10 {
499		b = append(b, '0')
500	}
501
502	b = strconv.AppendInt(b, int64(t.Minute()), 10)
503	b = append(b, gv.timeSeparator...)
504
505	if t.Second() < 10 {
506		b = append(b, '0')
507	}
508
509	b = strconv.AppendInt(b, int64(t.Second()), 10)
510	b = append(b, []byte{0x20}...)
511
512	tz, _ := t.Zone()
513	b = append(b, tz...)
514
515	return string(b)
516}
517
518// FmtTimeFull returns the full time representation of 't' for 'gv'
519func (gv *gv) FmtTimeFull(t time.Time) string {
520
521	b := make([]byte, 0, 32)
522
523	if t.Hour() < 10 {
524		b = append(b, '0')
525	}
526
527	b = strconv.AppendInt(b, int64(t.Hour()), 10)
528	b = append(b, gv.timeSeparator...)
529
530	if t.Minute() < 10 {
531		b = append(b, '0')
532	}
533
534	b = strconv.AppendInt(b, int64(t.Minute()), 10)
535	b = append(b, gv.timeSeparator...)
536
537	if t.Second() < 10 {
538		b = append(b, '0')
539	}
540
541	b = strconv.AppendInt(b, int64(t.Second()), 10)
542	b = append(b, []byte{0x20}...)
543
544	tz, _ := t.Zone()
545
546	if btz, ok := gv.timezones[tz]; ok {
547		b = append(b, btz...)
548	} else {
549		b = append(b, tz...)
550	}
551
552	return string(b)
553}
554