-
Notifications
You must be signed in to change notification settings - Fork 46
/
currency.go
132 lines (115 loc) · 3.19 KB
/
currency.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
// Copyright (c) 2020 Bojan Zivanovic and contributors
// SPDX-License-Identifier: MIT
// Package currency handles currency amounts, provides currency information and formatting.
package currency
import "sort"
// DefaultDigits is a placeholder for each currency's number of fraction digits.
const DefaultDigits uint8 = 255
// ForCountryCode returns the currency code for a country code.
func ForCountryCode(countryCode string) (currencyCode string, ok bool) {
currencyCode, ok = countryCurrencies[countryCode]
return currencyCode, ok
}
// GetCurrencyCodes returns all known currency codes.
func GetCurrencyCodes() []string {
return currencyCodes
}
// IsValid checks whether a currency code is valid.
//
// An empty currency code is considered valid.
func IsValid(currencyCode string) bool {
if currencyCode == "" {
return true
}
_, ok := currencies[currencyCode]
return ok
}
// GetNumericCode returns the numeric code for a currency code.
func GetNumericCode(currencyCode string) (numericCode string, ok bool) {
if currencyCode == "" || !IsValid(currencyCode) {
return "000", false
}
return currencies[currencyCode].numericCode, true
}
// GetDigits returns the number of fraction digits for a currency code.
func GetDigits(currencyCode string) (digits uint8, ok bool) {
if currencyCode == "" || !IsValid(currencyCode) {
return 0, false
}
return currencies[currencyCode].digits, true
}
// GetSymbol returns the symbol for a currency code.
func GetSymbol(currencyCode string, locale Locale) (symbol string, ok bool) {
if currencyCode == "" || !IsValid(currencyCode) {
return currencyCode, false
}
symbols, ok := currencySymbols[currencyCode]
if !ok {
return currencyCode, true
}
enLocale := Locale{Language: "en"}
enUSLocale := Locale{Language: "en", Territory: "US"}
if locale == enLocale || locale == enUSLocale || locale.IsEmpty() {
// The "en"/"en-US" symbol is always first.
return symbols[0].symbol, true
}
for {
localeID := locale.String()
for _, s := range symbols {
if contains(s.locales, localeID) {
symbol = s.symbol
break
}
}
if symbol != "" {
break
}
locale = locale.GetParent()
if locale.IsEmpty() {
break
}
}
return symbol, true
}
// getFormat returns the format for a locale.
func getFormat(locale Locale) currencyFormat {
// CLDR considers "en" and "en-US" to be equivalent.
// Fall back immediately for better performance
enUSLocale := Locale{Language: "en", Territory: "US"}
if locale == enUSLocale || locale.IsEmpty() {
return currencyFormats["en"]
}
var format currencyFormat
for {
localeID := locale.String()
if cf, ok := currencyFormats[localeID]; ok {
format = cf
break
}
locale = locale.GetParent()
if locale.IsEmpty() {
break
}
}
return format
}
// contains returns whether the sorted slice a contains x.
// The slice must be sorted in ascending order.
func contains(a []string, x string) bool {
n := len(a)
if n < 10 {
// Linear search is faster with a small number of elements.
for _, v := range a {
if v == x {
return true
}
}
} else {
// Binary search is faster with a large number of elements.
i := sort.SearchStrings(a, x)
if i < n && a[i] == x {
return true
}
}
return false
}