gettext

package module
v0.0.0-...-b9a4882 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 20, 2018 License: MIT Imports: 14 Imported by: 0

README

go-gettext

GoDoc Build Status

GNU gettext utilities for Go, forked from https://github.com/leonelquinteros/gotext

WARNING

This repository has been moved to github.com/lestrrat-go/gettext. This repository exists so that libraries pointing to this URL will keep functioning, but this repository will NOT be updated in the future. Please use the new import path.

Features

Features Specific To This Fork

  • Properly reports errors
  • gettext.LocaleSet wrapper to handle multiple languages dynamically

Features From Fork Source

  • Implements GNU gettext support in native Go.
  • Complete support for PO files including:
  • Thread-safe: This package is safe for concurrent use across multiple goroutines.
  • Woorks with UTF-8 encoding as it's the default for Go language.
  • Language codes are automatically simplified from the form en_UK to en if the first isn't available.
  • Ready to use inside Go templates.

License

MIT license

Installation

go get github.com/lestrrat/go-gettext
  • There are no requirements or dependencies to use this package.
  • No need to install GNU gettext utilities (unless specific needs of CLI tools).
  • No need for environment variables. Some naming conventions are applied but not needed.

Locales directories structure

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...

About translation function names

The standard GNU gettext defines helper functions that maps to the gettext() function and it's widely adopted by most implementations.

The basic translation function is usually _() in the form:

_("Translate this")

In Go, this can't be implemented by a reusable package as the function name has to start with a capital letter in order to be exported.

Each implementation of this package can declare this helper functions inside their own packages if this function naming are desired/needed:

package main

import "github.com/lestrrat/go-gettext"

func _(str string, vars ...interface{}) string {
    return gettext.Get(str, vars...)
}

This is valid and can be used within a package.

In normal conditions the Go compiler will optimize the calls to _() by replacing its content in place of the function call to reduce the function calling overhead. This is a normal Go compiler behavior.

Usage examples

Using dynamic variables on translations

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 "github.com/lestrrat/go-gettext"

func main() {
    l := gettext.NewLocale("en_US", 
        WithSource(NewFileSystemSource("/path/to/locales/root/dir")))
    l.AddDomain("domain-name")
    
    // Set variables
    name := "John"
    
    // Translate text with variables
    println(gettext.Get("Hi, my name is %s", name))
}

Using Locale object

import "github.com/lestrrat/go-gettext"

func main() {
    // Create Locale with library path and language code
    l := gettext.NewLocale("es_UY", 
        WithSource(NewFileSystemSource("/path/to/locales/root/dir")))
    
    // Load domain '/path/to/locales/root/dir/es_UY/default.po'
    l.AddDomain("default")
    
    // Translate text from default domain
    println(l.Get("Translate this"))
    
    // Load different domain
    l.AddDomain("translations")
    
    // Translate text from domain
    println(l.GetD("translations", "Translate this"))
}

You may pass the locale object to text/template (or the like) to localize your templates. If you set the Locale object as "Loc" in the template, then the template code would look like:

{{ .Loc.Get "Translate this" }}

Use a different source for .po files

When you want to embed everything in a go binary, including the .po files, you can use the WithSource option.

import "github.com/lestrrat/go-gettext"

func main() {
    // Create Locale with library path and language code, and use
    // the `Asset` function that is generated by asset packers, e.g
    // github.com/lestrrat/go-packasset or github.com/tmthrgd/go-bindata
    l := gettext.NewLocale("es_UY", WithSource(SourceFunc(Asset)))

    // Load domain '/path/to/locales/root/dir/es_UY/default.po'
    l.AddDomain("default")

    // Translate text from default domain
    println(l.Get("Translate this"))

    // Load different domain
    l.AddDomain("translations")

    // Translate text from domain
    println(l.GetD("translations", "Translate this"))
}

Using the Po object to handle .po files and PO-formatted strings

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 "github.com/lestrrat/go-gettext"

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"
`
    po, err := NewParser().ParseString(str)
    if err != nil {
        ...
    }
    
    println(po.Get("Translate this"))
}

Use plural forms of translations

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)

Plural formulas are parsed and evaluated using Anko

import "github.com/lestrrat/go-gettext"

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"
`
    po, err := NewParser().ParseString(str)
    if err != nil {
        ...
    }

    println(po.GetN("One with var: %s", "Several with vars: %s", 54, v))
    // "This one is the plural: Variable"
}

ACKNOWLEDGEMENTS

Documentation

Overview

Package gettext implements GNU gettext utilities.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type FileSystemSource

type FileSystemSource struct {
	// contains filtered or unexported fields
}

func NewFileSystemSource

func NewFileSystemSource(dir string) *FileSystemSource

func (FileSystemSource) ReadFile

func (f FileSystemSource) ReadFile(s string) ([]byte, error)

type Locale

type Locale interface {
	AddDomain(string) error
	Get(string, ...interface{}) string
	GetN(string, string, int, ...interface{}) string
	GetD(string, string, ...interface{}) string
	GetND(string, string, string, int, ...interface{}) string
	GetC(string, string, ...interface{}) string
	GetNC(string, string, int, string, ...interface{}) string
	GetDC(string, string, string, ...interface{}) string
	GetNDC(string, string, string, int, string, ...interface{}) string
}

