Localization
Finqu themes support multiple languages through JSON files in the locales/ directory.
Storefront translations
Each language needs a locale file:
locales/
en.json
fi.json
sv.jsonUse translation keys in your Liquid templates:
{{ 'general.add_to_cart' | t }}Keys are nested in the JSON file:
{
"general": {
"add_to_cart": "Add to cart"
}
}The active language comes from the customer’s locale (request.locale).
Schema translations
Section, block, and setting labels shown in the theme designer can be translated separately from storefront copy using schema locale files:
locales/
en.json
en.schema.json
fi.json
fi.schema.jsonAt runtime, schema translations are merged into the corresponding locale for the storefront. You do not need to duplicate schema labels inside fi.json unless the same string is also used on the storefront.
Translation keys (t:)
In schema JSON (sections, blocks, settings_schema.json, and settings_data.json), reference schema locale files with a t: prefix:
{
"type": "checkbox",
"id": "showPromotion",
"label": "t:blocks.product-title-price.settings.showPromotion.label"
}The path after t: maps to nested keys in {lang}.schema.json using dot notation:
{
"blocks": {
"product-title-price": {
"settings": {
"showPromotion": {
"label": "Näytä tarjous"
}
}
}
}
}Rules:
- Use nested JSON objects, not flat keys like
"blocks.foo.label": "...". - Keys are case-sensitive —
product-templateandPRODUCT-TEMPLATEare different paths. - If a key is missing in the active language, Finqu falls back to
en.schema.json. - On the storefront,
t:values are resolved when Liquid reads setting values. - In the theme designer,
t:values are resolved when schemas and preset data are loaded for the active preview language.
Inline localization objects
You can also localize schema labels inline with language-keyed objects:
{% schema %}
{
"name": {
"en": "Hero banner",
"fi": "Hero-banneri"
},
"settings": [
{
"type": "text",
"id": "heading",
"label": {
"en": "Heading",
"fi": "Otsikko"
}
}
]
}
{% endschema %}Both formats work in the designer:
You can mix both in the same theme.
What is translated in the designer
The theme designer resolves schema translations for the preview language (language picker in the designer navbar, stored in the fnq-designer-locale cookie). When the preview language changes, section, block, and theme labels reload in that language.
Presets
Presets ship default configuration for themes, sections, and blocks. To target different markets, define full preset content per locale — not just translated labels.
Finqu resolves presets for the active language:
- Storefront — customer’s locale (
request.locale) - Designer — preview language from the navbar (
fnq-designer-localecookie)
Resolution order: active locale → default → first available entry.
Preset settings can include rich text, images, block instances, and layout values. Values inside presets can also use t: keys; those resolve when the preset is loaded for the active language.
Locale-keyed preset maps
The primary format groups preset variants by locale code:
"presets": {
"fi": [
{
"name": "t:sections.hero.presets.default.name",
"settings": {
"heading": "Tervetuloa",
"body": "<p>Suomenkielinen rich text -sisältö</p>"
}
}
],
"default": [
{
"name": "Default hero",
"settings": {
"heading": "Welcome",
"body": "<p>English rich text content</p>"
}
}
]
}When a Finnish customer views the storefront, Finqu uses the fi preset settings. Other locales fall back to default.
You can also use a flat array when one configuration is enough for all languages:
"presets": [
{
"name": "t:sections.two-columns.presets.columns-2.name",
"settings": {
"left_column_width": 50,
"right_column_width": 50
}
}
]Theme-level presets
Whole-store style variants live in config/settings_data.json. Each preset can include locale-specific snapshots:
{
"presets": {
"minimal": {
"id": "minimal",
"name": "t:presets.minimal.name",
"default": {
"settings": { },
"templates": { },
"sections": [ ]
},
"fi": {
"settings": { },
"templates": { },
"sections": [ ]
}
}
}
}When a merchant picks or previews a theme preset, Finqu loads the snapshot for the active locale. Preset names still resolve via t: keys or inline { en, fi } objects:
{
"presets": {
"minimal": {
"name": "Minimalistinen"
}
}
}Section and block schema presets
Section and block schemas use locale-keyed preset maps to ship market-specific defaults — copy, rich text, images, and layout together:
{% schema %}
{
"name": "t:sections.footer.name",
"presets": {
"fi": [
{
"settings": {
"heading": "Ota yhteyttä",
"body": "<p>Suomenkielinen sisältö</p>"
}
}
],
"default": [
{
"settings": {
"heading": "Contact us",
"body": "<p>English content</p>"
}
}
]
}
}
{% endschema %}When a merchant adds the section or block, the designer applies the preset for the current preview language.
For multiple layout variants within one locale, each locale entry is an array of preset objects:
"presets": {
"default": [
{
"name": "Columns 2",
"settings": { "left_column_width": 50 }
},
{
"name": "Columns 3",
"settings": { "left_column_width": 33 }
}
],
"fi": [
{
"name": "Sarakkeet 2",
"settings": { "left_column_width": 50 }
},
{
"name": "Sarakkeet 3",
"settings": { "left_column_width": 33 }
}
]
}Setting-level presets
Theme settings with style-editor or style-picker can wrap style presets by locale:
{
"type": "style-editor",
"id": "buttons",
"presets": {
"fi": {
"primary": {
"name": "t:settings.buttons.presets.primary.name",
"default": {
"border_radius": 0
}
}
},
"default": {
"primary": {
"name": "Primary",
"default": {
"border_radius": 4
}
}
}
}
}Or use a single id-keyed map when styles are the same across markets:
{
"type": "style-editor",
"id": "buttons",
"presets": {
"primary": {
"name": "t:settings.buttons.presets.primary.name",
"default": { }
}
}
}Example locales/fi.schema.json
{
"sections": {
"hero": {
"name": "Hero-banneri",
"settings": {
"heading": {
"label": "Otsikko"
}
}
},
"product-template": {
"name": "Tuotesivu"
}
},
"blocks": {
"product-page-title": {
"name": "Tuotteen otsikko",
"settings": {
"showVendor": {
"label": "Näytä valmistaja"
}
}
}
},
"presets": {
"minimal": {
"name": "Minimalistinen"
}
}
}Referenced from schema as:
"name": "t:sections.hero.name""label": "t:blocks.product-page-title.settings.showVendor.label""name": "t:presets.minimal.name"
Best practices
- Keep storefront copy in
{lang}.jsonand designer labels in{lang}.schema.jsonor inline schema objects. - Use locale-keyed preset maps (
fi,default, etc.) to ship market-specific defaults — rich text, images, and layout together. - Prefer
t:keys inside presetnamefields and{lang}.schema.jsonwhen labels repeat across locales. - Use inline
{ en, fi }objects for small schemas or few labels. - Ship a locale file for every language your theme claims to support.
- Use the same language codes as your store’s enabled locales (
en,fi,sv, etc.). - Keep translation key paths stable — use preset slugs and setting ids, not array indexes, in
t:paths where possible. - Test the designer with the preview language picker, not only the merchant UI language.
- Test the storefront with the store locale picker or
localizationform on a deployed store.