package detect import ( "net/http" "strings" ) /* NewHttpDetector initializes new language detector */ func NewHttpDetector(languages []string, path string, maxAge int) func(http.ResponseWriter, *http.Request) string { const cookieName = "lang" if len(languages) == 0 { panic("empty languages list") } /* initialize state */ defaultLang := strings.ToLower(languages[0]) langSet := make(map[string]struct{}, len(languages)) for _, lang := range languages { langSet[strings.ToLower(lang)] = struct{}{} } /* detectLanguage returns a language string */ return func(w http.ResponseWriter, r *http.Request) string { /* check for query language override */ if lang := strings.ToLower(r.URL.Query().Get(cookieName)); lang != "" { if _, ok := langSet[lang]; ok { /* language provided by query string, enforce it and send cookie */ http.SetCookie(w, &http.Cookie{ Name: cookieName, Value: lang, Path: path, HttpOnly: true, SameSite: http.SameSiteLaxMode, Secure: r.TLS != nil, MaxAge: maxAge, }) return lang } } /* check for cookie preferences */ cookie, err := r.Cookie(cookieName) if err == nil { cookieLang := strings.ToLower(cookie.Value) if _, ok := langSet[cookieLang]; ok { return cookieLang } } /* fall back to browser preferences */ acceptLanguage := strings.ToLower(r.Header.Get("Accept-Language")) parts := strings.Split(acceptLanguage, ",") for _, part := range parts { part = strings.TrimSpace(part) if part == "" { continue } /* cut off ";q=..." */ if idx := strings.IndexByte(part, ';'); idx >= 0 { part = part[:idx] } /* try exact match first */ if _, ok := langSet[part]; ok { return part } /* try base language */ if i := strings.IndexByte(part, '-'); i >= 0 { base := part[:i] if _, ok := langSet[base]; ok { return base } } } return defaultLang } }