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