1package i18n 2 3import ( 4 "embed" 5 "github.com/jeandeaual/go-locale" 6 "github.com/nicksnyder/go-i18n/v2/i18n" 7 "golang.org/x/text/language" 8 "gopkg.in/yaml.v2" 9 "log" 10 "strings" 11) 12 13//go:embed *.yaml 14var localeFiles embed.FS 15 16var localizer *i18n.Localizer 17 18// Initialize initializes the i18n bundle and localizer 19func Initialize() { 20 lang := getPreferredLanguage() 21 22 bundle := i18n.NewBundle(language.English) 23 bundle.RegisterUnmarshalFunc("yaml", yaml.Unmarshal) 24 25 // Load English translations first 26 if err := loadTranslations(bundle, "en.yaml"); err != nil { 27 log.Fatalf("Failed to load default English translation: %s", err) 28 } 29 30 // Try to load the specified language translations 31 if lang != "en" { 32 if err := loadTranslations(bundle, lang+".yaml"); err != nil { 33 // Try loading the base language if the specific locale fails 34 baseLang := strings.Split(lang, "-")[0] 35 if baseLang != lang { // Only attempt if baseLang is different from lang 36 log.Printf("Failed to load %s translation, trying base language %s: %s", lang, baseLang, err) 37 if err := loadTranslations(bundle, baseLang+".yaml"); err != nil { 38 log.Printf("Failed to load base language %s translation, falling back to English: %s", baseLang, err) 39 } else { 40 lang = baseLang 41 } 42 } else { 43 log.Printf("Failed to load %s translation, falling back to English: %s", lang, err) 44 } 45 } 46 } 47 48 // Create a localizer for the specified language 49 localizer = i18n.NewLocalizer(bundle, lang) 50} 51 52// loadTranslations loads translation files into the bundle 53func loadTranslations(bundle *i18n.Bundle, filename string) error { 54 data, err := localeFiles.ReadFile(filename) 55 if err != nil { 56 return err 57 } 58 59 // Must use bundle.ParseMessageFileBytes instead of LoadMessageFile for embedded data 60 _, err = bundle.ParseMessageFileBytes(data, filename) 61 if err != nil { 62 return err 63 } 64 return nil 65} 66 67// T translates a message ID to the current language 68func T(messageID string, templateData map[string]string) string { 69 result, err := localizer.Localize(&i18n.LocalizeConfig{ 70 MessageID: messageID, 71 TemplateData: templateData, 72 }) 73 if err != nil { 74 log.Printf("Failed to localize message: %s", err) 75 return messageID + "*" 76 } 77 return result 78} 79 80// getPreferredLanguage determines the user's preferred language using go-locale 81func getPreferredLanguage() string { 82 lang, err := locale.GetLocale() 83 if err != nil { 84 log.Printf("Failed to get preferred language, defaulting to English: %s", err) 85 return "en" 86 } 87 88 // Normalize the language code 89 lang = strings.Split(lang, ".")[0] // Remove encoding part 90 lang = strings.ReplaceAll(lang, "_", "-") 91 92 return lang 93} 94