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) }