diff options
Diffstat (limited to 'vendor/github.com/nicksnyder/go-i18n/i18n/language/codegen')
-rw-r--r-- | vendor/github.com/nicksnyder/go-i18n/i18n/language/codegen/main.go | 132 | ||||
-rw-r--r-- | vendor/github.com/nicksnyder/go-i18n/i18n/language/codegen/xml.go | 143 |
2 files changed, 275 insertions, 0 deletions
diff --git a/vendor/github.com/nicksnyder/go-i18n/i18n/language/codegen/main.go b/vendor/github.com/nicksnyder/go-i18n/i18n/language/codegen/main.go new file mode 100644 index 00000000..5d6b6ad4 --- /dev/null +++ b/vendor/github.com/nicksnyder/go-i18n/i18n/language/codegen/main.go @@ -0,0 +1,132 @@ +package main + +import ( + "encoding/xml" + "flag" + "fmt" + "io/ioutil" + "os" + "text/template" +) + +var usage = `%[1]s generates Go code to support CLDR plural rules. + +Usage: %[1]s [options] + +Options: + +` + +func main() { + flag.Usage = func() { + fmt.Fprintf(os.Stderr, usage, os.Args[0]) + flag.PrintDefaults() + } + var in, cout, tout string + flag.StringVar(&in, "i", "plurals.xml", "the input XML file containing CLDR plural rules") + flag.StringVar(&cout, "cout", "", "the code output file") + flag.StringVar(&tout, "tout", "", "the test output file") + flag.BoolVar(&verbose, "v", false, "verbose output") + flag.Parse() + + buf, err := ioutil.ReadFile(in) + if err != nil { + fatalf("failed to read file: %s", err) + } + + var data SupplementalData + if err := xml.Unmarshal(buf, &data); err != nil { + fatalf("failed to unmarshal xml: %s", err) + } + + count := 0 + for _, pg := range data.PluralGroups { + count += len(pg.SplitLocales()) + } + infof("parsed %d locales", count) + + if cout != "" { + file := openWritableFile(cout) + if err := codeTemplate.Execute(file, data); err != nil { + fatalf("unable to execute code template because %s", err) + } else { + infof("generated %s", cout) + } + } else { + infof("not generating code file (use -cout)") + } + + if tout != "" { + file := openWritableFile(tout) + if err := testTemplate.Execute(file, data); err != nil { + fatalf("unable to execute test template because %s", err) + } else { + infof("generated %s", tout) + } + } else { + infof("not generating test file (use -tout)") + } +} + +func openWritableFile(name string) *os.File { + file, err := os.OpenFile(name, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644) + if err != nil { + fatalf("failed to write file %s because %s", name, err) + } + return file +} + +var codeTemplate = template.Must(template.New("spec").Parse(`package language +// This file is generated by i18n/language/codegen/generate.sh + +func init() { +{{range .PluralGroups}} + registerPluralSpec({{printf "%#v" .SplitLocales}}, &PluralSpec{ + Plurals: newPluralSet({{range $i, $e := .PluralRules}}{{if $i}}, {{end}}{{$e.CountTitle}}{{end}}), + PluralFunc: func(ops *operands) Plural { {{range .PluralRules}}{{if .GoCondition}} + // {{.Condition}} + if {{.GoCondition}} { + return {{.CountTitle}} + }{{end}}{{end}} + return Other + }, + }){{end}} +} +`)) + +var testTemplate = template.Must(template.New("spec").Parse(`package language +// This file is generated by i18n/language/codegen/generate.sh + +import "testing" + +{{range .PluralGroups}} +func Test{{.Name}}(t *testing.T) { + var tests []pluralTest + {{range .PluralRules}} + {{if .IntegerExamples}}tests = appendIntegerTests(tests, {{.CountTitle}}, {{printf "%#v" .IntegerExamples}}){{end}} + {{if .DecimalExamples}}tests = appendDecimalTests(tests, {{.CountTitle}}, {{printf "%#v" .DecimalExamples}}){{end}} + {{end}} + locales := {{printf "%#v" .SplitLocales}} + for _, locale := range locales { + runTests(t, locale, tests) + } +} +{{end}} +`)) + +func infof(format string, args ...interface{}) { + fmt.Fprintf(os.Stderr, format+"\n", args...) +} + +var verbose bool + +func verbosef(format string, args ...interface{}) { + if verbose { + infof(format, args...) + } +} + +func fatalf(format string, args ...interface{}) { + infof("fatal: "+format+"\n", args...) + os.Exit(1) +} diff --git a/vendor/github.com/nicksnyder/go-i18n/i18n/language/codegen/xml.go b/vendor/github.com/nicksnyder/go-i18n/i18n/language/codegen/xml.go new file mode 100644 index 00000000..9d39053c --- /dev/null +++ b/vendor/github.com/nicksnyder/go-i18n/i18n/language/codegen/xml.go @@ -0,0 +1,143 @@ +package main + +import ( + "encoding/xml" + "fmt" + "regexp" + "strings" +) + +// SupplementalData is the top level struct of plural.xml +type SupplementalData struct { + XMLName xml.Name `xml:"supplementalData"` + PluralGroups []PluralGroup `xml:"plurals>pluralRules"` +} + +// PluralGroup is a group of locales with the same plural rules. +type PluralGroup struct { + Locales string `xml:"locales,attr"` + PluralRules []PluralRule `xml:"pluralRule"` +} + +// Name returns a unique name for this plural group. +func (pg *PluralGroup) Name() string { + n := strings.Title(pg.Locales) + return strings.Replace(n, " ", "", -1) +} + +// SplitLocales returns all the locales in the PluralGroup as a slice. +func (pg *PluralGroup) SplitLocales() []string { + return strings.Split(pg.Locales, " ") +} + +// PluralRule is the rule for a single plural form. +type PluralRule struct { + Count string `xml:"count,attr"` + Rule string `xml:",innerxml"` +} + +// CountTitle returns the title case of the PluralRule's count. +func (pr *PluralRule) CountTitle() string { + return strings.Title(pr.Count) +} + +// Condition returns the condition where the PluralRule applies. +func (pr *PluralRule) Condition() string { + i := strings.Index(pr.Rule, "@") + return pr.Rule[:i] +} + +// Examples returns the integer and decimal exmaples for the PLuralRule. +func (pr *PluralRule) Examples() (integer []string, decimal []string) { + ex := strings.Replace(pr.Rule, ", …", "", -1) + ddelim := "@decimal" + if i := strings.Index(ex, ddelim); i > 0 { + dex := strings.TrimSpace(ex[i+len(ddelim):]) + decimal = strings.Split(dex, ", ") + ex = ex[:i] + } + idelim := "@integer" + if i := strings.Index(ex, idelim); i > 0 { + iex := strings.TrimSpace(ex[i+len(idelim):]) + integer = strings.Split(iex, ", ") + } + return integer, decimal +} + +// IntegerExamples returns the integer exmaples for the PLuralRule. +func (pr *PluralRule) IntegerExamples() []string { + integer, _ := pr.Examples() + return integer +} + +// DecimalExamples returns the decimal exmaples for the PLuralRule. +func (pr *PluralRule) DecimalExamples() []string { + _, decimal := pr.Examples() + return decimal +} + +var relationRegexp = regexp.MustCompile("([niftvw])(?: % ([0-9]+))? (!=|=)(.*)") + +// GoCondition converts the XML condition to valid Go code. +func (pr *PluralRule) GoCondition() string { + var ors []string + for _, and := range strings.Split(pr.Condition(), "or") { + var ands []string + for _, relation := range strings.Split(and, "and") { + parts := relationRegexp.FindStringSubmatch(relation) + if parts == nil { + continue + } + lvar, lmod, op, rhs := strings.Title(parts[1]), parts[2], parts[3], strings.TrimSpace(parts[4]) + if op == "=" { + op = "==" + } + lvar = "ops." + lvar + var rhor []string + var rany []string + for _, rh := range strings.Split(rhs, ",") { + if parts := strings.Split(rh, ".."); len(parts) == 2 { + from, to := parts[0], parts[1] + if lvar == "ops.N" { + if lmod != "" { + rhor = append(rhor, fmt.Sprintf("ops.NmodInRange(%s, %s, %s)", lmod, from, to)) + } else { + rhor = append(rhor, fmt.Sprintf("ops.NinRange(%s, %s)", from, to)) + } + } else if lmod != "" { + rhor = append(rhor, fmt.Sprintf("intInRange(%s %% %s, %s, %s)", lvar, lmod, from, to)) + } else { + rhor = append(rhor, fmt.Sprintf("intInRange(%s, %s, %s)", lvar, from, to)) + } + } else { + rany = append(rany, rh) + } + } + + if len(rany) > 0 { + rh := strings.Join(rany, ",") + if lvar == "ops.N" { + if lmod != "" { + rhor = append(rhor, fmt.Sprintf("ops.NmodEqualsAny(%s, %s)", lmod, rh)) + } else { + rhor = append(rhor, fmt.Sprintf("ops.NequalsAny(%s)", rh)) + } + } else if lmod != "" { + rhor = append(rhor, fmt.Sprintf("intEqualsAny(%s %% %s, %s)", lvar, lmod, rh)) + } else { + rhor = append(rhor, fmt.Sprintf("intEqualsAny(%s, %s)", lvar, rh)) + } + } + r := strings.Join(rhor, " || ") + if len(rhor) > 1 { + r = "(" + r + ")" + } + if op == "!=" { + r = "!" + r + } + ands = append(ands, r) + } + ors = append(ors, strings.Join(ands, " && ")) + } + return strings.Join(ors, " ||\n") +} |