294 lines
		
	
	
		
			8.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			294 lines
		
	
	
		
			8.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package locales
 | |
| 
 | |
| import (
 | |
| 	"strconv"
 | |
| 	"time"
 | |
| 
 | |
| 	"github.com/go-playground/locales/currency"
 | |
| )
 | |
| 
 | |
| // // ErrBadNumberValue is returned when the number passed for
 | |
| // // plural rule determination cannot be parsed
 | |
| // type ErrBadNumberValue struct {
 | |
| // 	NumberValue string
 | |
| // 	InnerError  error
 | |
| // }
 | |
| 
 | |
| // // Error returns ErrBadNumberValue error string
 | |
| // func (e *ErrBadNumberValue) Error() string {
 | |
| // 	return fmt.Sprintf("Invalid Number Value '%s' %s", e.NumberValue, e.InnerError)
 | |
| // }
 | |
| 
 | |
| // var _ error = new(ErrBadNumberValue)
 | |
| 
 | |
| // PluralRule denotes the type of plural rules
 | |
| type PluralRule int
 | |
| 
 | |
| // PluralRule's
 | |
| const (
 | |
| 	PluralRuleUnknown PluralRule = iota
 | |
| 	PluralRuleZero               // zero
 | |
| 	PluralRuleOne                // one - singular
 | |
| 	PluralRuleTwo                // two - dual
 | |
| 	PluralRuleFew                // few - paucal
 | |
| 	PluralRuleMany               // many - also used for fractions if they have a separate class
 | |
| 	PluralRuleOther              // other - required—general plural form—also used if the language only has a single form
 | |
| )
 | |
| 
 | |
| const (
 | |
| 	pluralsString = "UnknownZeroOneTwoFewManyOther"
 | |
| )
 | |
| 
 | |
| // Translator encapsulates an instance of a locale
 | |
| // NOTE: some values are returned as a []byte just in case the caller
 | |
| // wishes to add more and can help avoid allocations; otherwise just cast as string
 | |
