i18n Locale Validation#
The i18n plugin's locale validation — checking that a requested locale code actually exists in the list of configured locales — is only applied to Content Manager routes via middleware. The public Content API and the document service do not perform this check, meaning callers can create or manage content under any syntactically valid (or even invalid) locale string without receiving an error.
Where Validation Lives: Content Manager Only#
validateLocaleCreation is a Koa middleware that intercepts POST / PUT requests, extracts the locale from the request query or body, and calls getValidLocale, which queries the database to confirm the locale is configured. If the locale is not found, it throws an ApplicationError("This locale doesn't exist") .
This middleware is registered in register.ts on exactly two route prefixes :
/content-manager/collection-types/:model/content-manager/single-types/:model
A code comment marks this as a known, intentional gap: // TODO: v5 if implemented in the CM => delete this middleware — the intent is to move this check to a more central layer, but that work has not been done.
What the Document Service Does Instead#
The document service's checkLocale function (in repository.ts) validates format only — it enforces BCP 47 syntax using the regex /^[a-zA-Z]{2,3}(-[a-zA-Z0-9]{2,8})*$/ with a 35-character max length . It does not look up the locale against the configured-locales table.
Even this format validation is gated behind the api.documents.strictParams config flag . When strictParams is false or unset (the default), locale values pass through completely unchecked at the document service layer.
The i18n transforms in internationalization.ts (defaultLocale, localeToLookup, localeToData) handle locale-to-query translation but perform no configured-locale validation . The defaultLocale transform will fall back to the system default locale if none is supplied, and localeToData only checks that the value is a non-wildcard string.
Gap Summary#
| Layer | Validates against configured locales? | Notes |
|---|---|---|
| Content Manager middleware | ✅ Yes | validateLocaleCreation → getValidLocale → DB lookup |
| Content API routes | ❌ No | Zod z.string() schema only; no existence check |
Document service (checkLocale) | ❌ No | BCP 47 format check only; gated by strictParams |
i18n transforms (localeToData etc.) | ❌ No | Translate params; do not validate existence |
Key Files#
| File | Role |
|---|---|
packages/plugins/i18n/server/src/controllers/validate-locale-creation.ts | The only place configured-locale validation is enforced |
packages/plugins/i18n/server/src/register.ts | Registers the middleware on CM routes only |
packages/plugins/i18n/server/src/services/content-types.ts | getValidLocale — the DB-backed locale existence check |
packages/core/core/src/services/document-service/repository.ts | checkLocale — format-only validation, strictParams-gated |
packages/core/core/src/services/document-service/internationalization.ts | i18n transforms applied during document service operations |