rules.go (8577B)
1 package locales 2 3 import ( 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 25 type PluralRule int 26 27 // PluralRule's 28 const ( 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 38 const ( 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 45 type 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 158 func (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. 227 func 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. 252 func 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. 269 func 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 }