package middleware import ( "strings" "fotbal-club/internal/models" "fotbal-club/pkg/database" "github.com/gin-gonic/gin" "gorm.io/gorm" ) // I18nMiddleware handles internationalization type I18nMiddleware struct { db *gorm.DB defaultLang *models.Language } // NewI18nMiddleware creates a new i18n middleware func NewI18nMiddleware() (*I18nMiddleware, error) { db := database.GetDB() // Get default language defaultLang, err := models.GetDefaultLanguage(db) if err != nil { return nil, err } return &I18nMiddleware{ db: db, defaultLang: defaultLang, }, nil } // Middleware returns the Gin middleware function func (m *I18nMiddleware) Middleware() gin.HandlerFunc { return func(c *gin.Context) { // Try to get language from various sources in priority order // 1. User preference (if authenticated) if userID, exists := c.Get("user_id"); exists { if userPref, err := m.getUserLanguage(userID.(uint)); err == nil { c.Set("language", userPref.LanguageCode) c.Set("language_name", userPref.Language.Name) c.Next() return } } // 2. URL parameter (?lang=en) if lang := c.Query("lang"); lang != "" && m.isValidLanguage(lang) { c.Set("language", lang) c.Set("language_name", m.getLanguageName(lang)) c.Next() return } // 3. Cookie if cookie, err := c.Cookie("lang"); err == nil && m.isValidLanguage(cookie) { c.Set("language", cookie) c.Set("language_name", m.getLanguageName(cookie)) c.Next() return } // 4. Accept-Language header if header := c.GetHeader("Accept-Language"); header != "" { if lang := m.parseAcceptLanguage(header); lang != "" { c.Set("language", lang) c.Set("language_name", m.getLanguageName(lang)) c.Next() return } } // 5. Default language c.Set("language", m.defaultLang.Code) c.Set("language_name", m.defaultLang.Name) c.Next() } } // getUserLanguage gets user's preferred language from database func (m *I18nMiddleware) getUserLanguage(userID uint) (*models.UserLanguagePreference, error) { var pref models.UserLanguagePreference err := m.db.Where("user_id = ?", userID).Preload("Language").First(&pref).Error return &pref, err } // isValidLanguage checks if language code is valid and active func (m *I18nMiddleware) isValidLanguage(code string) bool { var count int64 m.db.Model(&models.Language{}).Where("code = ? AND is_active = ?", code, true).Count(&count) return count > 0 } // getLanguageName returns the name of a language func (m *I18nMiddleware) getLanguageName(code string) string { var lang models.Language err := m.db.Where("code = ?", code).First(&lang).Error if err != nil { return m.defaultLang.Name } return lang.Name } // parseAcceptLanguage parses Accept-Language header and returns best match func (m *I18nMiddleware) parseAcceptLanguage(header string) string { // Simple implementation - split by comma and take first // In production, you'd want to parse q-values langs := strings.Split(header, ",") for _, lang := range langs { lang = strings.TrimSpace(strings.Split(lang, ";")[0]) // Convert en-US to en, de-DE to de, etc. if len(lang) > 2 { lang = lang[:2] } if m.isValidLanguage(lang) { return lang } } return "" } // GetLanguage returns the current language code from context func GetLanguage(c *gin.Context) string { if lang, exists := c.Get("language"); exists { return lang.(string) } return "cs" // fallback to Czech } // GetLanguageName returns the current language name from context func GetLanguageName(c *gin.Context) string { if name, exists := c.Get("language_name"); exists { return name.(string) } return "Čeština" } // SetLanguageCookie sets the language preference in a cookie func SetLanguageCookie(c *gin.Context, languageCode string) { c.SetCookie("lang", languageCode, 365*24*60*60, "/", "", false, true) } // TranslationHelper provides translation functions type TranslationHelper struct { db *gorm.DB } // NewTranslationHelper creates a new translation helper func NewTranslationHelper() *TranslationHelper { return &TranslationHelper{ db: database.GetDB(), } } // T translates a key using the current language context func (th *TranslationHelper) T(c *gin.Context, key string) string { lang := GetLanguage(c) translation, err := models.GetTranslationWithFallback(th.db, key, lang) if err != nil { // Return key if translation not found return key } return translation.Value } // TWithParams translates a key with parameters func (th *TranslationHelper) TWithParams(c *gin.Context, key string, params map[string]interface{}) string { result := th.T(c, key) // Simple parameter replacement for k, v := range params { result = strings.ReplaceAll(result, "{{"+k+"}}", v.(string)) } return result }