1package xh 2 3import ( 4 "math" 5 "strconv" 6 "time" 7 8 "github.com/gohugoio/locales" 9 "github.com/gohugoio/locales/currency" 10) 11 12type xh 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 'xh' locale 43func New() locales.Translator { 44 return &xh{ 45 locale: "xh", 46 pluralsCardinal: []locales.PluralRule{2, 6}, 47 pluralsOrdinal: nil, 48 pluralsRange: nil, 49 decimal: ".", 50 group: " ", 51 minus: "-", 52 percent: "%", 53 timeSeparator: ":", 54 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", "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", "R", "ZMK", "ZMW", "ZRN", "ZRZ", "ZWD", "ZWL", "ZWR"}, 55 monthsAbbreviated: []string{"", "Jan", "Feb", "Mat", "Epr", "Mey", "Jun", "Jul", "Aga", "Sep", "Okt", "Nov", "Dis"}, 56 monthsNarrow: []string{"", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"}, 57 monthsWide: []string{"", "Janyuwari", "Februwari", "Matshi", "Epreli", "Meyi", "Juni", "Julayi", "Agasti", "Septemba", "Okthoba", "Novemba", "Disemba"}, 58 daysAbbreviated: []string{"Caw", "Mvu", "Bin", "Tha", "Sin", "Hla", "Mgq"}, 59 daysNarrow: []string{"S", "M", "T", "W", "T", "F", "S"}, 60 daysWide: []string{"Cawe", "Mvulo", "Lwesibini", "Lwesithathu", "Lwesine", "Lwesihlanu", "Mgqibelo"}, 61 periodsWide: []string{"AM", "PM"}, 62 erasAbbreviated: []string{"BC", "AD"}, 63 erasNarrow: []string{"", ""}, 64 erasWide: []string{"BC", "umnyaka wokuzalwa kukaYesu"}, 65 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", "∅∅∅": "∅∅∅"}, 66 } 67} 68 69// Locale returns the current translators string locale 70func (xh *xh) Locale() string { 71 return xh.locale 72} 73 74// PluralsCardinal returns the list of cardinal plural rules associated with 'xh' 75func (xh *xh) PluralsCardinal() []locales.PluralRule { 76 return xh.pluralsCardinal 77} 78 79// PluralsOrdinal returns the list of ordinal plural rules associated with 'xh' 80func (xh *xh) PluralsOrdinal() []locales.PluralRule { 81 return xh.pluralsOrdinal 82} 83 84// PluralsRange returns the list of range plural rules associated with 'xh' 85func (xh *xh) PluralsRange() []locales.PluralRule { 86 return xh.pluralsRange 87} 88 89// CardinalPluralRule returns the cardinal PluralRule given 'num' and digits/precision of 'v' for 'xh' 90func (xh *xh) CardinalPluralRule(num float64, v uint64) locales.PluralRule { 91 92 n := math.Abs(num) 93 94 if n == 1 { 95 return locales.PluralRuleOne 96 } 97 98 return locales.PluralRuleOther 99} 100 101// OrdinalPluralRule returns the ordinal PluralRule given 'num' and digits/precision of 'v' for 'xh' 102func (xh *xh) OrdinalPluralRule(num float64, v uint64) locales.PluralRule { 103 return locales.PluralRuleUnknown 104} 105 106// RangePluralRule returns the ordinal PluralRule given 'num1', 'num2' and digits/precision of 'v1' and 'v2' for 'xh' 107func (xh *xh) RangePluralRule(num1 float64, v1 uint64, num2 float64, v2 uint64) locales.PluralRule { 108 return locales.PluralRuleUnknown 109} 110 111// MonthAbbreviated returns the locales abbreviated month given the 'month' provided 112func (xh *xh) MonthAbbreviated(month time.Month) string { 113 return xh.monthsAbbreviated[month] 114} 115 116// MonthsAbbreviated returns the locales abbreviated months 117func (xh *xh) MonthsAbbreviated() []string { 118 return xh.monthsAbbreviated[1:] 119} 120 121// MonthNarrow returns the locales narrow month given the 'month' provided 122func (xh *xh) MonthNarrow(month time.Month) string { 123 return xh.monthsNarrow[month] 124} 125 126// MonthsNarrow returns the locales narrow months 127func (xh *xh) MonthsNarrow() []string { 128 return xh.monthsNarrow[1:] 129} 130 131// MonthWide returns the locales wide month given the 'month' provided 132func (xh *xh) MonthWide(month time.Month) string { 133 return xh.monthsWide[month] 134} 135 136// MonthsWide returns the locales wide months 137func (xh *xh) MonthsWide() []string { 138 return xh.monthsWide[1:] 139} 140 141// WeekdayAbbreviated returns the locales abbreviated weekday given the 'weekday' provided 142func (xh *xh) WeekdayAbbreviated(weekday time.Weekday) string { 143 return xh.daysAbbreviated[weekday] 144} 145 146// WeekdaysAbbreviated returns the locales abbreviated weekdays 147func (xh *xh) WeekdaysAbbreviated() []string { 148 return xh.daysAbbreviated 149} 150 151// WeekdayNarrow returns the locales narrow weekday given the 'weekday' provided 152func (xh *xh) WeekdayNarrow(weekday time.Weekday) string { 153 return xh.daysNarrow[weekday] 154} 155 156// WeekdaysNarrow returns the locales narrow weekdays 157func (xh *xh) WeekdaysNarrow() []string { 158 return xh.daysNarrow 159} 160 161// WeekdayShort returns the locales short weekday given the 'weekday' provided 162func (xh *xh) WeekdayShort(weekday time.Weekday) string { 163 return xh.daysShort[weekday] 164} 165 166// WeekdaysShort returns the locales short weekdays 167func (xh *xh) WeekdaysShort() []string { 168 return xh.daysShort 169} 170 171// WeekdayWide returns the locales wide weekday given the 'weekday' provided 172func (xh *xh) WeekdayWide(weekday time.Weekday) string { 173 return xh.daysWide[weekday] 174} 175 176// WeekdaysWide returns the locales wide weekdays 177func (xh *xh) WeekdaysWide() []string { 178 return xh.daysWide 179} 180 181// Decimal returns the decimal point of number 182func (xh *xh) Decimal() string { 183 return xh.decimal 184} 185 186// Group returns the group of number 187func (xh *xh) Group() string { 188 return xh.group 189} 190 191// Group returns the minus sign of number 192func (xh *xh) Minus() string { 193 return xh.minus 194} 195 196// FmtNumber returns 'num' with digits/precision of 'v' for 'xh' and handles both Whole and Real numbers based on 'v' 197func (xh *xh) FmtNumber(num float64, v uint64) string { 198 199 s := strconv.FormatFloat(math.Abs(num), 'f', int(v), 64) 200 l := len(s) + 2 + 2*len(s[:len(s)-int(v)-1])/3 201 count := 0 202 inWhole := v == 0 203 b := make([]byte, 0, l) 204 205 for i := len(s) - 1; i >= 0; i-- { 206 207 if s[i] == '.' { 208 b = append(b, xh.decimal[0]) 209 inWhole = true 210 continue 211 } 212 213 if inWhole { 214 if count == 3 { 215 for j := len(xh.group) - 1; j >= 0; j-- { 216 b = append(b, xh.group[j]) 217 } 218 count = 1 219 } else { 220 count++ 221 } 222 } 223 224 b = append(b, s[i]) 225 } 226 227 if num < 0 { 228 b = append(b, xh.minus[0]) 229 } 230 231 // reverse 232 for i, j := 0, len(b)-1; i < j; i, j = i+1, j-1 { 233 b[i], b[j] = b[j], b[i] 234 } 235 236 return string(b) 237} 238 239// FmtPercent returns 'num' with digits/precision of 'v' for 'xh' and handles both Whole and Real numbers based on 'v' 240// NOTE: 'num' passed into FmtPercent is assumed to be in percent already 241func (xh *xh) FmtPercent(num float64, v uint64) string { 242 s := strconv.FormatFloat(math.Abs(num), 'f', int(v), 64) 243 l := len(s) + 3 244 b := make([]byte, 0, l) 245 246 for i := len(s) - 1; i >= 0; i-- { 247 248 if s[i] == '.' { 249 b = append(b, xh.decimal[0]) 250 continue 251 } 252 253 b = append(b, s[i]) 254 } 255 256 if num < 0 { 257 b = append(b, xh.minus[0]) 258 } 259 260 // reverse 261 for i, j := 0, len(b)-1; i < j; i, j = i+1, j-1 { 262 b[i], b[j] = b[j], b[i] 263 } 264 265 b = append(b, xh.percent...) 266 267 return string(b) 268} 269 270// FmtCurrency returns the currency representation of 'num' with digits/precision of 'v' for 'xh' 271func (xh *xh) FmtCurrency(num float64, v uint64, currency currency.Type) string { 272 273 s := strconv.FormatFloat(math.Abs(num), 'f', int(v), 64) 274 symbol := xh.currencies[currency] 275 l := len(s) + len(symbol) + 2 + 2*len(s[:len(s)-int(v)-1])/3 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, xh.decimal[0]) 284 inWhole = true 285 continue 286 } 287 288 if inWhole { 289 if count == 3 { 290 for j := len(xh.group) - 1; j >= 0; j-- { 291 b = append(b, xh.group[j]) 292 } 293 count = 1 294 } else { 295 count++ 296 } 297 } 298 299 b = append(b, s[i]) 300 } 301 302 for j := len(symbol) - 1; j >= 0; j-- { 303 b = append(b, symbol[j]) 304 } 305 306 if num < 0 { 307 b = append(b, xh.minus[0]) 308 } 309 310 // reverse 311 for i, j := 0, len(b)-1; i < j; i, j = i+1, j-1 { 312 b[i], b[j] = b[j], b[i] 313 } 314 315 if int(v) < 2 { 316 317 if v == 0 { 318 b = append(b, xh.decimal...) 319 } 320 321 for i := 0; i < 2-int(v); i++ { 322 b = append(b, '0') 323 } 324 } 325 326 return string(b) 327} 328 329// FmtAccounting returns the currency representation of 'num' with digits/precision of 'v' for 'xh' 330// in accounting notation. 331func (xh *xh) FmtAccounting(num float64, v uint64, currency currency.Type) string { 332 333 s := strconv.FormatFloat(math.Abs(num), 'f', int(v), 64) 334 symbol := xh.currencies[currency] 335 l := len(s) + len(symbol) + 2 + 2*len(s[:len(s)-int(v)-1])/3 336 count := 0 337 inWhole := v == 0 338 b := make([]byte, 0, l) 339 340 for i := len(s) - 1; i >= 0; i-- { 341 342 if s[i] == '.' { 343 b = append(b, xh.decimal[0]) 344 inWhole = true 345 continue 346 } 347 348 if inWhole { 349 if count == 3 { 350 for j := len(xh.group) - 1; j >= 0; j-- { 351 b = append(b, xh.group[j]) 352 } 353 count = 1 354 } else { 355 count++ 356 } 357 } 358 359 b = append(b, s[i]) 360 } 361 362 if num < 0 { 363 364 for j := len(symbol) - 1; j >= 0; j-- { 365 b = append(b, symbol[j]) 366 } 367 368 b = append(b, xh.minus[0]) 369 370 } else { 371 372 for j := len(symbol) - 1; j >= 0; j-- { 373 b = append(b, symbol[j]) 374 } 375 376 } 377 378 // reverse 379 for i, j := 0, len(b)-1; i < j; i, j = i+1, j-1 { 380 b[i], b[j] = b[j], b[i] 381 } 382 383 if int(v) < 2 { 384 385 if v == 0 { 386 b = append(b, xh.decimal...) 387 } 388 389 for i := 0; i < 2-int(v); i++ { 390 b = append(b, '0') 391 } 392 } 393 394 return string(b) 395} 396 397// FmtDateShort returns the short date representation of 't' for 'xh' 398func (xh *xh) FmtDateShort(t time.Time) string { 399 400 b := make([]byte, 0, 32) 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 b = append(b, []byte{0x2d}...) 409 410 if t.Month() < 10 { 411 b = append(b, '0') 412 } 413 414 b = strconv.AppendInt(b, int64(t.Month()), 10) 415 416 b = append(b, []byte{0x2d}...) 417 418 if t.Day() < 10 { 419 b = append(b, '0') 420 } 421 422 b = strconv.AppendInt(b, int64(t.Day()), 10) 423 424 return string(b) 425} 426 427// FmtDateMedium returns the medium date representation of 't' for 'xh' 428func (xh *xh) FmtDateMedium(t time.Time) string { 429 430 b := make([]byte, 0, 32) 431 432 if t.Year() > 0 { 433 b = strconv.AppendInt(b, int64(t.Year()), 10) 434 } else { 435 b = strconv.AppendInt(b, int64(-t.Year()), 10) 436 } 437 438 b = append(b, []byte{0x20}...) 439 b = append(b, xh.monthsAbbreviated[t.Month()]...) 440 b = append(b, []byte{0x20}...) 441 b = strconv.AppendInt(b, int64(t.Day()), 10) 442 443 return string(b) 444} 445 446// FmtDateLong returns the long date representation of 't' for 'xh' 447func (xh *xh) FmtDateLong(t time.Time) string { 448 449 b := make([]byte, 0, 32) 450 451 if t.Year() > 0 { 452 b = strconv.AppendInt(b, int64(t.Year()), 10) 453 } else { 454 b = strconv.AppendInt(b, int64(-t.Year()), 10) 455 } 456 457 b = append(b, []byte{0x20}...) 458 b = append(b, xh.monthsWide[t.Month()]...) 459 b = append(b, []byte{0x20}...) 460 b = strconv.AppendInt(b, int64(t.Day()), 10) 461 462 return string(b) 463} 464 465// FmtDateFull returns the full date representation of 't' for 'xh' 466func (xh *xh) FmtDateFull(t time.Time) string { 467 468 b := make([]byte, 0, 32) 469 470 if t.Year() > 0 { 471 b = strconv.AppendInt(b, int64(t.Year()), 10) 472 } else { 473 b = strconv.AppendInt(b, int64(-t.Year()), 10) 474 } 475 476 b = append(b, []byte{0x20}...) 477 b = append(b, xh.monthsWide[t.Month()]...) 478 b = append(b, []byte{0x20}...) 479 b = strconv.AppendInt(b, int64(t.Day()), 10) 480 b = append(b, []byte{0x2c, 0x20}...) 481 b = append(b, xh.daysWide[t.Weekday()]...) 482 483 return string(b) 484} 485 486// FmtTimeShort returns the short time representation of 't' for 'xh' 487func (xh *xh) FmtTimeShort(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, xh.timeSeparator...) 497 498 if t.Minute() < 10 { 499 b = append(b, '0') 500 } 501 502 b = strconv.AppendInt(b, int64(t.Minute()), 10) 503 504 return string(b) 505} 506 507// FmtTimeMedium returns the medium time representation of 't' for 'xh' 508func (xh *xh) FmtTimeMedium(t time.Time) string { 509 510 b := make([]byte, 0, 32) 511 512 if t.Hour() < 10 { 513 b = append(b, '0') 514 } 515 516 b = strconv.AppendInt(b, int64(t.Hour()), 10) 517 b = append(b, xh.timeSeparator...) 518 519 if t.Minute() < 10 { 520 b = append(b, '0') 521 } 522 523 b = strconv.AppendInt(b, int64(t.Minute()), 10) 524 b = append(b, xh.timeSeparator...) 525 526 if t.Second() < 10 { 527 b = append(b, '0') 528 } 529 530 b = strconv.AppendInt(b, int64(t.Second()), 10) 531 532 return string(b) 533} 534 535// FmtTimeLong returns the long time representation of 't' for 'xh' 536func (xh *xh) FmtTimeLong(t time.Time) string { 537 538 b := make([]byte, 0, 32) 539 540 if t.Hour() < 10 { 541 b = append(b, '0') 542 } 543 544 b = strconv.AppendInt(b, int64(t.Hour()), 10) 545 b = append(b, xh.timeSeparator...) 546 547 if t.Minute() < 10 { 548 b = append(b, '0') 549 } 550 551 b = strconv.AppendInt(b, int64(t.Minute()), 10) 552 b = append(b, xh.timeSeparator...) 553 554 if t.Second() < 10 { 555 b = append(b, '0') 556 } 557 558 b = strconv.AppendInt(b, int64(t.Second()), 10) 559 b = append(b, []byte{0x20}...) 560 561 tz, _ := t.Zone() 562 b = append(b, tz...) 563 564 return string(b) 565} 566 567// FmtTimeFull returns the full time representation of 't' for 'xh' 568func (xh *xh) FmtTimeFull(t time.Time) string { 569 570 b := make([]byte, 0, 32) 571 572 if t.Hour() < 10 { 573 b = append(b, '0') 574 } 575 576 b = strconv.AppendInt(b, int64(t.Hour()), 10) 577 b = append(b, xh.timeSeparator...) 578 579 if t.Minute() < 10 { 580 b = append(b, '0') 581 } 582 583 b = strconv.AppendInt(b, int64(t.Minute()), 10) 584 b = append(b, xh.timeSeparator...) 585 586 if t.Second() < 10 { 587 b = append(b, '0') 588 } 589 590 b = strconv.AppendInt(b, int64(t.Second()), 10) 591 b = append(b, []byte{0x20}...) 592 593 tz, _ := t.Zone() 594 595 if btz, ok := xh.timezones[tz]; ok { 596 b = append(b, btz...) 597 } else { 598 b = append(b, tz...) 599 } 600 601 return string(b) 602} 603