package i18n import ( "embed" "encoding/json" "github.com/nicksnyder/go-i18n/v2/i18n" "github.com/rs/zerolog/log" "golang.org/x/text/language" ) //go:embed translations/*.json var translationFS embed.FS // Bundle is the global i18n bundle var Bundle *i18n.Bundle // SupportedLanguages lists all supported language codes var SupportedLanguages = []string{"en", "es", "fr", "de", "pt", "it", "ja", "ko", "nl", "zh"} // DefaultLanguage is the fallback language const DefaultLanguage = "en" // Init initializes the i18n bundle with embedded translation files func Init() error { Bundle = i18n.NewBundle(language.English) Bundle.RegisterUnmarshalFunc("json", json.Unmarshal) // Load all translation files for _, lang := range SupportedLanguages { path := "translations/" + lang + ".json" data, err := translationFS.ReadFile(path) if err != nil { log.Warn().Str("language", lang).Err(err).Msg("Failed to load translation file") continue } Bundle.MustParseMessageFileBytes(data, path) log.Info().Str("language", lang).Msg("Loaded translation file") } return nil } // NewLocalizer creates a new localizer for the given language tags func NewLocalizer(langs ...string) *i18n.Localizer { return i18n.NewLocalizer(Bundle, langs...) } // T translates a message ID with optional template data func T(localizer *i18n.Localizer, messageID string, templateData map[string]interface{}) string { if localizer == nil { localizer = NewLocalizer(DefaultLanguage) } msg, err := localizer.Localize(&i18n.LocalizeConfig{ MessageID: messageID, TemplateData: templateData, }) if err != nil { // Fallback to message ID if translation not found log.Debug().Str("message_id", messageID).Err(err).Msg("Translation not found") return messageID } return msg } // TSimple translates a message ID without template data func TSimple(localizer *i18n.Localizer, messageID string) string { return T(localizer, messageID, nil) } // MustT translates a message ID or panics func MustT(localizer *i18n.Localizer, messageID string, templateData map[string]interface{}) string { if localizer == nil { localizer = NewLocalizer(DefaultLanguage) } msg, err := localizer.Localize(&i18n.LocalizeConfig{ MessageID: messageID, TemplateData: templateData, }) if err != nil { panic(err) } return msg }