2024-02-17 19:08:58 +06:00
|
|
|
package kernel
|
2024-01-28 22:01:16 +06:00
|
|
|
|
|
|
|
import (
|
|
|
|
"github.com/BurntSushi/toml"
|
|
|
|
"github.com/nicksnyder/go-i18n/v2/i18n"
|
|
|
|
"golang.org/x/text/cases"
|
|
|
|
"golang.org/x/text/language"
|
|
|
|
"golang.org/x/text/language/display"
|
|
|
|
"path/filepath"
|
|
|
|
"sort"
|
|
|
|
)
|
|
|
|
|
2024-02-17 19:08:58 +06:00
|
|
|
type LocalizerContract interface {
|
2024-01-28 22:01:16 +06:00
|
|
|
GetLanguages() []Lang
|
|
|
|
GetMessage(localizeConfig *i18n.LocalizeConfig) string
|
|
|
|
SetCurrentLanguage(lang Lang) error
|
2024-01-31 21:02:12 +06:00
|
|
|
SetCurrentLanguageByCode(code string) error
|
2024-01-28 22:01:16 +06:00
|
|
|
GetCurrentLanguage() *CurrentLanguage
|
2024-02-17 19:08:58 +06:00
|
|
|
AddListener(listener LocalizerListenerContract)
|
|
|
|
}
|
|
|
|
|
|
|
|
type LocalizerListenerContract interface {
|
|
|
|
Change(localizerService LocalizerContract)
|
2024-01-28 22:01:16 +06:00
|
|
|
}
|
|
|
|
|
|
|
|
type Lang struct {
|
|
|
|
Code string
|
|
|
|
Title string
|
|
|
|
}
|
|
|
|
|
|
|
|
type CurrentLanguage struct {
|
|
|
|
Lang Lang
|
|
|
|
localizer *i18n.Localizer
|
|
|
|
localizerDefault *i18n.Localizer
|
|
|
|
}
|
|
|
|
|
2024-02-17 19:08:58 +06:00
|
|
|
type Localizer struct {
|
|
|
|
bundle *i18n.Bundle
|
|
|
|
languages []Lang
|
|
|
|
currentLanguage *CurrentLanguage
|
|
|
|
localizerListener map[int]LocalizerListenerContract
|
2024-01-28 22:01:16 +06:00
|
|
|
}
|
|
|
|
|
2024-02-17 19:08:58 +06:00
|
|
|
func NewLocalizer(directory string, languageDefault language.Tag) (*Localizer, error) {
|
2024-01-28 22:01:16 +06:00
|
|
|
bundle := i18n.NewBundle(languageDefault)
|
|
|
|
bundle.RegisterUnmarshalFunc("toml", toml.Unmarshal)
|
|
|
|
|
|
|
|
languages, err := initLanguages(directory, bundle)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
localizerDefault := i18n.NewLocalizer(bundle, languageDefault.String())
|
|
|
|
|
2024-02-17 19:08:58 +06:00
|
|
|
return &Localizer{
|
2024-01-28 22:01:16 +06:00
|
|
|
bundle: bundle,
|
|
|
|
languages: languages,
|
|
|
|
currentLanguage: &CurrentLanguage{
|
|
|
|
Lang: Lang{
|
|
|
|
Code: languageDefault.String(),
|
|
|
|
Title: cases.Title(languageDefault).String(display.Self.Name(languageDefault)),
|
|
|
|
},
|
|
|
|
localizer: localizerDefault,
|
|
|
|
localizerDefault: localizerDefault,
|
|
|
|
},
|
2024-02-17 19:08:58 +06:00
|
|
|
localizerListener: map[int]LocalizerListenerContract{},
|
2024-01-28 22:01:16 +06:00
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func initLanguages(directory string, bundle *i18n.Bundle) ([]Lang, error) {
|
|
|
|
var languages []Lang
|
|
|
|
|
|
|
|
files, err := filepath.Glob(directory + "/active.*.toml")
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
for _, file := range files {
|
2024-01-31 21:22:38 +06:00
|
|
|
lang, err := bundle.LoadMessageFile(file)
|
2024-01-28 22:01:16 +06:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2024-01-31 21:22:38 +06:00
|
|
|
title := cases.Title(lang.Tag).String(display.Self.Name(lang.Tag))
|
|
|
|
languages = append(languages, Lang{Code: lang.Tag.String(), Title: title})
|
2024-01-28 22:01:16 +06:00
|
|
|
}
|
|
|
|
|
|
|
|
sort.Sort(languagesSort(languages))
|
|
|
|
|
|
|
|
return languages, nil
|
|
|
|
}
|
|
|
|
|
2024-02-17 19:08:58 +06:00
|
|
|
func (l Localizer) GetLanguages() []Lang {
|
|
|
|
return l.languages
|
2024-01-28 22:01:16 +06:00
|
|
|
}
|
|
|
|
|
2024-02-17 19:08:58 +06:00
|
|
|
func (l Localizer) GetMessage(localizeConfig *i18n.LocalizeConfig) string {
|
|
|
|
message, err := l.GetCurrentLanguage().localizer.Localize(localizeConfig)
|
2024-01-28 22:01:16 +06:00
|
|
|
if err != nil {
|
2024-02-17 19:08:58 +06:00
|
|
|
message, err = l.GetCurrentLanguage().localizerDefault.Localize(localizeConfig)
|
2024-01-28 22:01:16 +06:00
|
|
|
if err != nil {
|
|
|
|
return err.Error()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return message
|
|
|
|
}
|
|
|
|
|
2024-02-17 19:08:58 +06:00
|
|
|
func (l Localizer) SetCurrentLanguage(lang Lang) error {
|
|
|
|
l.currentLanguage.Lang = lang
|
|
|
|
l.currentLanguage.localizer = i18n.NewLocalizer(l.bundle, lang.Code)
|
|
|
|
l.eventSetCurrentLanguage()
|
2024-01-28 22:01:16 +06:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2024-02-17 19:08:58 +06:00
|
|
|
func (l Localizer) SetCurrentLanguageByCode(code string) error {
|
2024-01-31 21:22:38 +06:00
|
|
|
lang, err := language.Parse(code)
|
2024-01-31 21:02:12 +06:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2024-01-31 21:22:38 +06:00
|
|
|
title := cases.Title(lang).String(display.Self.Name(lang))
|
2024-02-17 19:08:58 +06:00
|
|
|
return l.SetCurrentLanguage(Lang{Code: lang.String(), Title: title})
|
|
|
|
}
|
|
|
|
|
|
|
|
func (l Localizer) GetCurrentLanguage() *CurrentLanguage {
|
|
|
|
return l.currentLanguage
|
2024-01-31 21:02:12 +06:00
|
|
|
}
|
|
|
|
|
2024-02-17 19:08:58 +06:00
|
|
|
func (l Localizer) AddListener(listener LocalizerListenerContract) {
|
|
|
|
l.localizerListener[len(l.localizerListener)] = listener
|
|
|
|
}
|
|
|
|
|
|
|
|
func (l Localizer) eventSetCurrentLanguage() {
|
|
|
|
for _, listener := range l.localizerListener {
|
|
|
|
listener.Change(l)
|
|
|
|
}
|
2024-01-28 22:01:16 +06:00
|
|
|
}
|
|
|
|
|
|
|
|
type languagesSort []Lang
|
|
|
|
|
|
|
|
func (l languagesSort) Len() int { return len(l) }
|
|
|
|
func (l languagesSort) Swap(i, j int) { l[i], l[j] = l[j], l[i] }
|
|
|
|
func (l languagesSort) Less(i, j int) bool {
|
|
|
|
return languagePriority(l[i]) < languagePriority(l[j])
|
|
|
|
}
|
|
|
|
func languagePriority(l Lang) int {
|
|
|
|
priority := 0
|
|
|
|
|
|
|
|
switch l.Code {
|
|
|
|
case "ru":
|
|
|
|
priority = -3
|
|
|
|
case "kk":
|
|
|
|
priority = -2
|
|
|
|
case "en":
|
|
|
|
priority = -1
|
|
|
|
}
|
|
|
|
|
|
|
|
return priority
|
|
|
|
}
|