From 38ee83e45b4de7edf89bf9f0ef629eb4c6ad0fa8 Mon Sep 17 00:00:00 2001 From: Christopher Speller Date: Thu, 12 May 2016 23:56:07 -0400 Subject: Moving to glide --- vendor/github.com/nicksnyder/go-i18n/.gitignore | 6 + vendor/github.com/nicksnyder/go-i18n/.travis.yml | 8 + vendor/github.com/nicksnyder/go-i18n/CHANGELOG | 5 + vendor/github.com/nicksnyder/go-i18n/README.md | 130 ++++ vendor/github.com/nicksnyder/go-i18n/goi18n/doc.go | 59 ++ .../github.com/nicksnyder/go-i18n/goi18n/gendoc.sh | 10 + .../github.com/nicksnyder/go-i18n/goi18n/goi18n.go | 82 +++ .../github.com/nicksnyder/go-i18n/goi18n/merge.go | 127 ++++ .../nicksnyder/go-i18n/goi18n/merge_test.go | 74 +++ .../nicksnyder/go-i18n/goi18n/testdata/en-us.yaml | 30 + .../goi18n/testdata/expected/ar-ar.all.json | 65 ++ .../testdata/expected/ar-ar.untranslated.json | 50 ++ .../goi18n/testdata/expected/en-us.all.json | 45 ++ .../testdata/expected/en-us.untranslated.json | 1 + .../goi18n/testdata/expected/fr-fr.all.json | 45 ++ .../testdata/expected/fr-fr.untranslated.json | 45 ++ .../go-i18n/goi18n/testdata/input/ar-ar.one.json | 54 ++ .../go-i18n/goi18n/testdata/input/ar-ar.two.json | 54 ++ .../go-i18n/goi18n/testdata/input/en-us.one.json | 30 + .../go-i18n/goi18n/testdata/input/en-us.two.json | 26 + .../go-i18n/goi18n/testdata/input/fr-fr.json | 0 .../goi18n/testdata/input/yaml/ar-ar.one.json | 54 ++ .../goi18n/testdata/input/yaml/ar-ar.two.json | 54 ++ .../goi18n/testdata/input/yaml/en-us.one.yaml | 19 + .../goi18n/testdata/input/yaml/en-us.two.json | 26 + .../go-i18n/goi18n/testdata/input/yaml/fr-fr.json | 0 .../nicksnyder/go-i18n/i18n/bundle/bundle_test.go | 289 ++++++++ .../nicksnyder/go-i18n/i18n/example_test.go | 63 ++ .../go-i18n/i18n/exampletemplate_test.go | 63 ++ .../nicksnyder/go-i18n/i18n/exampleyaml_test.go | 62 ++ .../go-i18n/i18n/language/codegen/generate.sh | 5 + .../go-i18n/i18n/language/codegen/main.go | 132 ++++ .../go-i18n/i18n/language/codegen/plurals.xml | 230 +++++++ .../go-i18n/i18n/language/codegen/xml.go | 143 ++++ .../go-i18n/i18n/language/language_test.go | 85 +++ .../go-i18n/i18n/language/operands_test.go | 45 ++ .../go-i18n/i18n/language/plural_test.go | 28 + .../go-i18n/i18n/language/pluralspec_gen_test.go | 645 ++++++++++++++++++ .../go-i18n/i18n/language/pluralspec_test.go | 733 +++++++++++++++++++++ .../i18n/translation/plural_translation_test.go | 308 +++++++++ .../go-i18n/i18n/translation/template_test.go | 146 ++++ .../go-i18n/i18n/translation/translation_test.go | 17 + 42 files changed, 4093 insertions(+) create mode 100644 vendor/github.com/nicksnyder/go-i18n/.gitignore create mode 100644 vendor/github.com/nicksnyder/go-i18n/.travis.yml create mode 100644 vendor/github.com/nicksnyder/go-i18n/CHANGELOG create mode 100644 vendor/github.com/nicksnyder/go-i18n/README.md create mode 100644 vendor/github.com/nicksnyder/go-i18n/goi18n/doc.go create mode 100644 vendor/github.com/nicksnyder/go-i18n/goi18n/gendoc.sh create mode 100644 vendor/github.com/nicksnyder/go-i18n/goi18n/goi18n.go create mode 100644 vendor/github.com/nicksnyder/go-i18n/goi18n/merge.go create mode 100644 vendor/github.com/nicksnyder/go-i18n/goi18n/merge_test.go create mode 100644 vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/en-us.yaml create mode 100644 vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/expected/ar-ar.all.json create mode 100644 vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/expected/ar-ar.untranslated.json create mode 100644 vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/expected/en-us.all.json create mode 100644 vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/expected/en-us.untranslated.json create mode 100644 vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/expected/fr-fr.all.json create mode 100644 vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/expected/fr-fr.untranslated.json create mode 100644 vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/input/ar-ar.one.json create mode 100644 vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/input/ar-ar.two.json create mode 100644 vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/input/en-us.one.json create mode 100644 vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/input/en-us.two.json create mode 100644 vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/input/fr-fr.json create mode 100644 vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/input/yaml/ar-ar.one.json create mode 100644 vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/input/yaml/ar-ar.two.json create mode 100644 vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/input/yaml/en-us.one.yaml create mode 100644 vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/input/yaml/en-us.two.json create mode 100644 vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/input/yaml/fr-fr.json create mode 100644 vendor/github.com/nicksnyder/go-i18n/i18n/bundle/bundle_test.go create mode 100644 vendor/github.com/nicksnyder/go-i18n/i18n/example_test.go create mode 100644 vendor/github.com/nicksnyder/go-i18n/i18n/exampletemplate_test.go create mode 100644 vendor/github.com/nicksnyder/go-i18n/i18n/exampleyaml_test.go create mode 100644 vendor/github.com/nicksnyder/go-i18n/i18n/language/codegen/generate.sh create mode 100644 vendor/github.com/nicksnyder/go-i18n/i18n/language/codegen/main.go create mode 100644 vendor/github.com/nicksnyder/go-i18n/i18n/language/codegen/plurals.xml create mode 100644 vendor/github.com/nicksnyder/go-i18n/i18n/language/codegen/xml.go create mode 100644 vendor/github.com/nicksnyder/go-i18n/i18n/language/language_test.go create mode 100644 vendor/github.com/nicksnyder/go-i18n/i18n/language/operands_test.go create mode 100644 vendor/github.com/nicksnyder/go-i18n/i18n/language/plural_test.go create mode 100644 vendor/github.com/nicksnyder/go-i18n/i18n/language/pluralspec_gen_test.go create mode 100644 vendor/github.com/nicksnyder/go-i18n/i18n/language/pluralspec_test.go create mode 100644 vendor/github.com/nicksnyder/go-i18n/i18n/translation/plural_translation_test.go create mode 100644 vendor/github.com/nicksnyder/go-i18n/i18n/translation/template_test.go create mode 100644 vendor/github.com/nicksnyder/go-i18n/i18n/translation/translation_test.go (limited to 'vendor/github.com/nicksnyder') diff --git a/vendor/github.com/nicksnyder/go-i18n/.gitignore b/vendor/github.com/nicksnyder/go-i18n/.gitignore new file mode 100644 index 000000000..20e1aa8ff --- /dev/null +++ b/vendor/github.com/nicksnyder/go-i18n/.gitignore @@ -0,0 +1,6 @@ +*.a +_* +output/ +.DS_Store +*.test +*.swp diff --git a/vendor/github.com/nicksnyder/go-i18n/.travis.yml b/vendor/github.com/nicksnyder/go-i18n/.travis.yml new file mode 100644 index 000000000..8558bb44f --- /dev/null +++ b/vendor/github.com/nicksnyder/go-i18n/.travis.yml @@ -0,0 +1,8 @@ +language: go +sudo: false +go: + - 1.2 + - 1.3 + - 1.4 + - 1.5 + - tip diff --git a/vendor/github.com/nicksnyder/go-i18n/CHANGELOG b/vendor/github.com/nicksnyder/go-i18n/CHANGELOG new file mode 100644 index 000000000..c7949b143 --- /dev/null +++ b/vendor/github.com/nicksnyder/go-i18n/CHANGELOG @@ -0,0 +1,5 @@ +Feb 24, 2015 +- Add Korean + +Feb 18, 2015 +- Added ParseTranslationFileBytes so translation files may be loaded from an arbitrary serialization format, such as go-bindata. diff --git a/vendor/github.com/nicksnyder/go-i18n/README.md b/vendor/github.com/nicksnyder/go-i18n/README.md new file mode 100644 index 000000000..5aef540b3 --- /dev/null +++ b/vendor/github.com/nicksnyder/go-i18n/README.md @@ -0,0 +1,130 @@ +go-i18n [![Build Status](https://secure.travis-ci.org/nicksnyder/go-i18n.png?branch=master)](http://travis-ci.org/nicksnyder/go-i18n) +======= + +go-i18n is a Go [package](#i18n-package) and a [command](#goi18n-command) that helps you translate Go programs into multiple languages. +* Supports [pluralized strings](http://cldr.unicode.org/index/cldr-spec/plural-rules) for all 200+ languages in the [Unicode Common Locale Data Repository (CLDR)](http://www.unicode.org/cldr/charts/28/supplemental/language_plural_rules.html). + * Code and tests are [automatically generated](https://github.com/nicksnyder/go-i18n/tree/master/i18n/language/codegen) from [CLDR data](http://cldr.unicode.org/index/downloads) +* Supports strings with named variables using [text/template](http://golang.org/pkg/text/template/) syntax. +* Translation files are simple JSON or YAML. +* [Documented](http://godoc.org/github.com/nicksnyder/go-i18n) and [tested](https://travis-ci.org/nicksnyder/go-i18n)! + +Package i18n [![GoDoc](http://godoc.org/github.com/nicksnyder/go-i18n?status.png)](http://godoc.org/github.com/nicksnyder/go-i18n/i18n) +------------ + +The i18n package provides runtime APIs for fetching translated strings. + +Command goi18n [![GoDoc](http://godoc.org/github.com/nicksnyder/go-i18n?status.png)](http://godoc.org/github.com/nicksnyder/go-i18n/goi18n) +-------------- + +The goi18n command provides functionality for managing the translation process. + +Installation +------------ + +Make sure you have [setup GOPATH](http://golang.org/doc/code.html#GOPATH). + + go get -u github.com/nicksnyder/go-i18n/goi18n + goi18n -help + +Workflow +-------- + +A typical workflow looks like this: + +1. Add a new string to your source code. + + ```go + T("settings_title") + ``` + +2. Add the string to en-US.all.json + + ```json + [ + { + "id": "settings_title", + "translation": "Settings" + } + ] + ``` + +3. Run goi18n + + ``` + goi18n path/to/*.all.json + ``` + +4. Send `path/to/*.untranslated.json` to get translated. +5. Run goi18n again to merge the translations + + ```sh + goi18n path/to/*.all.json path/to/*.untranslated.json + ``` + +Translation files +----------------- + +A translation file stores translated and untranslated strings. + +Example: + +```json +[ + { + "id": "d_days", + "translation": { + "one": "{{.Count}} day", + "other": "{{.Count}} days" + } + }, + { + "id": "my_height_in_meters", + "translation": { + "one": "I am {{.Count}} meter tall.", + "other": "I am {{.Count}} meters tall." + } + }, + { + "id": "person_greeting", + "translation": "Hello {{.Person}}" + }, + { + "id": "person_unread_email_count", + "translation": { + "one": "{{.Person}} has {{.Count}} unread email.", + "other": "{{.Person}} has {{.Count}} unread emails." + } + }, + { + "id": "person_unread_email_count_timeframe", + "translation": { + "one": "{{.Person}} has {{.Count}} unread email in the past {{.Timeframe}}.", + "other": "{{.Person}} has {{.Count}} unread emails in the past {{.Timeframe}}." + } + }, + { + "id": "program_greeting", + "translation": "Hello world" + }, + { + "id": "your_unread_email_count", + "translation": { + "one": "You have {{.Count}} unread email.", + "other": "You have {{.Count}} unread emails." + } + } +] +``` + +Contributions +------------- + +If you would like to submit a pull request, please + +1. Write tests +2. Format code with [goimports](https://github.com/bradfitz/goimports). +3. Read the [common code review comments](https://github.com/golang/go/wiki/CodeReviewComments). + +License +------- +go-i18n is available under the MIT license. See the [LICENSE](LICENSE) file for more info. diff --git a/vendor/github.com/nicksnyder/go-i18n/goi18n/doc.go b/vendor/github.com/nicksnyder/go-i18n/goi18n/doc.go new file mode 100644 index 000000000..10d244217 --- /dev/null +++ b/vendor/github.com/nicksnyder/go-i18n/goi18n/doc.go @@ -0,0 +1,59 @@ +// The goi18n command formats and merges translation files. +// +// go get -u github.com/nicksnyder/go-i18n/goi18n +// goi18n -help +// +// Help documentation: +// +// goi18n formats and merges translation files. +// +// Usage: +// +// goi18n [options] [files...] +// +// Translation files: +// +// A translation file contains the strings and translations for a single language. +// +// Translation file names must have a suffix of a supported format (e.g. .json) and +// contain a valid language tag as defined by RFC 5646 (e.g. en-us, fr, zh-hant, etc.). +// +// For each language represented by at least one input translation file, goi18n will produce 2 output files: +// +// xx-yy.all.format +// This file contains all strings for the language (translated and untranslated). +// Use this file when loading strings at runtime. +// +// xx-yy.untranslated.format +// This file contains the strings that have not been translated for this language. +// The translations for the strings in this file will be extracted from the source language. +// After they are translated, merge them back into xx-yy.all.format using goi18n. +// +// Merging: +// +// goi18n will merge multiple translation files for the same language. +// Duplicate translations will be merged into the existing translation. +// Non-empty fields in the duplicate translation will overwrite those fields in the existing translation. +// Empty fields in the duplicate translation are ignored. +// +// Adding a new language: +// +// To produce translation files for a new language, create an empty translation file with the +// appropriate name and pass it in to goi18n. +// +// Options: +// +// -sourceLanguage tag +// goi18n uses the strings from this language to seed the translations for other languages. +// Default: en-us +// +// -outdir directory +// goi18n writes the output translation files to this directory. +// Default: . +// +// -format format +// goi18n encodes the output translation files in this format. +// Supported formats: json, yaml +// Default: json +// +package main diff --git a/vendor/github.com/nicksnyder/go-i18n/goi18n/gendoc.sh b/vendor/github.com/nicksnyder/go-i18n/goi18n/gendoc.sh new file mode 100644 index 000000000..094f479a5 --- /dev/null +++ b/vendor/github.com/nicksnyder/go-i18n/goi18n/gendoc.sh @@ -0,0 +1,10 @@ +go install +echo "// The goi18n command formats and merges translation files." > doc.go +echo "//" >> doc.go +echo "// go get -u github.com/nicksnyder/go-i18n/goi18n" >> doc.go +echo "// goi18n -help" >> doc.go +echo "//" >> doc.go +echo "// Help documentation:" >> doc.go +echo "//" >> doc.go +goi18n -help | sed -e 's/^/\/\/ /' >> doc.go +echo "package main" >> doc.go diff --git a/vendor/github.com/nicksnyder/go-i18n/goi18n/goi18n.go b/vendor/github.com/nicksnyder/go-i18n/goi18n/goi18n.go new file mode 100644 index 000000000..f57ea8175 --- /dev/null +++ b/vendor/github.com/nicksnyder/go-i18n/goi18n/goi18n.go @@ -0,0 +1,82 @@ +package main + +import ( + "flag" + "fmt" + "os" +) + +func usage() { + fmt.Printf(`goi18n formats and merges translation files. + +Usage: + + goi18n [options] [files...] + +Translation files: + + A translation file contains the strings and translations for a single language. + + Translation file names must have a suffix of a supported format (e.g. .json) and + contain a valid language tag as defined by RFC 5646 (e.g. en-us, fr, zh-hant, etc.). + + For each language represented by at least one input translation file, goi18n will produce 2 output files: + + xx-yy.all.format + This file contains all strings for the language (translated and untranslated). + Use this file when loading strings at runtime. + + xx-yy.untranslated.format + This file contains the strings that have not been translated for this language. + The translations for the strings in this file will be extracted from the source language. + After they are translated, merge them back into xx-yy.all.format using goi18n. + +Merging: + + goi18n will merge multiple translation files for the same language. + Duplicate translations will be merged into the existing translation. + Non-empty fields in the duplicate translation will overwrite those fields in the existing translation. + Empty fields in the duplicate translation are ignored. + +Adding a new language: + + To produce translation files for a new language, create an empty translation file with the + appropriate name and pass it in to goi18n. + +Options: + + -sourceLanguage tag + goi18n uses the strings from this language to seed the translations for other languages. + Default: en-us + + -outdir directory + goi18n writes the output translation files to this directory. + Default: . + + -format format + goi18n encodes the output translation files in this format. + Supported formats: json, yaml + Default: json + +`) + os.Exit(1) +} + +func main() { + flag.Usage = usage + sourceLanguage := flag.String("sourceLanguage", "en-us", "") + outdir := flag.String("outdir", ".", "") + format := flag.String("format", "json", "") + flag.Parse() + + mc := &mergeCommand{ + translationFiles: flag.Args(), + sourceLanguageTag: *sourceLanguage, + outdir: *outdir, + format: *format, + } + if err := mc.execute(); err != nil { + fmt.Println(err.Error()) + os.Exit(1) + } +} diff --git a/vendor/github.com/nicksnyder/go-i18n/goi18n/merge.go b/vendor/github.com/nicksnyder/go-i18n/goi18n/merge.go new file mode 100644 index 000000000..1317fe958 --- /dev/null +++ b/vendor/github.com/nicksnyder/go-i18n/goi18n/merge.go @@ -0,0 +1,127 @@ +package main + +import ( + "encoding/json" + "fmt" + "gopkg.in/yaml.v2" + "io/ioutil" + "path/filepath" + "reflect" + "sort" + + "github.com/nicksnyder/go-i18n/i18n/bundle" + "github.com/nicksnyder/go-i18n/i18n/language" + "github.com/nicksnyder/go-i18n/i18n/translation" +) + +type mergeCommand struct { + translationFiles []string + sourceLanguageTag string + outdir string + format string +} + +func (mc *mergeCommand) execute() error { + if len(mc.translationFiles) < 1 { + return fmt.Errorf("need at least one translation file to parse") + } + + if lang := language.Parse(mc.sourceLanguageTag); lang == nil { + return fmt.Errorf("invalid source locale: %s", mc.sourceLanguageTag) + } + + marshal, err := newMarshalFunc(mc.format) + if err != nil { + return err + } + + bundle := bundle.New() + for _, tf := range mc.translationFiles { + if err := bundle.LoadTranslationFile(tf); err != nil { + return fmt.Errorf("failed to load translation file %s because %s\n", tf, err) + } + } + + translations := bundle.Translations() + sourceLanguageTag := language.NormalizeTag(mc.sourceLanguageTag) + sourceTranslations := translations[sourceLanguageTag] + if sourceTranslations == nil { + return fmt.Errorf("no translations found for source locale %s", sourceLanguageTag) + } + for translationID, src := range sourceTranslations { + for _, localeTranslations := range translations { + if dst := localeTranslations[translationID]; dst == nil || reflect.TypeOf(src) != reflect.TypeOf(dst) { + localeTranslations[translationID] = src.UntranslatedCopy() + } + } + } + + for localeID, localeTranslations := range translations { + lang := language.MustParse(localeID)[0] + all := filter(localeTranslations, func(t translation.Translation) translation.Translation { + return t.Normalize(lang) + }) + if err := mc.writeFile("all", all, localeID, marshal); err != nil { + return err + } + + untranslated := filter(localeTranslations, func(t translation.Translation) translation.Translation { + if t.Incomplete(lang) { + return t.Normalize(lang).Backfill(sourceTranslations[t.ID()]) + } + return nil + }) + if err := mc.writeFile("untranslated", untranslated, localeID, marshal); err != nil { + return err + } + } + return nil +} + +type marshalFunc func(interface{}) ([]byte, error) + +func (mc *mergeCommand) writeFile(label string, translations []translation.Translation, localeID string, marshal marshalFunc) error { + sort.Sort(translation.SortableByID(translations)) + buf, err := marshal(marshalInterface(translations)) + if err != nil { + return fmt.Errorf("failed to marshal %s strings to %s because %s", localeID, mc.format, err) + } + filename := filepath.Join(mc.outdir, fmt.Sprintf("%s.%s.%s", localeID, label, mc.format)) + if err := ioutil.WriteFile(filename, buf, 0666); err != nil { + return fmt.Errorf("failed to write %s because %s", filename, err) + } + return nil +} + +func filter(translations map[string]translation.Translation, filter func(translation.Translation) translation.Translation) []translation.Translation { + filtered := make([]translation.Translation, 0, len(translations)) + for _, translation := range translations { + if t := filter(translation); t != nil { + filtered = append(filtered, t) + } + } + return filtered + +} + +func newMarshalFunc(format string) (marshalFunc, error) { + switch format { + case "json": + return func(v interface{}) ([]byte, error) { + return json.MarshalIndent(v, "", " ") + }, nil + case "yaml": + return func(v interface{}) ([]byte, error) { + return yaml.Marshal(v) + }, nil + } + return nil, fmt.Errorf("unsupported format: %s\n", format) +} + +func marshalInterface(translations []translation.Translation) []interface{} { + mi := make([]interface{}, len(translations)) + for i, translation := range translations { + mi[i] = translation.MarshalInterface() + } + return mi +} diff --git a/vendor/github.com/nicksnyder/go-i18n/goi18n/merge_test.go b/vendor/github.com/nicksnyder/go-i18n/goi18n/merge_test.go new file mode 100644 index 000000000..f0d0d47a1 --- /dev/null +++ b/vendor/github.com/nicksnyder/go-i18n/goi18n/merge_test.go @@ -0,0 +1,74 @@ +package main + +import ( + "bytes" + "io/ioutil" + "os" + "testing" +) + +func TestMergeExecuteJSON(t *testing.T) { + files := []string{ + "testdata/input/en-us.one.json", + "testdata/input/en-us.two.json", + "testdata/input/fr-fr.json", + "testdata/input/ar-ar.one.json", + "testdata/input/ar-ar.two.json", + } + testMergeExecute(t, files) +} + +func TestMergeExecuteYAML(t *testing.T) { + files := []string{ + "testdata/input/yaml/en-us.one.yaml", + "testdata/input/yaml/en-us.two.json", + "testdata/input/yaml/fr-fr.json", + "testdata/input/yaml/ar-ar.one.json", + "testdata/input/yaml/ar-ar.two.json", + } + testMergeExecute(t, files) +} + +func testMergeExecute(t *testing.T, files []string) { + resetDir(t, "testdata/output") + + mc := &mergeCommand{ + translationFiles: files, + sourceLanguageTag: "en-us", + outdir: "testdata/output", + format: "json", + } + if err := mc.execute(); err != nil { + t.Fatal(err) + } + + expectEqualFiles(t, "testdata/output/en-us.all.json", "testdata/expected/en-us.all.json") + expectEqualFiles(t, "testdata/output/ar-ar.all.json", "testdata/expected/ar-ar.all.json") + expectEqualFiles(t, "testdata/output/fr-fr.all.json", "testdata/expected/fr-fr.all.json") + expectEqualFiles(t, "testdata/output/en-us.untranslated.json", "testdata/expected/en-us.untranslated.json") + expectEqualFiles(t, "testdata/output/ar-ar.untranslated.json", "testdata/expected/ar-ar.untranslated.json") + expectEqualFiles(t, "testdata/output/fr-fr.untranslated.json", "testdata/expected/fr-fr.untranslated.json") +} + +func resetDir(t *testing.T, dir string) { + if err := os.RemoveAll(dir); err != nil { + t.Fatal(err) + } + if err := os.Mkdir(dir, 0777); err != nil { + t.Fatal(err) + } +} + +func expectEqualFiles(t *testing.T, expectedName, actualName string) { + actual, err := ioutil.ReadFile(actualName) + if err != nil { + t.Fatal(err) + } + expected, err := ioutil.ReadFile(expectedName) + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(actual, expected) { + t.Fatalf("contents of files did not match: %s, %s", expectedName, actualName) + } +} diff --git a/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/en-us.yaml b/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/en-us.yaml new file mode 100644 index 000000000..cdf9c8dc5 --- /dev/null +++ b/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/en-us.yaml @@ -0,0 +1,30 @@ +- id: program_greeting + translation: "Hello world" + +- id: person_greeting + translation: "Hello {{.Person}}" + +- id: my_height_in_meters + translation: + one: "I am {{.Count}} meter tall." + other: "I am {{.Count}} meters tall." + +- id: your_unread_email_count + translation: + one: "You have {{.Count}} unread email." + other: "You have {{.Count}} unread emails." + +- id: person_unread_email_count + translation: + one: "{{.Person}} has {{.Count}} unread email." + other: "{{.Person}} has {{.Count}} unread emails." + +- id: person_unread_email_count_timeframe + translation: + one: "{{.Person}} has {{.Count}} unread email in the past {{.Timeframe}}." + other: "{{.Person}} has {{.Count}} unread emails in the past {{.Timeframe}}." + +- id: d_days + translation: + one: "{{.Count}} day" + other: "{{.Count}} days" diff --git a/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/expected/ar-ar.all.json b/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/expected/ar-ar.all.json new file mode 100644 index 000000000..26a72ff30 --- /dev/null +++ b/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/expected/ar-ar.all.json @@ -0,0 +1,65 @@ +[ + { + "id": "d_days", + "translation": { + "few": "new arabic few translation of d_days", + "many": "arabic many translation of d_days", + "one": "arabic one translation of d_days", + "other": "", + "two": "", + "zero": "" + } + }, + { + "id": "my_height_in_meters", + "translation": { + "few": "", + "many": "", + "one": "", + "other": "", + "two": "", + "zero": "" + } + }, + { + "id": "person_greeting", + "translation": "new arabic translation of person_greeting" + }, + { + "id": "person_unread_email_count", + "translation": { + "few": "arabic few translation of person_unread_email_count", + "many": "arabic many translation of person_unread_email_count", + "one": "arabic one translation of person_unread_email_count", + "other": "arabic other translation of person_unread_email_count", + "two": "arabic two translation of person_unread_email_count", + "zero": "arabic zero translation of person_unread_email_count" + } + }, + { + "id": "person_unread_email_count_timeframe", + "translation": { + "few": "", + "many": "", + "one": "", + "other": "", + "two": "", + "zero": "" + } + }, + { + "id": "program_greeting", + "translation": "" + }, + { + "id": "your_unread_email_count", + "translation": { + "few": "", + "many": "", + "one": "", + "other": "", + "two": "", + "zero": "" + } + } +] \ No newline at end of file diff --git a/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/expected/ar-ar.untranslated.json b/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/expected/ar-ar.untranslated.json new file mode 100644 index 000000000..a19fa0bee --- /dev/null +++ b/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/expected/ar-ar.untranslated.json @@ -0,0 +1,50 @@ +[ + { + "id": "d_days", + "translation": { + "few": "new arabic few translation of d_days", + "many": "arabic many translation of d_days", + "one": "arabic one translation of d_days", + "other": "{{.Count}} days", + "two": "{{.Count}} days", + "zero": "{{.Count}} days" + } + }, + { + "id": "my_height_in_meters", + "translation": { + "few": "I am {{.Count}} meters tall.", + "many": "I am {{.Count}} meters tall.", + "one": "I am {{.Count}} meters tall.", + "other": "I am {{.Count}} meters tall.", + "two": "I am {{.Count}} meters tall.", + "zero": "I am {{.Count}} meters tall." + } + }, + { + "id": "person_unread_email_count_timeframe", + "translation": { + "few": "{{.Person}} has {{.Count}} unread emails in the past {{.Timeframe}}.", + "many": "{{.Person}} has {{.Count}} unread emails in the past {{.Timeframe}}.", + "one": "{{.Person}} has {{.Count}} unread emails in the past {{.Timeframe}}.", + "other": "{{.Person}} has {{.Count}} unread emails in the past {{.Timeframe}}.", + "two": "{{.Person}} has {{.Count}} unread emails in the past {{.Timeframe}}.", + "zero": "{{.Person}} has {{.Count}} unread emails in the past {{.Timeframe}}." + } + }, + { + "id": "program_greeting", + "translation": "Hello world" + }, + { + "id": "your_unread_email_count", + "translation": { + "few": "You have {{.Count}} unread emails.", + "many": "You have {{.Count}} unread emails.", + "one": "You have {{.Count}} unread emails.", + "other": "You have {{.Count}} unread emails.", + "two": "You have {{.Count}} unread emails.", + "zero": "You have {{.Count}} unread emails." + } + } +] \ No newline at end of file diff --git a/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/expected/en-us.all.json b/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/expected/en-us.all.json new file mode 100644 index 000000000..5aedc235a --- /dev/null +++ b/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/expected/en-us.all.json @@ -0,0 +1,45 @@ +[ + { + "id": "d_days", + "translation": { + "one": "{{.Count}} day", + "other": "{{.Count}} days" + } + }, + { + "id": "my_height_in_meters", + "translation": { + "one": "I am {{.Count}} meter tall.", + "other": "I am {{.Count}} meters tall." + } + }, + { + "id": "person_greeting", + "translation": "Hello {{.Person}}" + }, + { + "id": "person_unread_email_count", + "translation": { + "one": "{{.Person}} has {{.Count}} unread email.", + "other": "{{.Person}} has {{.Count}} unread emails." + } + }, + { + "id": "person_unread_email_count_timeframe", + "translation": { + "one": "{{.Person}} has {{.Count}} unread email in the past {{.Timeframe}}.", + "other": "{{.Person}} has {{.Count}} unread emails in the past {{.Timeframe}}." + } + }, + { + "id": "program_greeting", + "translation": "Hello world" + }, + { + "id": "your_unread_email_count", + "translation": { + "one": "You have {{.Count}} unread email.", + "other": "You have {{.Count}} unread emails." + } + } +] \ No newline at end of file diff --git a/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/expected/en-us.untranslated.json b/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/expected/en-us.untranslated.json new file mode 100644 index 000000000..0637a088a --- /dev/null +++ b/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/expected/en-us.untranslated.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/expected/fr-fr.all.json b/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/expected/fr-fr.all.json new file mode 100644 index 000000000..20e0b8736 --- /dev/null +++ b/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/expected/fr-fr.all.json @@ -0,0 +1,45 @@ +[ + { + "id": "d_days", + "translation": { + "one": "", + "other": "" + } + }, + { + "id": "my_height_in_meters", + "translation": { + "one": "", + "other": "" + } + }, + { + "id": "person_greeting", + "translation": "" + }, + { + "id": "person_unread_email_count", + "translation": { + "one": "", + "other": "" + } + }, + { + "id": "person_unread_email_count_timeframe", + "translation": { + "one": "", + "other": "" + } + }, + { + "id": "program_greeting", + "translation": "" + }, + { + "id": "your_unread_email_count", + "translation": { + "one": "", + "other": "" + } + } +] \ No newline at end of file diff --git a/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/expected/fr-fr.untranslated.json b/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/expected/fr-fr.untranslated.json new file mode 100644 index 000000000..e2d3967c5 --- /dev/null +++ b/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/expected/fr-fr.untranslated.json @@ -0,0 +1,45 @@ +[ + { + "id": "d_days", + "translation": { + "one": "{{.Count}} days", + "other": "{{.Count}} days" + } + }, + { + "id": "my_height_in_meters", + "translation": { + "one": "I am {{.Count}} meters tall.", + "other": "I am {{.Count}} meters tall." + } + }, + { + "id": "person_greeting", + "translation": "Hello {{.Person}}" + }, + { + "id": "person_unread_email_count", + "translation": { + "one": "{{.Person}} has {{.Count}} unread emails.", + "other": "{{.Person}} has {{.Count}} unread emails." + } + }, + { + "id": "person_unread_email_count_timeframe", + "translation": { + "one": "{{.Person}} has {{.Count}} unread emails in the past {{.Timeframe}}.", + "other": "{{.Person}} has {{.Count}} unread emails in the past {{.Timeframe}}." + } + }, + { + "id": "program_greeting", + "translation": "Hello world" + }, + { + "id": "your_unread_email_count", + "translation": { + "one": "You have {{.Count}} unread emails.", + "other": "You have {{.Count}} unread emails." + } + } +] \ No newline at end of file diff --git a/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/input/ar-ar.one.json b/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/input/ar-ar.one.json new file mode 100644 index 000000000..f5af1d6f4 --- /dev/null +++ b/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/input/ar-ar.one.json @@ -0,0 +1,54 @@ +[ + { + "id": "d_days", + "translation": { + "few": "arabic few translation of d_days", + "many": "arabic many translation of d_days", + "one": "", + "other": "", + "two": "", + "zero": "" + } + }, + { + "id": "person_greeting", + "translation": "arabic translation of person_greeting" + }, + { + "id": "person_unread_email_count", + "translation": { + "few": "arabic few translation of person_unread_email_count", + "many": "arabic many translation of person_unread_email_count", + "one": "arabic one translation of person_unread_email_count", + "other": "", + "two": "", + "zero": "" + } + }, + { + "id": "person_unread_email_count_timeframe", + "translation": { + "few": "", + "many": "", + "one": "", + "other": "", + "two": "", + "zero": "" + } + }, + { + "id": "program_greeting", + "translation": "" + }, + { + "id": "your_unread_email_count", + "translation": { + "few": "", + "many": "", + "one": "", + "other": "", + "two": "", + "zero": "" + } + } +] diff --git a/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/input/ar-ar.two.json b/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/input/ar-ar.two.json new file mode 100644 index 000000000..e98d7e9b2 --- /dev/null +++ b/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/input/ar-ar.two.json @@ -0,0 +1,54 @@ +[ + { + "id": "d_days", + "translation": { + "few": "new arabic few translation of d_days", + "many": "", + "one": "arabic one translation of d_days", + "other": "", + "two": "", + "zero": "" + } + }, + { + "id": "person_greeting", + "translation": "new arabic translation of person_greeting" + }, + { + "id": "person_unread_email_count", + "translation": { + "few": "", + "many": "", + "one": "", + "other": "arabic other translation of person_unread_email_count", + "two": "arabic two translation of person_unread_email_count", + "zero": "arabic zero translation of person_unread_email_count" + } + }, + { + "id": "person_unread_email_count_timeframe", + "translation": { + "few": "", + "many": "", + "one": "", + "other": "", + "two": "", + "zero": "" + } + }, + { + "id": "program_greeting", + "translation": "" + }, + { + "id": "your_unread_email_count", + "translation": { + "few": "", + "many": "", + "one": "", + "other": "", + "two": "", + "zero": "" + } + } +] diff --git a/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/input/en-us.one.json b/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/input/en-us.one.json new file mode 100644 index 000000000..63a9d6ffb --- /dev/null +++ b/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/input/en-us.one.json @@ -0,0 +1,30 @@ +[ + { + "id": "program_greeting", + "translation": "Hello world" + }, + { + "id": "your_unread_email_count", + "translation": { + "one": "You have {{.Count}} unread email.", + "other": "You have {{.Count}} unread emails." + } + }, + { + "id": "my_height_in_meters", + "translation": { + "one": "I am {{.Count}} meter tall.", + "other": "I am {{.Count}} meters tall." + } + }, + { + "id": "person_unread_email_count_timeframe", + "translation": { + "one": "{{.Person}} has {{.Count}} unread email in the past {{.Timeframe}}." + } + }, + { + "id": "d_days", + "translation": "this should get overwritten" + } +] diff --git a/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/input/en-us.two.json b/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/input/en-us.two.json new file mode 100644 index 000000000..dcc715c43 --- /dev/null +++ b/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/input/en-us.two.json @@ -0,0 +1,26 @@ +[ + { + "id": "person_greeting", + "translation": "Hello {{.Person}}" + }, + { + "id": "person_unread_email_count", + "translation": { + "one": "{{.Person}} has {{.Count}} unread email.", + "other": "{{.Person}} has {{.Count}} unread emails." + } + }, + { + "id": "person_unread_email_count_timeframe", + "translation": { + "other": "{{.Person}} has {{.Count}} unread emails in the past {{.Timeframe}}." + } + }, + { + "id": "d_days", + "translation": { + "one": "{{.Count}} day", + "other": "{{.Count}} days" + } + } +] diff --git a/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/input/fr-fr.json b/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/input/fr-fr.json new file mode 100644 index 000000000..e69de29bb diff --git a/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/input/yaml/ar-ar.one.json b/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/input/yaml/ar-ar.one.json new file mode 100644 index 000000000..f5af1d6f4 --- /dev/null +++ b/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/input/yaml/ar-ar.one.json @@ -0,0 +1,54 @@ +[ + { + "id": "d_days", + "translation": { + "few": "arabic few translation of d_days", + "many": "arabic many translation of d_days", + "one": "", + "other": "", + "two": "", + "zero": "" + } + }, + { + "id": "person_greeting", + "translation": "arabic translation of person_greeting" + }, + { + "id": "person_unread_email_count", + "translation": { + "few": "arabic few translation of person_unread_email_count", + "many": "arabic many translation of person_unread_email_count", + "one": "arabic one translation of person_unread_email_count", + "other": "", + "two": "", + "zero": "" + } + }, + { + "id": "person_unread_email_count_timeframe", + "translation": { + "few": "", + "many": "", + "one": "", + "other": "", + "two": "", + "zero": "" + } + }, + { + "id": "program_greeting", + "translation": "" + }, + { + "id": "your_unread_email_count", + "translation": { + "few": "", + "many": "", + "one": "", + "other": "", + "two": "", + "zero": "" + } + } +] diff --git a/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/input/yaml/ar-ar.two.json b/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/input/yaml/ar-ar.two.json new file mode 100644 index 000000000..e98d7e9b2 --- /dev/null +++ b/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/input/yaml/ar-ar.two.json @@ -0,0 +1,54 @@ +[ + { + "id": "d_days", + "translation": { + "few": "new arabic few translation of d_days", + "many": "", + "one": "arabic one translation of d_days", + "other": "", + "two": "", + "zero": "" + } + }, + { + "id": "person_greeting", + "translation": "new arabic translation of person_greeting" + }, + { + "id": "person_unread_email_count", + "translation": { + "few": "", + "many": "", + "one": "", + "other": "arabic other translation of person_unread_email_count", + "two": "arabic two translation of person_unread_email_count", + "zero": "arabic zero translation of person_unread_email_count" + } + }, + { + "id": "person_unread_email_count_timeframe", + "translation": { + "few": "", + "many": "", + "one": "", + "other": "", + "two": "", + "zero": "" + } + }, + { + "id": "program_greeting", + "translation": "" + }, + { + "id": "your_unread_email_count", + "translation": { + "few": "", + "many": "", + "one": "", + "other": "", + "two": "", + "zero": "" + } + } +] diff --git a/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/input/yaml/en-us.one.yaml b/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/input/yaml/en-us.one.yaml new file mode 100644 index 000000000..3ca8e380d --- /dev/null +++ b/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/input/yaml/en-us.one.yaml @@ -0,0 +1,19 @@ +- id: program_greeting + translation: Hello world + +- id: your_unread_email_count + translation: + one: You have {{.Count}} unread email. + other: You have {{.Count}} unread emails. + +- id: my_height_in_meters + translation: + one: I am {{.Count}} meter tall. + other: I am {{.Count}} meters tall. + +- id: person_unread_email_count_timeframe + translation: + one: "{{.Person}} has {{.Count}} unread email in the past {{.Timeframe}}." + +- id: d_days + translation: this should get overwritten \ No newline at end of file diff --git a/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/input/yaml/en-us.two.json b/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/input/yaml/en-us.two.json new file mode 100644 index 000000000..dcc715c43 --- /dev/null +++ b/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/input/yaml/en-us.two.json @@ -0,0 +1,26 @@ +[ + { + "id": "person_greeting", + "translation": "Hello {{.Person}}" + }, + { + "id": "person_unread_email_count", + "translation": { + "one": "{{.Person}} has {{.Count}} unread email.", + "other": "{{.Person}} has {{.Count}} unread emails." + } + }, + { + "id": "person_unread_email_count_timeframe", + "translation": { + "other": "{{.Person}} has {{.Count}} unread emails in the past {{.Timeframe}}." + } + }, + { + "id": "d_days", + "translation": { + "one": "{{.Count}} day", + "other": "{{.Count}} days" + } + } +] diff --git a/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/input/yaml/fr-fr.json b/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/input/yaml/fr-fr.json new file mode 100644 index 000000000..e69de29bb diff --git a/vendor/github.com/nicksnyder/go-i18n/i18n/bundle/bundle_test.go b/vendor/github.com/nicksnyder/go-i18n/i18n/bundle/bundle_test.go new file mode 100644 index 000000000..b9c0a0593 --- /dev/null +++ b/vendor/github.com/nicksnyder/go-i18n/i18n/bundle/bundle_test.go @@ -0,0 +1,289 @@ +package bundle + +import ( + "fmt" + "testing" + + "reflect" + "sort" + + "github.com/nicksnyder/go-i18n/i18n/language" + "github.com/nicksnyder/go-i18n/i18n/translation" +) + +func TestMustLoadTranslationFile(t *testing.T) { + t.Skipf("not implemented") +} + +func TestLoadTranslationFile(t *testing.T) { + t.Skipf("not implemented") +} + +func TestParseTranslationFileBytes(t *testing.T) { + t.Skipf("not implemented") +} + +func TestAddTranslation(t *testing.T) { + t.Skipf("not implemented") +} + +func TestMustTfunc(t *testing.T) { + defer func() { + if r := recover(); r == nil { + t.Errorf("expected MustTfunc to panic") + } + }() + New().MustTfunc("invalid") +} + +func TestLanguageTagsAndTranslationIDs(t *testing.T) { + b := New() + translationID := "translation_id" + englishLanguage := languageWithTag("en-US") + frenchLanguage := languageWithTag("fr-FR") + spanishLanguage := languageWithTag("es") + addFakeTranslation(t, b, englishLanguage, "English"+translationID) + addFakeTranslation(t, b, frenchLanguage, translationID) + addFakeTranslation(t, b, spanishLanguage, translationID) + + tags := b.LanguageTags() + sort.Strings(tags) + compareTo := []string{englishLanguage.Tag, spanishLanguage.Tag, frenchLanguage.Tag} + if !reflect.DeepEqual(tags, compareTo) { + t.Errorf("LanguageTags() = %#v; expected: %#v", tags, compareTo) + } + + ids := b.LanguageTranslationIDs(englishLanguage.Tag) + sort.Strings(ids) + compareTo = []string{"English" + translationID} + if !reflect.DeepEqual(ids, compareTo) { + t.Errorf("LanguageTranslationIDs() = %#v; expected: %#v", ids, compareTo) + } +} + +func TestTfuncAndLanguage(t *testing.T) { + b := New() + translationID := "translation_id" + englishLanguage := languageWithTag("en-US") + frenchLanguage := languageWithTag("fr-FR") + spanishLanguage := languageWithTag("es") + chineseLanguage := languageWithTag("zh-hans-cn") + englishTranslation := addFakeTranslation(t, b, englishLanguage, translationID) + frenchTranslation := addFakeTranslation(t, b, frenchLanguage, translationID) + spanishTranslation := addFakeTranslation(t, b, spanishLanguage, translationID) + chineseTranslation := addFakeTranslation(t, b, chineseLanguage, translationID) + + tests := []struct { + languageIDs []string + result string + expectedLanguage *language.Language + }{ + { + []string{"invalid"}, + translationID, + nil, + }, + { + []string{"invalid", "invalid2"}, + translationID, + nil, + }, + { + []string{"invalid", "en-US"}, + englishTranslation, + englishLanguage, + }, + { + []string{"en-US", "invalid"}, + englishTranslation, + englishLanguage, + }, + { + []string{"en-US", "fr-FR"}, + englishTranslation, + englishLanguage, + }, + { + []string{"invalid", "es"}, + spanishTranslation, + spanishLanguage, + }, + { + []string{"zh-CN,fr-XX,es"}, + spanishTranslation, + spanishLanguage, + }, + { + []string{"fr"}, + frenchTranslation, + + // The language is still "fr" even though the translation is provided by "fr-FR" + languageWithTag("fr"), + }, + { + []string{"zh"}, + chineseTranslation, + + // The language is still "zh" even though the translation is provided by "zh-hans-cn" + languageWithTag("zh"), + }, + { + []string{"zh-hans"}, + chineseTranslation, + + // The language is still "zh-hans" even though the translation is provided by "zh-hans-cn" + languageWithTag("zh-hans"), + }, + { + []string{"zh-hans-cn"}, + chineseTranslation, + languageWithTag("zh-hans-cn"), + }, + } + + for i, test := range tests { + tf, lang, err := b.TfuncAndLanguage(test.languageIDs[0], test.languageIDs[1:]...) + if err != nil && test.expectedLanguage != nil { + t.Errorf("Tfunc(%v) = error{%q}; expected no error", test.languageIDs, err) + } + if err == nil && test.expectedLanguage == nil { + t.Errorf("Tfunc(%v) = nil error; expected error", test.languageIDs) + } + if result := tf(translationID); result != test.result { + t.Errorf("translation %d was %s; expected %s", i, result, test.result) + } + if (lang == nil && test.expectedLanguage != nil) || + (lang != nil && test.expectedLanguage == nil) || + (lang != nil && test.expectedLanguage != nil && lang.String() != test.expectedLanguage.String()) { + t.Errorf("lang %d was %s; expected %s", i, lang, test.expectedLanguage) + } + } +} + +func addFakeTranslation(t *testing.T, b *Bundle, lang *language.Language, translationID string) string { + translation := fakeTranslation(lang, translationID) + b.AddTranslation(lang, testNewTranslation(t, map[string]interface{}{ + "id": translationID, + "translation": translation, + })) + return translation +} + +func fakeTranslation(lang *language.Language, translationID string) string { + return fmt.Sprintf("%s(%s)", lang.Tag, translationID) +} + +func testNewTranslation(t *testing.T, data map[string]interface{}) translation.Translation { + translation, err := translation.NewTranslation(data) + if err != nil { + t.Fatal(err) + } + return translation +} + +func languageWithTag(tag string) *language.Language { + return language.MustParse(tag)[0] +} + +func createBenchmarkTranslateFunc(b *testing.B, translationTemplate interface{}, count interface{}, expected string) func(data interface{}) { + bundle := New() + lang := "en-US" + translationID := "translation_id" + translation, err := translation.NewTranslation(map[string]interface{}{ + "id": translationID, + "translation": translationTemplate, + }) + if err != nil { + b.Fatal(err) + } + bundle.AddTranslation(languageWithTag(lang), translation) + tf, err := bundle.Tfunc(lang) + if err != nil { + b.Fatal(err) + } + return func(data interface{}) { + var result string + if count == nil { + result = tf(translationID, data) + } else { + result = tf(translationID, count, data) + } + if result != expected { + b.Fatalf("expected %q, got %q", expected, result) + } + } +} + +func createBenchmarkPluralTranslateFunc(b *testing.B) func(data interface{}) { + translationTemplate := map[string]interface{}{ + "one": "{{.Person}} is {{.Count}} year old.", + "other": "{{.Person}} is {{.Count}} years old.", + } + count := 26 + expected := "Bob is 26 years old." + return createBenchmarkTranslateFunc(b, translationTemplate, count, expected) +} + +func createBenchmarkNonPluralTranslateFunc(b *testing.B) func(data interface{}) { + translationTemplate := "Hi {{.Person}}!" + expected := "Hi Bob!" + return createBenchmarkTranslateFunc(b, translationTemplate, nil, expected) +} + +func BenchmarkTranslateNonPluralWithMap(b *testing.B) { + data := map[string]interface{}{ + "Person": "Bob", + } + tf := createBenchmarkNonPluralTranslateFunc(b) + b.ResetTimer() + for i := 0; i < b.N; i++ { + tf(data) + } +} + +func BenchmarkTranslateNonPluralWithStruct(b *testing.B) { + data := struct{ Person string }{Person: "Bob"} + tf := createBenchmarkNonPluralTranslateFunc(b) + b.ResetTimer() + for i := 0; i < b.N; i++ { + tf(data) + } +} + +func BenchmarkTranslateNonPluralWithStructPointer(b *testing.B) { + data := &struct{ Person string }{Person: "Bob"} + tf := createBenchmarkNonPluralTranslateFunc(b) + b.ResetTimer() + for i := 0; i < b.N; i++ { + tf(data) + } +} + +func BenchmarkTranslatePluralWithMap(b *testing.B) { + data := map[string]interface{}{ + "Person": "Bob", + } + tf := createBenchmarkPluralTranslateFunc(b) + b.ResetTimer() + for i := 0; i < b.N; i++ { + tf(data) + } +} + +func BenchmarkTranslatePluralWithStruct(b *testing.B) { + data := struct{ Person string }{Person: "Bob"} + tf := createBenchmarkPluralTranslateFunc(b) + b.ResetTimer() + for i := 0; i < b.N; i++ { + tf(data) + } +} + +func BenchmarkTranslatePluralWithStructPointer(b *testing.B) { + data := &struct{ Person string }{Person: "Bob"} + tf := createBenchmarkPluralTranslateFunc(b) + b.ResetTimer() + for i := 0; i < b.N; i++ { + tf(data) + } +} diff --git a/vendor/github.com/nicksnyder/go-i18n/i18n/example_test.go b/vendor/github.com/nicksnyder/go-i18n/i18n/example_test.go new file mode 100644 index 000000000..d2d9706a7 --- /dev/null +++ b/vendor/github.com/nicksnyder/go-i18n/i18n/example_test.go @@ -0,0 +1,63 @@ +package i18n_test + +import ( + "fmt" + + "github.com/nicksnyder/go-i18n/i18n" +) + +func Example() { + i18n.MustLoadTranslationFile("../goi18n/testdata/expected/en-us.all.json") + + T, _ := i18n.Tfunc("en-US") + + bobMap := map[string]interface{}{"Person": "Bob"} + bobStruct := struct{ Person string }{Person: "Bob"} + + fmt.Println(T("program_greeting")) + fmt.Println(T("person_greeting", bobMap)) + fmt.Println(T("person_greeting", bobStruct)) + + fmt.Println(T("your_unread_email_count", 0)) + fmt.Println(T("your_unread_email_count", 1)) + fmt.Println(T("your_unread_email_count", 2)) + fmt.Println(T("my_height_in_meters", "1.7")) + + fmt.Println(T("person_unread_email_count", 0, bobMap)) + fmt.Println(T("person_unread_email_count", 1, bobMap)) + fmt.Println(T("person_unread_email_count", 2, bobMap)) + fmt.Println(T("person_unread_email_count", 0, bobStruct)) + fmt.Println(T("person_unread_email_count", 1, bobStruct)) + fmt.Println(T("person_unread_email_count", 2, bobStruct)) + + fmt.Println(T("person_unread_email_count_timeframe", 3, map[string]interface{}{ + "Person": "Bob", + "Timeframe": T("d_days", 0), + })) + fmt.Println(T("person_unread_email_count_timeframe", 3, map[string]interface{}{ + "Person": "Bob", + "Timeframe": T("d_days", 1), + })) + fmt.Println(T("person_unread_email_count_timeframe", 3, map[string]interface{}{ + "Person": "Bob", + "Timeframe": T("d_days", 2), + })) + + // Output: + // Hello world + // Hello Bob + // Hello Bob + // You have 0 unread emails. + // You have 1 unread email. + // You have 2 unread emails. + // I am 1.7 meters tall. + // Bob has 0 unread emails. + // Bob has 1 unread email. + // Bob has 2 unread emails. + // Bob has 0 unread emails. + // Bob has 1 unread email. + // Bob has 2 unread emails. + // Bob has 3 unread emails in the past 0 days. + // Bob has 3 unread emails in the past 1 day. + // Bob has 3 unread emails in the past 2 days. +} diff --git a/vendor/github.com/nicksnyder/go-i18n/i18n/exampletemplate_test.go b/vendor/github.com/nicksnyder/go-i18n/i18n/exampletemplate_test.go new file mode 100644 index 000000000..962936610 --- /dev/null +++ b/vendor/github.com/nicksnyder/go-i18n/i18n/exampletemplate_test.go @@ -0,0 +1,63 @@ +package i18n_test + +import ( + "github.com/nicksnyder/go-i18n/i18n" + "os" + "text/template" +) + +var funcMap = map[string]interface{}{ + "T": i18n.IdentityTfunc, +} + +var tmpl = template.Must(template.New("").Funcs(funcMap).Parse(` +{{T "program_greeting"}} +{{T "person_greeting" .}} +{{T "your_unread_email_count" 0}} +{{T "your_unread_email_count" 1}} +{{T "your_unread_email_count" 2}} +{{T "person_unread_email_count" 0 .}} +{{T "person_unread_email_count" 1 .}} +{{T "person_unread_email_count" 2 .}} +`)) + +func Example_template() { + i18n.MustLoadTranslationFile("../goi18n/testdata/expected/en-us.all.json") + + T, _ := i18n.Tfunc("en-US") + tmpl.Funcs(map[string]interface{}{ + "T": T, + }) + + tmpl.Execute(os.Stdout, map[string]interface{}{ + "Person": "Bob", + "Timeframe": T("d_days", 1), + }) + + tmpl.Execute(os.Stdout, struct { + Person string + Timeframe string + }{ + Person: "Bob", + Timeframe: T("d_days", 1), + }) + + // Output: + // Hello world + // Hello Bob + // You have 0 unread emails. + // You have 1 unread email. + // You have 2 unread emails. + // Bob has 0 unread emails. + // Bob has 1 unread email. + // Bob has 2 unread emails. + // + // Hello world + // Hello Bob + // You have 0 unread emails. + // You have 1 unread email. + // You have 2 unread emails. + // Bob has 0 unread emails. + // Bob has 1 unread email. + // Bob has 2 unread emails. +} diff --git a/vendor/github.com/nicksnyder/go-i18n/i18n/exampleyaml_test.go b/vendor/github.com/nicksnyder/go-i18n/i18n/exampleyaml_test.go new file mode 100644 index 000000000..b2e7bdcfe --- /dev/null +++ b/vendor/github.com/nicksnyder/go-i18n/i18n/exampleyaml_test.go @@ -0,0 +1,62 @@ +package i18n_test + +import ( + "fmt" + "github.com/nicksnyder/go-i18n/i18n" +) + +func ExampleYAML() { + i18n.MustLoadTranslationFile("../goi18n/testdata/en-us.yaml") + + T, _ := i18n.Tfunc("en-US") + + bobMap := map[string]interface{}{"Person": "Bob"} + bobStruct := struct{ Person string }{Person: "Bob"} + + fmt.Println(T("program_greeting")) + fmt.Println(T("person_greeting", bobMap)) + fmt.Println(T("person_greeting", bobStruct)) + + fmt.Println(T("your_unread_email_count", 0)) + fmt.Println(T("your_unread_email_count", 1)) + fmt.Println(T("your_unread_email_count", 2)) + fmt.Println(T("my_height_in_meters", "1.7")) + + fmt.Println(T("person_unread_email_count", 0, bobMap)) + fmt.Println(T("person_unread_email_count", 1, bobMap)) + fmt.Println(T("person_unread_email_count", 2, bobMap)) + fmt.Println(T("person_unread_email_count", 0, bobStruct)) + fmt.Println(T("person_unread_email_count", 1, bobStruct)) + fmt.Println(T("person_unread_email_count", 2, bobStruct)) + + fmt.Println(T("person_unread_email_count_timeframe", 3, map[string]interface{}{ + "Person": "Bob", + "Timeframe": T("d_days", 0), + })) + fmt.Println(T("person_unread_email_count_timeframe", 3, map[string]interface{}{ + "Person": "Bob", + "Timeframe": T("d_days", 1), + })) + fmt.Println(T("person_unread_email_count_timeframe", 3, map[string]interface{}{ + "Person": "Bob", + "Timeframe": T("d_days", 2), + })) + + // Output: + // Hello world + // Hello Bob + // Hello Bob + // You have 0 unread emails. + // You have 1 unread email. + // You have 2 unread emails. + // I am 1.7 meters tall. + // Bob has 0 unread emails. + // Bob has 1 unread email. + // Bob has 2 unread emails. + // Bob has 0 unread emails. + // Bob has 1 unread email. + // Bob has 2 unread emails. + // Bob has 3 unread emails in the past 0 days. + // Bob has 3 unread emails in the past 1 day. + // Bob has 3 unread emails in the past 2 days. +} diff --git a/vendor/github.com/nicksnyder/go-i18n/i18n/language/codegen/generate.sh b/vendor/github.com/nicksnyder/go-i18n/i18n/language/codegen/generate.sh new file mode 100644 index 000000000..a9fae846a --- /dev/null +++ b/vendor/github.com/nicksnyder/go-i18n/i18n/language/codegen/generate.sh @@ -0,0 +1,5 @@ +#!/bin/sh +go build && ./codegen -cout ../pluralspec_gen.go -tout ../pluralspec_gen_test.go && \ + gofmt -w=true ../pluralspec_gen.go && \ + gofmt -w=true ../pluralspec_gen_test.go && \ + rm codegen 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 000000000..5d6b6ad4f --- /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/plurals.xml b/vendor/github.com/nicksnyder/go-i18n/i18n/language/codegen/plurals.xml new file mode 100644 index 000000000..cdd0b5296 --- /dev/null +++ b/vendor/github.com/nicksnyder/go-i18n/i18n/language/codegen/plurals.xml @@ -0,0 +1,230 @@ + + + + + + + + + + + + @integer 0~15, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … + + + + + + i = 0 or n = 1 @integer 0, 1 @decimal 0.0~1.0, 0.00~0.04 + @integer 2~17, 100, 1000, 10000, 100000, 1000000, … @decimal 1.1~2.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … + + + i = 0,1 @integer 0, 1 @decimal 0.0~1.5 + @integer 2~17, 100, 1000, 10000, 100000, 1000000, … @decimal 2.0~3.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … + + + i = 1 and v = 0 @integer 1 + @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … + + + n = 0,1 or i = 0 and f = 1 @integer 0, 1 @decimal 0.0, 0.1, 1.0, 0.00, 0.01, 1.00, 0.000, 0.001, 1.000, 0.0000, 0.0001, 1.0000 + @integer 2~17, 100, 1000, 10000, 100000, 1000000, … @decimal 0.2~0.9, 1.1~1.8, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … + + + n = 0..1 @integer 0, 1 @decimal 0.0, 1.0, 0.00, 1.00, 0.000, 1.000, 0.0000, 1.0000 + @integer 2~17, 100, 1000, 10000, 100000, 1000000, … @decimal 0.1~0.9, 1.1~1.7, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … + + + n = 0..1 or n = 11..99 @integer 0, 1, 11~24 @decimal 0.0, 1.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0, 24.0 + @integer 2~10, 100~106, 1000, 10000, 100000, 1000000, … @decimal 0.1~0.9, 1.1~1.7, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … + + + n = 0..2 and n != 2 @integer 0, 1 @decimal 0.0, 1.0, 0.00, 1.00, 0.000, 1.000, 0.0000, 1.0000 + @integer 2~17, 100, 1000, 10000, 100000, 1000000, … @decimal 0.1~0.9, 1.1~1.7, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … + + + n = 1 @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 + @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … + + + n = 1 and v = 0 @integer 1 + @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … + + + n = 1 or t != 0 and i = 0,1 @integer 1 @decimal 0.1~1.6 + @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0, 2.0~3.4, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … + + + t = 0 and i % 10 = 1 and i % 100 != 11 or t != 0 @integer 1, 21, 31, 41, 51, 61, 71, 81, 101, 1001, … @decimal 0.1~1.6, 10.1, 100.1, 1000.1, … + @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … + + + v = 0 and i % 10 = 1 or f % 10 = 1 @integer 1, 11, 21, 31, 41, 51, 61, 71, 101, 1001, … @decimal 0.1, 1.1, 2.1, 3.1, 4.1, 5.1, 6.1, 7.1, 10.1, 100.1, 1000.1, … + @integer 0, 2~10, 12~17, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0, 0.2~1.0, 1.2~1.7, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … + + + v = 0 and i = 1,2,3 or v = 0 and i % 10 != 4,6,9 or v != 0 and f % 10 != 4,6,9 @integer 0~3, 5, 7, 8, 10~13, 15, 17, 18, 20, 21, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.3, 0.5, 0.7, 0.8, 1.0~1.3, 1.5, 1.7, 1.8, 2.0, 2.1, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … + @integer 4, 6, 9, 14, 16, 19, 24, 26, 104, 1004, … @decimal 0.4, 0.6, 0.9, 1.4, 1.6, 1.9, 2.4, 2.6, 10.4, 100.4, 1000.4, … + + + + + + n % 10 = 0 or n % 100 = 11..19 or v = 2 and f % 100 = 11..19 @integer 0, 10~20, 30, 40, 50, 60, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … + n % 10 = 1 and n % 100 != 11 or v = 2 and f % 10 = 1 and f % 100 != 11 or v != 2 and f % 10 = 1 @integer 1, 21, 31, 41, 51, 61, 71, 81, 101, 1001, … @decimal 0.1, 1.0, 1.1, 2.1, 3.1, 4.1, 5.1, 6.1, 7.1, 10.1, 100.1, 1000.1, … + @integer 2~9, 22~29, 102, 1002, … @decimal 0.2~0.9, 1.2~1.9, 10.2, 100.2, 1000.2, … + + + n = 0 @integer 0 @decimal 0.0, 0.00, 0.000, 0.0000 + i = 0,1 and n != 0 @integer 1 @decimal 0.1~1.6 + @integer 2~17, 100, 1000, 10000, 100000, 1000000, … @decimal 2.0~3.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … + + + n = 0 @integer 0 @decimal 0.0, 0.00, 0.000, 0.0000 + n = 1 @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 + @integer 2~17, 100, 1000, 10000, 100000, 1000000, … @decimal 0.1~0.9, 1.1~1.7, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … + + + + + + n = 1 @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 + n = 2 @integer 2 @decimal 2.0, 2.00, 2.000, 2.0000 + @integer 0, 3~17, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … + + + + + + i = 0 or n = 1 @integer 0, 1 @decimal 0.0~1.0, 0.00~0.04 + n = 2..10 @integer 2~10 @decimal 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 2.00, 3.00, 4.00, 5.00, 6.00, 7.00, 8.00 + @integer 11~26, 100, 1000, 10000, 100000, 1000000, … @decimal 1.1~1.9, 2.1~2.7, 10.1, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … + + + i = 1 and v = 0 @integer 1 + v != 0 or n = 0 or n != 1 and n % 100 = 1..19 @integer 0, 2~16, 101, 1001, … @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … + @integer 20~35, 100, 1000, 10000, 100000, 1000000, … + + + v = 0 and i % 10 = 1 and i % 100 != 11 or f % 10 = 1 and f % 100 != 11 @integer 1, 21, 31, 41, 51, 61, 71, 81, 101, 1001, … @decimal 0.1, 1.1, 2.1, 3.1, 4.1, 5.1, 6.1, 7.1, 10.1, 100.1, 1000.1, … + v = 0 and i % 10 = 2..4 and i % 100 != 12..14 or f % 10 = 2..4 and f % 100 != 12..14 @integer 2~4, 22~24, 32~34, 42~44, 52~54, 62, 102, 1002, … @decimal 0.2~0.4, 1.2~1.4, 2.2~2.4, 3.2~3.4, 4.2~4.4, 5.2, 10.2, 100.2, 1000.2, … + @integer 0, 5~19, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0, 0.5~1.0, 1.5~2.0, 2.5~2.7, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … + + + + + + n = 1,11 @integer 1, 11 @decimal 1.0, 11.0, 1.00, 11.00, 1.000, 11.000, 1.0000 + n = 2,12 @integer 2, 12 @decimal 2.0, 12.0, 2.00, 12.00, 2.000, 12.000, 2.0000 + n = 3..10,13..19 @integer 3~10, 13~19 @decimal 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 3.00 + @integer 0, 20~34, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.1, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … + + + v = 0 and i % 100 = 1 @integer 1, 101, 201, 301, 401, 501, 601, 701, 1001, … + v = 0 and i % 100 = 2 @integer 2, 102, 202, 302, 402, 502, 602, 702, 1002, … + v = 0 and i % 100 = 3..4 or v != 0 @integer 3, 4, 103, 104, 203, 204, 303, 304, 403, 404, 503, 504, 603, 604, 703, 704, 1003, … @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … + @integer 0, 5~19, 100, 1000, 10000, 100000, 1000000, … + + + v = 0 and i % 100 = 1 or f % 100 = 1 @integer 1, 101, 201, 301, 401, 501, 601, 701, 1001, … @decimal 0.1, 1.1, 2.1, 3.1, 4.1, 5.1, 6.1, 7.1, 10.1, 100.1, 1000.1, … + v = 0 and i % 100 = 2 or f % 100 = 2 @integer 2, 102, 202, 302, 402, 502, 602, 702, 1002, … @decimal 0.2, 1.2, 2.2, 3.2, 4.2, 5.2, 6.2, 7.2, 10.2, 100.2, 1000.2, … + v = 0 and i % 100 = 3..4 or f % 100 = 3..4 @integer 3, 4, 103, 104, 203, 204, 303, 304, 403, 404, 503, 504, 603, 604, 703, 704, 1003, … @decimal 0.3, 0.4, 1.3, 1.4, 2.3, 2.4, 3.3, 3.4, 4.3, 4.4, 5.3, 5.4, 6.3, 6.4, 7.3, 7.4, 10.3, 100.3, 1000.3, … + @integer 0, 5~19, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0, 0.5~1.0, 1.5~2.0, 2.5~2.7, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … + + + + + + i = 1 and v = 0 @integer 1 + i = 2 and v = 0 @integer 2 + v = 0 and n != 0..10 and n % 10 = 0 @integer 20, 30, 40, 50, 60, 70, 80, 90, 100, 1000, 10000, 100000, 1000000, … + @integer 0, 3~17, 101, 1001, … @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … + + + + + + i = 1 and v = 0 @integer 1 + i = 2..4 and v = 0 @integer 2~4 + v != 0 @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … + @integer 0, 5~19, 100, 1000, 10000, 100000, 1000000, … + + + i = 1 and v = 0 @integer 1 + v = 0 and i % 10 = 2..4 and i % 100 != 12..14 @integer 2~4, 22~24, 32~34, 42~44, 52~54, 62, 102, 1002, … + v = 0 and i != 1 and i % 10 = 0..1 or v = 0 and i % 10 = 5..9 or v = 0 and i % 100 = 12..14 @integer 0, 5~19, 100, 1000, 10000, 100000, 1000000, … + @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … + + + n % 10 = 1 and n % 100 != 11 @integer 1, 21, 31, 41, 51, 61, 71, 81, 101, 1001, … @decimal 1.0, 21.0, 31.0, 41.0, 51.0, 61.0, 71.0, 81.0, 101.0, 1001.0, … + n % 10 = 2..4 and n % 100 != 12..14 @integer 2~4, 22~24, 32~34, 42~44, 52~54, 62, 102, 1002, … @decimal 2.0, 3.0, 4.0, 22.0, 23.0, 24.0, 32.0, 33.0, 102.0, 1002.0, … + n % 10 = 0 or n % 10 = 5..9 or n % 100 = 11..14 @integer 0, 5~19, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … + @decimal 0.1~0.9, 1.1~1.7, 10.1, 100.1, 1000.1, … + + + n % 10 = 1 and n % 100 != 11..19 @integer 1, 21, 31, 41, 51, 61, 71, 81, 101, 1001, … @decimal 1.0, 21.0, 31.0, 41.0, 51.0, 61.0, 71.0, 81.0, 101.0, 1001.0, … + n % 10 = 2..9 and n % 100 != 11..19 @integer 2~9, 22~29, 102, 1002, … @decimal 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 22.0, 102.0, 1002.0, … + f != 0 @decimal 0.1~0.9, 1.1~1.7, 10.1, 100.1, 1000.1, … + @integer 0, 10~20, 30, 40, 50, 60, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … + + + n = 1 @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 + n = 0 or n % 100 = 2..10 @integer 0, 2~10, 102~107, 1002, … @decimal 0.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 10.0, 102.0, 1002.0, … + n % 100 = 11..19 @integer 11~19, 111~117, 1011, … @decimal 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 111.0, 1011.0, … + @integer 20~35, 100, 1000, 10000, 100000, 1000000, … @decimal 0.1~0.9, 1.1~1.7, 10.1, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … + + + v = 0 and i % 10 = 1 and i % 100 != 11 @integer 1, 21, 31, 41, 51, 61, 71, 81, 101, 1001, … + v = 0 and i % 10 = 2..4 and i % 100 != 12..14 @integer 2~4, 22~24, 32~34, 42~44, 52~54, 62, 102, 1002, … + v = 0 and i % 10 = 0 or v = 0 and i % 10 = 5..9 or v = 0 and i % 100 = 11..14 @integer 0, 5~19, 100, 1000, 10000, 100000, 1000000, … + @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … + + + + + + n % 10 = 1 and n % 100 != 11,71,91 @integer 1, 21, 31, 41, 51, 61, 81, 101, 1001, … @decimal 1.0, 21.0, 31.0, 41.0, 51.0, 61.0, 81.0, 101.0, 1001.0, … + n % 10 = 2 and n % 100 != 12,72,92 @integer 2, 22, 32, 42, 52, 62, 82, 102, 1002, … @decimal 2.0, 22.0, 32.0, 42.0, 52.0, 62.0, 82.0, 102.0, 1002.0, … + n % 10 = 3..4,9 and n % 100 != 10..19,70..79,90..99 @integer 3, 4, 9, 23, 24, 29, 33, 34, 39, 43, 44, 49, 103, 1003, … @decimal 3.0, 4.0, 9.0, 23.0, 24.0, 29.0, 33.0, 34.0, 103.0, 1003.0, … + n != 0 and n % 1000000 = 0 @integer 1000000, … @decimal 1000000.0, 1000000.00, 1000000.000, … + @integer 0, 5~8, 10~20, 100, 1000, 10000, 100000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, … + + + n = 1 @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 + n = 2 @integer 2 @decimal 2.0, 2.00, 2.000, 2.0000 + n = 3..6 @integer 3~6 @decimal 3.0, 4.0, 5.0, 6.0, 3.00, 4.00, 5.00, 6.00, 3.000, 4.000, 5.000, 6.000, 3.0000, 4.0000, 5.0000, 6.0000 + n = 7..10 @integer 7~10 @decimal 7.0, 8.0, 9.0, 10.0, 7.00, 8.00, 9.00, 10.00, 7.000, 8.000, 9.000, 10.000, 7.0000, 8.0000, 9.0000, 10.0000 + @integer 0, 11~25, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.1, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … + + + v = 0 and i % 10 = 1 @integer 1, 11, 21, 31, 41, 51, 61, 71, 101, 1001, … + v = 0 and i % 10 = 2 @integer 2, 12, 22, 32, 42, 52, 62, 72, 102, 1002, … + v = 0 and i % 100 = 0,20,40,60,80 @integer 0, 20, 40, 60, 80, 100, 120, 140, 1000, 10000, 100000, 1000000, … + v != 0 @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … + @integer 3~10, 13~19, 23, 103, 1003, … + + + + + + n = 0 @integer 0 @decimal 0.0, 0.00, 0.000, 0.0000 + n = 1 @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 + n = 2 @integer 2 @decimal 2.0, 2.00, 2.000, 2.0000 + n % 100 = 3..10 @integer 3~10, 103~110, 1003, … @decimal 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 103.0, 1003.0, … + n % 100 = 11..99 @integer 11~26, 111, 1011, … @decimal 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 111.0, 1011.0, … + @integer 100~102, 200~202, 300~302, 400~402, 500~502, 600, 1000, 10000, 100000, 1000000, … @decimal 0.1~0.9, 1.1~1.7, 10.1, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … + + + n = 0 @integer 0 @decimal 0.0, 0.00, 0.000, 0.0000 + n = 1 @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 + n = 2 @integer 2 @decimal 2.0, 2.00, 2.000, 2.0000 + n = 3 @integer 3 @decimal 3.0, 3.00, 3.000, 3.0000 + n = 6 @integer 6 @decimal 6.0, 6.00, 6.000, 6.0000 + @integer 4, 5, 7~20, 100, 1000, 10000, 100000, 1000000, … @decimal 0.1~0.9, 1.1~1.7, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … + + + 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 000000000..9d39053c2 --- /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") +} diff --git a/vendor/github.com/nicksnyder/go-i18n/i18n/language/language_test.go b/vendor/github.com/nicksnyder/go-i18n/i18n/language/language_test.go new file mode 100644 index 000000000..2949bfe4a --- /dev/null +++ b/vendor/github.com/nicksnyder/go-i18n/i18n/language/language_test.go @@ -0,0 +1,85 @@ +package language + +import ( + "reflect" + "testing" +) + +func TestParse(t *testing.T) { + tests := []struct { + src string + lang []*Language + }{ + {"en", []*Language{{"en", pluralSpecs["en"]}}}, + {"en-US", []*Language{{"en-us", pluralSpecs["en"]}}}, + {"en_US", []*Language{{"en-us", pluralSpecs["en"]}}}, + {"en-GB", []*Language{{"en-gb", pluralSpecs["en"]}}}, + {"zh-CN", []*Language{{"zh-cn", pluralSpecs["zh"]}}}, + {"zh-TW", []*Language{{"zh-tw", pluralSpecs["zh"]}}}, + {"pt-BR", []*Language{{"pt-br", pluralSpecs["pt"]}}}, + {"pt_BR", []*Language{{"pt-br", pluralSpecs["pt"]}}}, + {"pt-PT", []*Language{{"pt-pt", pluralSpecs["pt-pt"]}}}, + {"pt_PT", []*Language{{"pt-pt", pluralSpecs["pt-pt"]}}}, + {"zh-Hans-CN", []*Language{{"zh-hans-cn", pluralSpecs["zh"]}}}, + {"zh-Hant-TW", []*Language{{"zh-hant-tw", pluralSpecs["zh"]}}}, + {"en-US-en-US", []*Language{{"en-us-en-us", pluralSpecs["en"]}}}, + {".en-US..en-US.", []*Language{{"en-us", pluralSpecs["en"]}}}, + { + "it, xx-zz, xx-ZZ, zh, en-gb;q=0.8, en;q=0.7, es-ES;q=0.6, de-xx", + []*Language{ + {"it", pluralSpecs["it"]}, + {"zh", pluralSpecs["zh"]}, + {"en-gb", pluralSpecs["en"]}, + {"en", pluralSpecs["en"]}, + {"es-es", pluralSpecs["es"]}, + {"de-xx", pluralSpecs["de"]}, + }, + }, + { + "it-qq,xx,xx-zz,xx-ZZ,zh,en-gb;q=0.8,en;q=0.7,es-ES;q=0.6,de-xx", + []*Language{ + {"it-qq", pluralSpecs["it"]}, + {"zh", pluralSpecs["zh"]}, + {"en-gb", pluralSpecs["en"]}, + {"en", pluralSpecs["en"]}, + {"es-es", pluralSpecs["es"]}, + {"de-xx", pluralSpecs["de"]}, + }, + }, + {"en.json", []*Language{{"en", pluralSpecs["en"]}}}, + {"en-US.json", []*Language{{"en-us", pluralSpecs["en"]}}}, + {"en-us.json", []*Language{{"en-us", pluralSpecs["en"]}}}, + {"en-xx.json", []*Language{{"en-xx", pluralSpecs["en"]}}}, + {"xx-Yyen-US", nil}, + {"en US", nil}, + {"", nil}, + {"-", nil}, + {"_", nil}, + {"-en", nil}, + {"_en", nil}, + {"-en-", nil}, + {"_en_", nil}, + {"xx", nil}, + } + for _, test := range tests { + lang := Parse(test.src) + if !reflect.DeepEqual(lang, test.lang) { + t.Errorf("Parse(%q) = %s expected %s", test.src, lang, test.lang) + } + } +} + +func TestMatchingTags(t *testing.T) { + tests := []struct { + lang *Language + matches []string + }{ + {&Language{"zh-hans-cn", nil}, []string{"zh", "zh-hans", "zh-hans-cn"}}, + {&Language{"foo", nil}, []string{"foo"}}, + } + for _, test := range tests { + if actual := test.lang.MatchingTags(); !reflect.DeepEqual(test.matches, actual) { + t.Errorf("matchingTags(%q) = %q expected %q", test.lang.Tag, actual, test.matches) + } + } +} diff --git a/vendor/github.com/nicksnyder/go-i18n/i18n/language/operands_test.go b/vendor/github.com/nicksnyder/go-i18n/i18n/language/operands_test.go new file mode 100644 index 000000000..29030876a --- /dev/null +++ b/vendor/github.com/nicksnyder/go-i18n/i18n/language/operands_test.go @@ -0,0 +1,45 @@ +package language + +import ( + "reflect" + "testing" +) + +func TestNewOperands(t *testing.T) { + tests := []struct { + input interface{} + ops *operands + err bool + }{ + {int64(0), &operands{0.0, 0, 0, 0, 0, 0}, false}, + {int64(1), &operands{1.0, 1, 0, 0, 0, 0}, false}, + {"0", &operands{0.0, 0, 0, 0, 0, 0}, false}, + {"1", &operands{1.0, 1, 0, 0, 0, 0}, false}, + {"1.0", &operands{1.0, 1, 1, 0, 0, 0}, false}, + {"1.00", &operands{1.0, 1, 2, 0, 0, 0}, false}, + {"1.3", &operands{1.3, 1, 1, 1, 3, 3}, false}, + {"1.30", &operands{1.3, 1, 2, 1, 30, 3}, false}, + {"1.03", &operands{1.03, 1, 2, 2, 3, 3}, false}, + {"1.230", &operands{1.23, 1, 3, 2, 230, 23}, false}, + {"20.0230", &operands{20.023, 20, 4, 3, 230, 23}, false}, + {20.0230, nil, true}, + } + for _, test := range tests { + ops, err := newOperands(test.input) + if err != nil && !test.err { + t.Errorf("newOperands(%#v) unexpected error: %s", test.input, err) + } else if err == nil && test.err { + t.Errorf("newOperands(%#v) returned %#v; expected error", test.input, ops) + } else if !reflect.DeepEqual(ops, test.ops) { + t.Errorf("newOperands(%#v) returned %#v; expected %#v", test.input, ops, test.ops) + } + } +} + +func BenchmarkNewOperand(b *testing.B) { + for i := 0; i < b.N; i++ { + if _, err := newOperands("1234.56780000"); err != nil { + b.Fatal(err) + } + } +} diff --git a/vendor/github.com/nicksnyder/go-i18n/i18n/language/plural_test.go b/vendor/github.com/nicksnyder/go-i18n/i18n/language/plural_test.go new file mode 100644 index 000000000..6336d29b2 --- /dev/null +++ b/vendor/github.com/nicksnyder/go-i18n/i18n/language/plural_test.go @@ -0,0 +1,28 @@ +package language + +import ( + "testing" +) + +func TestNewPlural(t *testing.T) { + tests := []struct { + src string + plural Plural + err bool + }{ + {"zero", Zero, false}, + {"one", One, false}, + {"two", Two, false}, + {"few", Few, false}, + {"many", Many, false}, + {"other", Other, false}, + {"asdf", Invalid, true}, + } + for _, test := range tests { + plural, err := NewPlural(test.src) + wrongErr := (err != nil && !test.err) || (err == nil && test.err) + if plural != test.plural || wrongErr { + t.Errorf("NewPlural(%#v) returned %#v,%#v; expected %#v", test.src, plural, err, test.plural) + } + } +} diff --git a/vendor/github.com/nicksnyder/go-i18n/i18n/language/pluralspec_gen_test.go b/vendor/github.com/nicksnyder/go-i18n/i18n/language/pluralspec_gen_test.go new file mode 100644 index 000000000..c8ec41fd4 --- /dev/null +++ b/vendor/github.com/nicksnyder/go-i18n/i18n/language/pluralspec_gen_test.go @@ -0,0 +1,645 @@ +package language + +// This file is generated by i18n/language/codegen/generate.sh + +import "testing" + +func TestBmBoDzIdIgIiInJaJboJvJwKdeKeaKmKoLktLoMsMyNqoRootSahSesSgThToViWoYoZh(t *testing.T) { + var tests []pluralTest + + tests = appendIntegerTests(tests, Other, []string{"0~15", "100", "1000", "10000", "100000", "1000000"}) + tests = appendDecimalTests(tests, Other, []string{"0.0~1.5", "10.0", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"}) + + locales := []string{"bm", "bo", "dz", "id", "ig", "ii", "in", "ja", "jbo", "jv", "jw", "kde", "kea", "km", "ko", "lkt", "lo", "ms", "my", "nqo", "root", "sah", "ses", "sg", "th", "to", "vi", "wo", "yo", "zh"} + for _, locale := range locales { + runTests(t, locale, tests) + } +} + +func TestAmAsBnFaGuHiKnMrZu(t *testing.T) { + var tests []pluralTest + + tests = appendIntegerTests(tests, One, []string{"0", "1"}) + tests = appendDecimalTests(tests, One, []string{"0.0~1.0", "0.00~0.04"}) + + tests = appendIntegerTests(tests, Other, []string{"2~17", "100", "1000", "10000", "100000", "1000000"}) + tests = appendDecimalTests(tests, Other, []string{"1.1~2.6", "10.0", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"}) + + locales := []string{"am", "as", "bn", "fa", "gu", "hi", "kn", "mr", "zu"} + for _, locale := range locales { + runTests(t, locale, tests) + } +} + +func TestFfFrHyKab(t *testing.T) { + var tests []pluralTest + + tests = appendIntegerTests(tests, One, []string{"0", "1"}) + tests = appendDecimalTests(tests, One, []string{"0.0~1.5"}) + + tests = appendIntegerTests(tests, Other, []string{"2~17", "100", "1000", "10000", "100000", "1000000"}) + tests = appendDecimalTests(tests, Other, []string{"2.0~3.5", "10.0", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"}) + + locales := []string{"ff", "fr", "hy", "kab"} + for _, locale := range locales { + runTests(t, locale, tests) + } +} + +func TestAstCaDeEnEtFiFyGlItJiNlSvSwUrYi(t *testing.T) { + var tests []pluralTest + + tests = appendIntegerTests(tests, One, []string{"1"}) + + tests = appendIntegerTests(tests, Other, []string{"0", "2~16", "100", "1000", "10000", "100000", "1000000"}) + tests = appendDecimalTests(tests, Other, []string{"0.0~1.5", "10.0", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"}) + + locales := []string{"ast", "ca", "de", "en", "et", "fi", "fy", "gl", "it", "ji", "nl", "sv", "sw", "ur", "yi"} + for _, locale := range locales { + runTests(t, locale, tests) + } +} + +func TestSi(t *testing.T) { + var tests []pluralTest + + tests = appendIntegerTests(tests, One, []string{"0", "1"}) + tests = appendDecimalTests(tests, One, []string{"0.0", "0.1", "1.0", "0.00", "0.01", "1.00", "0.000", "0.001", "1.000", "0.0000", "0.0001", "1.0000"}) + + tests = appendIntegerTests(tests, Other, []string{"2~17", "100", "1000", "10000", "100000", "1000000"}) + tests = appendDecimalTests(tests, Other, []string{"0.2~0.9", "1.1~1.8", "10.0", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"}) + + locales := []string{"si"} + for _, locale := range locales { + runTests(t, locale, tests) + } +} + +func TestAkBhGuwLnMgNsoPaTiWa(t *testing.T) { + var tests []pluralTest + + tests = appendIntegerTests(tests, One, []string{"0", "1"}) + tests = appendDecimalTests(tests, One, []string{"0.0", "1.0", "0.00", "1.00", "0.000", "1.000", "0.0000", "1.0000"}) + + tests = appendIntegerTests(tests, Other, []string{"2~17", "100", "1000", "10000", "100000", "1000000"}) + tests = appendDecimalTests(tests, Other, []string{"0.1~0.9", "1.1~1.7", "10.0", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"}) + + locales := []string{"ak", "bh", "guw", "ln", "mg", "nso", "pa", "ti", "wa"} + for _, locale := range locales { + runTests(t, locale, tests) + } +} + +func TestTzm(t *testing.T) { + var tests []pluralTest + + tests = appendIntegerTests(tests, One, []string{"0", "1", "11~24"}) + tests = appendDecimalTests(tests, One, []string{"0.0", "1.0", "11.0", "12.0", "13.0", "14.0", "15.0", "16.0", "17.0", "18.0", "19.0", "20.0", "21.0", "22.0", "23.0", "24.0"}) + + tests = appendIntegerTests(tests, Other, []string{"2~10", "100~106", "1000", "10000", "100000", "1000000"}) + tests = appendDecimalTests(tests, Other, []string{"0.1~0.9", "1.1~1.7", "10.0", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"}) + + locales := []string{"tzm"} + for _, locale := range locales { + runTests(t, locale, tests) + } +} + +func TestPt(t *testing.T) { + var tests []pluralTest + + tests = appendIntegerTests(tests, One, []string{"0", "1"}) + tests = appendDecimalTests(tests, One, []string{"0.0", "1.0", "0.00", "1.00", "0.000", "1.000", "0.0000", "1.0000"}) + + tests = appendIntegerTests(tests, Other, []string{"2~17", "100", "1000", "10000", "100000", "1000000"}) + tests = appendDecimalTests(tests, Other, []string{"0.1~0.9", "1.1~1.7", "10.0", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"}) + + locales := []string{"pt"} + for _, locale := range locales { + runTests(t, locale, tests) + } +} + +func TestAfAsaAzBemBezBgBrxCeCggChrCkbDvEeElEoEsEuFoFurGswHaHawHuJgoJmcKaKajKcgKkKkjKlKsKsbKuKyLbLgMasMgoMlMnNahNbNdNeNnNnhNoNrNyNynOmOrOsPapPsRmRofRwkSaqSdhSehSnSoSqSsSsyStSyrTaTeTeoTigTkTnTrTsUgUzVeVoVunWaeXhXog(t *testing.T) { + var tests []pluralTest + + tests = appendIntegerTests(tests, One, []string{"1"}) + tests = appendDecimalTests(tests, One, []string{"1.0", "1.00", "1.000", "1.0000"}) + + tests = appendIntegerTests(tests, Other, []string{"0", "2~16", "100", "1000", "10000", "100000", "1000000"}) + tests = appendDecimalTests(tests, Other, []string{"0.0~0.9", "1.1~1.6", "10.0", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"}) + + locales := []string{"af", "asa", "az", "bem", "bez", "bg", "brx", "ce", "cgg", "chr", "ckb", "dv", "ee", "el", "eo", "es", "eu", "fo", "fur", "gsw", "ha", "haw", "hu", "jgo", "jmc", "ka", "kaj", "kcg", "kk", "kkj", "kl", "ks", "ksb", "ku", "ky", "lb", "lg", "mas", "mgo", "ml", "mn", "nah", "nb", "nd", "ne", "nn", "nnh", "no", "nr", "ny", "nyn", "om", "or", "os", "pap", "ps", "rm", "rof", "rwk", "saq", "sdh", "seh", "sn", "so", "sq", "ss", "ssy", "st", "syr", "ta", "te", "teo", "tig", "tk", "tn", "tr", "ts", "ug", "uz", "ve", "vo", "vun", "wae", "xh", "xog"} + for _, locale := range locales { + runTests(t, locale, tests) + } +} + +func TestPt_PT(t *testing.T) { + var tests []pluralTest + + tests = appendIntegerTests(tests, One, []string{"1"}) + + tests = appendIntegerTests(tests, Other, []string{"0", "2~16", "100", "1000", "10000", "100000", "1000000"}) + tests = appendDecimalTests(tests, Other, []string{"0.0~1.5", "10.0", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"}) + + locales := []string{"pt_PT"} + for _, locale := range locales { + runTests(t, locale, tests) + } +} + +func TestDa(t *testing.T) { + var tests []pluralTest + + tests = appendIntegerTests(tests, One, []string{"1"}) + tests = appendDecimalTests(tests, One, []string{"0.1~1.6"}) + + tests = appendIntegerTests(tests, Other, []string{"0", "2~16", "100", "1000", "10000", "100000", "1000000"}) + tests = appendDecimalTests(tests, Other, []string{"0.0", "2.0~3.4", "10.0", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"}) + + locales := []string{"da"} + for _, locale := range locales { + runTests(t, locale, tests) + } +} + +func TestIs(t *testing.T) { + var tests []pluralTest + + tests = appendIntegerTests(tests, One, []string{"1", "21", "31", "41", "51", "61", "71", "81", "101", "1001"}) + tests = appendDecimalTests(tests, One, []string{"0.1~1.6", "10.1", "100.1", "1000.1"}) + + tests = appendIntegerTests(tests, Other, []string{"0", "2~16", "100", "1000", "10000", "100000", "1000000"}) + tests = appendDecimalTests(tests, Other, []string{"0.0", "2.0", "3.0", "4.0", "5.0", "6.0", "7.0", "8.0", "10.0", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"}) + + locales := []string{"is"} + for _, locale := range locales { + runTests(t, locale, tests) + } +} + +func TestMk(t *testing.T) { + var tests []pluralTest + + tests = appendIntegerTests(tests, One, []string{"1", "11", "21", "31", "41", "51", "61", "71", "101", "1001"}) + tests = appendDecimalTests(tests, One, []string{"0.1", "1.1", "2.1", "3.1", "4.1", "5.1", "6.1", "7.1", "10.1", "100.1", "1000.1"}) + + tests = appendIntegerTests(tests, Other, []string{"0", "2~10", "12~17", "100", "1000", "10000", "100000", "1000000"}) + tests = appendDecimalTests(tests, Other, []string{"0.0", "0.2~1.0", "1.2~1.7", "10.0", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"}) + + locales := []string{"mk"} + for _, locale := range locales { + runTests(t, locale, tests) + } +} + +func TestFilTl(t *testing.T) { + var tests []pluralTest + + tests = appendIntegerTests(tests, One, []string{"0~3", "5", "7", "8", "10~13", "15", "17", "18", "20", "21", "100", "1000", "10000", "100000", "1000000"}) + tests = appendDecimalTests(tests, One, []string{"0.0~0.3", "0.5", "0.7", "0.8", "1.0~1.3", "1.5", "1.7", "1.8", "2.0", "2.1", "10.0", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"}) + + tests = appendIntegerTests(tests, Other, []string{"4", "6", "9", "14", "16", "19", "24", "26", "104", "1004"}) + tests = appendDecimalTests(tests, Other, []string{"0.4", "0.6", "0.9", "1.4", "1.6", "1.9", "2.4", "2.6", "10.4", "100.4", "1000.4"}) + + locales := []string{"fil", "tl"} + for _, locale := range locales { + runTests(t, locale, tests) + } +} + +func TestLvPrg(t *testing.T) { + var tests []pluralTest + + tests = appendIntegerTests(tests, Zero, []string{"0", "10~20", "30", "40", "50", "60", "100", "1000", "10000", "100000", "1000000"}) + tests = appendDecimalTests(tests, Zero, []string{"0.0", "10.0", "11.0", "12.0", "13.0", "14.0", "15.0", "16.0", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"}) + + tests = appendIntegerTests(tests, One, []string{"1", "21", "31", "41", "51", "61", "71", "81", "101", "1001"}) + tests = appendDecimalTests(tests, One, []string{"0.1", "1.0", "1.1", "2.1", "3.1", "4.1", "5.1", "6.1", "7.1", "10.1", "100.1", "1000.1"}) + + tests = appendIntegerTests(tests, Other, []string{"2~9", "22~29", "102", "1002"}) + tests = appendDecimalTests(tests, Other, []string{"0.2~0.9", "1.2~1.9", "10.2", "100.2", "1000.2"}) + + locales := []string{"lv", "prg"} + for _, locale := range locales { + runTests(t, locale, tests) + } +} + +func TestLag(t *testing.T) { + var tests []pluralTest + + tests = appendIntegerTests(tests, Zero, []string{"0"}) + tests = appendDecimalTests(tests, Zero, []string{"0.0", "0.00", "0.000", "0.0000"}) + + tests = appendIntegerTests(tests, One, []string{"1"}) + tests = appendDecimalTests(tests, One, []string{"0.1~1.6"}) + + tests = appendIntegerTests(tests, Other, []string{"2~17", "100", "1000", "10000", "100000", "1000000"}) + tests = appendDecimalTests(tests, Other, []string{"2.0~3.5", "10.0", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"}) + + locales := []string{"lag"} + for _, locale := range locales { + runTests(t, locale, tests) + } +} + +func TestKsh(t *testing.T) { + var tests []pluralTest + + tests = appendIntegerTests(tests, Zero, []string{"0"}) + tests = appendDecimalTests(tests, Zero, []string{"0.0", "0.00", "0.000", "0.0000"}) + + tests = appendIntegerTests(tests, One, []string{"1"}) + tests = appendDecimalTests(tests, One, []string{"1.0", "1.00", "1.000", "1.0000"}) + + tests = appendIntegerTests(tests, Other, []string{"2~17", "100", "1000", "10000", "100000", "1000000"}) + tests = appendDecimalTests(tests, Other, []string{"0.1~0.9", "1.1~1.7", "10.0", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"}) + + locales := []string{"ksh"} + for _, locale := range locales { + runTests(t, locale, tests) + } +} + +func TestIuKwNaqSeSmaSmiSmjSmnSms(t *testing.T) { + var tests []pluralTest + + tests = appendIntegerTests(tests, One, []string{"1"}) + tests = appendDecimalTests(tests, One, []string{"1.0", "1.00", "1.000", "1.0000"}) + + tests = appendIntegerTests(tests, Two, []string{"2"}) + tests = appendDecimalTests(tests, Two, []string{"2.0", "2.00", "2.000", "2.0000"}) + + tests = appendIntegerTests(tests, Other, []string{"0", "3~17", "100", "1000", "10000", "100000", "1000000"}) + tests = appendDecimalTests(tests, Other, []string{"0.0~0.9", "1.1~1.6", "10.0", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"}) + + locales := []string{"iu", "kw", "naq", "se", "sma", "smi", "smj", "smn", "sms"} + for _, locale := range locales { + runTests(t, locale, tests) + } +} + +func TestShi(t *testing.T) { + var tests []pluralTest + + tests = appendIntegerTests(tests, One, []string{"0", "1"}) + tests = appendDecimalTests(tests, One, []string{"0.0~1.0", "0.00~0.04"}) + + tests = appendIntegerTests(tests, Few, []string{"2~10"}) + tests = appendDecimalTests(tests, Few, []string{"2.0", "3.0", "4.0", "5.0", "6.0", "7.0", "8.0", "9.0", "10.0", "2.00", "3.00", "4.00", "5.00", "6.00", "7.00", "8.00"}) + + tests = appendIntegerTests(tests, Other, []string{"11~26", "100", "1000", "10000", "100000", "1000000"}) + tests = appendDecimalTests(tests, Other, []string{"1.1~1.9", "2.1~2.7", "10.1", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"}) + + locales := []string{"shi"} + for _, locale := range locales { + runTests(t, locale, tests) + } +} + +func TestMoRo(t *testing.T) { + var tests []pluralTest + + tests = appendIntegerTests(tests, One, []string{"1"}) + + tests = appendIntegerTests(tests, Few, []string{"0", "2~16", "101", "1001"}) + tests = appendDecimalTests(tests, Few, []string{"0.0~1.5", "10.0", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"}) + + tests = appendIntegerTests(tests, Other, []string{"20~35", "100", "1000", "10000", "100000", "1000000"}) + + locales := []string{"mo", "ro"} + for _, locale := range locales { + runTests(t, locale, tests) + } +} + +func TestBsHrShSr(t *testing.T) { + var tests []pluralTest + + tests = appendIntegerTests(tests, One, []string{"1", "21", "31", "41", "51", "61", "71", "81", "101", "1001"}) + tests = appendDecimalTests(tests, One, []string{"0.1", "1.1", "2.1", "3.1", "4.1", "5.1", "6.1", "7.1", "10.1", "100.1", "1000.1"}) + + tests = appendIntegerTests(tests, Few, []string{"2~4", "22~24", "32~34", "42~44", "52~54", "62", "102", "1002"}) + tests = appendDecimalTests(tests, Few, []string{"0.2~0.4", "1.2~1.4", "2.2~2.4", "3.2~3.4", "4.2~4.4", "5.2", "10.2", "100.2", "1000.2"}) + + tests = appendIntegerTests(tests, Other, []string{"0", "5~19", "100", "1000", "10000", "100000", "1000000"}) + tests = appendDecimalTests(tests, Other, []string{"0.0", "0.5~1.0", "1.5~2.0", "2.5~2.7", "10.0", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"}) + + locales := []string{"bs", "hr", "sh", "sr"} + for _, locale := range locales { + runTests(t, locale, tests) + } +} + +func TestGd(t *testing.T) { + var tests []pluralTest + + tests = appendIntegerTests(tests, One, []string{"1", "11"}) + tests = appendDecimalTests(tests, One, []string{"1.0", "11.0", "1.00", "11.00", "1.000", "11.000", "1.0000"}) + + tests = appendIntegerTests(tests, Two, []string{"2", "12"}) + tests = appendDecimalTests(tests, Two, []string{"2.0", "12.0", "2.00", "12.00", "2.000", "12.000", "2.0000"}) + + tests = appendIntegerTests(tests, Few, []string{"3~10", "13~19"}) + tests = appendDecimalTests(tests, Few, []string{"3.0", "4.0", "5.0", "6.0", "7.0", "8.0", "9.0", "10.0", "13.0", "14.0", "15.0", "16.0", "17.0", "18.0", "19.0", "3.00"}) + + tests = appendIntegerTests(tests, Other, []string{"0", "20~34", "100", "1000", "10000", "100000", "1000000"}) + tests = appendDecimalTests(tests, Other, []string{"0.0~0.9", "1.1~1.6", "10.1", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"}) + + locales := []string{"gd"} + for _, locale := range locales { + runTests(t, locale, tests) + } +} + +func TestSl(t *testing.T) { + var tests []pluralTest + + tests = appendIntegerTests(tests, One, []string{"1", "101", "201", "301", "401", "501", "601", "701", "1001"}) + + tests = appendIntegerTests(tests, Two, []string{"2", "102", "202", "302", "402", "502", "602", "702", "1002"}) + + tests = appendIntegerTests(tests, Few, []string{"3", "4", "103", "104", "203", "204", "303", "304", "403", "404", "503", "504", "603", "604", "703", "704", "1003"}) + tests = appendDecimalTests(tests, Few, []string{"0.0~1.5", "10.0", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"}) + + tests = appendIntegerTests(tests, Other, []string{"0", "5~19", "100", "1000", "10000", "100000", "1000000"}) + + locales := []string{"sl"} + for _, locale := range locales { + runTests(t, locale, tests) + } +} + +func TestDsbHsb(t *testing.T) { + var tests []pluralTest + + tests = appendIntegerTests(tests, One, []string{"1", "101", "201", "301", "401", "501", "601", "701", "1001"}) + tests = appendDecimalTests(tests, One, []string{"0.1", "1.1", "2.1", "3.1", "4.1", "5.1", "6.1", "7.1", "10.1", "100.1", "1000.1"}) + + tests = appendIntegerTests(tests, Two, []string{"2", "102", "202", "302", "402", "502", "602", "702", "1002"}) + tests = appendDecimalTests(tests, Two, []string{"0.2", "1.2", "2.2", "3.2", "4.2", "5.2", "6.2", "7.2", "10.2", "100.2", "1000.2"}) + + tests = appendIntegerTests(tests, Few, []string{"3", "4", "103", "104", "203", "204", "303", "304", "403", "404", "503", "504", "603", "604", "703", "704", "1003"}) + tests = appendDecimalTests(tests, Few, []string{"0.3", "0.4", "1.3", "1.4", "2.3", "2.4", "3.3", "3.4", "4.3", "4.4", "5.3", "5.4", "6.3", "6.4", "7.3", "7.4", "10.3", "100.3", "1000.3"}) + + tests = appendIntegerTests(tests, Other, []string{"0", "5~19", "100", "1000", "10000", "100000", "1000000"}) + tests = appendDecimalTests(tests, Other, []string{"0.0", "0.5~1.0", "1.5~2.0", "2.5~2.7", "10.0", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"}) + + locales := []string{"dsb", "hsb"} + for _, locale := range locales { + runTests(t, locale, tests) + } +} + +func TestHeIw(t *testing.T) { + var tests []pluralTest + + tests = appendIntegerTests(tests, One, []string{"1"}) + + tests = appendIntegerTests(tests, Two, []string{"2"}) + + tests = appendIntegerTests(tests, Many, []string{"20", "30", "40", "50", "60", "70", "80", "90", "100", "1000", "10000", "100000", "1000000"}) + + tests = appendIntegerTests(tests, Other, []string{"0", "3~17", "101", "1001"}) + tests = appendDecimalTests(tests, Other, []string{"0.0~1.5", "10.0", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"}) + + locales := []string{"he", "iw"} + for _, locale := range locales { + runTests(t, locale, tests) + } +} + +func TestCsSk(t *testing.T) { + var tests []pluralTest + + tests = appendIntegerTests(tests, One, []string{"1"}) + + tests = appendIntegerTests(tests, Few, []string{"2~4"}) + + tests = appendDecimalTests(tests, Many, []string{"0.0~1.5", "10.0", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"}) + + tests = appendIntegerTests(tests, Other, []string{"0", "5~19", "100", "1000", "10000", "100000", "1000000"}) + + locales := []string{"cs", "sk"} + for _, locale := range locales { + runTests(t, locale, tests) + } +} + +func TestPl(t *testing.T) { + var tests []pluralTest + + tests = appendIntegerTests(tests, One, []string{"1"}) + + tests = appendIntegerTests(tests, Few, []string{"2~4", "22~24", "32~34", "42~44", "52~54", "62", "102", "1002"}) + + tests = appendIntegerTests(tests, Many, []string{"0", "5~19", "100", "1000", "10000", "100000", "1000000"}) + + tests = appendDecimalTests(tests, Other, []string{"0.0~1.5", "10.0", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"}) + + locales := []string{"pl"} + for _, locale := range locales { + runTests(t, locale, tests) + } +} + +func TestBe(t *testing.T) { + var tests []pluralTest + + tests = appendIntegerTests(tests, One, []string{"1", "21", "31", "41", "51", "61", "71", "81", "101", "1001"}) + tests = appendDecimalTests(tests, One, []string{"1.0", "21.0", "31.0", "41.0", "51.0", "61.0", "71.0", "81.0", "101.0", "1001.0"}) + + tests = appendIntegerTests(tests, Few, []string{"2~4", "22~24", "32~34", "42~44", "52~54", "62", "102", "1002"}) + tests = appendDecimalTests(tests, Few, []string{"2.0", "3.0", "4.0", "22.0", "23.0", "24.0", "32.0", "33.0", "102.0", "1002.0"}) + + tests = appendIntegerTests(tests, Many, []string{"0", "5~19", "100", "1000", "10000", "100000", "1000000"}) + tests = appendDecimalTests(tests, Many, []string{"0.0", "5.0", "6.0", "7.0", "8.0", "9.0", "10.0", "11.0", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"}) + + tests = appendDecimalTests(tests, Other, []string{"0.1~0.9", "1.1~1.7", "10.1", "100.1", "1000.1"}) + + locales := []string{"be"} + for _, locale := range locales { + runTests(t, locale, tests) + } +} + +func TestLt(t *testing.T) { + var tests []pluralTest + + tests = appendIntegerTests(tests, One, []string{"1", "21", "31", "41", "51", "61", "71", "81", "101", "1001"}) + tests = appendDecimalTests(tests, One, []string{"1.0", "21.0", "31.0", "41.0", "51.0", "61.0", "71.0", "81.0", "101.0", "1001.0"}) + + tests = appendIntegerTests(tests, Few, []string{"2~9", "22~29", "102", "1002"}) + tests = appendDecimalTests(tests, Few, []string{"2.0", "3.0", "4.0", "5.0", "6.0", "7.0", "8.0", "9.0", "22.0", "102.0", "1002.0"}) + + tests = appendDecimalTests(tests, Many, []string{"0.1~0.9", "1.1~1.7", "10.1", "100.1", "1000.1"}) + + tests = appendIntegerTests(tests, Other, []string{"0", "10~20", "30", "40", "50", "60", "100", "1000", "10000", "100000", "1000000"}) + tests = appendDecimalTests(tests, Other, []string{"0.0", "10.0", "11.0", "12.0", "13.0", "14.0", "15.0", "16.0", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"}) + + locales := []string{"lt"} + for _, locale := range locales { + runTests(t, locale, tests) + } +} + +func TestMt(t *testing.T) { + var tests []pluralTest + + tests = appendIntegerTests(tests, One, []string{"1"}) + tests = appendDecimalTests(tests, One, []string{"1.0", "1.00", "1.000", "1.0000"}) + + tests = appendIntegerTests(tests, Few, []string{"0", "2~10", "102~107", "1002"}) + tests = appendDecimalTests(tests, Few, []string{"0.0", "2.0", "3.0", "4.0", "5.0", "6.0", "7.0", "8.0", "10.0", "102.0", "1002.0"}) + + tests = appendIntegerTests(tests, Many, []string{"11~19", "111~117", "1011"}) + tests = appendDecimalTests(tests, Many, []string{"11.0", "12.0", "13.0", "14.0", "15.0", "16.0", "17.0", "18.0", "111.0", "1011.0"}) + + tests = appendIntegerTests(tests, Other, []string{"20~35", "100", "1000", "10000", "100000", "1000000"}) + tests = appendDecimalTests(tests, Other, []string{"0.1~0.9", "1.1~1.7", "10.1", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"}) + + locales := []string{"mt"} + for _, locale := range locales { + runTests(t, locale, tests) + } +} + +func TestRuUk(t *testing.T) { + var tests []pluralTest + + tests = appendIntegerTests(tests, One, []string{"1", "21", "31", "41", "51", "61", "71", "81", "101", "1001"}) + + tests = appendIntegerTests(tests, Few, []string{"2~4", "22~24", "32~34", "42~44", "52~54", "62", "102", "1002"}) + + tests = appendIntegerTests(tests, Many, []string{"0", "5~19", "100", "1000", "10000", "100000", "1000000"}) + + tests = appendDecimalTests(tests, Other, []string{"0.0~1.5", "10.0", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"}) + + locales := []string{"ru", "uk"} + for _, locale := range locales { + runTests(t, locale, tests) + } +} + +func TestBr(t *testing.T) { + var tests []pluralTest + + tests = appendIntegerTests(tests, One, []string{"1", "21", "31", "41", "51", "61", "81", "101", "1001"}) + tests = appendDecimalTests(tests, One, []string{"1.0", "21.0", "31.0", "41.0", "51.0", "61.0", "81.0", "101.0", "1001.0"}) + + tests = appendIntegerTests(tests, Two, []string{"2", "22", "32", "42", "52", "62", "82", "102", "1002"}) + tests = appendDecimalTests(tests, Two, []string{"2.0", "22.0", "32.0", "42.0", "52.0", "62.0", "82.0", "102.0", "1002.0"}) + + tests = appendIntegerTests(tests, Few, []string{"3", "4", "9", "23", "24", "29", "33", "34", "39", "43", "44", "49", "103", "1003"}) + tests = appendDecimalTests(tests, Few, []string{"3.0", "4.0", "9.0", "23.0", "24.0", "29.0", "33.0", "34.0", "103.0", "1003.0"}) + + tests = appendIntegerTests(tests, Many, []string{"1000000"}) + tests = appendDecimalTests(tests, Many, []string{"1000000.0", "1000000.00", "1000000.000"}) + + tests = appendIntegerTests(tests, Other, []string{"0", "5~8", "10~20", "100", "1000", "10000", "100000"}) + tests = appendDecimalTests(tests, Other, []string{"0.0~0.9", "1.1~1.6", "10.0", "100.0", "1000.0", "10000.0", "100000.0"}) + + locales := []string{"br"} + for _, locale := range locales { + runTests(t, locale, tests) + } +} + +func TestGa(t *testing.T) { + var tests []pluralTest + + tests = appendIntegerTests(tests, One, []string{"1"}) + tests = appendDecimalTests(tests, One, []string{"1.0", "1.00", "1.000", "1.0000"}) + + tests = appendIntegerTests(tests, Two, []string{"2"}) + tests = appendDecimalTests(tests, Two, []string{"2.0", "2.00", "2.000", "2.0000"}) + + tests = appendIntegerTests(tests, Few, []string{"3~6"}) + tests = appendDecimalTests(tests, Few, []string{"3.0", "4.0", "5.0", "6.0", "3.00", "4.00", "5.00", "6.00", "3.000", "4.000", "5.000", "6.000", "3.0000", "4.0000", "5.0000", "6.0000"}) + + tests = appendIntegerTests(tests, Many, []string{"7~10"}) + tests = appendDecimalTests(tests, Many, []string{"7.0", "8.0", "9.0", "10.0", "7.00", "8.00", "9.00", "10.00", "7.000", "8.000", "9.000", "10.000", "7.0000", "8.0000", "9.0000", "10.0000"}) + + tests = appendIntegerTests(tests, Other, []string{"0", "11~25", "100", "1000", "10000", "100000", "1000000"}) + tests = appendDecimalTests(tests, Other, []string{"0.0~0.9", "1.1~1.6", "10.1", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"}) + + locales := []string{"ga"} + for _, locale := range locales { + runTests(t, locale, tests) + } +} + +func TestGv(t *testing.T) { + var tests []pluralTest + + tests = appendIntegerTests(tests, One, []string{"1", "11", "21", "31", "41", "51", "61", "71", "101", "1001"}) + + tests = appendIntegerTests(tests, Two, []string{"2", "12", "22", "32", "42", "52", "62", "72", "102", "1002"}) + + tests = appendIntegerTests(tests, Few, []string{"0", "20", "40", "60", "80", "100", "120", "140", "1000", "10000", "100000", "1000000"}) + + tests = appendDecimalTests(tests, Many, []string{"0.0~1.5", "10.0", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"}) + + tests = appendIntegerTests(tests, Other, []string{"3~10", "13~19", "23", "103", "1003"}) + + locales := []string{"gv"} + for _, locale := range locales { + runTests(t, locale, tests) + } +} + +func TestAr(t *testing.T) { + var tests []pluralTest + + tests = appendIntegerTests(tests, Zero, []string{"0"}) + tests = appendDecimalTests(tests, Zero, []string{"0.0", "0.00", "0.000", "0.0000"}) + + tests = appendIntegerTests(tests, One, []string{"1"}) + tests = appendDecimalTests(tests, One, []string{"1.0", "1.00", "1.000", "1.0000"}) + + tests = appendIntegerTests(tests, Two, []string{"2"}) + tests = appendDecimalTests(tests, Two, []string{"2.0", "2.00", "2.000", "2.0000"}) + + tests = appendIntegerTests(tests, Few, []string{"3~10", "103~110", "1003"}) + tests = appendDecimalTests(tests, Few, []string{"3.0", "4.0", "5.0", "6.0", "7.0", "8.0", "9.0", "10.0", "103.0", "1003.0"}) + + tests = appendIntegerTests(tests, Many, []string{"11~26", "111", "1011"}) + tests = appendDecimalTests(tests, Many, []string{"11.0", "12.0", "13.0", "14.0", "15.0", "16.0", "17.0", "18.0", "111.0", "1011.0"}) + + tests = appendIntegerTests(tests, Other, []string{"100~102", "200~202", "300~302", "400~402", "500~502", "600", "1000", "10000", "100000", "1000000"}) + tests = appendDecimalTests(tests, Other, []string{"0.1~0.9", "1.1~1.7", "10.1", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"}) + + locales := []string{"ar"} + for _, locale := range locales { + runTests(t, locale, tests) + } +} + +func TestCy(t *testing.T) { + var tests []pluralTest + + tests = appendIntegerTests(tests, Zero, []string{"0"}) + tests = appendDecimalTests(tests, Zero, []string{"0.0", "0.00", "0.000", "0.0000"}) + + tests = appendIntegerTests(tests, One, []string{"1"}) + tests = appendDecimalTests(tests, One, []string{"1.0", "1.00", "1.000", "1.0000"}) + + tests = appendIntegerTests(tests, Two, []string{"2"}) + tests = appendDecimalTests(tests, Two, []string{"2.0", "2.00", "2.000", "2.0000"}) + + tests = appendIntegerTests(tests, Few, []string{"3"}) + tests = appendDecimalTests(tests, Few, []string{"3.0", "3.00", "3.000", "3.0000"}) + + tests = appendIntegerTests(tests, Many, []string{"6"}) + tests = appendDecimalTests(tests, Many, []string{"6.0", "6.00", "6.000", "6.0000"}) + + tests = appendIntegerTests(tests, Other, []string{"4", "5", "7~20", "100", "1000", "10000", "100000", "1000000"}) + tests = appendDecimalTests(tests, Other, []string{"0.1~0.9", "1.1~1.7", "10.0", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"}) + + locales := []string{"cy"} + for _, locale := range locales { + runTests(t, locale, tests) + } +} diff --git a/vendor/github.com/nicksnyder/go-i18n/i18n/language/pluralspec_test.go b/vendor/github.com/nicksnyder/go-i18n/i18n/language/pluralspec_test.go new file mode 100644 index 000000000..34931b7bb --- /dev/null +++ b/vendor/github.com/nicksnyder/go-i18n/i18n/language/pluralspec_test.go @@ -0,0 +1,733 @@ +package language + +import ( + "fmt" + "strconv" + "strings" + "testing" +) + +const onePlusEpsilon = "1.00000000000000000000000000000001" + +func TestGetPluralSpec(t *testing.T) { + tests := []struct { + src string + spec *PluralSpec + }{ + {"pl", pluralSpecs["pl"]}, + {"en", pluralSpecs["en"]}, + {"en-US", pluralSpecs["en"]}, + {"en_US", pluralSpecs["en"]}, + {"en-GB", pluralSpecs["en"]}, + {"zh-CN", pluralSpecs["zh"]}, + {"zh-TW", pluralSpecs["zh"]}, + {"pt-BR", pluralSpecs["pt"]}, + {"pt_BR", pluralSpecs["pt"]}, + {"pt-PT", pluralSpecs["pt-pt"]}, + {"pt_PT", pluralSpecs["pt-pt"]}, + {"zh-Hans-CN", pluralSpecs["zh"]}, + {"zh-Hant-TW", pluralSpecs["zh"]}, + {"zh-CN", pluralSpecs["zh"]}, + {"zh-TW", pluralSpecs["zh"]}, + {"zh-Hans", pluralSpecs["zh"]}, + {"zh-Hant", pluralSpecs["zh"]}, + {"ko-KR", pluralSpecs["ko"]}, + {"ko_KR", pluralSpecs["ko"]}, + {"ko-KP", pluralSpecs["ko"]}, + {"ko_KP", pluralSpecs["ko"]}, + {"en-US-en-US", pluralSpecs["en"]}, + {"th", pluralSpecs["th"]}, + {"th-TH", pluralSpecs["th"]}, + {"hr", pluralSpecs["hr"]}, + {"bs", pluralSpecs["bs"]}, + {"sr", pluralSpecs["sr"]}, + {"ti", pluralSpecs["ti"]}, + {"vi", pluralSpecs["vi"]}, + {"vi-VN", pluralSpecs["vi"]}, + {"mk", pluralSpecs["mk"]}, + {"mk-MK", pluralSpecs["mk"]}, + {"lv", pluralSpecs["lv"]}, + {"lv-LV", pluralSpecs["lv"]}, + {".en-US..en-US.", nil}, + {"zh, en-gb;q=0.8, en;q=0.7", nil}, + {"zh,en-gb;q=0.8,en;q=0.7", nil}, + {"xx, en-gb;q=0.8, en;q=0.7", nil}, + {"xx,en-gb;q=0.8,en;q=0.7", nil}, + {"xx-YY,xx;q=0.8,en-US,en;q=0.8,de;q=0.6,nl;q=0.4", nil}, + {"/foo/es/en.json", nil}, + {"xx-Yyen-US", nil}, + {"en US", nil}, + {"", nil}, + {"-", nil}, + {"_", nil}, + {".", nil}, + {"-en", nil}, + {"_en", nil}, + {"-en-", nil}, + {"_en_", nil}, + {"xx", nil}, + } + for _, test := range tests { + spec := getPluralSpec(test.src) + if spec != test.spec { + t.Errorf("getPluralSpec(%q) = %q expected %q", test.src, spec, test.spec) + } + } +} + +type pluralTest struct { + num interface{} + plural Plural +} + +func appendIntegerTests(tests []pluralTest, plural Plural, examples []string) []pluralTest { + for _, ex := range expandExamples(examples) { + i, err := strconv.ParseInt(ex, 10, 64) + if err != nil { + panic(err) + } + tests = append(tests, pluralTest{ex, plural}, pluralTest{i, plural}) + } + return tests +} + +func appendDecimalTests(tests []pluralTest, plural Plural, examples []string) []pluralTest { + for _, ex := range expandExamples(examples) { + tests = append(tests, pluralTest{ex, plural}) + } + return tests +} + +func expandExamples(examples []string) []string { + var expanded []string + for _, ex := range examples { + if parts := strings.Split(ex, "~"); len(parts) == 2 { + for ex := parts[0]; ; ex = increment(ex) { + expanded = append(expanded, ex) + if ex == parts[1] { + break + } + } + } else { + expanded = append(expanded, ex) + } + } + return expanded +} + +func increment(dec string) string { + runes := []rune(dec) + carry := true + for i := len(runes) - 1; carry && i >= 0; i-- { + switch runes[i] { + case '.': + continue + case '9': + runes[i] = '0' + default: + runes[i]++ + carry = false + } + } + if carry { + runes = append([]rune{'1'}, runes...) + } + return string(runes) +} + +// +// Below here are tests that were manually written before tests were automatically generated. +// These are kept around as sanity checks for our code generation. +// + +func TestArabic(t *testing.T) { + tests := []pluralTest{ + {0, Zero}, + {"0", Zero}, + {"0.0", Zero}, + {"0.00", Zero}, + {1, One}, + {"1", One}, + {"1.0", One}, + {"1.00", One}, + {onePlusEpsilon, Other}, + {2, Two}, + {"2", Two}, + {"2.0", Two}, + {"2.00", Two}, + {3, Few}, + {"3", Few}, + {"3.0", Few}, + {"3.00", Few}, + {10, Few}, + {"10", Few}, + {"10.0", Few}, + {"10.00", Few}, + {103, Few}, + {"103", Few}, + {"103.0", Few}, + {"103.00", Few}, + {110, Few}, + {"110", Few}, + {"110.0", Few}, + {"110.00", Few}, + {11, Many}, + {"11", Many}, + {"11.0", Many}, + {"11.00", Many}, + {99, Many}, + {"99", Many}, + {"99.0", Many}, + {"99.00", Many}, + {111, Many}, + {"111", Many}, + {"111.0", Many}, + {"111.00", Many}, + {199, Many}, + {"199", Many}, + {"199.0", Many}, + {"199.00", Many}, + {100, Other}, + {"100", Other}, + {"100.0", Other}, + {"100.00", Other}, + {102, Other}, + {"102", Other}, + {"102.0", Other}, + {"102.00", Other}, + {200, Other}, + {"200", Other}, + {"200.0", Other}, + {"200.00", Other}, + {202, Other}, + {"202", Other}, + {"202.0", Other}, + {"202.00", Other}, + } + tests = appendFloatTests(tests, 0.1, 0.9, Other) + tests = appendFloatTests(tests, 1.1, 1.9, Other) + tests = appendFloatTests(tests, 2.1, 2.9, Other) + tests = appendFloatTests(tests, 3.1, 3.9, Other) + tests = appendFloatTests(tests, 4.1, 4.9, Other) + runTests(t, "ar", tests) +} + +func TestBelarusian(t *testing.T) { + tests := []pluralTest{ + {0, Many}, + {1, One}, + {2, Few}, + {3, Few}, + {4, Few}, + {5, Many}, + {19, Many}, + {20, Many}, + {21, One}, + {11, Many}, + {52, Few}, + {101, One}, + {"0.1", Other}, + {"0.7", Other}, + {"1.5", Other}, + {"1.0", One}, + {onePlusEpsilon, Other}, + {"2.0", Few}, + {"10.0", Many}, + } + runTests(t, "be", tests) +} + +func TestBurmese(t *testing.T) { + tests := appendIntTests(nil, 0, 10, Other) + tests = appendFloatTests(tests, 0, 10, Other) + runTests(t, "my", tests) +} + +func TestCatalan(t *testing.T) { + tests := []pluralTest{ + {0, Other}, + {"0", Other}, + {1, One}, + {"1", One}, + {"1.0", Other}, + {onePlusEpsilon, Other}, + {2, Other}, + {"2", Other}, + } + tests = appendIntTests(tests, 2, 10, Other) + tests = appendFloatTests(tests, 0, 10, Other) + runTests(t, "ca", tests) +} + +func TestChinese(t *testing.T) { + tests := appendIntTests(nil, 0, 10, Other) + tests = appendFloatTests(tests, 0, 10, Other) + runTests(t, "zh", tests) +} + +func TestCzech(t *testing.T) { + tests := []pluralTest{ + {0, Other}, + {"0", Other}, + {1, One}, + {"1", One}, + {onePlusEpsilon, Many}, + {2, Few}, + {"2", Few}, + {3, Few}, + {"3", Few}, + {4, Few}, + {"4", Few}, + {5, Other}, + {"5", Other}, + } + tests = appendFloatTests(tests, 0, 10, Many) + runTests(t, "cs", tests) +} + +func TestDanish(t *testing.T) { + tests := []pluralTest{ + {0, Other}, + {1, One}, + {onePlusEpsilon, One}, + {2, Other}, + } + tests = appendFloatTests(tests, 0.1, 1.9, One) + tests = appendFloatTests(tests, 2.0, 10.0, Other) + runTests(t, "da", tests) +} + +func TestDutch(t *testing.T) { + tests := []pluralTest{ + {0, Other}, + {1, One}, + {onePlusEpsilon, Other}, + {2, Other}, + } + tests = appendFloatTests(tests, 0.0, 10.0, Other) + runTests(t, "nl", tests) +} + +func TestEnglish(t *testing.T) { + tests := []pluralTest{ + {0, Other}, + {1, One}, + {onePlusEpsilon, Other}, + {2, Other}, + } + tests = appendFloatTests(tests, 0.0, 10.0, Other) + runTests(t, "en", tests) +} + +func TestFrench(t *testing.T) { + tests := []pluralTest{ + {0, One}, + {1, One}, + {onePlusEpsilon, One}, + {2, Other}, + } + tests = appendFloatTests(tests, 0.0, 1.9, One) + tests = appendFloatTests(tests, 2.0, 10.0, Other) + runTests(t, "fr", tests) +} + +func TestGerman(t *testing.T) { + tests := []pluralTest{ + {0, Other}, + {1, One}, + {onePlusEpsilon, Other}, + {2, Other}, + } + tests = appendFloatTests(tests, 0.0, 10.0, Other) + runTests(t, "de", tests) +} + +func TestIcelandic(t *testing.T) { + tests := []pluralTest{ + {0, Other}, + {1, One}, + {2, Other}, + {11, Other}, + {21, One}, + {111, Other}, + {"0.0", Other}, + {"0.1", One}, + {"2.0", Other}, + } + runTests(t, "is", tests) +} + +func TestIndonesian(t *testing.T) { + tests := appendIntTests(nil, 0, 10, Other) + tests = appendFloatTests(tests, 0, 10, Other) + runTests(t, "id", tests) +} + +func TestItalian(t *testing.T) { + tests := []pluralTest{ + {0, Other}, + {1, One}, + {onePlusEpsilon, Other}, + {2, Other}, + } + tests = appendFloatTests(tests, 0.0, 10.0, Other) + runTests(t, "it", tests) +} + +func TestKorean(t *testing.T) { + tests := appendIntTests(nil, 0, 10, Other) + tests = appendFloatTests(tests, 0, 10, Other) + runTests(t, "ko", tests) +} + +func TestLatvian(t *testing.T) { + tests := []pluralTest{ + {0, Zero}, + {"0", Zero}, + {"0.1", One}, + {1, One}, + {"1", One}, + {onePlusEpsilon, One}, + {"10.0", Zero}, + {"10.1", One}, + {"10.2", Other}, + {21, One}, + } + tests = appendFloatTests(tests, 0.2, 0.9, Other) + tests = appendFloatTests(tests, 1.2, 1.9, Other) + tests = appendIntTests(tests, 2, 9, Other) + tests = appendIntTests(tests, 10, 20, Zero) + tests = appendIntTests(tests, 22, 29, Other) + runTests(t, "lv", tests) +} + +func TestJapanese(t *testing.T) { + tests := appendIntTests(nil, 0, 10, Other) + tests = appendFloatTests(tests, 0, 10, Other) + runTests(t, "ja", tests) +} + +func TestLithuanian(t *testing.T) { + tests := []pluralTest{ + {0, Other}, + {1, One}, + {2, Few}, + {3, Few}, + {9, Few}, + {10, Other}, + {11, Other}, + {"0.1", Many}, + {"0.7", Many}, + {"1.0", One}, + {onePlusEpsilon, Many}, + {"2.0", Few}, + {"10.0", Other}, + } + runTests(t, "lt", tests) +} + +func TestMalay(t *testing.T) { + tests := appendIntTests(nil, 0, 10, Other) + tests = appendFloatTests(tests, 0, 10, Other) + runTests(t, "ms", tests) +} + +func TestPolish(t *testing.T) { + tests := []pluralTest{ + {0, Many}, + {1, One}, + {2, Few}, + {3, Few}, + {4, Few}, + {5, Many}, + {19, Many}, + {20, Many}, + {10, Many}, + {11, Many}, + {52, Few}, + {"0.1", Other}, + {"0.7", Other}, + {"1.5", Other}, + {"1.0", Other}, + {onePlusEpsilon, Other}, + {"2.0", Other}, + {"10.0", Other}, + } + runTests(t, "pl", tests) +} + +func TestPortuguese(t *testing.T) { + tests := []pluralTest{ + {0, One}, + {"0.0", One}, + {1, One}, + {"1.0", One}, + {onePlusEpsilon, Other}, + {2, Other}, + } + tests = appendFloatTests(tests, 0.1, 0.9, Other) + tests = appendFloatTests(tests, 1.1, 10.0, Other) + runTests(t, "pt", tests) +} + +func TestMacedonian(t *testing.T) { + tests := []pluralTest{ + {0, Other}, + {1, One}, + {"1.1", One}, + {"2.1", One}, + {onePlusEpsilon, One}, + {2, Other}, + {"2.2", Other}, + {11, One}, + } + runTests(t, "mk", tests) +} + +func TestPortugueseEuropean(t *testing.T) { + tests := []pluralTest{ + {0, Other}, + {"0.0", Other}, + {"0.1", Other}, + {"0.01", Other}, + {1, One}, + {"1", One}, + {"1.1", Other}, + {"1.01", Other}, + {onePlusEpsilon, Other}, + {2, Other}, + } + tests = appendFloatTests(tests, 2.0, 10.0, Other) + runTests(t, "pt-pt", tests) +} + +func TestRussian(t *testing.T) { + tests := []pluralTest{ + {0, Many}, + {1, One}, + {2, Few}, + {3, Few}, + {4, Few}, + {5, Many}, + {19, Many}, + {20, Many}, + {21, One}, + {11, Many}, + {52, Few}, + {101, One}, + {"0.1", Other}, + {"0.7", Other}, + {"1.5", Other}, + {"1.0", Other}, + {onePlusEpsilon, Other}, + {"2.0", Other}, + {"10.0", Other}, + } + runTests(t, "ru", tests) +} + +func TestSpanish(t *testing.T) { + tests := []pluralTest{ + {0, Other}, + {1, One}, + {"1", One}, + {"1.0", One}, + {"1.00", One}, + {onePlusEpsilon, Other}, + {2, Other}, + } + tests = appendFloatTests(tests, 0.0, 0.9, Other) + tests = appendFloatTests(tests, 1.1, 10.0, Other) + runTests(t, "es", tests) +} + +func TestNorweigan(t *testing.T) { + tests := []pluralTest{ + {0, Other}, + {1, One}, + {"1", One}, + {"1.0", One}, + {"1.00", One}, + {onePlusEpsilon, Other}, + {2, Other}, + } + tests = appendFloatTests(tests, 0.0, 0.9, Other) + tests = appendFloatTests(tests, 1.1, 10.0, Other) + runTests(t, "no", tests) +} + +func TestBulgarian(t *testing.T) { + tests := []pluralTest{ + {0, Other}, + {1, One}, + {2, Other}, + {3, Other}, + {9, Other}, + {10, Other}, + {11, Other}, + {"0.1", Other}, + {"0.7", Other}, + {"1.0", One}, + {"1.001", Other}, + {onePlusEpsilon, Other}, + {"1.1", Other}, + {"2.0", Other}, + {"10.0", Other}, + } + runTests(t, "bg", tests) +} + +func TestSwedish(t *testing.T) { + tests := []pluralTest{ + {0, Other}, + {1, One}, + {onePlusEpsilon, Other}, + {2, Other}, + } + tests = appendFloatTests(tests, 0.0, 10.0, Other) + runTests(t, "sv", tests) +} + +func TestThai(t *testing.T) { + tests := appendIntTests(nil, 0, 10, Other) + tests = appendFloatTests(tests, 0, 10, Other) + runTests(t, "th", tests) +} + +func TestVietnamese(t *testing.T) { + tests := appendIntTests(nil, 0, 10, Other) + tests = appendFloatTests(tests, 0, 10, Other) + runTests(t, "vi", tests) +} + +func TestTurkish(t *testing.T) { + tests := []pluralTest{ + {0, Other}, + {1, One}, + {"1", One}, + {"1.0", One}, + {"1.00", One}, + {"1.001", Other}, + {"1.100", Other}, + {"1.101", Other}, + {onePlusEpsilon, Other}, + {2, Other}, + {"0.7", Other}, + {"2.0", Other}, + } + runTests(t, "tr", tests) +} + +func TestUkrainian(t *testing.T) { + tests := []pluralTest{ + {0, Many}, + {1, One}, + {2, Few}, + {3, Few}, + {4, Few}, + {5, Many}, + {19, Many}, + {20, Many}, + {21, One}, + {11, Many}, + {52, Few}, + {101, One}, + {"0.1", Other}, + {"0.7", Other}, + {"1.5", Other}, + {"1.0", Other}, + {onePlusEpsilon, Other}, + {"2.0", Other}, + {"10.0", Other}, + } + runTests(t, "uk", tests) +} + +func TestCroatian(t *testing.T) { + tests := makeCroatianBosnianSerbianTests() + runTests(t, "hr", tests) +} + +func TestBosnian(t *testing.T) { + tests := makeCroatianBosnianSerbianTests() + runTests(t, "bs", tests) +} + +func TestSerbian(t *testing.T) { + tests := makeCroatianBosnianSerbianTests() + runTests(t, "sr", tests) +} + +func makeCroatianBosnianSerbianTests() []pluralTest { + return []pluralTest{ + {1, One}, + {"0.1", One}, + {21, One}, + {101, One}, + {1001, One}, + {51, One}, + {"1.1", One}, + {"5.1", One}, + {"100.1", One}, + {"1000.1", One}, + {2, Few}, + {"0.2", Few}, + {22, Few}, + {"1.2", Few}, + {24, Few}, + {"2.4", Few}, + {102, Few}, + {"100.2", Few}, + {1002, Few}, + {"1000.2", Few}, + {5, Other}, + {"0.5", Other}, + {0, Other}, + {100, Other}, + {19, Other}, + {"0.0", Other}, + {"100.0", Other}, + {"1000.0", Other}, + } +} + +func TestTigrinya(t *testing.T) { + tests := []pluralTest{ + {0, One}, + {1, One}, + } + tests = appendIntTests(tests, 2, 10, Other) + tests = appendFloatTests(tests, 1.1, 10.0, Other) + runTests(t, "ti", tests) +} + +func appendIntTests(tests []pluralTest, from, to int, p Plural) []pluralTest { + for i := from; i <= to; i++ { + tests = append(tests, pluralTest{i, p}) + } + return tests +} + +func appendFloatTests(tests []pluralTest, from, to float64, p Plural) []pluralTest { + stride := 0.1 + format := "%.1f" + for f := from; f < to; f += stride { + tests = append(tests, pluralTest{fmt.Sprintf(format, f), p}) + } + tests = append(tests, pluralTest{fmt.Sprintf(format, to), p}) + return tests +} + +func runTests(t *testing.T, pluralSpecID string, tests []pluralTest) { + pluralSpecID = normalizePluralSpecID(pluralSpecID) + if spec := pluralSpecs[pluralSpecID]; spec != nil { + for _, test := range tests { + if plural, err := spec.Plural(test.num); plural != test.plural { + t.Errorf("%s: PluralCategory(%#v) returned %s, %v; expected %s", pluralSpecID, test.num, plural, err, test.plural) + } + } + } else { + t.Errorf("could not find plural spec for locale %s", pluralSpecID) + } + +} diff --git a/vendor/github.com/nicksnyder/go-i18n/i18n/translation/plural_translation_test.go b/vendor/github.com/nicksnyder/go-i18n/i18n/translation/plural_translation_test.go new file mode 100644 index 000000000..ea7de7fd9 --- /dev/null +++ b/vendor/github.com/nicksnyder/go-i18n/i18n/translation/plural_translation_test.go @@ -0,0 +1,308 @@ +package translation + +import ( + "reflect" + "testing" + + "github.com/nicksnyder/go-i18n/i18n/language" +) + +func mustTemplate(t *testing.T, src string) *template { + tmpl, err := newTemplate(src) + if err != nil { + t.Fatal(err) + } + return tmpl +} + +func pluralTranslationFixture(t *testing.T, id string, pluralCategories ...language.Plural) *pluralTranslation { + templates := make(map[language.Plural]*template, len(pluralCategories)) + for _, pc := range pluralCategories { + templates[pc] = mustTemplate(t, string(pc)) + } + return &pluralTranslation{id, templates} +} + +func verifyDeepEqual(t *testing.T, actual, expected interface{}) { + if !reflect.DeepEqual(actual, expected) { + t.Fatalf("\n%#v\nnot equal to expected value\n%#v", actual, expected) + } +} + +func TestPluralTranslationMerge(t *testing.T) { + pt := pluralTranslationFixture(t, "id", language.One, language.Other) + oneTemplate, otherTemplate := pt.templates[language.One], pt.templates[language.Other] + + pt.Merge(pluralTranslationFixture(t, "id")) + verifyDeepEqual(t, pt.templates, map[language.Plural]*template{ + language.One: oneTemplate, + language.Other: otherTemplate, + }) + + pt2 := pluralTranslationFixture(t, "id", language.One, language.Two) + pt.Merge(pt2) + verifyDeepEqual(t, pt.templates, map[language.Plural]*template{ + language.One: pt2.templates[language.One], + language.Two: pt2.templates[language.Two], + language.Other: otherTemplate, + }) +} + +/* Test implementations from old idea + +func TestCopy(t *testing.T) { + ls := &LocalizedString{ + ID: "id", + Translation: testingTemplate(t, "translation {{.Hello}}"), + Translations: map[language.Plural]*template{ + language.One: testingTemplate(t, "plural {{.One}}"), + language.Other: testingTemplate(t, "plural {{.Other}}"), + }, + } + + c := ls.Copy() + delete(c.Translations, language.One) + if _, ok := ls.Translations[language.One]; !ok { + t.Errorf("deleting plural translation from copy deleted it from the original") + } + c.Translations[language.Two] = testingTemplate(t, "plural {{.Two}}") + if _, ok := ls.Translations[language.Two]; ok { + t.Errorf("adding plural translation to copy added it to the original") + } +} + +func TestNormalize(t *testing.T) { + oneTemplate := testingTemplate(t, "one {{.One}}") + ls := &LocalizedString{ + Translation: testingTemplate(t, "single {{.Single}}"), + Translations: map[language.Plural]*template{ + language.One: oneTemplate, + language.Two: testingTemplate(t, "two {{.Two}}"), + }, + } + ls.Normalize(LanguageWithCode("en")) + if ls.Translation != nil { + t.Errorf("ls.Translation is %#v; expected nil", ls.Translation) + } + if actual := ls.Translations[language.Two]; actual != nil { + t.Errorf("ls.Translation[language.Two] is %#v; expected nil", actual) + } + if actual := ls.Translations[language.One]; actual != oneTemplate { + t.Errorf("ls.Translations[language.One] is %#v; expected %#v", actual, oneTemplate) + } + if _, ok := ls.Translations[language.Other]; !ok { + t.Errorf("ls.Translations[language.Other] shouldn't be empty") + } +} + +func TestMergeTranslation(t *testing.T) { + ls := &LocalizedString{} + + translation := testingTemplate(t, "one {{.Hello}}") + ls.Merge(&LocalizedString{ + Translation: translation, + }) + if ls.Translation != translation { + t.Errorf("expected %#v; got %#v", translation, ls.Translation) + } + + ls.Merge(&LocalizedString{}) + if ls.Translation != translation { + t.Errorf("expected %#v; got %#v", translation, ls.Translation) + } + + translation = testingTemplate(t, "two {{.Hello}}") + ls.Merge(&LocalizedString{ + Translation: translation, + }) + if ls.Translation != translation { + t.Errorf("expected %#v; got %#v", translation, ls.Translation) + } +} + +func TestMergeTranslations(t *testing.T) { + ls := &LocalizedString{} + + oneTemplate := testingTemplate(t, "one {{.One}}") + otherTemplate := testingTemplate(t, "other {{.Other}}") + ls.Merge(&LocalizedString{ + Translations: map[language.Plural]*template{ + language.One: oneTemplate, + language.Other: otherTemplate, + }, + }) + if actual := ls.Translations[language.One]; actual != oneTemplate { + t.Errorf("ls.Translations[language.One] expected %#v; got %#v", oneTemplate, actual) + } + if actual := ls.Translations[language.Other]; actual != otherTemplate { + t.Errorf("ls.Translations[language.Other] expected %#v; got %#v", otherTemplate, actual) + } + + ls.Merge(&LocalizedString{ + Translations: map[language.Plural]*template{}, + }) + if actual := ls.Translations[language.One]; actual != oneTemplate { + t.Errorf("ls.Translations[language.One] expected %#v; got %#v", oneTemplate, actual) + } + if actual := ls.Translations[language.Other]; actual != otherTemplate { + t.Errorf("ls.Translations[language.Other] expected %#v; got %#v", otherTemplate, actual) + } + + twoTemplate := testingTemplate(t, "two {{.Two}}") + otherTemplate = testingTemplate(t, "second other {{.Other}}") + ls.Merge(&LocalizedString{ + Translations: map[language.Plural]*template{ + language.Two: twoTemplate, + language.Other: otherTemplate, + }, + }) + if actual := ls.Translations[language.One]; actual != oneTemplate { + t.Errorf("ls.Translations[language.One] expected %#v; got %#v", oneTemplate, actual) + } + if actual := ls.Translations[language.Two]; actual != twoTemplate { + t.Errorf("ls.Translations[language.Two] expected %#v; got %#v", twoTemplate, actual) + } + if actual := ls.Translations[language.Other]; actual != otherTemplate { + t.Errorf("ls.Translations[language.Other] expected %#v; got %#v", otherTemplate, actual) + } +} + +func TestMissingTranslations(t *testing.T) { + en := LanguageWithCode("en") + + tests := []struct { + localizedString *LocalizedString + language *Language + expected bool + }{ + { + &LocalizedString{}, + en, + true, + }, + { + &LocalizedString{Translation: testingTemplate(t, "single {{.Single}}")}, + en, + false, + }, + { + &LocalizedString{ + Translation: testingTemplate(t, "single {{.Single}}"), + Translations: map[language.Plural]*template{ + language.One: testingTemplate(t, "one {{.One}}"), + }}, + en, + true, + }, + { + &LocalizedString{Translations: map[language.Plural]*template{ + language.One: testingTemplate(t, "one {{.One}}"), + }}, + en, + true, + }, + { + &LocalizedString{Translations: map[language.Plural]*template{ + language.One: nil, + language.Other: nil, + }}, + en, + true, + }, + { + &LocalizedString{Translations: map[language.Plural]*template{ + language.One: testingTemplate(t, ""), + language.Other: testingTemplate(t, ""), + }}, + en, + true, + }, + { + &LocalizedString{Translations: map[language.Plural]*template{ + language.One: testingTemplate(t, "one {{.One}}"), + language.Other: testingTemplate(t, "other {{.Other}}"), + }}, + en, + false, + }, + } + + for _, tt := range tests { + if actual := tt.localizedString.MissingTranslations(tt.language); actual != tt.expected { + t.Errorf("expected %t got %t for %s, %#v", + tt.expected, actual, tt.language.code, tt.localizedString) + } + } +} + +func TestHasTranslations(t *testing.T) { + en := LanguageWithCode("en") + + tests := []struct { + localizedString *LocalizedString + language *Language + expected bool + }{ + { + &LocalizedString{}, + en, + false, + }, + { + &LocalizedString{Translation: testingTemplate(t, "single {{.Single}}")}, + en, + true, + }, + { + &LocalizedString{ + Translation: testingTemplate(t, "single {{.Single}}"), + Translations: map[language.Plural]*template{}}, + en, + false, + }, + { + &LocalizedString{Translations: map[language.Plural]*template{ + language.One: testingTemplate(t, "one {{.One}}"), + }}, + en, + true, + }, + { + &LocalizedString{Translations: map[language.Plural]*template{ + language.Two: testingTemplate(t, "two {{.Two}}"), + }}, + en, + false, + }, + { + &LocalizedString{Translations: map[language.Plural]*template{ + language.One: nil, + }}, + en, + false, + }, + { + &LocalizedString{Translations: map[language.Plural]*template{ + language.One: testingTemplate(t, ""), + }}, + en, + false, + }, + } + + for _, tt := range tests { + if actual := tt.localizedString.HasTranslations(tt.language); actual != tt.expected { + t.Errorf("expected %t got %t for %s, %#v", + tt.expected, actual, tt.language.code, tt.localizedString) + } + } +} + +func testingTemplate(t *testing.T, src string) *template { + tmpl, err := newTemplate(src) + if err != nil { + t.Fatal(err) + } + return tmpl +} +*/ diff --git a/vendor/github.com/nicksnyder/go-i18n/i18n/translation/template_test.go b/vendor/github.com/nicksnyder/go-i18n/i18n/translation/template_test.go new file mode 100644 index 000000000..73a923404 --- /dev/null +++ b/vendor/github.com/nicksnyder/go-i18n/i18n/translation/template_test.go @@ -0,0 +1,146 @@ +package translation + +import ( + "bytes" + "fmt" + //"launchpad.net/goyaml" + "testing" + gotemplate "text/template" +) + +func TestNilTemplate(t *testing.T) { + expected := "hello" + tmpl := &template{ + tmpl: nil, + src: expected, + } + if actual := tmpl.Execute(nil); actual != expected { + t.Errorf("Execute(nil) returned %s; expected %s", actual, expected) + } +} + +func TestMarshalText(t *testing.T) { + tmpl := &template{ + tmpl: gotemplate.Must(gotemplate.New("id").Parse("this is a {{.foo}} template")), + src: "boom", + } + expectedBuf := []byte(tmpl.src) + if buf, err := tmpl.MarshalText(); !bytes.Equal(buf, expectedBuf) || err != nil { + t.Errorf("MarshalText() returned %#v, %#v; expected %#v, nil", buf, err, expectedBuf) + } +} + +func TestUnmarshalText(t *testing.T) { + tmpl := &template{} + tmpl.UnmarshalText([]byte("hello {{.World}}")) + result := tmpl.Execute(map[string]string{ + "World": "world!", + }) + expected := "hello world!" + if result != expected { + t.Errorf("expected %#v; got %#v", expected, result) + } +} + +/* +func TestYAMLMarshal(t *testing.T) { + src := "hello {{.World}}" + tmpl, err := newTemplate(src) + if err != nil { + t.Fatal(err) + } + buf, err := goyaml.Marshal(tmpl) + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(buf, []byte(src)) { + t.Fatalf(`expected "%s"; got "%s"`, src, buf) + } +} + +func TestYAMLUnmarshal(t *testing.T) { + buf := []byte(`Tmpl: "hello"`) + + var out struct { + Tmpl *template + } + var foo map[string]string + if err := goyaml.Unmarshal(buf, &foo); err != nil { + t.Fatal(err) + } + if out.Tmpl == nil { + t.Fatalf("out.Tmpl was nil") + } + if out.Tmpl.tmpl == nil { + t.Fatalf("out.Tmpl.tmpl was nil") + } + if expected := "hello {{.World}}"; out.Tmpl.src != expected { + t.Fatalf("expected %s; got %s", expected, out.Tmpl.src) + } +} + +func TestGetYAML(t *testing.T) { + src := "hello" + tmpl := &template{ + tmpl: nil, + src: src, + } + if tag, value := tmpl.GetYAML(); tag != "" || value != src { + t.Errorf("GetYAML() returned (%#v, %#v); expected (%#v, %#v)", tag, value, "", src) + } +} + +func TestSetYAML(t *testing.T) { + tmpl := &template{} + tmpl.SetYAML("tagDoesntMatter", "hello {{.World}}") + result := tmpl.Execute(map[string]string{ + "World": "world!", + }) + expected := "hello world!" + if result != expected { + t.Errorf("expected %#v; got %#v", expected, result) + } +} +*/ + +func BenchmarkExecuteNilTemplate(b *testing.B) { + template := &template{src: "hello world"} + b.ResetTimer() + for i := 0; i < b.N; i++ { + template.Execute(nil) + } +} + +func BenchmarkExecuteHelloWorldTemplate(b *testing.B) { + template, err := newTemplate("hello world") + if err != nil { + b.Fatal(err) + } + b.ResetTimer() + for i := 0; i < b.N; i++ { + template.Execute(nil) + } +} + +// Executing a simple template like this is ~6x slower than Sprintf +// but it is still only a few microseconds which should be sufficiently fast. +// The benefit is that we have nice semantic tags in the translation. +func BenchmarkExecuteHelloNameTemplate(b *testing.B) { + template, err := newTemplate("hello {{.Name}}") + if err != nil { + b.Fatal(err) + } + b.ResetTimer() + for i := 0; i < b.N; i++ { + template.Execute(map[string]string{ + "Name": "Nick", + }) + } +} + +func BenchmarkSprintf(b *testing.B) { + b.ResetTimer() + for i := 0; i < b.N; i++ { + fmt.Sprintf("hello %s", "nick") + } +} diff --git a/vendor/github.com/nicksnyder/go-i18n/i18n/translation/translation_test.go b/vendor/github.com/nicksnyder/go-i18n/i18n/translation/translation_test.go new file mode 100644 index 000000000..7380d5a6f --- /dev/null +++ b/vendor/github.com/nicksnyder/go-i18n/i18n/translation/translation_test.go @@ -0,0 +1,17 @@ +package translation + +import ( + "sort" + "testing" +) + +// Check this here to avoid unnecessary import of sort package. +var _ = sort.Interface(make(SortableByID, 0, 0)) + +func TestNewSingleTranslation(t *testing.T) { + t.Skipf("not implemented") +} + +func TestNewPluralTranslation(t *testing.T) { + t.Skipf("not implemented") +} -- cgit v1.2.3-1-g7c22