1// Copyright 2016 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 6 7// Package plural provides utilities for handling linguistic plurals in text. 8// 9// The definitions in this package are based on the plural rule handling defined 10// in CLDR. See 11// http://unicode.org/reports/tr35/tr35-numbers.html#Language_Plural_Rules for 12// details. 13package plural 14 15import ( 16 "golang.org/x/text/internal/number" 17 "golang.org/x/text/language" 18) 19 20// Rules defines the plural rules for all languages for a certain plural type. 21// 22// 23// This package is UNDER CONSTRUCTION and its API may change. 24type Rules struct { 25 rules []pluralCheck 26 index []byte 27 langToIndex []byte 28 inclusionMasks []uint64 29} 30 31var ( 32 // Cardinal defines the plural rules for numbers indicating quantities. 33 Cardinal *Rules = cardinal 34 35 // Ordinal defines the plural rules for numbers indicating position 36 // (first, second, etc.). 37 Ordinal *Rules = ordinal 38 39 ordinal = &Rules{ 40 ordinalRules, 41 ordinalIndex, 42 ordinalLangToIndex, 43 ordinalInclusionMasks[:], 44 } 45 46 cardinal = &Rules{ 47 cardinalRules, 48 cardinalIndex, 49 cardinalLangToIndex, 50 cardinalInclusionMasks[:], 51 } 52) 53 54// getIntApprox converts the digits in slice digits[start:end] to an integer 55// according to the following rules: 56// - Let i be asInt(digits[start:end]), where out-of-range digits are assumed 57// to be zero. 58// - Result n is big if i / 10^nMod > 1. 59// - Otherwise the result is i % 10^nMod. 60// 61// For example, if digits is {1, 2, 3} and start:end is 0:5, then the result 62// for various values of nMod is: 63// - when nMod == 2, n == big 64// - when nMod == 3, n == big 65// - when nMod == 4, n == big 66// - when nMod == 5, n == 12300 67// - when nMod == 6, n == 12300 68// - when nMod == 7, n == 12300 69func getIntApprox(digits []byte, start, end, nMod, big int) (n int) { 70 // Leading 0 digits just result in 0. 71 p := start 72 if p < 0 { 73 p = 0 74 } 75 // Range only over the part for which we have digits. 76 mid := end 77 if mid >= len(digits) { 78 mid = len(digits) 79 } 80 // Check digits more significant that nMod. 81 if q := end - nMod; q > 0 { 82 if q > mid { 83 q = mid 84 } 85 for ; p < q; p++ { 86 if digits[p] != 0 { 87 return big 88 } 89 } 90 } 91 for ; p < mid; p++ { 92 n = 10*n + int(digits[p]) 93 } 94 // Multiply for trailing zeros. 95 for ; p < end; p++ { 96 n *= 10 97 } 98 return n 99} 100 101// MatchDigits computes the plural form for the given language and the given 102// decimal floating point digits. The digits are stored in big-endian order and 103// are of value byte(0) - byte(9). The floating point position is indicated by 104// exp and the number of visible decimals is scale. All leading and trailing 105// zeros may be omitted from digits. 106// 107// The following table contains examples of possible arguments to represent 108// the given numbers. 109// decimal digits exp scale 110// 123 []byte{1, 2, 3} 3 0 111// 123.4 []byte{1, 2, 3, 4} 3 1 112// 123.40 []byte{1, 2, 3, 4} 3 2 113// 100000 []byte{1} 6 0 114// 100000.00 []byte{1} 6 3 115func (p *Rules) MatchDigits(t language.Tag, digits []byte, exp, scale int) Form { 116 index, _ := language.CompactIndex(t) 117 118 // Differentiate up to including mod 1000000 for the integer part. 119 n := getIntApprox(digits, 0, exp, 6, 1000000) 120 121 // Differentiate up to including mod 100 for the fractional part. 122 f := getIntApprox(digits, exp, exp+scale, 2, 100) 123 124 return matchPlural(p, index, n, f, scale) 125} 126 127func (p *Rules) matchDisplayDigits(t language.Tag, d *number.Digits) (Form, int) { 128 n := getIntApprox(d.Digits, 0, int(d.Exp), 6, 1000000) 129 return p.MatchDigits(t, d.Digits, int(d.Exp), d.NumFracDigits()), n 130} 131 132func validForms(p *Rules, t language.Tag) (forms []Form) { 133 index, _ := language.CompactIndex(t) 134 offset := p.langToIndex[index] 135 rules := p.rules[p.index[offset]:p.index[offset+1]] 136 137 forms = append(forms, Other) 138 last := Other 139 for _, r := range rules { 140 if cat := Form(r.cat & formMask); cat != andNext && last != cat { 141 forms = append(forms, cat) 142 last = cat 143 } 144 } 145 return forms 146} 147 148func (p *Rules) matchComponents(t language.Tag, n, f, scale int) Form { 149 index, _ := language.CompactIndex(t) 150 return matchPlural(p, index, n, f, scale) 151} 152 153// MatchPlural returns the plural form for the given language and plural 154// operands (as defined in 155// http://unicode.org/reports/tr35/tr35-numbers.html#Language_Plural_Rules): 156// where 157// n absolute value of the source number (integer and decimals) 158// input 159// i integer digits of n. 160// v number of visible fraction digits in n, with trailing zeros. 161// w number of visible fraction digits in n, without trailing zeros. 162// f visible fractional digits in n, with trailing zeros (f = t * 10^(v-w)) 163// t visible fractional digits in n, without trailing zeros. 164// 165// If any of the operand values is too large to fit in an int, it is okay to 166// pass the value modulo 10,000,000. 167func (p *Rules) MatchPlural(lang language.Tag, i, v, w, f, t int) Form { 168 index, _ := language.CompactIndex(lang) 169 return matchPlural(p, index, i, f, v) 170} 171 172func matchPlural(p *Rules, index int, n, f, v int) Form { 173 nMask := p.inclusionMasks[n%maxMod] 174 // Compute the fMask inline in the rules below, as it is relatively rare. 175 // fMask := p.inclusionMasks[f%maxMod] 176 vMask := p.inclusionMasks[v%maxMod] 177 178 // Do the matching 179 offset := p.langToIndex[index] 180 rules := p.rules[p.index[offset]:p.index[offset+1]] 181 for i := 0; i < len(rules); i++ { 182 rule := rules[i] 183 setBit := uint64(1 << rule.setID) 184 var skip bool 185 switch op := opID(rule.cat >> opShift); op { 186 case opI: // i = x 187 skip = n >= numN || nMask&setBit == 0 188 189 case opI | opNotEqual: // i != x 190 skip = n < numN && nMask&setBit != 0 191 192 case opI | opMod: // i % m = x 193 skip = nMask&setBit == 0 194 195 case opI | opMod | opNotEqual: // i % m != x 196 skip = nMask&setBit != 0 197 198 case opN: // n = x 199 skip = f != 0 || n >= numN || nMask&setBit == 0 200 201 case opN | opNotEqual: // n != x 202 skip = f == 0 && n < numN && nMask&setBit != 0 203 204 case opN | opMod: // n % m = x 205 skip = f != 0 || nMask&setBit == 0 206 207 case opN | opMod | opNotEqual: // n % m != x 208 skip = f == 0 && nMask&setBit != 0 209 210 case opF: // f = x 211 skip = f >= numN || p.inclusionMasks[f%maxMod]&setBit == 0 212 213 case opF | opNotEqual: // f != x 214 skip = f < numN && p.inclusionMasks[f%maxMod]&setBit != 0 215 216 case opF | opMod: // f % m = x 217 skip = p.inclusionMasks[f%maxMod]&setBit == 0 218 219 case opF | opMod | opNotEqual: // f % m != x 220 skip = p.inclusionMasks[f%maxMod]&setBit != 0 221 222 case opV: // v = x 223 skip = v < numN && vMask&setBit == 0 224 225 case opV | opNotEqual: // v != x 226 skip = v < numN && vMask&setBit != 0 227 228 case opW: // w == 0 229 skip = f != 0 230 231 case opW | opNotEqual: // w != 0 232 skip = f == 0 233 234 // Hard-wired rules that cannot be handled by our algorithm. 235 236 case opBretonM: 237 skip = f != 0 || n == 0 || n%1000000 != 0 238 239 case opAzerbaijan00s: 240 // 100,200,300,400,500,600,700,800,900 241 skip = n == 0 || n >= 1000 || n%100 != 0 242 243 case opItalian800: 244 skip = (f != 0 || n >= numN || nMask&setBit == 0) && n != 800 245 } 246 if skip { 247 // advance over AND entries. 248 for ; i < len(rules) && rules[i].cat&formMask == andNext; i++ { 249 } 250 continue 251 } 252 // return if we have a final entry. 253 if cat := rule.cat & formMask; cat != andNext { 254 return Form(cat) 255 } 256 } 257 return Other 258} 259