1package locales 2 3import ( 4 "strconv" 5 "time" 6 7 "github.com/go-playground/locales/currency" 8) 9 10// // ErrBadNumberValue is returned when the number passed for 11// // plural rule determination cannot be parsed 12// type ErrBadNumberValue struct { 13// NumberValue string 14// InnerError error 15// } 16 17// // Error returns ErrBadNumberValue error string 18// func (e *ErrBadNumberValue) Error() string { 19// return fmt.Sprintf("Invalid Number Value '%s' %s", e.NumberValue, e.InnerError) 20// } 21 22// var _ error = new(ErrBadNumberValue) 23 24// PluralRule denotes the type of plural rules 25type PluralRule int 26 27// PluralRule's 28const ( 29 PluralRuleUnknown PluralRule = iota 30 PluralRuleZero // zero 31 PluralRuleOne // one - singular 32 PluralRuleTwo // two - dual 33 PluralRuleFew // few - paucal 34 PluralRuleMany // many - also used for fractions if they have a separate class 35 PluralRuleOther // other - required—general plural form—also used if the language only has a single form 36) 37 38const ( 39 pluralsString = "UnknownZeroOneTwoFewManyOther" 40) 41 42// Translator encapsulates an instance of a locale 43// NOTE: some values are returned as a []byte just in case the caller 44// wishes to add more and can help avoid allocations; otherwise just cast as string 45type Translator interface { 46 47 // The following Functions are for overriding, debugging or developing 48 // with a Translator Locale 49 50 // Locale returns the string value of the translator 51 Locale() string 52 53 // returns an array of cardinal plural rules associated 54 // with this translator 55 PluralsCardinal() []PluralRule 56 57 // returns an array of ordinal plural rules associated 58 // with this translator 59 PluralsOrdinal() []PluralRule 60 61 // returns an array of range plural rules associated 62 // with this translator 63 PluralsRange() []PluralRule 64 65 // returns the cardinal PluralRule given 'num' and digits/precision of 'v' for locale 66 CardinalPluralRule(num float64, v uint64) PluralRule 67 68 // returns the ordinal PluralRule given 'num' and digits/precision of 'v' for locale 69 OrdinalPluralRule(num float64, v uint64) PluralRule 70 71 // returns the ordinal PluralRule given 'num1', 'num2' and digits/precision of 'v1' and 'v2' for locale 72 RangePluralRule(num1 float64, v1 uint64, num2 float64, v2 uint64) PluralRule 73 74 // returns the locales abbreviated month given the 'month' provided 75 MonthAbbreviated(month time.Month) string 76 77 // returns the locales abbreviated months 78 MonthsAbbreviated() []string 79 80 // returns the locales narrow month given the 'month' provided 81 MonthNarrow(month time.Month) string 82 83 // returns the locales narrow months 84 MonthsNarrow() []string 85 86 // returns the locales wide month given the 'month' provided 87 MonthWide(month time.Month) string 88 89 // returns the locales wide months 90 MonthsWide() []string 91 92 // returns the locales abbreviated weekday given the 'weekday' provided 93 WeekdayAbbreviated(weekday time.Weekday) string 94 95 // returns the locales abbreviated weekdays 96 WeekdaysAbbreviated() []string 97 98 // returns the locales narrow weekday given the 'weekday' provided 99 WeekdayNarrow(weekday time.Weekday) string 100 101 // WeekdaysNarrowreturns the locales narrow weekdays 102 WeekdaysNarrow() []string 103 104 // returns the locales short weekday given the 'weekday' provided 105 WeekdayShort(weekday time.Weekday) string 106 107 // returns the locales short weekdays 108 WeekdaysShort() []string 109 110 // returns the locales wide weekday given the 'weekday' provided 111 WeekdayWide(weekday time.Weekday) string 112 113 // returns the locales wide weekdays 114 WeekdaysWide() []string 115 116 // The following Functions are common Formatting functionsfor the Translator's Locale 117 118 // returns 'num' with digits/precision of 'v' for locale and handles both Whole and Real numbers based on 'v' 119 FmtNumber(num float64, v uint64) string 120 121 // returns 'num' with digits/precision of 'v' for locale and handles both Whole and Real numbers based on 'v' 122 // NOTE: 'num' passed into FmtPercent is assumed to be in percent already 123 FmtPercent(num float64, v uint64) string 124 125 // returns the currency representation of 'num' with digits/precision of 'v' for locale 126 FmtCurrency(num float64, v uint64, currency currency.Type) string 127 128 // returns the currency representation of 'num' with digits/precision of 'v' for locale 129 // in accounting notation. 130 FmtAccounting(num float64, v uint64, currency currency.Type) string 131 132 // returns the short date representation of 't' for locale 133 FmtDateShort(t time.Time) string 134 135 // returns the medium date representation of 't' for locale 136 FmtDateMedium(t time.Time) string 137 138 // returns the long date representation of 't' for locale 139 FmtDateLong(t time.Time) string 140 141 // returns the full date representation of 't' for locale 142 FmtDateFull(t time.Time) string 143 144 // returns the short time representation of 't' for locale 145 FmtTimeShort(t time.Time) string 146 147 // returns the medium time representation of 't' for locale 148 FmtTimeMedium(t time.Time) string 149 150 // returns the long time representation of 't' for locale 151 FmtTimeLong(t time.Time) string 152 153 // returns the full time representation of 't' for locale 154 FmtTimeFull(t time.Time) string 155} 156 157// String returns the string value of PluralRule 158func (p PluralRule) String() string { 159 160 switch p { 161 case PluralRuleZero: 162 return pluralsString[7:11] 163 case PluralRuleOne: 164 return pluralsString[11:14] 165 case PluralRuleTwo: 166 return pluralsString[14:17] 167 case PluralRuleFew: 168 return pluralsString[17:20] 169 case PluralRuleMany: 170 return pluralsString[20:24] 171 case PluralRuleOther: 172 return pluralsString[24:] 173 default: 174 return pluralsString[:7] 175 } 176} 177 178// 179// Precision Notes: 180// 181// must specify a precision >= 0, and here is why https://play.golang.org/p/LyL90U0Vyh 182// 183// v := float64(3.141) 184// i := float64(int64(v)) 185// 186// fmt.Println(v - i) 187// 188// or 189// 190// s := strconv.FormatFloat(v-i, 'f', -1, 64) 191// fmt.Println(s) 192// 193// these will not print what you'd expect: 0.14100000000000001 194// and so this library requires a precision to be specified, or 195// inaccurate plural rules could be applied. 196// 197// 198// 199// n - absolute value of the source number (integer and decimals). 200// i - integer digits of n. 201// v - number of visible fraction digits in n, with trailing zeros. 202// w - number of visible fraction digits in n, without trailing zeros. 203// f - visible fractional digits in n, with trailing zeros. 204// t - visible fractional digits in n, without trailing zeros. 205// 206// 207// Func(num float64, v uint64) // v = digits/precision and prevents -1 as a special case as this can lead to very unexpected behaviour, see precision note's above. 208// 209// n := math.Abs(num) 210// i := int64(n) 211// v := v 212// 213// 214// w := strconv.FormatFloat(num-float64(i), 'f', int(v), 64) // then parse backwards on string until no more zero's.... 215// f := strconv.FormatFloat(n, 'f', int(v), 64) // then turn everything after decimal into an int64 216// t := strconv.FormatFloat(n, 'f', int(v), 64) // then parse backwards on string until no more zero's.... 217// 218// 219// 220// General Inclusion Rules 221// - v will always be available inherently 222// - all require n 223// - w requires i 224// 225 226// W returns the number of visible fraction digits in N, without trailing zeros. 227func W(n float64, v uint64) (w int64) { 228 229 s := strconv.FormatFloat(n-float64(int64(n)), 'f', int(v), 64) 230 231 // with either be '0' or '0.xxxx', so if 1 then w will be zero 232 // otherwise need to parse 233 if len(s) != 1 { 234 235 s = s[2:] 236 end := len(s) + 1 237 238 for i := end; i >= 0; i-- { 239 if s[i] != '0' { 240 end = i + 1 241 break 242 } 243 } 244 245 w = int64(len(s[:end])) 246 } 247 248 return 249} 250 251// F returns the visible fractional digits in N, with trailing zeros. 252func F(n float64, v uint64) (f int64) { 253 254 s := strconv.FormatFloat(n-float64(int64(n)), 'f', int(v), 64) 255 256 // with either be '0' or '0.xxxx', so if 1 then f will be zero 257 // otherwise need to parse 258 if len(s) != 1 { 259 260 // ignoring error, because it can't fail as we generated 261 // the string internally from a real number 262 f, _ = strconv.ParseInt(s[2:], 10, 64) 263 } 264 265 return 266} 267 268// T returns the visible fractional digits in N, without trailing zeros. 269func T(n float64, v uint64) (t int64) { 270 271 s := strconv.FormatFloat(n-float64(int64(n)), 'f', int(v), 64) 272 273 // with either be '0' or '0.xxxx', so if 1 then t will be zero 274 // otherwise need to parse 275 if len(s) != 1 { 276 277 s = s[2:] 278 end := len(s) + 1 279 280 for i := end; i >= 0; i-- { 281 if s[i] != '0' { 282 end = i + 1 283 break 284 } 285 } 286 287 // ignoring error, because it can't fail as we generated 288 // the string internally from a real number 289 t, _ = strconv.ParseInt(s[:end], 10, 64) 290 } 291 292 return 293} 294