fix: use a single translator for middleware (#10633)

# Which Problems Are Solved

Comparing the v3 and v4 deployments we noticed an increase in memory
usage. A first analysis revealed that it might be related to the
(multiple) initialization of the `i18n.Translator`, partially related

# How the Problems Are Solved

Initialize the tranlator once (apart from the translator interceptor,
which uses context / request specific information) and pass it to all
necessary middleware.

# Additional Changes

Removed unnecessary error return parameter from the translator
initialization.

# Additional Context

- noticed internally
- backport to v4.x
This commit is contained in:
Livio Spring
2025-09-09 08:34:59 +02:00
committed by GitHub
parent 79809d0199
commit a0c3ccecf7
19 changed files with 118 additions and 106 deletions

View File

@@ -24,6 +24,7 @@ import (
"github.com/zitadel/saml/pkg/provider"
"golang.org/x/net/http2"
"golang.org/x/net/http2/h2c"
"golang.org/x/text/language"
"github.com/zitadel/zitadel/cmd/build"
"github.com/zitadel/zitadel/cmd/encryption"
@@ -438,7 +439,22 @@ func startAPIs(
http_util.WithMaxAge(int(math.Floor(config.Quotas.Access.ExhaustedCookieMaxAge.Seconds()))),
)
limitingAccessInterceptor := middleware.NewAccessInterceptor(accessSvc, exhaustedCookieHandler, &config.Quotas.Access.AccessConfig)
apis, err := api.New(ctx, config.Port, router, queries, verifier, config.SystemAuthZ, config.InternalAuthZ, tlsConfig, config.ExternalDomain, append(config.InstanceHostHeaders, config.PublicHostHeaders...), limitingAccessInterceptor, keys.Target)
translator := i18n.NewZitadelTranslator(language.English)
apis, err := api.New(
ctx,
config.Port,
router,
queries,
verifier,
config.SystemAuthZ,
config.InternalAuthZ,
tlsConfig,
config.ExternalDomain,
append(config.InstanceHostHeaders, config.PublicHostHeaders...),
limitingAccessInterceptor,
keys.Target,
translator,
)
if err != nil {
return nil, fmt.Errorf("error creating api %w", err)
}
@@ -541,9 +557,22 @@ func startAPIs(
return nil, err
}
instanceInterceptor := middleware.InstanceInterceptor(queries, config.ExternalDomain, login.IgnoreInstanceEndpoints...)
instanceInterceptor := middleware.InstanceInterceptor(queries, config.ExternalDomain, translator, login.IgnoreInstanceEndpoints...)
assetsCache := middleware.AssetsCacheInterceptor(config.AssetStorage.Cache.MaxAge, config.AssetStorage.Cache.SharedMaxAge)
apis.RegisterHandlerOnPrefix(assets.HandlerPrefix, assets.NewHandler(commands, verifier, config.SystemAuthZ, config.InternalAuthZ, id.SonyFlakeGenerator(), store, queries, middleware.CallDurationHandler, instanceInterceptor.Handler, assetsCache.Handler, limitingAccessInterceptor.Handle))
apis.RegisterHandlerOnPrefix(assets.HandlerPrefix, assets.NewHandler(
commands,
verifier,
config.SystemAuthZ,
config.InternalAuthZ,
id.SonyFlakeGenerator(),
store,
queries,
middleware.CallDurationHandler,
instanceInterceptor.Handler,
assetsCache.Handler,
limitingAccessInterceptor.Handle,
translator,
))
federatedLogoutsCache, err := connector.StartCache[federatedlogout.Index, string, *federatedlogout.FederatedLogout](ctx, []federatedlogout.Index{federatedlogout.IndexRequestID}, cache.PurposeFederatedLogout, cacheConnectors.Config.FederatedLogouts, cacheConnectors)
if err != nil {
@@ -609,6 +638,7 @@ func startAPIs(
verifier,
keys.User,
&config.SCIM,
translator,
instanceInterceptor.HandlerFuncWithError,
middleware.AuthorizationInterceptor(verifier, config.SystemAuthZ, config.InternalAuthZ).HandlerFuncWithError))

View File

@@ -23,6 +23,7 @@ import (
http_mw "github.com/zitadel/zitadel/internal/api/http/middleware"
"github.com/zitadel/zitadel/internal/api/ui/login"
"github.com/zitadel/zitadel/internal/crypto"
"github.com/zitadel/zitadel/internal/i18n"
"github.com/zitadel/zitadel/internal/query"
"github.com/zitadel/zitadel/internal/telemetry/metrics"
"github.com/zitadel/zitadel/internal/telemetry/tracing"
@@ -51,6 +52,7 @@ type API struct {
connectServices map[string][]string
targetEncryptionAlgorithm crypto.EncryptionAlgorithm
translator *i18n.Translator
}
func (a *API) ListGrpcServices() []string {
@@ -103,6 +105,7 @@ func New(
hostHeaders []string,
accessInterceptor *http_mw.AccessInterceptor,
targetEncryptionAlgorithm crypto.EncryptionAlgorithm,
translator *i18n.Translator,
) (_ *API, err error) {
api := &API{
port: port,
@@ -117,9 +120,10 @@ func New(
systemAuthZ: systemAuthz,
connectServices: make(map[string][]string),
targetEncryptionAlgorithm: targetEncryptionAlgorithm,
translator: translator,
}
api.grpcServer = server.CreateServer(api.verifier, systemAuthz, authZ, queries, externalDomain, tlsConfig, accessInterceptor.AccessService(), targetEncryptionAlgorithm)
api.grpcServer = server.CreateServer(api.verifier, systemAuthz, authZ, queries, externalDomain, tlsConfig, accessInterceptor.AccessService(), targetEncryptionAlgorithm, api.translator)
api.grpcGateway, err = server.CreateGateway(ctx, port, hostHeaders, accessInterceptor, tlsConfig)
if err != nil {
return nil, err
@@ -188,7 +192,7 @@ func (a *API) registerConnectServer(service server.ConnectServer) {
connect_middleware.CallDurationHandler(),
connect_middleware.MetricsHandler(metricTypes, grpc_api.Probes...),
connect_middleware.NoCacheInterceptor(),
connect_middleware.InstanceInterceptor(a.queries, a.externalDomain, system_pb.SystemService_ServiceDesc.ServiceName, healthpb.Health_ServiceDesc.ServiceName),
connect_middleware.InstanceInterceptor(a.queries, a.externalDomain, a.translator, system_pb.SystemService_ServiceDesc.ServiceName, healthpb.Health_ServiceDesc.ServiceName),
connect_middleware.AccessStorageInterceptor(a.accessInterceptor.AccessService()),
connect_middleware.ErrorHandler(),
connect_middleware.LimitsInterceptor(system_pb.SystemService_ServiceDesc.ServiceName),

View File

@@ -13,7 +13,6 @@ import (
"github.com/gabriel-vasile/mimetype"
"github.com/gorilla/mux"
"github.com/zitadel/logging"
"golang.org/x/text/language"
"github.com/zitadel/zitadel/internal/api/authz"
http_util "github.com/zitadel/zitadel/internal/api/http"
@@ -94,9 +93,17 @@ func DefaultErrorHandler(translator *i18n.Translator) func(w http.ResponseWriter
}
}
func NewHandler(commands *command.Commands, verifier authz.APITokenVerifier, systemAuthCOnfig authz.Config, authConfig authz.Config, idGenerator id.Generator, storage static.Storage, queries *query.Queries, callDurationInterceptor, instanceInterceptor, assetCacheInterceptor, accessInterceptor func(handler http.Handler) http.Handler) http.Handler {
translator, err := i18n.NewZitadelTranslator(language.English)
logging.OnError(err).Panic("unable to get translator")
func NewHandler(
commands *command.Commands,
verifier authz.APITokenVerifier,
systemAuthCOnfig authz.Config,
authConfig authz.Config,
idGenerator id.Generator,
storage static.Storage,
queries *query.Queries,
callDurationInterceptor, instanceInterceptor, assetCacheInterceptor, accessInterceptor func(handler http.Handler) http.Handler,
translator *i18n.Translator,
) http.Handler {
h := &Handler{
commands: commands,
errorHandler: DefaultErrorHandler(translator),

View File

@@ -8,7 +8,6 @@ import (
"connectrpc.com/connect"
"github.com/zitadel/logging"
"golang.org/x/text/language"
"github.com/zitadel/zitadel/internal/api/authz"
zitadel_http "github.com/zitadel/zitadel/internal/api/http"
@@ -18,9 +17,7 @@ import (
object_v3 "github.com/zitadel/zitadel/pkg/grpc/object/v3alpha"
)
func InstanceInterceptor(verifier authz.InstanceVerifier, externalDomain string, explicitInstanceIdServices ...string) connect.UnaryInterceptorFunc {
translator, err := i18n.NewZitadelTranslator(language.English)
logging.OnError(err).Panic("unable to get translator")
func InstanceInterceptor(verifier authz.InstanceVerifier, externalDomain string, translator *i18n.Translator, explicitInstanceIdServices ...string) connect.UnaryInterceptorFunc {
return func(handler connect.UnaryFunc) connect.UnaryFunc {
return func(ctx context.Context, req connect.AnyRequest) (connect.AnyResponse, error) {
return setInstance(ctx, req, handler, verifier, externalDomain, translator, explicitInstanceIdServices...)

View File

@@ -4,7 +4,6 @@ import (
"context"
"connectrpc.com/connect"
"github.com/zitadel/logging"
"github.com/zitadel/zitadel/internal/api/authz"
"github.com/zitadel/zitadel/internal/i18n"
@@ -21,17 +20,11 @@ func TranslationHandler() connect.UnaryInterceptorFunc {
defer func() { span.EndWithError(err) }()
if err != nil {
translator, translatorError := getTranslator(ctx)
if translatorError != nil {
return resp, err
}
translator := getTranslator(ctx)
return resp, translateError(ctx, err, translator)
}
if loc, ok := resp.Any().(localizers); ok {
translator, translatorError := getTranslator(ctx)
if translatorError != nil {
return resp, err
}
translator := getTranslator(ctx)
translateFields(ctx, loc, translator)
}
return resp, nil
@@ -39,10 +32,6 @@ func TranslationHandler() connect.UnaryInterceptorFunc {
}
}
func getTranslator(ctx context.Context) (*i18n.Translator, error) {
translator, err := i18n.NewZitadelTranslator(authz.GetInstance(ctx).DefaultLanguage())
if err != nil {
logging.New().WithError(err).Error("could not load translator")
}
return translator, err
func getTranslator(ctx context.Context) *i18n.Translator {
return i18n.NewZitadelTranslator(authz.GetInstance(ctx).DefaultLanguage())
}

View File

@@ -7,7 +7,6 @@ import (
"strings"
"github.com/zitadel/logging"
"golang.org/x/text/language"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
@@ -24,9 +23,7 @@ const (
HTTP1Host = "x-zitadel-http1-host"
)
func InstanceInterceptor(verifier authz.InstanceVerifier, externalDomain string, explicitInstanceIdServices ...string) grpc.UnaryServerInterceptor {
translator, err := i18n.NewZitadelTranslator(language.English)
logging.OnError(err).Panic("unable to get translator")
func InstanceInterceptor(verifier authz.InstanceVerifier, externalDomain string, translator *i18n.Translator, explicitInstanceIdServices ...string) grpc.UnaryServerInterceptor {
return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
return setInstance(ctx, req, info, handler, verifier, externalDomain, translator, explicitInstanceIdServices...)
}

View File

@@ -3,7 +3,6 @@ package middleware
import (
"context"
"github.com/zitadel/logging"
"google.golang.org/grpc"
"github.com/zitadel/zitadel/internal/api/authz"
@@ -19,27 +18,17 @@ func TranslationHandler() func(ctx context.Context, req interface{}, info *grpc.
defer func() { span.EndWithError(err) }()
if loc, ok := resp.(localizers); ok && resp != nil {
translator, translatorError := getTranslator(ctx)
if translatorError != nil {
return resp, err
}
translator := getTranslator(ctx)
translateFields(ctx, loc, translator)
}
if err != nil {
translator, translatorError := getTranslator(ctx)
if translatorError != nil {
return resp, err
}
translator := getTranslator(ctx)
err = translateError(ctx, err, translator)
}
return resp, err
}
}
func getTranslator(ctx context.Context) (*i18n.Translator, error) {
translator, err := i18n.NewZitadelTranslator(authz.GetInstance(ctx).DefaultLanguage())
if err != nil {
logging.New().WithError(err).Error("could not load translator")
}
return translator, err
func getTranslator(ctx context.Context) *i18n.Translator {
return i18n.NewZitadelTranslator(authz.GetInstance(ctx).DefaultLanguage())
}

View File

@@ -15,6 +15,7 @@ import (
grpc_api "github.com/zitadel/zitadel/internal/api/grpc"
"github.com/zitadel/zitadel/internal/api/grpc/server/middleware"
"github.com/zitadel/zitadel/internal/crypto"
"github.com/zitadel/zitadel/internal/i18n"
"github.com/zitadel/zitadel/internal/logstore"
"github.com/zitadel/zitadel/internal/logstore/record"
"github.com/zitadel/zitadel/internal/query"
@@ -62,6 +63,7 @@ func CreateServer(
tlsConfig *tls.Config,
accessSvc *logstore.Service[*record.AccessLog],
targetEncAlg crypto.EncryptionAlgorithm,
translator *i18n.Translator,
) *grpc.Server {
metricTypes := []metrics.MetricType{metrics.MetricTypeTotalCount, metrics.MetricTypeRequestCount, metrics.MetricTypeStatusCode}
serverOptions := []grpc.ServerOption{
@@ -70,7 +72,7 @@ func CreateServer(
middleware.CallDurationHandler(),
middleware.MetricsHandler(metricTypes, grpc_api.Probes...),
middleware.NoCacheInterceptor(),
middleware.InstanceInterceptor(queries, externalDomain, system_pb.SystemService_ServiceDesc.ServiceName, healthpb.Health_ServiceDesc.ServiceName),
middleware.InstanceInterceptor(queries, externalDomain, translator, system_pb.SystemService_ServiceDesc.ServiceName, healthpb.Health_ServiceDesc.ServiceName),
middleware.AccessStorageInterceptor(accessSvc),
middleware.ErrorHandler(),
middleware.LimitsInterceptor(system_pb.SystemService_ServiceDesc.ServiceName),

View File

@@ -8,7 +8,6 @@ import (
"strings"
"github.com/zitadel/logging"
"golang.org/x/text/language"
"github.com/zitadel/zitadel/internal/api/authz"
zitadel_http "github.com/zitadel/zitadel/internal/api/http"
@@ -24,12 +23,12 @@ type instanceInterceptor struct {
translator *i18n.Translator
}
func InstanceInterceptor(verifier authz.InstanceVerifier, externalDomain string, ignoredPrefixes ...string) *instanceInterceptor {
func InstanceInterceptor(verifier authz.InstanceVerifier, externalDomain string, translator *i18n.Translator, ignoredPrefixes ...string) *instanceInterceptor {
return &instanceInterceptor{
verifier: verifier,
externalDomain: externalDomain,
ignoredPrefixes: ignoredPrefixes,
translator: newZitadelTranslator(),
translator: translator,
}
}
@@ -99,9 +98,3 @@ func setInstance(ctx context.Context, verifier authz.InstanceVerifier) (_ contex
span.End()
return authz.WithInstance(ctx, instance), nil
}
func newZitadelTranslator() *i18n.Translator {
translator, err := i18n.NewZitadelTranslator(language.English)
logging.OnError(err).Panic("unable to get translator")
return translator
}

View File

@@ -16,6 +16,7 @@ import (
zitadel_http "github.com/zitadel/zitadel/internal/api/http"
"github.com/zitadel/zitadel/internal/execution/target"
"github.com/zitadel/zitadel/internal/feature"
"github.com/zitadel/zitadel/internal/i18n"
)
func Test_instanceInterceptor_Handler(t *testing.T) {
@@ -70,7 +71,7 @@ func Test_instanceInterceptor_Handler(t *testing.T) {
t.Run(tt.name, func(t *testing.T) {
a := &instanceInterceptor{
verifier: tt.fields.verifier,
translator: newZitadelTranslator(),
translator: i18n.NewZitadelTranslator(language.English),
}
next := &testHandler{}
got := a.HandlerFunc(next)
@@ -134,7 +135,7 @@ func Test_instanceInterceptor_HandlerFunc(t *testing.T) {
t.Run(tt.name, func(t *testing.T) {
a := &instanceInterceptor{
verifier: tt.fields.verifier,
translator: newZitadelTranslator(),
translator: i18n.NewZitadelTranslator(language.English),
}
next := &testHandler{}
got := a.HandlerFunc(next)
@@ -197,7 +198,7 @@ func Test_instanceInterceptor_HandlerFuncWithError(t *testing.T) {
t.Run(tt.name, func(t *testing.T) {
a := &instanceInterceptor{
verifier: tt.fields.verifier,
translator: newZitadelTranslator(),
translator: i18n.NewZitadelTranslator(language.English),
}
var ctx context.Context
got := a.HandlerFuncWithError(func(w http.ResponseWriter, r *http.Request) error {

View File

@@ -16,12 +16,14 @@ import (
"github.com/zitadel/zitadel/internal/api/scim/metadata"
"github.com/zitadel/zitadel/internal/api/scim/schemas"
"github.com/zitadel/zitadel/internal/api/scim/serrors"
"github.com/zitadel/zitadel/internal/i18n"
"github.com/zitadel/zitadel/internal/zerrors"
)
type BulkHandler struct {
cfg *scim_config.BulkConfig
handlersByPluralResourceName map[schemas.ScimResourceTypePlural]RawResourceHandlerAdapter
translator *i18n.Translator
}
type BulkRequest struct {
@@ -56,6 +58,7 @@ func (r *BulkRequest) GetSchemas() []schemas.ScimSchemaType {
func NewBulkHandler(
cfg scim_config.BulkConfig,
translator *i18n.Translator,
handlers ...RawResourceHandlerAdapter,
) *BulkHandler {
handlersByPluralResourceName := make(map[schemas.ScimResourceTypePlural]RawResourceHandlerAdapter, len(handlers))
@@ -66,6 +69,7 @@ func NewBulkHandler(
return &BulkHandler{
&cfg,
handlersByPluralResourceName,
translator,
}
}
@@ -140,7 +144,7 @@ func (h *BulkHandler) processOperation(ctx context.Context, op *BulkRequestOpera
opResp.Status = strconv.Itoa(statusCode)
if err != nil {
opResp.Error = serrors.MapToScimError(ctx, err)
opResp.Error = serrors.MapToScimError(ctx, h.translator, err)
opResp.Status = opResp.Error.Status
}
}()

View File

@@ -9,7 +9,6 @@ import (
"strconv"
"github.com/zitadel/logging"
"golang.org/x/text/language"
http_util "github.com/zitadel/zitadel/internal/api/http"
zhttp_middleware "github.com/zitadel/zitadel/internal/api/http/middleware"
@@ -67,24 +66,22 @@ const (
ScimTypeUniqueness scimErrorType = "uniqueness"
)
var translator *i18n.Translator
func ErrorHandler(translator *i18n.Translator) func(next zhttp_middleware.HandlerFuncWithError) http.Handler {
return func(next zhttp_middleware.HandlerFuncWithError) http.Handler {
var err error
func ErrorHandler(next zhttp_middleware.HandlerFuncWithError) http.Handler {
var err error
translator, err = i18n.NewZitadelTranslator(language.English)
logging.OnError(err).Panic("unable to get translator")
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if err = next(w, r); err == nil {
return
}
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if err = next(w, r); err == nil {
return
}
scimErr := MapToScimError(r.Context(), translator, err)
w.WriteHeader(scimErr.StatusCode)
scimErr := MapToScimError(r.Context(), err)
w.WriteHeader(scimErr.StatusCode)
jsonErr := json.NewEncoder(w).Encode(scimErr)
logging.OnError(jsonErr).Warn("Failed to marshal scim error response")
})
jsonErr := json.NewEncoder(w).Encode(scimErr)
logging.OnError(jsonErr).Warn("Failed to marshal scim error response")
})
}
}
func ThrowInvalidValue(parent error) error {
@@ -146,7 +143,7 @@ func (err *wrappedScimError) Error() string {
return fmt.Sprintf("SCIM Error: %s: %s", err.ScimType, err.Parent.Error())
}
func MapToScimError(ctx context.Context, err error) *ScimError {
func MapToScimError(ctx context.Context, translator *i18n.Translator, err error) *ScimError {
scimError := new(ScimError)
if ok := errors.As(err, &scimError); ok {
return scimError
@@ -154,7 +151,7 @@ func MapToScimError(ctx context.Context, err error) *ScimError {
scimWrappedError := new(wrappedScimError)
if ok := errors.As(err, &scimWrappedError); ok {
mappedErr := MapToScimError(ctx, scimWrappedError.Parent)
mappedErr := MapToScimError(ctx, translator, scimWrappedError.Parent)
if scimWrappedError.ScimType != "" {
mappedErr.ScimType = scimWrappedError.ScimType
}

View File

@@ -7,6 +7,7 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"golang.org/x/text/language"
"github.com/zitadel/zitadel/internal/i18n"
"github.com/zitadel/zitadel/internal/zerrors"
@@ -97,9 +98,10 @@ func TestErrorHandler(t *testing.T) {
t.Run(tt.name, func(t *testing.T) {
req := httptest.NewRequest("GET", "/", nil)
recorder := httptest.NewRecorder()
ErrorHandler(func(http.ResponseWriter, *http.Request) error {
return tt.err
}).ServeHTTP(recorder, req)
ErrorHandler(i18n.NewZitadelTranslator(language.English))(
func(http.ResponseWriter, *http.Request) error {
return tt.err
}).ServeHTTP(recorder, req)
assert.Equal(t, tt.wantStatus, recorder.Code)
if tt.wantBody != "" {

View File

@@ -18,6 +18,7 @@ import (
"github.com/zitadel/zitadel/internal/api/scim/serrors"
"github.com/zitadel/zitadel/internal/command"
"github.com/zitadel/zitadel/internal/crypto"
"github.com/zitadel/zitadel/internal/i18n"
"github.com/zitadel/zitadel/internal/query"
)
@@ -27,10 +28,11 @@ func NewServer(
verifier *authz.ApiTokenVerifier,
userCodeAlg crypto.EncryptionAlgorithm,
config *sconfig.Config,
translator *i18n.Translator,
middlewares ...zhttp_middlware.MiddlewareWithErrorFunc,
) http.Handler {
verifier.RegisterServer("SCIM-V2", schemas.HandlerPrefix, AuthMapping)
return buildHandler(command, query, userCodeAlg, config, middlewares...)
return buildHandler(command, query, userCodeAlg, config, translator, middlewares...)
}
func buildHandler(
@@ -38,16 +40,17 @@ func buildHandler(
query *query.Queries,
userCodeAlg crypto.EncryptionAlgorithm,
cfg *sconfig.Config,
translator *i18n.Translator,
middlewares ...zhttp_middlware.MiddlewareWithErrorFunc,
) http.Handler {
router := mux.NewRouter()
middleware := buildMiddleware(cfg, query, middlewares)
middleware := buildMiddleware(cfg, query, translator, middlewares)
usersHandler := sresources.NewResourceHandlerAdapter(sresources.NewUsersHandler(command, query, userCodeAlg, cfg))
mapResource(router, middleware, usersHandler)
bulkHandler := sresources.NewBulkHandler(cfg.Bulk, usersHandler)
bulkHandler := sresources.NewBulkHandler(cfg.Bulk, translator, usersHandler)
router.Handle("/"+zhttp.OrgIdInPathVariable+"/Bulk", middleware(handleJsonResponse(bulkHandler.BulkFromHttp))).Methods(http.MethodPost)
serviceProviderHandler := newServiceProviderHandler(cfg, usersHandler)
@@ -60,11 +63,16 @@ func buildHandler(
return router
}
func buildMiddleware(cfg *sconfig.Config, query *query.Queries, middlewares []zhttp_middlware.MiddlewareWithErrorFunc) zhttp_middlware.ErrorHandlerFunc {
func buildMiddleware(
cfg *sconfig.Config,
query *query.Queries,
translator *i18n.Translator,
middlewares []zhttp_middlware.MiddlewareWithErrorFunc,
) zhttp_middlware.ErrorHandlerFunc {
// content type middleware needs to run at the very beginning to correctly set content types of errors
middlewares = append([]zhttp_middlware.MiddlewareWithErrorFunc{smiddleware.ContentTypeMiddleware}, middlewares...)
middlewares = append(middlewares, smiddleware.ScimContextMiddleware(query))
scimMiddleware := zhttp_middlware.ChainedWithErrorHandler(serrors.ErrorHandler, middlewares...)
scimMiddleware := zhttp_middlware.ChainedWithErrorHandler(serrors.ErrorHandler(translator), middlewares...)
return func(handler zhttp_middlware.HandlerFuncWithError) http.Handler {
return http.MaxBytesHandler(scimMiddleware(handler), cfg.MaxRequestBodySize)
}

View File

@@ -437,8 +437,7 @@ func (l *Login) getTranslator(ctx context.Context, authReq *domain.AuthRequest)
if err != nil {
logging.OnError(err).Warn("cannot load instance restrictions to retrieve allowed languages for creating the translator")
}
translator, err := l.renderer.NewTranslator(ctx, restrictions.AllowedLanguages)
logging.OnError(err).Warn("cannot load translator")
translator := l.renderer.NewTranslator(ctx, restrictions.AllowedLanguages)
if authReq != nil {
l.addLoginTranslations(translator, authReq.DefaultTranslations)
l.addLoginTranslations(translator, authReq.OrgTranslations)

View File

@@ -31,7 +31,7 @@ func init() {
}
}
func newBundle(ns Namespace, defaultLanguage language.Tag, allowedLanguages []language.Tag) (*i18n.Bundle, error) {
func newBundle(ns Namespace, defaultLanguage language.Tag, allowedLanguages []language.Tag) *i18n.Bundle {
bundle := i18n.NewBundle(defaultLanguage)
for lang, file := range translationMessages[ns] {
@@ -41,7 +41,7 @@ func newBundle(ns Namespace, defaultLanguage language.Tag, allowedLanguages []la
bundle.MustAddMessages(lang, file.Messages...)
}
return bundle, nil
return bundle
}
func loadTranslationsFromNamespace(ns Namespace) {

View File

@@ -32,32 +32,28 @@ type Message struct {
}
// NewZitadelTranslator translates to all supported languages, as the ZITADEL texts are not customizable.
func NewZitadelTranslator(defaultLanguage language.Tag) (*Translator, error) {
func NewZitadelTranslator(defaultLanguage language.Tag) *Translator {
return newTranslator(ZITADEL, defaultLanguage, SupportedLanguages(), "")
}
func NewNotificationTranslator(defaultLanguage language.Tag, allowedLanguages []language.Tag) (*Translator, error) {
func NewNotificationTranslator(defaultLanguage language.Tag, allowedLanguages []language.Tag) *Translator {
return newTranslator(NOTIFICATION, defaultLanguage, allowedLanguages, "")
}
func NewLoginTranslator(defaultLanguage language.Tag, allowedLanguages []language.Tag, cookieName string) (*Translator, error) {
func NewLoginTranslator(defaultLanguage language.Tag, allowedLanguages []language.Tag, cookieName string) *Translator {
return newTranslator(LOGIN, defaultLanguage, allowedLanguages, cookieName)
}
func newTranslator(ns Namespace, defaultLanguage language.Tag, allowedLanguages []language.Tag, cookieName string) (*Translator, error) {
func newTranslator(ns Namespace, defaultLanguage language.Tag, allowedLanguages []language.Tag, cookieName string) *Translator {
t := new(Translator)
var err error
t.allowedLanguages = allowedLanguages
if len(t.allowedLanguages) == 0 {
t.allowedLanguages = SupportedLanguages()
}
t.bundle, err = newBundle(ns, defaultLanguage, t.allowedLanguages)
if err != nil {
return nil, err
}
t.bundle = newBundle(ns, defaultLanguage, t.allowedLanguages)
t.cookieHandler = http_util.NewCookieHandler()
t.cookieName = cookieName
return t, nil
return t
}
func (t *Translator) SupportedLanguages() []language.Tag {

View File

@@ -14,10 +14,7 @@ func (n *NotificationQueries) GetTranslatorWithOrgTexts(ctx context.Context, org
if err != nil {
return nil, err
}
translator, err := i18n.NewNotificationTranslator(n.GetDefaultLanguage(ctx), restrictions.AllowedLanguages)
if err != nil {
return nil, err
}
translator := i18n.NewNotificationTranslator(n.GetDefaultLanguage(ctx), restrictions.AllowedLanguages)
allCustomTexts, err := n.CustomTextListByTemplate(ctx, authz.GetInstance(ctx).InstanceID(), textType, false)
if err != nil {

View File

@@ -43,7 +43,7 @@ func (r *Renderer) RenderTemplate(w http.ResponseWriter, req *http.Request, tran
}
}
func (r *Renderer) NewTranslator(ctx context.Context, allowedLanguages []language.Tag) (*i18n.Translator, error) {
func (r *Renderer) NewTranslator(ctx context.Context, allowedLanguages []language.Tag) *i18n.Translator {
return i18n.NewLoginTranslator(authz.GetInstance(ctx).DefaultLanguage(), allowedLanguages, r.cookieName)
}