Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4b94e83723 | ||
|
|
756045ab5e | ||
|
|
2bb9254f26 | ||
|
|
88952938dc |
43
README.md
43
README.md
@@ -1,5 +1,5 @@
|
||||
[](https://github.com/leonelquinteros/gotext)
|
||||
[](LICENSE)
|
||||
[](https://badge.fury.io/gh/leonelquinteros%2Fgotext)
|
||||
[](https://godoc.org/github.com/leonelquinteros/gotext)
|
||||
[](https://travis-ci.org/leonelquinteros/gotext)
|
||||
[](https://codecov.io/gh/leonelquinteros/gotext)
|
||||
@@ -9,8 +9,6 @@
|
||||
|
||||
[GNU gettext utilities](https://www.gnu.org/software/gettext) for Go.
|
||||
|
||||
Version: [v1.1.1](https://github.com/leonelquinteros/gotext/releases/tag/v1.1.1)
|
||||
|
||||
|
||||
# Features
|
||||
|
||||
@@ -158,17 +156,20 @@ This is a normal Go compiler behavior.
|
||||
For quick/simple translations you can use the package level functions directly.
|
||||
|
||||
```go
|
||||
import "github.com/leonelquinteros/gotext"
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/leonelquinteros/gotext"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Configure package
|
||||
gotext.Configure("/path/to/locales/root/dir", "en_UK", "domain-name")
|
||||
|
||||
// Translate text from default domain
|
||||
println(gotext.Get("My text on 'domain-name' domain"))
|
||||
fmt.Println(gotext.Get("My text on 'domain-name' domain"))
|
||||
|
||||
// Translate text from a different domain without reconfigure
|
||||
println(gotext.GetD("domain2", "Another text on a different domain"))
|
||||
fmt.Println(gotext.GetD("domain2", "Another text on a different domain"))
|
||||
}
|
||||
|
||||
```
|
||||
@@ -179,7 +180,10 @@ All translation strings support dynamic variables to be inserted without transla
|
||||
Use the fmt.Printf syntax (from Go's "fmt" package) to specify how to print the non-translated variable inside the translation string.
|
||||
|
||||
```go
|
||||
import "github.com/leonelquinteros/gotext"
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/leonelquinteros/gotext"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Configure package
|
||||
@@ -189,7 +193,7 @@ func main() {
|
||||
name := "John"
|
||||
|
||||
// Translate text with variables
|
||||
println(gotext.Get("Hi, my name is %s", name))
|
||||
fmt.Println(gotext.Get("Hi, my name is %s", name))
|
||||
}
|
||||
|
||||
```
|
||||
@@ -201,7 +205,10 @@ When having multiple languages/domains/libraries at the same time, you can creat
|
||||
so you can handle each settings on their own.
|
||||
|
||||
```go
|
||||
import "github.com/leonelquinteros/gotext"
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/leonelquinteros/gotext"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Create Locale with library path and language code
|
||||
@@ -211,13 +218,13 @@ func main() {
|
||||
l.AddDomain("default")
|
||||
|
||||
// Translate text from default domain
|
||||
println(l.Get("Translate this"))
|
||||
fmt.Println(l.Get("Translate this"))
|
||||
|
||||
// Load different domain
|
||||
l.AddDomain("translations")
|
||||
|
||||
// Translate text from domain
|
||||
println(l.GetD("translations", "Translate this"))
|
||||
fmt.Println(l.GetD("translations", "Translate this"))
|
||||
}
|
||||
```
|
||||
|
||||
@@ -235,7 +242,10 @@ For when you need to work with PO files and strings,
|
||||
you can directly use the Po object to parse it and access the translations in there in the same way.
|
||||
|
||||
```go
|
||||
import "github.com/leonelquinteros/gotext"
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/leonelquinteros/gotext"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Set PO content
|
||||
@@ -254,7 +264,7 @@ msgstr "This one sets the var: %s"
|
||||
po := new(Po)
|
||||
po.Parse(str)
|
||||
|
||||
println(po.Get("Translate this"))
|
||||
fmt.Println(po.Get("Translate this"))
|
||||
}
|
||||
```
|
||||
|
||||
@@ -268,7 +278,10 @@ as defined in (https://www.gnu.org/savannah-checkouts/gnu/gettext/manual/html_no
|
||||
Plural formulas are parsed and evaluated using [Kinako](https://github.com/mattn/kinako)
|
||||
|
||||
```go
|
||||
import "github.com/leonelquinteros/gotext"
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/leonelquinteros/gotext"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Set PO content
|
||||
@@ -295,7 +308,7 @@ msgstr[1] "This one is the plural: %s"
|
||||
po := new(Po)
|
||||
po.Parse(str)
|
||||
|
||||
println(po.GetN("One with var: %s", "Several with vars: %s", 54, v))
|
||||
fmt.Println(po.GetN("One with var: %s", "Several with vars: %s", 54, v))
|
||||
// "This one is the plural: Variable"
|
||||
}
|
||||
```
|
||||
|
||||
@@ -3,17 +3,20 @@ Package gotext implements GNU gettext utilities.
|
||||
|
||||
For quick/simple translations you can use the package level functions directly.
|
||||
|
||||
import "github.com/leonelquinteros/gotext"
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/leonelquinteros/gotext"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Configure package
|
||||
gotext.Configure("/path/to/locales/root/dir", "en_UK", "domain-name")
|
||||
|
||||
// Translate text from default domain
|
||||
println(gotext.Get("My text on 'domain-name' domain"))
|
||||
fmt.Println(gotext.Get("My text on 'domain-name' domain"))
|
||||
|
||||
// Translate text from a different domain without reconfigure
|
||||
println(gotext.GetD("domain2", "Another text on a different domain"))
|
||||
fmt.Println(gotext.GetD("domain2", "Another text on a different domain"))
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
100
gotext_test.go
100
gotext_test.go
@@ -79,6 +79,11 @@ msgstr "Some random translation in a context"
|
||||
msgid "More"
|
||||
msgstr "More translation"
|
||||
|
||||
msgid "Untranslated"
|
||||
msgid_plural "Several untranslated"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
|
||||
`
|
||||
|
||||
// Create Locales directory on default location
|
||||
@@ -141,6 +146,79 @@ msgstr "More translation"
|
||||
}
|
||||
}
|
||||
|
||||
func TestUntranslated(t *testing.T) {
|
||||
// Set PO content
|
||||
str := `
|
||||
# msgid ""
|
||||
# msgstr ""
|
||||
# Initial comment
|
||||
# Headers below
|
||||
"Language: en\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
msgid "Untranslated"
|
||||
msgid_plural "Several untranslated"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
|
||||
`
|
||||
|
||||
// Create Locales directory on default location
|
||||
dirname := path.Clean("/tmp" + string(os.PathSeparator) + "en_US")
|
||||
err := os.MkdirAll(dirname, os.ModePerm)
|
||||
if err != nil {
|
||||
t.Fatalf("Can't create test directory: %s", err.Error())
|
||||
}
|
||||
|
||||
// Write PO content to default domain file
|
||||
filename := path.Clean(dirname + string(os.PathSeparator) + "default.po")
|
||||
|
||||
f, err := os.Create(filename)
|
||||
if err != nil {
|
||||
t.Fatalf("Can't create test file: %s", err.Error())
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
_, err = f.WriteString(str)
|
||||
if err != nil {
|
||||
t.Fatalf("Can't write to test file: %s", err.Error())
|
||||
}
|
||||
|
||||
// Set package configuration
|
||||
Configure("/tmp", "en_US", "default")
|
||||
|
||||
// Test untranslated
|
||||
tr := Get("Untranslated")
|
||||
if tr != "Untranslated" {
|
||||
t.Errorf("Expected 'Untranslated' but got '%s'", tr)
|
||||
}
|
||||
tr = GetN("Untranslated", "Several untranslated", 1)
|
||||
if tr != "Untranslated" {
|
||||
t.Errorf("Expected 'Untranslated' but got '%s'", tr)
|
||||
}
|
||||
|
||||
tr = GetN("Untranslated", "Several untranslated", 2)
|
||||
if tr != "Several untranslated" {
|
||||
t.Errorf("Expected 'Several untranslated' but got '%s'", tr)
|
||||
}
|
||||
|
||||
tr = GetD("default", "Untranslated")
|
||||
if tr != "Untranslated" {
|
||||
t.Errorf("Expected 'Untranslated' but got '%s'", tr)
|
||||
}
|
||||
tr = GetND("default", "Untranslated", "Several untranslated", 1)
|
||||
if tr != "Untranslated" {
|
||||
t.Errorf("Expected 'Untranslated' but got '%s'", tr)
|
||||
}
|
||||
|
||||
tr = GetND("default", "Untranslated", "Several untranslated", 2)
|
||||
if tr != "Several untranslated" {
|
||||
t.Errorf("Expected 'Several untranslated' but got '%s'", tr)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPackageRace(t *testing.T) {
|
||||
// Set PO content
|
||||
str := `# Some comment
|
||||
@@ -184,16 +262,18 @@ msgstr[2] "And this is the second plural form: %s"
|
||||
c1 := make(chan bool)
|
||||
c2 := make(chan bool)
|
||||
|
||||
// Test translations
|
||||
go func(done chan bool) {
|
||||
Get("My text")
|
||||
done <- true
|
||||
}(c1)
|
||||
for i := 0; i < 100; i++ {
|
||||
// Test translations
|
||||
go func(done chan bool) {
|
||||
Get("My text")
|
||||
done <- true
|
||||
}(c1)
|
||||
|
||||
go func(done chan bool) {
|
||||
Get("My text")
|
||||
done <- true
|
||||
}(c2)
|
||||
go func(done chan bool) {
|
||||
Get("My text")
|
||||
done <- true
|
||||
}(c2)
|
||||
|
||||
Get("My text")
|
||||
Get("My text")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,10 @@ multiple languages at the same time by working with this object.
|
||||
|
||||
Example:
|
||||
|
||||
import "github.com/leonelquinteros/gotext"
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/leonelquinteros/gotext"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Create Locale with library path and language code
|
||||
@@ -24,13 +27,13 @@ Example:
|
||||
l.AddDomain("default")
|
||||
|
||||
// Translate text from default domain
|
||||
println(l.Get("Translate this"))
|
||||
fmt.Println(l.Get("Translate this"))
|
||||
|
||||
// Load different domain ('/path/to/i18n/dir/en_US/LC_MESSAGES/extras.po')
|
||||
l.AddDomain("extras")
|
||||
|
||||
// Translate text from domain
|
||||
println(l.GetD("extras", "Translate this"))
|
||||
fmt.Println(l.GetD("extras", "Translate this"))
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
26
po.go
26
po.go
@@ -3,14 +3,13 @@ package gotext
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"github.com/mattn/kinako/vm"
|
||||
"io/ioutil"
|
||||
"net/textproto"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/mattn/kinako/vm"
|
||||
)
|
||||
|
||||
type translation struct {
|
||||
@@ -29,7 +28,9 @@ func newTranslation() *translation {
|
||||
func (t *translation) get() string {
|
||||
// Look for translation index 0
|
||||
if _, ok := t.trs[0]; ok {
|
||||
return t.trs[0]
|
||||
if t.trs[0] != "" {
|
||||
return t.trs[0]
|
||||
}
|
||||
}
|
||||
|
||||
// Return unstranlated id by default
|
||||
@@ -39,10 +40,17 @@ func (t *translation) get() string {
|
||||
func (t *translation) getN(n int) string {
|
||||
// Look for translation index
|
||||
if _, ok := t.trs[n]; ok {
|
||||
return t.trs[n]
|
||||
if t.trs[n] != "" {
|
||||
return t.trs[n]
|
||||
}
|
||||
}
|
||||
|
||||
// Return unstranlated plural by default
|
||||
// Return unstranlated singular if corresponding
|
||||
if n == 0 {
|
||||
return t.id
|
||||
}
|
||||
|
||||
// Return untranslated plural by default
|
||||
return t.pluralID
|
||||
}
|
||||
|
||||
@@ -53,7 +61,10 @@ And it's safe for concurrent use by multiple goroutines by using the sync packag
|
||||
|
||||
Example:
|
||||
|
||||
import "github.com/leonelquinteros/gotext"
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/leonelquinteros/gotext"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Create po object
|
||||
@@ -63,7 +74,7 @@ Example:
|
||||
po.ParseFile("/path/to/po/file/translations.po")
|
||||
|
||||
// Get translation
|
||||
println(po.Get("Translate this"))
|
||||
fmt.Println(po.Get("Translate this"))
|
||||
}
|
||||
|
||||
*/
|
||||
@@ -435,6 +446,7 @@ func (po *Po) GetN(str, plural string, n int, vars ...interface{}) string {
|
||||
if n == 1 {
|
||||
return fmt.Sprintf(str, vars...)
|
||||
}
|
||||
|
||||
return fmt.Sprintf(plural, vars...)
|
||||
}
|
||||
|
||||
|
||||
34
po_test.go
34
po_test.go
@@ -69,8 +69,17 @@ msgctxt "Ctx"
|
||||
msgid "Some random in a context"
|
||||
msgstr "Some random translation in a context"
|
||||
|
||||
msgid "Empty translation"
|
||||
msgstr ""
|
||||
|
||||
msgid "Empty plural form singular"
|
||||
msgid_plural "Empty plural form"
|
||||
msgstr[0] "Singular translated"
|
||||
msgstr[1] "
|
||||
|
||||
msgid "More"
|
||||
msgstr "More translation"
|
||||
"
|
||||
`
|
||||
|
||||
// Write PO content to file
|
||||
@@ -145,8 +154,8 @@ msgstr "More translation"
|
||||
|
||||
// Test syntax error parsed translations
|
||||
tr = po.Get("This one has invalid syntax translations")
|
||||
if tr != "" {
|
||||
t.Errorf("Expected '' but got '%s'", tr)
|
||||
if tr != "This one has invalid syntax translations" {
|
||||
t.Errorf("Expected 'This one has invalid syntax translations' but got '%s'", tr)
|
||||
}
|
||||
|
||||
tr = po.GetN("This one has invalid syntax translations", "This are tests", 4)
|
||||
@@ -177,6 +186,27 @@ msgstr "More translation"
|
||||
t.Errorf("Expected 'Original' but got '%s'", tr)
|
||||
}
|
||||
|
||||
// Test empty translation strings
|
||||
tr = po.Get("Empty translation")
|
||||
if tr != "Empty translation" {
|
||||
t.Errorf("Expected 'Empty translation' but got '%s'", tr)
|
||||
}
|
||||
|
||||
tr = po.Get("Empty plural form singular")
|
||||
if tr != "Singular translated" {
|
||||
t.Errorf("Expected 'Singular translated' but got '%s'", tr)
|
||||
}
|
||||
|
||||
tr = po.GetN("Empty plural form singular", "Empty plural form", 1)
|
||||
if tr != "Singular translated" {
|
||||
t.Errorf("Expected 'Singular translated' but got '%s'", tr)
|
||||
}
|
||||
|
||||
tr = po.GetN("Empty plural form singular", "Empty plural form", 2)
|
||||
if tr != "Empty plural form" {
|
||||
t.Errorf("Expected 'Empty plural form' but got '%s'", tr)
|
||||
}
|
||||
|
||||
// Test last translation
|
||||
tr = po.Get("More")
|
||||
if tr != "More translation" {
|
||||
|
||||
Reference in New Issue
Block a user