| type Translator interface {
 | |
| 
 | |
| 	// The following Functions are for overriding, debugging or developing
 | |
| 	// with a Translator Locale
 | |
| 
 | |
| 	// Locale returns the string value of the translator
 | |
| 	Locale() string
 | |
| 
 | |
| 	// returns an array of cardinal plural rules associated
 | |
| 	// with this translator
 | |
| 	PluralsCardinal() []PluralRule
 | |
| 
 | |
| 	// returns an array of ordinal plural rules associated
 | |
| 	// with this translator
 | |
| 	PluralsOrdinal() []PluralRule
 | |
| 
 | |
| 	// returns an array of range plural rules associated
 | |
| 	// with this translator
 | |
| 	PluralsRange() []PluralRule
 | |
| 
 | |
| 	// returns the cardinal PluralRule given 'num' and digits/precision of 'v' for locale
 | |
| 	CardinalPluralRule(num float64, v uint64) PluralRule
 | |
| 
 | |
| 	// returns the ordinal PluralRule given 'num' and digits/precision of 'v' for locale
 | |
| 	OrdinalPluralRule(num float64, v uint64) PluralRule
 | |
| 
 | |
| 	// returns the ordinal PluralRule given 'num1', 'num2' and digits/precision of 'v1' and 'v2' for locale
 | |
| 	RangePluralRule(num1 float64, v1 uint64, num2 float64, v2 uint64) PluralRule
 | |
| 
 | |
| 	// returns the locales abbreviated month given the 'month' provided
 | |
| 	MonthAbbreviated(month time.Month) string
 | |
| 
 | |
| 	// returns the locales abbreviated months
 | |
| 	MonthsAbbreviated() []string
 | |
| 
 | |
| 	// returns the locales narrow month given the 'month' provided
 | |
| 	MonthNarrow(month time.Month) string
 | |
| 
 | |
| 	// returns the locales narrow months
 | |
| 	MonthsNarrow() []string
 | |
| 
 | |
| 	// returns the locales wide month given the 'month' provided
 | |
| 	MonthWide(month time.Month) string
 | |
| 
 | |
| 	// returns the locales wide months
 | |
| 	MonthsWide() []string
 | |
| 
 | |
| 	// returns the locales abbreviated weekday given the 'weekday' provided
 | |
| 	WeekdayAbbreviated(weekday time.Weekday) string
 | |
| 
 | |
| 	// returns the locales abbreviated weekdays
 | |
| 	WeekdaysAbbreviated() []string
 | |
| 
 | |
| 	// returns the locales narrow weekday given the 'weekday' provided
 | |
| 	WeekdayNarrow(weekday time.Weekday) string
 | |
| 
 | |
| 	// WeekdaysNarrowreturns the locales narrow weekdays
 | |
| 	WeekdaysNarrow() []string
 | |
| 
 | |
| 	// returns the locales short weekday given the 'weekday' provided
 | |
| 	WeekdayShort(weekday time.Weekday) string
 | |
| 
 | |
| 	// returns the locales short weekdays
 | |
| 	WeekdaysShort() []string
 | |
| 
 | |
| 	// returns the locales wide weekday given the 'weekday' provided
 | |
| 	WeekdayWide(weekday time.Weekday) string
 | |
| 
 | |
| 	// returns the locales wide weekdays
 | |
| 	WeekdaysWide() []string
 | |
| 
 | |
| 	// The following Functions are common Formatting functionsfor the Translator's Locale
 | |
| 
 | |
| 	// returns 'num' with digits/precision of 'v' for locale and handles both Whole and Real numbers based on 'v'
 | |
| 	FmtNumber(num float64, v uint64) string
 | |
| 
 | |
| 	// returns 'num' with digits/precision of 'v' for locale and handles both Whole and Real numbers based on 'v'
 | |
| 	// NOTE: 'num' passed into FmtPercent is assumed to be in percent already
 | |
| 	FmtPercent(num float64, v uint64) string
 | |
| 
 | |
| 	// returns the currency representation of 'num' with digits/precision of 'v' for locale
 | |
| 	FmtCurrency(num float64, v uint64, currency currency.Type) string
 | |
| 
 | |
| 	// returns the currency representation of 'num' with digits/precision of 'v' for locale
 | |
| 	// in accounting notation.
 | |
| 	FmtAccounting(num float64, v uint64, currency currency.Type) string
 | |
| 
 | |
| 	// returns the short date representation of 't' for locale
 | |
| 	FmtDateShort(t time.Time) string
 | |
| 
 | |
| 	// returns the medium date representation of 't' for locale
 | |
| 	FmtDateMedium(t time.Time) string
 | |
| 
 | |
| 	//  returns the long date representation of 't' for locale
 | |
| 	FmtDateLong(t time.Time) string
 | |
| 
 | |
| 	// returns the full date representation of 't' for locale
 | |
| 	FmtDateFull(t time.Time) string
 | |
| 
 | |
| 	// returns the short time representation of 't' for locale
 | |
| 	FmtTimeShort(t time.Time) string
 | |
| 
 | |
| 	// returns the medium time representation of 't' for locale
 | |
| 	FmtTimeMedium(t time.Time) string
 | |
| 
 | |
| 	// returns the long time representation of 't' for locale
 | |
| 	FmtTimeLong(t time.Time) string
 | |
| 
 | |
| 	// returns the full time representation of 't' for locale
 | |
| 	FmtTimeFull(t time.Time) string
 | |
| }
 | |
| 
 | |
| // String returns the string value  of PluralRule
 | |
| func (p PluralRule) String() string {
 | |
| 
 | |
| 	switch p {
 | |
| 	case PluralRuleZero:
 | |
| 		return pluralsString[7:11]
 | |
| 	case PluralRuleOne:
 | |
| 		return pluralsString[11:14]
 | |
| 	case PluralRuleTwo:
 | |
| 		return pluralsString[14:17]
 | |
| 	case PluralRuleFew:
 | |
| 		return pluralsString[17:20]
 | |
| 	case PluralRuleMany:
 | |
| 		return pluralsString[20:24]
 | |
| 	case PluralRuleOther:
 | |
| 		return pluralsString[24:]
 | |
| 	default:
 | |
| 		return pluralsString[:7]
 | |
| 	}
 | |
| }
 | |
| 
 | |
| //
 | |
| // Precision Notes:
 | |
| //
 | |
| // must specify a precision >= 0, and here is why https://play.golang.org/p/LyL90U0Vyh
 | |
| //
 | |
| // 	v := float64(3.141)
 | |
| // 	i := float64(int64(v))
 | |
| //
 | |
