ElasticFunnels gives you a single, brand-wide system for translating page copy without forking pages or maintaining duplicate variants. You write your page once, bind elements to translation keys in the builder, store translations per language in the admin, and the page swaps the right copy in/out based on the visitor’s language. The system is intentionally narrow: it only translates copy. Layout, images, links, and behavior stay identical across languages. Use Page Variants when you need a fully different experience per audience.Documentation Index
Fetch the complete documentation index at: https://docs.elasticfunnels.io/llms.txt
Use this file to discover all available pages before exploring further.
How it works
There are two things to manage:- Languages — the list of locales your brand supports (e.g.
en,pt-br,de). One language is your default. - Entries — for each language, a list of
key → translationrows. The same key (e.g.hero.title) lives in every language.
Translation keys
Keys use dot notation so you can group related copy together —hero.title, checkout.cta, faq.refund_policy. They can contain
letters, numbers, dots, dashes, and underscores, must start with a
letter or number, and can be up to 191 characters long.
Each key is unique within a language but is meant to repeat across
languages — that’s how the system knows the English hero.title and
the German hero.title are the same slot.
Managing languages and translations
Open Pages → Advanced → Translations to manage everything in one place.Add a language
- Click Add language.
- Enter a locale code — short BCP-47 tag like
en,de,pt-br. - Optionally add a display label (shown only in the admin).
- Toggle Default language for the language that should be served when no other language is selected.
- Use Sort order to control the order in language pickers.
Add translation entries
- In the Entries section, pick a language from the dropdown.
- Click Add entry.
- Enter a Key (e.g.
hero.title) and the translated Value. - Save.
Bulk edit
Click Bulk edit above the entries table to switch to a spreadsheet-style editor. Add or change many keys at once, then click Save all changes. The whole batch saves together — if any row fails validation, nothing is saved.Permissions
Access to translations is controlled by the Translations module permissions in your role:view, create, update, delete.
Binding elements in the page builder
Open any page in the builder, select an element, and look for the Translations sector in the right-hand panel. The sector has a single field:data-ef-hl=. Type a translation
key (e.g. hero.title) and the builder binds the selected element to
that key. The original copy stays in place and acts as the fallback
when no entry exists for the active language.
A bound element looks like this in the published page:
- Replace the inner content of
<h1>with the entry forhero.titlein the active language. - Swap the
altattribute on the<img>with the entry forhero.alt. - Swap the
placeholderon the<input>with the entry forform.email_placeholder.
alt, title, placeholder, value, and aria-label. If a
binding exists but the active language has no entry for that key, the
original markup is left untouched (so editors always see something).
Choosing the active language
ElasticFunnels picks the active language for each request from these sources, in priority order:- URL path segment, when the page slug captures a language with a
{hl}placeholder (see wildcard routes) — e.g./en/about. ?hl=query parameter — preferred name (matches Google’s convention).?locale=query parameter.?lang=query parameter.- Domain default — set on the domain.
- Brand default — set on the brand.
- Browser
Accept-Languageheader. - English (
en) as a final fallback.
- Exact match wins —
?hl=pt-brservespt-brif you have it. - Region falls back to base —
?hl=pt-brservesptif onlyptis configured. - Otherwise the brand’s default language is used.
Clean URLs per language
If you want URLs like/en/about and /pt-br/about to switch the
active language, capture the locale segment in your page slug:
- Page slug:
{hl}/about - URLs that match:
/en/about,/pt-br/about
{hl} placeholder feeds straight into the language picker above —
no extra wiring required.
Using translations in templates
Inside a page or component template you can read translations directly:| Helper | Returns |
|---|---|
t(key, fallback?) | Translation for key in the active language. Falls back to the brand default language entry, then to fallback, then to ''. |
'key' | t / 'key' | t('Default') | Filter form of t(). |
locale() | Active language code (e.g. en, pt-br). |
locales() | All language codes configured for the brand. |
default_locale() | The brand’s default language code. |
{{ locale }}— active language code{{ locales }}— list of codes{{ default_locale }}— brand default
Using translations in backend scripts
Backend scripts (<script scope="backend">) get the same helpers:
Caching
Translations are served from a fast in-memory cache so live pages stay fast. Saving any language or entry from the admin busts the cache immediately — your changes are visible on the next page load, no manual purge needed.Patterns and pitfalls
- Always set a default language.
t()falls back to the brand default before falling back to the literal fallback string. A brand with no default will return the literal fallback for missing entries — confusing for editors who expect to see the original copy. - Use stable keys. Editing copy in the builder does not change the
bound key. Once
hero.titleexists, keep using it; rename only when the meaning of the slot truly changes. - Bound text wins. The original builder copy is never shown to a visitor when the active language has an entry for the key. Treat the in-builder copy as your “default language” copy.
- Self-closing tags only get attribute swaps.
<img>,<input>, etc. don’t have inner text, so a binding only replacesalt/title/placeholder/value/aria-labelif those are set. - Region snap-down. A brand configured with
ptwill accept?hl=pt-brand serve theptentries. If you need true regional variants, addptandpt-bras separate languages.
Related
- Wildcard routes — capture an
hlpath segment for clean URLs like/en/about. - Page variables — non-translation per-locale switches (currency formatting, date masks, etc.).
- Backend scripts → data functions
— full reference for
t(),getLocale(),getLocales(),getDefaultLocale().