Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/gohugoio/go-i18n.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick Snyder <nickdsnyder@gmail.com>2019-05-19 20:46:31 +0300
committerGitHub <noreply@github.com>2019-05-19 20:46:31 +0300
commitbe3966fd39d744b0fce2bc71c79f42911cef7b7c (patch)
treeccf72bc95a7f9bdb69fdbb007a6f37a411ba8d13
parent3c6ee9071cf061f4b0101e14412f74d6e7a8ada6 (diff)
v2 only (#176)
fixes https://github.com/nicksnyder/go-i18n/issues/172
-rw-r--r--.codecov.yml10
-rw-r--r--.gitignore4
-rw-r--r--.goreleaser.yml (renamed from v2/.goreleaser.yml)0
-rw-r--r--.travis.yml2
-rw-r--r--dev.md4
-rw-r--r--example/README.md (renamed from v2/example/README.md)0
-rw-r--r--example/active.en.toml (renamed from v2/example/active.en.toml)0
-rw-r--r--example/active.es.toml (renamed from v2/example/active.es.toml)0
-rw-r--r--example/main.go (renamed from v2/example/main.go)0
-rw-r--r--go.mod9
-rw-r--r--go.sum (renamed from v2/go.sum)0
-rw-r--r--goi18n/active.en.toml (renamed from v2/goi18n/active.en.toml)0
-rw-r--r--goi18n/common_test.go (renamed from v2/goi18n/common_test.go)0
-rw-r--r--goi18n/constants_command.go229
-rw-r--r--goi18n/constants_command_test.go42
-rw-r--r--goi18n/doc.go93
-rw-r--r--goi18n/extract_command.go (renamed from v2/goi18n/extract_command.go)7
-rw-r--r--goi18n/extract_command_test.go (renamed from v2/goi18n/extract_command_test.go)0
-rw-r--r--goi18n/gendoc.sh12
-rw-r--r--goi18n/goi18n.go55
-rw-r--r--goi18n/main.go (renamed from v2/goi18n/main.go)7
-rw-r--r--goi18n/main_test.go (renamed from v2/goi18n/main_test.go)0
-rw-r--r--goi18n/marshal.go (renamed from v2/goi18n/marshal.go)0
-rw-r--r--goi18n/merge_command.go438
-rw-r--r--goi18n/merge_command_flat_test.go36
-rw-r--r--goi18n/merge_command_test.go596
-rw-r--r--goi18n/testdata/en-us.flat.json34
-rw-r--r--goi18n/testdata/en-us.flat.toml25
-rw-r--r--goi18n/testdata/en-us.flat.yaml29
-rw-r--r--goi18n/testdata/en-us.yaml35
-rw-r--r--goi18n/testdata/expected/R.go38
-rw-r--r--goi18n/testdata/expected/ar-ar.all.json65
-rw-r--r--goi18n/testdata/expected/ar-ar.untranslated.json50
-rw-r--r--goi18n/testdata/expected/en-us.all.json45
-rw-r--r--goi18n/testdata/expected/en-us.untranslated.json1
-rw-r--r--goi18n/testdata/expected/flat/ar-ar.all.json43
-rw-r--r--goi18n/testdata/expected/flat/ar-ar.untranslated.json32
-rw-r--r--goi18n/testdata/expected/flat/en-us.all.json27
-rw-r--r--goi18n/testdata/expected/flat/en-us.untranslated.json1
-rw-r--r--goi18n/testdata/expected/flat/en-us.untranslated.json.json0
-rw-r--r--goi18n/testdata/expected/flat/fr-fr.all.json27
-rw-r--r--goi18n/testdata/expected/flat/fr-fr.untranslated.json27
-rw-r--r--goi18n/testdata/expected/fr-fr.all.json45
-rw-r--r--goi18n/testdata/expected/fr-fr.untranslated.json45
-rw-r--r--goi18n/testdata/input/ar-ar.one.json54
-rw-r--r--goi18n/testdata/input/ar-ar.two.json54
-rw-r--r--goi18n/testdata/input/en-us.constants.json45
-rw-r--r--goi18n/testdata/input/en-us.one.json30
-rw-r--r--goi18n/testdata/input/en-us.two.json26
-rw-r--r--goi18n/testdata/input/flat/ar-ar.one.toml37
-rw-r--r--goi18n/testdata/input/flat/ar-ar.two.json45
-rw-r--r--goi18n/testdata/input/flat/en-us.constants.json34
-rw-r--r--goi18n/testdata/input/flat/en-us.one.yaml16
-rw-r--r--goi18n/testdata/input/flat/en-us.two.json19
-rw-r--r--goi18n/testdata/input/flat/fr-fr.json0
-rw-r--r--goi18n/testdata/input/fr-fr.json0
-rw-r--r--goi18n/testdata/input/yaml/ar-ar.one.json54
-rw-r--r--goi18n/testdata/input/yaml/ar-ar.two.json54
-rw-r--r--goi18n/testdata/input/yaml/en-us.one.yaml19
-rw-r--r--goi18n/testdata/input/yaml/en-us.two.json26
-rw-r--r--goi18n/testdata/input/yaml/fr-fr.json0
-rw-r--r--i18n/bundle.go (renamed from v2/i18n/bundle.go)0
-rw-r--r--i18n/bundle/bundle.go443
-rw-r--r--i18n/bundle/bundle_test.go364
-rw-r--r--i18n/bundle_test.go (renamed from v2/i18n/bundle_test.go)0
-rw-r--r--i18n/doc.go (renamed from v2/i18n/doc.go)0
-rw-r--r--i18n/example_test.go198
-rw-r--r--i18n/exampletemplate_test.go64
-rw-r--r--i18n/exampleyaml_test.go63
-rw-r--r--i18n/i18n.go158
-rw-r--r--i18n/language/codegen/generate.sh5
-rw-r--r--i18n/language/codegen/main.go132
-rw-r--r--i18n/language/codegen/plurals.xml226
-rw-r--r--i18n/language/codegen/xml.go143
-rw-r--r--i18n/language/language.go99
-rw-r--r--i18n/language/language_test.go85
-rw-r--r--i18n/language/operands.go119
-rw-r--r--i18n/language/operands_test.go45
-rw-r--r--i18n/language/plural.go40
-rw-r--r--i18n/language/plural_test.go28
-rw-r--r--i18n/language/pluralspec.go75
-rw-r--r--i18n/language/pluralspec_gen.go557
-rw-r--r--i18n/language/pluralspec_gen_test.go631
-rw-r--r--i18n/language/pluralspec_test.go716
-rw-r--r--i18n/language_test.go (renamed from v2/i18n/language_test.go)0
-rw-r--r--i18n/localizer.go (renamed from v2/i18n/localizer.go)0
-rw-r--r--i18n/localizer_test.go (renamed from v2/i18n/localizer_test.go)0
-rw-r--r--i18n/message.go (renamed from v2/i18n/message.go)0
-rw-r--r--i18n/message_template.go (renamed from v2/i18n/message_template.go)0
-rw-r--r--i18n/message_template_test.go (renamed from v2/i18n/message_template_test.go)0
-rw-r--r--i18n/message_test.go (renamed from v2/i18n/message_test.go)0
-rw-r--r--i18n/parse.go (renamed from v2/i18n/parse.go)0
-rw-r--r--i18n/parse_test.go (renamed from v2/i18n/parse_test.go)0
-rw-r--r--i18n/translation/plural_translation.go82
-rw-r--r--i18n/translation/plural_translation_test.go308
-rw-r--r--i18n/translation/single_translation.go61
-rw-r--r--i18n/translation/template.go65
-rw-r--r--i18n/translation/template_test.go89
-rw-r--r--i18n/translation/translation.go84
-rw-r--r--i18n/translation/translation_test.go17
-rw-r--r--i18n/translations_test.go89
-rw-r--r--internal/plural/codegen/generate.sh (renamed from v2/internal/plural/codegen/generate.sh)0
-rw-r--r--internal/plural/codegen/main.go (renamed from v2/internal/plural/codegen/main.go)0
-rw-r--r--internal/plural/codegen/plurals.xml (renamed from v2/internal/plural/codegen/plurals.xml)0
-rw-r--r--internal/plural/codegen/xml.go (renamed from v2/internal/plural/codegen/xml.go)0
-rw-r--r--internal/plural/doc.go (renamed from v2/internal/plural/doc.go)0
-rw-r--r--internal/plural/form.go (renamed from v2/internal/plural/form.go)0
-rw-r--r--internal/plural/operands.go (renamed from v2/internal/plural/operands.go)0
-rw-r--r--internal/plural/operands_test.go (renamed from v2/internal/plural/operands_test.go)0
-rw-r--r--internal/plural/rule.go (renamed from v2/internal/plural/rule.go)0
-rw-r--r--internal/plural/rule_gen.go (renamed from v2/internal/plural/rule_gen.go)0
-rw-r--r--internal/plural/rule_gen_test.go (renamed from v2/internal/plural/rule_gen_test.go)0
-rw-r--r--internal/plural/rule_test.go (renamed from v2/internal/plural/rule_test.go)0
-rw-r--r--internal/plural/rules.go (renamed from v2/internal/plural/rules.go)0
-rw-r--r--internal/plural/rules_test.go (renamed from v2/internal/plural/rules_test.go)0
-rw-r--r--internal/template.go (renamed from v2/internal/template.go)0
-rw-r--r--internal/template_test.go (renamed from v2/internal/template_test.go)0
-rw-r--r--v2/go.mod11
-rw-r--r--v2/goi18n/merge_command.go292
-rw-r--r--v2/goi18n/merge_command_test.go563
-rw-r--r--v2/i18n/example_test.go141
121 files changed, 932 insertions, 7687 deletions
diff --git a/.codecov.yml b/.codecov.yml
index b90d6da..879fd14 100644
--- a/.codecov.yml
+++ b/.codecov.yml
@@ -4,13 +4,5 @@ coverage:
default:
threshold: 50%
project:
- default: false
- v1:
- threshold: 0.1%
- paths:
- - i18n
- - goi18n
- v2:
+ default:
threshold: 0.1%
- paths:
- - v2
diff --git a/.gitignore b/.gitignore
index d9af66f..281914e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,7 +5,7 @@ output/
*.test
*.swp
-v2/example/example
-v2/goi18n/goi18n
+example/example
+goi18n/goi18n
dist/
diff --git a/v2/.goreleaser.yml b/.goreleaser.yml
index d9352ad..d9352ad 100644
--- a/v2/.goreleaser.yml
+++ b/.goreleaser.yml
diff --git a/.travis.yml b/.travis.yml
index 8d1a79d..a9e9c51 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -2,8 +2,6 @@ language: go
matrix:
include:
- - go: 1.2.x
- env: PKG='./i18n/... ./goi18n/...'
- go: 1.9.x
env: PKG='./...'
- go: 1.12.x
diff --git a/dev.md b/dev.md
index a55181e..d0210bb 100644
--- a/dev.md
+++ b/dev.md
@@ -4,5 +4,5 @@
1. Go to http://cldr.unicode.org/index/downloads to find the latest version.
1. Download the latest version of cldr-common (e.g. http://unicode.org/Public/cldr/33/cldr-common-33.0.zip)
-1. Unzip and copy `common/supplemental/plurals.xml` to `v2/i18n/internal/plural/codegen/plurals.xml`
-1. Run `generate.sh` in `v2/i18n/internal/plural/codegen/`
+1. Unzip and copy `common/supplemental/plurals.xml` to `i18n/internal/plural/codegen/plurals.xml`
+1. Run `generate.sh` in `i18n/internal/plural/codegen/`
diff --git a/v2/example/README.md b/example/README.md
index 4ef9c4d..4ef9c4d 100644
--- a/v2/example/README.md
+++ b/example/README.md
diff --git a/v2/example/active.en.toml b/example/active.en.toml
index e642c54..e642c54 100644
--- a/v2/example/active.en.toml
+++ b/example/active.en.toml
diff --git a/v2/example/active.es.toml b/example/active.es.toml
index 43b5593..43b5593 100644
--- a/v2/example/active.es.toml
+++ b/example/active.es.toml
diff --git a/v2/example/main.go b/example/main.go
index 838e145..838e145 100644
--- a/v2/example/main.go
+++ b/example/main.go
diff --git a/go.mod b/go.mod
index d42c15a..7aba6f8 100644
--- a/go.mod
+++ b/go.mod
@@ -1,6 +1,11 @@
-module github.com/nicksnyder/go-i18n
+module github.com/nicksnyder/go-i18n/v2
require (
- github.com/pelletier/go-toml v1.2.0
+ github.com/BurntSushi/toml v0.3.0
+ golang.org/x/crypto v0.0.0-20190506204251-e1dfcc566284 // indirect
+ golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c // indirect
+ golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b // indirect
+ golang.org/x/text v0.3.2
+ golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c // indirect
gopkg.in/yaml.v2 v2.2.1
)
diff --git a/v2/go.sum b/go.sum
index 96207c2..96207c2 100644
--- a/v2/go.sum
+++ b/go.sum
diff --git a/v2/goi18n/active.en.toml b/goi18n/active.en.toml
index e69de29..e69de29 100644
--- a/v2/goi18n/active.en.toml
+++ b/goi18n/active.en.toml
diff --git a/v2/goi18n/common_test.go b/goi18n/common_test.go
index 0017bd2..0017bd2 100644
--- a/v2/goi18n/common_test.go
+++ b/goi18n/common_test.go
diff --git a/goi18n/constants_command.go b/goi18n/constants_command.go
deleted file mode 100644
index d877add..0000000
--- a/goi18n/constants_command.go
+++ /dev/null
@@ -1,229 +0,0 @@
-package main
-
-import (
- "flag"
- "fmt"
- "os"
- "path/filepath"
- "reflect"
- "regexp"
- "sort"
- "strconv"
- "strings"
- "text/template"
- "unicode"
-
- "github.com/nicksnyder/go-i18n/i18n/bundle"
- "github.com/nicksnyder/go-i18n/i18n/language"
- "github.com/nicksnyder/go-i18n/i18n/translation"
-)
-
-type constantsCommand struct {
- translationFiles []string
- packageName string
- outdir string
-}
-
-type templateConstants struct {
- ID string
- Name string
- Comments []string
-}
-
-type templateHeader struct {
- PackageName string
- Constants []templateConstants
-}
-
-var constTemplate = template.Must(template.New("").Parse(`// DON'T CHANGE THIS FILE MANUALLY
-// This file was generated using the command:
-// $ goi18n constants
-
-package {{.PackageName}}
-{{range .Constants}}
-// {{.Name}} is the identifier for the following localizable string template(s):{{range .Comments}}
-// {{.}}{{end}}
-const {{.Name}} = "{{.ID}}"
-{{end}}`))
-
-func (cc *constantsCommand) execute() error {
- if len(cc.translationFiles) != 1 {
- return fmt.Errorf("need one translation file")
- }
-
- bundle := bundle.New()
-
- if err := bundle.LoadTranslationFile(cc.translationFiles[0]); err != nil {
- return fmt.Errorf("failed to load translation file %s because %s\n", cc.translationFiles[0], err)
- }
-
- translations := bundle.Translations()
- lang := translations[bundle.LanguageTags()[0]]
-
- // create an array of id to organize
- keys := make([]string, len(lang))
- i := 0
-
- for id := range lang {
- keys[i] = id
- i++
- }
- sort.Strings(keys)
-
- tmpl := &templateHeader{
- PackageName: cc.packageName,
- Constants: make([]templateConstants, len(keys)),
- }
-
- for i, id := range keys {
- tmpl.Constants[i].ID = id
- tmpl.Constants[i].Name = toCamelCase(id)
- tmpl.Constants[i].Comments = toComments(lang[id])
- }
-
- filename := filepath.Join(cc.outdir, cc.packageName+".go")
- f, err := os.Create(filename)
- if err != nil {
- return fmt.Errorf("failed to create file %s because %s", filename, err)
- }
-
- defer f.Close()
-
- if err = constTemplate.Execute(f, tmpl); err != nil {
- return fmt.Errorf("failed to write file %s because %s", filename, err)
- }
-
- return nil
-}
-
-func (cc *constantsCommand) parse(arguments []string) {
- flags := flag.NewFlagSet("constants", flag.ExitOnError)
- flags.Usage = usageConstants
-
- packageName := flags.String("package", "R", "")
- outdir := flags.String("outdir", ".", "")
-
- flags.Parse(arguments)
-
- cc.translationFiles = flags.Args()
- cc.packageName = *packageName
- cc.outdir = *outdir
-}
-
-func (cc *constantsCommand) SetArgs(args []string) {
- cc.translationFiles = args
-}
-
-func usageConstants() {
- fmt.Printf(`Generate constant file from translation file.
-
-Usage:
-
- goi18n constants [options] [file]
-
-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.).
-
-Options:
-
- -package name
- goi18n generates the constant file under the package name.
- Default: R
-
- -outdir directory
- goi18n writes the constant file to this directory.
- Default: .
-
-`)
-}
-
-// commonInitialisms is a set of common initialisms.
-// Only add entries that are highly unlikely to be non-initialisms.
-// For instance, "ID" is fine (Freudian code is rare), but "AND" is not.
-// https://github.com/golang/lint/blob/master/lint.go
-var commonInitialisms = map[string]bool{
- "API": true,
- "ASCII": true,
- "CPU": true,
- "CSS": true,
- "DNS": true,
- "EOF": true,
- "GUID": true,
- "HTML": true,
- "HTTP": true,
- "HTTPS": true,
- "ID": true,
- "IP": true,
- "JSON": true,
- "LHS": true,
- "QPS": true,
- "RAM": true,
- "RHS": true,
- "RPC": true,
- "SLA": true,
- "SMTP": true,
- "SQL": true,
- "SSH": true,
- "TCP": true,
- "TLS": true,
- "TTL": true,
- "UDP": true,
- "UI": true,
- "UID": true,
- "UUID": true,
- "URI": true,
- "URL": true,
- "UTF8": true,
- "VM": true,
- "XML": true,
- "XSRF": true,
- "XSS": true,
-}
-
-func toCamelCase(id string) string {
- var result string
-
- r := regexp.MustCompile(`[\-\.\_\s]`)
- words := r.Split(id, -1)
-
- for _, w := range words {
- upper := strings.ToUpper(w)
- if commonInitialisms[upper] {
- result += upper
- continue
- }
-
- if len(w) > 0 {
- u := []rune(w)
- u[0] = unicode.ToUpper(u[0])
- result += string(u)
- }
- }
- return result
-}
-
-func toComments(trans translation.Translation) []string {
- var result []string
- data := trans.MarshalInterface().(map[string]interface{})
-
- t := data["translation"]
-
- switch v := reflect.ValueOf(t); v.Kind() {
- case reflect.Map:
- for _, k := range []language.Plural{"zero", "one", "two", "few", "many", "other"} {
- vt := v.MapIndex(reflect.ValueOf(k))
- if !vt.IsValid() {
- continue
- }
- result = append(result, string(k)+": "+strconv.Quote(fmt.Sprint(vt.Interface())))
- }
- default:
- result = append(result, strconv.Quote(fmt.Sprint(t)))
- }
-
- return result
-}
diff --git a/goi18n/constants_command_test.go b/goi18n/constants_command_test.go
deleted file mode 100644
index 43dea3f..0000000
--- a/goi18n/constants_command_test.go
+++ /dev/null
@@ -1,42 +0,0 @@
-package main
-
-import "testing"
-
-func TestConstantsExecute(t *testing.T) {
- resetDir(t, "testdata/output")
-
- cc := &constantsCommand{
- translationFiles: []string{"testdata/input/en-us.constants.json"},
- packageName: "R",
- outdir: "testdata/output",
- }
-
- if err := cc.execute(); err != nil {
- t.Fatal(err)
- }
-
- expectEqualFiles(t, "testdata/output/R.go", "testdata/expected/R.go")
-}
-
-func TestToCamelCase(t *testing.T) {
- expectEqual := func(test, expected string) {
- result := toCamelCase(test)
- if result != expected {
- t.Fatalf("failed toCamelCase the test %s was expected %s but the result was %s", test, expected, result)
- }
- }
-
- expectEqual("", "")
- expectEqual("a", "A")
- expectEqual("_", "")
- expectEqual("__code__", "Code")
- expectEqual("test", "Test")
- expectEqual("test_one", "TestOne")
- expectEqual("test.two", "TestTwo")
- expectEqual("test_alpha_beta", "TestAlphaBeta")
- expectEqual("word word", "WordWord")
- expectEqual("test_id", "TestID")
- expectEqual("tcp_name", "TCPName")
- expectEqual("こんにちは", "こんにちは")
- expectEqual("test_a", "TestA")
-}
diff --git a/goi18n/doc.go b/goi18n/doc.go
deleted file mode 100644
index 97c7a7f..0000000
--- a/goi18n/doc.go
+++ /dev/null
@@ -1,93 +0,0 @@
-// The goi18n command formats and merges translation files.
-//
-// go get -u github.com/nicksnyder/go-i18n/goi18n
-// goi18n -help
-//
-// Help documentation:
-//
-// goi18n manages translation files.
-//
-// Usage:
-//
-// goi18n merge Merge translation files
-// goi18n constants Generate constant file from translation file
-//
-// For more details execute:
-//
-// goi18n [command] -help
-//
-// Merge translation files.
-//
-// Usage:
-//
-// goi18n merge [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
-//
-// Generate constant file from translation file.
-//
-// Usage:
-//
-// goi18n constants [options] [file]
-//
-// 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.).
-//
-// Options:
-//
-// -package name
-// goi18n generates the constant file under the package name.
-// Default: R
-//
-// -outdir directory
-// goi18n writes the constant file to this directory.
-// Default: .
-//
-package main
diff --git a/v2/goi18n/extract_command.go b/goi18n/extract_command.go
index b7bee37..178a06d 100644
--- a/v2/goi18n/extract_command.go
+++ b/goi18n/extract_command.go
@@ -51,16 +51,19 @@ func (ec *extractCommand) name() string {
return "extract"
}
-func (ec *extractCommand) parse(args []string) {
+func (ec *extractCommand) parse(args []string) error {
flags := flag.NewFlagSet("extract", flag.ExitOnError)
flags.Usage = usageExtract
flags.Var(&ec.sourceLanguage, "sourceLanguage", "en")
flags.StringVar(&ec.outdir, "outdir", ".", "")
flags.StringVar(&ec.format, "format", "toml", "")
- flags.Parse(args)
+ if err := flags.Parse(args); err != nil {
+ return err
+ }
ec.paths = flags.Args()
+ return nil
}
func (ec *extractCommand) execute() error {
diff --git a/v2/goi18n/extract_command_test.go b/goi18n/extract_command_test.go
index 4aacafa..4aacafa 100644
--- a/v2/goi18n/extract_command_test.go
+++ b/goi18n/extract_command_test.go
diff --git a/goi18n/gendoc.sh b/goi18n/gendoc.sh
deleted file mode 100644
index f30df34..0000000
--- a/goi18n/gendoc.sh
+++ /dev/null
@@ -1,12 +0,0 @@
-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 | sed -e 's/^/\/\/ /' >> doc.go
-goi18n merge -help | sed -e 's/^/\/\/ /' >> doc.go
-goi18n constants -help | sed -e 's/^/\/\/ /' >> doc.go
-echo "package main" >> doc.go
diff --git a/goi18n/goi18n.go b/goi18n/goi18n.go
deleted file mode 100644
index 3bd763f..0000000
--- a/goi18n/goi18n.go
+++ /dev/null
@@ -1,55 +0,0 @@
-package main
-
-import (
- "flag"
- "fmt"
- "os"
-)
-
-type command interface {
- execute() error
- parse(arguments []string)
-}
-
-func main() {
- flag.Usage = usage
-
- if len(os.Args) == 1 {
- usage()
- }
-
- var cmd command
-
- switch os.Args[1] {
- case "merge":
- cmd = &mergeCommand{}
- cmd.parse(os.Args[2:])
- case "constants":
- cmd = &constantsCommand{}
- cmd.parse(os.Args[2:])
- default:
- cmd = &mergeCommand{}
- cmd.parse(os.Args[1:])
- }
-
- if err := cmd.execute(); err != nil {
- fmt.Println(err.Error())
- os.Exit(1)
- }
-}
-
-func usage() {
- fmt.Printf(`goi18n manages translation files.
-
-Usage:
-
- goi18n merge Merge translation files
- goi18n constants Generate constant file from translation file
-
-For more details execute:
-
- goi18n [command] -help
-
-`)
- os.Exit(1)
-}
diff --git a/v2/goi18n/main.go b/goi18n/main.go
index 03e9240..f2f3d2c 100644
--- a/v2/goi18n/main.go
+++ b/goi18n/main.go
@@ -88,7 +88,7 @@ Workflow:
type command interface {
name() string
- parse(arguments []string)
+ parse(arguments []string) error
execute() error
}
@@ -116,7 +116,10 @@ func testableMain(args []string) int {
cmdName := flags.Arg(0)
for _, cmd := range commands {
if cmd.name() == cmdName {
- cmd.parse(flags.Args()[1:])
+ if err := cmd.parse(flags.Args()[1:]); err != nil {
+ fmt.Fprintln(os.Stderr, err)
+ return 1
+ }
if err := cmd.execute(); err != nil {
fmt.Fprintln(os.Stderr, err)
return 1
diff --git a/v2/goi18n/main_test.go b/goi18n/main_test.go
index 42d3a6a..42d3a6a 100644
--- a/v2/goi18n/main_test.go
+++ b/goi18n/main_test.go
diff --git a/v2/goi18n/marshal.go b/goi18n/marshal.go
index 751b698..751b698 100644
--- a/v2/goi18n/marshal.go
+++ b/goi18n/marshal.go
diff --git a/goi18n/merge_command.go b/goi18n/merge_command.go
index 1b9d04f..9765c6d 100644
--- a/goi18n/merge_command.go
+++ b/goi18n/merge_command.go
@@ -1,239 +1,295 @@
package main
import (
+ "crypto/sha1"
"encoding/json"
"flag"
"fmt"
+ "io"
"io/ioutil"
- "path/filepath"
- "reflect"
- "sort"
+ "os"
+
+ "github.com/BurntSushi/toml"
+ "github.com/nicksnyder/go-i18n/v2/i18n"
+ "github.com/nicksnyder/go-i18n/v2/internal"
+ "github.com/nicksnyder/go-i18n/v2/internal/plural"
+ "golang.org/x/text/language"
+ yaml "gopkg.in/yaml.v2"
+)
- "gopkg.in/yaml.v2"
+func usageMerge() {
+ fmt.Fprintf(os.Stderr, `usage: goi18n merge [options] [message files]
- "github.com/nicksnyder/go-i18n/i18n/bundle"
- "github.com/nicksnyder/go-i18n/i18n/language"
- "github.com/nicksnyder/go-i18n/i18n/translation"
- toml "github.com/pelletier/go-toml"
-)
+Merge reads all messages in the message files and produces two files per language.
-type mergeCommand struct {
- translationFiles []string
- sourceLanguage string
- outdir string
- format string
- flat bool
-}
+ xx-yy.active.format
+ This file contains messages that should be loaded at runtime.
-func (mc *mergeCommand) execute() error {
- if len(mc.translationFiles) < 1 {
- return fmt.Errorf("need at least one translation file to parse")
- }
+ xx-yy.translate.format
+ This file contains messages that are empty and should be translated.
- if lang := language.Parse(mc.sourceLanguage); lang == nil {
- return fmt.Errorf("invalid source locale: %s", mc.sourceLanguage)
- }
+Message 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.).
- bundle := bundle.New()
- for _, tf := range mc.translationFiles {
- if err := bundle.LoadTranslationFile(tf); err != nil {
- return fmt.Errorf("failed to load translation file %s: %s\n", tf, err)
- }
- }
+To add support for a new language, create an empty translation file with the
+appropriate name and pass it in to goi18n merge.
- translations := bundle.Translations()
- sourceLanguageTag := language.NormalizeTag(mc.sourceLanguage)
- 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()
- }
- }
- }
+Flags:
- 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); err != nil {
- return err
- }
+ -sourceLanguage tag
+ Translate messages from this language (e.g. en, en-US, zh-Hant-CN)
+ Default: en
- 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); err != nil {
- return err
- }
- }
- return nil
+ -outdir directory
+ Write message files to this directory.
+ Default: .
+
+ -format format
+ Output message files in this format.
+ Supported formats: json, toml, yaml
+ Default: toml
+`)
}
-func (mc *mergeCommand) parse(arguments []string) {
+type mergeCommand struct {
+ messageFiles []string
+ sourceLanguage languageTag
+ outdir string
+ format string
+}
+
+func (mc *mergeCommand) name() string {
+ return "merge"
+}
+
+func (mc *mergeCommand) parse(args []string) error {
flags := flag.NewFlagSet("merge", flag.ExitOnError)
flags.Usage = usageMerge
- sourceLanguage := flags.String("sourceLanguage", "en-us", "")
- outdir := flags.String("outdir", ".", "")
- format := flags.String("format", "json", "")
- flat := flags.Bool("flat", true, "")
-
- flags.Parse(arguments)
-
- mc.translationFiles = flags.Args()
- mc.sourceLanguage = *sourceLanguage
- mc.outdir = *outdir
- mc.format = *format
- if *format == "toml" {
- mc.flat = true
- } else {
- mc.flat = *flat
+ flags.Var(&mc.sourceLanguage, "sourceLanguage", "en")
+ flags.StringVar(&mc.outdir, "outdir", ".", "")
+ flags.StringVar(&mc.format, "format", "toml", "")
+ if err := flags.Parse(args); err != nil {
+ return err
}
-}
-func (mc *mergeCommand) SetArgs(args []string) {
- mc.translationFiles = args
+ mc.messageFiles = flags.Args()
+ return nil
}
-func (mc *mergeCommand) writeFile(label string, translations []translation.Translation, localeID string) error {
- sort.Sort(translation.SortableByID(translations))
-
- var convert func([]translation.Translation) interface{}
- if mc.flat {
- convert = marshalFlatInterface
- } else {
- convert = marshalInterface
+func (mc *mergeCommand) execute() error {
+ if len(mc.messageFiles) < 1 {
+ return fmt.Errorf("need at least one message file to parse")
}
-
- buf, err := mc.marshal(convert(translations))
+ inFiles := make(map[string][]byte)
+ for _, path := range mc.messageFiles {
+ content, err := ioutil.ReadFile(path)
+ if err != nil {
+ return err
+ }
+ inFiles[path] = content
+ }
+ ops, err := merge(inFiles, mc.sourceLanguage.Tag(), mc.outdir, mc.format)
if err != nil {
- return fmt.Errorf("failed to marshal %s strings to %s: %s", localeID, mc.format, err)
+ return 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: %s", filename, err)
+ for path, content := range ops.writeFiles {
+ if err := ioutil.WriteFile(path, content, 0666); err != nil {
+ return err
+ }
+ }
+ for _, path := range ops.deleteFiles {
+ // Ignore error since it isn't guaranteed to exist.
+ os.Remove(path)
}
return nil
}
-func filter(translations map[string]translation.Translation, f func(translation.Translation) translation.Translation) []translation.Translation {
- filtered := make([]translation.Translation, 0, len(translations))
- for _, translation := range translations {
- if t := f(translation); t != nil {
- filtered = append(filtered, t)
+type fileSystemOp struct {
+ writeFiles map[string][]byte
+ deleteFiles []string
+}
+
+func merge(messageFiles map[string][]byte, sourceLanguageTag language.Tag, outdir, outputFormat string) (*fileSystemOp, error) {
+ unmerged := make(map[language.Tag][]map[string]*i18n.MessageTemplate)
+ sourceMessageTemplates := make(map[string]*i18n.MessageTemplate)
+ unmarshalFuncs := map[string]i18n.UnmarshalFunc{
+ "json": json.Unmarshal,
+ "toml": toml.Unmarshal,
+ "yaml": yaml.Unmarshal,
+ }
+ for path, content := range messageFiles {
+ mf, err := i18n.ParseMessageFileBytes(content, path, unmarshalFuncs)
+ if err != nil {
+ return nil, fmt.Errorf("failed to load message file %s: %s", path, err)
+ }
+ templates := map[string]*i18n.MessageTemplate{}
+ for _, m := range mf.Messages {
+ templates[m.ID] = i18n.NewMessageTemplate(m)
+ }
+ if mf.Tag == sourceLanguageTag {
+ for _, template := range templates {
+ if sourceMessageTemplates[template.ID] != nil {
+ return nil, fmt.Errorf("multiple source translations for id %s", template.ID)
+ }
+ template.Hash = hash(template)
+ sourceMessageTemplates[template.ID] = template
+ }
}
+ unmerged[mf.Tag] = append(unmerged[mf.Tag], templates)
}
- return filtered
-}
+ if len(sourceMessageTemplates) == 0 {
+ return nil, fmt.Errorf("no messages found for source locale %s", sourceLanguageTag)
+ }
+
+ pluralRules := plural.DefaultRules()
+ all := make(map[language.Tag]map[string]*i18n.MessageTemplate)
+ all[sourceLanguageTag] = sourceMessageTemplates
+ for _, srcTemplate := range sourceMessageTemplates {
+ for dstLangTag, messageTemplates := range unmerged {
+ if dstLangTag == sourceLanguageTag {
+ continue
+ }
+ pluralRule := pluralRules.Rule(dstLangTag)
+ if pluralRule == nil {
+ // Non-standard languages not supported because
+ // we don't know if translations are complete or not.
+ continue
+ }
+ if all[dstLangTag] == nil {
+ all[dstLangTag] = make(map[string]*i18n.MessageTemplate)
+ }
+ dstMessageTemplate := all[dstLangTag][srcTemplate.ID]
+ if dstMessageTemplate == nil {
+ dstMessageTemplate = &i18n.MessageTemplate{
+ Message: &i18n.Message{
+ ID: srcTemplate.ID,
+ Description: srcTemplate.Description,
+ Hash: srcTemplate.Hash,
+ },
+ PluralTemplates: make(map[plural.Form]*internal.Template),
+ }
+ all[dstLangTag][srcTemplate.ID] = dstMessageTemplate
+ }
-func marshalFlatInterface(translations []translation.Translation) interface{} {
- mi := make(map[string]interface{}, len(translations))
- for _, translation := range translations {
- mi[translation.ID()] = translation.MarshalFlatInterface()
+ // Check all unmerged message templates for this message id.
+ for _, messageTemplates := range messageTemplates {
+ unmergedTemplate := messageTemplates[srcTemplate.ID]
+ if unmergedTemplate == nil {
+ continue
+ }
+ // Ignore empty hashes for v1 backward compatibility.
+ if unmergedTemplate.Hash != "" && unmergedTemplate.Hash != srcTemplate.Hash {
+ // This was translated from different content so discard.
+ continue
+ }
+
+ // Merge in the translated messages.
+ for pluralForm := range pluralRule.PluralForms {
+ dt := unmergedTemplate.PluralTemplates[pluralForm]
+ if dt != nil && dt.Src != "" {
+ dstMessageTemplate.PluralTemplates[pluralForm] = dt
+ }
+ }
+ }
+ }
}
- return mi
-}
-func marshalInterface(translations []translation.Translation) interface{} {
- mi := make([]interface{}, len(translations))
- for i, translation := range translations {
- mi[i] = translation.MarshalInterface()
+ translate := make(map[language.Tag]map[string]*i18n.MessageTemplate)
+ active := make(map[language.Tag]map[string]*i18n.MessageTemplate)
+ for langTag, messageTemplates := range all {
+ active[langTag] = make(map[string]*i18n.MessageTemplate)
+ if langTag == sourceLanguageTag {
+ active[langTag] = messageTemplates
+ continue
+ }
+ pluralRule := pluralRules.Rule(langTag)
+ if pluralRule == nil {
+ // Non-standard languages not supported because
+ // we don't know if translations are complete or not.
+ continue
+ }
+ for _, messageTemplate := range messageTemplates {
+ srcMessageTemplate := sourceMessageTemplates[messageTemplate.ID]
+ activeMessageTemplate, translateMessageTemplate := activeDst(srcMessageTemplate, messageTemplate, pluralRule)
+ if translateMessageTemplate != nil {
+ if translate[langTag] == nil {
+ translate[langTag] = make(map[string]*i18n.MessageTemplate)
+ }
+ translate[langTag][messageTemplate.ID] = translateMessageTemplate
+ }
+ if activeMessageTemplate != nil {
+ active[langTag][messageTemplate.ID] = activeMessageTemplate
+ }
+ }
}
- return mi
-}
-func (mc mergeCommand) marshal(v interface{}) ([]byte, error) {
- switch mc.format {
- case "json":
- return json.MarshalIndent(v, "", " ")
- case "toml":
- return marshalTOML(v)
- case "yaml":
- return yaml.Marshal(v)
+ writeFiles := make(map[string][]byte, len(translate)+len(active))
+ for langTag, messageTemplates := range translate {
+ path, content, err := writeFile(outdir, "translate", langTag, outputFormat, messageTemplates, false)
+ if err != nil {
+ return nil, err
+ }
+ writeFiles[path] = content
}
- return nil, fmt.Errorf("unsupported format: %s\n", mc.format)
+ deleteFiles := []string{}
+ for langTag, messageTemplates := range active {
+ path, content, err := writeFile(outdir, "active", langTag, outputFormat, messageTemplates, langTag == sourceLanguageTag)
+ if err != nil {
+ return nil, err
+ }
+ if len(content) > 0 {
+ writeFiles[path] = content
+ } else {
+ deleteFiles = append(deleteFiles, path)
+ }
+ }
+ return &fileSystemOp{writeFiles: writeFiles, deleteFiles: deleteFiles}, nil
}
-func marshalTOML(v interface{}) ([]byte, error) {
- m, ok := v.(map[string]interface{})
- if !ok {
- return nil, fmt.Errorf("invalid format for marshaling to TOML")
+// activeDst returns the active part of the dst and whether dst is a complete translation of src.
+func activeDst(src, dst *i18n.MessageTemplate, pluralRule *plural.Rule) (active *i18n.MessageTemplate, translateMessageTemplate *i18n.MessageTemplate) {
+ pluralForms := pluralRule.PluralForms
+ if len(src.PluralTemplates) == 1 {
+ pluralForms = map[plural.Form]struct{}{
+ plural.Other: {},
+ }
}
- tree, err := toml.TreeFromMap(m)
- if err != nil {
- return nil, err
+ for pluralForm := range pluralForms {
+ dt := dst.PluralTemplates[pluralForm]
+ if dt == nil || dt.Src == "" {
+ if translateMessageTemplate == nil {
+ translateMessageTemplate = &i18n.MessageTemplate{
+ Message: &i18n.Message{
+ ID: src.ID,
+ Description: src.Description,
+ Hash: src.Hash,
+ },
+ PluralTemplates: make(map[plural.Form]*internal.Template),
+ }
+ }
+ translateMessageTemplate.PluralTemplates[pluralForm] = src.PluralTemplates[plural.Other]
+ continue
+ }
+ if active == nil {
+ active = &i18n.MessageTemplate{
+ Message: &i18n.Message{
+ ID: src.ID,
+ Description: src.Description,
+ Hash: src.Hash,
+ },
+ PluralTemplates: make(map[plural.Form]*internal.Template),
+ }
+ }
+ active.PluralTemplates[pluralForm] = dt
}
- s, err := tree.ToTomlString()
- return []byte(s), err
+ return
}
-func usageMerge() {
- fmt.Printf(`Merge translation files.
-
-Usage:
-
- goi18n merge [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, toml, yaml
- Default: json
-
- -flat
- goi18n writes the output translation files in flat format.
- Usage of '-format toml' automitically sets this flag.
- Default: true
-
-`)
+func hash(t *i18n.MessageTemplate) string {
+ h := sha1.New()
+ _, _ = io.WriteString(h, t.Description)
+ _, _ = io.WriteString(h, t.PluralTemplates[plural.Other].Src)
+ return fmt.Sprintf("sha1-%x", h.Sum(nil))
}
diff --git a/goi18n/merge_command_flat_test.go b/goi18n/merge_command_flat_test.go
deleted file mode 100644
index caa892d..0000000
--- a/goi18n/merge_command_flat_test.go
+++ /dev/null
@@ -1,36 +0,0 @@
-package main
-
-import "testing"
-
-func TestMergeExecuteFlat(t *testing.T) {
- files := []string{
- "testdata/input/flat/en-us.one.yaml",
- "testdata/input/flat/en-us.two.json",
- "testdata/input/flat/fr-fr.json",
- "testdata/input/flat/ar-ar.one.toml",
- "testdata/input/flat/ar-ar.two.json",
- }
- testFlatMergeExecute(t, files)
-}
-
-func testFlatMergeExecute(t *testing.T, files []string) {
- resetDir(t, "testdata/output/flat")
-
- mc := &mergeCommand{
- translationFiles: files,
- sourceLanguage: "en-us",
- outdir: "testdata/output/flat",
- format: "json",
- flat: true,
- }
- if err := mc.execute(); err != nil {
- t.Fatal(err)
- }
-
- expectEqualFiles(t, "testdata/output/flat/en-us.all.json", "testdata/expected/flat/en-us.all.json")
- expectEqualFiles(t, "testdata/output/flat/ar-ar.all.json", "testdata/expected/flat/ar-ar.all.json")
- expectEqualFiles(t, "testdata/output/flat/fr-fr.all.json", "testdata/expected/flat/fr-fr.all.json")
- expectEqualFiles(t, "testdata/output/flat/en-us.untranslated.json", "testdata/expected/flat/en-us.untranslated.json")
- expectEqualFiles(t, "testdata/output/flat/ar-ar.untranslated.json", "testdata/expected/flat/ar-ar.untranslated.json")
- expectEqualFiles(t, "testdata/output/flat/fr-fr.untranslated.json", "testdata/expected/flat/fr-fr.untranslated.json")
-}
diff --git a/goi18n/merge_command_test.go b/goi18n/merge_command_test.go
index 425a6b6..ff7c221 100644
--- a/goi18n/merge_command_test.go
+++ b/goi18n/merge_command_test.go
@@ -4,72 +4,560 @@ import (
"bytes"
"io/ioutil"
"os"
+ "path/filepath"
"testing"
+
+ "golang.org/x/text/language"
)
-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)
+type testCase struct {
+ name string
+ inFiles map[string][]byte
+ sourceLanguage language.Tag
+ outFiles map[string][]byte
+ deleteFiles []string
}
-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 expectFile(s string) []byte {
+ // Trimming leading newlines gives nicer formatting for file literals in test cases.
+ return bytes.TrimLeft([]byte(s), "\n")
}
-func testMergeExecute(t *testing.T, files []string) {
- resetDir(t, "testdata/output")
-
- mc := &mergeCommand{
- translationFiles: files,
- sourceLanguage: "en-us",
- outdir: "testdata/output",
- format: "json",
- flat: false,
+func TestMerge(t *testing.T) {
+ testCases := []*testCase{
+ {
+ name: "single identity",
+ sourceLanguage: language.AmericanEnglish,
+ inFiles: map[string][]byte{
+ "one.en-US.toml": []byte("1HelloMessage = \"Hello\"\n"),
+ },
+ outFiles: map[string][]byte{
+ "active.en-US.toml": []byte("1HelloMessage = \"Hello\"\n"),
+ },
+ },
+ {
+ name: "plural identity",
+ sourceLanguage: language.AmericanEnglish,
+ inFiles: map[string][]byte{
+ "active.en-US.toml": []byte(`
+[UnreadEmails]
+description = "Message that tells the user how many unread emails they have"
+one = "{{.Count}} unread email"
+other = "{{.Count}} unread emails"
+`),
+ },
+ outFiles: map[string][]byte{
+ "active.en-US.toml": expectFile(`
+[UnreadEmails]
+description = "Message that tells the user how many unread emails they have"
+one = "{{.Count}} unread email"
+other = "{{.Count}} unread emails"
+`),
+ },
+ },
+ {
+ name: "migrate source lang from v1 format",
+ sourceLanguage: language.AmericanEnglish,
+ inFiles: map[string][]byte{
+ "one.en-US.json": []byte(`[
+ {
+ "id": "simple",
+ "translation": "simple translation"
+ },
+ {
+ "id": "everything",
+ "translation": {
+ "zero": "zero translation",
+ "one": "one translation",
+ "two": "two translation",
+ "few": "few translation",
+ "many": "many translation",
+ "other": "other translation"
+ }
}
- if err := mc.execute(); err != nil {
- t.Fatal(err)
+]`),
+ },
+ outFiles: map[string][]byte{
+ "active.en-US.toml": expectFile(`
+simple = "simple translation"
+
+[everything]
+few = "few translation"
+many = "many translation"
+one = "one translation"
+other = "other translation"
+two = "two translation"
+zero = "zero translation"
+`),
+ },
+ },
+ {
+ name: "migrate source lang from v1 flat format",
+ sourceLanguage: language.AmericanEnglish,
+ inFiles: map[string][]byte{
+ "one.en-US.json": []byte(`{
+ "simple": {
+ "other": "simple translation"
+ },
+ "everything": {
+ "zero": "zero translation",
+ "one": "one translation",
+ "two": "two translation",
+ "few": "few translation",
+ "many": "many translation",
+ "other": "other translation"
}
+}`),
+ },
+ outFiles: map[string][]byte{
+ "active.en-US.toml": expectFile(`
+simple = "simple translation"
- 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")
-}
+[everything]
+few = "few translation"
+many = "many translation"
+one = "one translation"
+other = "other translation"
+two = "two translation"
+zero = "zero translation"
+`),
+ },
+ },
+ {
+ name: "merge source files",
+ sourceLanguage: language.AmericanEnglish,
+ inFiles: map[string][]byte{
+ "one.en-US.toml": []byte("1HelloMessage = \"Hello\"\n"),
+ "two.en-US.toml": []byte("2GoodbyeMessage = \"Goodbye\"\n"),
+ },
+ outFiles: map[string][]byte{
+ "active.en-US.toml": []byte("1HelloMessage = \"Hello\"\n2GoodbyeMessage = \"Goodbye\"\n"),
+ },
+ },
+ {
+ name: "missing hash",
+ sourceLanguage: language.AmericanEnglish,
+ inFiles: map[string][]byte{
+ "en-US.toml": []byte(`
+1HelloMessage = "Hello"
+`),
+ "es-ES.toml": []byte(`
+[1HelloMessage]
+other = "Hola"
+`),
+ },
+ outFiles: map[string][]byte{
+ "active.en-US.toml": expectFile(`
+1HelloMessage = "Hello"
+`),
+ "active.es-ES.toml": expectFile(`
+[1HelloMessage]
+hash = "sha1-f7ff9e8b7bb2e09b70935a5d785e0cc5d9d0abf0"
+other = "Hola"
+`),
+ },
+ },
+ {
+ name: "add single translation",
+ sourceLanguage: language.AmericanEnglish,
+ inFiles: map[string][]byte{
+ "en-US.toml": []byte(`
+1HelloMessage = "Hello"
+2GoodbyeMessage = "Goodbye"
+`),
+ "es-ES.toml": []byte(`
+[1HelloMessage]
+hash = "sha1-f7ff9e8b7bb2e09b70935a5d785e0cc5d9d0abf0"
+other = "Hola"
+`),
+ },
+ outFiles: map[string][]byte{
+ "active.en-US.toml": expectFile(`
+1HelloMessage = "Hello"
+2GoodbyeMessage = "Goodbye"
+`),
+ "active.es-ES.toml": expectFile(`
+[1HelloMessage]
+hash = "sha1-f7ff9e8b7bb2e09b70935a5d785e0cc5d9d0abf0"
+other = "Hola"
+`),
+ "translate.es-ES.toml": expectFile(`
+[2GoodbyeMessage]
+hash = "sha1-b5b29c53e3c71cb9c6581ab053d7758fab8ca24d"
+other = "Goodbye"
+`),
+ },
+ },
+ {
+ name: "remove single translation",
+ sourceLanguage: language.AmericanEnglish,
+ inFiles: map[string][]byte{
+ "en-US.toml": []byte(`
+1HelloMessage = "Hello"
+`),
+ "es-ES.toml": []byte(`
+[1HelloMessage]
+hash = "sha1-f7ff9e8b7bb2e09b70935a5d785e0cc5d9d0abf0"
+other = "Hola"
-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)
- }
-}
+[2GoodbyeMessage]
+hash = "sha1-b5b29c53e3c71cb9c6581ab053d7758fab8ca24d"
+other = "Goodbye"
+`),
+ },
+ outFiles: map[string][]byte{
+ "active.en-US.toml": expectFile(`
+1HelloMessage = "Hello"
+`),
+ "active.es-ES.toml": expectFile(`
+[1HelloMessage]
+hash = "sha1-f7ff9e8b7bb2e09b70935a5d785e0cc5d9d0abf0"
+other = "Hola"
+`),
+ },
+ },
+ {
+ name: "edit single translation",
+ sourceLanguage: language.AmericanEnglish,
+ inFiles: map[string][]byte{
+ "en-US.toml": []byte(`
+1HelloMessage = "Hi"
+`),
+ "es-ES.toml": []byte(`
+[1HelloMessage]
+hash = "sha1-f7ff9e8b7bb2e09b70935a5d785e0cc5d9d0abf0"
+other = "Hola"
+`),
+ },
+ outFiles: map[string][]byte{
+ "active.en-US.toml": expectFile(`
+1HelloMessage = "Hi"
+`),
+ "translate.es-ES.toml": expectFile(`
+[1HelloMessage]
+hash = "sha1-94dd9e08c129c785f7f256e82fbe0a30e6d1ae40"
+other = "Hi"
+`),
+ },
+ },
+ {
+ name: "add plural translation",
+ sourceLanguage: language.AmericanEnglish,
+ inFiles: map[string][]byte{
+ "en-US.toml": []byte(`
+[UnreadEmails]
+description = "Message that tells the user how many unread emails they have"
+one = "{{.Count}} unread email"
+other = "{{.Count}} unread emails"
+`),
+ "es-ES.toml": nil,
+ "ar-AR.toml": nil,
+ "zh-CN.toml": nil,
+ },
+ outFiles: map[string][]byte{
+ "active.en-US.toml": expectFile(`
+[UnreadEmails]
+description = "Message that tells the user how many unread emails they have"
+one = "{{.Count}} unread email"
+other = "{{.Count}} unread emails"
+`),
+ "translate.es-ES.toml": expectFile(`
+[UnreadEmails]
+description = "Message that tells the user how many unread emails they have"
+hash = "sha1-5afbc91dfedb9755627655c365eb47a89e541099"
+one = "{{.Count}} unread emails"
+other = "{{.Count}} unread emails"
+`),
+ "translate.ar-AR.toml": expectFile(`
+[UnreadEmails]
+description = "Message that tells the user how many unread emails they have"
+few = "{{.Count}} unread emails"
+hash = "sha1-5afbc91dfedb9755627655c365eb47a89e541099"
+many = "{{.Count}} unread emails"
+one = "{{.Count}} unread emails"
+other = "{{.Count}} unread emails"
+two = "{{.Count}} unread emails"
+zero = "{{.Count}} unread emails"
+`),
+ "translate.zh-CN.toml": expectFile(`
+[UnreadEmails]
+description = "Message that tells the user how many unread emails they have"
+hash = "sha1-5afbc91dfedb9755627655c365eb47a89e541099"
+other = "{{.Count}} unread emails"
+`),
+ },
+ },
+ {
+ name: "remove plural translation",
+ sourceLanguage: language.AmericanEnglish,
+ inFiles: map[string][]byte{
+ "en-US.toml": []byte(`
+1HelloMessage = "Hello"
+`),
+ "es-ES.toml": []byte(`
+[1HelloMessage]
+hash = "sha1-f7ff9e8b7bb2e09b70935a5d785e0cc5d9d0abf0"
+other = "Hola"
-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)
+[UnreadEmails]
+description = "Message that tells the user how many unread emails they have"
+hash = "sha1-5afbc91dfedb9755627655c365eb47a89e541099"
+one = "{{.Count}} unread emails"
+other = "{{.Count}} unread emails"
+`),
+ "ar-AR.toml": []byte(`
+[1HelloMessage]
+hash = "sha1-f7ff9e8b7bb2e09b70935a5d785e0cc5d9d0abf0"
+other = "Hello"
+
+[UnreadEmails]
+description = "Message that tells the user how many unread emails they have"
+few = "{{.Count}} unread emails"
+hash = "sha1-5afbc91dfedb9755627655c365eb47a89e541099"
+many = "{{.Count}} unread emails"
+one = "{{.Count}} unread emails"
+other = "{{.Count}} unread emails"
+two = "{{.Count}} unread emails"
+zero = "{{.Count}} unread emails"
+`),
+ "zh-CN.toml": []byte(`
+[1HelloMessage]
+hash = "sha1-f7ff9e8b7bb2e09b70935a5d785e0cc5d9d0abf0"
+other = "Hello"
+
+[UnreadEmails]
+description = "Message that tells the user how many unread emails they have"
+hash = "sha1-5afbc91dfedb9755627655c365eb47a89e541099"
+other = "{{.Count}} unread emails"
+`),
+ },
+ outFiles: map[string][]byte{
+ "active.en-US.toml": expectFile(`
+1HelloMessage = "Hello"
+`),
+ "active.es-ES.toml": expectFile(`
+[1HelloMessage]
+hash = "sha1-f7ff9e8b7bb2e09b70935a5d785e0cc5d9d0abf0"
+other = "Hola"
+`),
+ "active.ar-AR.toml": expectFile(`
+[1HelloMessage]
+hash = "sha1-f7ff9e8b7bb2e09b70935a5d785e0cc5d9d0abf0"
+other = "Hello"
+`),
+ "active.zh-CN.toml": expectFile(`
+[1HelloMessage]
+hash = "sha1-f7ff9e8b7bb2e09b70935a5d785e0cc5d9d0abf0"
+other = "Hello"
+`),
+ },
+ },
+ {
+ name: "edit plural translation",
+ sourceLanguage: language.AmericanEnglish,
+ inFiles: map[string][]byte{
+ "en-US.toml": []byte(`
+[UnreadEmails]
+description = "Message that tells the user how many unread emails they have"
+one = "{{.Count}} unread emails!"
+other = "{{.Count}} unread emails!"
+`),
+ "es-ES.toml": []byte(`
+[UnreadEmails]
+description = "Message that tells the user how many unread emails they have"
+hash = "sha1-5afbc91dfedb9755627655c365eb47a89e541099"
+one = "{{.Count}} unread emails"
+other = "{{.Count}} unread emails"
+`),
+ "ar-AR.toml": []byte(`
+[UnreadEmails]
+description = "Message that tells the user how many unread emails they have"
+few = "{{.Count}} unread emails"
+hash = "sha1-5afbc91dfedb9755627655c365eb47a89e541099"
+many = "{{.Count}} unread emails"
+one = "{{.Count}} unread emails"
+other = "{{.Count}} unread emails"
+two = "{{.Count}} unread emails"
+zero = "{{.Count}} unread emails"
+`),
+ "zh-CN.toml": []byte(`
+[UnreadEmails]
+description = "Message that tells the user how many unread emails they have"
+hash = "sha1-5afbc91dfedb9755627655c365eb47a89e541099"
+other = "{{.Count}} unread emails"
+`),
+ },
+ deleteFiles: []string{
+ "active.es-ES.toml",
+ "active.ar-AR.toml",
+ "active.zh-CN.toml",
+ },
+ outFiles: map[string][]byte{
+ "active.en-US.toml": expectFile(`
+[UnreadEmails]
+description = "Message that tells the user how many unread emails they have"
+one = "{{.Count}} unread emails!"
+other = "{{.Count}} unread emails!"
+`),
+ "translate.es-ES.toml": expectFile(`
+[UnreadEmails]
+description = "Message that tells the user how many unread emails they have"
+hash = "sha1-92a24983c5bbc0c42462cdc252dca68ebdb46501"
+one = "{{.Count}} unread emails!"
+other = "{{.Count}} unread emails!"
+`),
+ "translate.ar-AR.toml": expectFile(`
+[UnreadEmails]
+description = "Message that tells the user how many unread emails they have"
+few = "{{.Count}} unread emails!"
+hash = "sha1-92a24983c5bbc0c42462cdc252dca68ebdb46501"
+many = "{{.Count}} unread emails!"
+one = "{{.Count}} unread emails!"
+other = "{{.Count}} unread emails!"
+two = "{{.Count}} unread emails!"
+zero = "{{.Count}} unread emails!"
+`),
+ "translate.zh-CN.toml": expectFile(`
+[UnreadEmails]
+description = "Message that tells the user how many unread emails they have"
+hash = "sha1-92a24983c5bbc0c42462cdc252dca68ebdb46501"
+other = "{{.Count}} unread emails!"
+`),
+ },
+ },
+ {
+ name: "merge plural translation",
+ sourceLanguage: language.AmericanEnglish,
+ inFiles: map[string][]byte{
+ "en-US.toml": []byte(`
+[UnreadEmails]
+description = "Message that tells the user how many unread emails they have"
+one = "{{.Count}} unread emails"
+other = "{{.Count}} unread emails"
+`),
+ "zero.ar-AR.toml": []byte(`
+[UnreadEmails]
+description = "Message that tells the user how many unread emails they have"
+hash = "sha1-5afbc91dfedb9755627655c365eb47a89e541099"
+zero = "{{.Count}} unread emails"
+`),
+ "one.ar-AR.toml": []byte(`
+[UnreadEmails]
+description = "Message that tells the user how many unread emails they have"
+hash = "sha1-5afbc91dfedb9755627655c365eb47a89e541099"
+one = "{{.Count}} unread emails"
+`),
+ "two.ar-AR.toml": []byte(`
+[UnreadEmails]
+description = "Message that tells the user how many unread emails they have"
+hash = "sha1-5afbc91dfedb9755627655c365eb47a89e541099"
+two = "{{.Count}} unread emails"
+`),
+ "few.ar-AR.toml": []byte(`
+[UnreadEmails]
+description = "Message that tells the user how many unread emails they have"
+few = "{{.Count}} unread emails"
+hash = "sha1-5afbc91dfedb9755627655c365eb47a89e541099"
+`),
+ "many.ar-AR.toml": []byte(`
+[UnreadEmails]
+description = "Message that tells the user how many unread emails they have"
+hash = "sha1-5afbc91dfedb9755627655c365eb47a89e541099"
+many = "{{.Count}} unread emails"
+`),
+ "other.ar-AR.toml": []byte(`
+[UnreadEmails]
+description = "Message that tells the user how many unread emails they have"
+hash = "sha1-5afbc91dfedb9755627655c365eb47a89e541099"
+other = "{{.Count}} unread emails"
+`),
+ },
+ outFiles: map[string][]byte{
+ "active.en-US.toml": expectFile(`
+[UnreadEmails]
+description = "Message that tells the user how many unread emails they have"
+one = "{{.Count}} unread emails"
+other = "{{.Count}} unread emails"
+`),
+ "active.ar-AR.toml": expectFile(`
+[UnreadEmails]
+description = "Message that tells the user how many unread emails they have"
+few = "{{.Count}} unread emails"
+hash = "sha1-5afbc91dfedb9755627655c365eb47a89e541099"
+many = "{{.Count}} unread emails"
+one = "{{.Count}} unread emails"
+other = "{{.Count}} unread emails"
+two = "{{.Count}} unread emails"
+zero = "{{.Count}} unread emails"
+`),
+ },
+ },
}
- if !bytes.Equal(actual, expected) {
- t.Errorf("contents of files did not match: %s, %s", expectedName, actualName)
+
+ for _, testCase := range testCases {
+ t.Run(testCase.name, func(t *testing.T) {
+ indir := mustTempDir("TestMergeCommandIn")
+ defer os.RemoveAll(indir)
+ outdir := mustTempDir("TestMergeCommandOut")
+ defer os.RemoveAll(outdir)
+
+ infiles := make([]string, 0, len(testCase.inFiles))
+ for name, content := range testCase.inFiles {
+ path := filepath.Join(indir, name)
+ infiles = append(infiles, path)
+ if err := ioutil.WriteFile(path, content, 0666); err != nil {
+ t.Fatal(err)
+ }
+ }
+
+ for _, name := range testCase.deleteFiles {
+ path := filepath.Join(outdir, name)
+ if err := ioutil.WriteFile(path, []byte(`this file should get deleted`), 0666); err != nil {
+ t.Fatal(err)
+ }
+ }
+
+ args := append([]string{"merge", "-sourceLanguage", testCase.sourceLanguage.String(), "-outdir", outdir}, infiles...)
+ if code := testableMain(args); code != 0 {
+ t.Fatalf("expected exit code 0; got %d\n", code)
+ }
+
+ files, err := ioutil.ReadDir(outdir)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // Verify that all actual files have expected contents.
+ actualFiles := make(map[string]struct{}, len(files))
+ for _, f := range files {
+ actualFiles[f.Name()] = struct{}{}
+ if f.IsDir() {
+ t.Errorf("found unexpected dir %s", f.Name())
+ continue
+ }
+ path := filepath.Join(outdir, f.Name())
+ actual, err := ioutil.ReadFile(path)
+ if err != nil {
+ t.Error(err)
+ continue
+ }
+ expected, ok := testCase.outFiles[f.Name()]
+ if !ok {
+ t.Errorf("found unexpected file %s with contents:\n%s\n", f.Name(), actual)
+ continue
+ }
+ if !bytes.Equal(actual, expected) {
+ t.Errorf("unexpected contents %s\ngot\n%s\nexpected\n%s", f.Name(), actual, expected)
+ continue
+ }
+ }
+
+ // Verify that all expected files are accounted for.
+ for name := range testCase.outFiles {
+ if _, ok := actualFiles[name]; !ok {
+ t.Errorf("did not find expected file %s", name)
+ }
+ }
+ })
}
}
diff --git a/goi18n/testdata/en-us.flat.json b/goi18n/testdata/en-us.flat.json
deleted file mode 100644
index f67d21c..0000000
--- a/goi18n/testdata/en-us.flat.json
+++ /dev/null
@@ -1,34 +0,0 @@
-{
- "program_greeting": {
- "other": "Hello world"
- },
-
- "person_greeting": {
- "other": "Hello {{.Person}}"
- },
-
- "my_height_in_meters": {
- "one": "I am {{.Count}} meter tall.",
- "other": "I am {{.Count}} meters tall."
- },
-
- "your_unread_email_count": {
- "one": "You have {{.Count}} unread email.",
- "other": "You have {{.Count}} unread emails."
- },
-
- "person_unread_email_count": {
- "one": "{{.Person}} has {{.Count}} unread email.",
- "other": "{{.Person}} has {{.Count}} unread emails."
- },
-
- "person_unread_email_count_timeframe": {
- "one": "{{.Person}} has {{.Count}} unread email in the past {{.Timeframe}}.",
- "other": "{{.Person}} has {{.Count}} unread emails in the past {{.Timeframe}}."
- },
-
- "d_days": {
- "one": "{{.Count}} day.",
- "other": "{{.Count}} days."
- }
-}
diff --git a/goi18n/testdata/en-us.flat.toml b/goi18n/testdata/en-us.flat.toml
deleted file mode 100644
index 5623a6c..0000000
--- a/goi18n/testdata/en-us.flat.toml
+++ /dev/null
@@ -1,25 +0,0 @@
-[program_greeting]
-other = "Hello world"
-
-[person_greeting]
-other = "Hello {{.Person}}"
-
-[my_height_in_meters]
-one = "I am {{.Count}} meter tall."
-other = "I am {{.Count}} meters tall."
-
-[your_unread_email_count]
-one = "You have {{.Count}} unread email."
-other = "You have {{.Count}} unread emails."
-
-[person_unread_email_count]
-one = "{{.Person}} has {{.Count}} unread email."
-other = "{{.Person}} has {{.Count}} unread emails."
-
-[person_unread_email_count_timeframe]
-one = "{{.Person}} has {{.Count}} unread email in the past {{.Timeframe}}."
-other = "{{.Person}} has {{.Count}} unread emails in the past {{.Timeframe}}."
-
-[d_days]
-one = "{{.Count}} day"
-other = "{{.Count}} days"
diff --git a/goi18n/testdata/en-us.flat.yaml b/goi18n/testdata/en-us.flat.yaml
deleted file mode 100644
index 6641289..0000000
--- a/goi18n/testdata/en-us.flat.yaml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-# Comment
-# Comment
-program_greeting:
- other: "Hello world"
-
-person_greeting:
- other: "Hello {{.Person}}"
-
-my_height_in_meters:
- one: "I am {{.Count}} meter tall."
- other: "I am {{.Count}} meters tall."
-
-your_unread_email_count:
- one: "You have {{.Count}} unread email."
- other: "You have {{.Count}} unread emails."
-
-person_unread_email_count:
- one: "{{.Person}} has {{.Count}} unread email."
- other: "{{.Person}} has {{.Count}} unread emails."
-
-person_unread_email_count_timeframe:
- one: "{{.Person}} has {{.Count}} unread email in the past {{.Timeframe}}."
- other: "{{.Person}} has {{.Count}} unread emails in the past {{.Timeframe}}."
-
-d_days:
- one: "{{.Count}} day"
- other: "{{.Count}} days"
diff --git a/goi18n/testdata/en-us.yaml b/goi18n/testdata/en-us.yaml
deleted file mode 100644
index a8f5ed9..0000000
--- a/goi18n/testdata/en-us.yaml
+++ /dev/null
@@ -1,35 +0,0 @@
-
-
-
-# Comment
-# Comment
-- 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/goi18n/testdata/expected/R.go b/goi18n/testdata/expected/R.go
deleted file mode 100644
index 9b5334a..0000000
--- a/goi18n/testdata/expected/R.go
+++ /dev/null
@@ -1,38 +0,0 @@
-// DON'T CHANGE THIS FILE MANUALLY
-// This file was generated using the command:
-// $ goi18n constants
-
-package R
-
-// DDays is the identifier for the following localizable string template(s):
-// one: "{{.Count}} day"
-// other: "{{.Count}} days"
-const DDays = "d_days"
-
-// MyHeightInMeters is the identifier for the following localizable string template(s):
-// one: "I am {{.Count}} meter tall."
-// other: "I am {{.Count}} meters tall."
-const MyHeightInMeters = "my_height_in_meters"
-
-// PersonGreeting is the identifier for the following localizable string template(s):
-// "Hello {{.Person}}"
-const PersonGreeting = "person_greeting"
-
-// PersonUnreadEmailCount is the identifier for the following localizable string template(s):
-// one: "{{.Person}} has {{.Count}} unread email."
-// other: "{{.Person}} has {{.Count}} unread emails."
-const PersonUnreadEmailCount = "person_unread_email_count"
-
-// PersonUnreadEmailCountTimeframe is the identifier for the following localizable string template(s):
-// one: "{{.Person}} has {{.Count}} unread email in the past {{.Timeframe}}."
-// other: "{{.Person}} has {{.Count}} unread emails in the past {{.Timeframe}}."
-const PersonUnreadEmailCountTimeframe = "person_unread_email_count_timeframe"
-
-// ProgramGreeting is the identifier for the following localizable string template(s):
-// "Hello world"
-const ProgramGreeting = "program_greeting"
-
-// YourUnreadEmailCount is the identifier for the following localizable string template(s):
-// one: "You have {{.Count}} unread email."
-// other: "You have {{.Count}} unread emails."
-const YourUnreadEmailCount = "your_unread_email_count"
diff --git a/goi18n/testdata/expected/ar-ar.all.json b/goi18n/testdata/expected/ar-ar.all.json
deleted file mode 100644
index 26a72ff..0000000
--- a/goi18n/testdata/expected/ar-ar.all.json
+++ /dev/null
@@ -1,65 +0,0 @@
-[
- {
- "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/goi18n/testdata/expected/ar-ar.untranslated.json b/goi18n/testdata/expected/ar-ar.untranslated.json
deleted file mode 100644
index a19fa0b..0000000
--- a/goi18n/testdata/expected/ar-ar.untranslated.json
+++ /dev/null
@@ -1,50 +0,0 @@
-[
- {
- "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/goi18n/testdata/expected/en-us.all.json b/goi18n/testdata/expected/en-us.all.json
deleted file mode 100644
index 5aedc23..0000000
--- a/goi18n/testdata/expected/en-us.all.json
+++ /dev/null
@@ -1,45 +0,0 @@
-[
- {
- "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/goi18n/testdata/expected/en-us.untranslated.json b/goi18n/testdata/expected/en-us.untranslated.json
deleted file mode 100644
index 0637a08..0000000
--- a/goi18n/testdata/expected/en-us.untranslated.json
+++ /dev/null
@@ -1 +0,0 @@
-[] \ No newline at end of file
diff --git a/goi18n/testdata/expected/flat/ar-ar.all.json b/goi18n/testdata/expected/flat/ar-ar.all.json
deleted file mode 100644
index 1adb99c..0000000
--- a/goi18n/testdata/expected/flat/ar-ar.all.json
+++ /dev/null
@@ -1,43 +0,0 @@
-{
- "d_days": {
- "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": ""
- },
- "my_height_in_meters": {
- "few": "",
- "many": "",
- "one": "",
- "other": "",
- "two": "",
- "zero": ""
- },
- "person_greeting": {
- "other": "new arabic translation of person_greeting"
- },
- "person_unread_email_count": {
- "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"
- },
- "person_unread_email_count_timeframe": {
- "other": ""
- },
- "program_greeting": {
- "other": ""
- },
- "your_unread_email_count": {
- "few": "",
- "many": "",
- "one": "",
- "other": "",
- "two": "",
- "zero": ""
- }
-} \ No newline at end of file
diff --git a/goi18n/testdata/expected/flat/ar-ar.untranslated.json b/goi18n/testdata/expected/flat/ar-ar.untranslated.json
deleted file mode 100644
index ea7aa7d..0000000
--- a/goi18n/testdata/expected/flat/ar-ar.untranslated.json
+++ /dev/null
@@ -1,32 +0,0 @@
-{
- "d_days": {
- "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"
- },
- "my_height_in_meters": {
- "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."
- },
- "person_unread_email_count_timeframe": {
- "other": "{{.Person}} has {{.Count}} unread emails in the past {{.Timeframe}}."
- },
- "program_greeting": {
- "other": "Hello world"
- },
- "your_unread_email_count": {
- "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/goi18n/testdata/expected/flat/en-us.all.json b/goi18n/testdata/expected/flat/en-us.all.json
deleted file mode 100644
index 766b2a7..0000000
--- a/goi18n/testdata/expected/flat/en-us.all.json
+++ /dev/null
@@ -1,27 +0,0 @@
-{
- "d_days": {
- "one": "{{.Count}} day",
- "other": "{{.Count}} days"
- },
- "my_height_in_meters": {
- "one": "I am {{.Count}} meter tall.",
- "other": "I am {{.Count}} meters tall."
- },
- "person_greeting": {
- "other": "Hello {{.Person}}"
- },
- "person_unread_email_count": {
- "one": "{{.Person}} has {{.Count}} unread email.",
- "other": "{{.Person}} has {{.Count}} unread emails."
- },
- "person_unread_email_count_timeframe": {
- "other": "{{.Person}} has {{.Count}} unread emails in the past {{.Timeframe}}."
- },
- "program_greeting": {
- "other": "Hello world"
- },
- "your_unread_email_count": {
- "one": "You have {{.Count}} unread email.",
- "other": "You have {{.Count}} unread emails."
- }
-} \ No newline at end of file
diff --git a/goi18n/testdata/expected/flat/en-us.untranslated.json b/goi18n/testdata/expected/flat/en-us.untranslated.json
deleted file mode 100644
index 9e26dfe..0000000
--- a/goi18n/testdata/expected/flat/en-us.untranslated.json
+++ /dev/null
@@ -1 +0,0 @@
-{} \ No newline at end of file
diff --git a/goi18n/testdata/expected/flat/en-us.untranslated.json.json b/goi18n/testdata/expected/flat/en-us.untranslated.json.json
deleted file mode 100644
index e69de29..0000000
--- a/goi18n/testdata/expected/flat/en-us.untranslated.json.json
+++ /dev/null
diff --git a/goi18n/testdata/expected/flat/fr-fr.all.json b/goi18n/testdata/expected/flat/fr-fr.all.json
deleted file mode 100644
index b0ee031..0000000
--- a/goi18n/testdata/expected/flat/fr-fr.all.json
+++ /dev/null
@@ -1,27 +0,0 @@
-{
- "d_days": {
- "one": "",
- "other": ""
- },
- "my_height_in_meters": {
- "one": "",
- "other": ""
- },
- "person_greeting": {
- "other": ""
- },
- "person_unread_email_count": {
- "one": "",
- "other": ""
- },
- "person_unread_email_count_timeframe": {
- "other": ""
- },
- "program_greeting": {
- "other": ""
- },
- "your_unread_email_count": {
- "one": "",
- "other": ""
- }
-} \ No newline at end of file
diff --git a/goi18n/testdata/expected/flat/fr-fr.untranslated.json b/goi18n/testdata/expected/flat/fr-fr.untranslated.json
deleted file mode 100644
index e6d5c4f..0000000
--- a/goi18n/testdata/expected/flat/fr-fr.untranslated.json
+++ /dev/null
@@ -1,27 +0,0 @@
-{
- "d_days": {
- "one": "{{.Count}} days",
- "other": "{{.Count}} days"
- },
- "my_height_in_meters": {
- "one": "I am {{.Count}} meters tall.",
- "other": "I am {{.Count}} meters tall."
- },
- "person_greeting": {
- "other": "Hello {{.Person}}"
- },
- "person_unread_email_count": {
- "one": "{{.Person}} has {{.Count}} unread emails.",
- "other": "{{.Person}} has {{.Count}} unread emails."
- },
- "person_unread_email_count_timeframe": {
- "other": "{{.Person}} has {{.Count}} unread emails in the past {{.Timeframe}}."
- },
- "program_greeting": {
- "other": "Hello world"
- },
- "your_unread_email_count": {
- "one": "You have {{.Count}} unread emails.",
- "other": "You have {{.Count}} unread emails."
- }
-} \ No newline at end of file
diff --git a/goi18n/testdata/expected/fr-fr.all.json b/goi18n/testdata/expected/fr-fr.all.json
deleted file mode 100644
index 20e0b87..0000000
--- a/goi18n/testdata/expected/fr-fr.all.json
+++ /dev/null
@@ -1,45 +0,0 @@
-[
- {
- "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/goi18n/testdata/expected/fr-fr.untranslated.json b/goi18n/testdata/expected/fr-fr.untranslated.json
deleted file mode 100644
index e2d3967..0000000
--- a/goi18n/testdata/expected/fr-fr.untranslated.json
+++ /dev/null
@@ -1,45 +0,0 @@
-[
- {
- "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/goi18n/testdata/input/ar-ar.one.json b/goi18n/testdata/input/ar-ar.one.json
deleted file mode 100644
index f5af1d6..0000000
--- a/goi18n/testdata/input/ar-ar.one.json
+++ /dev/null
@@ -1,54 +0,0 @@
-[
- {
- "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/goi18n/testdata/input/ar-ar.two.json b/goi18n/testdata/input/ar-ar.two.json
deleted file mode 100644
index e98d7e9..0000000
--- a/goi18n/testdata/input/ar-ar.two.json
+++ /dev/null
@@ -1,54 +0,0 @@
-[
- {
- "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/goi18n/testdata/input/en-us.constants.json b/goi18n/testdata/input/en-us.constants.json
deleted file mode 100644
index 5aedc23..0000000
--- a/goi18n/testdata/input/en-us.constants.json
+++ /dev/null
@@ -1,45 +0,0 @@
-[
- {
- "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/goi18n/testdata/input/en-us.one.json b/goi18n/testdata/input/en-us.one.json
deleted file mode 100644
index 63a9d6f..0000000
--- a/goi18n/testdata/input/en-us.one.json
+++ /dev/null
@@ -1,30 +0,0 @@
-[
- {
- "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/goi18n/testdata/input/en-us.two.json b/goi18n/testdata/input/en-us.two.json
deleted file mode 100644
index dcc715c..0000000
--- a/goi18n/testdata/input/en-us.two.json
+++ /dev/null
@@ -1,26 +0,0 @@
-[
- {
- "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/goi18n/testdata/input/flat/ar-ar.one.toml b/goi18n/testdata/input/flat/ar-ar.one.toml
deleted file mode 100644
index 364a62c..0000000
--- a/goi18n/testdata/input/flat/ar-ar.one.toml
+++ /dev/null
@@ -1,37 +0,0 @@
-[d_days]
-few = "arabic few translation of d_days"
-many = "arabic many translation of d_days"
-one = ""
-other = ""
-two = ""
-zero = ""
-
-[person_greeting]
-other = "arabic translation of person_greeting"
-
-[person_unread_email_count]
-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 = ""
-
-[person_unread_email_count_timeframe]
-few = ""
-many = ""
-one = ""
-other = ""
-two = ""
-zero = ""
-
-[program_greeting]
-other = ""
-
-[your_unread_email_count]
-few = ""
-many = ""
-one = ""
-other = ""
-two = ""
-zero = ""
diff --git a/goi18n/testdata/input/flat/ar-ar.two.json b/goi18n/testdata/input/flat/ar-ar.two.json
deleted file mode 100644
index 5e6fba4..0000000
--- a/goi18n/testdata/input/flat/ar-ar.two.json
+++ /dev/null
@@ -1,45 +0,0 @@
-{
- "d_days": {
- "few": "new arabic few translation of d_days",
- "many": "",
- "one": "arabic one translation of d_days",
- "other": "",
- "two": "",
- "zero": ""
- },
-
- "person_greeting": {
- "other": "new arabic translation of person_greeting"
- },
-
- "person_unread_email_count": {
- "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"
- },
-
- "person_unread_email_count_timeframe": {
- "few": "",
- "many": "",
- "one": "",
- "other": "",
- "two": "",
- "zero": ""
- },
-
- "program_greeting": {
- "other": ""
- },
-
- "your_unread_email_count": {
- "few": "",
- "many": "",
- "one": "",
- "other": "",
- "two": "",
- "zero": ""
- }
-}
diff --git a/goi18n/testdata/input/flat/en-us.constants.json b/goi18n/testdata/input/flat/en-us.constants.json
deleted file mode 100644
index c41b2b9..0000000
--- a/goi18n/testdata/input/flat/en-us.constants.json
+++ /dev/null
@@ -1,34 +0,0 @@
-{
- "d_days": {
- "one": "{{.Count}} day",
- "other": "{{.Count}} days"
- },
-
- "my_height_in_meters": {
- "one": "I am {{.Count}} meter tall.",
- "other": "I am {{.Count}} meters tall."
- },
-
- "person_greeting": {
- "other": "Hello {{.Person}}"
- },
-
- "person_unread_email_count": {
- "one": "{{.Person}} has {{.Count}} unread email.",
- "other": "{{.Person}} has {{.Count}} unread emails."
- },
-
- "person_unread_email_count_timeframe": {
- "one": "{{.Person}} has {{.Count}} unread email in the past {{.Timeframe}}.",
- "other": "{{.Person}} has {{.Count}} unread emails in the past {{.Timeframe}}."
- },
-
- "program_greeting": {
- "other": "Hello world"
- },
-
- "your_unread_email_count": {
- "one": "You have {{.Count}} unread email.",
- "other": "You have {{.Count}} unread emails."
- }
-}
diff --git a/goi18n/testdata/input/flat/en-us.one.yaml b/goi18n/testdata/input/flat/en-us.one.yaml
deleted file mode 100644
index 02ae001..0000000
--- a/goi18n/testdata/input/flat/en-us.one.yaml
+++ /dev/null
@@ -1,16 +0,0 @@
-program_greeting:
- other: "Hello world"
-
-your_unread_email_count:
- one: "You have {{.Count}} unread email."
- other: "You have {{.Count}} unread emails."
-
-my_height_in_meters:
- one: "I am {{.Count}} meter tall."
- other: "I am {{.Count}} meters tall."
-
-person_unread_email_count_timeframe:
- other: "{{.Person}} has {{.Count}} unread email in the past {{.Timeframe}}."
-
-d_days:
- other: "this should get overwritten"
diff --git a/goi18n/testdata/input/flat/en-us.two.json b/goi18n/testdata/input/flat/en-us.two.json
deleted file mode 100644
index 06bd28d..0000000
--- a/goi18n/testdata/input/flat/en-us.two.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "person_greeting": {
- "other": "Hello {{.Person}}"
- },
-
- "person_unread_email_count": {
- "one": "{{.Person}} has {{.Count}} unread email.",
- "other": "{{.Person}} has {{.Count}} unread emails."
- },
-
- "person_unread_email_count_timeframe": {
- "other": "{{.Person}} has {{.Count}} unread emails in the past {{.Timeframe}}."
- },
-
- "d_days": {
- "one": "{{.Count}} day",
- "other": "{{.Count}} days"
- }
-}
diff --git a/goi18n/testdata/input/flat/fr-fr.json b/goi18n/testdata/input/flat/fr-fr.json
deleted file mode 100644
index e69de29..0000000
--- a/goi18n/testdata/input/flat/fr-fr.json
+++ /dev/null
diff --git a/goi18n/testdata/input/fr-fr.json b/goi18n/testdata/input/fr-fr.json
deleted file mode 100644
index e69de29..0000000
--- a/goi18n/testdata/input/fr-fr.json
+++ /dev/null
diff --git a/goi18n/testdata/input/yaml/ar-ar.one.json b/goi18n/testdata/input/yaml/ar-ar.one.json
deleted file mode 100644
index f5af1d6..0000000
--- a/goi18n/testdata/input/yaml/ar-ar.one.json
+++ /dev/null
@@ -1,54 +0,0 @@
-[
- {
- "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/goi18n/testdata/input/yaml/ar-ar.two.json b/goi18n/testdata/input/yaml/ar-ar.two.json
deleted file mode 100644
index e98d7e9..0000000
--- a/goi18n/testdata/input/yaml/ar-ar.two.json
+++ /dev/null
@@ -1,54 +0,0 @@
-[
- {
- "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/goi18n/testdata/input/yaml/en-us.one.yaml b/goi18n/testdata/input/yaml/en-us.one.yaml
deleted file mode 100644
index 3ca8e38..0000000
--- a/goi18n/testdata/input/yaml/en-us.one.yaml
+++ /dev/null
@@ -1,19 +0,0 @@
-- 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/goi18n/testdata/input/yaml/en-us.two.json b/goi18n/testdata/input/yaml/en-us.two.json
deleted file mode 100644
index dcc715c..0000000
--- a/goi18n/testdata/input/yaml/en-us.two.json
+++ /dev/null
@@ -1,26 +0,0 @@
-[
- {
- "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/goi18n/testdata/input/yaml/fr-fr.json b/goi18n/testdata/input/yaml/fr-fr.json
deleted file mode 100644
index e69de29..0000000
--- a/goi18n/testdata/input/yaml/fr-fr.json
+++ /dev/null
diff --git a/v2/i18n/bundle.go b/i18n/bundle.go
index 62bcd43..62bcd43 100644
--- a/v2/i18n/bundle.go
+++ b/i18n/bundle.go
diff --git a/i18n/bundle/bundle.go b/i18n/bundle/bundle.go
deleted file mode 100644
index 6376146..0000000
--- a/i18n/bundle/bundle.go
+++ /dev/null
@@ -1,443 +0,0 @@
-// Package bundle manages translations for multiple languages.
-package bundle
-
-import (
- "bytes"
- "encoding/json"
- "fmt"
- "io/ioutil"
- "path/filepath"
- "reflect"
- "sync"
- "unicode"
-
- "github.com/nicksnyder/go-i18n/i18n/language"
- "github.com/nicksnyder/go-i18n/i18n/translation"
- toml "github.com/pelletier/go-toml"
- "gopkg.in/yaml.v2"
-)
-
-// TranslateFunc is a copy of i18n.TranslateFunc to avoid a circular dependency.
-type TranslateFunc func(translationID string, args ...interface{}) string
-
-// Bundle stores the translations for multiple languages.
-type Bundle struct {
- // The primary translations for a language tag and translation id.
- translations map[string]map[string]translation.Translation
-
- // Translations that can be used when an exact language match is not possible.
- fallbackTranslations map[string]map[string]translation.Translation
-
- sync.RWMutex
-}
-
-// New returns an empty bundle.
-func New() *Bundle {
- return &Bundle{
- translations: make(map[string]map[string]translation.Translation),
- fallbackTranslations: make(map[string]map[string]translation.Translation),
- }
-}
-
-// MustLoadTranslationFile is similar to LoadTranslationFile
-// except it panics if an error happens.
-func (b *Bundle) MustLoadTranslationFile(filename string) {
- if err := b.LoadTranslationFile(filename); err != nil {
- panic(err)
- }
-}
-
-// LoadTranslationFile loads the translations from filename into memory.
-//
-// The language that the translations are associated with is parsed from the filename (e.g. en-US.json).
-//
-// Generally you should load translation files once during your program's initialization.
-func (b *Bundle) LoadTranslationFile(filename string) error {
- buf, err := ioutil.ReadFile(filename)
- if err != nil {
- return err
- }
- return b.ParseTranslationFileBytes(filename, buf)
-}
-
-// ParseTranslationFileBytes is similar to LoadTranslationFile except it parses the bytes in buf.
-//
-// It is useful for parsing translation files embedded with go-bindata.
-func (b *Bundle) ParseTranslationFileBytes(filename string, buf []byte) error {
- basename := filepath.Base(filename)
- langs := language.Parse(basename)
- switch l := len(langs); {
- case l == 0:
- return fmt.Errorf("no language found in %q", basename)
- case l > 1:
- return fmt.Errorf("multiple languages found in filename %q: %v; expected one", basename, langs)
- }
- translations, err := parseTranslations(filename, buf)
- if err != nil {
- return err
- }
- b.AddTranslation(langs[0], translations...)
- return nil
-}
-
-func parseTranslations(filename string, buf []byte) ([]translation.Translation, error) {
- if len(buf) == 0 {
- return []translation.Translation{}, nil
- }
-
- ext := filepath.Ext(filename)
-
- // `github.com/pelletier/go-toml` lacks an Unmarshal function,
- // so we should parse TOML separately.
- if ext == ".toml" {
- tree, err := toml.LoadReader(bytes.NewReader(buf))
- if err != nil {
- return nil, err
- }
-
- m := make(map[string]map[string]interface{})
- for k, v := range tree.ToMap() {
- m[k] = v.(map[string]interface{})
- }
-
- return parseFlatFormat(m)
- }
-
- // Then parse other formats.
- if isStandardFormat(ext, buf) {
- var standardFormat []map[string]interface{}
- if err := unmarshal(ext, buf, &standardFormat); err != nil {
- return nil, fmt.Errorf("failed to unmarshal %v: %v", filename, err)
- }
- return parseStandardFormat(standardFormat)
- }
- var flatFormat map[string]map[string]interface{}
- if err := unmarshal(ext, buf, &flatFormat); err != nil {
- return nil, fmt.Errorf("failed to unmarshal %v: %v", filename, err)
- }
- return parseFlatFormat(flatFormat)
-}
-
-func isStandardFormat(ext string, buf []byte) bool {
- buf = deleteLeadingComments(ext, buf)
- firstRune := rune(buf[0])
- return (ext == ".json" && firstRune == '[') || (ext == ".yaml" && firstRune == '-')
-}
-
-// deleteLeadingComments deletes leading newlines and comments in buf.
-// It only works for ext == ".yaml".
-func deleteLeadingComments(ext string, buf []byte) []byte {
- if ext != ".yaml" {
- return buf
- }
-
- for {
- buf = bytes.TrimLeftFunc(buf, unicode.IsSpace)
- if buf[0] == '#' {
- buf = deleteLine(buf)
- } else {
- break
- }
- }
-
- return buf
-}
-
-func deleteLine(buf []byte) []byte {
- index := bytes.IndexRune(buf, '\n')
- if index == -1 { // If there is only one line without newline ...
- return nil // ... delete it and return nothing.
- }
- if index == len(buf)-1 { // If there is only one line with newline ...
- return nil // ... do the same as above.
- }
- return buf[index+1:]
-}
-
-// unmarshal finds an appropriate unmarshal function for ext
-// (extension of filename) and unmarshals buf to out. out must be a pointer.
-func unmarshal(ext string, buf []byte, out interface{}) error {
- switch ext {
- case ".json":
- return json.Unmarshal(buf, out)
- case ".yaml":
- return yaml.Unmarshal(buf, out)
- }
-
- return fmt.Errorf("unsupported file extension %v", ext)
-}
-
-func parseStandardFormat(data []map[string]interface{}) ([]translation.Translation, error) {
- translations := make([]translation.Translation, 0, len(data))
- for i, translationData := range data {
- t, err := translation.NewTranslation(translationData)
- if err != nil {
- return nil, fmt.Errorf("unable to parse translation #%d because %s\n%v", i, err, translationData)
- }
- translations = append(translations, t)
- }
- return translations, nil
-}
-
-// parseFlatFormat just converts data from flat format to standard format
-// and passes it to parseStandardFormat.
-//
-// Flat format logic:
-// key of data must be a string and data[key] must be always map[string]interface{},
-// but if there is only "other" key in it then it is non-plural, else plural.
-func parseFlatFormat(data map[string]map[string]interface{}) ([]translation.Translation, error) {
- var standardFormatData []map[string]interface{}
- for id, translationData := range data {
- dataObject := make(map[string]interface{})
- dataObject["id"] = id
- if len(translationData) == 1 { // non-plural form
- _, otherExists := translationData["other"]
- if otherExists {
- dataObject["translation"] = translationData["other"]
- }
- } else { // plural form
- dataObject["translation"] = translationData
- }
-
- standardFormatData = append(standardFormatData, dataObject)
- }
-
- return parseStandardFormat(standardFormatData)
-}
-
-// AddTranslation adds translations for a language.
-//
-// It is useful if your translations are in a format not supported by LoadTranslationFile.
-func (b *Bundle) AddTranslation(lang *language.Language, translations ...translation.Translation) {
- b.Lock()
- defer b.Unlock()
- if b.translations[lang.Tag] == nil {
- b.translations[lang.Tag] = make(map[string]translation.Translation, len(translations))
- }
- currentTranslations := b.translations[lang.Tag]
- for _, newTranslation := range translations {
- if currentTranslation := currentTranslations[newTranslation.ID()]; currentTranslation != nil {
- currentTranslations[newTranslation.ID()] = currentTranslation.Merge(newTranslation)
- } else {
- currentTranslations[newTranslation.ID()] = newTranslation
- }
- }
-
- // lang can provide translations for less specific language tags.
- for _, tag := range lang.MatchingTags() {
- b.fallbackTranslations[tag] = currentTranslations
- }
-}
-
-// Translations returns all translations in the bundle.
-func (b *Bundle) Translations() map[string]map[string]translation.Translation {
- t := make(map[string]map[string]translation.Translation)
- b.RLock()
- for tag, translations := range b.translations {
- t[tag] = make(map[string]translation.Translation)
- for id, translation := range translations {
- t[tag][id] = translation
- }
- }
- b.RUnlock()
- return t
-}
-
-// LanguageTags returns the tags of all languages that that have been added.
-func (b *Bundle) LanguageTags() []string {
- var tags []string
- b.RLock()
- for k := range b.translations {
- tags = append(tags, k)
- }
- b.RUnlock()
- return tags
-}
-
-// LanguageTranslationIDs returns the ids of all translations that have been added for a given language.
-func (b *Bundle) LanguageTranslationIDs(languageTag string) []string {
- var ids []string
- b.RLock()
- for id := range b.translations[languageTag] {
- ids = append(ids, id)
- }
- b.RUnlock()
- return ids
-}
-
-// MustTfunc is similar to Tfunc except it panics if an error happens.
-func (b *Bundle) MustTfunc(pref string, prefs ...string) TranslateFunc {
- tfunc, err := b.Tfunc(pref, prefs...)
- if err != nil {
- panic(err)
- }
- return tfunc
-}
-
-// MustTfuncAndLanguage is similar to TfuncAndLanguage except it panics if an error happens.
-func (b *Bundle) MustTfuncAndLanguage(pref string, prefs ...string) (TranslateFunc, *language.Language) {
- tfunc, language, err := b.TfuncAndLanguage(pref, prefs...)
- if err != nil {
- panic(err)
- }
- return tfunc, language
-}
-
-// Tfunc is similar to TfuncAndLanguage except is doesn't return the Language.
-func (b *Bundle) Tfunc(pref string, prefs ...string) (TranslateFunc, error) {
- tfunc, _, err := b.TfuncAndLanguage(pref, prefs...)
- return tfunc, err
-}
-
-// TfuncAndLanguage returns a TranslateFunc for the first Language that
-// has a non-zero number of translations in the bundle.
-//
-// The returned Language matches the the first language preference that could be satisfied,
-// but this may not strictly match the language of the translations used to satisfy that preference.
-//
-// For example, the user may request "zh". If there are no translations for "zh" but there are translations
-// for "zh-cn", then the translations for "zh-cn" will be used but the returned Language will be "zh".
-//
-// It can parse languages from Accept-Language headers (RFC 2616),
-// but it assumes weights are monotonically decreasing.
-func (b *Bundle) TfuncAndLanguage(pref string, prefs ...string) (TranslateFunc, *language.Language, error) {
- lang := b.supportedLanguage(pref, prefs...)
- var err error
- if lang == nil {
- err = fmt.Errorf("no supported languages found %#v", append(prefs, pref))
- }
- return func(translationID string, args ...interface{}) string {
- return b.translate(lang, translationID, args...)
- }, lang, err
-}
-
-// supportedLanguage returns the first language which
-// has a non-zero number of translations in the bundle.
-func (b *Bundle) supportedLanguage(pref string, prefs ...string) *language.Language {
- lang := b.translatedLanguage(pref)
- if lang == nil {
- for _, pref := range prefs {
- lang = b.translatedLanguage(pref)
- if lang != nil {
- break
- }
- }
- }
- return lang
-}
-
-func (b *Bundle) translatedLanguage(src string) *language.Language {
- langs := language.Parse(src)
- b.RLock()
- defer b.RUnlock()
- for _, lang := range langs {
- if len(b.translations[lang.Tag]) > 0 ||
- len(b.fallbackTranslations[lang.Tag]) > 0 {
- return lang
- }
- }
- return nil
-}
-
-func (b *Bundle) translate(lang *language.Language, translationID string, args ...interface{}) string {
- if lang == nil {
- return translationID
- }
-
- translation := b.translation(lang, translationID)
- if translation == nil {
- return translationID
- }
-
- var data interface{}
- var count interface{}
- if argc := len(args); argc > 0 {
- if isNumber(args[0]) {
- count = args[0]
- if argc > 1 {
- data = args[1]
- }
- } else {
- data = args[0]
- }
- }
-
- if count != nil {
- if data == nil {
- data = map[string]interface{}{"Count": count}
- } else {
- dataMap := toMap(data)
- dataMap["Count"] = count
- data = dataMap
- }
- } else {
- dataMap := toMap(data)
- if c, ok := dataMap["Count"]; ok {
- count = c
- }
- }
-
- p, _ := lang.Plural(count)
- template := translation.Template(p)
- if template == nil {
- return translationID
- }
-
- s := template.Execute(data)
- if s == "" {
- return translationID
- }
- return s
-}
-
-func (b *Bundle) translation(lang *language.Language, translationID string) translation.Translation {
- b.RLock()
- defer b.RUnlock()
- translations := b.translations[lang.Tag]
- if translations == nil {
- translations = b.fallbackTranslations[lang.Tag]
- if translations == nil {
- return nil
- }
- }
- return translations[translationID]
-}
-
-func isNumber(n interface{}) bool {
- switch n.(type) {
- case int, int8, int16, int32, int64, string:
- return true
- }
- return false
-}
-
-func toMap(input interface{}) map[string]interface{} {
- if data, ok := input.(map[string]interface{}); ok {
- return data
- }
- v := reflect.ValueOf(input)
- switch v.Kind() {
- case reflect.Ptr:
- return toMap(v.Elem().Interface())
- case reflect.Struct:
- return structToMap(v)
- default:
- return nil
- }
-}
-
-// Converts the top level of a struct to a map[string]interface{}.
-// Code inspired by github.com/fatih/structs.
-func structToMap(v reflect.Value) map[string]interface{} {
- out := make(map[string]interface{})
- t := v.Type()
- for i := 0; i < t.NumField(); i++ {
- field := t.Field(i)
- if field.PkgPath != "" {
- // unexported field. skip.
- continue
- }
- out[field.Name] = v.FieldByName(field.Name).Interface()
- }
- return out
-}
diff --git a/i18n/bundle/bundle_test.go b/i18n/bundle/bundle_test.go
deleted file mode 100644
index da3830a..0000000
--- a/i18n/bundle/bundle_test.go
+++ /dev/null
@@ -1,364 +0,0 @@
-package bundle
-
-import (
- "fmt"
- "strconv"
- "sync"
- "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 TestConcurrent(t *testing.T) {
- b := New()
- // bootstrap bundle
- translationID := "translation_id" // +1
- englishLanguage := languageWithTag("en-US")
- addFakeTranslation(t, b, englishLanguage, translationID)
-
- tf, err := b.Tfunc(englishLanguage.Tag)
- if err != nil {
- t.Errorf("Tfunc(%v) = error{%q}; expected no error", []string{englishLanguage.Tag}, err)
- }
-
- const iterations = 1000
- var wg sync.WaitGroup
- wg.Add(iterations)
-
- // Using go routines insert 1000 ints into our map.
- go func() {
- for i := 0; i < iterations/2; i++ {
- // Add item to map.
- translationID := strconv.FormatInt(int64(i), 10)
- addFakeTranslation(t, b, englishLanguage, translationID)
-
- // Retrieve item from map.
- tf(translationID)
-
- wg.Done()
- } // Call go routine with current index.
- }()
-
- go func() {
- for i := iterations / 2; i < iterations; i++ {
- // Add item to map.
- translationID := strconv.FormatInt(int64(i), 10)
- addFakeTranslation(t, b, englishLanguage, translationID)
-
- // Retrieve item from map.
- tf(translationID)
-
- wg.Done()
- } // Call go routine with current index.
- }()
-
- // Wait for all go routines to finish.
- wg.Wait()
-
- // Make sure map contains 1000+1 elements.
- count := len(b.Translations()[englishLanguage.Tag])
- if count != iterations+1 {
- t.Error("Expecting 1001 elements, got", count)
- }
-}
-
-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 BenchmarkTranslatePluralWithMapAndCountField(b *testing.B) {
- data := map[string]interface{}{
- "Person": "Bob",
- "Count": 26,
- }
-
- translationTemplate := map[string]interface{}{
- "one": "{{.Person}} is {{.Count}} year old.",
- "other": "{{.Person}} is {{.Count}} years old.",
- }
- expected := "Bob is 26 years old."
-
- tf := createBenchmarkTranslateFunc(b, translationTemplate, nil, expected)
-
- 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/v2/i18n/bundle_test.go b/i18n/bundle_test.go
index da8a697..da8a697 100644
--- a/v2/i18n/bundle_test.go
+++ b/i18n/bundle_test.go
diff --git a/v2/i18n/doc.go b/i18n/doc.go
index 73d7a06..73d7a06 100644
--- a/v2/i18n/doc.go
+++ b/i18n/doc.go
diff --git a/i18n/example_test.go b/i18n/example_test.go
index 305c5b3..2256e63 100644
--- a/i18n/example_test.go
+++ b/i18n/example_test.go
@@ -3,95 +3,139 @@ package i18n_test
import (
"fmt"
- "github.com/nicksnyder/go-i18n/i18n"
+ "github.com/BurntSushi/toml"
+ "github.com/nicksnyder/go-i18n/v2/i18n"
+ "golang.org/x/text/language"
)
-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))
+func ExampleLocalizer_MustLocalize() {
+ bundle := i18n.NewBundle(language.English)
+ localizer := i18n.NewLocalizer(bundle, "en")
+ fmt.Println(localizer.MustLocalize(&i18n.LocalizeConfig{
+ DefaultMessage: &i18n.Message{
+ ID: "HelloWorld",
+ Other: "Hello World!",
+ },
+ }))
+ // Output:
+ // Hello World!
+}
- type Count struct{ Count int }
- fmt.Println(T("your_unread_email_count", Count{0}))
- fmt.Println(T("your_unread_email_count", Count{1}))
- fmt.Println(T("your_unread_email_count", Count{2}))
+func ExampleLocalizer_MustLocalize_noDefaultMessage() {
+ bundle := i18n.NewBundle(language.English)
+ bundle.RegisterUnmarshalFunc("toml", toml.Unmarshal)
+ bundle.MustParseMessageFileBytes([]byte(`
+HelloWorld = "Hello World!"
+`), "en.toml")
+ bundle.MustParseMessageFileBytes([]byte(`
+HelloWorld = "Hola Mundo!"
+`), "es.toml")
- fmt.Println(T("your_unread_email_count", map[string]interface{}{"Count": 0}))
- fmt.Println(T("your_unread_email_count", map[string]interface{}{"Count": "1"}))
- fmt.Println(T("your_unread_email_count", map[string]interface{}{"Count": "3.14"}))
+ {
+ localizer := i18n.NewLocalizer(bundle, "en-US")
+ fmt.Println(localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "HelloWorld"}))
+ }
+ {
+ localizer := i18n.NewLocalizer(bundle, "es-ES")
+ fmt.Println(localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "HelloWorld"}))
+ }
+ // Output:
+ // Hello World!
+ // Hola Mundo!
+}
- fmt.Println(T("person_unread_email_count_timeframe", 3, map[string]interface{}{
- "Person": "Bob",
- "Timeframe": T("d_days", 0),
+func ExampleLocalizer_MustLocalize_plural() {
+ bundle := i18n.NewBundle(language.English)
+ localizer := i18n.NewLocalizer(bundle, "en")
+ catsMessage := &i18n.Message{
+ ID: "Cats",
+ One: "I have {{.PluralCount}} cat.",
+ Other: "I have {{.PluralCount}} cats.",
+ }
+ fmt.Println(localizer.MustLocalize(&i18n.LocalizeConfig{
+ DefaultMessage: catsMessage,
+ PluralCount: 1,
}))
- fmt.Println(T("person_unread_email_count_timeframe", 3, map[string]interface{}{
- "Person": "Bob",
- "Timeframe": T("d_days", 1),
+ fmt.Println(localizer.MustLocalize(&i18n.LocalizeConfig{
+ DefaultMessage: catsMessage,
+ PluralCount: 2,
}))
- fmt.Println(T("person_unread_email_count_timeframe", 3, map[string]interface{}{
- "Person": "Bob",
- "Timeframe": T("d_days", 2),
+ fmt.Println(localizer.MustLocalize(&i18n.LocalizeConfig{
+ DefaultMessage: catsMessage,
+ PluralCount: "2.5",
}))
+ // Output:
+ // I have 1 cat.
+ // I have 2 cats.
+ // I have 2.5 cats.
+}
- fmt.Println(T("person_unread_email_count_timeframe", 1, map[string]interface{}{
- "Count": 30,
- "Person": "Bob",
- "Timeframe": T("d_days", 0),
+func ExampleLocalizer_MustLocalize_template() {
+ bundle := i18n.NewBundle(language.English)
+ localizer := i18n.NewLocalizer(bundle, "en")
+ helloPersonMessage := &i18n.Message{
+ ID: "HelloPerson",
+ Other: "Hello {{.Name}}!",
+ }
+ fmt.Println(localizer.MustLocalize(&i18n.LocalizeConfig{
+ DefaultMessage: helloPersonMessage,
+ TemplateData: map[string]string{"Name": "Nick"},
}))
- fmt.Println(T("person_unread_email_count_timeframe", 2, map[string]interface{}{
- "Count": 20,
- "Person": "Bob",
- "Timeframe": T("d_days", 1),
+ // Output:
+ // Hello Nick!
+}
+
+func ExampleLocalizer_MustLocalize_plural_template() {
+ bundle := i18n.NewBundle(language.English)
+ localizer := i18n.NewLocalizer(bundle, "en")
+ personCatsMessage := &i18n.Message{
+ ID: "PersonCats",
+ One: "{{.Name}} has {{.Count}} cat.",
+ Other: "{{.Name}} has {{.Count}} cats.",
+ }
+ fmt.Println(localizer.MustLocalize(&i18n.LocalizeConfig{
+ DefaultMessage: personCatsMessage,
+ PluralCount: 1,
+ TemplateData: map[string]interface{}{
+ "Name": "Nick",
+ "Count": 1,
+ },
}))
- fmt.Println(T("person_unread_email_count_timeframe", 3, map[string]interface{}{
- "Count": 10,
- "Person": "Bob",
- "Timeframe": T("d_days", 2),
+ fmt.Println(localizer.MustLocalize(&i18n.LocalizeConfig{
+ DefaultMessage: personCatsMessage,
+ PluralCount: 2,
+ TemplateData: map[string]interface{}{
+ "Name": "Nick",
+ "Count": 2,
+ },
}))
+ fmt.Println(localizer.MustLocalize(&i18n.LocalizeConfig{
+ DefaultMessage: personCatsMessage,
+ PluralCount: "2.5",
+ TemplateData: map[string]interface{}{
+ "Name": "Nick",
+ "Count": "2.5",
+ },
+ }))
+ // Output:
+ // Nick has 1 cat.
+ // Nick has 2 cats.
+ // Nick has 2.5 cats.
+}
+func ExampleLocalizer_MustLocalize_customTemplateDelims() {
+ bundle := i18n.NewBundle(language.English)
+ localizer := i18n.NewLocalizer(bundle, "en")
+ helloPersonMessage := &i18n.Message{
+ ID: "HelloPerson",
+ Other: "Hello <<.Name>>!",
+ LeftDelim: "<<",
+ RightDelim: ">>",
+ }
+ fmt.Println(localizer.MustLocalize(&i18n.LocalizeConfig{
+ DefaultMessage: helloPersonMessage,
+ TemplateData: map[string]string{"Name": "Nick"},
+ }))
// 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.
- // You have 0 unread emails.
- // You have 1 unread email.
- // You have 2 unread emails.
- // You have 0 unread emails.
- // You have 1 unread email.
- // You have 3.14 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.
- // Bob has 1 unread email in the past 0 days.
- // Bob has 2 unread emails in the past 1 day.
- // Bob has 3 unread emails in the past 2 days.
+ // Hello Nick!
}
diff --git a/i18n/exampletemplate_test.go b/i18n/exampletemplate_test.go
deleted file mode 100644
index 3648bd1..0000000
--- a/i18n/exampletemplate_test.go
+++ /dev/null
@@ -1,64 +0,0 @@
-package i18n_test
-
-import (
- "os"
- "text/template"
-
- "github.com/nicksnyder/go-i18n/i18n"
-)
-
-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/i18n/exampleyaml_test.go b/i18n/exampleyaml_test.go
deleted file mode 100644
index a38dcfc..0000000
--- a/i18n/exampleyaml_test.go
+++ /dev/null
@@ -1,63 +0,0 @@
-package i18n_test
-
-import (
- "fmt"
-
- "github.com/nicksnyder/go-i18n/i18n"
-)
-
-func Example_yaml() {
- 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/i18n/i18n.go b/i18n/i18n.go
deleted file mode 100644
index c478ff6..0000000
--- a/i18n/i18n.go
+++ /dev/null
@@ -1,158 +0,0 @@
-// Package i18n supports string translations with variable substitution and CLDR pluralization.
-// It is intended to be used in conjunction with the goi18n command, although that is not strictly required.
-//
-// Initialization
-//
-// Your Go program should load translations during its initialization.
-// i18n.MustLoadTranslationFile("path/to/fr-FR.all.json")
-// If your translations are in a file format not supported by (Must)?LoadTranslationFile,
-// then you can use the AddTranslation function to manually add translations.
-//
-// Fetching a translation
-//
-// Use Tfunc or MustTfunc to fetch a TranslateFunc that will return the translated string for a specific language.
-// func handleRequest(w http.ResponseWriter, r *http.Request) {
-// cookieLang := r.Cookie("lang")
-// acceptLang := r.Header.Get("Accept-Language")
-// defaultLang = "en-US" // known valid language
-// T, err := i18n.Tfunc(cookieLang, acceptLang, defaultLang)
-// fmt.Println(T("Hello world"))
-// }
-//
-// Usually it is a good idea to identify strings by a generic id rather than the English translation,
-// but the rest of this documentation will continue to use the English translation for readability.
-// T("Hello world") // ok
-// T("programGreeting") // better!
-//
-// Variables
-//
-// TranslateFunc supports strings that have variables using the text/template syntax.
-// T("Hello {{.Person}}", map[string]interface{}{
-// "Person": "Bob",
-// })
-//
-// Pluralization
-//
-// TranslateFunc supports the pluralization of strings using the CLDR pluralization rules defined here:
-// http://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html
-// T("You have {{.Count}} unread emails.", 2)
-// T("I am {{.Count}} meters tall.", "1.7")
-//
-// Plural strings may also have variables.
-// T("{{.Person}} has {{.Count}} unread emails", 2, map[string]interface{}{
-// "Person": "Bob",
-// })
-//
-// Sentences with multiple plural components can be supported with nesting.
-// T("{{.Person}} has {{.Count}} unread emails in the past {{.Timeframe}}.", 3, map[string]interface{}{
-// "Person": "Bob",
-// "Timeframe": T("{{.Count}} days", 2),
-// })
-//
-// Templates
-//
-// You can use the .Funcs() method of a text/template or html/template to register a TranslateFunc
-// for usage inside of that template.
-package i18n
-
-import (
- "github.com/nicksnyder/go-i18n/i18n/bundle"
- "github.com/nicksnyder/go-i18n/i18n/language"
- "github.com/nicksnyder/go-i18n/i18n/translation"
-)
-
-// TranslateFunc returns the translation of the string identified by translationID.
-//
-// If there is no translation for translationID, then the translationID itself is returned.
-// This makes it easy to identify missing translations in your app.
-//
-// If translationID is a non-plural form, then the first variadic argument may be a map[string]interface{}
-// or struct that contains template data.
-//
-// If translationID is a plural form, the function accepts two parameter signatures
-// 1. T(count int, data struct{})
-// The first variadic argument must be an integer type
-// (int, int8, int16, int32, int64) or a float formatted as a string (e.g. "123.45").
-// The second variadic argument may be a map[string]interface{} or struct{} that contains template data.
-// 2. T(data struct{})
-// data must be a struct{} or map[string]interface{} that contains a Count field and the template data,
-// Count field must be an integer type (int, int8, int16, int32, int64)
-// or a float formatted as a string (e.g. "123.45").
-type TranslateFunc func(translationID string, args ...interface{}) string
-
-// IdentityTfunc returns a TranslateFunc that always returns the translationID passed to it.
-//
-// It is a useful placeholder when parsing a text/template or html/template
-// before the actual Tfunc is available.
-func IdentityTfunc() TranslateFunc {
- return func(translationID string, args ...interface{}) string {
- return translationID
- }
-}
-
-var defaultBundle = bundle.New()
-
-// MustLoadTranslationFile is similar to LoadTranslationFile
-// except it panics if an error happens.
-func MustLoadTranslationFile(filename string) {
- defaultBundle.MustLoadTranslationFile(filename)
-}
-
-// LoadTranslationFile loads the translations from filename into memory.
-//
-// The language that the translations are associated with is parsed from the filename (e.g. en-US.json).
-//
-// Generally you should load translation files once during your program's initialization.
-func LoadTranslationFile(filename string) error {
- return defaultBundle.LoadTranslationFile(filename)
-}
-
-// ParseTranslationFileBytes is similar to LoadTranslationFile except it parses the bytes in buf.
-//
-// It is useful for parsing translation files embedded with go-bindata.
-func ParseTranslationFileBytes(filename string, buf []byte) error {
- return defaultBundle.ParseTranslationFileBytes(filename, buf)
-}
-
-// AddTranslation adds translations for a language.
-//
-// It is useful if your translations are in a format not supported by LoadTranslationFile.
-func AddTranslation(lang *language.Language, translations ...translation.Translation) {
- defaultBundle.AddTranslation(lang, translations...)
-}
-
-// LanguageTags returns the tags of all languages that have been added.
-func LanguageTags() []string {
- return defaultBundle.LanguageTags()
-}
-
-// LanguageTranslationIDs returns the ids of all translations that have been added for a given language.
-func LanguageTranslationIDs(languageTag string) []string {
- return defaultBundle.LanguageTranslationIDs(languageTag)
-}
-
-// MustTfunc is similar to Tfunc except it panics if an error happens.
-func MustTfunc(languageSource string, languageSources ...string) TranslateFunc {
- return TranslateFunc(defaultBundle.MustTfunc(languageSource, languageSources...))
-}
-
-// Tfunc returns a TranslateFunc that will be bound to the first language which
-// has a non-zero number of translations.
-//
-// It can parse languages from Accept-Language headers (RFC 2616).
-func Tfunc(languageSource string, languageSources ...string) (TranslateFunc, error) {
- tfunc, err := defaultBundle.Tfunc(languageSource, languageSources...)
- return TranslateFunc(tfunc), err
-}
-
-// MustTfuncAndLanguage is similar to TfuncAndLanguage except it panics if an error happens.
-func MustTfuncAndLanguage(languageSource string, languageSources ...string) (TranslateFunc, *language.Language) {
- tfunc, lang := defaultBundle.MustTfuncAndLanguage(languageSource, languageSources...)
- return TranslateFunc(tfunc), lang
-}
-
-// TfuncAndLanguage is similar to Tfunc except it also returns the language which TranslateFunc is bound to.
-func TfuncAndLanguage(languageSource string, languageSources ...string) (TranslateFunc, *language.Language, error) {
- tfunc, lang, err := defaultBundle.TfuncAndLanguage(languageSource, languageSources...)
- return TranslateFunc(tfunc), lang, err
-}
diff --git a/i18n/language/codegen/generate.sh b/i18n/language/codegen/generate.sh
deleted file mode 100644
index a9fae84..0000000
--- a/i18n/language/codegen/generate.sh
+++ /dev/null
@@ -1,5 +0,0 @@
-#!/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/i18n/language/codegen/main.go b/i18n/language/codegen/main.go
deleted file mode 100644
index 5897103..0000000
--- a/i18n/language/codegen/main.go
+++ /dev/null
@@ -1,132 +0,0 @@
-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/i18n/language/codegen/plurals.xml b/i18n/language/codegen/plurals.xml
deleted file mode 100644
index 3310c8e..0000000
--- a/i18n/language/codegen/plurals.xml
+++ /dev/null
@@ -1,226 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<!DOCTYPE supplementalData SYSTEM "../../common/dtd/ldmlSupplemental.dtd">
-<!--
-Copyright © 1991-2015 Unicode, Inc.
-CLDR data files are interpreted according to the LDML specification (http://unicode.org/reports/tr35/)
-For terms of use, see http://www.unicode.org/copyright.html
--->
-<supplementalData>
- <version number="$Revision: 13253 $"/>
- <plurals type="cardinal">
- <!-- For a canonicalized list, use GeneratedPluralSamples -->
-
- <!-- 1: other -->
-
- <pluralRules locales="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 yue zh">
- <pluralRule count="other"> @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, …</pluralRule>
- </pluralRules>
-
- <!-- 2: one,other -->
-
- <pluralRules locales="am as bn fa gu hi kn mr zu">
- <pluralRule count="one">i = 0 or n = 1 @integer 0, 1 @decimal 0.0~1.0, 0.00~0.04</pluralRule>
- <pluralRule count="other"> @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, …</pluralRule>
- </pluralRules>
- <pluralRules locales="ff fr hy kab">
- <pluralRule count="one">i = 0,1 @integer 0, 1 @decimal 0.0~1.5</pluralRule>
- <pluralRule count="other"> @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, …</pluralRule>
- </pluralRules>
- <pluralRules locales="pt">
- <pluralRule count="one">i = 0..1 @integer 0, 1 @decimal 0.0~1.5</pluralRule>
- <pluralRule count="other"> @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, …</pluralRule>
- </pluralRules>
- <pluralRules locales="ast ca de en et fi fy gl it ji nl sv sw ur yi">
- <pluralRule count="one">i = 1 and v = 0 @integer 1</pluralRule>
- <pluralRule count="other"> @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, …</pluralRule>
- </pluralRules>
- <pluralRules locales="si">
- <pluralRule count="one">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</pluralRule>
- <pluralRule count="other"> @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, …</pluralRule>
- </pluralRules>
- <pluralRules locales="ak bh guw ln mg nso pa ti wa">
- <pluralRule count="one">n = 0..1 @integer 0, 1 @decimal 0.0, 1.0, 0.00, 1.00, 0.000, 1.000, 0.0000, 1.0000</pluralRule>
- <pluralRule count="other"> @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, …</pluralRule>
- </pluralRules>
- <pluralRules locales="tzm">
- <pluralRule count="one">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</pluralRule>
- <pluralRule count="other"> @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, …</pluralRule>
- </pluralRules>
- <pluralRules locales="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">
- <pluralRule count="one">n = 1 @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000</pluralRule>
- <pluralRule count="other"> @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, …</pluralRule>
- </pluralRules>
- <pluralRules locales="da">
- <pluralRule count="one">n = 1 or t != 0 and i = 0,1 @integer 1 @decimal 0.1~1.6</pluralRule>
- <pluralRule count="other"> @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, …</pluralRule>
- </pluralRules>
- <pluralRules locales="is">
- <pluralRule count="one">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, …</pluralRule>
- <pluralRule count="other"> @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, …</pluralRule>
- </pluralRules>
- <pluralRules locales="mk">
- <pluralRule count="one">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, …</pluralRule>
- <pluralRule count="other"> @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, …</pluralRule>
- </pluralRules>
- <pluralRules locales="fil tl">
- <pluralRule count="one">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, …</pluralRule>
- <pluralRule count="other"> @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, …</pluralRule>
- </pluralRules>
-
- <!-- 3: zero,one,other -->
-
- <pluralRules locales="lv prg">
- <pluralRule count="zero">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, …</pluralRule>
- <pluralRule count="one">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, …</pluralRule>
- <pluralRule count="other"> @integer 2~9, 22~29, 102, 1002, … @decimal 0.2~0.9, 1.2~1.9, 10.2, 100.2, 1000.2, …</pluralRule>
- </pluralRules>
- <pluralRules locales="lag">
- <pluralRule count="zero">n = 0 @integer 0 @decimal 0.0, 0.00, 0.000, 0.0000</pluralRule>
- <pluralRule count="one">i = 0,1 and n != 0 @integer 1 @decimal 0.1~1.6</pluralRule>
- <pluralRule count="other"> @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, …</pluralRule>
- </pluralRules>
- <pluralRules locales="ksh">
- <pluralRule count="zero">n = 0 @integer 0 @decimal 0.0, 0.00, 0.000, 0.0000</pluralRule>
- <pluralRule count="one">n = 1 @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000</pluralRule>
- <pluralRule count="other"> @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, …</pluralRule>
- </pluralRules>
-
- <!-- 3: one,two,other -->
-
- <pluralRules locales="iu kw naq se sma smi smj smn sms">
- <pluralRule count="one">n = 1 @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000</pluralRule>
- <pluralRule count="two">n = 2 @integer 2 @decimal 2.0, 2.00, 2.000, 2.0000</pluralRule>
- <pluralRule count="other"> @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, …</pluralRule>
- </pluralRules>
-
- <!-- 3: one,few,other -->
-
- <pluralRules locales="shi">
- <pluralRule count="one">i = 0 or n = 1 @integer 0, 1 @decimal 0.0~1.0, 0.00~0.04</pluralRule>
- <pluralRule count="few">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</pluralRule>
- <pluralRule count="other"> @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, …</pluralRule>
- </pluralRules>
- <pluralRules locales="mo ro">
- <pluralRule count="one">i = 1 and v = 0 @integer 1</pluralRule>
- <pluralRule count="few">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, …</pluralRule>
- <pluralRule count="other"> @integer 20~35, 100, 1000, 10000, 100000, 1000000, …</pluralRule>
- </pluralRules>
- <pluralRules locales="bs hr sh sr">
- <pluralRule count="one">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, …</pluralRule>
- <pluralRule count="few">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, …</pluralRule>
- <pluralRule count="other"> @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, …</pluralRule>
- </pluralRules>
-
- <!-- 4: one,two,few,other -->
-
- <pluralRules locales="gd">
- <pluralRule count="one">n = 1,11 @integer 1, 11 @decimal 1.0, 11.0, 1.00, 11.00, 1.000, 11.000, 1.0000</pluralRule>
- <pluralRule count="two">n = 2,12 @integer 2, 12 @decimal 2.0, 12.0, 2.00, 12.00, 2.000, 12.000, 2.0000</pluralRule>
- <pluralRule count="few">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</pluralRule>
- <pluralRule count="other"> @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, …</pluralRule>
- </pluralRules>
- <pluralRules locales="sl">
- <pluralRule count="one">v = 0 and i % 100 = 1 @integer 1, 101, 201, 301, 401, 501, 601, 701, 1001, …</pluralRule>
- <pluralRule count="two">v = 0 and i % 100 = 2 @integer 2, 102, 202, 302, 402, 502, 602, 702, 1002, …</pluralRule>
- <pluralRule count="few">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, …</pluralRule>
- <pluralRule count="other"> @integer 0, 5~19, 100, 1000, 10000, 100000, 1000000, …</pluralRule>
- </pluralRules>
- <pluralRules locales="dsb hsb">
- <pluralRule count="one">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, …</pluralRule>
- <pluralRule count="two">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, …</pluralRule>
- <pluralRule count="few">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, …</pluralRule>
- <pluralRule count="other"> @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, …</pluralRule>
- </pluralRules>
-
- <!-- 4: one,two,many,other -->
-
- <pluralRules locales="he iw">
- <pluralRule count="one">i = 1 and v = 0 @integer 1</pluralRule>
- <pluralRule count="two">i = 2 and v = 0 @integer 2</pluralRule>
- <pluralRule count="many">v = 0 and n != 0..10 and n % 10 = 0 @integer 20, 30, 40, 50, 60, 70, 80, 90, 100, 1000, 10000, 100000, 1000000, …</pluralRule>
- <pluralRule count="other"> @integer 0, 3~17, 101, 1001, … @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …</pluralRule>
- </pluralRules>
-
- <!-- 4: one,few,many,other -->
-
- <pluralRules locales="cs sk">
- <pluralRule count="one">i = 1 and v = 0 @integer 1</pluralRule>
- <pluralRule count="few">i = 2..4 and v = 0 @integer 2~4</pluralRule>
- <pluralRule count="many">v != 0 @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …</pluralRule>
- <pluralRule count="other"> @integer 0, 5~19, 100, 1000, 10000, 100000, 1000000, …</pluralRule>
- </pluralRules>
- <pluralRules locales="pl">
- <pluralRule count="one">i = 1 and v = 0 @integer 1</pluralRule>
- <pluralRule count="few">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, …</pluralRule>
- <pluralRule count="many">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, …</pluralRule>
- <pluralRule count="other"> @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …</pluralRule>
- </pluralRules>
- <pluralRules locales="be">
- <pluralRule count="one">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, …</pluralRule>
- <pluralRule count="few">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, …</pluralRule>
- <pluralRule count="many">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, …</pluralRule>
- <pluralRule count="other"> @decimal 0.1~0.9, 1.1~1.7, 10.1, 100.1, 1000.1, …</pluralRule>
- </pluralRules>
- <pluralRules locales="lt">
- <pluralRule count="one">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, …</pluralRule>
- <pluralRule count="few">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, …</pluralRule>
- <pluralRule count="many">f != 0 @decimal 0.1~0.9, 1.1~1.7, 10.1, 100.1, 1000.1, …</pluralRule>
- <pluralRule count="other"> @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, …</pluralRule>
- </pluralRules>
- <pluralRules locales="mt">
- <pluralRule count="one">n = 1 @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000</pluralRule>
- <pluralRule count="few">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, …</pluralRule>
- <pluralRule count="many">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, …</pluralRule>
- <pluralRule count="other"> @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, …</pluralRule>
- </pluralRules>
- <pluralRules locales="ru uk">
- <pluralRule count="one">v = 0 and i % 10 = 1 and i % 100 != 11 @integer 1, 21, 31, 41, 51, 61, 71, 81, 101, 1001, …</pluralRule>
- <pluralRule count="few">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, …</pluralRule>
- <pluralRule count="many">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, …</pluralRule>
- <pluralRule count="other"> @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …</pluralRule>
- </pluralRules>
-
- <!-- 5: one,two,few,many,other -->
-
- <pluralRules locales="br">
- <pluralRule count="one">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, …</pluralRule>
- <pluralRule count="two">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, …</pluralRule>
- <pluralRule count="few">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, …</pluralRule>
- <pluralRule count="many">n != 0 and n % 1000000 = 0 @integer 1000000, … @decimal 1000000.0, 1000000.00, 1000000.000, …</pluralRule>
- <pluralRule count="other"> @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, …</pluralRule>
- </pluralRules>
- <pluralRules locales="ga">
- <pluralRule count="one">n = 1 @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000</pluralRule>
- <pluralRule count="two">n = 2 @integer 2 @decimal 2.0, 2.00, 2.000, 2.0000</pluralRule>
- <pluralRule count="few">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</pluralRule>
- <pluralRule count="many">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</pluralRule>
- <pluralRule count="other"> @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, …</pluralRule>
- </pluralRules>
- <pluralRules locales="gv">
- <pluralRule count="one">v = 0 and i % 10 = 1 @integer 1, 11, 21, 31, 41, 51, 61, 71, 101, 1001, …</pluralRule>
- <pluralRule count="two">v = 0 and i % 10 = 2 @integer 2, 12, 22, 32, 42, 52, 62, 72, 102, 1002, …</pluralRule>
- <pluralRule count="few">v = 0 and i % 100 = 0,20,40,60,80 @integer 0, 20, 40, 60, 80, 100, 120, 140, 1000, 10000, 100000, 1000000, …</pluralRule>
- <pluralRule count="many">v != 0 @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …</pluralRule>
- <pluralRule count="other"> @integer 3~10, 13~19, 23, 103, 1003, …</pluralRule>
- </pluralRules>
-
- <!-- 6: zero,one,two,few,many,other -->
-
- <pluralRules locales="ar ars">
- <pluralRule count="zero">n = 0 @integer 0 @decimal 0.0, 0.00, 0.000, 0.0000</pluralRule>
- <pluralRule count="one">n = 1 @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000</pluralRule>
- <pluralRule count="two">n = 2 @integer 2 @decimal 2.0, 2.00, 2.000, 2.0000</pluralRule>
- <pluralRule count="few">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, …</pluralRule>
- <pluralRule count="many">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, …</pluralRule>
- <pluralRule count="other"> @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, …</pluralRule>
- </pluralRules>
- <pluralRules locales="cy">
- <pluralRule count="zero">n = 0 @integer 0 @decimal 0.0, 0.00, 0.000, 0.0000</pluralRule>
- <pluralRule count="one">n = 1 @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000</pluralRule>
- <pluralRule count="two">n = 2 @integer 2 @decimal 2.0, 2.00, 2.000, 2.0000</pluralRule>
- <pluralRule count="few">n = 3 @integer 3 @decimal 3.0, 3.00, 3.000, 3.0000</pluralRule>
- <pluralRule count="many">n = 6 @integer 6 @decimal 6.0, 6.00, 6.000, 6.0000</pluralRule>
- <pluralRule count="other"> @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, …</pluralRule>
- </pluralRules>
- </plurals>
-</supplementalData>
diff --git a/i18n/language/codegen/xml.go b/i18n/language/codegen/xml.go
deleted file mode 100644
index 9d39053..0000000
--- a/i18n/language/codegen/xml.go
+++ /dev/null
@@ -1,143 +0,0 @@
-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/i18n/language/language.go b/i18n/language/language.go
deleted file mode 100644
index b045a27..0000000
--- a/i18n/language/language.go
+++ /dev/null
@@ -1,99 +0,0 @@
-// Package language defines languages that implement CLDR pluralization.
-package language
-
-import (
- "fmt"
- "strings"
-)
-
-// Language is a written human language.
-type Language struct {
- // Tag uniquely identifies the language as defined by RFC 5646.
- //
- // Most language tags are a two character language code (ISO 639-1)
- // optionally followed by a dash and a two character country code (ISO 3166-1).
- // (e.g. en, pt-br)
- Tag string
- *PluralSpec
-}
-
-func (l *Language) String() string {
- return l.Tag
-}
-
-// MatchingTags returns the set of language tags that map to this Language.
-// e.g. "zh-hans-cn" yields {"zh", "zh-hans", "zh-hans-cn"}
-// BUG: This should be computed once and stored as a field on Language for efficiency,
-// but this would require changing how Languages are constructed.
-func (l *Language) MatchingTags() []string {
- parts := strings.Split(l.Tag, "-")
- var prefix, matches []string
- for _, part := range parts {
- prefix = append(prefix, part)
- match := strings.Join(prefix, "-")
- matches = append(matches, match)
- }
- return matches
-}
-
-// Parse returns a slice of supported languages found in src or nil if none are found.
-// It can parse language tags and Accept-Language headers.
-func Parse(src string) []*Language {
- var langs []*Language
- start := 0
- for end, chr := range src {
- switch chr {
- case ',', ';', '.':
- tag := strings.TrimSpace(src[start:end])
- if spec := GetPluralSpec(tag); spec != nil {
- langs = append(langs, &Language{NormalizeTag(tag), spec})
- }
- start = end + 1
- }
- }
- if start > 0 {
- tag := strings.TrimSpace(src[start:])
- if spec := GetPluralSpec(tag); spec != nil {
- langs = append(langs, &Language{NormalizeTag(tag), spec})
- }
- return dedupe(langs)
- }
- if spec := GetPluralSpec(src); spec != nil {
- langs = append(langs, &Language{NormalizeTag(src), spec})
- }
- return langs
-}
-
-func dedupe(langs []*Language) []*Language {
- found := make(map[string]struct{}, len(langs))
- deduped := make([]*Language, 0, len(langs))
- for _, lang := range langs {
- if _, ok := found[lang.Tag]; !ok {
- found[lang.Tag] = struct{}{}
- deduped = append(deduped, lang)
- }
- }
- return deduped
-}
-
-// MustParse is similar to Parse except it panics instead of retuning a nil Language.
-func MustParse(src string) []*Language {
- langs := Parse(src)
- if len(langs) == 0 {
- panic(fmt.Errorf("unable to parse language from %q", src))
- }
- return langs
-}
-
-// Add adds support for a new language.
-func Add(l *Language) {
- tag := NormalizeTag(l.Tag)
- pluralSpecs[tag] = l.PluralSpec
-}
-
-// NormalizeTag returns a language tag with all lower-case characters
-// and dashes "-" instead of underscores "_"
-func NormalizeTag(tag string) string {
- tag = strings.ToLower(tag)
- return strings.Replace(tag, "_", "-", -1)
-}
diff --git a/i18n/language/language_test.go b/i18n/language/language_test.go
deleted file mode 100644
index 1ab3314..0000000
--- a/i18n/language/language_test.go
+++ /dev/null
@@ -1,85 +0,0 @@
-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", []*Language{{"pt-pt", pluralSpecs["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/i18n/language/operands.go b/i18n/language/operands.go
deleted file mode 100644
index c0bee68..0000000
--- a/i18n/language/operands.go
+++ /dev/null
@@ -1,119 +0,0 @@
-package language
-
-import (
- "fmt"
- "strconv"
- "strings"
-)
-
-// Operands is a representation of http://unicode.org/reports/tr35/tr35-numbers.html#Operands
-type Operands struct {
- N float64 // absolute value of the source number (integer and decimals)
- I int64 // integer digits of n
- V int64 // number of visible fraction digits in n, with trailing zeros
- W int64 // number of visible fraction digits in n, without trailing zeros
- F int64 // visible fractional digits in n, with trailing zeros
- T int64 // visible fractional digits in n, without trailing zeros
-}
-
-// NequalsAny returns true if o represents an integer equal to any of the arguments.
-func (o *Operands) NequalsAny(any ...int64) bool {
- for _, i := range any {
- if o.I == i && o.T == 0 {
- return true
- }
- }
- return false
-}
-
-// NmodEqualsAny returns true if o represents an integer equal to any of the arguments modulo mod.
-func (o *Operands) NmodEqualsAny(mod int64, any ...int64) bool {
- modI := o.I % mod
- for _, i := range any {
- if modI == i && o.T == 0 {
- return true
- }
- }
- return false
-}
-
-// NinRange returns true if o represents an integer in the closed interval [from, to].
-func (o *Operands) NinRange(from, to int64) bool {
- return o.T == 0 && from <= o.I && o.I <= to
-}
-
-// NmodInRange returns true if o represents an integer in the closed interval [from, to] modulo mod.
-func (o *Operands) NmodInRange(mod, from, to int64) bool {
- modI := o.I % mod
- return o.T == 0 && from <= modI && modI <= to
-}
-
-func newOperands(v interface{}) (*Operands, error) {
- switch v := v.(type) {
- case int:
- return newOperandsInt64(int64(v)), nil
- case int8:
- return newOperandsInt64(int64(v)), nil
- case int16:
- return newOperandsInt64(int64(v)), nil
- case int32:
- return newOperandsInt64(int64(v)), nil
- case int64:
- return newOperandsInt64(v), nil
- case string:
- return newOperandsString(v)
- case float32, float64:
- return nil, fmt.Errorf("floats should be formatted into a string")
- default:
- return nil, fmt.Errorf("invalid type %T; expected integer or string", v)
- }
-}
-
-func newOperandsInt64(i int64) *Operands {
- if i < 0 {
- i = -i
- }
- return &Operands{float64(i), i, 0, 0, 0, 0}
-}
-
-func newOperandsString(s string) (*Operands, error) {
- if s[0] == '-' {
- s = s[1:]
- }
- n, err := strconv.ParseFloat(s, 64)
- if err != nil {
- return nil, err
- }
- ops := &Operands{N: n}
- parts := strings.SplitN(s, ".", 2)
- ops.I, err = strconv.ParseInt(parts[0], 10, 64)
- if err != nil {
- return nil, err
- }
- if len(parts) == 1 {
- return ops, nil
- }
- fraction := parts[1]
- ops.V = int64(len(fraction))
- for i := ops.V - 1; i >= 0; i-- {
- if fraction[i] != '0' {
- ops.W = i + 1
- break
- }
- }
- if ops.V > 0 {
- f, err := strconv.ParseInt(fraction, 10, 0)
- if err != nil {
- return nil, err
- }
- ops.F = f
- }
- if ops.W > 0 {
- t, err := strconv.ParseInt(fraction[:ops.W], 10, 0)
- if err != nil {
- return nil, err
- }
- ops.T = t
- }
- return ops, nil
-}
diff --git a/i18n/language/operands_test.go b/i18n/language/operands_test.go
deleted file mode 100644
index e4f3390..0000000
--- a/i18n/language/operands_test.go
+++ /dev/null
@@ -1,45 +0,0 @@
-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/i18n/language/plural.go b/i18n/language/plural.go
deleted file mode 100644
index 1f3ea5c..0000000
--- a/i18n/language/plural.go
+++ /dev/null
@@ -1,40 +0,0 @@
-package language
-
-import (
- "fmt"
-)
-
-// Plural represents a language pluralization form as defined here:
-// http://cldr.unicode.org/index/cldr-spec/plural-rules
-type Plural string
-
-// All defined plural categories.
-const (
- Invalid Plural = "invalid"
- Zero = "zero"
- One = "one"
- Two = "two"
- Few = "few"
- Many = "many"
- Other = "other"
-)
-
-// NewPlural returns src as a Plural
-// or Invalid and a non-nil error if src is not a valid Plural.
-func NewPlural(src string) (Plural, error) {
- switch src {
- case "zero":
- return Zero, nil
- case "one":
- return One, nil
- case "two":
- return Two, nil
- case "few":
- return Few, nil
- case "many":
- return Many, nil
- case "other":
- return Other, nil
- }
- return Invalid, fmt.Errorf("invalid plural category %s", src)
-}
diff --git a/i18n/language/plural_test.go b/i18n/language/plural_test.go
deleted file mode 100644
index 6336d29..0000000
--- a/i18n/language/plural_test.go
+++ /dev/null
@@ -1,28 +0,0 @@
-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/i18n/language/pluralspec.go b/i18n/language/pluralspec.go
deleted file mode 100644
index fc31e88..0000000
--- a/i18n/language/pluralspec.go
+++ /dev/null
@@ -1,75 +0,0 @@
-package language
-
-import "strings"
-
-// PluralSpec defines the CLDR plural rules for a language.
-// http://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html
-// http://unicode.org/reports/tr35/tr35-numbers.html#Operands
-type PluralSpec struct {
- Plurals map[Plural]struct{}
- PluralFunc func(*Operands) Plural
-}
-
-var pluralSpecs = make(map[string]*PluralSpec)
-
-func normalizePluralSpecID(id string) string {
- id = strings.Replace(id, "_", "-", -1)
- id = strings.ToLower(id)
- return id
-}
-
-// RegisterPluralSpec registers a new plural spec for the language ids.
-func RegisterPluralSpec(ids []string, ps *PluralSpec) {
- for _, id := range ids {
- id = normalizePluralSpecID(id)
- pluralSpecs[id] = ps
- }
-}
-
-// Plural returns the plural category for number as defined by
-// the language's CLDR plural rules.
-func (ps *PluralSpec) Plural(number interface{}) (Plural, error) {
- ops, err := newOperands(number)
- if err != nil {
- return Invalid, err
- }
- return ps.PluralFunc(ops), nil
-}
-
-// GetPluralSpec returns the PluralSpec that matches the longest prefix of tag.
-// It returns nil if no PluralSpec matches tag.
-func GetPluralSpec(tag string) *PluralSpec {
- tag = NormalizeTag(tag)
- subtag := tag
- for {
- if spec := pluralSpecs[subtag]; spec != nil {
- return spec
- }
- end := strings.LastIndex(subtag, "-")
- if end == -1 {
- return nil
- }
- subtag = subtag[:end]
- }
-}
-
-func newPluralSet(plurals ...Plural) map[Plural]struct{} {
- set := make(map[Plural]struct{}, len(plurals))
- for _, plural := range plurals {
- set[plural] = struct{}{}
- }
- return set
-}
-
-func intInRange(i, from, to int64) bool {
- return from <= i && i <= to
-}
-
-func intEqualsAny(i int64, any ...int64) bool {
- for _, a := range any {
- if i == a {
- return true
- }
- }
- return false
-}
diff --git a/i18n/language/pluralspec_gen.go b/i18n/language/pluralspec_gen.go
deleted file mode 100644
index 0268bb9..0000000
--- a/i18n/language/pluralspec_gen.go
+++ /dev/null
@@ -1,557 +0,0 @@
-package language
-
-// This file is generated by i18n/language/codegen/generate.sh
-
-func init() {
-
- RegisterPluralSpec([]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", "yue", "zh"}, &PluralSpec{
- Plurals: newPluralSet(Other),
- PluralFunc: func(ops *Operands) Plural {
- return Other
- },
- })
- RegisterPluralSpec([]string{"am", "as", "bn", "fa", "gu", "hi", "kn", "mr", "zu"}, &PluralSpec{
- Plurals: newPluralSet(One, Other),
- PluralFunc: func(ops *Operands) Plural {
- // i = 0 or n = 1
- if intEqualsAny(ops.I, 0) ||
- ops.NequalsAny(1) {
- return One
- }
- return Other
- },
- })
- RegisterPluralSpec([]string{"ff", "fr", "hy", "kab"}, &PluralSpec{
- Plurals: newPluralSet(One, Other),
- PluralFunc: func(ops *Operands) Plural {
- // i = 0,1
- if intEqualsAny(ops.I, 0, 1) {
- return One
- }
- return Other
- },
- })
- RegisterPluralSpec([]string{"pt"}, &PluralSpec{
- Plurals: newPluralSet(One, Other),
- PluralFunc: func(ops *Operands) Plural {
- // i = 0..1
- if intInRange(ops.I, 0, 1) {
- return One
- }
- return Other
- },
- })
- RegisterPluralSpec([]string{"ast", "ca", "de", "en", "et", "fi", "fy", "gl", "it", "ji", "nl", "sv", "sw", "ur", "yi"}, &PluralSpec{
- Plurals: newPluralSet(One, Other),
- PluralFunc: func(ops *Operands) Plural {
- // i = 1 and v = 0
- if intEqualsAny(ops.I, 1) && intEqualsAny(ops.V, 0) {
- return One
- }
- return Other
- },
- })
- RegisterPluralSpec([]string{"si"}, &PluralSpec{
- Plurals: newPluralSet(One, Other),
- PluralFunc: func(ops *Operands) Plural {
- // n = 0,1 or i = 0 and f = 1
- if ops.NequalsAny(0, 1) ||
- intEqualsAny(ops.I, 0) && intEqualsAny(ops.F, 1) {
- return One
- }
- return Other
- },
- })
- RegisterPluralSpec([]string{"ak", "bh", "guw", "ln", "mg", "nso", "pa", "ti", "wa"}, &PluralSpec{
- Plurals: newPluralSet(One, Other),
- PluralFunc: func(ops *Operands) Plural {
- // n = 0..1
- if ops.NinRange(0, 1) {
- return One
- }
- return Other
- },
- })
- RegisterPluralSpec([]string{"tzm"}, &PluralSpec{
- Plurals: newPluralSet(One, Other),
- PluralFunc: func(ops *Operands) Plural {
- // n = 0..1 or n = 11..99
- if ops.NinRange(0, 1) ||
- ops.NinRange(11, 99) {
- return One
- }
- return Other
- },
- })
- RegisterPluralSpec([]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"}, &PluralSpec{
- Plurals: newPluralSet(One, Other),
- PluralFunc: func(ops *Operands) Plural {
- // n = 1
- if ops.NequalsAny(1) {
- return One
- }
- return Other
- },
- })
- RegisterPluralSpec([]string{"da"}, &PluralSpec{
- Plurals: newPluralSet(One, Other),
- PluralFunc: func(ops *Operands) Plural {
- // n = 1 or t != 0 and i = 0,1
- if ops.NequalsAny(1) ||
- !intEqualsAny(ops.T, 0) && intEqualsAny(ops.I, 0, 1) {
- return One
- }
- return Other
- },
- })
- RegisterPluralSpec([]string{"is"}, &PluralSpec{
- Plurals: newPluralSet(One, Other),
- PluralFunc: func(ops *Operands) Plural {
- // t = 0 and i % 10 = 1 and i % 100 != 11 or t != 0
- if intEqualsAny(ops.T, 0) && intEqualsAny(ops.I%10, 1) && !intEqualsAny(ops.I%100, 11) ||
- !intEqualsAny(ops.T, 0) {
- return One
- }
- return Other
- },
- })
- RegisterPluralSpec([]string{"mk"}, &PluralSpec{
- Plurals: newPluralSet(One, Other),
- PluralFunc: func(ops *Operands) Plural {
- // v = 0 and i % 10 = 1 or f % 10 = 1
- if intEqualsAny(ops.V, 0) && intEqualsAny(ops.I%10, 1) ||
- intEqualsAny(ops.F%10, 1) {
- return One
- }
- return Other
- },
- })
- RegisterPluralSpec([]string{"fil", "tl"}, &PluralSpec{
- Plurals: newPluralSet(One, Other),
- PluralFunc: func(ops *Operands) Plural {
- // 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
- if intEqualsAny(ops.V, 0) && intEqualsAny(ops.I, 1, 2, 3) ||
- intEqualsAny(ops.V, 0) && !intEqualsAny(ops.I%10, 4, 6, 9) ||
- !intEqualsAny(ops.V, 0) && !intEqualsAny(ops.F%10, 4, 6, 9) {
- return One
- }
- return Other
- },
- })
- RegisterPluralSpec([]string{"lv", "prg"}, &PluralSpec{
- Plurals: newPluralSet(Zero, One, Other),
- PluralFunc: func(ops *Operands) Plural {
- // n % 10 = 0 or n % 100 = 11..19 or v = 2 and f % 100 = 11..19
- if ops.NmodEqualsAny(10, 0) ||
- ops.NmodInRange(100, 11, 19) ||
- intEqualsAny(ops.V, 2) && intInRange(ops.F%100, 11, 19) {
- return Zero
- }
- // 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
- if ops.NmodEqualsAny(10, 1) && !ops.NmodEqualsAny(100, 11) ||
- intEqualsAny(ops.V, 2) && intEqualsAny(ops.F%10, 1) && !intEqualsAny(ops.F%100, 11) ||
- !intEqualsAny(ops.V, 2) && intEqualsAny(ops.F%10, 1) {
- return One
- }
- return Other
- },
- })
- RegisterPluralSpec([]string{"lag"}, &PluralSpec{
- Plurals: newPluralSet(Zero, One, Other),
- PluralFunc: func(ops *Operands) Plural {
- // n = 0
- if ops.NequalsAny(0) {
- return Zero
- }
- // i = 0,1 and n != 0
- if intEqualsAny(ops.I, 0, 1) && !ops.NequalsAny(0) {
- return One
- }
- return Other
- },
- })
- RegisterPluralSpec([]string{"ksh"}, &PluralSpec{
- Plurals: newPluralSet(Zero, One, Other),
- PluralFunc: func(ops *Operands) Plural {
- // n = 0
- if ops.NequalsAny(0) {
- return Zero
- }
- // n = 1
- if ops.NequalsAny(1) {
- return One
- }
- return Other
- },
- })
- RegisterPluralSpec([]string{"iu", "kw", "naq", "se", "sma", "smi", "smj", "smn", "sms"}, &PluralSpec{
- Plurals: newPluralSet(One, Two, Other),
- PluralFunc: func(ops *Operands) Plural {
- // n = 1
- if ops.NequalsAny(1) {
- return One
- }
- // n = 2
- if ops.NequalsAny(2) {
- return Two
- }
- return Other
- },
- })
- RegisterPluralSpec([]string{"shi"}, &PluralSpec{
- Plurals: newPluralSet(One, Few, Other),
- PluralFunc: func(ops *Operands) Plural {
- // i = 0 or n = 1
- if intEqualsAny(ops.I, 0) ||
- ops.NequalsAny(1) {
- return One
- }
- // n = 2..10
- if ops.NinRange(2, 10) {
- return Few
- }
- return Other
- },
- })
- RegisterPluralSpec([]string{"mo", "ro"}, &PluralSpec{
- Plurals: newPluralSet(One, Few, Other),
- PluralFunc: func(ops *Operands) Plural {
- // i = 1 and v = 0
- if intEqualsAny(ops.I, 1) && intEqualsAny(ops.V, 0) {
- return One
- }
- // v != 0 or n = 0 or n != 1 and n % 100 = 1..19
- if !intEqualsAny(ops.V, 0) ||
- ops.NequalsAny(0) ||
- !ops.NequalsAny(1) && ops.NmodInRange(100, 1, 19) {
- return Few
- }
- return Other
- },
- })
- RegisterPluralSpec([]string{"bs", "hr", "sh", "sr"}, &PluralSpec{
- Plurals: newPluralSet(One, Few, Other),
- PluralFunc: func(ops *Operands) Plural {
- // v = 0 and i % 10 = 1 and i % 100 != 11 or f % 10 = 1 and f % 100 != 11
- if intEqualsAny(ops.V, 0) && intEqualsAny(ops.I%10, 1) && !intEqualsAny(ops.I%100, 11) ||
- intEqualsAny(ops.F%10, 1) && !intEqualsAny(ops.F%100, 11) {
- return One
- }
- // v = 0 and i % 10 = 2..4 and i % 100 != 12..14 or f % 10 = 2..4 and f % 100 != 12..14
- if intEqualsAny(ops.V, 0) && intInRange(ops.I%10, 2, 4) && !intInRange(ops.I%100, 12, 14) ||
- intInRange(ops.F%10, 2, 4) && !intInRange(ops.F%100, 12, 14) {
- return Few
- }
- return Other
- },
- })
- RegisterPluralSpec([]string{"gd"}, &PluralSpec{
- Plurals: newPluralSet(One, Two, Few, Other),
- PluralFunc: func(ops *Operands) Plural {
- // n = 1,11
- if ops.NequalsAny(1, 11) {
- return One
- }
- // n = 2,12
- if ops.NequalsAny(2, 12) {
- return Two
- }
- // n = 3..10,13..19
- if ops.NinRange(3, 10) || ops.NinRange(13, 19) {
- return Few
- }
- return Other
- },
- })
- RegisterPluralSpec([]string{"sl"}, &PluralSpec{
- Plurals: newPluralSet(One, Two, Few, Other),
- PluralFunc: func(ops *Operands) Plural {
- // v = 0 and i % 100 = 1
- if intEqualsAny(ops.V, 0) && intEqualsAny(ops.I%100, 1) {
- return One
- }
- // v = 0 and i % 100 = 2
- if intEqualsAny(ops.V, 0) && intEqualsAny(ops.I%100, 2) {
- return Two
- }
- // v = 0 and i % 100 = 3..4 or v != 0
- if intEqualsAny(ops.V, 0) && intInRange(ops.I%100, 3, 4) ||
- !intEqualsAny(ops.V, 0) {
- return Few
- }
- return Other
- },
- })
- RegisterPluralSpec([]string{"dsb", "hsb"}, &PluralSpec{
- Plurals: newPluralSet(One, Two, Few, Other),
- PluralFunc: func(ops *Operands) Plural {
- // v = 0 and i % 100 = 1 or f % 100 = 1
- if intEqualsAny(ops.V, 0) && intEqualsAny(ops.I%100, 1) ||
- intEqualsAny(ops.F%100, 1) {
- return One
- }
- // v = 0 and i % 100 = 2 or f % 100 = 2
- if intEqualsAny(ops.V, 0) && intEqualsAny(ops.I%100, 2) ||
- intEqualsAny(ops.F%100, 2) {
- return Two
- }
- // v = 0 and i % 100 = 3..4 or f % 100 = 3..4
- if intEqualsAny(ops.V, 0) && intInRange(ops.I%100, 3, 4) ||
- intInRange(ops.F%100, 3, 4) {
- return Few
- }
- return Other
- },
- })
- RegisterPluralSpec([]string{"he", "iw"}, &PluralSpec{
- Plurals: newPluralSet(One, Two, Many, Other),
- PluralFunc: func(ops *Operands) Plural {
- // i = 1 and v = 0
- if intEqualsAny(ops.I, 1) && intEqualsAny(ops.V, 0) {
- return One
- }
- // i = 2 and v = 0
- if intEqualsAny(ops.I, 2) && intEqualsAny(ops.V, 0) {
- return Two
- }
- // v = 0 and n != 0..10 and n % 10 = 0
- if intEqualsAny(ops.V, 0) && !ops.NinRange(0, 10) && ops.NmodEqualsAny(10, 0) {
- return Many
- }
- return Other
- },
- })
- RegisterPluralSpec([]string{"cs", "sk"}, &PluralSpec{
- Plurals: newPluralSet(One, Few, Many, Other),
- PluralFunc: func(ops *Operands) Plural {
- // i = 1 and v = 0
- if intEqualsAny(ops.I, 1) && intEqualsAny(ops.V, 0) {
- return One
- }
- // i = 2..4 and v = 0
- if intInRange(ops.I, 2, 4) && intEqualsAny(ops.V, 0) {
- return Few
- }
- // v != 0
- if !intEqualsAny(ops.V, 0) {
- return Many
- }
- return Other
- },
- })
- RegisterPluralSpec([]string{"pl"}, &PluralSpec{
- Plurals: newPluralSet(One, Few, Many, Other),
- PluralFunc: func(ops *Operands) Plural {
- // i = 1 and v = 0
- if intEqualsAny(ops.I, 1) && intEqualsAny(ops.V, 0) {
- return One
- }
- // v = 0 and i % 10 = 2..4 and i % 100 != 12..14
- if intEqualsAny(ops.V, 0) && intInRange(ops.I%10, 2, 4) && !intInRange(ops.I%100, 12, 14) {
- return Few
- }
- // 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
- if intEqualsAny(ops.V, 0) && !intEqualsAny(ops.I, 1) && intInRange(ops.I%10, 0, 1) ||
- intEqualsAny(ops.V, 0) && intInRange(ops.I%10, 5, 9) ||
- intEqualsAny(ops.V, 0) && intInRange(ops.I%100, 12, 14) {
- return Many
- }
- return Other
- },
- })
- RegisterPluralSpec([]string{"be"}, &PluralSpec{
- Plurals: newPluralSet(One, Few, Many, Other),
- PluralFunc: func(ops *Operands) Plural {
- // n % 10 = 1 and n % 100 != 11
- if ops.NmodEqualsAny(10, 1) && !ops.NmodEqualsAny(100, 11) {
- return One
- }
- // n % 10 = 2..4 and n % 100 != 12..14
- if ops.NmodInRange(10, 2, 4) && !ops.NmodInRange(100, 12, 14) {
- return Few
- }
- // n % 10 = 0 or n % 10 = 5..9 or n % 100 = 11..14
- if ops.NmodEqualsAny(10, 0) ||
- ops.NmodInRange(10, 5, 9) ||
- ops.NmodInRange(100, 11, 14) {
- return Many
- }
- return Other
- },
- })
- RegisterPluralSpec([]string{"lt"}, &PluralSpec{
- Plurals: newPluralSet(One, Few, Many, Other),
- PluralFunc: func(ops *Operands) Plural {
- // n % 10 = 1 and n % 100 != 11..19
- if ops.NmodEqualsAny(10, 1) && !ops.NmodInRange(100, 11, 19) {
- return One
- }
- // n % 10 = 2..9 and n % 100 != 11..19
- if ops.NmodInRange(10, 2, 9) && !ops.NmodInRange(100, 11, 19) {
- return Few
- }
- // f != 0
- if !intEqualsAny(ops.F, 0) {
- return Many
- }
- return Other
- },
- })
- RegisterPluralSpec([]string{"mt"}, &PluralSpec{
- Plurals: newPluralSet(One, Few, Many, Other),
- PluralFunc: func(ops *Operands) Plural {
- // n = 1
- if ops.NequalsAny(1) {
- return One
- }
- // n = 0 or n % 100 = 2..10
- if ops.NequalsAny(0) ||
- ops.NmodInRange(100, 2, 10) {
- return Few
- }
- // n % 100 = 11..19
- if ops.NmodInRange(100, 11, 19) {
- return Many
- }
- return Other
- },
- })
- RegisterPluralSpec([]string{"ru", "uk"}, &PluralSpec{
- Plurals: newPluralSet(One, Few, Many, Other),
- PluralFunc: func(ops *Operands) Plural {
- // v = 0 and i % 10 = 1 and i % 100 != 11
- if intEqualsAny(ops.V, 0) && intEqualsAny(ops.I%10, 1) && !intEqualsAny(ops.I%100, 11) {
- return One
- }
- // v = 0 and i % 10 = 2..4 and i % 100 != 12..14
- if intEqualsAny(ops.V, 0) && intInRange(ops.I%10, 2, 4) && !intInRange(ops.I%100, 12, 14) {
- return Few
- }
- // v = 0 and i % 10 = 0 or v = 0 and i % 10 = 5..9 or v = 0 and i % 100 = 11..14
- if intEqualsAny(ops.V, 0) && intEqualsAny(ops.I%10, 0) ||
- intEqualsAny(ops.V, 0) && intInRange(ops.I%10, 5, 9) ||
- intEqualsAny(ops.V, 0) && intInRange(ops.I%100, 11, 14) {
- return Many
- }
- return Other
- },
- })
- RegisterPluralSpec([]string{"br"}, &PluralSpec{
- Plurals: newPluralSet(One, Two, Few, Many, Other),
- PluralFunc: func(ops *Operands) Plural {
- // n % 10 = 1 and n % 100 != 11,71,91
- if ops.NmodEqualsAny(10, 1) && !ops.NmodEqualsAny(100, 11, 71, 91) {
- return One
- }
- // n % 10 = 2 and n % 100 != 12,72,92
- if ops.NmodEqualsAny(10, 2) && !ops.NmodEqualsAny(100, 12, 72, 92) {
- return Two
- }
- // n % 10 = 3..4,9 and n % 100 != 10..19,70..79,90..99
- if (ops.NmodInRange(10, 3, 4) || ops.NmodEqualsAny(10, 9)) && !(ops.NmodInRange(100, 10, 19) || ops.NmodInRange(100, 70, 79) || ops.NmodInRange(100, 90, 99)) {
- return Few
- }
- // n != 0 and n % 1000000 = 0
- if !ops.NequalsAny(0) && ops.NmodEqualsAny(1000000, 0) {
- return Many
- }
- return Other
- },
- })
- RegisterPluralSpec([]string{"ga"}, &PluralSpec{
- Plurals: newPluralSet(One, Two, Few, Many, Other),
- PluralFunc: func(ops *Operands) Plural {
- // n = 1
- if ops.NequalsAny(1) {
- return One
- }
- // n = 2
- if ops.NequalsAny(2) {
- return Two
- }
- // n = 3..6
- if ops.NinRange(3, 6) {
- return Few
- }
- // n = 7..10
- if ops.NinRange(7, 10) {
- return Many
- }
- return Other
- },
- })
- RegisterPluralSpec([]string{"gv"}, &PluralSpec{
- Plurals: newPluralSet(One, Two, Few, Many, Other),
- PluralFunc: func(ops *Operands) Plural {
- // v = 0 and i % 10 = 1
- if intEqualsAny(ops.V, 0) && intEqualsAny(ops.I%10, 1) {
- return One
- }
- // v = 0 and i % 10 = 2
- if intEqualsAny(ops.V, 0) && intEqualsAny(ops.I%10, 2) {
- return Two
- }
- // v = 0 and i % 100 = 0,20,40,60,80
- if intEqualsAny(ops.V, 0) && intEqualsAny(ops.I%100, 0, 20, 40, 60, 80) {
- return Few
- }
- // v != 0
- if !intEqualsAny(ops.V, 0) {
- return Many
- }
- return Other
- },
- })
- RegisterPluralSpec([]string{"ar", "ars"}, &PluralSpec{
- Plurals: newPluralSet(Zero, One, Two, Few, Many, Other),
- PluralFunc: func(ops *Operands) Plural {
- // n = 0
- if ops.NequalsAny(0) {
- return Zero
- }
- // n = 1
- if ops.NequalsAny(1) {
- return One
- }
- // n = 2
- if ops.NequalsAny(2) {
- return Two
- }
- // n % 100 = 3..10
- if ops.NmodInRange(100, 3, 10) {
- return Few
- }
- // n % 100 = 11..99
- if ops.NmodInRange(100, 11, 99) {
- return Many
- }
- return Other
- },
- })
- RegisterPluralSpec([]string{"cy"}, &PluralSpec{
- Plurals: newPluralSet(Zero, One, Two, Few, Many, Other),
- PluralFunc: func(ops *Operands) Plural {
- // n = 0
- if ops.NequalsAny(0) {
- return Zero
- }
- // n = 1
- if ops.NequalsAny(1) {
- return One
- }
- // n = 2
- if ops.NequalsAny(2) {
- return Two
- }
- // n = 3
- if ops.NequalsAny(3) {
- return Few
- }
- // n = 6
- if ops.NequalsAny(6) {
- return Many
- }
- return Other
- },
- })
-}
diff --git a/i18n/language/pluralspec_gen_test.go b/i18n/language/pluralspec_gen_test.go
deleted file mode 100644
index 4cfa97b..0000000
--- a/i18n/language/pluralspec_gen_test.go
+++ /dev/null
@@ -1,631 +0,0 @@
-package language
-
-// This file is generated by i18n/language/codegen/generate.sh
-
-import "testing"
-
-func TestBmBoDzIdIgIiInJaJboJvJwKdeKeaKmKoLktLoMsMyNqoRootSahSesSgThToViWoYoYueZh(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", "yue", "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 TestPt(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{"pt"}
- 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 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 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 TestArArs(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", "ars"}
- 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/i18n/language/pluralspec_test.go b/i18n/language/pluralspec_test.go
deleted file mode 100644
index e9ff407..0000000
--- a/i18n/language/pluralspec_test.go
+++ /dev/null
@@ -1,716 +0,0 @@
-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", pluralSpecs["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) = %v expected %v", 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, One},
- {2, Other},
- }
- tests = appendFloatTests(tests, 0, 1.5, One)
- tests = appendFloatTests(tests, 2, 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 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/v2/i18n/language_test.go b/i18n/language_test.go
index 3c4de69..3c4de69 100644
--- a/v2/i18n/language_test.go
+++ b/i18n/language_test.go
diff --git a/v2/i18n/localizer.go b/i18n/localizer.go
index 5d3b0df..5d3b0df 100644
--- a/v2/i18n/localizer.go
+++ b/i18n/localizer.go
diff --git a/v2/i18n/localizer_test.go b/i18n/localizer_test.go
index d08e970..d08e970 100644
--- a/v2/i18n/localizer_test.go
+++ b/i18n/localizer_test.go
diff --git a/v2/i18n/message.go b/i18n/message.go
index f8f789a..f8f789a 100644
--- a/v2/i18n/message.go
+++ b/i18n/message.go
diff --git a/v2/i18n/message_template.go b/i18n/message_template.go
index 65a16cb..65a16cb 100644
--- a/v2/i18n/message_template.go
+++ b/i18n/message_template.go
diff --git a/v2/i18n/message_template_test.go b/i18n/message_template_test.go
index d920cd4..d920cd4 100644
--- a/v2/i18n/message_template_test.go
+++ b/i18n/message_template_test.go
diff --git a/v2/i18n/message_test.go b/i18n/message_test.go
index b37063a..b37063a 100644
--- a/v2/i18n/message_test.go
+++ b/i18n/message_test.go
diff --git a/v2/i18n/parse.go b/i18n/parse.go
index 57dd7fe..57dd7fe 100644
--- a/v2/i18n/parse.go
+++ b/i18n/parse.go
diff --git a/v2/i18n/parse_test.go b/i18n/parse_test.go
index 3272e52..3272e52 100644
--- a/v2/i18n/parse_test.go
+++ b/i18n/parse_test.go
diff --git a/i18n/translation/plural_translation.go b/i18n/translation/plural_translation.go
deleted file mode 100644
index 17c3260..0000000
--- a/i18n/translation/plural_translation.go
+++ /dev/null
@@ -1,82 +0,0 @@
-package translation
-
-import (
- "github.com/nicksnyder/go-i18n/i18n/language"
-)
-
-type pluralTranslation struct {
- id string
- templates map[language.Plural]*template
-}
-
-func (pt *pluralTranslation) MarshalInterface() interface{} {
- return map[string]interface{}{
- "id": pt.id,
- "translation": pt.templates,
- }
-}
-
-func (pt *pluralTranslation) MarshalFlatInterface() interface{} {
- return pt.templates
-}
-
-func (pt *pluralTranslation) ID() string {
- return pt.id
-}
-
-func (pt *pluralTranslation) Template(pc language.Plural) *template {
- return pt.templates[pc]
-}
-
-func (pt *pluralTranslation) UntranslatedCopy() Translation {
- return &pluralTranslation{pt.id, make(map[language.Plural]*template)}
-}
-
-func (pt *pluralTranslation) Normalize(l *language.Language) Translation {
- // Delete plural categories that don't belong to this language.
- for pc := range pt.templates {
- if _, ok := l.Plurals[pc]; !ok {
- delete(pt.templates, pc)
- }
- }
- // Create map entries for missing valid categories.
- for pc := range l.Plurals {
- if _, ok := pt.templates[pc]; !ok {
- pt.templates[pc] = mustNewTemplate("")
- }
- }
- return pt
-}
-
-func (pt *pluralTranslation) Backfill(src Translation) Translation {
- for pc, t := range pt.templates {
- if (t == nil || t.src == "") && src != nil {
- pt.templates[pc] = src.Template(language.Other)
- }
- }
- return pt
-}
-
-func (pt *pluralTranslation) Merge(t Translation) Translation {
- other, ok := t.(*pluralTranslation)
- if !ok || pt.ID() != t.ID() {
- return t
- }
- for pluralCategory, template := range other.templates {
- if template != nil && template.src != "" {
- pt.templates[pluralCategory] = template
- }
- }
- return pt
-}
-
-func (pt *pluralTranslation) Incomplete(l *language.Language) bool {
- for pc := range l.Plurals {
- if t := pt.templates[pc]; t == nil || t.src == "" {
- return true
- }
- }
- return false
-}
-
-var _ = Translation(&pluralTranslation{})
diff --git a/i18n/translation/plural_translation_test.go b/i18n/translation/plural_translation_test.go
deleted file mode 100644
index ea7de7f..0000000
--- a/i18n/translation/plural_translation_test.go
+++ /dev/null
@@ -1,308 +0,0 @@
-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/i18n/translation/single_translation.go b/i18n/translation/single_translation.go
deleted file mode 100644
index a76c8c9..0000000
--- a/i18n/translation/single_translation.go
+++ /dev/null
@@ -1,61 +0,0 @@
-package translation
-
-import (
- "github.com/nicksnyder/go-i18n/i18n/language"
-)
-
-type singleTranslation struct {
- id string
- template *template
-}
-
-func (st *singleTranslation) MarshalInterface() interface{} {
- return map[string]interface{}{
- "id": st.id,
- "translation": st.template,
- }
-}
-
-func (st *singleTranslation) MarshalFlatInterface() interface{} {
- return map[string]interface{}{"other": st.template}
-}
-
-func (st *singleTranslation) ID() string {
- return st.id
-}
-
-func (st *singleTranslation) Template(pc language.Plural) *template {
- return st.template
-}
-
-func (st *singleTranslation) UntranslatedCopy() Translation {
- return &singleTranslation{st.id, mustNewTemplate("")}
-}
-
-func (st *singleTranslation) Normalize(language *language.Language) Translation {
- return st
-}
-
-func (st *singleTranslation) Backfill(src Translation) Translation {
- if (st.template == nil || st.template.src == "") && src != nil {
- st.template = src.Template(language.Other)
- }
- return st
-}
-
-func (st *singleTranslation) Merge(t Translation) Translation {
- other, ok := t.(*singleTranslation)
- if !ok || st.ID() != t.ID() {
- return t
- }
- if other.template != nil && other.template.src != "" {
- st.template = other.template
- }
- return st
-}
-
-func (st *singleTranslation) Incomplete(l *language.Language) bool {
- return st.template == nil || st.template.src == ""
-}
-
-var _ = Translation(&singleTranslation{})
diff --git a/i18n/translation/template.go b/i18n/translation/template.go
deleted file mode 100644
index 3310150..0000000
--- a/i18n/translation/template.go
+++ /dev/null
@@ -1,65 +0,0 @@
-package translation
-
-import (
- "bytes"
- "encoding"
- "strings"
- gotemplate "text/template"
-)
-
-type template struct {
- tmpl *gotemplate.Template
- src string
-}
-
-func newTemplate(src string) (*template, error) {
- if src == "" {
- return new(template), nil
- }
-
- var tmpl template
- err := tmpl.parseTemplate(src)
- return &tmpl, err
-}
-
-func mustNewTemplate(src string) *template {
- t, err := newTemplate(src)
- if err != nil {
- panic(err)
- }
- return t
-}
-
-func (t *template) String() string {
- return t.src
-}
-
-func (t *template) Execute(args interface{}) string {
- if t.tmpl == nil {
- return t.src
- }
- var buf bytes.Buffer
- if err := t.tmpl.Execute(&buf, args); err != nil {
- return err.Error()
- }
- return buf.String()
-}
-
-func (t *template) MarshalText() ([]byte, error) {
- return []byte(t.src), nil
-}
-
-func (t *template) UnmarshalText(src []byte) error {
- return t.parseTemplate(string(src))
-}
-
-func (t *template) parseTemplate(src string) (err error) {
- t.src = src
- if strings.Contains(src, "{{") {
- t.tmpl, err = gotemplate.New(src).Parse(src)
- }
- return
-}
-
-var _ = encoding.TextMarshaler(&template{})
-var _ = encoding.TextUnmarshaler(&template{})
diff --git a/i18n/translation/template_test.go b/i18n/translation/template_test.go
deleted file mode 100644
index a28c3ed..0000000
--- a/i18n/translation/template_test.go
+++ /dev/null
@@ -1,89 +0,0 @@
-package translation
-
-import (
- "bytes"
- "fmt"
-
- "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{}
- if err := tmpl.UnmarshalText([]byte("hello {{.World}}")); err != nil {
- t.Fatal(err)
- }
- 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",
- })
- }
-}
-
-var sprintfResult string
-
-func BenchmarkSprintf(b *testing.B) {
- b.ResetTimer()
- for i := 0; i < b.N; i++ {
- sprintfResult = fmt.Sprintf("hello %s", "nick")
- }
-}
diff --git a/i18n/translation/translation.go b/i18n/translation/translation.go
deleted file mode 100644
index 93f87f6..0000000
--- a/i18n/translation/translation.go
+++ /dev/null
@@ -1,84 +0,0 @@
-// Package translation defines the interface for a translation.
-package translation
-
-import (
- "fmt"
-
- "github.com/nicksnyder/go-i18n/i18n/language"
-)
-
-// Translation is the interface that represents a translated string.
-type Translation interface {
- // MarshalInterface returns the object that should be used
- // to serialize the translation.
- MarshalInterface() interface{}
- MarshalFlatInterface() interface{}
- ID() string
- Template(language.Plural) *template
- UntranslatedCopy() Translation
- Normalize(language *language.Language) Translation
- Backfill(src Translation) Translation
- Merge(Translation) Translation
- Incomplete(l *language.Language) bool
-}
-
-// SortableByID implements sort.Interface for a slice of translations.
-type SortableByID []Translation
-
-func (a SortableByID) Len() int { return len(a) }
-func (a SortableByID) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
-func (a SortableByID) Less(i, j int) bool { return a[i].ID() < a[j].ID() }
-
-// NewTranslation reflects on data to create a new Translation.
-//
-// data["id"] must be a string and data["translation"] must be either a string
-// for a non-plural translation or a map[string]interface{} for a plural translation.
-func NewTranslation(data map[string]interface{}) (Translation, error) {
- id, ok := data["id"].(string)
- if !ok {
- return nil, fmt.Errorf(`missing "id" key`)
- }
- var pluralObject map[string]interface{}
- switch translation := data["translation"].(type) {
- case string:
- tmpl, err := newTemplate(translation)
- if err != nil {
- return nil, err
- }
- return &singleTranslation{id, tmpl}, nil
- case map[interface{}]interface{}:
- // The YAML parser uses interface{} keys so we first convert them to string keys.
- pluralObject = make(map[string]interface{})
- for k, v := range translation {
- kstr, ok := k.(string)
- if !ok {
- return nil, fmt.Errorf(`invalid plural category type %T; expected string`, k)
- }
- pluralObject[kstr] = v
- }
- case map[string]interface{}:
- pluralObject = translation
- case nil:
- return nil, fmt.Errorf(`missing "translation" key`)
- default:
- return nil, fmt.Errorf(`unsupported type for "translation" key %T`, translation)
- }
-
- templates := make(map[language.Plural]*template, len(pluralObject))
- for k, v := range pluralObject {
- pc, err := language.NewPlural(k)
- if err != nil {
- return nil, err
- }
- str, ok := v.(string)
- if !ok {
- return nil, fmt.Errorf(`plural category "%s" has value of type %T; expected string`, pc, v)
- }
- tmpl, err := newTemplate(str)
- if err != nil {
- return nil, err
- }
- templates[pc] = tmpl
- }
- return &pluralTranslation{id, templates}, nil
-}
diff --git a/i18n/translation/translation_test.go b/i18n/translation/translation_test.go
deleted file mode 100644
index 4740e02..0000000
--- a/i18n/translation/translation_test.go
+++ /dev/null
@@ -1,17 +0,0 @@
-package translation
-
-import (
- "sort"
- "testing"
-)
-
-// Check this here to avoid unnecessary import of sort package.
-var _ = sort.Interface(make(SortableByID, 0))
-
-func TestNewSingleTranslation(t *testing.T) {
- t.Skipf("not implemented")
-}
-
-func TestNewPluralTranslation(t *testing.T) {
- t.Skipf("not implemented")
-}
diff --git a/i18n/translations_test.go b/i18n/translations_test.go
deleted file mode 100644
index ba1a21b..0000000
--- a/i18n/translations_test.go
+++ /dev/null
@@ -1,89 +0,0 @@
-package i18n
-
-import (
- "testing"
-
- "github.com/nicksnyder/go-i18n/i18n/bundle"
-)
-
-var bobMap = map[string]interface{}{"Person": "Bob"}
-var bobStruct = struct{ Person string }{Person: "Bob"}
-
-var testCases = []struct {
- id string
- arg interface{}
- want string
-}{
- {"program_greeting", nil, "Hello world"},
- {"person_greeting", bobMap, "Hello Bob"},
- {"person_greeting", bobStruct, "Hello Bob"},
-
- {"your_unread_email_count", 0, "You have 0 unread emails."},
- {"your_unread_email_count", 1, "You have 1 unread email."},
- {"your_unread_email_count", 2, "You have 2 unread emails."},
- {"my_height_in_meters", "1.7", "I am 1.7 meters tall."},
-
- {"person_unread_email_count", []interface{}{0, bobMap}, "Bob has 0 unread emails."},
- {"person_unread_email_count", []interface{}{1, bobMap}, "Bob has 1 unread email."},
- {"person_unread_email_count", []interface{}{2, bobMap}, "Bob has 2 unread emails."},
- {"person_unread_email_count", []interface{}{0, bobStruct}, "Bob has 0 unread emails."},
- {"person_unread_email_count", []interface{}{1, bobStruct}, "Bob has 1 unread email."},
- {"person_unread_email_count", []interface{}{2, bobStruct}, "Bob has 2 unread emails."},
-
- {"person_unread_email_count_timeframe", []interface{}{3, map[string]interface{}{
- "Person": "Bob",
- "Timeframe": "0 days",
- }}, "Bob has 3 unread emails in the past 0 days."},
- {"person_unread_email_count_timeframe", []interface{}{3, map[string]interface{}{
- "Person": "Bob",
- "Timeframe": "1 day",
- }}, "Bob has 3 unread emails in the past 1 day."},
- {"person_unread_email_count_timeframe", []interface{}{3, map[string]interface{}{
- "Person": "Bob",
- "Timeframe": "2 days",
- }}, "Bob has 3 unread emails in the past 2 days."},
-}
-
-func testFile(t *testing.T, path string) {
- b := bundle.New()
- b.MustLoadTranslationFile(path)
-
- T, err := b.Tfunc("en-US")
- if err != nil {
- t.Fatal(err)
- }
-
- for _, tc := range testCases {
- var args []interface{}
- if _, ok := tc.arg.([]interface{}); ok {
- args = tc.arg.([]interface{})
- } else {
- args = []interface{}{tc.arg}
- }
-
- got := T(tc.id, args...)
- if got != tc.want {
- t.Errorf("got: %v; want: %v", got, tc.want)
- }
- }
-}
-
-func TestJSONParse(t *testing.T) {
- testFile(t, "../goi18n/testdata/expected/en-us.all.json")
-}
-
-func TestYAMLParse(t *testing.T) {
- testFile(t, "../goi18n/testdata/en-us.yaml")
-}
-
-func TestJSONFlatParse(t *testing.T) {
- testFile(t, "../goi18n/testdata/en-us.flat.json")
-}
-
-func TestYAMLFlatParse(t *testing.T) {
- testFile(t, "../goi18n/testdata/en-us.flat.yaml")
-}
-
-func TestTOMLFlatParse(t *testing.T) {
- testFile(t, "../goi18n/testdata/en-us.flat.toml")
-}
diff --git a/v2/internal/plural/codegen/generate.sh b/internal/plural/codegen/generate.sh
index c9b71a7..c9b71a7 100644
--- a/v2/internal/plural/codegen/generate.sh
+++ b/internal/plural/codegen/generate.sh
diff --git a/v2/internal/plural/codegen/main.go b/internal/plural/codegen/main.go
index 2b58c38..2b58c38 100644
--- a/v2/internal/plural/codegen/main.go
+++ b/internal/plural/codegen/main.go
diff --git a/v2/internal/plural/codegen/plurals.xml b/internal/plural/codegen/plurals.xml
index 9bd3e70..9bd3e70 100644
--- a/v2/internal/plural/codegen/plurals.xml
+++ b/internal/plural/codegen/plurals.xml
diff --git a/v2/internal/plural/codegen/xml.go b/internal/plural/codegen/xml.go
index adcc1e2..adcc1e2 100644
--- a/v2/internal/plural/codegen/xml.go
+++ b/internal/plural/codegen/xml.go
diff --git a/v2/internal/plural/doc.go b/internal/plural/doc.go
index c2a71d5..c2a71d5 100644
--- a/v2/internal/plural/doc.go
+++ b/internal/plural/doc.go
diff --git a/v2/internal/plural/form.go b/internal/plural/form.go
index 287a87f..287a87f 100644
--- a/v2/internal/plural/form.go
+++ b/internal/plural/form.go
diff --git a/v2/internal/plural/operands.go b/internal/plural/operands.go
index 4d29726..4d29726 100644
--- a/v2/internal/plural/operands.go
+++ b/internal/plural/operands.go
diff --git a/v2/internal/plural/operands_test.go b/internal/plural/operands_test.go
index 9074e5c..9074e5c 100644
--- a/v2/internal/plural/operands_test.go
+++ b/internal/plural/operands_test.go
diff --git a/v2/internal/plural/rule.go b/internal/plural/rule.go
index 0869c84..0869c84 100644
--- a/v2/internal/plural/rule.go
+++ b/internal/plural/rule.go
diff --git a/v2/internal/plural/rule_gen.go b/internal/plural/rule_gen.go
index b089925..b089925 100644
--- a/v2/internal/plural/rule_gen.go
+++ b/internal/plural/rule_gen.go
diff --git a/v2/internal/plural/rule_gen_test.go b/internal/plural/rule_gen_test.go
index a17782c..a17782c 100644
--- a/v2/internal/plural/rule_gen_test.go
+++ b/internal/plural/rule_gen_test.go
diff --git a/v2/internal/plural/rule_test.go b/internal/plural/rule_test.go
index 85d26d9..85d26d9 100644
--- a/v2/internal/plural/rule_test.go
+++ b/internal/plural/rule_test.go
diff --git a/v2/internal/plural/rules.go b/internal/plural/rules.go
index 87eb836..87eb836 100644
--- a/v2/internal/plural/rules.go
+++ b/internal/plural/rules.go
diff --git a/v2/internal/plural/rules_test.go b/internal/plural/rules_test.go
index 759241d..759241d 100644
--- a/v2/internal/plural/rules_test.go
+++ b/internal/plural/rules_test.go
diff --git a/v2/internal/template.go b/internal/template.go
index 4079f52..4079f52 100644
--- a/v2/internal/template.go
+++ b/internal/template.go
diff --git a/v2/internal/template_test.go b/internal/template_test.go
index dcc7b27..dcc7b27 100644
--- a/v2/internal/template_test.go
+++ b/internal/template_test.go
diff --git a/v2/go.mod b/v2/go.mod
deleted file mode 100644
index 7aba6f8..0000000
--- a/v2/go.mod
+++ /dev/null
@@ -1,11 +0,0 @@
-module github.com/nicksnyder/go-i18n/v2
-
-require (
- github.com/BurntSushi/toml v0.3.0
- golang.org/x/crypto v0.0.0-20190506204251-e1dfcc566284 // indirect
- golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c // indirect
- golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b // indirect
- golang.org/x/text v0.3.2
- golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c // indirect
- gopkg.in/yaml.v2 v2.2.1
-)
diff --git a/v2/goi18n/merge_command.go b/v2/goi18n/merge_command.go
deleted file mode 100644
index 6e6041f..0000000
--- a/v2/goi18n/merge_command.go
+++ /dev/null
@@ -1,292 +0,0 @@
-package main
-
-import (
- "crypto/sha1"
- "encoding/json"
- "flag"
- "fmt"
- "io"
- "io/ioutil"
- "os"
-
- "github.com/BurntSushi/toml"
- "github.com/nicksnyder/go-i18n/v2/i18n"
- "github.com/nicksnyder/go-i18n/v2/internal"
- "github.com/nicksnyder/go-i18n/v2/internal/plural"
- "golang.org/x/text/language"
- yaml "gopkg.in/yaml.v2"
-)
-
-func usageMerge() {
- fmt.Fprintf(os.Stderr, `usage: goi18n merge [options] [message files]
-
-Merge reads all messages in the message files and produces two files per language.
-
- xx-yy.active.format
- This file contains messages that should be loaded at runtime.
-
- xx-yy.translate.format
- This file contains messages that are empty and should be translated.
-
-Message 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.).
-
-To add support for a new language, create an empty translation file with the
-appropriate name and pass it in to goi18n merge.
-
-Flags:
-
- -sourceLanguage tag
- Translate messages from this language (e.g. en, en-US, zh-Hant-CN)
- Default: en
-
- -outdir directory
- Write message files to this directory.
- Default: .
-
- -format format
- Output message files in this format.
- Supported formats: json, toml, yaml
- Default: toml
-`)
-}
-
-type mergeCommand struct {
- messageFiles []string
- sourceLanguage languageTag
- outdir string
- format string
-}
-
-func (mc *mergeCommand) name() string {
- return "merge"
-}
-
-func (mc *mergeCommand) parse(args []string) {
- flags := flag.NewFlagSet("merge", flag.ExitOnError)
- flags.Usage = usageMerge
-
- flags.Var(&mc.sourceLanguage, "sourceLanguage", "en")
- flags.StringVar(&mc.outdir, "outdir", ".", "")
- flags.StringVar(&mc.format, "format", "toml", "")
- flags.Parse(args)
-
- mc.messageFiles = flags.Args()
-}
-
-func (mc *mergeCommand) execute() error {
- if len(mc.messageFiles) < 1 {
- return fmt.Errorf("need at least one message file to parse")
- }
- inFiles := make(map[string][]byte)
- for _, path := range mc.messageFiles {
- content, err := ioutil.ReadFile(path)
- if err != nil {
- return err
- }
- inFiles[path] = content
- }
- ops, err := merge(inFiles, mc.sourceLanguage.Tag(), mc.outdir, mc.format)
- if err != nil {
- return err
- }
- for path, content := range ops.writeFiles {
- if err := ioutil.WriteFile(path, content, 0666); err != nil {
- return err
- }
- }
- for _, path := range ops.deleteFiles {
- // Ignore error since it isn't guaranteed to exist.
- os.Remove(path)
- }
- return nil
-}
-
-type fileSystemOp struct {
- writeFiles map[string][]byte
- deleteFiles []string
-}
-
-func merge(messageFiles map[string][]byte, sourceLanguageTag language.Tag, outdir, outputFormat string) (*fileSystemOp, error) {
- unmerged := make(map[language.Tag][]map[string]*i18n.MessageTemplate)
- sourceMessageTemplates := make(map[string]*i18n.MessageTemplate)
- unmarshalFuncs := map[string]i18n.UnmarshalFunc{
- "json": json.Unmarshal,
- "toml": toml.Unmarshal,
- "yaml": yaml.Unmarshal,
- }
- for path, content := range messageFiles {
- mf, err := i18n.ParseMessageFileBytes(content, path, unmarshalFuncs)
- if err != nil {
- return nil, fmt.Errorf("failed to load message file %s: %s", path, err)
- }
- templates := map[string]*i18n.MessageTemplate{}
- for _, m := range mf.Messages {
- templates[m.ID] = i18n.NewMessageTemplate(m)
- }
- if mf.Tag == sourceLanguageTag {
- for _, template := range templates {
- if sourceMessageTemplates[template.ID] != nil {
- return nil, fmt.Errorf("multiple source translations for id %s", template.ID)
- }
- template.Hash = hash(template)
- sourceMessageTemplates[template.ID] = template
- }
- }
- unmerged[mf.Tag] = append(unmerged[mf.Tag], templates)
- }
-
- if len(sourceMessageTemplates) == 0 {
- return nil, fmt.Errorf("no messages found for source locale %s", sourceLanguageTag)
- }
-
- pluralRules := plural.DefaultRules()
- all := make(map[language.Tag]map[string]*i18n.MessageTemplate)
- all[sourceLanguageTag] = sourceMessageTemplates
- for _, srcTemplate := range sourceMessageTemplates {
- for dstLangTag, messageTemplates := range unmerged {
- if dstLangTag == sourceLanguageTag {
- continue
- }
- pluralRule := pluralRules.Rule(dstLangTag)
- if pluralRule == nil {
- // Non-standard languages not supported because
- // we don't know if translations are complete or not.
- continue
- }
- if all[dstLangTag] == nil {
- all[dstLangTag] = make(map[string]*i18n.MessageTemplate)
- }
- dstMessageTemplate := all[dstLangTag][srcTemplate.ID]
- if dstMessageTemplate == nil {
- dstMessageTemplate = &i18n.MessageTemplate{
- Message: &i18n.Message{
- ID: srcTemplate.ID,
- Description: srcTemplate.Description,
- Hash: srcTemplate.Hash,
- },
- PluralTemplates: make(map[plural.Form]*internal.Template),
- }
- all[dstLangTag][srcTemplate.ID] = dstMessageTemplate
- }
-
- // Check all unmerged message templates for this message id.
- for _, messageTemplates := range messageTemplates {
- unmergedTemplate := messageTemplates[srcTemplate.ID]
- if unmergedTemplate == nil {
- continue
- }
- // Ignore empty hashes for v1 backward compatibility.
- if unmergedTemplate.Hash != "" && unmergedTemplate.Hash != srcTemplate.Hash {
- // This was translated from different content so discard.
- continue
- }
-
- // Merge in the translated messages.
- for pluralForm := range pluralRule.PluralForms {
- dt := unmergedTemplate.PluralTemplates[pluralForm]
- if dt != nil && dt.Src != "" {
- dstMessageTemplate.PluralTemplates[pluralForm] = dt
- }
- }
- }
- }
- }
-
- translate := make(map[language.Tag]map[string]*i18n.MessageTemplate)
- active := make(map[language.Tag]map[string]*i18n.MessageTemplate)
- for langTag, messageTemplates := range all {
- active[langTag] = make(map[string]*i18n.MessageTemplate)
- if langTag == sourceLanguageTag {
- active[langTag] = messageTemplates
- continue
- }
- pluralRule := pluralRules.Rule(langTag)
- if pluralRule == nil {
- // Non-standard languages not supported because
- // we don't know if translations are complete or not.
- continue
- }
- for _, messageTemplate := range messageTemplates {
- srcMessageTemplate := sourceMessageTemplates[messageTemplate.ID]
- activeMessageTemplate, translateMessageTemplate := activeDst(srcMessageTemplate, messageTemplate, pluralRule)
- if translateMessageTemplate != nil {
- if translate[langTag] == nil {
- translate[langTag] = make(map[string]*i18n.MessageTemplate)
- }
- translate[langTag][messageTemplate.ID] = translateMessageTemplate
- }
- if activeMessageTemplate != nil {
- active[langTag][messageTemplate.ID] = activeMessageTemplate
- }
- }
- }
-
- writeFiles := make(map[string][]byte, len(translate)+len(active))
- for langTag, messageTemplates := range translate {
- path, content, err := writeFile(outdir, "translate", langTag, outputFormat, messageTemplates, false)
- if err != nil {
- return nil, err
- }
- writeFiles[path] = content
- }
- deleteFiles := []string{}
- for langTag, messageTemplates := range active {
- path, content, err := writeFile(outdir, "active", langTag, outputFormat, messageTemplates, langTag == sourceLanguageTag)
- if err != nil {
- return nil, err
- }
- if len(content) > 0 {
- writeFiles[path] = content
- } else {
- deleteFiles = append(deleteFiles, path)
- }
- }
- return &fileSystemOp{writeFiles: writeFiles, deleteFiles: deleteFiles}, nil
-}
-
-// activeDst returns the active part of the dst and whether dst is a complete translation of src.
-func activeDst(src, dst *i18n.MessageTemplate, pluralRule *plural.Rule) (active *i18n.MessageTemplate, translateMessageTemplate *i18n.MessageTemplate) {
- pluralForms := pluralRule.PluralForms
- if len(src.PluralTemplates) == 1 {
- pluralForms = map[plural.Form]struct{}{
- plural.Other: {},
- }
- }
- for pluralForm := range pluralForms {
- dt := dst.PluralTemplates[pluralForm]
- if dt == nil || dt.Src == "" {
- if translateMessageTemplate == nil {
- translateMessageTemplate = &i18n.MessageTemplate{
- Message: &i18n.Message{
- ID: src.ID,
- Description: src.Description,
- Hash: src.Hash,
- },
- PluralTemplates: make(map[plural.Form]*internal.Template),
- }
- }
- translateMessageTemplate.PluralTemplates[pluralForm] = src.PluralTemplates[plural.Other]
- continue
- }
- if active == nil {
- active = &i18n.MessageTemplate{
- Message: &i18n.Message{
- ID: src.ID,
- Description: src.Description,
- Hash: src.Hash,
- },
- PluralTemplates: make(map[plural.Form]*internal.Template),
- }
- }
- active.PluralTemplates[pluralForm] = dt
- }
- return
-}
-
-func hash(t *i18n.MessageTemplate) string {
- h := sha1.New()
- io.WriteString(h, t.Description)
- io.WriteString(h, t.PluralTemplates[plural.Other].Src)
- return fmt.Sprintf("sha1-%x", h.Sum(nil))
-}
diff --git a/v2/goi18n/merge_command_test.go b/v2/goi18n/merge_command_test.go
deleted file mode 100644
index ff7c221..0000000
--- a/v2/goi18n/merge_command_test.go
+++ /dev/null
@@ -1,563 +0,0 @@
-package main
-
-import (
- "bytes"
- "io/ioutil"
- "os"
- "path/filepath"
- "testing"
-
- "golang.org/x/text/language"
-)
-
-type testCase struct {
- name string
- inFiles map[string][]byte
- sourceLanguage language.Tag
- outFiles map[string][]byte
- deleteFiles []string
-}
-
-func expectFile(s string) []byte {
- // Trimming leading newlines gives nicer formatting for file literals in test cases.
- return bytes.TrimLeft([]byte(s), "\n")
-}
-
-func TestMerge(t *testing.T) {
- testCases := []*testCase{
- {
- name: "single identity",
- sourceLanguage: language.AmericanEnglish,
- inFiles: map[string][]byte{
- "one.en-US.toml": []byte("1HelloMessage = \"Hello\"\n"),
- },
- outFiles: map[string][]byte{
- "active.en-US.toml": []byte("1HelloMessage = \"Hello\"\n"),
- },
- },
- {
- name: "plural identity",
- sourceLanguage: language.AmericanEnglish,
- inFiles: map[string][]byte{
- "active.en-US.toml": []byte(`
-[UnreadEmails]
-description = "Message that tells the user how many unread emails they have"
-one = "{{.Count}} unread email"
-other = "{{.Count}} unread emails"
-`),
- },
- outFiles: map[string][]byte{
- "active.en-US.toml": expectFile(`
-[UnreadEmails]
-description = "Message that tells the user how many unread emails they have"
-one = "{{.Count}} unread email"
-other = "{{.Count}} unread emails"
-`),
- },
- },
- {
- name: "migrate source lang from v1 format",
- sourceLanguage: language.AmericanEnglish,
- inFiles: map[string][]byte{
- "one.en-US.json": []byte(`[
- {
- "id": "simple",
- "translation": "simple translation"
- },
- {
- "id": "everything",
- "translation": {
- "zero": "zero translation",
- "one": "one translation",
- "two": "two translation",
- "few": "few translation",
- "many": "many translation",
- "other": "other translation"
- }
- }
-]`),
- },
- outFiles: map[string][]byte{
- "active.en-US.toml": expectFile(`
-simple = "simple translation"
-
-[everything]
-few = "few translation"
-many = "many translation"
-one = "one translation"
-other = "other translation"
-two = "two translation"
-zero = "zero translation"
-`),
- },
- },
- {
- name: "migrate source lang from v1 flat format",
- sourceLanguage: language.AmericanEnglish,
- inFiles: map[string][]byte{
- "one.en-US.json": []byte(`{
- "simple": {
- "other": "simple translation"
- },
- "everything": {
- "zero": "zero translation",
- "one": "one translation",
- "two": "two translation",
- "few": "few translation",
- "many": "many translation",
- "other": "other translation"
- }
-}`),
- },
- outFiles: map[string][]byte{
- "active.en-US.toml": expectFile(`
-simple = "simple translation"
-
-[everything]
-few = "few translation"
-many = "many translation"
-one = "one translation"
-other = "other translation"
-two = "two translation"
-zero = "zero translation"
-`),
- },
- },
- {
- name: "merge source files",
- sourceLanguage: language.AmericanEnglish,
- inFiles: map[string][]byte{
- "one.en-US.toml": []byte("1HelloMessage = \"Hello\"\n"),
- "two.en-US.toml": []byte("2GoodbyeMessage = \"Goodbye\"\n"),
- },
- outFiles: map[string][]byte{
- "active.en-US.toml": []byte("1HelloMessage = \"Hello\"\n2GoodbyeMessage = \"Goodbye\"\n"),
- },
- },
- {
- name: "missing hash",
- sourceLanguage: language.AmericanEnglish,
- inFiles: map[string][]byte{
- "en-US.toml": []byte(`
-1HelloMessage = "Hello"
-`),
- "es-ES.toml": []byte(`
-[1HelloMessage]
-other = "Hola"
-`),
- },
- outFiles: map[string][]byte{
- "active.en-US.toml": expectFile(`
-1HelloMessage = "Hello"
-`),
- "active.es-ES.toml": expectFile(`
-[1HelloMessage]
-hash = "sha1-f7ff9e8b7bb2e09b70935a5d785e0cc5d9d0abf0"
-other = "Hola"
-`),
- },
- },
- {
- name: "add single translation",
- sourceLanguage: language.AmericanEnglish,
- inFiles: map[string][]byte{
- "en-US.toml": []byte(`
-1HelloMessage = "Hello"
-2GoodbyeMessage = "Goodbye"
-`),
- "es-ES.toml": []byte(`
-[1HelloMessage]
-hash = "sha1-f7ff9e8b7bb2e09b70935a5d785e0cc5d9d0abf0"
-other = "Hola"
-`),
- },
- outFiles: map[string][]byte{
- "active.en-US.toml": expectFile(`
-1HelloMessage = "Hello"
-2GoodbyeMessage = "Goodbye"
-`),
- "active.es-ES.toml": expectFile(`
-[1HelloMessage]
-hash = "sha1-f7ff9e8b7bb2e09b70935a5d785e0cc5d9d0abf0"
-other = "Hola"
-`),
- "translate.es-ES.toml": expectFile(`
-[2GoodbyeMessage]
-hash = "sha1-b5b29c53e3c71cb9c6581ab053d7758fab8ca24d"
-other = "Goodbye"
-`),
- },
- },
- {
- name: "remove single translation",
- sourceLanguage: language.AmericanEnglish,
- inFiles: map[string][]byte{
- "en-US.toml": []byte(`
-1HelloMessage = "Hello"
-`),
- "es-ES.toml": []byte(`
-[1HelloMessage]
-hash = "sha1-f7ff9e8b7bb2e09b70935a5d785e0cc5d9d0abf0"
-other = "Hola"
-
-[2GoodbyeMessage]
-hash = "sha1-b5b29c53e3c71cb9c6581ab053d7758fab8ca24d"
-other = "Goodbye"
-`),
- },
- outFiles: map[string][]byte{
- "active.en-US.toml": expectFile(`
-1HelloMessage = "Hello"
-`),
- "active.es-ES.toml": expectFile(`
-[1HelloMessage]
-hash = "sha1-f7ff9e8b7bb2e09b70935a5d785e0cc5d9d0abf0"
-other = "Hola"
-`),
- },
- },
- {
- name: "edit single translation",
- sourceLanguage: language.AmericanEnglish,
- inFiles: map[string][]byte{
- "en-US.toml": []byte(`
-1HelloMessage = "Hi"
-`),
- "es-ES.toml": []byte(`
-[1HelloMessage]
-hash = "sha1-f7ff9e8b7bb2e09b70935a5d785e0cc5d9d0abf0"
-other = "Hola"
-`),
- },
- outFiles: map[string][]byte{
- "active.en-US.toml": expectFile(`
-1HelloMessage = "Hi"
-`),
- "translate.es-ES.toml": expectFile(`
-[1HelloMessage]
-hash = "sha1-94dd9e08c129c785f7f256e82fbe0a30e6d1ae40"
-other = "Hi"
-`),
- },
- },
- {
- name: "add plural translation",
- sourceLanguage: language.AmericanEnglish,
- inFiles: map[string][]byte{
- "en-US.toml": []byte(`
-[UnreadEmails]
-description = "Message that tells the user how many unread emails they have"
-one = "{{.Count}} unread email"
-other = "{{.Count}} unread emails"
-`),
- "es-ES.toml": nil,
- "ar-AR.toml": nil,
- "zh-CN.toml": nil,
- },
- outFiles: map[string][]byte{
- "active.en-US.toml": expectFile(`
-[UnreadEmails]
-description = "Message that tells the user how many unread emails they have"
-one = "{{.Count}} unread email"
-other = "{{.Count}} unread emails"
-`),
- "translate.es-ES.toml": expectFile(`
-[UnreadEmails]
-description = "Message that tells the user how many unread emails they have"
-hash = "sha1-5afbc91dfedb9755627655c365eb47a89e541099"
-one = "{{.Count}} unread emails"
-other = "{{.Count}} unread emails"
-`),
- "translate.ar-AR.toml": expectFile(`
-[UnreadEmails]
-description = "Message that tells the user how many unread emails they have"
-few = "{{.Count}} unread emails"
-hash = "sha1-5afbc91dfedb9755627655c365eb47a89e541099"
-many = "{{.Count}} unread emails"
-one = "{{.Count}} unread emails"
-other = "{{.Count}} unread emails"
-two = "{{.Count}} unread emails"
-zero = "{{.Count}} unread emails"
-`),
- "translate.zh-CN.toml": expectFile(`
-[UnreadEmails]
-description = "Message that tells the user how many unread emails they have"
-hash = "sha1-5afbc91dfedb9755627655c365eb47a89e541099"
-other = "{{.Count}} unread emails"
-`),
- },
- },
- {
- name: "remove plural translation",
- sourceLanguage: language.AmericanEnglish,
- inFiles: map[string][]byte{
- "en-US.toml": []byte(`
-1HelloMessage = "Hello"
-`),
- "es-ES.toml": []byte(`
-[1HelloMessage]
-hash = "sha1-f7ff9e8b7bb2e09b70935a5d785e0cc5d9d0abf0"
-other = "Hola"
-
-[UnreadEmails]
-description = "Message that tells the user how many unread emails they have"
-hash = "sha1-5afbc91dfedb9755627655c365eb47a89e541099"
-one = "{{.Count}} unread emails"
-other = "{{.Count}} unread emails"
-`),
- "ar-AR.toml": []byte(`
-[1HelloMessage]
-hash = "sha1-f7ff9e8b7bb2e09b70935a5d785e0cc5d9d0abf0"
-other = "Hello"
-
-[UnreadEmails]
-description = "Message that tells the user how many unread emails they have"
-few = "{{.Count}} unread emails"
-hash = "sha1-5afbc91dfedb9755627655c365eb47a89e541099"
-many = "{{.Count}} unread emails"
-one = "{{.Count}} unread emails"
-other = "{{.Count}} unread emails"
-two = "{{.Count}} unread emails"
-zero = "{{.Count}} unread emails"
-`),
- "zh-CN.toml": []byte(`
-[1HelloMessage]
-hash = "sha1-f7ff9e8b7bb2e09b70935a5d785e0cc5d9d0abf0"
-other = "Hello"
-
-[UnreadEmails]
-description = "Message that tells the user how many unread emails they have"
-hash = "sha1-5afbc91dfedb9755627655c365eb47a89e541099"
-other = "{{.Count}} unread emails"
-`),
- },
- outFiles: map[string][]byte{
- "active.en-US.toml": expectFile(`
-1HelloMessage = "Hello"
-`),
- "active.es-ES.toml": expectFile(`
-[1HelloMessage]
-hash = "sha1-f7ff9e8b7bb2e09b70935a5d785e0cc5d9d0abf0"
-other = "Hola"
-`),
- "active.ar-AR.toml": expectFile(`
-[1HelloMessage]
-hash = "sha1-f7ff9e8b7bb2e09b70935a5d785e0cc5d9d0abf0"
-other = "Hello"
-`),
- "active.zh-CN.toml": expectFile(`
-[1HelloMessage]
-hash = "sha1-f7ff9e8b7bb2e09b70935a5d785e0cc5d9d0abf0"
-other = "Hello"
-`),
- },
- },
- {
- name: "edit plural translation",
- sourceLanguage: language.AmericanEnglish,
- inFiles: map[string][]byte{
- "en-US.toml": []byte(`
-[UnreadEmails]
-description = "Message that tells the user how many unread emails they have"
-one = "{{.Count}} unread emails!"
-other = "{{.Count}} unread emails!"
-`),
- "es-ES.toml": []byte(`
-[UnreadEmails]
-description = "Message that tells the user how many unread emails they have"
-hash = "sha1-5afbc91dfedb9755627655c365eb47a89e541099"
-one = "{{.Count}} unread emails"
-other = "{{.Count}} unread emails"
-`),
- "ar-AR.toml": []byte(`
-[UnreadEmails]
-description = "Message that tells the user how many unread emails they have"
-few = "{{.Count}} unread emails"
-hash = "sha1-5afbc91dfedb9755627655c365eb47a89e541099"
-many = "{{.Count}} unread emails"
-one = "{{.Count}} unread emails"
-other = "{{.Count}} unread emails"
-two = "{{.Count}} unread emails"
-zero = "{{.Count}} unread emails"
-`),
- "zh-CN.toml": []byte(`
-[UnreadEmails]
-description = "Message that tells the user how many unread emails they have"
-hash = "sha1-5afbc91dfedb9755627655c365eb47a89e541099"
-other = "{{.Count}} unread emails"
-`),
- },
- deleteFiles: []string{
- "active.es-ES.toml",
- "active.ar-AR.toml",
- "active.zh-CN.toml",
- },
- outFiles: map[string][]byte{
- "active.en-US.toml": expectFile(`
-[UnreadEmails]
-description = "Message that tells the user how many unread emails they have"
-one = "{{.Count}} unread emails!"
-other = "{{.Count}} unread emails!"
-`),
- "translate.es-ES.toml": expectFile(`
-[UnreadEmails]
-description = "Message that tells the user how many unread emails they have"
-hash = "sha1-92a24983c5bbc0c42462cdc252dca68ebdb46501"
-one = "{{.Count}} unread emails!"
-other = "{{.Count}} unread emails!"
-`),
- "translate.ar-AR.toml": expectFile(`
-[UnreadEmails]
-description = "Message that tells the user how many unread emails they have"
-few = "{{.Count}} unread emails!"
-hash = "sha1-92a24983c5bbc0c42462cdc252dca68ebdb46501"
-many = "{{.Count}} unread emails!"
-one = "{{.Count}} unread emails!"
-other = "{{.Count}} unread emails!"
-two = "{{.Count}} unread emails!"
-zero = "{{.Count}} unread emails!"
-`),
- "translate.zh-CN.toml": expectFile(`
-[UnreadEmails]
-description = "Message that tells the user how many unread emails they have"
-hash = "sha1-92a24983c5bbc0c42462cdc252dca68ebdb46501"
-other = "{{.Count}} unread emails!"
-`),
- },
- },
- {
- name: "merge plural translation",
- sourceLanguage: language.AmericanEnglish,
- inFiles: map[string][]byte{
- "en-US.toml": []byte(`
-[UnreadEmails]
-description = "Message that tells the user how many unread emails they have"
-one = "{{.Count}} unread emails"
-other = "{{.Count}} unread emails"
-`),
- "zero.ar-AR.toml": []byte(`
-[UnreadEmails]
-description = "Message that tells the user how many unread emails they have"
-hash = "sha1-5afbc91dfedb9755627655c365eb47a89e541099"
-zero = "{{.Count}} unread emails"
-`),
- "one.ar-AR.toml": []byte(`
-[UnreadEmails]
-description = "Message that tells the user how many unread emails they have"
-hash = "sha1-5afbc91dfedb9755627655c365eb47a89e541099"
-one = "{{.Count}} unread emails"
-`),
- "two.ar-AR.toml": []byte(`
-[UnreadEmails]
-description = "Message that tells the user how many unread emails they have"
-hash = "sha1-5afbc91dfedb9755627655c365eb47a89e541099"
-two = "{{.Count}} unread emails"
-`),
- "few.ar-AR.toml": []byte(`
-[UnreadEmails]
-description = "Message that tells the user how many unread emails they have"
-few = "{{.Count}} unread emails"
-hash = "sha1-5afbc91dfedb9755627655c365eb47a89e541099"
-`),
- "many.ar-AR.toml": []byte(`
-[UnreadEmails]
-description = "Message that tells the user how many unread emails they have"
-hash = "sha1-5afbc91dfedb9755627655c365eb47a89e541099"
-many = "{{.Count}} unread emails"
-`),
- "other.ar-AR.toml": []byte(`
-[UnreadEmails]
-description = "Message that tells the user how many unread emails they have"
-hash = "sha1-5afbc91dfedb9755627655c365eb47a89e541099"
-other = "{{.Count}} unread emails"
-`),
- },
- outFiles: map[string][]byte{
- "active.en-US.toml": expectFile(`
-[UnreadEmails]
-description = "Message that tells the user how many unread emails they have"
-one = "{{.Count}} unread emails"
-other = "{{.Count}} unread emails"
-`),
- "active.ar-AR.toml": expectFile(`
-[UnreadEmails]
-description = "Message that tells the user how many unread emails they have"
-few = "{{.Count}} unread emails"
-hash = "sha1-5afbc91dfedb9755627655c365eb47a89e541099"
-many = "{{.Count}} unread emails"
-one = "{{.Count}} unread emails"
-other = "{{.Count}} unread emails"
-two = "{{.Count}} unread emails"
-zero = "{{.Count}} unread emails"
-`),
- },
- },
- }
-
- for _, testCase := range testCases {
- t.Run(testCase.name, func(t *testing.T) {
- indir := mustTempDir("TestMergeCommandIn")
- defer os.RemoveAll(indir)
- outdir := mustTempDir("TestMergeCommandOut")
- defer os.RemoveAll(outdir)
-
- infiles := make([]string, 0, len(testCase.inFiles))
- for name, content := range testCase.inFiles {
- path := filepath.Join(indir, name)
- infiles = append(infiles, path)
- if err := ioutil.WriteFile(path, content, 0666); err != nil {
- t.Fatal(err)
- }
- }
-
- for _, name := range testCase.deleteFiles {
- path := filepath.Join(outdir, name)
- if err := ioutil.WriteFile(path, []byte(`this file should get deleted`), 0666); err != nil {
- t.Fatal(err)
- }
- }
-
- args := append([]string{"merge", "-sourceLanguage", testCase.sourceLanguage.String(), "-outdir", outdir}, infiles...)
- if code := testableMain(args); code != 0 {
- t.Fatalf("expected exit code 0; got %d\n", code)
- }
-
- files, err := ioutil.ReadDir(outdir)
- if err != nil {
- t.Fatal(err)
- }
-
- // Verify that all actual files have expected contents.
- actualFiles := make(map[string]struct{}, len(files))
- for _, f := range files {
- actualFiles[f.Name()] = struct{}{}
- if f.IsDir() {
- t.Errorf("found unexpected dir %s", f.Name())
- continue
- }
- path := filepath.Join(outdir, f.Name())
- actual, err := ioutil.ReadFile(path)
- if err != nil {
- t.Error(err)
- continue
- }
- expected, ok := testCase.outFiles[f.Name()]
- if !ok {
- t.Errorf("found unexpected file %s with contents:\n%s\n", f.Name(), actual)
- continue
- }
- if !bytes.Equal(actual, expected) {
- t.Errorf("unexpected contents %s\ngot\n%s\nexpected\n%s", f.Name(), actual, expected)
- continue
- }
- }
-
- // Verify that all expected files are accounted for.
- for name := range testCase.outFiles {
- if _, ok := actualFiles[name]; !ok {
- t.Errorf("did not find expected file %s", name)
- }
- }
- })
- }
-}
diff --git a/v2/i18n/example_test.go b/v2/i18n/example_test.go
deleted file mode 100644
index 2256e63..0000000
--- a/v2/i18n/example_test.go
+++ /dev/null
@@ -1,141 +0,0 @@
-package i18n_test
-
-import (
- "fmt"
-
- "github.com/BurntSushi/toml"
- "github.com/nicksnyder/go-i18n/v2/i18n"
- "golang.org/x/text/language"
-)
-
-func ExampleLocalizer_MustLocalize() {
- bundle := i18n.NewBundle(language.English)
- localizer := i18n.NewLocalizer(bundle, "en")
- fmt.Println(localizer.MustLocalize(&i18n.LocalizeConfig{
- DefaultMessage: &i18n.Message{
- ID: "HelloWorld",
- Other: "Hello World!",
- },
- }))
- // Output:
- // Hello World!
-}
-
-func ExampleLocalizer_MustLocalize_noDefaultMessage() {
- bundle := i18n.NewBundle(language.English)
- bundle.RegisterUnmarshalFunc("toml", toml.Unmarshal)
- bundle.MustParseMessageFileBytes([]byte(`
-HelloWorld = "Hello World!"
-`), "en.toml")
- bundle.MustParseMessageFileBytes([]byte(`
-HelloWorld = "Hola Mundo!"
-`), "es.toml")
-
- {
- localizer := i18n.NewLocalizer(bundle, "en-US")
- fmt.Println(localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "HelloWorld"}))
- }
- {
- localizer := i18n.NewLocalizer(bundle, "es-ES")
- fmt.Println(localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "HelloWorld"}))
- }
- // Output:
- // Hello World!
- // Hola Mundo!
-}
-
-func ExampleLocalizer_MustLocalize_plural() {
- bundle := i18n.NewBundle(language.English)
- localizer := i18n.NewLocalizer(bundle, "en")
- catsMessage := &i18n.Message{
- ID: "Cats",
- One: "I have {{.PluralCount}} cat.",
- Other: "I have {{.PluralCount}} cats.",
- }
- fmt.Println(localizer.MustLocalize(&i18n.LocalizeConfig{
- DefaultMessage: catsMessage,
- PluralCount: 1,
- }))
- fmt.Println(localizer.MustLocalize(&i18n.LocalizeConfig{
- DefaultMessage: catsMessage,
- PluralCount: 2,
- }))
- fmt.Println(localizer.MustLocalize(&i18n.LocalizeConfig{
- DefaultMessage: catsMessage,
- PluralCount: "2.5",
- }))
- // Output:
- // I have 1 cat.
- // I have 2 cats.
- // I have 2.5 cats.
-}
-
-func ExampleLocalizer_MustLocalize_template() {
- bundle := i18n.NewBundle(language.English)
- localizer := i18n.NewLocalizer(bundle, "en")
- helloPersonMessage := &i18n.Message{
- ID: "HelloPerson",
- Other: "Hello {{.Name}}!",
- }
- fmt.Println(localizer.MustLocalize(&i18n.LocalizeConfig{
- DefaultMessage: helloPersonMessage,
- TemplateData: map[string]string{"Name": "Nick"},
- }))
- // Output:
- // Hello Nick!
-}
-
-func ExampleLocalizer_MustLocalize_plural_template() {
- bundle := i18n.NewBundle(language.English)
- localizer := i18n.NewLocalizer(bundle, "en")
- personCatsMessage := &i18n.Message{
- ID: "PersonCats",
- One: "{{.Name}} has {{.Count}} cat.",
- Other: "{{.Name}} has {{.Count}} cats.",
- }
- fmt.Println(localizer.MustLocalize(&i18n.LocalizeConfig{
- DefaultMessage: personCatsMessage,
- PluralCount: 1,
- TemplateData: map[string]interface{}{
- "Name": "Nick",
- "Count": 1,
- },
- }))
- fmt.Println(localizer.MustLocalize(&i18n.LocalizeConfig{
- DefaultMessage: personCatsMessage,
- PluralCount: 2,
- TemplateData: map[string]interface{}{
- "Name": "Nick",
- "Count": 2,
- },
- }))
- fmt.Println(localizer.MustLocalize(&i18n.LocalizeConfig{
- DefaultMessage: personCatsMessage,
- PluralCount: "2.5",
- TemplateData: map[string]interface{}{
- "Name": "Nick",
- "Count": "2.5",
- },
- }))
- // Output:
- // Nick has 1 cat.
- // Nick has 2 cats.
- // Nick has 2.5 cats.
-}
-
-func ExampleLocalizer_MustLocalize_customTemplateDelims() {
- bundle := i18n.NewBundle(language.English)
- localizer := i18n.NewLocalizer(bundle, "en")
- helloPersonMessage := &i18n.Message{
- ID: "HelloPerson",
- Other: "Hello <<.Name>>!",
- LeftDelim: "<<",
- RightDelim: ">>",
- }
- fmt.Println(localizer.MustLocalize(&i18n.LocalizeConfig{
- DefaultMessage: helloPersonMessage,
- TemplateData: map[string]string{"Name": "Nick"},
- }))
- // Output:
- // Hello Nick!
-}