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