From 1c9e01733308fe876a840a54ce7633540b182a75 Mon Sep 17 00:00:00 2001 From: mh-cbon Date: Sun, 16 Oct 2016 07:18:17 +0200 Subject: [PATCH] handle Count field from template data --- goi18n/doc.go | 62 +++++++++++++++++++------------------- i18n/bundle/bundle.go | 5 +++ i18n/bundle/bundle_test.go | 20 ++++++++++++ i18n/example_test.go | 34 +++++++++++++++++++++ i18n/i18n.go | 10 ++++-- 5 files changed, 98 insertions(+), 33 deletions(-) diff --git a/goi18n/doc.go b/goi18n/doc.go index a9927e52..97c7a7fb 100644 --- a/goi18n/doc.go +++ b/goi18n/doc.go @@ -6,88 +6,88 @@ // 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/i18n/bundle/bundle.go b/i18n/bundle/bundle.go index e93db95d..8e46fa29 100644 --- a/i18n/bundle/bundle.go +++ b/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) diff --git a/i18n/bundle/bundle_test.go b/i18n/bundle/bundle_test.go index b9c0a059..b241ad1d 100644 --- a/i18n/bundle/bundle_test.go +++ b/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) diff --git a/i18n/example_test.go b/i18n/example_test.go index d2d9706a..305c5b3d 100644 --- a/i18n/example_test.go +++ b/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. } diff --git a/i18n/i18n.go b/i18n/i18n.go index f9684296..c478ff6e 100644 --- a/i18n/i18n.go +++ b/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.