snapshot of https://github.com/cortezaproject/corteza.git (2024.9.x, 2026-09-18; blobs > 131072B omitted)
Some checks failed
SonarQube / SonarQube (push) Failing after 5m28s
E2e test on main branch push / server and client test (map[name:admin port:8080]) (push) Failing after 3m33s
Server and lib tests / Library test (js) (push) Failing after 1m36s
Server and lib tests / Library test (vue) (push) Successful in 2m24s
Server and lib tests / Web client test (admin) (push) Successful in 2m52s
Server and lib tests / Web client test (compose) (push) Successful in 3m23s
Server and lib tests / Web client test (discovery) (push) Successful in 2m49s
Server and lib tests / Web client test (one) (push) Successful in 2m52s
Server and lib tests / Web client test (privacy) (push) Successful in 2m44s
Server and lib tests / Web client test (reporter) (push) Successful in 2m56s
Server and lib tests / Web client test (workflow) (push) Successful in 3m0s
Server and lib tests / Server tests (push) Failing after 4m55s
E2e test on main branch push / notify-failure (push) Failing after 9s
Server and lib tests / Send matrix testing notification (push) Successful in 2s
Mark stale issues and pull requests / stale (push) Successful in 40s
Some checks failed
SonarQube / SonarQube (push) Failing after 5m28s
E2e test on main branch push / server and client test (map[name:admin port:8080]) (push) Failing after 3m33s
Server and lib tests / Library test (js) (push) Failing after 1m36s
Server and lib tests / Library test (vue) (push) Successful in 2m24s
Server and lib tests / Web client test (admin) (push) Successful in 2m52s
Server and lib tests / Web client test (compose) (push) Successful in 3m23s
Server and lib tests / Web client test (discovery) (push) Successful in 2m49s
Server and lib tests / Web client test (one) (push) Successful in 2m52s
Server and lib tests / Web client test (privacy) (push) Successful in 2m44s
Server and lib tests / Web client test (reporter) (push) Successful in 2m56s
Server and lib tests / Web client test (workflow) (push) Successful in 3m0s
Server and lib tests / Server tests (push) Failing after 4m55s
E2e test on main branch push / notify-failure (push) Failing after 9s
Server and lib tests / Send matrix testing notification (push) Successful in 2s
Mark stale issues and pull requests / stale (push) Successful in 40s
This commit is contained in:
132
server/pkg/locale/http.go
Normal file
132
server/pkg/locale/http.go
Normal file
@@ -0,0 +1,132 @@
|
||||
package locale
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"go.uber.org/zap"
|
||||
"golang.org/x/text/language"
|
||||
)
|
||||
|
||||
const AcceptLanguageHeader = "Accept-Language"
|
||||
const ContentLanguageHeader = "Content-Language"
|
||||
|
||||
func DetectLanguage(ll *service) func(next http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
var ctx = r.Context()
|
||||
|
||||
// resolve accept-language header
|
||||
// Accept-Language specifies the language of the response payload.
|
||||
ctx = SetAcceptLanguageToContext(ctx, resolveAcceptLanguageHeaders(r, ll))
|
||||
|
||||
// resolve content-language header
|
||||
// Content-Language specifies the language of the request payload.
|
||||
ctx = SetContentLanguageToContext(ctx, resolveContentLanguageHeaders(r.Header, ll))
|
||||
|
||||
next.ServeHTTP(w, r.WithContext(ctx))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// reads Content-Language headers from the request and returns
|
||||
// parsed value as language.Tag
|
||||
//
|
||||
// There are 4 valid scenarios for :
|
||||
// - lang == 'skip': returns und & services will (likely) ignore all translatable content
|
||||
// - invalid language: (same as skip)
|
||||
// - valid language: returns valid language; services will treat translatable content from the payload as translations
|
||||
// - no header: returns default language; (same as valid language)
|
||||
func resolveContentLanguageHeaders(h http.Header, ll *service) language.Tag {
|
||||
if ll == nil || ll.Default() == nil {
|
||||
return language.Und
|
||||
}
|
||||
|
||||
var cLang = h.Get(ContentLanguageHeader)
|
||||
|
||||
if cLang == "" {
|
||||
return ll.Default().Tag
|
||||
}
|
||||
|
||||
if cLang == "skip" {
|
||||
// more than 1 header or value equal to skip
|
||||
return language.Und
|
||||
}
|
||||
|
||||
if tag, err := language.Parse(cLang); err != nil {
|
||||
return language.Und
|
||||
} else {
|
||||
return tag
|
||||
}
|
||||
}
|
||||
|
||||
func resolveAcceptLanguageHeaders(r *http.Request, ll *service) (tag language.Tag) {
|
||||
if ll == nil || ll.Default() == nil {
|
||||
// locale service does not have anything loaded...
|
||||
return language.Und
|
||||
}
|
||||
|
||||
if ll.opt.DevelopmentMode {
|
||||
if err := ll.ReloadStatic(); err != nil {
|
||||
// when in development mode, refresh languages for every request
|
||||
ll.log.Error("failed to load locales", zap.Error(err))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
raw string
|
||||
)
|
||||
|
||||
// try to detect the language from the request's query string:
|
||||
if ll.opt.QueryStringParam != "" {
|
||||
raw = r.URL.Query().Get(ll.opt.QueryStringParam)
|
||||
}
|
||||
|
||||
// try to detect the language from the request's headers:
|
||||
if len(raw) == 0 {
|
||||
raw = r.Header.Get(AcceptLanguageHeader)
|
||||
}
|
||||
|
||||
if len(raw) == 0 {
|
||||
// no need for lang detection
|
||||
return ll.Default().Tag
|
||||
}
|
||||
|
||||
// parse & ignore errors
|
||||
var (
|
||||
preferred = ll.Default().Tag
|
||||
supported = ll.Tags()
|
||||
|
||||
accepted, _, err = language.ParseAcceptLanguage(raw)
|
||||
)
|
||||
|
||||
if err == nil {
|
||||
// ignoring index & confidence
|
||||
preferred, _, _ = language.NewMatcher(supported).Match(accepted...)
|
||||
|
||||
var match bool
|
||||
for _, s := range supported {
|
||||
if s == preferred {
|
||||
match = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !match {
|
||||
base, _ := preferred.Base()
|
||||
preferred = language.MustParse(base.String())
|
||||
}
|
||||
}
|
||||
|
||||
if ll.opt.DevelopmentMode {
|
||||
ll.log.Debug(
|
||||
"language detected",
|
||||
zap.String("preferred", preferred.String()),
|
||||
zap.String("raw", raw),
|
||||
)
|
||||
}
|
||||
|
||||
// new request with new context
|
||||
return preferred
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user