kataras/iris · error

locales expected to be %d but %d parsed

Error message

locales expected to be %d but %d parsed

What it means

With LoaderConfig.Strict enabled, the KV loader requires that the number of parsed locales equals the number of languages registered in the Matcher. If fewer locales were stored than m.Languages, it returns "locales expected to be %d but %d parsed". It's a completeness check on translations.

Source

Thrown at i18n/loader.go:133

		for _, langIndex := range languageIndexes {
			if langIndex == -1 {
				// If loader has more languages than defined for use in New function,
				// e.g. when New(KV(m), "en-US") contains el-GR and en-US but only "en-US" passed.
				continue
			}

			kv := keyValuesMulti[langIndex]
			err := cat.Store(langIndex, kv)
			if err != nil {
				return nil, err
			}
		}

		if n := len(cat.Locales); n == 0 {
			return nil, fmt.Errorf("locales not found in map")
		} else if options.Strict && n < len(m.Languages) {
			return nil, fmt.Errorf("locales expected to be %d but %d parsed", len(m.Languages), n)
		}

		return cat, nil
	}
}

// DefaultLoaderConfig represents the default loader configuration.
var DefaultLoaderConfig = LoaderConfig{
	Left:               "{{",
	Right:              "}}",
	Strict:             false,
	DefaultMessageFunc: nil,
	PluralFormDecoder:  internal.DefaultPluralFormDecoder,
	Funcs:              nil,
}

// load accepts a list of filenames (physical or virtual),
// a function that should return the contents of a specific file

View on GitHub (pinned to 7bedaf55a0)

Solutions

  1. Add translation entries for every registered language in the LangMap.
  2. Pass only the languages you actually have translations for to New.
  3. Disable Strict (LoaderConfig{Strict: false}) if partial coverage is intentional.
  4. Check parseLanguageName behavior: ensure map keys parse to registered language tags.

Example fix

// before
i18n.KV(m, i18n.LoaderConfig{Strict: true}) // m missing el-GR
// after
m["el-GR"] = map[string]any{"hello": "Γειά"} // add missing locale
Defensive patterns

Strategy: validation

Validate before calling

// check coverage before strict load
registered := []string{"en-US", "el-GR"}
for _, lang := range registered {
    if _, ok := langMap[lang]; !ok {
        return fmt.Errorf("strict mode: missing translations for %s", lang)
    }
}

Try / catch

localizer, err := loader(matcher)
if err != nil && strings.Contains(err.Error(), "locales expected to be") {
    return fmt.Errorf("incomplete translations: %w", err) // or log and continue non-strict
}

Prevention

When it happens

Trigger: Loading with LoaderConfig{Strict: true} via i18n.KV while the langMap covers fewer languages than were registered (e.g. New(KV(m), "en-US", "el-GR") but the map only contains "en-US"), or some map keys failed to parse to a registered language (index -1 skipped).

Common situations: Gradually adding translations: new language registered in New but its translations not yet added to the map; Strict enabled for CI to enforce complete translations.

Related errors


AI-assisted analysis of kataras/iris@7bedaf55a0 (2026-08-30). Data as JSON: /api/errors/bd722046eabd5091. Report an issue: GitHub.