You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
293 lines
8.4 KiB
293 lines
8.4 KiB
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 |
|
}
|
|
|