// 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 }