1// Copyright 2015 The Go Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5//go:generate go run gen.go gen_common.go -output tables.go 6 7// Package currency contains currency-related functionality. 8// 9// NOTE: the formatting functionality is currently under development and may 10// change without notice. 11package currency // import "golang.org/x/text/currency" 12 13import ( 14 "errors" 15 "sort" 16 17 "golang.org/x/text/internal/tag" 18 "golang.org/x/text/language" 19) 20 21// TODO: 22// - language-specific currency names. 23// - currency formatting. 24// - currency information per region 25// - register currency code (there are no private use area) 26 27// TODO: remove Currency type from package language. 28 29// Kind determines the rounding and rendering properties of a currency value. 30type Kind struct { 31 rounding rounding 32 // TODO: formatting type: standard, accounting. See CLDR. 33} 34 35type rounding byte 36 37const ( 38 standard rounding = iota 39 cash 40) 41 42var ( 43 // Standard defines standard rounding and formatting for currencies. 44 Standard Kind = Kind{rounding: standard} 45 46 // Cash defines rounding and formatting standards for cash transactions. 47 Cash Kind = Kind{rounding: cash} 48 49 // Accounting defines rounding and formatting standards for accounting. 50 Accounting Kind = Kind{rounding: standard} 51) 52 53// Rounding reports the rounding characteristics for the given currency, where 54// scale is the number of fractional decimals and increment is the number of 55// units in terms of 10^(-scale) to which to round to. 56func (k Kind) Rounding(cur Unit) (scale, increment int) { 57 info := currency.Elem(int(cur.index))[3] 58 switch k.rounding { 59 case standard: 60 info &= roundMask 61 case cash: 62 info >>= cashShift 63 } 64 return int(roundings[info].scale), int(roundings[info].increment) 65} 66 67// Unit is an ISO 4217 currency designator. 68type Unit struct { 69 index uint16 70} 71 72// String returns the ISO code of u. 73func (u Unit) String() string { 74 if u.index == 0 { 75 return "XXX" 76 } 77 return currency.Elem(int(u.index))[:3] 78} 79 80// Amount creates an Amount for the given currency unit and amount. 81func (u Unit) Amount(amount interface{}) Amount { 82 // TODO: verify amount is a supported number type 83 return Amount{amount: amount, currency: u} 84} 85 86var ( 87 errSyntax = errors.New("currency: tag is not well-formed") 88 errValue = errors.New("currency: tag is not a recognized currency") 89) 90 91// ParseISO parses a 3-letter ISO 4217 currency code. It returns an error if s 92// is not well-formed or not a recognized currency code. 93func ParseISO(s string) (Unit, error) { 94 var buf [4]byte // Take one byte more to detect oversize keys. 95 key := buf[:copy(buf[:], s)] 96 if !tag.FixCase("XXX", key) { 97 return Unit{}, errSyntax 98 } 99 if i := currency.Index(key); i >= 0 { 100 if i == xxx { 101 return Unit{}, nil 102 } 103 return Unit{uint16(i)}, nil 104 } 105 return Unit{}, errValue 106} 107 108// MustParseISO is like ParseISO, but panics if the given currency unit 109// cannot be parsed. It simplifies safe initialization of Unit values. 110func MustParseISO(s string) Unit { 111 c, err := ParseISO(s) 112 if err != nil { 113 panic(err) 114 } 115 return c 116} 117 118// FromRegion reports the currency unit that is currently legal tender in the 119// given region according to CLDR. It will return false if region currently does 120// not have a legal tender. 121func FromRegion(r language.Region) (currency Unit, ok bool) { 122 x := regionToCode(r) 123 i := sort.Search(len(regionToCurrency), func(i int) bool { 124 return regionToCurrency[i].region >= x 125 }) 126 if i < len(regionToCurrency) && regionToCurrency[i].region == x { 127 return Unit{regionToCurrency[i].code}, true 128 } 129 return Unit{}, false 130} 131 132// FromTag reports the most likely currency for the given tag. It considers the 133// currency defined in the -u extension and infers the region if necessary. 134func FromTag(t language.Tag) (Unit, language.Confidence) { 135 if cur := t.TypeForKey("cu"); len(cur) == 3 { 136 c, _ := ParseISO(cur) 137 return c, language.Exact 138 } 139 r, conf := t.Region() 140 if cur, ok := FromRegion(r); ok { 141 return cur, conf 142 } 143 return Unit{}, language.No 144} 145 146var ( 147 // Undefined and testing. 148 XXX Unit = Unit{} 149 XTS Unit = Unit{xts} 150 151 // G10 currencies https://en.wikipedia.org/wiki/G10_currencies. 152 USD Unit = Unit{usd} 153 EUR Unit = Unit{eur} 154 JPY Unit = Unit{jpy} 155 GBP Unit = Unit{gbp} 156 CHF Unit = Unit{chf} 157 AUD Unit = Unit{aud} 158 NZD Unit = Unit{nzd} 159 CAD Unit = Unit{cad} 160 SEK Unit = Unit{sek} 161 NOK Unit = Unit{nok} 162 163 // Additional common currencies as defined by CLDR. 164 BRL Unit = Unit{brl} 165 CNY Unit = Unit{cny} 166 DKK Unit = Unit{dkk} 167 INR Unit = Unit{inr} 168 RUB Unit = Unit{rub} 169 HKD Unit = Unit{hkd} 170 IDR Unit = Unit{idr} 171 KRW Unit = Unit{krw} 172 MXN Unit = Unit{mxn} 173 PLN Unit = Unit{pln} 174 SAR Unit = Unit{sar} 175 THB Unit = Unit{thb} 176 TRY Unit = Unit{try} 177 TWD Unit = Unit{twd} 178 ZAR Unit = Unit{zar} 179 180 // Precious metals. 181 XAG Unit = Unit{xag} 182 XAU Unit = Unit{xau} 183 XPT Unit = Unit{xpt} 184 XPD Unit = Unit{xpd} 185) 186