| // 	fmt.Println(v - i)
 | |
| //
 | |
| // 	or
 | |
| //
 | |
| // 	s := strconv.FormatFloat(v-i, 'f', -1, 64)
 | |
| // 	fmt.Println(s)
 | |
| //
 | |
| // these will not print what you'd expect: 0.14100000000000001
 | |
| // and so this library requires a precision to be specified, or
 | |
| // inaccurate plural rules could be applied.
 | |
| //
 | |
| //
 | |
| //
 | |
| // n - absolute value of the source number (integer and decimals).
 | |
| // i - integer digits of n.
 | |
| // v - number of visible fraction digits in n, with trailing zeros.
 | |
| // w - number of visible fraction digits in n, without trailing zeros.
 | |
| // f - visible fractional digits in n, with trailing zeros.
 | |
| // t - visible fractional digits in n, without trailing zeros.
 | |
| //
 | |
| //
 | |
| // 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.
 | |
| //
 | |
| // n := math.Abs(num)
 | |
| // i := int64(n)
 | |
| // v := v
 | |
| //
 | |
| //
 | |
| // w := strconv.FormatFloat(num-float64(i), 'f', int(v), 64)  // then parse backwards on string until no more zero's....
 | |
| // f := strconv.FormatFloat(n, 'f', int(v), 64) 			  // then turn everything after decimal into an int64
 | |
| // t := strconv.FormatFloat(n, 'f', int(v), 64) 			  // then parse backwards on string until no more zero's....
 | |
| //
 | |
| //
 | |
| //
 | |
| // General Inclusion Rules
 | |
| // - v will always be available inherently
 | |
| // - all require n
 | |
| // - w requires i
 | |
| //
 | |
| 
 | |
| // W returns the number of visible fraction digits in N, without trailing zeros.
 | |
| func W(n float64, v uint64) (w int64) {
 | |
| 
 | |
| 	s := strconv.FormatFloat(n-float64(int64(n)), 'f', int(v), 64)
 | |
| 
 | |
| 	// with either be '0' or '0.xxxx', so if 1 then w will be zero
 | |
| 	// otherwise need to parse
 | |
| 	if len(s) != 1 {
 | |
| 
 | |
| 		s = s[2:]
 | |
| 		end := len(s) + 1
 | |
| 
 | |
| 		for i := end; i >= 0; i-- {
 | |
| 			if s[i] != '0' {
 | |
| 				end = i + 1
 | |
| 				break
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		w = int64(len(s[:end]))
 | |
| 	}
 | |
| 
 | |
| 	return
 | |
| }
 | |
| 
 | |
| // F returns the visible fractional digits in N, with trailing zeros.
 | |
| func F(n float64, v uint64) (f int64) {
 | |
| 
 | |
| 	s := strconv.FormatFloat(n-float64(int64(n)), 'f', int(v), 64)
 | |
| 
 | |
| 	// with either be '0' or '0.xxxx', so if 1 then f will be zero
 | |
| 	// otherwise need to parse
 | |
| 	if len(s) != 1 {
 | |
| 
 | |
| 		// ignoring error, because it can't fail as we generated
 | |
| 		// the string internally from a real number
 | |
| 		f, _ = strconv.ParseInt(s[2:], 10, 64)
 | |
| 	}
 | |
| 
 | |
| 	return
 | |
| }
 | |
| 
 | |
| // T returns the visible fractional digits in N, without trailing zeros.
 | |
| func T(n float64, v uint64) (t int64) {
 | |
| 
 | |
| 	s := strconv.FormatFloat(n-float64(int64(n)), 'f', int(v), 64)
 | |
| 
 | |
| 	// with either be '0' or '0.xxxx', so if 1 then t will be zero
 | |
| 	// otherwise need to parse
 | |
| 	if len(s) != 1 {
 | |
| 
 | |
| 		s = s[2:]
 | |
| 		end := len(s) + 1
 | |
| 
 | |
| 		for i := end; i >= 0; i-- {
 | |
| 			if s[i] != '0' {
 | |
| 				end = i + 1
 | |
| 				break
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		// ignoring error, because it can't fail as we generated
 | |
| 		// the string internally from a real number
 | |
| 		t, _ = strconv.ParseInt(s[:end], 10, 64)
 | |
| 	}
 | |
| 
 | |
| 	return
 | |
| }
 |