Locale wraps the entire i18n collection for a single language (locale)

func NewLocale

func NewLocale(l string, options ...Option) Locale

NewLocale creates and initializes a new Locale object for a given language.

Possible options include: * WithSource: specifies where to load the .po files from * WithDefaultDomain: name of the default domain. "default", it not specified

type LocaleSet

type LocaleSet struct {
	// contains filtered or unexported fields
}

LocaleSet is a convenience wrapper around Locale objects. Multiple locales can be stored in this set, and users may dynamically ask for a Locale object for a given locale name.

func NewLocaleSet

func NewLocaleSet() *LocaleSet

func (*LocaleSet) AddDomain

func (s *LocaleSet) AddDomain(domain string) error

func (*LocaleSet) AddLocale

func (s *LocaleSet) AddLocale(l string) error

func (*LocaleSet) GetLocale

func (s *LocaleSet) GetLocale(l string) (Locale, error)

GetLocale returns the Locale corresponding to the ID l (i.e. "en", "ja", etc). If the corresponding locale is not found, an error is returned, and the first return value is set to *NullLocale, which you can use as a default fallback

func (*LocaleSet) Options

func (s *LocaleSet) Options(options ...Option)

Sets the options that are passed to `NewLocale()` when creating a new locale

func (*LocaleSet) SetLocale

func (s *LocaleSet) SetLocale(l string, locale Locale) error

type NullLocale

type NullLocale struct{}

func (NullLocale) AddDomain

func (l NullLocale) AddDomain(_ string) error

func (NullLocale) Get

func (l NullLocale) Get(s string, args ...interface{}) string

func (NullLocale) GetC

func (l NullLocale) GetC(str string, _ string, vars ...interface{}) string

func (NullLocale) GetD

func (l NullLocale) GetD(_ string, str string, vars ...interface{}) string

func (NullLocale) GetDC

func (l NullLocale) GetDC(_ string, str, _ string, vars ...interface{}) string

func (NullLocale) GetN

func (l NullLocale) GetN(str string, _ string, _ int, vars ...interface{}) string

func (NullLocale) GetNC

func (l NullLocale) GetNC(str string, _ string, _ int, _ string, vars ...interface{}) string

func (NullLocale) GetND

func (l NullLocale) GetND(_ string, str string, _ string, _ int, vars ...interface{}) string

func (NullLocale) GetNDC

func (l NullLocale) GetNDC(_ string, str string, _ string, _ int, _ string, vars ...interface{}) string

type Option

type Option interface {
	Name() string
	Value() interface{}
}

func WithDefaultDomain

func WithDefaultDomain(s string) Option

WithDefaultDomain is used in NewLocale() to specify the name of the domain that will be used by the `Get` method

func WithSource

func WithSource(s Source) Option

WithSource is used in NewLocale() to specify where to load the .po files from. By default FileSystemSource will be used.

func WithStrictParsing

func WithStrictParsing(b bool) Option

type Parser

type Parser struct {
	// contains filtered or unexported fields
}

Parser parses .po files and creates new Po objects

func NewParser

func NewParser(options ...Option) *Parser

NewParser creates a new .po parser

func (*Parser) Parse

func (p *Parser) Parse(data []byte) (*Po, error)

func (*Parser) ParseFile

func (p *Parser) ParseFile(f string) (*Po, error)

func (*Parser) ParseString

func (p *Parser) ParseString(s string) (*Po, error)

type Po

type Po struct {
	// contains filtered or unexported fields
}

Po stores content required for translation, and does the grunt work of producing localized strings.

Once created you cannot alter the object. You will have to create a new one yourself.

func (*Po) Get

func (po *Po) Get(str string, vars ...interface{}) string

Get retrieves the corresponding translation for the given string. Supports optional parameters (vars... interface{}) to be inserted on the formatted string using the fmt.Printf syntax.

func (*Po) GetC

func (po *Po) GetC(str, ctx string, vars ...interface{}) string

GetC retrieves the corresponding translation for a given string in the given context. Supports optional parameters (vars... interface{}) to be inserted on the formatted string using the fmt.Printf syntax.

func (*Po) GetN

func (po *Po) GetN(str, plural string, n int, vars ...interface{}) string

GetN retrieves the (N)th plural form of translation for the given string. Supports optional parameters (vars... interface{}) to be inserted on the formatted string using the fmt.Printf syntax.

func (*Po) GetNC

func (po *Po) GetNC(str, plural string, n int, ctx string, vars ...interface{}) string

GetNC retrieves the (N)th plural form of translation for the given string in the given context. Supports optional parameters (vars... interface{}) to be inserted on the formatted string using the fmt.Printf syntax.

type Source

type Source interface {
	ReadFile(string) ([]byte, error)
}

Source is an abstraction over where to get the content of a .po file. By default the FileSystemSource is used, but you may plug this into asset loaders, databases, etc byt providing a very thin wrapper around it.

Because this whole scheme originated from file-based systems, we still need to use file names as key

type SourceFunc

type SourceFunc func(string) ([]byte, error)

func (SourceFunc) ReadFile

func (f SourceFunc) ReadFile(s string) ([]byte, error)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL