Twig Translation
When to Use
When translating text in Twig templates — theme templates, custom template files, template suggestions.
Decision: Twig Translation Method
| If you need... | Use... | Why |
|---|---|---|
| Translate simple string | {{ 'Text'\|t }} |
One-line, no variables |
| Translate with placeholders | {% trans %} block |
Supports {{ variable }} placeholders |
| Translate plural forms | {% trans %}{% plural count %}{% endtrans %} |
Handles singular/plural per language |
| Add translation context | {% trans with {'context': 'My context'} %} |
Disambiguate ambiguous strings |
| Translate in specific language | {% trans with {'langcode': 'es'} %} |
Force specific language |
Pattern: Simple Translation Filter
{# Simple string #}
<h1>{{ 'Welcome'\|t }}</h1>
{# With context #}
<span>{{ 'May'\|t({}, {'context': 'Long month name'}) }}</span>
{# Common mistake — don't translate variables #}
{# BAD — security risk #}
<p>{{ user_input\|t }}</p>
{# GOOD — just output the variable #}
<p>{{ user_input }}</p>
Explanation:
- 'Text'\|t — translates literal string
- First argument: replacements (empty {} if none)
- Second argument: options (context, langcode)
- NEVER use \|t on variables — only literal strings
Pattern: Trans Block with Variables
{% trans %}
Welcome, {{ name }}!
{% endtrans %}
With placeholders and context:
{% trans with {'%filename': file.filename, '@size': file.size} %}
File %filename uploaded (@size bytes).
{% endtrans %}
With context:
{% trans with {'context': 'User greeting'} %}
Hello, {{ user.name }}!
{% endtrans %}
Pattern: Plural Forms
{% trans %}
1 item
{% plural count %}
{{ count }} items
{% endtrans %}
With context:
{% trans with {'context': 'Shopping cart'} %}
1 item in cart
{% plural item_count %}
{{ item_count }} items in cart
{% endtrans %}
Explanation:
- Text before {% plural %} — singular form
- Text after {% plural count %} — plural form
- count variable determines which form to use
- Language-specific plural rules applied automatically
Pattern: Field Output (Already Translated)
Entity fields are automatically translated — don't wrap in t:
{# GOOD — field already translated based on current language #}
<h1>{{ content.title }}</h1>
<div>{{ content.body }}</div>
{# BAD — double translation attempt #}
<h1>{{ content.title\|t }}</h1>
When field renders:
- Drupal loads entity translation based on language negotiation
- Field formatter outputs translated value
- No \|t needed on field output
Pattern: Translating Render Arrays in Preprocess
// In mytheme.theme or module.module
function mytheme_preprocess_page(&$variables) {
$variables['custom_message'] = [
'#markup' => t('Welcome to our site!'),
];
}
{# In page.html.twig #}
{{ custom_message }}
Explanation:
- Use t() in PHP preprocess
- Output render array in Twig without \|t
- Translation happens in PHP, Twig just renders
Common Mistakes
- Translating user content →
{{ node.title\|t }}is wrong. Node title is user content, not UI text. Already translated via entity translation - Using t filter on render arrays →
{{ content.field_name\|t }}is wrong. Field is already translated - Concatenating translated strings → Don't split sentences across multiple
{% trans %}blocks. Languages reorder words differently. Use single block with placeholders - Missing quotes on literal strings →
{{ Welcome\|t }}is wrong (undefined constant). Use{{ 'Welcome'\|t }}with quotes - Translating in wrong language layer → Don't use
\|tfor content that should be entity-translated. Interface translation is for UI, not content - Not using placeholders correctly →
{% trans %}Welcome {{ name }}{% endtrans %}works, but{% trans with {'@name': name} %}Welcome @name{% endtrans %}is clearer for translators
See Also
- → TranslatableMarkup & t() — PHP translation
- → Translating Content Entities — entity translation vs interface translation
- → Anti-Patterns & Common Mistakes — security issues
- Reference:
core/lib/Drupal/Core/Template/TwigNodeTrans.php - Reference: https://www.drupal.org/docs/develop/theming-drupal/twig-in-drupal/filters-modifying-variables-in-twig-templates
- Reference: https://www.drupal.org/node/2047135 (trans tag support)