How-to library · Developer docs

How-to library

Task-shaped pages: a title that starts with a verb, the situation in a few lines, the steps, the working code in both engines, and why this way rather than another. Found from a search, done, and left.

Add translation to a Twig site, which has no trans filter

Twig has no trans filter here, but every render receives the translator as __. Call __.translate(key, params, domain), wrap it in a macro that fixes the domain, and keep the keys in XLIFF files under translations/.

Context

Context. Stock Twig's trans filter needs an extension, and this platform's Twig environment takes no extensions from a site: a theme cannot register one. The translator itself is there, though: every template receives it as __, and the platform's own Twig templates translate with __.translate(). Translations live in XLIFF files in your repository, one per domain and language, exactly as on a Smarty site.

Steps

  1. Create translations/site-shop.en.xlf (and one per language) with dotted keys as sources and the text as targets.
  2. Write a macro over __.translate() that fixes your domain, so no template names it twice.
  3. Import the macro and use it. Escape any visitor-supplied parameter before it goes in: neither the text nor its parameters are escaped.
  4. For a whole template in one domain, set the default once with {% do __.setDefaultDomain('site-shop') %}.

Code

HTML
<?xml version="1.0"?>
<xliff xmlns="urn:oasis:names:tc:xliff:document:2.0" version="2.0" srcLang="en" trgLang="es">
  <file id="shop" original="shop.txt">
    <unit id="cart">
      <segment><source>cart.button.add</source><target>Añadir al carrito</target></segment>
      <segment><source>cart.items</source><target>%count% artículos en tu carrito</target></segment>
    </unit>
  </file>
</xliff>
Template code
{* the same in Smarty *}
{'cart.button.add'|_:'site-shop'}
{'cart.items'|_:'site-shop':['count' => $cart->getItemsCount()]}
{# templates/includes/i18n.twig #}
{% macro t(key, params = {}, domain = 'site-shop') %}{{ __.translate(key, params, domain) }}{% endmacro %}

{# any template #}
{% import 'includes/i18n.twig' as i18n %}
<button type="submit">{{ i18n.t('cart.button.add') }}</button>
<p>{{ i18n.t('cart.items', {'count': cart.getItemsCount()}) }}</p>
<h1>{{ i18n.t('search.results_for', {'query': _request.getParameter('q')|e}) }}</h1>

Why this and not that

Not text typed into the template: it cannot be translated later without editing every template, and the platform's own screens already read these files, so a site that relabels "Width" as "Width (cm)" does it by overriding the platform's key in its own file. Not a lookup without a domain: it falls back to the admin interface's domain and prints the key. A key printed on the page always means a missing translation or a mistyped domain.

Go deeper

Was this page helpful?

Your answer goes to the docs team.