4 Commits

Author SHA1 Message Date
Leonel Quinteros
4b94e83723 Properly handle singular vs plural defaults for untranslated strings. Fixes #9 2017-09-01 13:28:51 -03:00
Leonel Quinteros
756045ab5e Handle empty translation strings as untranslated as defined in https://www.gnu.org/software/gettext/manual/html_node/Untranslated-Entries.html. Fixes #9 2017-08-30 10:53:39 -03:00
Leonel Quinteros
2bb9254f26 Edit badges 2017-07-05 19:06:45 -03:00
Leonel Quinteros
88952938dc Update readme 2017-07-05 19:03:09 -03:00
6 changed files with 181 additions and 40 deletions

View File

@@ -1,5 +1,5 @@
[![GitHub release](https://img.shields.io/github/release/leonelquinteros/gotext.svg)](https://github.com/leonelquinteros/gotext)
[![MIT license](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
[![GitHub version](https://badge.fury.io/gh/leonelquinteros%2Fgotext.svg)](https://badge.fury.io/gh/leonelquinteros%2Fgotext)
[![GoDoc](https://godoc.org/github.com/leonelquinteros/gotext?status.svg)](https://godoc.org/github.com/leonelquinteros/gotext)
[![Build Status](https://travis-ci.org/leonelquinteros/gotext.svg?branch=master)](https://travis-ci.org/leonelquinteros/gotext)
[![codecov](https://codecov.io/gh/leonelquinteros/gotext/branch/master/graph/badge.svg)](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"
}
```

View File

@@ -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"))
}
*/

View File

@@ -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")
}
}

View File

@@ -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
View File

@@ -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...)
}

View File

@@ -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" {