Skip to content

Localization (multi-language)

Hyprism ships with English (default) and German translations covering both the storefront (what customers see) and the theme editor (what merchants see when customizing). This chapter covers using the built-in locales, adding new languages, and the translation architecture.

Shopify themes have two parallel translation systems:

LayerWhat it translatesFile
StorefrontButtons, labels, messages visible to customerslocales/en.default.json, locales/de.json, locales/X.json
Theme editorSettings labels, info-text, dropdown options visible to merchantslocales/en.default.schema.json, locales/de.schema.json, locales/X.schema.json

The storefront locale is what controls what your customers read. The theme editor locale is what controls what you read when customizing the theme.

For most merchants, only the storefront matters. The theme-editor locale is automatically read based on the language setting of your Shopify Admin account.

  • All theme strings — error messages, button labels, empty-state copy, accessibility labels
  • All section settings — 2,809 customizer-schema keys, in a deduplicated namespace that re-uses common labels across sections. The English and German schema files carry exactly the same key count; the theme’s pre-push checks fail on a missing one.
  • All section names and presets — visible in the “Add section” picker
  1. Shopify Admin → Settings → Languages.
  2. Add language → German.
  3. Click Publish next to German.

The German storefront is now available. To make it the default for German-speaking visitors, configure Shopify Markets (per-country language preferences).

Switching between languages on the storefront

Section titled “Switching between languages on the storefront”

Hyprism’s footer-localization block (chapter 5) provides a language switcher. Add it to your footer to give visitors a UI to switch languages.

Alternatively, Shopify auto-detects browser language and redirects to the appropriate locale (if Markets is configured).

To add a new language (e.g., French, Spanish, Italian, Dutch, Portuguese):

Shopify Admin → Settings → Languages → Add language → pick the target.

The new language is “unpublished” — visitors can’t see it yet.

Two options:

Option A: use the Translate & Adapt app (recommended)

Shopify offers a free app called Translate & Adapt that translates your store content using machine translation, with optional manual review.

  1. Install Translate & Adapt from the Shopify App Store.
  2. Add your new language.
  3. The app translates products, collections, articles, pages, and theme strings automatically.
  4. Review and edit translations as needed.

Option B: edit JSON directly

For developers / advanced users:

  1. Create locales/{lang}.json (copy en.default.json as a starting point).
  2. Translate every value to the target language (the keys stay the same).
  3. Push to Shopify with shopify theme push.

Step 3: translate theme-editor strings (optional)

Section titled “Step 3: translate theme-editor strings (optional)”

If you want the theme editor to render in the new language too (for merchants who admin in that language):

  1. Create locales/{lang}.schema.json (copy en.default.schema.json).
  2. Translate the values.
  3. Push.

This is optional — the Shopify Theme Store doesn’t require theme-editor translations beyond English. But it’s a nice touch for stores managed by non-English-speaking teams.

Shopify Admin → Settings → Languages → click Publish next to the new language.

Hyprism’s meta-tags.liquid snippet auto-emits hreflang annotations for every published locale:

<link rel="alternate" hreflang="en" href="https://yourstore.com/en/product-handle">
<link rel="alternate" hreflang="de" href="https://yourstore.com/de/product-handle">
<link rel="alternate" hreflang="x-default" href="https://yourstore.com/product-handle">

This tells Google “this page exists in these languages at these URLs” — Google then serves the right language to the right visitor.

Hyprism’s CSS is partially RTL-aware — most layout uses CSS logical properties (margin-inline-start instead of margin-left), which automatically flip in RTL languages (Arabic, Hebrew, Persian).

Some legacy CSS still uses physical properties (margin-left / margin-right) — these would need manual RTL overrides. For an Arabic or Hebrew storefront, expect to make some manual CSS adjustments.

If RTL is critical for your business, plan for ~10–20 hours of polish work in addition to the base translation.

You can override theme settings per locale. Example: different hero image for English vs German.

Shopify’s mechanism: publish multiple theme versions, each configured for a specific locale.

Or use the Translate & Adapt app which lets you swap images / videos / specific section settings per locale.

Currency is separate from language — Shopify’s Markets feature controls per-country currency display.

SettingWhereWhat it does
Shop currencyShopify Admin → Settings → GeneralYour base currency for transactions
Display currencyShopify MarketsPer-country presentation currency
Auto-formatAutoHyprism renders every price through Shopify’s money filter, which follows shop.money_format

The footer-localization block shows the current country/currency and lets visitors switch.

⛔⛔ A price does not follow the page language

Section titled “⛔⛔ A price does not follow the page language”

shop.money_format is a shop setting, not a visitor-locale one. On a German page of a US-currency store the price still reads $3,500.00, with a comma as the thousands separator and a dot before the decimals — measured, not assumed. That is correct behaviour: a currency has one canonical format, and a German-formatted dollar amount would be a different-looking number, not a translated one.

What this means when you add custom code: never assemble a price in JavaScript. '$' + (cents / 100).toFixed(2) is wrong even in the shop’s own currency, because toFixed knows nothing about a thousands separator — the same page then shows $3500.00 from your script next to $3,500.00 from the server.

Hyprism exposes exactly one formatter for this, window.neGeld(cents), defined in layout/theme.liquid and fed from data-ne-money-format (which is shop.money_format). Use it.

⚠️ Watch the units. /cart.js and /products/….js return cents; /search/suggest.json returns a string in currency units. Feeding the latter to a cents formatter without × 100 shows $35.00 instead of $3,500.00 — and that looks plausible enough to ship.

15.8 Translation toolchain (engineering note)

Section titled “15.8 Translation toolchain (engineering note)”

The locale files are large: 561 storefront keys and 2,809 schema keys per language — 6,740 strings across English and German. They were produced by migrating hard-coded English in the schemas to t: references, deduplicating labels that repeat across sections, machine-translating EN → DE, and then a manual pass for the terms a machine gets wrong.

⚠️ The scripts that did it are not shipped with the theme. An earlier version of this chapter gave a copy-paste recipe naming four of them; they lived in the build repo, not in scripts/, so the recipe could not work. What follows is the approach, not a command line.

To add a language:

  1. Copy locales/de.schema.json to locales/<code>.schema.json and locales/de.json to locales/<code>.json — starting from German rather than English keeps you honest about which strings are real translations and which are still placeholders.
  2. Machine-translate the values, leaving every key untouched. The key count must not change; a missing key renders as a silent “translation missing” that theme check does not catch.
  3. Do a manual pass over the terms a machine gets wrong. In German that was roughly 400 corrections across four rounds — mostly UI vocabulary where the literal translation is not what the interface calls the thing.
  4. Publish the language in Shopify Admin → Settings → Languages.

Two rules that cost real time to learn:

  • Runtime keys (| t in markup) belong in locales/*.json; schema keys (t: inside {% raw %}{% schema %}{% endraw %}) belong in locales/*.schema.json. Mixing them produces a TranslationKeyExists error at push.
  • A block heading set in a JSON template is not in a locale file at all. It sits as a value inside templates/*.json and is translated through Shopify’s translatable-resources API, not by editing a file. It is the blind spot of every file-based translation tool.

⚠️ A machine translation service’s free tier is usually measured in characters per month; one language of this theme is roughly 46k characters, so a handful of languages will exhaust a 500k monthly allowance.

Chapter 16 — App compatibility — integrating apps with Hyprism.