Этот коммит содержится в:
Christopher Speller
2016-11-16 19:28:52 -05:00
коммит произвёл GitHub
родитель 0b296dd8c2
Коммит 0135904f7d
445 изменённых файлов: 38624 добавлений и 14161 удалений

2
vendor/github.com/nicksnyder/go-i18n/.travis.yml сгенерированный поставляемый
Просмотреть файл

@@ -5,4 +5,6 @@ go:
- 1.3
- 1.4
- 1.5
- 1.6
- 1.7
- tip

230
vendor/github.com/nicksnyder/go-i18n/goi18n/constants_command.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,230 @@
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: .
`)
os.Exit(1)
}
// 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
}

42
vendor/github.com/nicksnyder/go-i18n/goi18n/constants_command_test.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,42 @@
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")
}

38
vendor/github.com/nicksnyder/go-i18n/goi18n/doc.go сгенерированный поставляемый
Просмотреть файл

@@ -5,11 +5,22 @@
//
// Help documentation:
//
// goi18n formats and merges translation files.
// goi18n manages translation files.
//
// Usage:
//
// goi18n [options] [files...]
// 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:
//
@@ -56,4 +67,27 @@
// 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

4
vendor/github.com/nicksnyder/go-i18n/goi18n/gendoc.sh сгенерированный поставляемый
Просмотреть файл

@@ -6,5 +6,7 @@ echo "// goi18n -help" >> doc.go
echo "//" >> doc.go
echo "// Help documentation:" >> doc.go
echo "//" >> doc.go
goi18n -help | sed -e 's/^/\/\/ /' >> 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

101
vendor/github.com/nicksnyder/go-i18n/goi18n/goi18n.go сгенерированный поставляемый
Просмотреть файл

@@ -6,77 +6,50 @@ import (
"os"
)
func usage() {
fmt.Printf(`goi18n formats and merges translation files.
Usage:
goi18n [options] [files...]
Translation files:
A translation file contains the strings and translations for a single language.
Translation file names must have a suffix of a supported format (e.g. .json) and
contain a valid language tag as defined by RFC 5646 (e.g. en-us, fr, zh-hant, etc.).
For each language represented by at least one input translation file, goi18n will produce 2 output files:
xx-yy.all.format
This file contains all strings for the language (translated and untranslated).
Use this file when loading strings at runtime.
xx-yy.untranslated.format
This file contains the strings that have not been translated for this language.
The translations for the strings in this file will be extracted from the source language.
After they are translated, merge them back into xx-yy.all.format using goi18n.
Merging:
goi18n will merge multiple translation files for the same language.
Duplicate translations will be merged into the existing translation.
Non-empty fields in the duplicate translation will overwrite those fields in the existing translation.
Empty fields in the duplicate translation are ignored.
Adding a new language:
To produce translation files for a new language, create an empty translation file with the
appropriate name and pass it in to goi18n.
Options:
-sourceLanguage tag
goi18n uses the strings from this language to seed the translations for other languages.
Default: en-us
-outdir directory
goi18n writes the output translation files to this directory.
Default: .
-format format
goi18n encodes the output translation files in this format.
Supported formats: json, yaml
Default: json
`)
os.Exit(1)
type command interface {
execute() error
parse(arguments []string)
}
func main() {
flag.Usage = usage
sourceLanguage := flag.String("sourceLanguage", "en-us", "")
outdir := flag.String("outdir", ".", "")
format := flag.String("format", "json", "")
flag.Parse()
mc := &mergeCommand{
translationFiles: flag.Args(),
sourceLanguageTag: *sourceLanguage,
outdir: *outdir,
format: *format,
if len(os.Args) == 1 {
usage()
}
if err := mc.execute(); err != nil {
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)
}

Просмотреть файл

@@ -2,23 +2,26 @@ package main
import (
"encoding/json"
"flag"
"fmt"
"gopkg.in/yaml.v2"
"io/ioutil"
"os"
"path/filepath"
"reflect"
"sort"
"gopkg.in/yaml.v2"
"github.com/nicksnyder/go-i18n/i18n/bundle"
"github.com/nicksnyder/go-i18n/i18n/language"
"github.com/nicksnyder/go-i18n/i18n/translation"
)
type mergeCommand struct {
translationFiles []string
sourceLanguageTag string
outdir string
format string
translationFiles []string
sourceLanguage string
outdir string
format string
}
func (mc *mergeCommand) execute() error {
@@ -26,8 +29,8 @@ func (mc *mergeCommand) execute() error {
return fmt.Errorf("need at least one translation file to parse")
}
if lang := language.Parse(mc.sourceLanguageTag); lang == nil {
return fmt.Errorf("invalid source locale: %s", mc.sourceLanguageTag)
if lang := language.Parse(mc.sourceLanguage); lang == nil {
return fmt.Errorf("invalid source locale: %s", mc.sourceLanguage)
}
marshal, err := newMarshalFunc(mc.format)
@@ -43,7 +46,7 @@ func (mc *mergeCommand) execute() error {
}
translations := bundle.Translations()
sourceLanguageTag := language.NormalizeTag(mc.sourceLanguageTag)
sourceLanguageTag := language.NormalizeTag(mc.sourceLanguage)
sourceTranslations := translations[sourceLanguageTag]
if sourceTranslations == nil {
return fmt.Errorf("no translations found for source locale %s", sourceLanguageTag)
@@ -78,6 +81,26 @@ func (mc *mergeCommand) execute() error {
return nil
}
func (mc *mergeCommand) parse(arguments []string) {
flags := flag.NewFlagSet("merge", flag.ExitOnError)
flags.Usage = usageMerge
sourceLanguage := flags.String("sourceLanguage", "en-us", "")
outdir := flags.String("outdir", ".", "")
format := flags.String("format", "json", "")
flags.Parse(arguments)
mc.translationFiles = flags.Args()
mc.sourceLanguage = *sourceLanguage
mc.outdir = *outdir
mc.format = *format
}
func (mc *mergeCommand) SetArgs(args []string) {
mc.translationFiles = args
}
type marshalFunc func(interface{}) ([]byte, error)
func (mc *mergeCommand) writeFile(label string, translations []translation.Translation, localeID string, marshal marshalFunc) error {
@@ -125,3 +148,59 @@ func marshalInterface(translations []translation.Translation) []interface{} {
}
return mi
}
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, yaml
Default: json
`)
os.Exit(1)
}

