Files
Stephan D d367dddbbd
Some checks failed
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/fx/1 Pipeline failed
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/fx/2 Pipeline failed
fx build fix
2025-11-08 00:40:01 +01:00

152 lines
4.2 KiB
Go

package lclrimp
import (
"encoding/json"
"path"
"github.com/tech/sendico/pkg/merrors"
"github.com/tech/sendico/pkg/mlogger"
"github.com/tech/sendico/pkg/mutil/fr"
"github.com/nicksnyder/go-i18n/v2/i18n"
"go.uber.org/zap"
"golang.org/x/text/language"
)
type Lang struct {
bundle *i18n.Bundle
localizer *i18n.Localizer
}
type Localizers = map[string]Lang
type Localizer struct {
logger mlogger.Logger
l9rs Localizers
support string
serviceName string
}
type Config struct {
Path string `yaml:"path"`
Langs []string `yaml:"languages"`
Support string `yaml:"support"`
ServiceName string `yaml:"service_name"`
}
func loadBundleLocalization(logger mlogger.Logger, bundle *i18n.Bundle, localizationPath string) error {
b, err := fr.ReadFile(logger, localizationPath)
if err != nil {
logger.Error("Failed to read localization", zap.Error(err), zap.String("localization_path", localizationPath))
return err
}
_, err = bundle.ParseMessageFileBytes(b, localizationPath)
if err != nil {
logger.Error("Failed to parse localization", zap.Error(err), zap.String("localization_path", localizationPath))
return err
}
return err
}
func loadLocalizations(logger mlogger.Logger, source string) (*i18n.Bundle, error) {
bundle := i18n.NewBundle(language.English)
// Register a json unmarshal function for i18n bundle.
bundle.RegisterUnmarshalFunc("json", json.Unmarshal)
// Load translations from json files for non-default languages.
err := loadBundleLocalization(logger, bundle, source)
if err != nil {
// will not log error once again, just return nil
return nil, err
}
return bundle, nil
}
func newLang(logger mlogger.Logger, language string, source string) (*Lang, error) {
var lang Lang
var err error
lang.bundle, err = loadLocalizations(logger, source)
if err != nil {
logger.Error("Failed to install language bundle", zap.Error(err),
zap.String("language", language), zap.String("source", source))
return nil, err
}
lang.localizer = i18n.NewLocalizer(lang.bundle, language)
if lang.localizer != nil {
logger.Info("Installed language bundle",
zap.String("language", language), zap.String("source", source))
} else {
logger.Error("Failed to install language bundle", zap.String("language", language), zap.String("source", source))
return nil, merrors.Internal("failed_to_load_localization")
}
return &lang, nil
}
func prepareLocalizers(logger mlogger.Logger, conf *Config) (Localizers, error) {
localizers := make(Localizers)
for _, lang := range conf.Langs {
path := path.Join(conf.Path, lang+".json")
l, err := newLang(logger, lang, path)
if err != nil {
logger.Error("Failed to load localization", zap.Error(err), zap.String("language", lang), zap.String("source", path))
return localizers, err
}
localizers[lang] = *l
}
return localizers, nil
}
func (loc *Localizer) LocalizeTemplate(id string, templateData, ctr any, lang string) (string, error) {
lclzr, found := loc.l9rs[lang]
if !found {
loc.logger.Info("Language not found, falling back to en", zap.String("message_id", id), zap.String("language", lang))
lclzr = loc.l9rs["en"]
}
config := i18n.LocalizeConfig{
MessageID: id,
TemplateData: templateData,
PluralCount: ctr,
}
localized, err := lclzr.localizer.Localize(&config)
if err != nil {
loc.logger.Warn("Failed to localize string", zap.Error(err), zap.String("message_id", id), zap.String("language", lang))
}
return localized, err
}
func (loc *Localizer) LocalizeString(id string, lang string) (string, error) {
return loc.LocalizeTemplate(id, nil, nil, lang)
}
func (loc *Localizer) ServiceName() string {
return loc.serviceName
}
func (loc *Localizer) SupportMail() string {
return loc.support
}
// NewConnection creates a new database connection
func CreateLocalizer(logger mlogger.Logger, config *Config) (*Localizer, error) {
p := new(Localizer)
p.logger = logger.Named("localizer")
var err error
p.l9rs, err = prepareLocalizers(p.logger, config)
if err != nil {
logger.Warn("Failed to create localizer", zap.Error(err))
return nil, err
}
p.serviceName = config.ServiceName
p.support = config.Support
logger.Info("Localizer is up", zap.String("service_name", p.serviceName), zap.String("support", p.support))
return p, nil
}