A theme owns its own strings. Every piece of text a section renders through the t filter — and every editor-facing setting label — comes from locale files the theme ships in its bundle. The platform provides the mechanism (the files' contract, the t filter, the editor lookup); the theme author provides the strings. Platform locale files are never involved: your theme's text is yours to write and yours to translate.
The file layout#
locales/
en.json storefront strings — what {{ 'key' | t }} renders
en.schema.json editor labels — what the merchant sees on your settings
fr.json
fr.schema.json
de.json
de.schema.json
Two files per locale, both flat JSON objects of string → string.
{
"add_to_cart": "Add to cart",
"sold_out": "Sold out",
"greeting": "Welcome back, {{ name }}!"
}
Keys are yours to name (dots are allowed in keys — "cart.title" is one flat key, not nesting). Values are strings; a value may contain {{ placeholder }} slots filled by t's named arguments.
Resolution#
For a buyer whose locale is L, {{ 'key' | t }} resolves in exactly this order: 1) locales/L.json — the buyer's locale, if the theme ships it; 2) locales/<default_locale>.json — the theme's declared default; 3) neither has the key → the literal text "translation missing: L.key" renders. The marker is deliberate: a missing string is visible in preview and review instead of silently blank, and a shipped store never crashes over a translation. Ship your default-locale file complete; add other locales as you translate them — a locale you don't ship simply falls back to your default.
Merchant overrides#
Merchants can override the value of any string from their admin without touching your theme — the platform stores those overrides separately and layers them over your files at render. Your files stay pristine (a theme update never fights a merchant's wording), and the keys are always yours: merchants can reword what you declared, never add or remove strings. If you remove a key in an update, any override of it simply stops applying.
Theme text in section settings#
A text, textarea or richtext setting in a section or block can hold "@t:
// sections/hero: schema setting
{ "id": "heading", "type": "text", "default": "@t:hero.heading", "editor": { "label": "Heading" } }
// templates/home.json
{ "type": "hero", "position": 0, "settings": { "heading": "@t:hero.heading", "blocks": [] } }
// locales/en.json locales/de.json
{ "hero.heading": "New in" } { "hero.heading": "Neu eingetroffen" }
// section template: print the setting as usual
<h2>{{ settings.heading }}</h2>
In the theme editor the merchant sees the string in the language they are editing. Editing it replaces the reference with their own text, which is then their content: they translate it with the editor's language selector like any other text, and a theme update no longer changes it. Until then, rewording the string in your locale files rewords every store that has not edited it. The setting arrives in the template as plain text, so print it directly rather than adding a default filter. References are not available in theme settings (config/settings_schema.json and presets), and app blocks never resolve them.
Validation at import#
Rule |
|
|---|---|
1 |
Every file under locales/ must parse as flat string-to-string JSON. |
2 |
File names must be a valid locale followed by .json or .schema.json, directly under locales/. |
3 |
For each namespace present, the package must include the matching default-locale file. For example, shipping fr.schema.json requires <default_locale>.schema.json. |
4 |
Every "@t: |
5 |
A string with plural forms (key.one, key.few and so on) also defines key.other in the same file, the form every language has. |
6 |
When the theme ships editor translation files, each of them names everything the editor shows: every section and preset name (sectionName. |
Currency and language formatting: the currency determines precision; the active shopper language/locale determines digits, separators, grouping and symbol placement. French can display INR zero as 0,00 ₹ without changing the currency. General number-format preferences apply to merchant presentation, not this shopper formatting. See the formatting guide, currency precision table, and language and RTL examples.