replace zxq.co/ripple/hanayo
This commit is contained in:
62
modules/locale/lang_map.go
Normal file
62
modules/locale/lang_map.go
Normal file
@@ -0,0 +1,62 @@
|
||||
package locale
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var languageMap = make(map[string]*po, 20)
|
||||
|
||||
func loadLanguages() {
|
||||
files, err := ioutil.ReadDir("./data/locales")
|
||||
if err != nil {
|
||||
fmt.Println("loadLanguages", err)
|
||||
return
|
||||
}
|
||||
for _, file := range files {
|
||||
if file.Name() == "templates.pot" || file.Name() == "." || file.Name() == ".." {
|
||||
continue
|
||||
}
|
||||
|
||||
p, err := parseFile("./data/locales/" + file.Name())
|
||||
if err != nil {
|
||||
fmt.Println(file.Name(), ":", err)
|
||||
continue
|
||||
}
|
||||
if p == nil {
|
||||
fmt.Println(file.Name(), ":", "p is nil")
|
||||
}
|
||||
|
||||
langName := strings.TrimPrefix(strings.TrimSuffix(file.Name(), ".po"), "templates-")
|
||||
languageMap[langName] = p
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
loadLanguages()
|
||||
}
|
||||
|
||||
// Get retrieves a string from a language
|
||||
func Get(langs []string, str string, vars ...interface{}) string {
|
||||
for _, lang := range langs {
|
||||
l := languageMap[lang]
|
||||
|
||||
if l == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if el := l.Translations[str]; el != "" {
|
||||
if len(vars) > 0 {
|
||||
return fmt.Sprintf(el, vars...)
|
||||
}
|
||||
return el
|
||||
}
|
||||
}
|
||||
|
||||
if len(vars) > 0 {
|
||||
return fmt.Sprintf(str, vars...)
|
||||
}
|
||||
|
||||
return str
|
||||
}
|
38
modules/locale/parse_header.go
Normal file
38
modules/locale/parse_header.go
Normal file
@@ -0,0 +1,38 @@
|
||||
package locale
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ParseHeader parses an Accept-Language header, and sorts the values.
|
||||
func ParseHeader(header string) []string {
|
||||
if header == "" {
|
||||
return nil
|
||||
}
|
||||
parts := strings.Split(header, ",")
|
||||
|
||||
sort.Slice(parts, func(i, j int) bool {
|
||||
return getQuality(parts[i]) > getQuality(parts[j])
|
||||
})
|
||||
|
||||
for idx, val := range parts {
|
||||
parts[idx] = strings.Replace(strings.SplitN(val, ";q=", 2)[0], "-", "_", 1)
|
||||
}
|
||||
|
||||
return parts
|
||||
}
|
||||
|
||||
func getQuality(s string) float32 {
|
||||
idx := strings.Index(s, ";q=")
|
||||
if idx == -1 {
|
||||
return 1
|
||||
}
|
||||
|
||||
f, err := strconv.ParseFloat(s[idx+3:], 32)
|
||||
if err != nil {
|
||||
return 1
|
||||
}
|
||||
return float32(f)
|
||||
}
|
45
modules/locale/parse_header_test.go
Normal file
45
modules/locale/parse_header_test.go
Normal file
@@ -0,0 +1,45 @@
|
||||
package locale
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestParseHeader(t *testing.T) {
|
||||
tt := []struct {
|
||||
In string
|
||||
Out []string
|
||||
}{
|
||||
{
|
||||
"en",
|
||||
[]string{"en"},
|
||||
},
|
||||
{
|
||||
"en-GB",
|
||||
[]string{"en_GB"},
|
||||
},
|
||||
{
|
||||
"en-GB;q=0.5,it",
|
||||
[]string{"it", "en_GB"},
|
||||
},
|
||||
{
|
||||
"en-GB;q=0.5,it,pl;q=0.2",
|
||||
[]string{"it", "en_GB", "pl"},
|
||||
},
|
||||
{
|
||||
"en-GB;q=0.5,pl;q=xd",
|
||||
[]string{"pl", "en_GB"},
|
||||
},
|
||||
{
|
||||
"",
|
||||
nil,
|
||||
},
|
||||
}
|
||||
|
||||
for _, el := range tt {
|
||||
got := ParseHeader(el.In)
|
||||
if !reflect.DeepEqual(got, el.Out) {
|
||||
t.Errorf("got %v want %v", got, el.Out)
|
||||
}
|
||||
}
|
||||
}
|
112
modules/locale/parser.go
Normal file
112
modules/locale/parser.go
Normal file
@@ -0,0 +1,112 @@
|
||||
package locale
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type po struct {
|
||||
Headers map[string]string
|
||||
Translations map[string]string
|
||||
}
|
||||
|
||||
// A minimal .po file parser.
|
||||
func parse(s *bufio.Scanner) *po {
|
||||
p := &po{
|
||||
Headers: make(map[string]string, 20),
|
||||
Translations: make(map[string]string, 500),
|
||||
}
|
||||
|
||||
const (
|
||||
currentNothing = iota
|
||||
currentMsgID
|
||||
currentMsgString
|
||||
)
|
||||
var current byte
|
||||
var currentID string
|
||||
var currentString string
|
||||
|
||||
for s.Scan() {
|
||||
line := strings.TrimSpace(s.Text())
|
||||
|
||||
if line == "" || line[0] == '#' {
|
||||
continue
|
||||
}
|
||||
|
||||
switch {
|
||||
case strings.HasPrefix(line, "msgid "):
|
||||
unq, err := strconv.Unquote(strings.TrimSpace(strings.TrimPrefix(line, "msgid")))
|
||||
if err != nil {
|
||||
fmt.Println(line)
|
||||
fmt.Println(err)
|
||||
return nil
|
||||
}
|
||||
|
||||
if current != currentNothing && currentID == "" && currentString != "" {
|
||||
for _, h := range strings.Split(currentString, "\n") {
|
||||
if h == "" {
|
||||
continue
|
||||
}
|
||||
parts := strings.SplitN(h, ": ", 2)
|
||||
if len(parts) != 2 {
|
||||
continue
|
||||
}
|
||||
p.Headers[parts[0]] = parts[1]
|
||||
}
|
||||
} else {
|
||||
p.Translations[currentID] = currentString
|
||||
}
|
||||
|
||||
currentID = unq
|
||||
current = currentMsgID
|
||||
case strings.HasPrefix(line, "msgstr "):
|
||||
unq, err := strconv.Unquote(strings.TrimSpace(strings.TrimPrefix(line, "msgstr")))
|
||||
if err != nil {
|
||||
fmt.Println(line)
|
||||
fmt.Println(err)
|
||||
return nil
|
||||
}
|
||||
currentString = unq
|
||||
current = currentMsgString
|
||||
case strings.HasPrefix(line, "msgid_plural "), strings.HasPrefix(line, "msgstr["):
|
||||
// We currently don't support plural in the Go parser, at least hold it off 'til it's needed.
|
||||
current = currentNothing
|
||||
default:
|
||||
if current == currentNothing {
|
||||
continue
|
||||
}
|
||||
|
||||
unq, err := strconv.Unquote(strings.TrimSpace(line))
|
||||
if err != nil {
|
||||
fmt.Println(line)
|
||||
fmt.Println(err)
|
||||
return nil
|
||||
}
|
||||
switch current {
|
||||
case currentMsgID:
|
||||
currentID += unq
|
||||
case currentMsgString:
|
||||
currentString += unq
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if current == currentMsgString {
|
||||
p.Translations[currentID] = currentString
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
func parseFile(fName string) (*po, error) {
|
||||
f, err := os.Open(fName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
s := bufio.NewScanner(f)
|
||||
p := parse(s)
|
||||
return p, nil
|
||||
}
|
Reference in New Issue
Block a user