152 lines
4.2 KiB
Go
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
|
|
}
|