Switch to v1.0.2 of github.com/chai2010/gettext-go

Signed-off-by: Davanum Srinivas <davanum@gmail.com>
This commit is contained in:
Davanum Srinivas 2022-06-10 16:07:52 -04:00
parent f3f50b4d7c
commit 1ff96ede74
No known key found for this signature in database
GPG Key ID: 80D83A796103BF59
38 changed files with 1036 additions and 552 deletions

4
go.mod
View File

@ -148,7 +148,7 @@ require (
github.com/beorn7/perks v1.0.1 // indirect
github.com/boltdb/bolt v1.3.1 // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5 // indirect
github.com/chai2010/gettext-go v1.0.2 // indirect
github.com/checkpoint-restore/go-criu/v5 v5.3.0 // indirect
github.com/cilium/ebpf v0.7.0 // indirect
github.com/containerd/cgroups v1.0.1 // indirect
@ -306,7 +306,7 @@ replace (
github.com/census-instrumentation/opencensus-proto => github.com/census-instrumentation/opencensus-proto v0.2.1
github.com/certifi/gocertifi => github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054
github.com/cespare/xxhash/v2 => github.com/cespare/xxhash/v2 v2.1.2
github.com/chai2010/gettext-go => github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5
github.com/chai2010/gettext-go => github.com/chai2010/gettext-go v1.0.2
github.com/checkpoint-restore/go-criu/v5 => github.com/checkpoint-restore/go-criu/v5 v5.3.0
github.com/chzyer/logex => github.com/chzyer/logex v1.1.10
github.com/chzyer/readline => github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e

4
go.sum
View File

@ -76,8 +76,8 @@ github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054 h1:uH66TXeswKn5P
github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA=
github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5 h1:7aWHqerlJ41y6FOsEUvknqgXnGmJyJSbjhAWq5pO4F8=
github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5/go.mod h1:/iP1qXHoty45bqomnu2LM+VVyAEdWN+vtSHGlQgyxbw=
github.com/chai2010/gettext-go v1.0.2 h1:1Lwwip6Q2QGsAdl/ZKPCwTe9fe0CjlUbqj5bFNSjIRk=
github.com/chai2010/gettext-go v1.0.2/go.mod h1:y+wnP2cHYaVj19NZhYKAwEMH2CI1gNHeQQ+5AjwawxA=
github.com/checkpoint-restore/go-criu/v5 v5.3.0 h1:wpFFOoomK3389ue2lAb0Boag6XPht5QYpipxmSNL4d8=
github.com/checkpoint-restore/go-criu/v5 v5.3.0/go.mod h1:E/eQpaFtUKGOOSEBZgmKAcn+zUUwWxqcaKZlF54wK8E=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=

View File

@ -6,7 +6,7 @@ go 1.18
require (
github.com/MakeNowJust/heredoc v1.0.0
github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5
github.com/chai2010/gettext-go v1.0.2
github.com/davecgh/go-spew v1.1.1
github.com/daviddengcn/go-colortext v0.0.0-20160507010035-511bcaf42ccd
github.com/docker/distribution v2.8.1+incompatible

View File

@ -58,8 +58,8 @@ github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:l
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5 h1:7aWHqerlJ41y6FOsEUvknqgXnGmJyJSbjhAWq5pO4F8=
github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5/go.mod h1:/iP1qXHoty45bqomnu2LM+VVyAEdWN+vtSHGlQgyxbw=
github.com/chai2010/gettext-go v1.0.2 h1:1Lwwip6Q2QGsAdl/ZKPCwTe9fe0CjlUbqj5bFNSjIRk=
github.com/chai2010/gettext-go v1.0.2/go.mod h1:y+wnP2cHYaVj19NZhYKAwEMH2CI1gNHeQQ+5AjwawxA=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=

View File

@ -25,7 +25,7 @@ import (
"os"
"strings"
"github.com/chai2010/gettext-go/gettext"
gettext "github.com/chai2010/gettext-go"
"k8s.io/klog/v2"
)

5
vendor/github.com/chai2010/gettext-go/.travis.yml generated vendored Normal file
View File

@ -0,0 +1,5 @@
language: go
go:
- "1.14"
- tip

191
vendor/github.com/chai2010/gettext-go/README.md generated vendored Normal file
View File

@ -0,0 +1,191 @@
- *赞助 BTC: 1Cbd6oGAUUyBi7X7MaR4np4nTmQZXVgkCW*
- *赞助 ETH: 0x623A3C3a72186A6336C79b18Ac1eD36e1c71A8a6*
- *Go语言付费QQ群: 1055927514*
----
# gettext-go: GNU gettext for Go ([Imported By Kubernetes](https://pkg.go.dev/github.com/chai2010/gettext-go@v0.1.0/gettext?tab=importedby))
- PkgDoc: [http://godoc.org/github.com/chai2010/gettext-go](http://godoc.org/github.com/chai2010/gettext-go)
- PkgDoc: [http://pkg.go.dev/github.com/chai2010/gettext-go](http://pkg.go.dev/github.com/chai2010/gettext-go)
## Install
1. `go get github.com/chai2010/gettext-go`
2. `go run hello.go`
The godoc.org or go.dev has more information.
## Examples
```Go
package main
import (
"fmt"
"github.com/chai2010/gettext-go"
)
func main() {
gettext := gettext.New("hello", "./examples/locale").SetLanguage("zh_CN")
fmt.Println(gettext.Gettext("Hello, world!"))
// Output: 你好, 世界!
}
```
```Go
package main
import (
"fmt"
"github.com/chai2010/gettext-go"
)
func main() {
gettext.SetLanguage("zh_CN")
gettext.BindLocale(gettext.New("hello", "locale"))
// gettext.BindLocale("hello", "locale") // from locale dir
// gettext.BindLocale("hello", "locale.zip") // from locale zip file
// gettext.BindLocale("hello", "locale.zip", zipData) // from embedded zip data
// translate source text
fmt.Println(gettext.Gettext("Hello, world!"))
// Output: 你好, 世界!
// if no msgctxt in PO file (only msgid and msgstr),
// specify context as "" by
fmt.Println(gettext.PGettext("", "Hello, world!"))
// Output: 你好, 世界!
// translate resource
fmt.Println(string(gettext.Getdata("poems.txt"))))
// Output: ...
}
```
Go file: [hello.go](https://github.com/chai2010/gettext-go/blob/master/examples/hello.go); PO file: [hello.po](https://github.com/chai2010/gettext-go/blob/master/examples/locale/default/LC_MESSAGES/hello.po);
----
## API Changes (v0.1.0 vs v1.0.0)
### Renamed package path
| v0.1.0 (old) | v1.0.0 (new) |
| ----------------------------------------------- | --------------------------------------- |
| `github.com/chai2010/gettext-go/gettext` | `github.com/chai2010/gettext-go` |
| `github.com/chai2010/gettext-go/gettext/po` | `github.com/chai2010/gettext-go/po` |
| `github.com/chai2010/gettext-go/gettext/mo` | `github.com/chai2010/gettext-go/mo` |
| `github.com/chai2010/gettext-go/gettext/plural` | `github.com/chai2010/gettext-go/plural` |
### Renamed functions
| v0.1.0 (old) | v1.0.0 (new) |
| ---------------------------------- | --------------------------- |
| `gettext-go/gettext.*` | `gettext-go.*` |
| `gettext-go/gettext.DefaultLocal` | `gettext-go.DefaultLanguage`|
| `gettext-go/gettext.BindTextdomain`| `gettext-go.BindLocale` |
| `gettext-go/gettext.Textdomain` | `gettext-go.SetDomain` |
| `gettext-go/gettext.SetLocale` | `gettext-go.SetLanguage` |
| `gettext-go/gettext/po.Load` | `gettext-go/po.LoadFile` |
| `gettext-go/gettext/po.LoadData` | `gettext-go/po.Load` |
| `gettext-go/gettext/mo.Load` | `gettext-go/mo.LoadFile` |
| `gettext-go/gettext/mo.LoadData` | `gettext-go/mo.Load` |
### Use empty string as the default context for `gettext.Gettext`
```go
package main
// v0.1.0
// if the **context** missing, use `callerName(2)` as the context:
// v1.0.0
// if the **context** missing, use empty string as the context:
func main() {
gettext.Gettext("hello")
// v0.1.0 => gettext.PGettext("main.main", "hello")
// v1.0.0 => gettext.PGettext("", "hello")
gettext.DGettext("domain", "hello")
// v0.1.0 => gettext.DPGettext("domain", "main.main", "hello")
// v1.0.0 => gettext.DPGettext("domain", "", "hello")
gettext.NGettext("domain", "hello", "hello2", n)
// v0.1.0 => gettext.PNGettext("domain", "main.main", "hello", "hello2", n)
// v1.0.0 => gettext.PNGettext("domain", "", "hello", "hello2", n)
gettext.DNGettext("domain", "hello", "hello2", n)
// v0.1.0 => gettext.DPNGettext("domain", "main.main", "hello", "hello2", n)
// v1.0.0 => gettext.DPNGettext("domain", "", "hello", "hello2", n)
}
```
### `BindLocale` support `FileSystem` interface
```go
// Use FileSystem:
// BindLocale(New("poedit", "name", OS("path/to/dir"))) // bind "poedit" domain
// BindLocale(New("poedit", "name", OS("path/to.zip"))) // bind "poedit" domain
```
## New API in v1.0.0
`Gettexter` interface:
```go
type Gettexter interface {
FileSystem() FileSystem
GetDomain() string
SetDomain(domain string) Gettexter
GetLanguage() string
SetLanguage(lang string) Gettexter
Gettext(msgid string) string
PGettext(msgctxt, msgid string) string
NGettext(msgid, msgidPlural string, n int) string
PNGettext(msgctxt, msgid, msgidPlural string, n int) string
DGettext(domain, msgid string) string
DPGettext(domain, msgctxt, msgid string) string
DNGettext(domain, msgid, msgidPlural string, n int) string
DPNGettext(domain, msgctxt, msgid, msgidPlural string, n int) string
Getdata(name string) []byte
DGetdata(domain, name string) []byte
}
func New(domain, path string, data ...interface{}) Gettexter
```
`FileSystem` interface:
```go
type FileSystem interface {
LocaleList() []string
LoadMessagesFile(domain, lang, ext string) ([]byte, error)
LoadResourceFile(domain, lang, name string) ([]byte, error)
String() string
}
func NewFS(name string, x interface{}) FileSystem
func OS(root string) FileSystem
func ZipFS(r *zip.Reader, name string) FileSystem
func NilFS(name string) FileSystem
```
----
## BUGS
Please report bugs to <chaishushan@gmail.com>.
Thanks!

View File

@ -7,18 +7,17 @@ Package gettext implements a basic GNU's gettext library.
Example:
import (
"github.com/chai2010/gettext-go/gettext"
"github.com/chai2010/gettext-go"
)
func main() {
gettext.SetLocale("zh_CN")
gettext.Textdomain("hello")
gettext.SetLanguage("zh_CN")
// gettext.BindTextdomain("hello", "local", nil) // from local dir
// gettext.BindTextdomain("hello", "local.zip", nil) // from local zip file
// gettext.BindTextdomain("hello", "local.zip", zipData) // from embedded zip data
// gettext.BindLocale(gettext.New("hello", "locale")) // from locale dir
// gettext.BindLocale(gettext.New("hello", "locale.zip")) // from locale zip file
// gettext.BindLocale(gettext.New("hello", "locale.zip", zipData)) // from embedded zip data
gettext.BindTextdomain("hello", "local", nil)
gettext.BindLocale(gettext.New("hello", "locale"))
// translate source text
fmt.Println(gettext.Gettext("Hello, world!"))
@ -29,28 +28,30 @@ Example:
// Output: ...
}
Translate directory struct("../examples/local.zip"):
Translate directory struct("./examples/locale.zip"):
Root: "path" or "file.zip/zipBaseName"
+-default # local: $(LC_MESSAGES) or $(LANG) or "default"
+-default # locale: $(LC_MESSAGES) or $(LANG) or "default"
| +-LC_MESSAGES # just for `gettext.Gettext`
| | +-hello.mo # $(Root)/$(local)/LC_MESSAGES/$(domain).mo
| | \-hello.po # $(Root)/$(local)/LC_MESSAGES/$(domain).mo
| | +-hello.mo # $(Root)/$(lang)/LC_MESSAGES/$(domain).mo
| | +-hello.po # $(Root)/$(lang)/LC_MESSAGES/$(domain).po
| | \-hello.json # $(Root)/$(lang)/LC_MESSAGES/$(domain).json
| |
| \-LC_RESOURCE # just for `gettext.Getdata`
| +-hello # domain map a dir in resource translate
| +-favicon.ico # $(Root)/$(local)/LC_RESOURCE/$(domain)/$(filename)
| +-favicon.ico # $(Root)/$(lang)/LC_RESOURCE/$(domain)/$(filename)
| \-poems.txt
|
\-zh_CN # simple chinese translate
+-LC_MESSAGES
| +-hello.mo # try "$(domain).mo" first
| \-hello.po # try "$(domain).po" second
| +-hello.po # try "$(domain).po" first
| +-hello.mo # try "$(domain).mo" second
| \-hello.json # try "$(domain).json" third
|
\-LC_RESOURCE
+-hello
+-favicon.ico # try "$(local)/$(domain)/file" first
\-poems.txt # try "default/$(domain)/file" second
+-favicon.ico # $(lang)/$(domain)/favicon.ico
\-poems.txt # $(lang)/$(domain)/poems.txt
See:
http://en.wikipedia.org/wiki/Gettext

84
vendor/github.com/chai2010/gettext-go/fs.go generated vendored Normal file
View File

@ -0,0 +1,84 @@
// Copyright 2013 ChaiShushan <chaishushan{AT}gmail.com>. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package gettext
import (
"archive/zip"
"bytes"
"fmt"
)
type FileSystem interface {
LocaleList() []string
LoadMessagesFile(domain, lang, ext string) ([]byte, error)
LoadResourceFile(domain, lang, name string) ([]byte, error)
String() string
}
func NewFS(name string, x interface{}) FileSystem {
if x == nil {
if name != "" {
return OS(name)
}
return NilFS(name)
}
switch x := x.(type) {
case []byte:
if len(x) == 0 {
return OS(name)
}
if r, err := zip.NewReader(bytes.NewReader(x), int64(len(x))); err == nil {
return ZipFS(r, name)
}
if fs, err := newJson(x, name); err == nil {
return fs
}
case string:
if len(x) == 0 {
return OS(name)
}
if r, err := zip.NewReader(bytes.NewReader([]byte(x)), int64(len(x))); err == nil {
return ZipFS(r, name)
}
if fs, err := newJson([]byte(x), name); err == nil {
return fs
}
case FileSystem:
return x
}
return NilFS(name)
}
func OS(root string) FileSystem {
return newOsFS(root)
}
func ZipFS(r *zip.Reader, name string) FileSystem {
return newZipFS(r, name)
}
func NilFS(name string) FileSystem {
return &nilFS{name}
}
type nilFS struct {
name string
}
func (p *nilFS) LocaleList() []string {
return nil
}
func (p *nilFS) LoadMessagesFile(domain, lang, ext string) ([]byte, error) {
return nil, fmt.Errorf("not found")
}
func (p *nilFS) LoadResourceFile(domain, lang, name string) ([]byte, error) {
return nil, fmt.Errorf("not found")
}
func (p *nilFS) String() string {
return "gettext.nilfs(" + p.name + ")"
}

66
vendor/github.com/chai2010/gettext-go/fs_json.go generated vendored Normal file
View File

@ -0,0 +1,66 @@
// Copyright 2020 ChaiShushan <chaishushan{AT}gmail.com>. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package gettext
import (
"encoding/json"
"fmt"
"sort"
)
type jsonFS struct {
name string
x map[string]struct {
LC_MESSAGES map[string][]struct {
MsgContext string `json:"msgctxt"` // msgctxt context
MsgId string `json:"msgid"` // msgid untranslated-string
MsgIdPlural string `json:"msgid_plural"` // msgid_plural untranslated-string-plural
MsgStr []string `json:"msgstr"` // msgstr translated-string
}
LC_RESOURCE map[string]map[string]string
}
}
func isJsonData() bool {
return false
}
func newJson(jsonData []byte, name string) (*jsonFS, error) {
p := &jsonFS{name: name}
if err := json.Unmarshal(jsonData, &p.x); err != nil {
return nil, err
}
return p, nil
}
func (p *jsonFS) LocaleList() []string {
var ss []string
for lang := range p.x {
ss = append(ss, lang)
}
sort.Strings(ss)
return ss
}
func (p *jsonFS) LoadMessagesFile(domain, lang, ext string) ([]byte, error) {
if v, ok := p.x[lang]; ok {
if v, ok := v.LC_MESSAGES[domain+ext]; ok {
return json.Marshal(v)
}
}
return nil, fmt.Errorf("not found")
}
func (p *jsonFS) LoadResourceFile(domain, lang, name string) ([]byte, error) {
if v, ok := p.x[lang]; ok {
if v, ok := v.LC_RESOURCE[domain]; ok {
return []byte(v[name]), nil
}
}
return nil, fmt.Errorf("not found")
}
func (p *jsonFS) String() string {
return "gettext.nilfs(" + p.name + ")"
}

91
vendor/github.com/chai2010/gettext-go/fs_os.go generated vendored Normal file
View File

@ -0,0 +1,91 @@
// Copyright 2013 ChaiShushan <chaishushan{AT}gmail.com>. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package gettext
import (
"archive/zip"
"bytes"
"fmt"
"io/ioutil"
"os"
"sort"
"strings"
)
type osFS struct {
root string
}
func newOsFS(root string) FileSystem {
// locale zip file
if fi, err := os.Stat(root); err == nil && !fi.IsDir() {
if strings.HasSuffix(strings.ToLower(root), ".zip") {
if x, err := ioutil.ReadFile(root); err == nil {
if r, err := zip.NewReader(bytes.NewReader(x), int64(len(x))); err == nil {
return ZipFS(r, root)
}
}
}
if strings.HasSuffix(strings.ToLower(root), ".json") {
if x, err := ioutil.ReadFile(root); err == nil {
if fs, err := newJson(x, root); err == nil {
return fs
}
}
}
}
// locale dir
return &osFS{root: root}
}
func (p *osFS) LocaleList() []string {
list, err := ioutil.ReadDir(p.root)
if err != nil {
return nil
}
ssMap := make(map[string]bool)
for _, dir := range list {
if dir.IsDir() {
ssMap[dir.Name()] = true
}
}
var locales = make([]string, 0, len(ssMap))
for s := range ssMap {
locales = append(locales, s)
}
sort.Strings(locales)
return locales
}
func (p *osFS) LoadMessagesFile(domain, locale, ext string) ([]byte, error) {
trName := p.makeMessagesFileName(domain, locale, ext)
rcData, err := ioutil.ReadFile(trName)
if err != nil {
return nil, err
}
return rcData, nil
}
func (p *osFS) LoadResourceFile(domain, locale, name string) ([]byte, error) {
rcName := p.makeResourceFileName(domain, locale, name)
rcData, err := ioutil.ReadFile(rcName)
if err != nil {
return nil, err
}
return rcData, nil
}
func (p *osFS) String() string {
return "gettext.localfs(" + p.root + ")"
}
func (p *osFS) makeMessagesFileName(domain, lang, ext string) string {
return fmt.Sprintf("%s/%s/LC_MESSAGES/%s%s", p.root, lang, domain, ext)
}
func (p *osFS) makeResourceFileName(domain, lang, name string) string {
return fmt.Sprintf("%s/%s/LC_RESOURCE/%s/%s", p.root, lang, domain, name)
}

142
vendor/github.com/chai2010/gettext-go/fs_zip.go generated vendored Normal file
View File

@ -0,0 +1,142 @@
// Copyright 2013 ChaiShushan <chaishushan{AT}gmail.com>. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package gettext
import (
"archive/zip"
"fmt"
"io/ioutil"
"sort"
"strings"
)
type zipFS struct {
root string
name string
r *zip.Reader
}
func newZipFS(r *zip.Reader, name string) *zipFS {
fs := &zipFS{r: r, name: name}
fs.root = fs.zipRoot()
return fs
}
func (p *zipFS) zipName() string {
name := p.name
if x := strings.LastIndexAny(name, `\/`); x != -1 {
name = name[x+1:]
}
name = strings.TrimSuffix(name, ".zip")
return name
}
func (p *zipFS) zipRoot() string {
var somepath string
for _, f := range p.r.File {
if x := strings.Index(f.Name, "LC_MESSAGES"); x != -1 {
somepath = f.Name
}
if x := strings.Index(f.Name, "LC_RESOURCE"); x != -1 {
somepath = f.Name
}
}
if somepath == "" {
return p.zipName()
}
ss := strings.Split(somepath, "/")
for i, s := range ss {
// $(root)/$(lang)/LC_MESSAGES
// $(root)/$(lang)/LC_RESOURCE
if (s == "LC_MESSAGES" || s == "LC_RESOURCE") && i >= 2 {
return strings.Join(ss[:i-1], "/")
}
}
return p.zipName()
}
func (p *zipFS) LocaleList() []string {
var locals []string
for s := range p.lsZip(p.r) {
locals = append(locals, s)
}
sort.Strings(locals)
return locals
}
func (p *zipFS) LoadMessagesFile(domain, lang, ext string) ([]byte, error) {
trName := p.makeMessagesFileName(domain, lang, ext)
for _, f := range p.r.File {
if f.Name != trName {
continue
}
rc, err := f.Open()
if err != nil {
return nil, err
}
rcData, err := ioutil.ReadAll(rc)
rc.Close()
return rcData, err
}
return nil, fmt.Errorf("not found")
}
func (p *zipFS) LoadResourceFile(domain, lang, name string) ([]byte, error) {
rcName := p.makeResourceFileName(domain, lang, name)
for _, f := range p.r.File {
if f.Name != rcName {
continue
}
rc, err := f.Open()
if err != nil {
return nil, err
}
rcData, err := ioutil.ReadAll(rc)
rc.Close()
return rcData, err
}
return nil, fmt.Errorf("not found")
}
func (p *zipFS) String() string {
return "gettext.zipfs(" + p.name + ")"
}
func (p *zipFS) makeMessagesFileName(domain, lang, ext string) string {
return fmt.Sprintf("%s/%s/LC_MESSAGES/%s%s", p.root, lang, domain, ext)
}
func (p *zipFS) makeResourceFileName(domain, lang, name string) string {
return fmt.Sprintf("%s/%s/LC_RESOURCE/%s/%s", p.root, lang, domain, name)
}
func (p *zipFS) lsZip(r *zip.Reader) map[string]bool {
ssMap := make(map[string]bool)
for _, f := range r.File {
if x := strings.Index(f.Name, "LC_MESSAGES"); x != -1 {
s := strings.TrimRight(f.Name[:x], `\/`)
if x = strings.LastIndexAny(s, `\/`); x != -1 {
s = s[x+1:]
}
if s != "" {
ssMap[s] = true
}
continue
}
if x := strings.Index(f.Name, "LC_RESOURCE"); x != -1 {
s := strings.TrimRight(f.Name[:x], `\/`)
if x = strings.LastIndexAny(s, `\/`); x != -1 {
s = s[x+1:]
}
if s != "" {
ssMap[s] = true
}
continue
}
}
return ssMap
}

View File

@ -5,57 +5,91 @@
package gettext
var (
defaultManager = newDomainManager()
DefaultLanguage string = getDefaultLanguage() // use $(LC_MESSAGES) or $(LANG) or "default"
)
var (
DefaultLocale = getDefaultLocale() // use $(LC_MESSAGES) or $(LANG) or "default"
)
type Gettexter interface {
FileSystem() FileSystem
// SetLocale sets and queries the program's current locale.
GetDomain() string
SetDomain(domain string) Gettexter
GetLanguage() string
SetLanguage(lang string) Gettexter
Gettext(msgid string) string
PGettext(msgctxt, msgid string) string
NGettext(msgid, msgidPlural string, n int) string
PNGettext(msgctxt, msgid, msgidPlural string, n int) string
DGettext(domain, msgid string) string
DPGettext(domain, msgctxt, msgid string) string
DNGettext(domain, msgid, msgidPlural string, n int) string
DPNGettext(domain, msgctxt, msgid, msgidPlural string, n int) string
Getdata(name string) []byte
DGetdata(domain, name string) []byte
}
// New create Interface use default language.
func New(domain, path string, data ...interface{}) Gettexter {
return newLocale(domain, path, data...)
}
var defaultGettexter struct {
lang string
domain string
Gettexter
}
func init() {
defaultGettexter.lang = getDefaultLanguage()
defaultGettexter.domain = "default"
defaultGettexter.Gettexter = newLocale("", "")
}
// BindLocale sets and queries program's domains.
//
// If the locale is not empty string, set the new local.
// Examples:
// BindLocale(New("poedit", "locale")) // bind "poedit" domain
//
// If the locale is empty string, don't change anything.
// Use zip file:
// BindLocale(New("poedit", "locale.zip")) // bind "poedit" domain
// BindLocale(New("poedit", "locale.zip", zipData)) // bind "poedit" domain
//
// Use FileSystem:
// BindLocale(New("poedit", "name", OS("path/to/dir"))) // bind "poedit" domain
// BindLocale(New("poedit", "name", OS("path/to.zip"))) // bind "poedit" domain
//
func BindLocale(g Gettexter) {
if g != nil {
defaultGettexter.Gettexter = g
defaultGettexter.SetLanguage(defaultGettexter.lang)
} else {
defaultGettexter.Gettexter = newLocale("", "")
defaultGettexter.SetLanguage(defaultGettexter.lang)
}
}
// SetLanguage sets and queries the program's current lang.
//
// If the lang is not empty string, set the new locale.
//
// If the lang is empty string, don't change anything.
//
// Returns is the current locale.
//
// Examples:
// SetLocale("") // get locale: return DefaultLocale
// SetLocale("zh_CN") // set locale: return zh_CN
// SetLocale("") // get locale: return zh_CN
func SetLocale(locale string) string {
return defaultManager.SetLocale(locale)
// SetLanguage("") // get locale: return DefaultLocale
// SetLanguage("zh_CN") // set locale: return zh_CN
// SetLanguage("") // get locale: return zh_CN
func SetLanguage(lang string) string {
defaultGettexter.SetLanguage(lang)
return defaultGettexter.GetLanguage()
}
// BindTextdomain sets and queries program's domains.
//
// If the domain and path are all not empty string, bind the new domain.
// If the domain already exists, return error.
//
// If the domain is not empty string, but the path is the empty string,
// delete the domain.
// If the domain don't exists, return error.
//
// If the domain and the path are all empty string, don't change anything.
//
// Returns is the all bind domains.
//
// Examples:
// BindTextdomain("poedit", "local", nil) // bind "poedit" domain
// BindTextdomain("", "", nil) // return all domains
// BindTextdomain("poedit", "", nil) // delete "poedit" domain
// BindTextdomain("", "", nil) // return all domains
//
// Use zip file:
// BindTextdomain("poedit", "local.zip", nil) // bind "poedit" domain
// BindTextdomain("poedit", "local.zip", zipData) // bind "poedit" domain
//
func BindTextdomain(domain, path string, zipData []byte) (domains, paths []string) {
return defaultManager.Bind(domain, path, zipData)
}
// Textdomain sets and retrieves the current message domain.
// SetDomain sets and retrieves the current message domain.
//
// If the domain is not empty string, set the new domains.
//
@ -64,10 +98,11 @@ func BindTextdomain(domain, path string, zipData []byte) (domains, paths []strin
// Returns is the all used domains.
//
// Examples:
// Textdomain("poedit") // set domain: poedit
// Textdomain("") // get domain: return poedit
func Textdomain(domain string) string {
return defaultManager.SetDomain(domain)
// SetDomain("poedit") // set domain: poedit
// SetDomain("") // get domain: return poedit
func SetDomain(domain string) string {
defaultGettexter.SetDomain(domain)
return defaultGettexter.GetDomain()
}
// Gettext attempt to translate a text string into the user's native language,
@ -77,10 +112,10 @@ func Textdomain(domain string) string {
//
// Examples:
// func Foo() {
// msg := gettext.Gettext("Hello") // msgctxt is "some/package/name.Foo"
// msg := gettext.Gettext("Hello") // msgctxt is ""
// }
func Gettext(msgid string) string {
return PGettext(callerName(2), msgid)
return defaultGettexter.Gettext(msgid)
}
// Getdata attempt to translate a resource file into the user's native language,
@ -89,11 +124,11 @@ func Gettext(msgid string) string {
// Examples:
// func Foo() {
// Textdomain("hello")
// BindTextdomain("hello", "local.zip", nilOrZipData)
// BindLocale("hello", "locale.zip", nilOrZipData)
// poems := gettext.Getdata("poems.txt")
// }
func Getdata(name string) []byte {
return defaultManager.Getdata(name)
return defaultGettexter.Getdata(name)
}
// NGettext attempt to translate a text string into the user's native language,
@ -107,7 +142,7 @@ func Getdata(name string) []byte {
// msg := gettext.NGettext("%d people", "%d peoples", 2)
// }
func NGettext(msgid, msgidPlural string, n int) string {
return PNGettext(callerName(2), msgid, msgidPlural, n)
return defaultGettexter.NGettext(msgid, msgidPlural, n)
}
// PGettext attempt to translate a text string into the user's native language,
@ -118,7 +153,7 @@ func NGettext(msgid, msgidPlural string, n int) string {
// msg := gettext.PGettext("gettext-go.example", "Hello") // msgctxt is "gettext-go.example"
// }
func PGettext(msgctxt, msgid string) string {
return PNGettext(msgctxt, msgid, "", 0)
return defaultGettexter.PGettext(msgctxt, msgid)
}
// PNGettext attempt to translate a text string into the user's native language,
@ -130,7 +165,7 @@ func PGettext(msgctxt, msgid string) string {
// msg := gettext.PNGettext("gettext-go.example", "%d people", "%d peoples", 2)
// }
func PNGettext(msgctxt, msgid, msgidPlural string, n int) string {
return defaultManager.PNGettext(msgctxt, msgid, msgidPlural, n)
return defaultGettexter.PNGettext(msgctxt, msgid, msgidPlural, n)
}
// DGettext like Gettext(), but looking up the message in the specified domain.
@ -140,7 +175,7 @@ func PNGettext(msgctxt, msgid, msgidPlural string, n int) string {
// msg := gettext.DGettext("poedit", "Hello")
// }
func DGettext(domain, msgid string) string {
return DPGettext(domain, callerName(2), msgid)
return defaultGettexter.DGettext(domain, msgid)
}
// DNGettext like NGettext(), but looking up the message in the specified domain.
@ -150,7 +185,7 @@ func DGettext(domain, msgid string) string {
// msg := gettext.PNGettext("poedit", "gettext-go.example", "%d people", "%d peoples", 2)
// }
func DNGettext(domain, msgid, msgidPlural string, n int) string {
return DPNGettext(domain, callerName(2), msgid, msgidPlural, n)
return defaultGettexter.DNGettext(domain, msgid, msgidPlural, n)
}
// DPGettext like PGettext(), but looking up the message in the specified domain.
@ -160,7 +195,7 @@ func DNGettext(domain, msgid, msgidPlural string, n int) string {
// msg := gettext.DPGettext("poedit", "gettext-go.example", "Hello")
// }
func DPGettext(domain, msgctxt, msgid string) string {
return DPNGettext(domain, msgctxt, msgid, "", 0)
return defaultGettexter.DPGettext(domain, msgctxt, msgid)
}
// DPNGettext like PNGettext(), but looking up the message in the specified domain.
@ -170,7 +205,7 @@ func DPGettext(domain, msgctxt, msgid string) string {
// msg := gettext.DPNGettext("poedit", "gettext-go.example", "%d people", "%d peoples", 2)
// }
func DPNGettext(domain, msgctxt, msgid, msgidPlural string, n int) string {
return defaultManager.DPNGettext(domain, msgctxt, msgid, msgidPlural, n)
return defaultGettexter.DPNGettext(domain, msgctxt, msgid, msgidPlural, n)
}
// DGetdata like Getdata(), but looking up the resource in the specified domain.
@ -180,5 +215,5 @@ func DPNGettext(domain, msgctxt, msgid, msgidPlural string, n int) string {
// msg := gettext.DGetdata("hello", "poems.txt")
// }
func DGetdata(domain, name string) []byte {
return defaultManager.DGetdata(domain, name)
return defaultGettexter.DGetdata(domain, name)
}

View File

@ -1,39 +0,0 @@
// Copyright 2013 ChaiShushan <chaishushan{AT}gmail.com>. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package gettext
import (
"regexp"
"runtime"
)
var (
reInit = regexp.MustCompile(`init·\d+$`) // main.init·1
reClosure = regexp.MustCompile(`func·\d+$`) // main.func·001
)
// caller types:
// runtime.goexit
// runtime.main
// main.init
// main.main
// main.init·1 -> main.init
// main.func·001 -> main.func
// code.google.com/p/gettext-go/gettext.TestCallerName
// ...
func callerName(skip int) string {
pc, _, _, ok := runtime.Caller(skip)
if !ok {
return ""
}
name := runtime.FuncForPC(pc).Name()
if reInit.MatchString(name) {
return reInit.ReplaceAllString(name, "init")
}
if reClosure.MatchString(name) {
return reClosure.ReplaceAllString(name, "func")
}
return name
}

View File

@ -1,119 +0,0 @@
// Copyright 2013 ChaiShushan <chaishushan{AT}gmail.com>. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package gettext
import (
"sync"
)
type domainManager struct {
mutex sync.Mutex
locale string
domain string
domainMap map[string]*fileSystem
trTextMap map[string]*translator
}
func newDomainManager() *domainManager {
return &domainManager{
locale: DefaultLocale,
domainMap: make(map[string]*fileSystem),
trTextMap: make(map[string]*translator),
}
}
func (p *domainManager) makeTrMapKey(domain, locale string) string {
return domain + "_$$$_" + locale
}
func (p *domainManager) Bind(domain, path string, data []byte) (domains, paths []string) {
p.mutex.Lock()
defer p.mutex.Unlock()
switch {
case domain != "" && path != "": // bind new domain
p.bindDomainTranslators(domain, path, data)
case domain != "" && path == "": // delete domain
p.deleteDomain(domain)
}
// return all bind domain
for k, fs := range p.domainMap {
domains = append(domains, k)
paths = append(paths, fs.FsName)
}
return
}
func (p *domainManager) SetLocale(locale string) string {
p.mutex.Lock()
defer p.mutex.Unlock()
if locale != "" {
p.locale = locale
}
return p.locale
}
func (p *domainManager) SetDomain(domain string) string {
p.mutex.Lock()
defer p.mutex.Unlock()
if domain != "" {
p.domain = domain
}
return p.domain
}
func (p *domainManager) Getdata(name string) []byte {
return p.getdata(p.domain, name)
}
func (p *domainManager) DGetdata(domain, name string) []byte {
return p.getdata(domain, name)
}
func (p *domainManager) PNGettext(msgctxt, msgid, msgidPlural string, n int) string {
p.mutex.Lock()
defer p.mutex.Unlock()
return p.gettext(p.domain, msgctxt, msgid, msgidPlural, n)
}
func (p *domainManager) DPNGettext(domain, msgctxt, msgid, msgidPlural string, n int) string {
p.mutex.Lock()
defer p.mutex.Unlock()
return p.gettext(domain, msgctxt, msgid, msgidPlural, n)
}
func (p *domainManager) gettext(domain, msgctxt, msgid, msgidPlural string, n int) string {
if p.locale == "" || p.domain == "" {
return msgid
}
if _, ok := p.domainMap[domain]; !ok {
return msgid
}
if f, ok := p.trTextMap[p.makeTrMapKey(domain, p.locale)]; ok {
return f.PNGettext(msgctxt, msgid, msgidPlural, n)
}
return msgid
}
func (p *domainManager) getdata(domain, name string) []byte {
if p.locale == "" || p.domain == "" {
return nil
}
if _, ok := p.domainMap[domain]; !ok {
return nil
}
if fs, ok := p.domainMap[domain]; ok {
if data, err := fs.LoadResourceFile(domain, p.locale, name); err == nil {
return data
}
if p.locale != "default" {
if data, err := fs.LoadResourceFile(domain, "default", name); err == nil {
return data
}
}
}
return nil
}

View File

@ -1,50 +0,0 @@
// Copyright 2013 ChaiShushan <chaishushan{AT}gmail.com>. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package gettext
import (
"fmt"
"strings"
)
func (p *domainManager) bindDomainTranslators(domain, path string, data []byte) {
if _, ok := p.domainMap[domain]; ok {
p.deleteDomain(domain) // delete old domain
}
fs := newFileSystem(path, data)
for locale, _ := range fs.LocaleMap {
trMapKey := p.makeTrMapKey(domain, locale)
if data, err := fs.LoadMessagesFile(domain, locale, ".mo"); err == nil {
p.trTextMap[trMapKey], _ = newMoTranslator(
fmt.Sprintf("%s_%s.mo", domain, locale),
data,
)
continue
}
if data, err := fs.LoadMessagesFile(domain, locale, ".po"); err == nil {
p.trTextMap[trMapKey], _ = newPoTranslator(
fmt.Sprintf("%s_%s.po", domain, locale),
data,
)
continue
}
p.trTextMap[p.makeTrMapKey(domain, locale)] = nilTranslator
}
p.domainMap[domain] = fs
}
func (p *domainManager) deleteDomain(domain string) {
if _, ok := p.domainMap[domain]; !ok {
return
}
// delete all mo files
trMapKeyPrefix := p.makeTrMapKey(domain, "")
for k, _ := range p.trTextMap {
if strings.HasPrefix(k, trMapKeyPrefix) {
delete(p.trTextMap, k)
}
}
delete(p.domainMap, domain)
}

View File

@ -1,187 +0,0 @@
// Copyright 2013 ChaiShushan <chaishushan{AT}gmail.com>. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package gettext
import (
"archive/zip"
"bytes"
"fmt"
"io/ioutil"
"log"
"os"
"strings"
)
type fileSystem struct {
FsName string
FsRoot string
FsZipData []byte
LocaleMap map[string]bool
}
func newFileSystem(path string, data []byte) *fileSystem {
fs := &fileSystem{
FsName: path,
FsZipData: data,
}
if err := fs.init(); err != nil {
log.Printf("gettext-go: invalid domain, err = %v", err)
}
return fs
}
func (p *fileSystem) init() error {
zipName := func(name string) string {
if x := strings.LastIndexAny(name, `\/`); x != -1 {
name = name[x+1:]
}
name = strings.TrimSuffix(name, ".zip")
return name
}
// zip data
if len(p.FsZipData) != 0 {
p.FsRoot = zipName(p.FsName)
p.LocaleMap = p.lsZip(p.FsZipData)
return nil
}
// local dir or zip file
fi, err := os.Stat(p.FsName)
if err != nil {
return err
}
// local dir
if fi.IsDir() {
p.FsRoot = p.FsName
p.LocaleMap = p.lsDir(p.FsName)
return nil
}
// local zip file
p.FsZipData, err = ioutil.ReadFile(p.FsName)
if err != nil {
return err
}
p.FsRoot = zipName(p.FsName)
p.LocaleMap = p.lsZip(p.FsZipData)
return nil
}
func (p *fileSystem) LoadMessagesFile(domain, local, ext string) ([]byte, error) {
if len(p.FsZipData) == 0 {
trName := p.makeMessagesFileName(domain, local, ext)
rcData, err := ioutil.ReadFile(trName)
if err != nil {
return nil, err
}
return rcData, nil
} else {
r, err := zip.NewReader(bytes.NewReader(p.FsZipData), int64(len(p.FsZipData)))
if err != nil {
return nil, err
}
trName := p.makeMessagesFileName(domain, local, ext)
for _, f := range r.File {
if f.Name != trName {
continue
}
rc, err := f.Open()
if err != nil {
return nil, err
}
rcData, err := ioutil.ReadAll(rc)
rc.Close()
return rcData, err
}
return nil, fmt.Errorf("not found")
}
}
func (p *fileSystem) LoadResourceFile(domain, local, name string) ([]byte, error) {
if len(p.FsZipData) == 0 {
rcName := p.makeResourceFileName(domain, local, name)
rcData, err := ioutil.ReadFile(rcName)
if err != nil {
return nil, err
}
return rcData, nil
} else {
r, err := zip.NewReader(bytes.NewReader(p.FsZipData), int64(len(p.FsZipData)))
if err != nil {
return nil, err
}
rcName := p.makeResourceFileName(domain, local, name)
for _, f := range r.File {
if f.Name != rcName {
continue
}
rc, err := f.Open()
if err != nil {
return nil, err
}
rcData, err := ioutil.ReadAll(rc)
rc.Close()
return rcData, err
}
return nil, fmt.Errorf("not found")
}
}
func (p *fileSystem) makeMessagesFileName(domain, local, ext string) string {
return fmt.Sprintf("%s/%s/LC_MESSAGES/%s%s", p.FsRoot, local, domain, ext)
}
func (p *fileSystem) makeResourceFileName(domain, local, name string) string {
return fmt.Sprintf("%s/%s/LC_RESOURCE/%s/%s", p.FsRoot, local, domain, name)
}
func (p *fileSystem) lsZip(data []byte) map[string]bool {
r, err := zip.NewReader(bytes.NewReader(data), int64(len(data)))
if err != nil {
return nil
}
ssMap := make(map[string]bool)
for _, f := range r.File {
if x := strings.Index(f.Name, "LC_MESSAGES"); x != -1 {
s := strings.TrimRight(f.Name[:x], `\/`)
if x = strings.LastIndexAny(s, `\/`); x != -1 {
s = s[x+1:]
}
if s != "" {
ssMap[s] = true
}
continue
}
if x := strings.Index(f.Name, "LC_RESOURCE"); x != -1 {
s := strings.TrimRight(f.Name[:x], `\/`)
if x = strings.LastIndexAny(s, `\/`); x != -1 {
s = s[x+1:]
}
if s != "" {
ssMap[s] = true
}
continue
}
}
return ssMap
}
func (p *fileSystem) lsDir(path string) map[string]bool {
list, err := ioutil.ReadDir(path)
if err != nil {
return nil
}
ssMap := make(map[string]bool)
for _, dir := range list {
if dir.IsDir() {
ssMap[dir.Name()] = true
}
}
return ssMap
}

205
vendor/github.com/chai2010/gettext-go/locale.go generated vendored Normal file
View File

@ -0,0 +1,205 @@
// Copyright 2020 ChaiShushan <chaishushan{AT}gmail.com>. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package gettext
import (
"fmt"
"sync"
)
type _Locale struct {
mutex sync.Mutex
fs FileSystem
lang string
domain string
trMap map[string]*translator
trCurrent *translator
}
var _ Gettexter = (*_Locale)(nil)
func newLocale(domain, path string, data ...interface{}) *_Locale {
if domain == "" {
domain = "default"
}
p := &_Locale{
lang: DefaultLanguage,
domain: domain,
}
if len(data) > 0 {
p.fs = NewFS(path, data[0])
} else {
p.fs = NewFS(path, nil)
}
p.syncTrMap()
return p
}
func (p *_Locale) makeTrMapKey(domain, _Locale string) string {
return domain + "_$$$_" + _Locale
}
func (p *_Locale) FileSystem() FileSystem {
return p.fs
}
func (p *_Locale) GetLanguage() string {
p.mutex.Lock()
defer p.mutex.Unlock()
return p.lang
}
func (p *_Locale) SetLanguage(lang string) Gettexter {
p.mutex.Lock()
defer p.mutex.Unlock()
if lang == "" {
lang = DefaultLanguage
}
if lang == p.lang {
return p
}
p.lang = lang
p.syncTrMap()
return p
}
func (p *_Locale) GetDomain() string {
p.mutex.Lock()
defer p.mutex.Unlock()
return p.domain
}
func (p *_Locale) SetDomain(domain string) Gettexter {
p.mutex.Lock()
defer p.mutex.Unlock()
if domain == "" || domain == p.domain {
return p
}
p.domain = domain
p.syncTrMap()
return p
}
func (p *_Locale) syncTrMap() {
p.trMap = make(map[string]*translator)
trMapKey := p.makeTrMapKey(p.domain, p.lang)
if tr, ok := p.trMap[trMapKey]; ok {
p.trCurrent = tr
return
}
// try load po file
if data, err := p.fs.LoadMessagesFile(p.domain, p.lang, ".po"); err == nil {
if tr, err := newPoTranslator(fmt.Sprintf("%s_%s.po", p.domain, p.lang), data); err == nil {
p.trMap[trMapKey] = tr
p.trCurrent = tr
return
}
}
// try load mo file
if data, err := p.fs.LoadMessagesFile(p.domain, p.lang, ".mo"); err == nil {
if tr, err := newMoTranslator(fmt.Sprintf("%s_%s.mo", p.domain, p.lang), data); err == nil {
p.trMap[trMapKey] = tr
p.trCurrent = tr
return
}
}
// try load json file
if data, err := p.fs.LoadMessagesFile(p.domain, p.lang, ".json"); err == nil {
if tr, err := newJsonTranslator(p.lang, fmt.Sprintf("%s_%s.json", p.domain, p.lang), data); err == nil {
p.trMap[trMapKey] = tr
p.trCurrent = tr
return
}
}
// no po/mo file
p.trMap[trMapKey] = nilTranslator
p.trCurrent = nilTranslator
return
}
func (p *_Locale) Gettext(msgid string) string {
p.mutex.Lock()
defer p.mutex.Unlock()
return p.trCurrent.PGettext("", msgid)
}
func (p *_Locale) PGettext(msgctxt, msgid string) string {
p.mutex.Lock()
defer p.mutex.Unlock()
return p.trCurrent.PGettext(msgctxt, msgid)
}
func (p *_Locale) NGettext(msgid, msgidPlural string, n int) string {
p.mutex.Lock()
defer p.mutex.Unlock()
return p.trCurrent.PNGettext("", msgid, msgidPlural, n)
}
func (p *_Locale) PNGettext(msgctxt, msgid, msgidPlural string, n int) string {
p.mutex.Lock()
defer p.mutex.Unlock()
return p.trCurrent.PNGettext(msgctxt, msgid, msgidPlural, n)
}
func (p *_Locale) DGettext(domain, msgid string) string {
p.mutex.Lock()
defer p.mutex.Unlock()
return p.gettext(domain, "", msgid, "", 0)
}
func (p *_Locale) DNGettext(domain, msgid, msgidPlural string, n int) string {
p.mutex.Lock()
defer p.mutex.Unlock()
return p.gettext(domain, "", msgid, msgidPlural, n)
}
func (p *_Locale) DPGettext(domain, msgctxt, msgid string) string {
p.mutex.Lock()
defer p.mutex.Unlock()
return p.gettext(domain, msgctxt, msgid, "", 0)
}
func (p *_Locale) DPNGettext(domain, msgctxt, msgid, msgidPlural string, n int) string {
p.mutex.Lock()
defer p.mutex.Unlock()
return p.gettext(domain, msgctxt, msgid, msgidPlural, n)
}
func (p *_Locale) Getdata(name string) []byte {
return p.getdata(p.domain, name)
}
func (p *_Locale) DGetdata(domain, name string) []byte {
return p.getdata(domain, name)
}
func (p *_Locale) gettext(domain, msgctxt, msgid, msgidPlural string, n int) string {
if f, ok := p.trMap[p.makeTrMapKey(domain, p.lang)]; ok {
return f.PNGettext(msgctxt, msgid, msgidPlural, n)
}
return msgid
}
func (p *_Locale) getdata(domain, name string) []byte {
if data, err := p.fs.LoadResourceFile(domain, p.lang, name); err == nil {
return data
}
if p.lang != "default" {
if data, err := p.fs.LoadResourceFile(domain, "default", name); err == nil {
return data
}
}
return nil
}

View File

@ -7,11 +7,11 @@ Package mo provides support for reading and writing GNU MO file.
Examples:
import (
"github.com/chai2010/gettext-go/gettext/mo"
"github.com/chai2010/gettext-go/mo"
)
func main() {
moFile, err := mo.Load("test.mo")
moFile, err := mo.LoadFile("test.mo")
if err != nil {
log.Fatal(err)
}

View File

@ -48,7 +48,9 @@ func encodeData(hdr *moHeader, f *File) []byte {
}
msgList = append(msgList, v)
}
sort.Sort(byMessages(msgList))
sort.Slice(msgList, func(i, j int) bool {
return msgList[i].less(&msgList[j])
})
var buf bytes.Buffer
var msgIdPosList = make([]moStrPos, len(msgList))
@ -101,24 +103,3 @@ func encodeMsgStr(v Message) string {
}
return v.MsgStr
}
type byMessages []Message
func (d byMessages) Len() int {
return len(d)
}
func (d byMessages) Less(i, j int) bool {
if a, b := d[i].MsgContext, d[j].MsgContext; a != b {
return a < b
}
if a, b := d[i].MsgId, d[j].MsgId; a != b {
return a < b
}
if a, b := d[i].MsgIdPlural, d[j].MsgIdPlural; a != b {
return a < b
}
return false
}
func (d byMessages) Swap(i, j int) {
d[i], d[j] = d[j], d[i]
}

View File

@ -37,17 +37,21 @@ type File struct {
Messages []Message
}
// Load loads mo file format data.
func Load(data []byte) (*File, error) {
return loadData(data)
}
// Load loads a named mo file.
func Load(name string) (*File, error) {
data, err := ioutil.ReadFile(name)
func LoadFile(path string) (*File, error) {
data, err := ioutil.ReadFile(path)
if err != nil {
return nil, err
}
return LoadData(data)
return loadData(data)
}
// LoadData loads mo file format data.
func LoadData(data []byte) (*File, error) {
func loadData(data []byte) (*File, error) {
r := bytes.NewReader(data)
var magicNumber uint32

View File

@ -37,3 +37,16 @@ func (p Message) String() string {
}
return buf.String()
}
func (m_i *Message) less(m_j *Message) bool {
if a, b := m_i.MsgContext, m_j.MsgContext; a != b {
return a < b
}
if a, b := m_i.MsgId, m_j.MsgId; a != b {
return a < b
}
if a, b := m_i.MsgIdPlural, m_j.MsgIdPlural; a != b {
return a < b
}
return false
}

View File

@ -7,7 +7,7 @@ Package plural provides standard plural formulas.
Examples:
import (
"code.google.com/p/gettext-go/gettext/plural"
"github.com/chai2010/gettext-go/plural"
)
func main() {

View File

@ -7,11 +7,11 @@ Package po provides support for reading and writing GNU PO file.
Examples:
import (
"github.com/chai2010/gettext-go/gettext/po"
"github.com/chai2010/gettext-go/po"
)
func main() {
poFile, err := po.Load("test.po")
poFile, err := po.LoadFile("test.po")
if err != nil {
log.Fatal(err)
}

View File

@ -20,17 +20,21 @@ type File struct {
Messages []Message
}
// Load loads a named po file.
func Load(name string) (*File, error) {
data, err := ioutil.ReadFile(name)
// Load loads po file format data.
func Load(data []byte) (*File, error) {
return loadData(data)
}
// LoadFile loads a named po file.
func LoadFile(path string) (*File, error) {
data, err := ioutil.ReadFile(path)
if err != nil {
return nil, err
}
return LoadData(data)
return loadData(data)
}
// LoadData loads po file format data.
func LoadData(data []byte) (*File, error) {
func loadData(data []byte) (*File, error) {
r := newLineReader(string(data))
var file File
for {
@ -59,7 +63,9 @@ func (f *File) Data() []byte {
// sort the massge as ReferenceFile/ReferenceLine field
var messages []Message
messages = append(messages, f.Messages...)
sort.Sort(byMessages(messages))
sort.Slice(messages, func(i, j int) bool {
return messages[i].less(&messages[j])
})
var buf bytes.Buffer
fmt.Fprintf(&buf, "%s\n", f.MimeHeader.String())

View File

@ -26,29 +26,21 @@ type Message struct {
MsgStrPlural []string // msgstr[0] translated-string-case-0
}
type byMessages []Message
func (d byMessages) Len() int {
return len(d)
}
func (d byMessages) Less(i, j int) bool {
if d[i].Comment.less(&d[j].Comment) {
func (p *Message) less(q *Message) bool {
if p.Comment.less(&q.Comment) {
return true
}
if a, b := d[i].MsgContext, d[j].MsgContext; a != b {
if a, b := p.MsgContext, q.MsgContext; a != b {
return a < b
}
if a, b := d[i].MsgId, d[j].MsgId; a != b {
if a, b := p.MsgId, q.MsgId; a != b {
return a < b
}
if a, b := d[i].MsgIdPlural, d[j].MsgIdPlural; a != b {
if a, b := p.MsgIdPlural, q.MsgIdPlural; a != b {
return a < b
}
return false
}
func (d byMessages) Swap(i, j int) {
d[i], d[j] = d[j], d[i]
}
func (p *Message) readPoEntry(r *lineReader) (err error) {
*p = Message{}
@ -175,15 +167,27 @@ func (p *Message) readString(r *lineReader) (msg string, err error) {
func (p Message) String() string {
var buf bytes.Buffer
fmt.Fprintf(&buf, "%s", p.Comment.String())
if p.MsgContext != "" {
fmt.Fprintf(&buf, "msgctxt %s", encodePoString(p.MsgContext))
}
fmt.Fprintf(&buf, "msgid %s", encodePoString(p.MsgId))
if p.MsgIdPlural != "" {
fmt.Fprintf(&buf, "msgid_plural %s", encodePoString(p.MsgIdPlural))
}
if p.MsgStr != "" {
fmt.Fprintf(&buf, "msgstr %s", encodePoString(p.MsgStr))
}
for i := 0; i < len(p.MsgStrPlural); i++ {
fmt.Fprintf(&buf, "msgstr[%d] %s", i, encodePoString(p.MsgStrPlural[i]))
if len(p.MsgStrPlural) == 0 {
if p.MsgStr != "" {
fmt.Fprintf(&buf, "msgstr %s", encodePoString(p.MsgStr))
} else {
fmt.Fprintf(&buf, "msgstr %s", `""`+"\n")
}
} else {
for i := 0; i < len(p.MsgStrPlural); i++ {
if p.MsgStrPlural[i] != "" {
fmt.Fprintf(&buf, "msgstr[%d] %s", i, encodePoString(p.MsgStrPlural[i]))
} else {
fmt.Fprintf(&buf, "msgstr[%d] %s", i, `""`+"\n")
}
}
}
return buf.String()
}

View File

@ -70,7 +70,11 @@ func encodePoString(text string) string {
buf.WriteRune(r)
}
}
buf.WriteString(`\n"` + "\n")
if i < len(lines)-1 {
buf.WriteString(`\n"` + "\n")
} else {
buf.WriteString(`"` + "\n")
}
}
return buf.String()
}

View File

@ -5,9 +5,11 @@
package gettext
import (
"github.com/chai2010/gettext-go/gettext/mo"
"github.com/chai2010/gettext-go/gettext/plural"
"github.com/chai2010/gettext-go/gettext/po"
"encoding/json"
"github.com/chai2010/gettext-go/mo"
"github.com/chai2010/gettext-go/plural"
"github.com/chai2010/gettext-go/po"
)
var nilTranslator = &translator{
@ -26,9 +28,9 @@ func newMoTranslator(name string, data []byte) (*translator, error) {
err error
)
if len(data) != 0 {
f, err = mo.LoadData(data)
f, err = mo.Load(data)
} else {
f, err = mo.Load(name)
f, err = mo.LoadFile(name)
}
if err != nil {
return nil, err
@ -53,9 +55,9 @@ func newPoTranslator(name string, data []byte) (*translator, error) {
err error
)
if len(data) != 0 {
f, err = po.LoadData(data)
f, err = po.Load(data)
} else {
f, err = po.Load(name)
f, err = po.LoadFile(name)
}
if err != nil {
return nil, err
@ -80,8 +82,43 @@ func newPoTranslator(name string, data []byte) (*translator, error) {
return tr, nil
}
func newJsonTranslator(lang, name string, jsonData []byte) (*translator, error) {
var msgList []struct {
MsgContext string `json:"msgctxt"` // msgctxt context
MsgId string `json:"msgid"` // msgid untranslated-string
MsgIdPlural string `json:"msgid_plural"` // msgid_plural untranslated-string-plural
MsgStr []string `json:"msgstr"` // msgstr translated-string
}
if err := json.Unmarshal(jsonData, &msgList); err != nil {
return nil, err
}
var tr = &translator{
MessageMap: make(map[string]mo.Message),
PluralFormula: plural.Formula(lang),
}
for _, v := range msgList {
var v_MsgStr string
var v_MsgStrPlural = v.MsgStr
if len(v.MsgStr) != 0 {
v_MsgStr = v.MsgStr[0]
}
tr.MessageMap[tr.makeMapKey(v.MsgContext, v.MsgId)] = mo.Message{
MsgContext: v.MsgContext,
MsgId: v.MsgId,
MsgIdPlural: v.MsgIdPlural,
MsgStr: v_MsgStr,
MsgStrPlural: v_MsgStrPlural,
}
}
return tr, nil
}
func (p *translator) PGettext(msgctxt, msgid string) string {
return p.PNGettext(msgctxt, msgid, "", 0)
return p.findMsgStr(msgctxt, msgid)
}
func (p *translator) PNGettext(msgctxt, msgid, msgidPlural string, n int) string {
@ -100,6 +137,16 @@ func (p *translator) PNGettext(msgctxt, msgid, msgidPlural string, n int) string
return msgid
}
func (p *translator) findMsgStr(msgctxt, msgid string) string {
key := p.makeMapKey(msgctxt, msgid)
if v, ok := p.MessageMap[key]; ok {
if v.MsgStr != "" {
return v.MsgStr
}
}
return msgid
}
func (p *translator) findMsgStrPlural(msgctxt, msgid, msgidPlural string) []string {
key := p.makeMapKey(msgctxt, msgid)
if v, ok := p.MessageMap[key]; ok {

View File

@ -9,17 +9,17 @@ import (
"strings"
)
func getDefaultLocale() string {
func getDefaultLanguage() string {
if v := os.Getenv("LC_MESSAGES"); v != "" {
return simplifiedLocale(v)
return simplifiedLanguage(v)
}
if v := os.Getenv("LANG"); v != "" {
return simplifiedLocale(v)
return simplifiedLanguage(v)
}
return "default"
}
func simplifiedLocale(lang string) string {
func simplifiedLanguage(lang string) string {
// en_US/en_US.UTF-8/zh_CN/zh_TW/el_GR@euro/...
if idx := strings.Index(lang, ":"); idx != -1 {
lang = lang[:idx]

14
vendor/modules.txt vendored
View File

@ -173,12 +173,12 @@ github.com/blang/semver/v4
# github.com/cespare/xxhash/v2 v2.1.2 => github.com/cespare/xxhash/v2 v2.1.2
## explicit; go 1.11
github.com/cespare/xxhash/v2
# github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5 => github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5
## explicit
github.com/chai2010/gettext-go/gettext
github.com/chai2010/gettext-go/gettext/mo
github.com/chai2010/gettext-go/gettext/plural
github.com/chai2010/gettext-go/gettext/po
# github.com/chai2010/gettext-go v1.0.2 => github.com/chai2010/gettext-go v1.0.2
## explicit; go 1.14
github.com/chai2010/gettext-go
github.com/chai2010/gettext-go/mo
github.com/chai2010/gettext-go/plural
github.com/chai2010/gettext-go/po
# github.com/checkpoint-restore/go-criu/v5 v5.3.0 => github.com/checkpoint-restore/go-criu/v5 v5.3.0
## explicit; go 1.13
github.com/checkpoint-restore/go-criu/v5
@ -2591,7 +2591,7 @@ sigs.k8s.io/yaml
# github.com/census-instrumentation/opencensus-proto => github.com/census-instrumentation/opencensus-proto v0.2.1
# github.com/certifi/gocertifi => github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054
# github.com/cespare/xxhash/v2 => github.com/cespare/xxhash/v2 v2.1.2
# github.com/chai2010/gettext-go => github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5
# github.com/chai2010/gettext-go => github.com/chai2010/gettext-go v1.0.2
# github.com/checkpoint-restore/go-criu/v5 => github.com/checkpoint-restore/go-criu/v5 v5.3.0
# github.com/chzyer/logex => github.com/chzyer/logex v1.1.10
# github.com/chzyer/readline => github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e