// Copyright 2017 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.package pluralimport ()// TODO: consider deleting this interface. Maybe VisibleDigits is always// sufficient and practical.// Interface is used for types that can determine their own plural form.typeInterfaceinterface {// PluralForm reports the plural form for the given language of the // underlying value. It also returns the integer value. If the integer value // is larger than fits in n, PluralForm may return a value modulo // 10,000,000.PluralForm(t language.Tag, scale int) (f Form, n int)}// Selectf returns the first case for which its selector is a match for the// arg-th substitution argument to a formatting call, formatting it as indicated// by format.//// The cases argument are pairs of selectors and messages. Selectors are of type// string or Form. Messages are of type string or catalog.Message. A selector// matches an argument if:// - it is "other" or Other// - it matches the plural form of the argument: "zero", "one", "two", "few",// or "many", or the equivalent Form// - it is of the form "=x" where x is an integer that matches the value of// the argument.// - it is of the form "<x" where x is an integer that is larger than the// argument.//// The format argument determines the formatting parameters for which to// determine the plural form. This is especially relevant for non-integer// values.//// The format string may be "", in which case a best-effort attempt is made to// find a reasonable representation on which to base the plural form. Examples// of format strings are:// - %.2f decimal with scale 2// - %.2e scientific notation with precision 3 (scale + 1)// - %d integerfunc ( int, string, ...interface{}) catalog.Message {varparser// Intercept the formatting parameters of format by doing a dummy print.fmt.Fprintf(io.Discard, , &) := &message{, kindDefault, 0, }switch .verb {case'g': .kind = kindPrecision .scale = .scalecase'f': .kind = kindScale .scale = .scalecase'e': .kind = kindScientific .scale = .scalecase'd': .kind = kindScale .scale = 0default:// TODO: do we need to handle errors? }return}type parser struct { verb rune scale int}func ( *parser) ( fmt.State, rune) { .verb = .scale = -1if , := .Precision(); { .scale = }}type message struct { arg int kind int scale int cases []interface{}}const (// Start with non-ASCII to allow skipping values. kindDefault = 0x80 + iota kindScale // verb f, number of fraction digits follows kindScientific // verb e, number of fraction digits follows kindPrecision // verb g, number of significant digits follows)var handle = catmsg.Register("golang.org/x/text/feature/plural:plural", execute)func ( *message) ( *catmsg.Encoder) error { .EncodeMessageType(handle) .EncodeUint(uint64(.arg)) .EncodeUint(uint64(.kind))if .kind > kindDefault { .EncodeUint(uint64(.scale)) } := validForms(cardinal, .Language())for := 0; < len(.cases); {if := compileSelector(, , .cases[]); != nil {return }if ++; >= len(.cases) {returnfmt.Errorf("plural: no message defined for selector %v", .cases[-1]) }varcatalog.Messageswitch x := .cases[].(type) {casestring: = catalog.String()casecatalog.Message: = default:returnfmt.Errorf("plural: message of type %T; must be string or catalog.Message", ) }if := .EncodeMessage(); != nil {return } ++ }returnnil}func compileSelector( *catmsg.Encoder, []Form, interface{}) error { := Otherswitch x := .(type) {casestring:if == "" {returnfmt.Errorf("plural: empty selector") }if := [0]; == '=' || == '<' { , := strconv.ParseUint([1:], 10, 16)if != nil {returnfmt.Errorf("plural: invalid number in selector %q: %v", , ) } .EncodeUint(uint64()) .EncodeUint()returnnil }varbool , = countMap[]if ! {returnfmt.Errorf("plural: invalid plural form %q", ) }caseForm: = default:returnfmt.Errorf("plural: selector of type %T; want string or Form", ) } := falsefor , := range {if == { = truebreak } }if ! {returnfmt.Errorf("plural: form %q not supported for language %q", , .Language()) } .EncodeUint(uint64())returnnil}func execute( *catmsg.Decoder) bool { := .Language() := int(.DecodeUint()) := int(.DecodeUint()) := -1// defaultif > kindDefault { = int(.DecodeUint()) } := Other := -1if := .Arg(); == nil {// Default to Other. } elseif , := .(number.VisibleDigits); { := .Digits(nil, , ) , = cardinal.matchDisplayDigits(, &) } elseif , := .(Interface); {// This covers lists and formatters from the number package. , = .PluralForm(, ) } else {varnumber.Formatterswitch {casekindScale: .InitDecimal() .SetScale()casekindScientific: .InitScientific() .SetScale()casekindPrecision: .InitDecimal() .SetPrecision()casekindDefault:// sensible default .InitDecimal()if := reflect.TypeOf().Kind(); reflect.Int <= && <= reflect.Uintptr { .SetScale(0) } else { .SetScale(2) } }varnumber.Decimal// TODO: buffer in Printer .Convert(.RoundingContext, ) := number.FormatDigits(&, .RoundingContext)if !.NaN && !.Inf { , = cardinal.matchDisplayDigits(.Language(), &) } }for !.Done() { := .DecodeUint()if ( == '=' && == int(.DecodeUint())) || ( == '<' && 0 <= && < int(.DecodeUint())) || == Form() ||Other == Form() {return .ExecuteMessage() } .SkipMessage() }returnfalse}
The pages are generated with Goldsv0.8.2. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.