1package ln 2 3import ( 4 "math" 5 "strconv" 6 "time" 7 8 "github.com/gohugoio/locales" 9 "github.com/gohugoio/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", "MRU", "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", "UYW", "UZS", "VEB", "VEF", "VES", "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{"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": "Ntángo ya Lubumbashi", "CDT": "CDT", "CHADT": "CHADT", "CHAST": "CHAST", "CLST": "CLST", "CLT": "CLT", "COST": "COST", "COT": "COT", "CST": "CST", "ChST": "ChST", "EAT": "Ntángo ya Afríka ya Ɛ́sita", "ECT": "ECT", "EDT": "EDT", "EST": "EST", "GFT": "GFT", "GMT": "Ntángo ya Londoni", "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": "Ntángo ya Afríka ya Sidi", "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", "∅∅∅": "∅∅∅"}, 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