119 lines
2.9 KiB
Go
119 lines
2.9 KiB
Go
package discordi18n
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
|
|
"gitea.dwysokinski.me/twhelp/dcbot/internal/domain"
|
|
"github.com/bwmarrin/discordgo"
|
|
lru "github.com/hashicorp/golang-lru/v2"
|
|
"github.com/nicksnyder/go-i18n/v2/i18n"
|
|
"golang.org/x/text/language"
|
|
)
|
|
|
|
const localizerCacheSize = 128
|
|
|
|
type Localizer struct {
|
|
bundle *i18n.Bundle
|
|
cache *lru.Cache[string, *i18n.Localizer]
|
|
defaultLanguage language.Tag
|
|
}
|
|
|
|
func NewLocalizer(defaultLanguage language.Tag) (*Localizer, error) {
|
|
b, err := newBundle(defaultLanguage)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
l, err := lru.New[string, *i18n.Localizer](localizerCacheSize)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &Localizer{
|
|
bundle: b,
|
|
cache: l,
|
|
}, nil
|
|
}
|
|
|
|
func (l *Localizer) Localize(lang string, lc *i18n.LocalizeConfig) (string, error) {
|
|
return l.newLocalizer(lang).Localize(lc)
|
|
}
|
|
|
|
func (l *Localizer) MustLocalize(lang string, lc *i18n.LocalizeConfig) string {
|
|
return l.newLocalizer(lang).MustLocalize(lc)
|
|
}
|
|
|
|
func (l *Localizer) LocalizeWithTag(lang string, lc *i18n.LocalizeConfig) (string, language.Tag, error) {
|
|
return l.newLocalizer(lang).LocalizeWithTag(lc)
|
|
}
|
|
|
|
func (l *Localizer) newLocalizer(lang string) *i18n.Localizer {
|
|
if loc, ok := l.cache.Get(lang); ok {
|
|
return loc
|
|
}
|
|
loc := i18n.NewLocalizer(l.bundle, lang, l.defaultLanguage.String())
|
|
_ = l.cache.Add(lang, loc)
|
|
return loc
|
|
}
|
|
|
|
func (l *Localizer) LocalizeDiscord(messageID string) (string, map[discordgo.Locale]string, error) {
|
|
return l.LocalizeDiscordWithConfig(&i18n.LocalizeConfig{
|
|
MessageID: messageID,
|
|
})
|
|
}
|
|
|
|
func (l *Localizer) LocalizeDiscordWithConfig(lc *i18n.LocalizeConfig) (string, map[discordgo.Locale]string, error) {
|
|
m := make(map[discordgo.Locale]string)
|
|
|
|
for _, tag := range l.bundle.LanguageTags() {
|
|
locale := discordgo.Locale(tag.String())
|
|
|
|
if discordgo.Locales[locale] == "" {
|
|
continue
|
|
}
|
|
|
|
msg, msgLang, err := l.LocalizeWithTag(tag.String(), lc)
|
|
if err != nil {
|
|
return "", nil, fmt.Errorf("couldn't lookup message in locale '%s': %w", locale, err)
|
|
}
|
|
|
|
if msgLang == l.defaultLanguage {
|
|
continue
|
|
}
|
|
|
|
m[locale] = msg
|
|
}
|
|
|
|
defaultMsg, err := l.Localize(l.defaultLanguage.String(), lc)
|
|
if err != nil {
|
|
return "", nil, fmt.Errorf("couldn't lookup message in default language: %w", err)
|
|
}
|
|
|
|
return defaultMsg, m, nil
|
|
}
|
|
|
|
func (l *Localizer) LocalizeError(lang string, errToLocalize error) string {
|
|
defaultErr, err := l.Localize(lang, &i18n.LocalizeConfig{MessageID: "err.default"})
|
|
if err != nil {
|
|
defaultErr = "Something went wrong. Try again later."
|
|
}
|
|
|
|
var translatableErr domain.TranslatableError
|
|
if !errors.As(errToLocalize, &translatableErr) {
|
|
return defaultErr
|
|
}
|
|
|
|
msgID := "err." + translatableErr.Slug()
|
|
msg, err := l.Localize(lang, &i18n.LocalizeConfig{
|
|
MessageID: msgID,
|
|
TemplateData: translatableErr.Params(),
|
|
})
|
|
if err != nil {
|
|
return defaultErr
|
|
}
|
|
return msg
|
|
}
|
|
|
|
func (l *Localizer) LanguageTags() []language.Tag {
|
|
return l.bundle.LanguageTags()
|
|
}
|