package httpapi import ( "net/http" "strings" "github.com/descrybe/descrybe-v2/apps/api/internal/i18n" ) // localeResponseWriter carries the resolved UI/API locale for Error()/CodedError. type localeResponseWriter struct { http.ResponseWriter locale string } func (w *localeResponseWriter) Locale() string { return w.locale } func (w *localeResponseWriter) Unwrap() http.ResponseWriter { return w.ResponseWriter } type localeCarrier interface { Locale() string } type responseUnwrapper interface { Unwrap() http.ResponseWriter } func localeOf(w http.ResponseWriter) string { for w != nil { if lc, ok := w.(localeCarrier); ok { return lc.Locale() } uw, ok := w.(responseUnwrapper) if !ok { break } w = uw.Unwrap() } return i18n.Default } // Locale resolves Accept-Language into a supported UI locale, stores it on the // request context and ResponseWriter, and sets Vary: Accept-Language. func Locale(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { lang := i18n.Resolve(r.Header.Get("Accept-Language")) ctx := i18n.WithLocale(r.Context(), lang) if v := w.Header().Get("Vary"); v == "" { w.Header().Set("Vary", "Accept-Language") } else if !containsCSVToken(v, "Accept-Language") { w.Header().Set("Vary", v+", Accept-Language") } next.ServeHTTP(&localeResponseWriter{ResponseWriter: w, locale: lang}, r.WithContext(ctx)) }) } func containsCSVToken(header, token string) bool { for _, part := range strings.Split(header, ",") { if strings.TrimSpace(part) == token { return true } } return false }