Use the theme domain
Catalog layout
- One directory per language, named with the
xx-XXcode. - The file is always
theme.po. - The header sets
X-Domain: theme.
static/locale/de-DE/LC_MESSAGES/theme.po
Extract strings
Run the console commands from the Aikeedo installation, pointing at your theme’s repository:theme domain.
The starter kit used to ship its own extraction script. It was removed: use these console commands, which share the application’s parser and won’t mangle quoting.
Translate
--force to redo existing translations, and --dry-run to preview. Review the output before release: marketing copy is where machine translation is weakest.
Working on the installed copy
Point--path at your repository, not at extra/extensions/.... The installed copy is overwritten by the next build, so edits there are lost.
When a language shows English
The theme’s language is resolved from the URL prefix, then the user’s preference, then thelocale cookie, then the browser’s Accept-Language, then the default. Three things must line up:
The language is enabled in Settings → Languages.
Your theme has a
theme.po for it.The string uses the
theme domain.locale global is null, which is why every template should use locale.code|default('en-US').
Translating JavaScript strings
Strings that only exist in the browser go through the theme’s own small helper, which reads a catalog exposed aswindow.locale. Prefer translating in Twig and passing the result into your component, and keep the JavaScript path for strings built at runtime.
RTL languages
Each locale carries adir. Set it on the document and use logical CSS properties so layouts mirror correctly:
Checklist
Every visible string uses a
d-prefixed helper with the theme domain.Contexts are used for short strings such as buttons and headings.
Catalogs exist for the languages you support, with
X-Domain: theme.Extraction was re-run after the last copy change.
static/locale/ is included in your release archive.The layout handles
dir and a null locale.