package i18n import ( "strings" "github.com/labstack/echo/v4" "github.com/nicksnyder/go-i18n/v2/i18n" "golang.org/x/text/language" ) const ( // LocalizerKey is the key used to store the localizer in Echo context LocalizerKey = "i18n_localizer" // LocaleKey is the key used to store the detected locale in Echo context LocaleKey = "i18n_locale" ) // Middleware returns an Echo middleware that detects the user's preferred language // from the Accept-Language header and stores a localizer in the context func Middleware() echo.MiddlewareFunc { return func(next echo.HandlerFunc) echo.HandlerFunc { return func(c echo.Context) error { // Get Accept-Language header acceptLang := c.Request().Header.Get("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) return next(c) } } } // 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 Echo context func GetLocalizer(c echo.Context) *i18n.Localizer { localizer := c.Get(LocalizerKey) if localizer != nil { if l, ok := localizer.(*i18n.Localizer); ok { return l } } return NewLocalizer(DefaultLanguage) } // GetLocale retrieves the detected locale from the Echo context func GetLocale(c echo.Context) string { locale := c.Get(LocaleKey) if locale != nil { if l, ok := locale.(string); ok { return l } } return DefaultLanguage } // LocalizedError returns a localized error message func LocalizedError(c echo.Context, messageID string, templateData map[string]interface{}) string { return T(GetLocalizer(c), messageID, templateData) } // LocalizedMessage returns a localized message func LocalizedMessage(c echo.Context, messageID string) string { return TSimple(GetLocalizer(c), messageID) } // LocalizedMessageWithData returns a localized message with template data func LocalizedMessageWithData(c echo.Context, messageID string, templateData map[string]interface{}) string { return T(GetLocalizer(c), messageID, templateData) }