Просмотреть файл

@@ -33,10 +33,10 @@ func testMergeExecute(t *testing.T, files []string) {
resetDir(t, "testdata/output")
mc := &mergeCommand{
translationFiles: files,
sourceLanguageTag: "en-us",
outdir: "testdata/output",
format: "json",
translationFiles: files,
sourceLanguage: "en-us",
outdir: "testdata/output",
format: "json",
}
if err := mc.execute(); err != nil {
t.Fatal(err)

38
vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/expected/R.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,38 @@
// 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"

45
vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/input/en-us.constants.json сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,45 @@
[
{
"id": "d_days",
"translation": {
"one": "{{.Count}} day",
"other": "{{.Count}} days"
}
},
{
"id": "my_height_in_meters",
"translation": {
"one": "I am {{.Count}} meter tall.",
"other": "I am {{.Count}} meters tall."
}
},
{
"id": "person_greeting",
"translation": "Hello {{.Person}}"
},
{
"id": "person_unread_email_count",
"translation": {
"one": "{{.Person}} has {{.Count}} unread email.",
"other": "{{.Person}} has {{.Count}} unread emails."
}
},
{
"id": "person_unread_email_count_timeframe",
"translation": {
"one": "{{.Person}} has {{.Count}} unread email in the past {{.Timeframe}}.",
"other": "{{.Person}} has {{.Count}} unread emails in the past {{.Timeframe}}."
}
},
{
"id": "program_greeting",
"translation": "Hello world"
},
{
"id": "your_unread_email_count",
"translation": {
"one": "You have {{.Count}} unread email.",
"other": "You have {{.Count}} unread emails."
}
}
]

5
vendor/github.com/nicksnyder/go-i18n/i18n/bundle/bundle.go сгенерированный поставляемый
Просмотреть файл

@@ -260,6 +260,11 @@ func (b *Bundle) translate(lang *language.Language, translationID string, args .
dataMap["Count"] = count
data = dataMap
}
} else {
dataMap := toMap(data)
if c, ok := dataMap["Count"]; ok {
count = c
}
}
p, _ := lang.Plural(count)

20
vendor/github.com/nicksnyder/go-i18n/i18n/bundle/bundle_test.go сгенерированный поставляемый
Просмотреть файл

@@ -270,6 +270,26 @@ func BenchmarkTranslatePluralWithMap(b *testing.B) {
}
}
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)

34
vendor/github.com/nicksnyder/go-i18n/i18n/example_test.go сгенерированный поставляемый
Просмотреть файл

@@ -30,6 +30,15 @@ func Example() {
fmt.Println(T("person_unread_email_count", 1, bobStruct))
fmt.Println(T("person_unread_email_count", 2, bobStruct))
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}))
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"}))
fmt.Println(T("person_unread_email_count_timeframe", 3, map[string]interface{}{
"Person": "Bob",
"Timeframe": T("d_days", 0),
@@ -43,6 +52,22 @@ func Example() {
"Timeframe": T("d_days", 2),
}))
fmt.Println(T("person_unread_email_count_timeframe", 1, map[string]interface{}{
"Count": 30,
"Person": "Bob",
"Timeframe": T("d_days", 0),
}))
fmt.Println(T("person_unread_email_count_timeframe", 2, map[string]interface{}{
"Count": 20,
"Person": "Bob",
"Timeframe": T("d_days", 1),
}))
fmt.Println(T("person_unread_email_count_timeframe", 3, map[string]interface{}{
"Count": 10,
"Person": "Bob",
"Timeframe": T("d_days", 2),
}))
// Output:
// Hello world
// Hello Bob
@@ -57,7 +82,16 @@ func Example() {
// 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.
}

10
vendor/github.com/nicksnyder/go-i18n/i18n/i18n.go сгенерированный поставляемый
Просмотреть файл

@@ -69,9 +69,15 @@ import (
// 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, then the first variadic argument must be an integer type
// 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.
// 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.