Files
gotext/po.go
Leonel Quinteros ed080f71c3 Improved docs
2016-06-24 17:06:33 -03:00

209 lines
4.4 KiB
Go

package gotext
import (
"fmt"
"io/ioutil"
"os"
"strconv"
"strings"
"sync"
)
type translation struct {
id string
pluralId string
trs map[int]string
}
func newTranslation() *translation {
tr := new(translation)
tr.trs = make(map[int]string)
return tr
}
func (t *translation) get() string {
// Look for translation index 0
if _, ok := t.trs[0]; ok {
return t.trs[0]
}
// Return unstranlated id by default
return t.id
}
func (t *translation) getN(n int) string {
// Look for translation index
if _, ok := t.trs[n]; ok {
return t.trs[n]
}
// Return unstranlated plural by default
return t.pluralId
}
/*
Po parses the content of any PO file and provides all the translation functions needed.
Example:
import "github.com/leonelquinteros/gotext"
func main() {
// Create po object
po := new(gotext.Po)
// Parse .po file
po.ParseFile("/path/to/po/file/translations.po")
// Get translation
println(po.Get("Translate this"))
}
*/
type Po struct {
// Storage
translations map[string]*translation
// Sync Mutex
sync.RWMutex
}
// ParseFile tries to read the file by its provided path (f) and parse its content as a .po file.
func (po *Po) ParseFile(f string) {
// Check if file exists
info, err := os.Stat(f)
if err != nil {
return
}
// Check that isn't a directory
if info.IsDir() {
return
}
// Parse file content
data, err := ioutil.ReadFile(f)
if err != nil {
return
}
po.Parse(string(data))
}
// Parse loads the translations specified in the provided string (str)
func (po *Po) Parse(str string) {
if po.translations == nil {
po.Lock()
po.translations = make(map[string]*translation)
po.Unlock()
}
lines := strings.Split(str, "\n")
tr := newTranslation()
for _, l := range lines {
// Trim spaces
l = strings.TrimSpace(l)
// Skip empty lines
if l == "" {
continue
}
// Skip invalid lines
if !strings.HasPrefix(l, "msgid") && !strings.HasPrefix(l, "msgid_plural") && !strings.HasPrefix(l, "msgstr") {
continue
}
// Buffer msgid and continue
if strings.HasPrefix(l, "msgid") && !strings.HasPrefix(l, "msgid_plural") {
// Save current translation buffer.
po.Lock()
po.translations[tr.id] = tr
po.Unlock()
// Flush buffer
tr = newTranslation()
// Set id
tr.id, _ = strconv.Unquote(strings.TrimSpace(strings.TrimPrefix(l, "msgid")))
// Loop
continue
}
// Check for plural form
if strings.HasPrefix(l, "msgid_plural") {
tr.pluralId, _ = strconv.Unquote(strings.TrimSpace(strings.TrimPrefix(l, "msgid_plural")))
// Loop
continue
}
// Save translation
if strings.HasPrefix(l, "msgstr") {
l = strings.TrimSpace(strings.TrimPrefix(l, "msgstr"))
// Check for indexed translation forms
if strings.HasPrefix(l, "[") {
in := strings.Index(l, "]")
if in == -1 {
// Skip wrong index formatting
continue
}
// Parse index
i, err := strconv.Atoi(l[1:in])
if err != nil {
// Skip wrong index formatting
continue
}
// Parse translation string
tr.trs[i], _ = strconv.Unquote(strings.TrimSpace(l[in+1:]))
// Loop
continue
}
// Save single translation form under 0 index
tr.trs[0], _ = strconv.Unquote(l)
}
}
// Save last translation buffer.
if tr.id != "" {
po.Lock()
po.translations[tr.id] = tr
po.Unlock()
}
}
// 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 *Po) Get(str string, vars ...interface{}) string {
if po.translations != nil {
if _, ok := po.translations[str]; ok {
return fmt.Sprintf(po.translations[str].get(), vars...)
}
}
// Return the same we received by default
return fmt.Sprintf(str, vars...)
}
// GetN retrieves the (N)th plural form translation for the given string.
// If n == 0, usually the singular form of the string is returned as defined in the PO file.
// Supports optional parameters (vars... interface{}) to be inserted on the formatted string using the fmt.Printf syntax.
func (po *Po) GetN(str, plural string, n int, vars ...interface{}) string {
if po.translations != nil {
if _, ok := po.translations[str]; ok {
return fmt.Sprintf(po.translations[str].getN(n), vars...)
}
}
// Return the plural string we received by default
return fmt.Sprintf(plural, vars...)
}