package i18n import ( "strings" "github.com/gin-gonic/gin" "github.com/nicksnyder/go-i18n/v2/i18n" "golang.org/x/text/language" ) const ( // LocalizerKey is the key used to store the localizer in Gin context LocalizerKey = "i18n_localizer" // LocaleKey is the key used to store the detected locale in Gin context LocaleKey = "i18n_locale" ) // Middleware returns a Gin middleware that detects the user's preferred language // from the Accept-Language header and stores a localizer in the context func Middleware() gin.HandlerFunc { return func(c *gin.Context) { // Get Accept-Language header acceptLang := c.GetHeader("Accept-Language") // Parse the preferred languages langs := parseAcceptLanguage(acceptLang) // Create localizer with the preferred languages localizer := NewLocalizer(langs...) // Determine the best matched locale for storage locale := matchLocale(langs) // Store in context c.Set(LocalizerKey, localizer) c.Set(LocaleKey, locale) c.Next() } } // parseAcceptLanguage parses the Accept-Language header and returns a slice of language tags func parseAcceptLanguage(header string) []string { if header == "" { return []string{DefaultLanguage} } // Parse using golang.org/x/text/language tags, _, err := language.ParseAcceptLanguage(header) if err != nil || len(tags) == 0 { return []string{DefaultLanguage} } // Convert to string slice and normalize langs := make([]string, 0, len(tags)) for _, tag := range tags { base, _ := tag.Base() lang := strings.ToLower(base.String()) // Only add supported languages for _, supported := range SupportedLanguages { if lang == supported { langs = append(langs, lang) break } } } // If no supported languages found, use default if len(langs) == 0 { return []string{DefaultLanguage} } return langs } // matchLocale returns the best matching locale from the provided languages func matchLocale(langs []string) string { for _, lang := range langs { for _, supported := range SupportedLanguages { if lang == supported { return supported } } } return DefaultLanguage } // GetLocalizer retrieves the localizer from the Gin context func GetLocalizer(c *gin.Context) *i18n.Localizer { if localizer, exists := c.Get(LocalizerKey); exists { if l, ok := localizer.(*i18n.Localizer); ok { return l } } return NewLocalizer(DefaultLanguage) } // GetLocale retrieves the detected locale from the Gin context func GetLocale(c *gin.Context) string { if locale, exists := c.Get(LocaleKey); exists { if l, ok := locale.(string); ok { return l } } return DefaultLanguage } // LocalizedError returns a localized error message func LocalizedError(c *gin.Context, messageID string, templateData map[string]interface{}) string { return T(GetLocalizer(c), messageID, templateData) } // LocalizedMessage returns a localized message func LocalizedMessage(c *gin.Context, messageID string) string { return TSimple(GetLocalizer(c), messageID) } // LocalizedMessageWithData returns a localized message with template data func LocalizedMessageWithData(c *gin.Context, messageID string, templateData map[string]interface{}) string { return T(GetLocalizer(c), messageID, templateData) }