diff --git a/pkg/schema/localizer/localizer.go b/pkg/schema/localizer/localizer.go
index a818f6e922993330ea0c4bca396b5a51c49bec37..0d1ddabec5bc5be09fb0cbd0ff9c4e83272b4baa 100644
--- a/pkg/schema/localizer/localizer.go
+++ b/pkg/schema/localizer/localizer.go
@@ -12,25 +12,39 @@ import (
 )
 
 type Localizer struct {
-	Schema   *schema.Schema
-	Locales  map[string]*locales.Locale
-	LocaleID string
+	schema           *schema.Schema
+	localesKV        map[string]*locales.Locale
+	locales          []*locales.Locale
+	localeID         string
+	allowNoPublished bool
+	allowDisabled    bool
+}
+
+type Config struct {
+	Schema           *schema.Schema
+	Locales          []*locales.Locale
+	LocaleID         string
+	AllowNoPublished bool
+	AllowDisabled    bool
 }
 
 // NewLocalizer создает экземпляр локализатора. Требуется указать "загруженную" схему
-func NewLocalizer(s *schema.Schema, locs []*locales.Locale, localeID string) *Localizer {
-	if localeID == "" {
-		localeID = locales.DefaultID
+func NewLocalizer(cfg Config) *Localizer {
+	if cfg.LocaleID == "" {
+		cfg.LocaleID = locales.DefaultID
 	}
 
 	loc := &Localizer{
-		Schema:   s,
-		Locales:  make(map[string]*locales.Locale, len(locs)),
-		LocaleID: localeID,
+		schema:           cfg.Schema,
+		localesKV:        make(map[string]*locales.Locale, len(cfg.Locales)),
+		locales:          cfg.Locales,
+		localeID:         cfg.LocaleID,
+		allowDisabled:    cfg.AllowDisabled,
+		allowNoPublished: cfg.AllowNoPublished,
 	}
 
-	for _, l := range locs {
-		loc.Locales[l.ID] = l
+	for _, l := range cfg.Locales {
+		loc.localesKV[l.ID] = l
 	}
 
 	return loc
@@ -43,15 +57,15 @@ func NewLocalizer(s *schema.Schema, locs []*locales.Locale, localeID string) *Lo
 // При отсутствии каких-либо полей в переводе на `localeID` данные берутся сначала из fallback-локали,
 // если перевод отсутствует то из `data`
 func (l *Localizer) Localize(data map[string]interface{}, translations map[string]map[string]interface{}) (localized map[string]interface{}, err error) {
-	if l.LocaleID == locales.DefaultID {
-		return data, nil
-	}
-
 	target, fallback, err := l.getTargetAndFallBackLocales()
 	if err != nil {
 		return nil, err
 	}
 
+	if target.IsDefault() {
+		return data, nil
+	}
+
 	// localize fallback -> target
 	fallbackData := data
 	var exist bool
@@ -75,15 +89,15 @@ func (l *Localizer) Localize(data map[string]interface{}, translations map[strin
 // ExtractTranslation Получить "просеянные" данные для локали localeID: все поля, значения которых совпадают
 // с переводом на fallback-локаль или основными данными, удаляются из перевода
 func (l *Localizer) ExtractTranslation(data map[string]interface{}, translations map[string]map[string]interface{}) (translation map[string]interface{}, err error) {
-	if l.LocaleID == locales.DefaultID {
-		return data, nil
-	}
-
 	target, fallback, err := l.getTargetAndFallBackLocales()
 	if err != nil {
 		return nil, err
 	}
 
+	if target.IsDefault() {
+		return data, nil
+	}
+
 	fallbackData := data
 	var exist bool
 	if !fallback.IsDefault() {
@@ -100,13 +114,46 @@ func (l *Localizer) ExtractTranslation(data map[string]interface{}, translations
 	return l.extractTranslation(translation, fallbackData)
 }
 
+func (l *Localizer) locale(localeID string) (loc *locales.Locale, err error) {
+	if localeID == "" {
+		return nil, locales.ErrLocaleIDRequired
+	}
+
+	var exist bool
+	if loc, exist = l.localesKV[localeID]; !exist {
+		return nil, locales.ErrNotFound
+	}
+
+	if loc == nil {
+		return nil, locales.ErrNotFound
+	}
+
+	if !l.allowDisabled && loc.Disabled {
+		return nil, errors.New("locale is disabled")
+	}
+
+	if !l.allowNoPublished && localeID == l.localeID && loc.NoPublish { // can use non-publishing locale for fallback
+		return nil, errors.New("localizer not configured for non-publishing locales")
+	}
+
+	return
+}
+
+func (l *Localizer) Locale() (loc *locales.Locale, err error) {
+	return l.locale(l.localeID)
+}
+
+func (l *Localizer) Locales() []*locales.Locale {
+	return l.locales
+}
+
 func (l *Localizer) getTargetAndFallBackLocales() (target, fallback *locales.Locale, err error) {
-	if target = l.Locales[l.LocaleID]; target == nil || target.Disabled {
+	if target, err = l.locale(l.localeID); err != nil {
 		return nil, nil, errors.New("target locale not found or disabled")
 	}
 
-	if fallback = l.Locales[target.Fallback]; fallback == nil || fallback.Disabled {
-		fallback = l.Locales[locales.DefaultID]
+	if fallback, err = l.locale(target.Fallback); err != nil {
+		fallback = l.localesKV[locales.DefaultID]
 	}
 	return
 }
@@ -116,7 +163,7 @@ func (l *Localizer) localize(target, fallback map[string]interface{}) (map[strin
 		return nil, nil
 	}
 
-	single := l.Schema.GetFields(func(f *field.Field, p string) bool {
+	single := l.schema.GetFields(func(f *field.Field, p string) bool {
 		return f.SingleLocale
 	})
 
@@ -125,7 +172,7 @@ func (l *Localizer) localize(target, fallback map[string]interface{}) (map[strin
 		cfg.Fields[sn.Path] = walk.FieldConfig{Fn: walk.KeepSrc}
 	}
 
-	w := walk.NewWalker(l.Schema, cfg)
+	w := walk.NewWalker(l.schema, cfg)
 	w.DefaultFn = localize
 
 	res, _, err := w.DataWalk(context.Background(), target, fallback)
@@ -145,7 +192,7 @@ func (l *Localizer) extractTranslation(target, fallback map[string]interface{})
 		return nil, nil
 	}
 
-	single := l.Schema.GetFields(func(f *field.Field, p string) bool {
+	single := l.schema.GetFields(func(f *field.Field, p string) bool {
 		return f.SingleLocale
 	})
 
@@ -154,7 +201,7 @@ func (l *Localizer) extractTranslation(target, fallback map[string]interface{})
 		cfg.Fields[sn.Path] = walk.FieldConfig{Fn: walk.RemoveValue}
 	}
 
-	w := walk.NewWalker(l.Schema, cfg)
+	w := walk.NewWalker(l.schema, cfg)
 	w.DefaultFn = extractTranslation
 
 	res, _, err := w.DataWalk(context.Background(), target, fallback)
diff --git a/pkg/schema/localizer/localizer_test.go b/pkg/schema/localizer/localizer_test.go
index 6f5fbdd687bb5d613f18fb039340a9489f5aaf9c..23e6f0fdad2440f3102f481ce410bb29a5acc190 100644
--- a/pkg/schema/localizer/localizer_test.go
+++ b/pkg/schema/localizer/localizer_test.go
@@ -355,7 +355,7 @@ func TestLocalizer_localize(t *testing.T) {
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
 			l := &Localizer{
-				Schema: s,
+				schema: s,
 			}
 			got, err := l.localize(tt.target, tt.fallback)
 			if !tt.wantErr {
@@ -598,7 +598,7 @@ func TestLocalizer_deLocalize(t *testing.T) {
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
 			l := &Localizer{
-				Schema: s,
+				schema: s,
 			}
 			got, err := l.extractTranslation(tt.target, tt.fallback)
 			if !tt.wantErr {