Permalink
Cannot retrieve contributors at this time
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
185 lines (160 sloc)
4.82 KB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Copyright 2015 The Go Authors. All rights reserved. | |
// Use of this source code is governed by a BSD-style | |
// license that can be found in the LICENSE file. | |
//go:generate go run gen.go gen_common.go -output tables.go | |
// Package currency contains currency-related functionality. | |
// | |
// NOTE: the formatting functionality is currently under development and may | |
// change without notice. | |
package currency // import "golang.org/x/text/currency" | |
import ( | |
"errors" | |
"sort" | |
"golang.org/x/text/internal/tag" | |
"golang.org/x/text/language" | |
) | |
// TODO: | |
// - language-specific currency names. | |
// - currency formatting. | |
// - currency information per region | |
// - register currency code (there are no private use area) | |
// TODO: remove Currency type from package language. | |
// Kind determines the rounding and rendering properties of a currency value. | |
type Kind struct { | |
rounding rounding | |
// TODO: formatting type: standard, accounting. See CLDR. | |
} | |
type rounding byte | |
const ( | |
standard rounding = iota | |
cash | |
) | |
var ( | |
// Standard defines standard rounding and formatting for currencies. | |
Standard Kind = Kind{rounding: standard} | |
// Cash defines rounding and formatting standards for cash transactions. | |
Cash Kind = Kind{rounding: cash} | |
// Accounting defines rounding and formatting standards for accounting. | |
Accounting Kind = Kind{rounding: standard} | |
) | |
// Rounding reports the rounding characteristics for the given currency, where | |
// scale is the number of fractional decimals and increment is the number of | |
// units in terms of 10^(-scale) to which to round to. | |
func (k Kind) Rounding(cur Unit) (scale, increment int) { | |
info := currency.Elem(int(cur.index))[3] | |
switch k.rounding { | |
case standard: | |
info &= roundMask | |
case cash: | |
info >>= cashShift | |
} | |
return int(roundings[info].scale), int(roundings[info].increment) | |
} | |
// Unit is an ISO 4217 currency designator. | |
type Unit struct { | |
index uint16 | |
} | |
// String returns the ISO code of u. | |
func (u Unit) String() string { | |
if u.index == 0 { | |
return "XXX" | |
} | |
return currency.Elem(int(u.index))[:3] | |
} | |
// Amount creates an Amount for the given currency unit and amount. | |
func (u Unit) Amount(amount interface{}) Amount { | |
// TODO: verify amount is a supported number type | |
return Amount{amount: amount, currency: u} | |
} | |
var ( | |
errSyntax = errors.New("currency: tag is not well-formed") | |
errValue = errors.New("currency: tag is not a recognized currency") | |
) | |
// ParseISO parses a 3-letter ISO 4217 currency code. It returns an error if s | |
// is not well-formed or not a recognized currency code. | |
func ParseISO(s string) (Unit, error) { | |
var buf [4]byte // Take one byte more to detect oversize keys. | |
key := buf[:copy(buf[:], s)] | |
if !tag.FixCase("XXX", key) { | |
return Unit{}, errSyntax | |
} | |
if i := currency.Index(key); i >= 0 { | |
if i == xxx { | |
return Unit{}, nil | |
} | |
return Unit{uint16(i)}, nil | |
} | |
return Unit{}, errValue | |
} | |
// MustParseISO is like ParseISO, but panics if the given currency unit | |
// cannot be parsed. It simplifies safe initialization of Unit values. | |
func MustParseISO(s string) Unit { | |
c, err := ParseISO(s) | |
if err != nil { | |
panic(err) | |
} | |
return c | |
} | |
// FromRegion reports the currency unit that is currently legal tender in the | |
// given region according to CLDR. It will return false if region currently does | |
// not have a legal tender. | |
func FromRegion(r language.Region) (currency Unit, ok bool) { | |
x := regionToCode(r) | |
i := sort.Search(len(regionToCurrency), func(i int) bool { | |
return regionToCurrency[i].region >= x | |
}) | |
if i < len(regionToCurrency) && regionToCurrency[i].region == x { | |
return Unit{regionToCurrency[i].code}, true | |
} | |
return Unit{}, false | |
} | |
// FromTag reports the most likely currency for the given tag. It considers the | |
// currency defined in the -u extension and infers the region if necessary. | |
func FromTag(t language.Tag) (Unit, language.Confidence) { | |
if cur := t.TypeForKey("cu"); len(cur) == 3 { | |
c, _ := ParseISO(cur) | |
return c, language.Exact | |
} | |
r, conf := t.Region() | |
if cur, ok := FromRegion(r); ok { | |
return cur, conf | |
} | |
return Unit{}, language.No | |
} | |
var ( | |
// Undefined and testing. | |
XXX Unit = Unit{} | |
XTS Unit = Unit{xts} | |
// G10 currencies https://en.wikipedia.org/wiki/G10_currencies. | |
USD Unit = Unit{usd} | |
EUR Unit = Unit{eur} | |
JPY Unit = Unit{jpy} | |
GBP Unit = Unit{gbp} | |
CHF Unit = Unit{chf} | |
AUD Unit = Unit{aud} | |
NZD Unit = Unit{nzd} | |
CAD Unit = Unit{cad} | |
SEK Unit = Unit{sek} | |
NOK Unit = Unit{nok} | |
// Additional common currencies as defined by CLDR. | |
BRL Unit = Unit{brl} | |
CNY Unit = Unit{cny} | |
DKK Unit = Unit{dkk} | |
INR Unit = Unit{inr} | |
RUB Unit = Unit{rub} | |
HKD Unit = Unit{hkd} | |
IDR Unit = Unit{idr} | |
KRW Unit = Unit{krw} | |
MXN Unit = Unit{mxn} | |
PLN Unit = Unit{pln} | |
SAR Unit = Unit{sar} | |
THB Unit = Unit{thb} | |
TRY Unit = Unit{try} | |
TWD Unit = Unit{twd} | |
ZAR Unit = Unit{zar} | |
// Precious metals. | |
XAG Unit = Unit{xag} | |
XAU Unit = Unit{xau} | |
XPT Unit = Unit{xpt} | |
XPD Unit = Unit{xpd} | |
) |