1package ln
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 ln 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	currencyPositiveSuffix 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// New returns a new instance of translator for the 'ln' locale
45func New() locales.Translator {
46	return &ln{
47		locale:                 "ln",
48		pluralsCardinal:        []locales.PluralRule{2, 6},
49		pluralsOrdinal:         nil,
50		pluralsRange:           nil,
51		decimal:                ",",
52		group:                  ".",
53		minus:                  "-",
54		percent:                "%",
55		perMille:               "‰",
56		timeSeparator:          ":",
57		inifinity:              "∞",
58		currencies:             []string{"ADP", "AED", "AFA", "AFN", "ALK", "ALL", "AMD", "ANG", "Kz", "AOK", "AON", "AOR", "ARA", "ARL", "ARM", "ARP", "ARS", "ATS", "A$", "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", "FC", "CHE", "Fr.", "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", "€", "FIM", "FJD", "FKP", "FRF", "£", "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", "NZ$", "OMR", "PAB", "PEI", "PEN", "PES", "PGK", "PHP", "PKR", "PLN", "PLZ", "PTE", "PYG", "QAR", "RHD", "ROL", "RON", "RSD", "RUB", "RUR", "RF", "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", "T$", "TPE", "TRL", "TRY", "TTD", "TWD", "TZS", "UAH", "UAK", "UGS", "UGX", "USD", "USN", "USS", "UYI", "UYP", "UYU", "UZS", "VEB", "VEF", "VND", "VNN", "VUV", "WST", "FCFA", "XAG", "XAU", "XBA", "XBB", "XBC", "XBD", "XCD", "XDR", "XEU", "XFO", "XFU", "XOF", "XPD", "F CFP", "XPT", "XRE", "XSU", "XTS", "XUA", "XXX", "YDD", "YER", "YUD", "YUM", "YUN", "YUR", "ZAL", "ZAR", "ZMK", "ZMW", "ZRN", "ZRZ", "ZWD", "ZWL", "ZWR"},
59		currencyPositiveSuffix: " ",
60		currencyNegativeSuffix: " ",
61		monthsAbbreviated:      []string{"", "yan", "fbl", "msi", "apl", "mai", "yun", "yul", "agt", "stb", "ɔtb", "nvb", "dsb"},
62		monthsNarrow:           []string{"", "y", "f", "m", "a", "m", "y", "y", "a", "s", "ɔ", "n", "d"},
63		monthsWide:             []string{"", "sánzá ya yambo", "sánzá ya míbalé", "sánzá ya mísáto", "sánzá ya mínei", "sánzá ya mítáno", "sánzá ya motóbá", "sánzá ya nsambo", "sánzá ya mwambe", "sánzá ya libwa", "sánzá ya zómi", "sánzá ya zómi na mɔ̌kɔ́", "sánzá ya zómi na míbalé"},
64		daysAbbreviated:        []string{"eye", "ybo", "mbl", "mst", "min", "mtn", "mps"},
65		daysNarrow:             []string{"e", "y", "m", "m", "m", "m", "p"},
66		daysWide:               []string{"eyenga", "mokɔlɔ mwa yambo", "mokɔlɔ mwa míbalé", "mokɔlɔ mwa mísáto", "mokɔlɔ ya mínéi", "mokɔlɔ ya mítáno", "mpɔ́sɔ"},
67		periodsAbbreviated:     []string{"ntɔ́ngɔ́", "mpókwa"},
68		periodsWide:            []string{"ntɔ́ngɔ́", "mpókwa"},
69		erasAbbreviated:        []string{"libóso ya", "nsima ya Y"},
70		erasNarrow:             []string{"", ""},
71		erasWide:               []string{"Yambo ya Yézu Krís", "Nsima ya Yézu Krís"},
72		timezones:              map[string]string{"CLST": "CLST", "UYST": "UYST", "WIB": "WIB", "HENOMX": "HENOMX", "SRT": "SRT", "GMT": "Ntángo ya Londoni", "WESZ": "WESZ", "JST": "JST", "HEEG": "HEEG", "AEDT": "AEDT", "SAST": "Ntángo ya Afríka ya Sidi", "MESZ": "MESZ", "LHDT": "LHDT", "WITA": "WITA", "CAT": "Ntángo ya Lubumbashi", "OEZ": "OEZ", "HAST": "HAST", "UYT": "UYT", "ADT": "ADT", "AKDT": "AKDT", "OESZ": "OESZ", "GYT": "GYT", "JDT": "JDT", "ECT": "ECT", "MEZ": "MEZ", "HKST": "HKST", "WART": "WART", "CLT": "CLT", "ARST": "ARST", "EST": "EST", "WARST": "WARST", "HAT": "HAT", "TMST": "TMST", "∅∅∅": "∅∅∅", "AWST": "AWST", "AWDT": "AWDT", "AEST": "AEST", "NZDT": "NZDT", "ACWST": "ACWST", "WIT": "WIT", "WAST": "WAST", "EDT": "EDT", "VET": "VET", "HADT": "HADT", "HECU": "HECU", "BT": "BT", "IST": "IST", "LHST": "LHST", "HKT": "HKT", "MST": "MST", "ART": "ART", "HNPMX": "HNPMX", "AST": "AST", "MYT": "MYT", "ACST": "ACST", "HNOG": "HNOG", "HNT": "HNT", "COST": "COST", "CHADT": "CHADT", "PST": "PST", "GFT": "GFT", "HNPM": "HNPM", "ChST": "ChST", "HNCU": "HNCU", "WEZ": "WEZ", "HNEG": "HNEG", "CST": "CST", "CDT": "CDT", "ACWDT": "ACWDT", "BOT": "BOT", "HNNOMX": "HNNOMX", "TMT": "TMT", "HEPMX": "HEPMX", "NZST": "NZST", "SGT": "SGT", "ACDT": "ACDT", "HEPM": "HEPM", "HEOG": "HEOG", "MDT": "MDT", "EAT": "Ntángo ya Afríka ya Ɛ́sita", "COT": "COT", "CHAST": "CHAST", "PDT": "PDT", "WAT": "WAT", "AKST": "AKST"},
73	}
74}
75
76// Locale returns the current translators string locale
77func (ln *ln) Locale() string {
78	return ln.locale
79}
80
81// PluralsCardinal returns the list of cardinal plural rules associated with 'ln'
82func (ln *ln) PluralsCardinal() []locales.PluralRule {
83	return ln.pluralsCardinal
84}
85
86// PluralsOrdinal returns the list of ordinal plural rules associated with 'ln'
87func (ln *ln) PluralsOrdinal() []locales.PluralRule {
88	return ln.pluralsOrdinal
89}
90
91// PluralsRange returns the list of range plural rules associated with 'ln'
92func (ln *ln) PluralsRange() []locales.PluralRule {
93	return ln.pluralsRange
94}
95
96// CardinalPluralRule returns the cardinal PluralRule given 'num' and digits/precision of 'v' for 'ln'
97func (ln *ln) CardinalPluralRule(num float64, v uint64) locales.PluralRule {
98
99	n := math.Abs(num)
100
101	if n >= 0 && n <= 1 {
102		return locales.PluralRuleOne
103	}
104
105	return locales.PluralRuleOther
106}
107
108// OrdinalPluralRule returns the ordinal PluralRule given 'num' and digits/precision of 'v' for 'ln'
109func (ln *ln) OrdinalPluralRule(num float64, v uint64) locales.PluralRule {
110	return locales.PluralRuleUnknown
111}
112
113// RangePluralRule returns the ordinal PluralRule given 'num1', 'num2' and digits/precision of 'v1' and 'v2' for 'ln'
114func (ln *ln) RangePluralRule(num1 float64, v1 uint64, num2 float64, v2 uint64) locales.PluralRule {
115	return locales.PluralRuleUnknown
116}
117
118// MonthAbbreviated returns the locales abbreviated month given the 'month' provided
119func (ln *ln) MonthAbbreviated(month time.Month) string {
120	return ln.monthsAbbreviated[month]
121}
122
123// MonthsAbbreviated returns the locales abbreviated months
124func (ln *ln) MonthsAbbreviated() []string {
125	return ln.monthsAbbreviated[1:]
126}
127
128// MonthNarrow returns the locales narrow month given the 'month' provided
129func (ln *ln) MonthNarrow(month time.Month) string {
130	return ln.monthsNarrow[month]
131}
132
133// MonthsNarrow returns the locales narrow months
134func (ln *ln) MonthsNarrow() []string {
135	return ln.monthsNarrow[1:]
136}
137
138// MonthWide returns the locales wide month given the 'month' provided
139func (ln *ln) MonthWide(month time.Month) string {
140	return ln.monthsWide[month]
141}
142
143// MonthsWide returns the locales wide months
144func (ln *ln) MonthsWide() []string {
145	return ln.monthsWide[1:]
146}
147
148// WeekdayAbbreviated returns the locales abbreviated weekday given the 'weekday' provided
149func (ln *ln) WeekdayAbbreviated(weekday time.Weekday) string {
150	return ln.daysAbbreviated[weekday]
151}
152
153// WeekdaysAbbreviated returns the locales abbreviated weekdays
154func (ln *ln) WeekdaysAbbreviated() []string {
155	return ln.daysAbbreviated
156}
157
158// WeekdayNarrow returns the locales narrow weekday given the 'weekday' provided
159func (ln *ln) WeekdayNarrow(weekday time.Weekday) string {
160	return ln.daysNarrow[weekday]
161}
162
163// WeekdaysNarrow returns the locales narrow weekdays
164func (ln *ln) WeekdaysNarrow() []string {
165	return ln.daysNarrow
166}
167
168// WeekdayShort returns the locales short weekday given the 'weekday' provided
169func (ln *ln) WeekdayShort(weekday time.Weekday) string {
170	return ln.daysShort[weekday]
171}
172
173// WeekdaysShort returns the locales short weekdays
174func (ln *ln) WeekdaysShort() []string {
175	return ln.daysShort
176}
177
178// WeekdayWide returns the locales wide weekday given the 'weekday' provided
179func (ln *ln) WeekdayWide(weekday time.Weekday) string {
180	return ln.daysWide[weekday]
181}
182
183// WeekdaysWide returns the locales wide weekdays
184func (ln *ln) WeekdaysWide() []string {
185	return ln.daysWide
186}
187
188// Decimal returns the decimal point of number
189func (ln *ln) Decimal() string {
190	return ln.decimal
191}
192
193// Group returns the group of number
194func (ln *ln) Group() string {
195	return ln.group
196}
197
198// Group returns the minus sign of number
199func (ln *ln) Minus() string {
200	return ln.minus
201}
202
203// FmtNumber returns 'num' with digits/precision of 'v' for 'ln' and handles both Whole and Real numbers based on 'v'
204func (ln *ln) FmtNumber(num float64, v uint64) string {
205
206	s := strconv.FormatFloat(math.Abs(num), 'f', int(v), 64)
207	l := len(s) + 2 + 1*len(s[:len(s)-int(v)-1])/3
208	count := 0
209	inWhole := v == 0
210	b := make([]byte, 0, l)
211
212	for i := len(s) - 1; i >= 0; i-- {
213
214		if s[i] == '.' {
215			b = append(b, ln.decimal[0])
216			inWhole = true
217			continue
218		}
219
220		if inWhole {
221			if count == 3 {
222				b = append(b, ln.group[0])
223				count = 1
224			} else {
225				count++
226			}
227		}
228
229		b = append(b, s[i])
230	}
231
232	if num < 0 {
233		b = append(b, ln.minus[0])
234	}
235
236	// reverse
237	for i, j := 0, len(b)-1; i < j; i, j = i+1, j-1 {
238		b[i], b[j] = b[j], b[i]
239	}
240
241	return string(b)
242}
243
244// FmtPercent returns 'num' with digits/precision of 'v' for 'ln' and handles both Whole and Real numbers based on 'v'
245// NOTE: 'num' passed into FmtPercent is assumed to be in percent already
246func (ln *ln) FmtPercent(num float64, v uint64) string {
247	return strconv.FormatFloat(math.Abs(num), 'f', int(v), 64)
248}
249
250// FmtCurrency returns the currency representation of 'num' with digits/precision of 'v' for 'ln'
251func (ln *ln) FmtCurrency(num float64, v uint64, currency currency.Type) string {
252
253	s := strconv.FormatFloat(math.Abs(num), 'f', int(v), 64)
254	symbol := ln.currencies[currency]
255	l := len(s) + len(symbol) + 4 + 1*len(s[:len(s)-int(v)-1])/3
256	count := 0
257	inWhole := v == 0
258	b := make([]byte, 0, l)
259
260	for i := len(s) - 1; i >= 0; i-- {
261
262		if s[i] == '.' {
263			b = append(b, ln.decimal[0])
264			inWhole = true
265			continue
266		}
267
268		if inWhole {
269			if count == 3 {
270				b = append(b, ln.group[0])
271				count = 1
272			} else {
273				count++
274			}
275		}
276
277		b = append(b, s[i])
278	}
279
280	if num < 0 {
281		b = append(b, ln.minus[0])
282	}
283
284	// reverse
285	for i, j := 0, len(b)-1; i < j; i, j = i+1, j-1 {
286		b[i], b[j] = b[j], b[i]
287	}
288
289	if int(v) < 2 {
290
291		if v == 0 {
292			b = append(b, ln.decimal...)
293		}
294
295		for i := 0; i < 2-int(v); i++ {
296			b = append(b, '0')
297		}
298	}
299
300	b = append(b, ln.currencyPositiveSuffix...)
301
302	b = append(b, symbol...)
303
304	return string(b)
305}
306
307// FmtAccounting returns the currency representation of 'num' with digits/precision of 'v' for 'ln'
308// in accounting notation.
309func (ln *ln) FmtAccounting(num float64, v uint64, currency currency.Type) string {
310
311	s := strconv.FormatFloat(math.Abs(num), 'f', int(v), 64)
312	symbol := ln.currencies[currency]
313	l := len(s) + len(symbol) + 4 + 1*len(s[:len(s)-int(v)-1])/3
314	count := 0
315	inWhole := v == 0
316	b := make([]byte, 0, l)
317
318	for i := len(s) - 1; i >= 0; i-- {
319
320		if s[i] == '.' {
321			b = append(b, ln.decimal[0])
322			inWhole = true
323			continue
324		}
325
326		if inWhole {
327			if count == 3 {
328				b = append(b, ln.group[0])
329				count = 1
330			} else {
331				count++
332			}
333		}
334
335		b = append(b, s[i])
336	}
337
338	if num < 0 {
339
340		b = append(b, ln.minus[0])
341
342	}
343
344	// reverse
345	for i, j := 0, len(b)-1; i < j; i, j = i+1, j-1 {
346		b[i], b[j] = b[j], b[i]
347	}
348
349	if int(v) < 2 {
350
351		if v == 0 {
352			b = append(b, ln.decimal...)
353		}
354
355		for i := 0; i < 2-int(v); i++ {
356			b = append(b, '0')
357		}
358	}
359
360	if num < 0 {
361		b = append(b, ln.currencyNegativeSuffix...)
362		b = append(b, symbol...)
363	} else {
364
365		b = append(b, ln.currencyPositiveSuffix...)
366		b = append(b, symbol...)
367	}
368
369	return string(b)
370}
371
372// FmtDateShort returns the short date representation of 't' for 'ln'
373func (ln *ln) FmtDateShort(t time.Time) string {
374
375	b := make([]byte, 0, 32)
376
377	b = strconv.AppendInt(b, int64(t.Day()), 10)
378	b = append(b, []byte{0x2f}...)
379	b = strconv.AppendInt(b, int64(t.Month()), 10)
380	b = append(b, []byte{0x2f}...)
381
382	if t.Year() > 0 {
383		b = strconv.AppendInt(b, int64(t.Year()), 10)
384	} else {
385		b = strconv.AppendInt(b, int64(-t.Year()), 10)
386	}
387
388	return string(b)
389}
390
391// FmtDateMedium returns the medium date representation of 't' for 'ln'
392func (ln *ln) FmtDateMedium(t time.Time) string {
393
394	b := make([]byte, 0, 32)
395
396	b = strconv.AppendInt(b, int64(t.Day()), 10)
397	b = append(b, []byte{0x20}...)
398	b = append(b, ln.monthsAbbreviated[t.Month()]...)
399	b = append(b, []byte{0x20}...)
400
401	if t.Year() > 0 {
402		b = strconv.AppendInt(b, int64(t.Year()), 10)
403	} else {
404		b = strconv.AppendInt(b, int64(-t.Year()), 10)
405	}
406
407	return string(b)
408}
409
410// FmtDateLong returns the long date representation of 't' for 'ln'
411func (ln *ln) FmtDateLong(t time.Time) string {
412
413	b := make([]byte, 0, 32)
414
415	b = strconv.AppendInt(b, int64(t.Day()), 10)
416	b = append(b, []byte{0x20}...)
417	b = append(b, ln.monthsWide[t.Month()]...)
418	b = append(b, []byte{0x20}...)
419
420	if t.Year() > 0 {
421		b = strconv.AppendInt(b, int64(t.Year()), 10)
422	} else {
423		b = strconv.AppendInt(b, int64(-t.Year()), 10)
424	}
425
426	return string(b)
427}
428
429// FmtDateFull returns the full date representation of 't' for 'ln'
430func (ln *ln) FmtDateFull(t time.Time) string {
431
432	b := make([]byte, 0, 32)
433
434	b = append(b, ln.daysWide[t.Weekday()]...)
435	b = append(b, []byte{0x20}...)
436	b = strconv.AppendInt(b, int64(t.Day()), 10)
437	b = append(b, []byte{0x20}...)
438	b = append(b, ln.monthsWide[t.Month()]...)
439	b = append(b, []byte{0x20}...)
440
441	if t.Year() > 0 {
442		b = strconv.AppendInt(b, int64(t.Year()), 10)
443	} else {
444		b = strconv.AppendInt(b, int64(-t.Year()), 10)
445	}
446
447	return string(b)
448}
449
450// FmtTimeShort returns the short time representation of 't' for 'ln'
451func (ln *ln) FmtTimeShort(t time.Time) string {
452
453	b := make([]byte, 0, 32)
454
455	if t.Hour() < 10 {
456		b = append(b, '0')
457	}
458
459	b = strconv.AppendInt(b, int64(t.Hour()), 10)
460	b = append(b, ln.timeSeparator...)
461
462	if t.Minute() < 10 {
463		b = append(b, '0')
464	}
465
466	b = strconv.AppendInt(b, int64(t.Minute()), 10)
467
468	return string(b)
469}
470
471// FmtTimeMedium returns the medium time representation of 't' for 'ln'
472func (ln *ln) FmtTimeMedium(t time.Time) string {
473
474	b := make([]byte, 0, 32)
475
476	if t.Hour() < 10 {
477		b = append(b, '0')
478	}
479
480	b = strconv.AppendInt(b, int64(t.Hour()), 10)
481	b = append(b, ln.timeSeparator...)
482
483	if t.Minute() < 10 {
484		b = append(b, '0')
485	}
486
487	b = strconv.AppendInt(b, int64(t.Minute()), 10)
488	b = append(b, ln.timeSeparator...)
489
490	if t.Second() < 10 {
491		b = append(b, '0')
492	}
493
494	b = strconv.AppendInt(b, int64(t.Second()), 10)
495
496	return string(b)
497}
498
499// FmtTimeLong returns the long time representation of 't' for 'ln'
500func (ln *ln) FmtTimeLong(t time.Time) string {
501
502	b := make([]byte, 0, 32)
503
504	if t.Hour() < 10 {
505		b = append(b, '0')
506	}
507
508	b = strconv.AppendInt(b, int64(t.Hour()), 10)
509	b = append(b, ln.timeSeparator...)
510
511	if t.Minute() < 10 {
512		b = append(b, '0')
513	}
514
515	b = strconv.AppendInt(b, int64(t.Minute()), 10)
516	b = append(b, ln.timeSeparator...)
517
518	if t.Second() < 10 {
519		b = append(b, '0')
520	}
521
522	b = strconv.AppendInt(b, int64(t.Second()), 10)
523	b = append(b, []byte{0x20}...)
524
525	tz, _ := t.Zone()
526	b = append(b, tz...)
527
528	return string(b)
529}
530
531// FmtTimeFull returns the full time representation of 't' for 'ln'
532func (ln *ln) FmtTimeFull(t time.Time) string {
533
534	b := make([]byte, 0, 32)
535
536	if t.Hour() < 10 {
537		b = append(b, '0')
538	}
539
540	b = strconv.AppendInt(b, int64(t.Hour()), 10)
541	b = append(b, ln.timeSeparator...)
542
543	if t.Minute() < 10 {
544		b = append(b, '0')
545	}
546
547	b = strconv.AppendInt(b, int64(t.Minute()), 10)
548	b = append(b, ln.timeSeparator...)
549
550	if t.Second() < 10 {
551		b = append(b, '0')
552	}
553
554	b = strconv.AppendInt(b, int64(t.Second()), 10)
555	b = append(b, []byte{0x20}...)
556
557	tz, _ := t.Zone()
558
559	if btz, ok := ln.timezones[tz]; ok {
560		b = append(b, btz...)
561	} else {
562		b = append(b, tz...)
563	}
564
565	return string(b)
566}
567