diff options
Diffstat (limited to 'vendor/golang.org/x/text/internal/catmsg/catmsg.go')
-rw-r--r-- | vendor/golang.org/x/text/internal/catmsg/catmsg.go | 415 |
1 files changed, 0 insertions, 415 deletions
diff --git a/vendor/golang.org/x/text/internal/catmsg/catmsg.go b/vendor/golang.org/x/text/internal/catmsg/catmsg.go deleted file mode 100644 index c0bf86f..0000000 --- a/vendor/golang.org/x/text/internal/catmsg/catmsg.go +++ /dev/null @@ -1,415 +0,0 @@ -// 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 catmsg contains support types for package x/text/message/catalog. -// -// This package contains the low-level implementations of Message used by the -// catalog package and provides primitives for other packages to implement their -// own. For instance, the plural package provides functionality for selecting -// translation strings based on the plural category of substitution arguments. -// -// -// Encoding and Decoding -// -// Catalogs store Messages encoded as a single string. Compiling a message into -// a string both results in compacter representation and speeds up evaluation. -// -// A Message must implement a Compile method to convert its arbitrary -// representation to a string. The Compile method takes an Encoder which -// facilitates serializing the message. Encoders also provide more context of -// the messages's creation (such as for which language the message is intended), -// which may not be known at the time of the creation of the message. -// -// Each message type must also have an accompanying decoder registered to decode -// the message. This decoder takes a Decoder argument which provides the -// counterparts for the decoding. -// -// -// Renderers -// -// A Decoder must be initialized with a Renderer implementation. These -// implementations must be provided by packages that use Catalogs, typically -// formatting packages such as x/text/message. A typical user will not need to -// worry about this type; it is only relevant to packages that do string -// formatting and want to use the catalog package to handle localized strings. -// -// A package that uses catalogs for selecting strings receives selection results -// as sequence of substrings passed to the Renderer. The following snippet shows -// how to express the above example using the message package. -// -// message.Set(language.English, "You are %d minute(s) late.", -// catalog.Var("minutes", plural.Select(1, "one", "minute")), -// catalog.String("You are %[1]d ${minutes} late.")) -// -// p := message.NewPrinter(language.English) -// p.Printf("You are %d minute(s) late.", 5) // always 5 minutes late. -// -// To evaluate the Printf, package message wraps the arguments in a Renderer -// that is passed to the catalog for message decoding. The call sequence that -// results from evaluating the above message, assuming the person is rather -// tardy, is: -// -// Render("You are %[1]d ") -// Arg(1) -// Render("minutes") -// Render(" late.") -// -// The calls to Arg is caused by the plural.Select execution, which evaluates -// the argument to determine whether the singular or plural message form should -// be selected. The calls to Render reports the partial results to the message -// package for further evaluation. -package catmsg - -import ( - "errors" - "fmt" - "strconv" - "strings" - "sync" - - "golang.org/x/text/language" -) - -// A Handle refers to a registered message type. -type Handle int - -// A Handler decodes and evaluates data compiled by a Message and sends the -// result to the Decoder. The output may depend on the value of the substitution -// arguments, accessible by the Decoder's Arg method. The Handler returns false -// if there is no translation for the given substitution arguments. -type Handler func(d *Decoder) bool - -// Register records the existence of a message type and returns a Handle that -// can be used in the Encoder's EncodeMessageType method to create such -// messages. The prefix of the name should be the package path followed by -// an optional disambiguating string. -// Register will panic if a handle for the same name was already registered. -func Register(name string, handler Handler) Handle { - mutex.Lock() - defer mutex.Unlock() - - if _, ok := names[name]; ok { - panic(fmt.Errorf("catmsg: handler for %q already exists", name)) - } - h := Handle(len(handlers)) - names[name] = h - handlers = append(handlers, handler) - return h -} - -// These handlers require fixed positions in the handlers slice. -const ( - msgVars Handle = iota - msgFirst - msgRaw - msgString - msgAffix - // Leave some arbitrary room for future expansion: 20 should suffice. - numInternal = 20 -) - -const prefix = "golang.org/x/text/internal/catmsg." - -var ( - // TODO: find a more stable way to link handles to message types. - mutex sync.Mutex - names = map[string]Handle{ - prefix + "Vars": msgVars, - prefix + "First": msgFirst, - prefix + "Raw": msgRaw, - prefix + "String": msgString, - prefix + "Affix": msgAffix, - } - handlers = make([]Handler, numInternal) -) - -func init() { - // This handler is a message type wrapper that initializes a decoder - // with a variable block. This message type, if present, is always at the - // start of an encoded message. - handlers[msgVars] = func(d *Decoder) bool { - blockSize := int(d.DecodeUint()) - d.vars = d.data[:blockSize] - d.data = d.data[blockSize:] - return d.executeMessage() - } - - // First takes the first message in a sequence that results in a match for - // the given substitution arguments. - handlers[msgFirst] = func(d *Decoder) bool { - for !d.Done() { - if d.ExecuteMessage() { - return true - } - } - return false - } - - handlers[msgRaw] = func(d *Decoder) bool { - d.Render(d.data) - return true - } - - // A String message alternates between a string constant and a variable - // substitution. - handlers[msgString] = func(d *Decoder) bool { - for !d.Done() { - if str := d.DecodeString(); str != "" { - d.Render(str) - } - if d.Done() { - break - } - d.ExecuteSubstitution() - } - return true - } - - handlers[msgAffix] = func(d *Decoder) bool { - // TODO: use an alternative method for common cases. - prefix := d.DecodeString() - suffix := d.DecodeString() - if prefix != "" { - d.Render(prefix) - } - ret := d.ExecuteMessage() - if suffix != "" { - d.Render(suffix) - } - return ret - } -} - -var ( - // ErrIncomplete indicates a compiled message does not define translations - // for all possible argument values. If this message is returned, evaluating - // a message may result in the ErrNoMatch error. - ErrIncomplete = errors.New("catmsg: incomplete message; may not give result for all inputs") - - // ErrNoMatch indicates no translation message matched the given input - // parameters when evaluating a message. - ErrNoMatch = errors.New("catmsg: no translation for inputs") -) - -// A Message holds a collection of translations for the same phrase that may -// vary based on the values of substitution arguments. -type Message interface { - // Compile encodes the format string(s) of the message as a string for later - // evaluation. - // - // The first call Compile makes on the encoder must be EncodeMessageType. - // The handle passed to this call may either be a handle returned by - // Register to encode a single custom message, or HandleFirst followed by - // a sequence of calls to EncodeMessage. - // - // Compile must return ErrIncomplete if it is possible for evaluation to - // not match any translation for a given set of formatting parameters. - // For example, selecting a translation based on plural form may not yield - // a match if the form "Other" is not one of the selectors. - // - // Compile may return any other application-specific error. For backwards - // compatibility with package like fmt, which often do not do sanity - // checking of format strings ahead of time, Compile should still make an - // effort to have some sensible fallback in case of an error. - Compile(e *Encoder) error -} - -// Compile converts a Message to a data string that can be stored in a Catalog. -// The resulting string can subsequently be decoded by passing to the Execute -// method of a Decoder. -func Compile(tag language.Tag, macros Dictionary, m Message) (data string, err error) { - // TODO: pass macros so they can be used for validation. - v := &Encoder{inBody: true} // encoder for variables - v.root = v - e := &Encoder{root: v, parent: v, tag: tag} // encoder for messages - err = m.Compile(e) - // This package serves te message package, which in turn is meant to be a - // drop-in replacement for fmt. With the fmt package, format strings are - // evaluated lazily and errors are handled by substituting strings in the - // result, rather then returning an error. Dealing with multiple languages - // makes it more important to check errors ahead of time. We chose to be - // consistent and compatible and allow graceful degradation in case of - // errors. - buf := e.buf[stripPrefix(e.buf):] - if len(v.buf) > 0 { - // Prepend variable block. - b := make([]byte, 1+maxVarintBytes+len(v.buf)+len(buf)) - b[0] = byte(msgVars) - b = b[:1+encodeUint(b[1:], uint64(len(v.buf)))] - b = append(b, v.buf...) - b = append(b, buf...) - buf = b - } - if err == nil { - err = v.err - } - return string(buf), err -} - -// FirstOf is a message type that prints the first message in the sequence that -// resolves to a match for the given substitution arguments. -type FirstOf []Message - -// Compile implements Message. -func (s FirstOf) Compile(e *Encoder) error { - e.EncodeMessageType(msgFirst) - err := ErrIncomplete - for i, m := range s { - if err == nil { - return fmt.Errorf("catalog: message argument %d is complete and blocks subsequent messages", i-1) - } - err = e.EncodeMessage(m) - } - return err -} - -// Var defines a message that can be substituted for a placeholder of the same -// name. If an expression does not result in a string after evaluation, Name is -// used as the substitution. For example: -// Var{ -// Name: "minutes", -// Message: plural.Select(1, "one", "minute"), -// } -// will resolve to minute for singular and minutes for plural forms. -type Var struct { - Name string - Message Message -} - -var errIsVar = errors.New("catmsg: variable used as message") - -// Compile implements Message. -// -// Note that this method merely registers a variable; it does not create an -// encoded message. -func (v *Var) Compile(e *Encoder) error { - if err := e.addVar(v.Name, v.Message); err != nil { - return err - } - // Using a Var by itself is an error. If it is in a sequence followed by - // other messages referring to it, this error will be ignored. - return errIsVar -} - -// Raw is a message consisting of a single format string that is passed as is -// to the Renderer. -// -// Note that a Renderer may still do its own variable substitution. -type Raw string - -// Compile implements Message. -func (r Raw) Compile(e *Encoder) (err error) { - e.EncodeMessageType(msgRaw) - // Special case: raw strings don't have a size encoding and so don't use - // EncodeString. - e.buf = append(e.buf, r...) - return nil -} - -// String is a message consisting of a single format string which contains -// placeholders that may be substituted with variables. -// -// Variable substitutions are marked with placeholders and a variable name of -// the form ${name}. Any other substitutions such as Go templates or -// printf-style substitutions are left to be done by the Renderer. -// -// When evaluation a string interpolation, a Renderer will receive separate -// calls for each placeholder and interstitial string. For example, for the -// message: "%[1]v ${invites} %[2]v to ${their} party." The sequence of calls -// is: -// d.Render("%[1]v ") -// d.Arg(1) -// d.Render(resultOfInvites) -// d.Render(" %[2]v to ") -// d.Arg(2) -// d.Render(resultOfTheir) -// d.Render(" party.") -// where the messages for "invites" and "their" both use a plural.Select -// referring to the first argument. -// -// Strings may also invoke macros. Macros are essentially variables that can be -// reused. Macros may, for instance, be used to make selections between -// different conjugations of a verb. See the catalog package description for an -// overview of macros. -type String string - -// Compile implements Message. It parses the placeholder formats and returns -// any error. -func (s String) Compile(e *Encoder) (err error) { - msg := string(s) - const subStart = "${" - hasHeader := false - p := 0 - b := []byte{} - for { - i := strings.Index(msg[p:], subStart) - if i == -1 { - break - } - b = append(b, msg[p:p+i]...) - p += i + len(subStart) - if i = strings.IndexByte(msg[p:], '}'); i == -1 { - b = append(b, "$!(MISSINGBRACE)"...) - err = fmt.Errorf("catmsg: missing '}'") - p = len(msg) - break - } - name := strings.TrimSpace(msg[p : p+i]) - if q := strings.IndexByte(name, '('); q == -1 { - if !hasHeader { - hasHeader = true - e.EncodeMessageType(msgString) - } - e.EncodeString(string(b)) - e.EncodeSubstitution(name) - b = b[:0] - } else if j := strings.IndexByte(name[q:], ')'); j == -1 { - // TODO: what should the error be? - b = append(b, "$!(MISSINGPAREN)"...) - err = fmt.Errorf("catmsg: missing ')'") - } else if x, sErr := strconv.ParseUint(strings.TrimSpace(name[q+1:q+j]), 10, 32); sErr != nil { - // TODO: handle more than one argument - b = append(b, "$!(BADNUM)"...) - err = fmt.Errorf("catmsg: invalid number %q", strings.TrimSpace(name[q+1:q+j])) - } else { - if !hasHeader { - hasHeader = true - e.EncodeMessageType(msgString) - } - e.EncodeString(string(b)) - e.EncodeSubstitution(name[:q], int(x)) - b = b[:0] - } - p += i + 1 - } - b = append(b, msg[p:]...) - if !hasHeader { - // Simplify string to a raw string. - Raw(string(b)).Compile(e) - } else if len(b) > 0 { - e.EncodeString(string(b)) - } - return err -} - -// Affix is a message that adds a prefix and suffix to another message. -// This is mostly used add back whitespace to a translation that was stripped -// before sending it out. -type Affix struct { - Message Message - Prefix string - Suffix string -} - -// Compile implements Message. -func (a Affix) Compile(e *Encoder) (err error) { - // TODO: consider adding a special message type that just adds a single - // return. This is probably common enough to handle the majority of cases. - // Get some stats first, though. - e.EncodeMessageType(msgAffix) - e.EncodeString(a.Prefix) - e.EncodeString(a.Suffix) - e.EncodeMessage(a.Message) - return nil -} |