From 621e49bb465f500cc46d47e39e828cf76d6381d7 Mon Sep 17 00:00:00 2001 From: Dimitri Sokolyuk Date: Tue, 24 Jul 2018 14:35:44 +0200 Subject: update vendor --- .../golang.org/x/text/message/pipeline/generate.go | 251 +++++++++++++++++++++ 1 file changed, 251 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 0000000..c5e51bd --- /dev/null +++ b/vendor/golang.org/x/text/message/pipeline/generate.go @@ -0,0 +1,251 @@ +// 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" + "io" + "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" +) + +var transRe = regexp.MustCompile(`messages\.(.*)\.json`) + +// Generate writes a Go file with the given package name to w, which defines a +// Catalog with translated messages. +func Generate(w io.Writer, pkg string, extracted *Locale, trans ...*Locale) (n int, err error) { + // TODO: add in external input. Right now we assume that all files are + // manually created and stored in the textdata directory. + + // Build up index of translations and original messages. + translations := map[language.Tag]map[string]Message{} + languages := []language.Tag{} + langVars := []string{} + usedKeys := map[string]int{} + + for _, loc := range trans { + 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 { + logf("Duplicate translation in locale %q for message %q", tag, id) + } + translations[tag][id] = m + } + } + } + } + + // Verify completeness and register keys. + internal.SortTags(languages) + + for _, tag := range languages { + langVars = append(langVars, strings.Replace(tag.String(), "-", "_", -1)) + dict := translations[tag] + for _, msg := range 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. + logf("%s: Missing entry for %q.", tag, id) + } + } + } + + cw := gen.NewCodeWriter() + + x := &struct { + Fallback language.Tag + Languages []string + }{ + Fallback: extracted.Language, + Languages: langVars, + } + + if err := lookup.Execute(cw, x); err != nil { + return 0, 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 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 0, wrap(err, "error") + } + // TODO: support macros. + data, err := catmsg.Compile(tag, nil, m) + if err != nil { + return 0, wrap(err, "error") + } + key := usedKeys[msg.Key] + if d := a[key]; d != "" && d != data { + logf("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.WriteGo(w, pkg, "") +} + +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