forked from bojanz/currency
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathcurrency.go
124 lines (110 loc) · 2.93 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
// 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
// GetCurrencyCodes returns all known currency codes.
func GetCurrencyCodes() []string {
return currencyCodes
}
// IsValid checks whether a currencyCode is valid.
//
// An empty currencyCode is considered valid.
func IsValid(currencyCode string) bool {
if currencyCode == "" {
return true
}
_, ok := currencies[currencyCode]
return ok
}
// GetNumericCode returns the numeric code for a currencyCode.
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 currencyCode.
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 currencyCode.
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 {
// 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 {
var format 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 = Locale{Language: "en"}
}
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
}