Files
MyClub/internal/middleware/i18n.go
T
Tomas Dvorak dfc079288f hot fix #1
2026-01-26 08:13:18 +01:00

182 lines
4.7 KiB
Go

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
}