translate/translate.go

121 lines
1.9 KiB
Go

package translate
import (
"fmt"
"hash/crc64"
"io"
"io/fs"
"os"
"path/filepath"
"strings"
"github.com/pelletier/go-toml/v2"
"golang.org/x/text/language"
)
type Translations struct {
Items []Translation `toml:"translation"`
}
type Translation struct {
ID uint64 `toml:"id"`
Value string `toml:"value"`
}
type Dictionary map[uint64]string
type Catalog map[language.Tag]Dictionary
type Translator struct {
cat Catalog
Fallback language.Tag
}
func New(cat Catalog) Translator {
return Translator{cat, language.English}
}
func NewFromDir(dir string) (Translator, error) {
return NewFromFS(os.DirFS(dir))
}
func NewFromFS(fsys fs.FS) (Translator, error) {
cat := Catalog{}
err := fs.WalkDir(fsys, ".", func(path string, d fs.DirEntry, err error) error {
if err != nil {
return err
}
if d.IsDir() {
return nil
}
ext := filepath.Ext(path)
if ext != ".toml" {
return nil
}
lang := filepath.Ext(strings.TrimSuffix(path, ext))
lang = strings.TrimPrefix(lang, ".")
tag, err := language.Parse(lang)
if err != nil {
return err
}
fl, err := fsys.Open(path)
if err != nil {
return err
}
var tr Translations
err = toml.NewDecoder(fl).Decode(&tr)
if err != nil {
return err
}
fl.Close()
cat[tag] = toDict(tr)
return nil
})
if err != nil {
return Translator{}, err
}
fmt.Println(cat)
return Translator{cat, language.English}, nil
}
func (t *Translator) TranslateTo(s string, tag language.Tag) string {
dict, ok := t.cat[tag]
if !ok {
dict, ok = t.cat[t.Fallback]
if !ok {
return s
}
}
id := hashString(s)
str, ok := dict[id]
if !ok {
str = s
}
return str
}
func toDict(tr Translations) Dictionary {
out := Dictionary{}
for _, item := range tr.Items {
out[item.ID] = item.Value
}
return out
}
func hashString(s string) uint64 {
hash := crc64.New(crc64.MakeTable(crc64.ISO))
_, err := io.WriteString(hash, s)
if err != nil {
return 0
}
return hash.Sum64()
}