verstak-sync-server/internal/server/web_locale.go

72 lines
2.0 KiB
Go

package server
import (
"net/http"
"strings"
)
const webLocaleCookieName = "verstak_locale"
func isSupportedWebLocale(locale string) bool {
return locale == "en" || locale == "ru"
}
// resolveWebLocale has a deliberately small, documented locale model. The
// cookie is a user preference; "system" delegates to Accept-Language, then
// the configured server default, and finally English.
func resolveWebLocale(r *http.Request, cfg *Config) string {
configured := "en"
if cfg != nil && isSupportedWebLocale(cfg.Web.DefaultLocale) {
configured = cfg.Web.DefaultLocale
}
if cookie, err := r.Cookie(webLocaleCookieName); err == nil {
switch cookie.Value {
case "ru", "en":
return cookie.Value
case "system":
if locale := localeFromAcceptLanguage(r.Header.Get("Accept-Language")); locale != "" {
return locale
}
return configured
default:
return configured
}
}
if locale := localeFromAcceptLanguage(r.Header.Get("Accept-Language")); locale != "" {
return locale
}
return configured
}
func localeFromAcceptLanguage(header string) string {
for _, part := range strings.Split(header, ",") {
language := strings.ToLower(strings.TrimSpace(strings.SplitN(part, ";", 2)[0]))
if language == "ru" || strings.HasPrefix(language, "ru-") {
return "ru"
}
if language == "en" || strings.HasPrefix(language, "en-") {
return "en"
}
}
return ""
}
func (s *Server) webLocale(r *http.Request) string {
return resolveWebLocale(r, s.cfg)
}
func (s *Server) webLocalePreference(r *http.Request) string {
if cookie, err := r.Cookie(webLocaleCookieName); err == nil && (cookie.Value == "ru" || cookie.Value == "en" || cookie.Value == "system") {
return cookie.Value
}
return "system"
}
func (s *Server) setWebLocale(w http.ResponseWriter, r *http.Request, locale string) {
secure := s.requestIsHTTPS(r)
http.SetCookie(w, &http.Cookie{
Name: webLocaleCookieName, Value: locale, Path: "/", HttpOnly: true,
Secure: secure, SameSite: http.SameSiteLaxMode, MaxAge: 365 * 24 * 60 * 60,
})
}