- principalFrom sets PreferredLocale from metadata admin_locale; personal API token principals clear it, so token clients keep the request locale - the guarded admin group runs locale.from-principal after the backend guard, overriding the LocaleResolver or Accept-Language locale - GET /lang honours a supported ?locale= and reports meta.locales (cabana.LangEnvelope, cabana.LangMeta) - Docker test for the override, refusals and /lang; docs and OpenAPI
35 lines
1.2 KiB
Go
35 lines
1.2 KiB
Go
package cabana
|
|
|
|
import (
|
|
"net/http"
|
|
"slices"
|
|
)
|
|
|
|
// adminLangPrefix is the only namespace the public bundle serves (D-20).
|
|
const adminLangPrefix = "backend::lang."
|
|
|
|
// langBundle serves GET {prefix}/api/v1/lang: every backend::lang key as CLDR
|
|
// forms for the request locale, with the fallback locale's keys underneath.
|
|
// A locale query parameter naming a supported admin locale (one of
|
|
// Translator.Locales(adminLangPrefix)) replaces the request locale; any other
|
|
// value is ignored. meta.locales lists the supported admin locales. It is
|
|
// public (the login screen needs it) and never includes another namespace.
|
|
func (s *service) langBundle(w http.ResponseWriter, r *http.Request) {
|
|
tr := s.translator()
|
|
locales := tr.Locales(adminLangPrefix)
|
|
if locales == nil {
|
|
locales = []string{}
|
|
}
|
|
locale := schemaLocale(r.Context(), tr)
|
|
if requested := r.URL.Query().Get("locale"); requested != "" && slices.Contains(locales, requested) {
|
|
locale = requested
|
|
}
|
|
data := map[string]map[string]string{}
|
|
if tr != nil {
|
|
locale = tr.Resolved(locale, adminLangPrefix)
|
|
data = tr.Bundle(locale, adminLangPrefix)
|
|
}
|
|
w.Header().Set("Cache-Control", "no-cache")
|
|
WriteData(w, http.StatusOK, data, map[string]any{"locale": locale, "locales": locales})
|
|
}
|