Skip to content

Locales

locales/<language>.json holds the text the theme prints. One file is the default (en.default.json); keys missing from another language fall back to it.

locales/en.default.json
{
"products": {
"add_to_cart": "Add to cart",
"low_stock": "Only {{ count }} left",
"reviews_html": "<strong>{{ rating }}</strong> out of 5"
},
"cart": { "count": { "one": "{{ count }} item", "other": "{{ count }} items" } }
}
{{ 'products.add_to_cart' | t }}
{{ 'products.low_stock' | t: count: variant.inventory_quantity }}
{{ 'cart.count' | t: count: cart.item_count }}
  • Variables are passed as name: value and written {{ name }} in the text. Their values are escaped.
  • HTML: only keys ending in _html may contain markup; other values are escaped.
  • Plurals: give an object of plural forms and pass count. English uses one and other; Arabic uses zero, one, two, few, many and other, picked by the CLDR rules:
locales/ar.json
{ "cart": { "count": {
"zero": "لا منتجات", "one": "منتج واحد", "two": "منتجان",
"few": "{{ count }} منتجات", "many": "{{ count }} منتجاً", "other": "{{ count }} منتج"
} } }

A missing key shows translation missing: ar.cart.count in the page, so it’s easy to spot in previews.

Schema names and labels can be translated keys: "label": "t:settings.cart_type". They’re read from locales/<language>.schema.json, shown in the merchant’s admin language.

Merchants can change any storefront text, per language, in Storefront › Translate › Theme texts, without editing files. Their wording wins over the locale files and survives theme updates.

locales/<language>.content.json translates the sample text a theme ships in its templates and section groups (headings, announcement text). When a merchant adds that language, the translations are offered as a starting point. Keys are paths to settings; values are [source, translation]:

locales/ar.content.json
{ "sections/footer-group.json/sections/footer/blocks/shop/settings/heading": ["Shop", "تسوّق"] }

Was this page helpful?