Files

65 lines
1.6 KiB
Go
Raw Permalink Normal View History

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
}