123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152 |
- // Copyright 2016 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
- // Package number contains tools and data for formatting numbers.
- package number
- import (
- "unicode/utf8"
- "golang.org/x/text/internal/language/compact"
- "golang.org/x/text/language"
- )
- // Info holds number formatting configuration data.
- type Info struct {
- system systemData // numbering system information
- symIndex symOffset // index to symbols
- }
- // InfoFromLangID returns a Info for the given compact language identifier and
- // numbering system identifier. If system is the empty string, the default
- // numbering system will be taken for that language.
- func InfoFromLangID(compactIndex compact.ID, numberSystem string) Info {
- p := langToDefaults[compactIndex]
- // Lookup the entry for the language.
- pSymIndex := symOffset(0) // Default: Latin, default symbols
- system, ok := systemMap[numberSystem]
- if !ok {
- // Take the value for the default numbering system. This is by far the
- // most common case as an alternative numbering system is hardly used.
- if p&hasNonLatnMask == 0 { // Latn digits.
- pSymIndex = p
- } else { // Non-Latn or multiple numbering systems.
- // Take the first entry from the alternatives list.
- data := langToAlt[p&^hasNonLatnMask]
- pSymIndex = data.symIndex
- system = data.system
- }
- } else {
- langIndex := compactIndex
- ns := system
- outerLoop:
- for ; ; p = langToDefaults[langIndex] {
- if p&hasNonLatnMask == 0 {
- if ns == 0 {
- // The index directly points to the symbol data.
- pSymIndex = p
- break
- }
- // Move to the parent and retry.
- langIndex = langIndex.Parent()
- } else {
- // The index points to a list of symbol data indexes.
- for _, e := range langToAlt[p&^hasNonLatnMask:] {
- if e.compactTag != langIndex {
- if langIndex == 0 {
- // The CLDR root defines full symbol information for
- // all numbering systems (even though mostly by
- // means of aliases). Fall back to the default entry
- // for Latn if there is no data for the numbering
- // system of this language.
- if ns == 0 {
- break
- }
- // Fall back to Latin and start from the original
- // language. See
- // https://unicode.org/reports/tr35/#Locale_Inheritance.
- ns = numLatn
- langIndex = compactIndex
- continue outerLoop
- }
- // Fall back to parent.
- langIndex = langIndex.Parent()
- } else if e.system == ns {
- pSymIndex = e.symIndex
- break outerLoop
- }
- }
- }
- }
- }
- if int(system) >= len(numSysData) { // algorithmic
- // Will generate ASCII digits in case the user inadvertently calls
- // WriteDigit or Digit on it.
- d := numSysData[0]
- d.id = system
- return Info{
- system: d,
- symIndex: pSymIndex,
- }
- }
- return Info{
- system: numSysData[system],
- symIndex: pSymIndex,
- }
- }
- // InfoFromTag returns a Info for the given language tag.
- func InfoFromTag(t language.Tag) Info {
- return InfoFromLangID(tagToID(t), t.TypeForKey("nu"))
- }
- // IsDecimal reports if the numbering system can convert decimal to native
- // symbols one-to-one.
- func (n Info) IsDecimal() bool {
- return int(n.system.id) < len(numSysData)
- }
- // WriteDigit writes the UTF-8 sequence for n corresponding to the given ASCII
- // digit to dst and reports the number of bytes written. dst must be large
- // enough to hold the rune (can be up to utf8.UTFMax bytes).
- func (n Info) WriteDigit(dst []byte, asciiDigit rune) int {
- copy(dst, n.system.zero[:n.system.digitSize])
- dst[n.system.digitSize-1] += byte(asciiDigit - '0')
- return int(n.system.digitSize)
- }
- // AppendDigit appends the UTF-8 sequence for n corresponding to the given digit
- // to dst and reports the number of bytes written. dst must be large enough to
- // hold the rune (can be up to utf8.UTFMax bytes).
- func (n Info) AppendDigit(dst []byte, digit byte) []byte {
- dst = append(dst, n.system.zero[:n.system.digitSize]...)
- dst[len(dst)-1] += digit
- return dst
- }
- // Digit returns the digit for the numbering system for the corresponding ASCII
- // value. For example, ni.Digit('3') could return '三'. Note that the argument
- // is the rune constant '3', which equals 51, not the integer constant 3.
- func (n Info) Digit(asciiDigit rune) rune {
- var x [utf8.UTFMax]byte
- n.WriteDigit(x[:], asciiDigit)
- r, _ := utf8.DecodeRune(x[:])
- return r
- }
- // Symbol returns the string for the given symbol type.
- func (n Info) Symbol(t SymbolType) string {
- return symData.Elem(int(symIndex[n.symIndex][t]))
- }
- func formatForLang(t language.Tag, index []byte) *Pattern {
- return &formats[index[tagToID(t)]]
- }
- func tagToID(t language.Tag) compact.ID {
- id, _ := compact.RegionalID(compact.Tag(t))
- return id
- }
|