Browse Source

Make website show localised text

tags/v1.4.0
Morgan Bazalgette 2 years ago
parent
commit
1326494f99
Signed by: Morgan Bazalgette <the@howl.moe> GPG Key ID: 40D328300D245DA5
4 changed files with 139 additions and 3 deletions
  1. 10
    3
      localisation.go
  2. 46
    0
      modules/locale/lang_map.go
  3. 38
    0
      modules/locale/parse_header.go
  4. 45
    0
      modules/locale/parse_header_test.go

+ 10
- 3
localisation.go View File

@@ -1,16 +1,23 @@
package main

import (
"fmt"

"github.com/gin-gonic/gin"
"zxq.co/ripple/hanayo/modules/locale"
)

// T translates a string into the language specified by the request.
func T(c *gin.Context, s string, args ...interface{}) string {
return fmt.Sprintf(s, args...)
return locale.Get(getLang(c), s, args...)
}

func (b *baseTemplateData) T(s string, args ...interface{}) string {
return T(b.Gin, s, args...)
}

func getLang(c *gin.Context) []string {
s, _ := c.Cookie("language")
if s != "" {
return []string{s}
}
return locale.ParseHeader(c.Request.Header.Get("Accept-Language"))
}

+ 46
- 0
modules/locale/lang_map.go View File

@@ -0,0 +1,46 @@
package locale

import (
"fmt"
"io/ioutil"
"strings"

"github.com/leonelquinteros/gotext"
)

var languageMap = make(map[string]*gotext.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
}

po := new(gotext.Po)
po.ParseFile("./data/locales/" + file.Name())

langName := strings.TrimPrefix(strings.TrimSuffix(file.Name(), ".po"), "templates-")
languageMap[langName] = po
}
}

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 {
return l.Get(str, vars...)
}
}

return fmt.Sprintf(str, vars...)
}

+ 38
- 0
modules/locale/parse_header.go View 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
- 0
modules/locale/parse_header_test.go View 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)
}
}
}

Loading…
Cancel
Save