rules.go raw

   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  }
 294