Browse Source

rework example, code cleanup + update README

Dean Karn 9 years ago
parent
commit
478fb7294a
3 changed files with 123 additions and 226 deletions
  1. 68 132
      README.md
  2. 55 90
      examples/basic/main.go
  3. 0 4
      translator.go

+ 68 - 132
README.md

@@ -11,31 +11,23 @@ Universal Translator is an i18n Translator for Go/Golang using CLDR data + plura
 
 
 Why another i18n library?
 Why another i18n library?
 --------------------------
 --------------------------
-I noticed that most libraries out there use static files for translations, which I'm not against just there is not option for coding it inline, 
-as well as having formats which do not handle all plural rules, or are overcomplicated. There is also very little in the way of helping the user
-know about what plural translations are needed for each language, no easy grouping to say, display all translations for a page...
+Because none of the plural rules seem to be correct out there, including the previous implimentation of this package,
+so I took it upon myself to create [locales](https://github.com/go-playground/locales) for everyone to use; this package 
+is a thin wrapper around [locales](https://github.com/go-playground/locales) in order to store and translate text for 
+use in your applications.
 
 
 Features
 Features
 --------
 --------
-- [x] Rules added from [CLDR](http://cldr.unicode.org/index/downloads) data
-- [x] Use fmt.Sprintf() for translation string parsing
-- [x] Add Translations in code
-- [x] Prints the supported plural rules for a given translators locale using translator.PrintPluralRules()
-- [x] Plural Translations
-- [x] Date, Time & DateTime formatting
-- [x] Number, Whole Number formatting
-- [x] Currency both standard & accounting, formatting i.e. -$1,234.50 vs ($1,234.50)
-- [x] Handles BC and AD Dates. i.e. January 2, 300 BC
+- [x] Rules generated from the latest [CLDR](http://cldr.unicode.org/index/downloads) data, v29
+- [x] Contains Cardinal, Ordinal and Range Plural Rules
+- [x] Contains Month, Weekday and Timezone translations built in
+- [x] Contains Date & Time formatting functions
+- [x] Contains Number, Currency, Accounting and Percent formatting functions
+- [x] Supports the "Gregorian" calendar only ( my time isn't unlimited, had to draw the line somewhere )
 - [ ] Support loading translations from files
 - [ ] Support loading translations from files
 - [ ] Exporting translations to file, mainly for getting them professionally translated
 - [ ] Exporting translations to file, mainly for getting them professionally translated
 - [ ] Code Generation for translation files -> Go code.. i.e. after it has been professionally translated
 - [ ] Code Generation for translation files -> Go code.. i.e. after it has been professionally translated
-- [ ] Printing of grouped translations, i.e. all transations for the homepage
-- [ ] Tests for all languages, I need help with this one see below
-
-Full Language tests
---------------------
-I could sure use your help adding tests for every language, it is a huge undertaking and I just don't have the free time to do it all at the moment;
-any help would be **greatly appreciated!!!!** please see [issue](https://github.com/go-playground/universal-translator/issues/1) for details.
+- [ ] Tests for all languages, I need help with this, please see [here](https://github.com/go-playground/locales/issues/1)
 
 
 Installation
 Installation
 -----------
 -----------
@@ -44,13 +36,7 @@ Use go get
 
 
 ```go
 ```go
 go get github.com/go-playground/universal-translator
 go get github.com/go-playground/universal-translator
-``` 
-
-or to update
-
-```go
-go get -u github.com/go-playground/universal-translator
-``` 
+```
 
 
 Usage
 Usage
 -------
 -------
@@ -59,120 +45,70 @@ package main
 
 
 import (
 import (
 	"fmt"
 	"fmt"
-	"time"
 
 
+	"github.com/go-playground/locales"
 	"github.com/go-playground/universal-translator"
 	"github.com/go-playground/universal-translator"
-
-	// DONE this way to avoid huge compile times + memory for all languages, although it would
-	// be nice for all applications to support all languages... that's not reality
-	_ "github.com/go-playground/universal-translator/resources/locales"
 )
 )
 
 
+// only one instance as translators within are shared + goroutine safe
+var universalTraslator *ut.UniversalTranslator
+
 func main() {
 func main() {
-	trans, _ := ut.GetTranslator("en")
-
-	trans.PrintPluralRules()
-	// OUTPUT:
-	// Translator locale 'en' supported rules:
-	//- PluralRuleOne
-	//- PluralRuleOther
-
-	// add a singular translation
-	trans.Add(ut.PluralRuleOne, "homepage", "welcome_msg", "Welcome to site %s")
-
-	// add singular + plural translation(s)
-	trans.Add(ut.PluralRuleOne, "homepage", "day_warning", "You only have %d day left in your trial")
-	trans.Add(ut.PluralRuleOther, "homepage", "day_warning", "You only have %d day's left in your trial")
-
-	// translate singular
-	translated := trans.T("welcome_msg", "Joey Bloggs")
-	fmt.Println(translated)
-	// OUTPUT: Welcome to site Joey Bloggs
-
-	// What if something went wrong? then translated would output "" (blank)
-	// How do I catch errors?
-	translated, err := trans.TSafe("welcome_m", "Joey Bloggs")
-	fmt.Println(translated)
-	// OUTPUT: ""
-	fmt.Println(err)
-	// OUTPUT: ***** WARNING:***** Translation Key 'welcome_m' Not Found
-
-	// NOTE: there is a Safe variant of most of the Translation and Formatting functions if you need them,
-	// for brevity will be using the non safe ones for the rest of this example
-
-	// The second parameter below, count, is needed as the final variable is a varadic and would not
-	// know which one to use in applying the plural rules.
-	// translate singular/plural
-	translated = trans.P("day_warning", 3, 3)
-	fmt.Println(translated)
-	// OUTPUT: You only have 3 day's left in your trial
-
-	translated = trans.P("day_warning", 1, 1)
-	fmt.Println(translated)
-	// OUTPUT: You only have 1 day left in your trial
-
-	// There are Full, Long, Medium and Short function for each of the following
-	dtString := "Jan 2, 2006 at 3:04:05pm"
-	dt, _ := time.Parse(dtString, dtString)
-
-	formatted := trans.FmtDateFull(dt)
-	fmt.Println(formatted)
-	// OUTPUT: Monday, January 2, 2006
-
-	formatted = trans.FmtDateShort(dt)
-	fmt.Println(formatted)
-	// OUTPUT: 1/2/06
-
-	formatted = trans.FmtTimeFull(dt)
-	fmt.Println(formatted)
-	// OUTPUT: 3:04:05 PM
-
-	formatted = trans.FmtDateTimeFull(dt)
-	fmt.Println(formatted)
-	// OUTPUT: Monday, January 2, 2006 at 3:04:05 PM
-
-	formatted = trans.FmtCurrency(ut.CurrencyStandard, "USD", 1234.50)
-	fmt.Println(formatted)
-	// OUTPUT: $1,234.50
-
-	formatted = trans.FmtCurrency(ut.CurrencyStandard, "USD", -1234.50)
-	fmt.Println(formatted)
-	// OUTPUT: -$1,234.50
-
-	formatted = trans.FmtCurrency(ut.CurrencyAccounting, "USD", -1234.50)
-	fmt.Println(formatted)
-	// OUTPUT: ($1,234.50)
-
-	formatted = trans.FmtCurrencyWhole(ut.CurrencyStandard, "USD", -1234.50)
-	fmt.Println(formatted)
-	// OUTPUT: -$1,234
-
-	formatted = trans.FmtNumber(1234.50)
-	fmt.Println(formatted)
-	// OUTPUT: 1,234.5
-
-	formatted = trans.FmtNumberWhole(1234.50)
-	fmt.Println(formatted)
-	// OUTPUT: 1,234
+
+	// NOTE: this example is omitting allot of error checking for brevity
+
+	universalTraslator, _ = ut.New("en", "en", "en_CA", "nl", "fr")
+
+	en := universalTraslator.GetTranslator("en")
+
+	// generally used after parsing an http 'Accept-Language' header
+	// and this will try to find a matching locale you support or
+	// fallback locale.
+	// en, _ := ut.FindTranslator([]string{"en", "en_CA", "nl"})
+
+	// this will help
+	fmt.Println("Cardinal Plural Rules:", en.PluralsCardinal())
+	fmt.Println("Ordinal Plural Rules:", en.PluralsOrdinal())
+	fmt.Println("Range Plural Rules:", en.PluralsRange())
+
+	// add basic language only translations
+	en.Add("welcome", "Welcome {0} to our test")
+
+	// add language translations dependant on cardinal plural rules
+	en.AddCardinal("days", "You have {0} day left to register", locales.PluralRuleOne)
+	en.AddCardinal("days", "You have {0} days left to register", locales.PluralRuleOther)
+
+	// add language translations dependant on ordinal plural rules
+	en.AddOrdinal("day-of-month", "{0}st", locales.PluralRuleOne)
+	en.AddOrdinal("day-of-month", "{0}nd", locales.PluralRuleTwo)
+	en.AddOrdinal("day-of-month", "{0}rd", locales.PluralRuleFew)
+	en.AddOrdinal("day-of-month", "{0}th", locales.PluralRuleOther)
+
+	// add language translations dependant on range plural rules
+	// NOTE: only one plural rule for range in 'en' locale
+	en.AddRange("between", "It's {0}-{1} days away", locales.PluralRuleOther)
+
+	// now lets use the translations we just added, in the same order we added them
+
+	fmt.Println(en.T("welcome", "Joeybloggs"))
+
+	fmt.Println(en.C("days", 1, 0, string(en.FmtNumber(1, 0)))) // you'd normally have variables defined for 1 and 0
+	fmt.Println(en.C("days", 2, 0, string(en.FmtNumber(2, 0))))
+	fmt.Println(en.C("days", 10456.25, 2, string(en.FmtNumber(10456.25, 2))))
+
+	fmt.Println(en.O("day-of-month", 1, 0, string(en.FmtNumber(1, 0))))
+	fmt.Println(en.O("day-of-month", 2, 0, string(en.FmtNumber(2, 0))))
+	fmt.Println(en.O("day-of-month", 3, 0, string(en.FmtNumber(3, 0))))
+	fmt.Println(en.O("day-of-month", 4, 0, string(en.FmtNumber(4, 0))))
+	fmt.Println(en.O("day-of-month", 10456.25, 0, string(en.FmtNumber(10456.25, 0))))
+
+	fmt.Println(en.R("between", 0, 0, 1, 0, string(en.FmtNumber(0, 0)), string(en.FmtNumber(1, 0))))
+	fmt.Println(en.R("between", 1, 0, 2, 0, string(en.FmtNumber(1, 0)), string(en.FmtNumber(2, 0))))
+	fmt.Println(en.R("between", 1, 0, 100, 0, string(en.FmtNumber(1, 0)), string(en.FmtNumber(100, 0))))
 }
 }
 ```
 ```
 
 
 Help With Tests
 Help With Tests
 ---------------
 ---------------
 To anyone interesting in helping or contributing, I sure could use some help creating tests for each language.
 To anyone interesting in helping or contributing, I sure could use some help creating tests for each language.
-Please see issue [here](https://github.com/go-playground/universal-translator/issues/1) for details.
-
-Thanks to some help, the following languages have tests:
-
-- [x] en - English US
-- [x] th - Thai thanks to @prideloki
-
-Special Thanks
---------------
-Special thanks to the following libraries that not only inspired, but that I borrowed a bunch of code from to create this.. ultimately there were many changes made and more to come, but without them would have taken forever to just get started.
-* [cldr](https://github.com/theplant/cldr) - A golang i18n tool using CLDR data
-* [i18n](https://github.com/vube/i18n) - golang package for basic i18n features, including message translation and number formatting
-
-Misc
--------
-Library is not at 1.0 yet, but don't forsee any major API changes; will raise to 1.0 once I've used it completely in at least one project without issue.
+Please see issue [here](https://github.com/go-playground/locales/issues/1) for details.

+ 55 - 90
examples/basic/main.go

@@ -2,99 +2,64 @@ package main
 
 
 import (
 import (
 	"fmt"
 	"fmt"
-	"time"
 
 
+	"github.com/go-playground/locales"
 	"github.com/go-playground/universal-translator"
 	"github.com/go-playground/universal-translator"
-
-	// DONE this way to avoid huge compile times + memory for all languages, although it would
-	// be nice for all applications to support all languages... that's not reality
-	_ "github.com/go-playground/universal-translator/resources/locales"
 )
 )
 
 
+// only one instance as translators within are shared + goroutine safe
+var universalTraslator *ut.UniversalTranslator
+
 func main() {
 func main() {
-	trans, _ := ut.GetTranslator("en")
-
-	trans.PrintPluralRules()
-	// OUTPUT:
-	// Translator locale 'en' supported rules:
-	//- PluralRuleOne
-	//- PluralRuleOther
-
-	// add a singular translation
-	trans.Add(ut.PluralRuleOne, "homepage", "welcome_msg", "Welcome to site %s")
-
-	// add singular + plural translation(s)
-	trans.Add(ut.PluralRuleOne, "homepage", "day_warning", "You only have %d day left in your trial")
-	trans.Add(ut.PluralRuleOther, "homepage", "day_warning", "You only have %d day's left in your trial")
-
-	// translate singular
-	translated := trans.T("welcome_msg", "Joey Bloggs")
-	fmt.Println(translated)
-	// OUTPUT: Welcome to site Joey Bloggs
-
-	// What if something went wrong? then translated would output "" (blank)
-	// How do I catch errors?
-	translated, err := trans.TSafe("welcome_m", "Joey Bloggs")
-	fmt.Println(translated)
-	// OUTPUT: ""
-	fmt.Println(err)
-	// OUTPUT: ***** WARNING:***** Translation Key 'welcome_m' Not Found
-
-	// NOTE: there is a Safe variant of most of the Translation and Formatting functions if you need them,
-	// for brevity will be using the non safe ones for the rest of this example
-
-	// The second parameter below, count, is needed as the final variable is a varadic and would not
-	// know which one to use in applying the plural rules.
-	// translate singular/plural
-	translated = trans.P("day_warning", 3, 3)
-	fmt.Println(translated)
-	// OUTPUT: You only have 3 day's left in your trial
-
-	translated = trans.P("day_warning", 1, 1)
-	fmt.Println(translated)
-	// OUTPUT: You only have 1 day left in your trial
-
-	// There are Full, Long, Medium and Short function for each of the following
-	dtString := "Jan 2, 2006 at 3:04:05pm"
-	dt, _ := time.Parse(dtString, dtString)
-
-	formatted := trans.FmtDateFull(dt)
-	fmt.Println(formatted)
-	// OUTPUT: Monday, January 2, 2006
-
-	formatted = trans.FmtDateShort(dt)
-	fmt.Println(formatted)
-	// OUTPUT: 1/2/06
-
-	formatted = trans.FmtTimeFull(dt)
-	fmt.Println(formatted)
-	// OUTPUT: 3:04:05 PM
-
-	formatted = trans.FmtDateTimeFull(dt)
-	fmt.Println(formatted)
-	// OUTPUT: Monday, January 2, 2006 at 3:04:05 PM
-
-	formatted = trans.FmtCurrency(ut.CurrencyStandard, "USD", 1234.50)
-	fmt.Println(formatted)
-	// OUTPUT: $1,234.50
-
-	formatted = trans.FmtCurrency(ut.CurrencyStandard, "USD", -1234.50)
-	fmt.Println(formatted)
-	// OUTPUT: -$1,234.50
-
-	formatted = trans.FmtCurrency(ut.CurrencyAccounting, "USD", -1234.50)
-	fmt.Println(formatted)
-	// OUTPUT: ($1,234.50)
-
-	formatted = trans.FmtCurrencyWhole(ut.CurrencyStandard, "USD", -1234.50)
-	fmt.Println(formatted)
-	// OUTPUT: -$1,234
-
-	formatted = trans.FmtNumber(1234.50)
-	fmt.Println(formatted)
-	// OUTPUT: 1,234.5
-
-	formatted = trans.FmtNumberWhole(1234.50)
-	fmt.Println(formatted)
-	// OUTPUT: 1,234
+
+	// NOTE: this example is omitting allot of error checking for brevity
+
+	universalTraslator, _ = ut.New("en", "en", "en_CA", "nl", "fr")
+
+	en := universalTraslator.GetTranslator("en")
+
+	// generally used after parsing an http 'Accept-Language' header
+	// and this will try to find a matching locale you support or
+	// fallback locale.
+	// en, _ := ut.FindTranslator([]string{"en", "en_CA", "nl"})
+
+	// this will help
+	fmt.Println("Cardinal Plural Rules:", en.PluralsCardinal())
+	fmt.Println("Ordinal Plural Rules:", en.PluralsOrdinal())
+	fmt.Println("Range Plural Rules:", en.PluralsRange())
+
+	// add basic language only translations
+	en.Add("welcome", "Welcome {0} to our test")
+
+	// add language translations dependant on cardinal plural rules
+	en.AddCardinal("days", "You have {0} day left to register", locales.PluralRuleOne)
+	en.AddCardinal("days", "You have {0} days left to register", locales.PluralRuleOther)
+
+	// add language translations dependant on ordinal plural rules
+	en.AddOrdinal("day-of-month", "{0}st", locales.PluralRuleOne)
+	en.AddOrdinal("day-of-month", "{0}nd", locales.PluralRuleTwo)
+	en.AddOrdinal("day-of-month", "{0}rd", locales.PluralRuleFew)
+	en.AddOrdinal("day-of-month", "{0}th", locales.PluralRuleOther)
+
+	// add language translations dependant on range plural rules
+	// NOTE: only one plural rule for range in 'en' locale
+	en.AddRange("between", "It's {0}-{1} days away", locales.PluralRuleOther)
+
+	// now lets use the translations we just added, in the same order we added them
+
+	fmt.Println(en.T("welcome", "Joeybloggs"))
+
+	fmt.Println(en.C("days", 1, 0, string(en.FmtNumber(1, 0)))) // you'd normally have variables defined for 1 and 0
+	fmt.Println(en.C("days", 2, 0, string(en.FmtNumber(2, 0))))
+	fmt.Println(en.C("days", 10456.25, 2, string(en.FmtNumber(10456.25, 2))))
+
+	fmt.Println(en.O("day-of-month", 1, 0, string(en.FmtNumber(1, 0))))
+	fmt.Println(en.O("day-of-month", 2, 0, string(en.FmtNumber(2, 0))))
+	fmt.Println(en.O("day-of-month", 3, 0, string(en.FmtNumber(3, 0))))
+	fmt.Println(en.O("day-of-month", 4, 0, string(en.FmtNumber(4, 0))))
+	fmt.Println(en.O("day-of-month", 10456.25, 0, string(en.FmtNumber(10456.25, 0))))
+
+	fmt.Println(en.R("between", 0, 0, 1, 0, string(en.FmtNumber(0, 0)), string(en.FmtNumber(1, 0))))
+	fmt.Println(en.R("between", 1, 0, 2, 0, string(en.FmtNumber(1, 0)), string(en.FmtNumber(2, 0))))
+	fmt.Println(en.R("between", 1, 0, 100, 0, string(en.FmtNumber(1, 0)), string(en.FmtNumber(100, 0))))
 }
 }

+ 0 - 4
translator.go

@@ -252,7 +252,6 @@ func (t *translator) T(key interface{}, params ...string) string {
 		return unknownTranslation
 		return unknownTranslation
 	}
 	}
 
 
-	// maybe pool these later?...
 	b := make([]byte, 0, 64)
 	b := make([]byte, 0, 64)
 
 
 	var start, end, count int
 	var start, end, count int
@@ -283,7 +282,6 @@ func (t *translator) C(key interface{}, num float64, digits uint64, param string
 
 
 	trans := tarr[rule]
 	trans := tarr[rule]
 
 
-	// maybe pool these later?...
 	b := make([]byte, 0, 64)
 	b := make([]byte, 0, 64)
 	b = append(b, trans.text[:trans.indexes[0]]...)
 	b = append(b, trans.text[:trans.indexes[0]]...)
 	b = append(b, param...)
 	b = append(b, param...)
@@ -304,7 +302,6 @@ func (t *translator) O(key interface{}, num float64, digits uint64, param string
 
 
 	trans := tarr[rule]
 	trans := tarr[rule]
 
 
-	// maybe pool these later?...
 	b := make([]byte, 0, 64)
 	b := make([]byte, 0, 64)
 	b = append(b, trans.text[:trans.indexes[0]]...)
 	b = append(b, trans.text[:trans.indexes[0]]...)
 	b = append(b, param...)
 	b = append(b, param...)
@@ -326,7 +323,6 @@ func (t *translator) R(key interface{}, num1 float64, digits1 uint64, num2 float
 
 
 	trans := tarr[rule]
 	trans := tarr[rule]
 
 
-	// maybe pool these later?...
 	b := make([]byte, 0, 64)
 	b := make([]byte, 0, 64)
 	b = append(b, trans.text[:trans.indexes[0]]...)
 	b = append(b, trans.text[:trans.indexes[0]]...)
 	b = append(b, param1...)
 	b = append(b, param1...)