Skip to content

Commit fe3f367

Browse files
Dean KarnDean Karn
authored andcommitted
Merge branch 'locales-based'
2 parents 367e66a + 478fb72 commit fe3f367

File tree

2,242 files changed

+1251
-44156
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

2,242 files changed

+1251
-44156
lines changed

README.md

Lines changed: 68 additions & 132 deletions
Original file line numberDiff line numberDiff line change
@@ -11,31 +11,23 @@ Universal Translator is an i18n Translator for Go/Golang using CLDR data + plura
1111

1212
Why another i18n library?
1313
--------------------------
14-
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,
15-
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
16-
know about what plural translations are needed for each language, no easy grouping to say, display all translations for a page...
14+
Because none of the plural rules seem to be correct out there, including the previous implimentation of this package,
15+
so I took it upon myself to create [locales](https://github.com/go-playground/locales) for everyone to use; this package
16+
is a thin wrapper around [locales](https://github.com/go-playground/locales) in order to store and translate text for
17+
use in your applications.
1718

1819
Features
1920
--------
20-
- [x] Rules added from [CLDR](http://cldr.unicode.org/index/downloads) data
21-
- [x] Use fmt.Sprintf() for translation string parsing
22-
- [x] Add Translations in code
23-
- [x] Prints the supported plural rules for a given translators locale using translator.PrintPluralRules()
24-
- [x] Plural Translations
25-
- [x] Date, Time & DateTime formatting
26-
- [x] Number, Whole Number formatting
27-
- [x] Currency both standard & accounting, formatting i.e. -$1,234.50 vs ($1,234.50)
28-
- [x] Handles BC and AD Dates. i.e. January 2, 300 BC
21+
- [x] Rules generated from the latest [CLDR](http://cldr.unicode.org/index/downloads) data, v29
22+
- [x] Contains Cardinal, Ordinal and Range Plural Rules
23+
- [x] Contains Month, Weekday and Timezone translations built in
24+
- [x] Contains Date & Time formatting functions
25+
- [x] Contains Number, Currency, Accounting and Percent formatting functions
26+
- [x] Supports the "Gregorian" calendar only ( my time isn't unlimited, had to draw the line somewhere )
2927
- [ ] Support loading translations from files
3028
- [ ] Exporting translations to file, mainly for getting them professionally translated
3129
- [ ] Code Generation for translation files -> Go code.. i.e. after it has been professionally translated
32-
- [ ] Printing of grouped translations, i.e. all transations for the homepage
33-
- [ ] Tests for all languages, I need help with this one see below
34-
35-
Full Language tests
36-
--------------------
37-
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;
38-
any help would be **greatly appreciated!!!!** please see [issue](https://github.com/go-playground/universal-translator/issues/1) for details.
30+
- [ ] Tests for all languages, I need help with this, please see [here](https://github.com/go-playground/locales/issues/1)
3931

4032
Installation
4133
-----------
@@ -44,13 +36,7 @@ Use go get
4436

4537
```go
4638
go get github.com/go-playground/universal-translator
47-
```
48-
49-
or to update
50-
51-
```go
52-
go get -u github.com/go-playground/universal-translator
53-
```
39+
```
5440

5541
Usage
5642
-------
@@ -59,120 +45,70 @@ package main
5945

6046
import (
6147
"fmt"
62-
"time"
6348

49+
"github.com/go-playground/locales"
6450
"github.com/go-playground/universal-translator"
65-
66-
// DONE this way to avoid huge compile times + memory for all languages, although it would
67-
// be nice for all applications to support all languages... that's not reality
68-
_ "github.com/go-playground/universal-translator/resources/locales"
6951
)
7052

53+
// only one instance as translators within are shared + goroutine safe
54+
var universalTraslator *ut.UniversalTranslator
55+
7156
func main() {
72-
trans, _ := ut.GetTranslator("en")
73-
74-
trans.PrintPluralRules()
75-
// OUTPUT:
76-
// Translator locale 'en' supported rules:
77-
//- PluralRuleOne
78-
//- PluralRuleOther
79-
80-
// add a singular translation
81-
trans.Add(ut.PluralRuleOne, "homepage", "welcome_msg", "Welcome to site %s")
82-
83-
// add singular + plural translation(s)
84-
trans.Add(ut.PluralRuleOne, "homepage", "day_warning", "You only have %d day left in your trial")
85-
trans.Add(ut.PluralRuleOther, "homepage", "day_warning", "You only have %d day's left in your trial")
86-
87-
// translate singular
88-
translated := trans.T("welcome_msg", "Joey Bloggs")
89-
fmt.Println(translated)
90-
// OUTPUT: Welcome to site Joey Bloggs
91-
92-
// What if something went wrong? then translated would output "" (blank)
93-
// How do I catch errors?
94-
translated, err := trans.TSafe("welcome_m", "Joey Bloggs")
95-
fmt.Println(translated)
96-
// OUTPUT: ""
97-
fmt.Println(err)
98-
// OUTPUT: ***** WARNING:***** Translation Key 'welcome_m' Not Found
99-
100-
// NOTE: there is a Safe variant of most of the Translation and Formatting functions if you need them,
101-
// for brevity will be using the non safe ones for the rest of this example
102-
103-
// The second parameter below, count, is needed as the final variable is a varadic and would not
104-
// know which one to use in applying the plural rules.
105-
// translate singular/plural
106-
translated = trans.P("day_warning", 3, 3)
107-
fmt.Println(translated)
108-
// OUTPUT: You only have 3 day's left in your trial
109-
110-
translated = trans.P("day_warning", 1, 1)
111-
fmt.Println(translated)
112-
// OUTPUT: You only have 1 day left in your trial
113-
114-
// There are Full, Long, Medium and Short function for each of the following
115-
dtString := "Jan 2, 2006 at 3:04:05pm"
116-
dt, _ := time.Parse(dtString, dtString)
117-
118-
formatted := trans.FmtDateFull(dt)
119-
fmt.Println(formatted)
120-
// OUTPUT: Monday, January 2, 2006
121-
122-
formatted = trans.FmtDateShort(dt)
123-
fmt.Println(formatted)
124-
// OUTPUT: 1/2/06
125-
126-
formatted = trans.FmtTimeFull(dt)
127-
fmt.Println(formatted)
128-
// OUTPUT: 3:04:05 PM
129-
130-
formatted = trans.FmtDateTimeFull(dt)
131-
fmt.Println(formatted)
132-
// OUTPUT: Monday, January 2, 2006 at 3:04:05 PM
133-
134-
formatted = trans.FmtCurrency(ut.CurrencyStandard, "USD", 1234.50)
135-
fmt.Println(formatted)
136-
// OUTPUT: $1,234.50
137-
138-
formatted = trans.FmtCurrency(ut.CurrencyStandard, "USD", -1234.50)
139-
fmt.Println(formatted)
140-
// OUTPUT: -$1,234.50
141-
142-
formatted = trans.FmtCurrency(ut.CurrencyAccounting, "USD", -1234.50)
143-
fmt.Println(formatted)
144-
// OUTPUT: ($1,234.50)
145-
146-
formatted = trans.FmtCurrencyWhole(ut.CurrencyStandard, "USD", -1234.50)
147-
fmt.Println(formatted)
148-
// OUTPUT: -$1,234
149-
150-
formatted = trans.FmtNumber(1234.50)
151-
fmt.Println(formatted)
152-
// OUTPUT: 1,234.5
153-
154-
formatted = trans.FmtNumberWhole(1234.50)
155-
fmt.Println(formatted)
156-
// OUTPUT: 1,234
57+
58+
// NOTE: this example is omitting allot of error checking for brevity
59+
60+
universalTraslator, _ = ut.New("en", "en", "en_CA", "nl", "fr")
61+
62+
en := universalTraslator.GetTranslator("en")
63+
64+
// generally used after parsing an http 'Accept-Language' header
65+
// and this will try to find a matching locale you support or
66+
// fallback locale.
67+
// en, _ := ut.FindTranslator([]string{"en", "en_CA", "nl"})
68+
69+
// this will help
70+
fmt.Println("Cardinal Plural Rules:", en.PluralsCardinal())
71+
fmt.Println("Ordinal Plural Rules:", en.PluralsOrdinal())
72+
fmt.Println("Range Plural Rules:", en.PluralsRange())
73+
74+
// add basic language only translations
75+
en.Add("welcome", "Welcome {0} to our test")
76+
77+
// add language translations dependant on cardinal plural rules
78+
en.AddCardinal("days", "You have {0} day left to register", locales.PluralRuleOne)
79+
en.AddCardinal("days", "You have {0} days left to register", locales.PluralRuleOther)
80+
81+
// add language translations dependant on ordinal plural rules
82+
en.AddOrdinal("day-of-month", "{0}st", locales.PluralRuleOne)
83+
en.AddOrdinal("day-of-month", "{0}nd", locales.PluralRuleTwo)
84+
en.AddOrdinal("day-of-month", "{0}rd", locales.PluralRuleFew)
85+
en.AddOrdinal("day-of-month", "{0}th", locales.PluralRuleOther)
86+
87+
// add language translations dependant on range plural rules
88+
// NOTE: only one plural rule for range in 'en' locale
89+
en.AddRange("between", "It's {0}-{1} days away", locales.PluralRuleOther)
90+
91+
// now lets use the translations we just added, in the same order we added them
92+
93+
fmt.Println(en.T("welcome", "Joeybloggs"))
94+
95+
fmt.Println(en.C("days", 1, 0, string(en.FmtNumber(1, 0)))) // you'd normally have variables defined for 1 and 0
96+
fmt.Println(en.C("days", 2, 0, string(en.FmtNumber(2, 0))))
97+
fmt.Println(en.C("days", 10456.25, 2, string(en.FmtNumber(10456.25, 2))))
98+
99+
fmt.Println(en.O("day-of-month", 1, 0, string(en.FmtNumber(1, 0))))
100+
fmt.Println(en.O("day-of-month", 2, 0, string(en.FmtNumber(2, 0))))
101+
fmt.Println(en.O("day-of-month", 3, 0, string(en.FmtNumber(3, 0))))
102+
fmt.Println(en.O("day-of-month", 4, 0, string(en.FmtNumber(4, 0))))
103+
fmt.Println(en.O("day-of-month", 10456.25, 0, string(en.FmtNumber(10456.25, 0))))
104+
105+
fmt.Println(en.R("between", 0, 0, 1, 0, string(en.FmtNumber(0, 0)), string(en.FmtNumber(1, 0))))
106+
fmt.Println(en.R("between", 1, 0, 2, 0, string(en.FmtNumber(1, 0)), string(en.FmtNumber(2, 0))))
107+
fmt.Println(en.R("between", 1, 0, 100, 0, string(en.FmtNumber(1, 0)), string(en.FmtNumber(100, 0))))
157108
}
158109
```
159110

160111
Help With Tests
161112
---------------
162113
To anyone interesting in helping or contributing, I sure could use some help creating tests for each language.
163-
Please see issue [here](https://github.com/go-playground/universal-translator/issues/1) for details.
164-
165-
Thanks to some help, the following languages have tests:
166-
167-
- [x] en - English US
168-
- [x] th - Thai thanks to @prideloki
169-
170-
Special Thanks
171-
--------------
172-
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.
173-
* [cldr](https://github.com/theplant/cldr) - A golang i18n tool using CLDR data
174-
* [i18n](https://github.com/vube/i18n) - golang package for basic i18n features, including message translation and number formatting
175-
176-
Misc
177-
-------
178-
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.
114+
Please see issue [here](https://github.com/go-playground/locales/issues/1) for details.

benchmarks_test.go

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package ut
2+
3+
import "testing"
4+
5+
func BenchmarkBasicTranslation(b *testing.B) {
6+
7+
ut, _ := New("en", "en")
8+
loc := ut.FindTranslator("en")
9+
loc.Add("welcome", "Welcome to the site")
10+
loc.Add("welcome-user", "Welcome to the site {0}")
11+
loc.Add("welcome-user2", "Welcome to the site {0}, your location is {1}")
12+
13+
b.Run("", func(b *testing.B) {
14+
for i := 0; i < b.N; i++ {
15+
loc.T("welcome")
16+
}
17+
})
18+
19+
b.Run("Parallel", func(b *testing.B) {
20+
21+
b.RunParallel(func(pb *testing.PB) {
22+
23+
for pb.Next() {
24+
loc.T("welcome")
25+
}
26+
})
27+
})
28+
29+
b.Run("With1Param", func(b *testing.B) {
30+
for i := 0; i < b.N; i++ {
31+
loc.T("welcome-user", "Joeybloggs")
32+
}
33+
})
34+
35+
b.Run("ParallelWith1Param", func(b *testing.B) {
36+
37+
b.RunParallel(func(pb *testing.PB) {
38+
39+
for pb.Next() {
40+
loc.T("welcome-user", "Joeybloggs")
41+
}
42+
})
43+
})
44+
45+
b.Run("With2Param", func(b *testing.B) {
46+
for i := 0; i < b.N; i++ {
47+
loc.T("welcome-user2", "Joeybloggs", "/dev/tty0")
48+
}
49+
})
50+
51+
b.Run("ParallelWith2Param", func(b *testing.B) {
52+
53+
b.RunParallel(func(pb *testing.PB) {
54+
55+
for pb.Next() {
56+
loc.T("welcome-user2", "Joeybloggs", "/dev/tty0")
57+
}
58+
})
59+
})
60+
}

0 commit comments

Comments
 (0)