GNU gettext utilities for Go.
en_UK
to en
if the first isn't available.Refer to the Godoc package documentation at (https://godoc.org/github.com/leonelquinteros/gotext)
go get github.com/leonelquinteros/gotext
Stable releases use semantic versioning tagging on this repository.
You can rely on this to use your preferred vendoring tool or to manually retrieve the corresponding release tag from the GitHub repository.
NOTE: v1.5.0 contains a breaking change on how Po
objects are initialised, see (https://github.com/leonelquinteros/gotext/issues/56)
Add github.com/leonelquinteros/gotext
inside the require
section in your go.mod
file.
i.e.
require (
github.com/leonelquinteros/gotext v1.4.0
)
http://gopkg.in/leonelquinteros/gotext.v1
To get the latest v1 package stable release, execute:
go get gopkg.in/leonelquinteros/gotext.v1
Import as
import "gopkg.in/leonelquinteros/gotext.v1"
Refer to it as gotext.
The package will assume a directories structure starting with a base path that will be provided to the package configuration or to object constructors depending on the use, but either will use the same convention to lookup inside the base path.
Inside the base directory where will be the language directories named using the language and country 2-letter codes (en_US, es_AR, ...).
All package functions can lookup after the simplified version for each language in case the full code isn't present but the more general language code exists.
So if the language set is en_UK
, but there is no directory named after that code and there is a directory named en
,
all package functions will be able to resolve this generalization and provide translations for the more general library.
The language codes are assumed to be ISO 639-1 codes (2-letter codes). That said, most functions will work with any coding standard as long the directory name matches the language code set on the configuration.
Then, there can be a LC_MESSAGES
containing all PO files or the PO files themselves.
A library directory structure can look like:
/path/to/locales
/path/to/locales/en_US
/path/to/locales/en_US/LC_MESSAGES
/path/to/locales/en_US/LC_MESSAGES/default.po
/path/to/locales/en_US/LC_MESSAGES/extras.po
/path/to/locales/en_UK
/path/to/locales/en_UK/LC_MESSAGES
/path/to/locales/en_UK/LC_MESSAGES/default.po
/path/to/locales/en_UK/LC_MESSAGES/extras.po
/path/to/locales/en_AU
/path/to/locales/en_AU/LC_MESSAGES
/path/to/locales/en_AU/LC_MESSAGES/default.po
/path/to/locales/en_AU/LC_MESSAGES/extras.po
/path/to/locales/es
/path/to/locales/es/default.po
/path/to/locales/es/extras.po
/path/to/locales/es_ES
/path/to/locales/es_ES/default.po
/path/to/locales/es_ES/extras.po
/path/to/locales/fr
/path/to/locales/fr/default.po
/path/to/locales/fr/extras.po
And so on...
For quick/simple translations you can use the package level functions directly.
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
fmt.Println(gotext.Get("My text on 'domain-name' domain"))
// Translate text from a different domain without reconfigure
fmt.Println(gotext.GetD("domain2", "Another text on a different domain"))
}
All translation strings support dynamic variables to be inserted without translate. Use the fmt.Printf syntax (from Go's "fmt" package) to specify how to print the non-translated variable inside the translation string.
import (
"fmt"
"github.com/leonelquinteros/gotext"
)
func main() {
// Configure package
gotext.Configure("/path/to/locales/root/dir", "en_UK", "domain-name")
// Set variables
name := "John"
// Translate text with variables
fmt.Println(gotext.Get("Hi, my name is %s", name))
}
When having multiple languages/domains/libraries at the same time, you can create Locale objects for each variation so you can handle each settings on their own.
import (
"fmt"
"github.com/leonelquinteros/gotext"
)
func main() {
// Create Locale with library path and language code
l := gotext.NewLocale("/path/to/locales/root/dir", "es_UY")
// Load domain '/path/to/locales/root/dir/es_UY/default.po'
l.AddDomain("default")
// Translate text from default domain
fmt.Println(l.Get("Translate this"))
// Load different domain
l.AddDomain("translations")
// Translate text from domain
fmt.Println(l.GetD("translations", "Translate this"))
}
This is also helpful for using inside templates (from the "text/template" package), where you can pass the Locale object to the template. If you set the Locale object as "Loc" in the template, then the template code would look like:
{{ .Loc.Get "Translate this" }}
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.
import (
"fmt"
"github.com/leonelquinteros/gotext"
)
func main() {
// Set PO content
str := `
msgid "Translate this"
msgstr "Translated text"
msgid "Another string"
msgstr ""
msgid "One with var: %s"
msgstr "This one sets the var: %s"
`
// Create Po object
po := gotext.NewPo()
po.Parse(str)
fmt.Println(po.Get("Translate this"))
}
PO format supports defining one or more plural forms for the same translation. Relying on the PO file headers, a Plural-Forms formula can be set on the translation file as defined in (https://www.gnu.org/savannah-checkouts/gnu/gettext/manual/html_node/Plural-forms.html)
import (
"fmt"
"github.com/leonelquinteros/gotext"
)
func main() {
// Set PO content
str := `
msgid ""
msgstr ""
# Header below
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
msgid "Translate this"
msgstr "Translated text"
msgid "Another string"
msgstr ""
msgid "One with var: %s"
msgid_plural "Several with vars: %s"
msgstr[0] "This one is the singular: %s"
msgstr[1] "This one is the plural: %s"
`
// Create Po object
po := new(gotext.Po)
po.Parse(str)
fmt.Println(po.GetN("One with var: %s", "Several with vars: %s", 54, v))
// "This one is the plural: Variable"
}