Policy Response Localization
Nauthilus v4 keeps Policy localization inside the owning namespace. A rule selects a stable translation key and deterministic fallback; the HTTP, gRPC, or IdP response boundary resolves the final language.
Generation-owned catalogs
The effective catalog is the immutable combination of built-in system resources, startup Lua catalogs, and top-level Policy catalogs. Startup and system catalogs are restart-bound. A successful config reload replaces only the top-level Policy layer.
policy:
namespaces:
authn:
localization:
catalogs:
- namespace: company
language: en
entries:
policy.company.account_locked: Login failed because the account is locked.
A request uses the catalog captured by its active Policy generation. Failed reloads do not alter the active resolver.
Rule-selected response messages
policy:
namespaces:
authn:
policy_sets:
configured:
visibility: private
rules:
- name: deny_locked_account
checkpoint: auth_decision
actions: [authenticate]
if:
attribute: subject.account_locked
is: true
then:
decision: deny
response_marker: auth.response.fail
response_language:
from: attribute
attribute: request.language
fallback: en
response_message:
from: i18n
i18n_key: policy.company.account_locked
fallback: Login failed because the account is locked.
Keep the fallback safe for direct client display. A missing key, missing language, or invalid language candidate uses the fallback instead of exposing an internal lookup error.
Allowlisted language candidates
Do not expose arbitrary request data to Policy. Allowlist and normalize only the intended header or gRPC metadata key:
policy:
namespaces:
authn:
fact_sources:
http_headers:
- header: Accept-Language
attribute: request.language
visibility: public
normalize:
trim: true
case: lower
max_length: 32
grpc_metadata:
- key: x-response-language
attribute: request.language
visibility: public
normalize:
trim: true
case: lower
max_length: 32
The response rule still owns whether an allowlisted candidate becomes rendering metadata.
Startup Lua catalog overlays
Deployment-owned startup code may register immutable catalog entries:
nauthilus_i18n.register_catalog({
namespace = "company",
language = "en",
entries = {
["policy.company.account_locked"] = "Login failed because the account is locked.",
},
})
Request-time Lua should emit stable facts. Use nauthilus_i18n.get_localized(...) only for Lua-owned logs, notices, or fallback strings; final authentication responses should remain rule-selected so reports and all transports share one decision path.
Do not add deployment-only keys to Nauthilus system resource files. Keep them in deployment startup catalogs or top-level policy.namespaces.<namespace>.localization.catalogs.
See I18N Lua API, Policy Configuration, and the manual v4 migration contract.