112 lines
1.8 KiB
Go
112 lines
1.8 KiB
Go
package translate
|
|
|
|
import (
|
|
"hash/crc32"
|
|
"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 uint32 `toml:"id"`
|
|
Value string `toml:"value"`
|
|
}
|
|
|
|
type Dictionary map[uint32]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
|
|
}
|
|
|
|
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) uint32 {
|
|
return crc32.ChecksumIEEE([]byte(s))
|
|
}
|