Localization (i18n)
Tiger never hardcodes a user-facing string. Everything is a semantic, owner-prefixed key, and the platform localizes for free.
Keys, not strings
Use a semantic key namespaced by owner: core.* (framework), app.* (your app), <module>.* (a
module), then .area.type.name:
billing.invoice.created
core.api.error.not_allowed
Strings live in plain PHP array files — <module>/languages/<lang>/<module>.php returning
['key' => 'text'] — cascading core → package modules → app modules → app global (last wins). In
views and forms use $this->_t('key'); API response messages translate automatically.
Language-only locales
Locales are language-only (en, es) — region subtags are reserved for genuine regional
divergence, not required up front.
Semantic locale URLs
/es/anything works on every route — the prefix is resolved and stripped before routing.
Resolution order is URL → cookie → browser → default, and the choice persists to a cookie (the
header language switcher writes the same cookie + localStorage).
Live overrides, no deploy
A translation DB table overrides or adds any string at request time — same live-override pattern
as config. Change a label for one org, or fix a typo in production, without a deploy.
See also
- Configuration — the same base-then-DB override shape.