From 2fa7c464f019f67c5c0494aaf5ac0f5ecc1ee7a7 Mon Sep 17 00:00:00 2001 From: Harrison Healey Date: Tue, 16 Jan 2018 12:03:31 -0500 Subject: Updated dependencies and added avct/uasurfer (#8089) * Updated dependencies and added avct/uasurfer * Added uasurfer to NOTICE.txt --- .../golang.org/x/text/message/pipeline/generate.go | 314 +++++++++++++++++++++ 1 file changed, 314 insertions(+) create mode 100644 vendor/golang.org/x/text/message/pipeline/generate.go (limited to 'vendor/golang.org/x/text/message/pipeline/generate.go') diff --git a/vendor/golang.org/x/text/message/pipeline/generate.go b/vendor/golang.org/x/text/message/pipeline/generate.go new file mode 100644 index 000000000..5d329b2f4 --- /dev/null +++ b/vendor/golang.org/x/text/message/pipeline/generate.go @@ -0,0 +1,314 @@ +// 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 pipeline + +import ( + "fmt" + "go/build" + "io" + "path/filepath" + "regexp" + "sort" + "strings" + "text/template" + + "golang.org/x/text/collate" + "golang.org/x/text/feature/plural" + "golang.org/x/text/internal" + "golang.org/x/text/internal/catmsg" + "golang.org/x/text/internal/gen" + "golang.org/x/text/language" + "golang.org/x/tools/go/loader" +) + +var transRe = regexp.MustCompile(`messages\.(.*)\.json`) + +// Generate writes a Go file that defines a Catalog with translated messages. +// Translations are retrieved from s.Messages, not s.Translations, so it +// is assumed Merge has been called. +func (s *State) Generate() error { + path := s.Config.GenPackage + if path == "" { + path = "." + } + isDir := path[0] == '.' + prog, err := loadPackages(&loader.Config{}, []string{path}) + if err != nil { + return wrap(err, "could not load package") + } + pkgs := prog.InitialPackages() + if len(pkgs) != 1 { + return errorf("more than one package selected: %v", pkgs) + } + pkg := pkgs[0].Pkg.Name() + + cw, err := s.generate() + if err != nil { + return err + } + if !isDir { + gopath := build.Default.GOPATH + path = filepath.Join(gopath, filepath.FromSlash(pkgs[0].Pkg.Path())) + } + path = filepath.Join(path, s.Config.GenFile) + cw.WriteGoFile(path, pkg) // TODO: WriteGoFile should return error. + return err +} + +// WriteGen writes a Go file with the given package name to w that defines a +// Catalog with translated messages. Translations are retrieved from s.Messages, +// not s.Translations, so it is assumed Merge has been called. +func (s *State) WriteGen(w io.Writer, pkg string) error { + cw, err := s.generate() + if err != nil { + return err + } + _, err = cw.WriteGo(w, pkg, "") + return err +} + +// Generate is deprecated; use (*State).Generate(). +func Generate(w io.Writer, pkg string, extracted *Messages, trans ...Messages) (n int, err error) { + s := State{ + Extracted: *extracted, + Translations: trans, + } + cw, err := s.generate() + if err != nil { + return 0, err + } + return cw.WriteGo(w, pkg, "") +} + +func (s *State) generate() (*gen.CodeWriter, error) { + // Build up index of translations and original messages. + translations := map[language.Tag]map[string]Message{} + languages := []language.Tag{} + usedKeys := map[string]int{} + + for _, loc := range s.Messages { + tag := loc.Language + if _, ok := translations[tag]; !ok { + translations[tag] = map[string]Message{} + languages = append(languages, tag) + } + for _, m := range loc.Messages { + if !m.Translation.IsEmpty() { + for _, id := range m.ID { + if _, ok := translations[tag][id]; ok { + warnf("Duplicate translation in locale %q for message %q", tag, id) + } + translations[tag][id] = m + } + } + } + } + + // Verify completeness and register keys. + internal.SortTags(languages) + + langVars := []string{} + for _, tag := range languages { + langVars = append(langVars, strings.Replace(tag.String(), "-", "_", -1)) + dict := translations[tag] + for _, msg := range s.Extracted.Messages { + for _, id := range msg.ID { + if trans, ok := dict[id]; ok && !trans.Translation.IsEmpty() { + if _, ok := usedKeys[msg.Key]; !ok { + usedKeys[msg.Key] = len(usedKeys) + } + break + } + // TODO: log missing entry. + warnf("%s: Missing entry for %q.", tag, id) + } + } + } + + cw := gen.NewCodeWriter() + + x := &struct { + Fallback language.Tag + Languages []string + }{ + Fallback: s.Extracted.Language, + Languages: langVars, + } + + if err := lookup.Execute(cw, x); err != nil { + return nil, wrap(err, "error") + } + + keyToIndex := []string{} + for k := range usedKeys { + keyToIndex = append(keyToIndex, k) + } + sort.Strings(keyToIndex) + fmt.Fprint(cw, "var messageKeyToIndex = map[string]int{\n") + for _, k := range keyToIndex { + fmt.Fprintf(cw, "%q: %d,\n", k, usedKeys[k]) + } + fmt.Fprint(cw, "}\n\n") + + for i, tag := range languages { + dict := translations[tag] + a := make([]string, len(usedKeys)) + for _, msg := range s.Extracted.Messages { + for _, id := range msg.ID { + if trans, ok := dict[id]; ok && !trans.Translation.IsEmpty() { + m, err := assemble(&msg, &trans.Translation) + if err != nil { + return nil, wrap(err, "error") + } + _, leadWS, trailWS := trimWS(msg.Key) + if leadWS != "" || trailWS != "" { + m = catmsg.Affix{ + Message: m, + Prefix: leadWS, + Suffix: trailWS, + } + } + // TODO: support macros. + data, err := catmsg.Compile(tag, nil, m) + if err != nil { + return nil, wrap(err, "error") + } + key := usedKeys[msg.Key] + if d := a[key]; d != "" && d != data { + warnf("Duplicate non-consistent translation for key %q, picking the one for message %q", msg.Key, id) + } + a[key] = string(data) + break + } + } + } + index := []uint32{0} + p := 0 + for _, s := range a { + p += len(s) + index = append(index, uint32(p)) + } + + cw.WriteVar(langVars[i]+"Index", index) + cw.WriteConst(langVars[i]+"Data", strings.Join(a, "")) + } + return cw, nil +} + +func assemble(m *Message, t *Text) (msg catmsg.Message, err error) { + keys := []string{} + for k := range t.Var { + keys = append(keys, k) + } + sort.Strings(keys) + var a []catmsg.Message + for _, k := range keys { + t := t.Var[k] + m, err := assemble(m, &t) + if err != nil { + return nil, err + } + a = append(a, &catmsg.Var{Name: k, Message: m}) + } + if t.Select != nil { + s, err := assembleSelect(m, t.Select) + if err != nil { + return nil, err + } + a = append(a, s) + } + if t.Msg != "" { + sub, err := m.Substitute(t.Msg) + if err != nil { + return nil, err + } + a = append(a, catmsg.String(sub)) + } + switch len(a) { + case 0: + return nil, errorf("generate: empty message") + case 1: + return a[0], nil + default: + return catmsg.FirstOf(a), nil + + } +} + +func assembleSelect(m *Message, s *Select) (msg catmsg.Message, err error) { + cases := []string{} + for c := range s.Cases { + cases = append(cases, c) + } + sortCases(cases) + + caseMsg := []interface{}{} + for _, c := range cases { + cm := s.Cases[c] + m, err := assemble(m, &cm) + if err != nil { + return nil, err + } + caseMsg = append(caseMsg, c, m) + } + + ph := m.Placeholder(s.Arg) + + switch s.Feature { + case "plural": + // TODO: only printf-style selects are supported as of yet. + return plural.Selectf(ph.ArgNum, ph.String, caseMsg...), nil + } + return nil, errorf("unknown feature type %q", s.Feature) +} + +func sortCases(cases []string) { + // TODO: implement full interface. + sort.Slice(cases, func(i, j int) bool { + if cases[j] == "other" && cases[i] != "other" { + return true + } + // the following code relies on '<' < '=' < any letter. + return cmpNumeric(cases[i], cases[j]) == -1 + }) +} + +var cmpNumeric = collate.New(language.Und, collate.Numeric).CompareString + +var lookup = template.Must(template.New("gen").Parse(` +import ( + "golang.org/x/text/language" + "golang.org/x/text/message" + "golang.org/x/text/message/catalog" +) + +type dictionary struct { + index []uint32 + data string +} + +func (d *dictionary) Lookup(key string) (data string, ok bool) { + p := messageKeyToIndex[key] + start, end := d.index[p], d.index[p+1] + if start == end { + return "", false + } + return d.data[start:end], true +} + +func init() { + dict := map[string]catalog.Dictionary{ + {{range .Languages}}"{{.}}": &dictionary{index: {{.}}Index, data: {{.}}Data }, + {{end}} + } + fallback := language.MustParse("{{.Fallback}}") + cat, err := catalog.NewFromMap(dict, catalog.Fallback(fallback)) + if err != nil { + panic(err) + } + message.DefaultCatalog = cat +} + +`)) -- cgit v1.2.3-1-g7c22