dcbot/internal/discord/internal/discordi18n/localizer.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()
}