Building a multilingual website in Drupal 10 or 11 is a powerful experience, thanks to the robust translation capabilities built into the core. While Drupal handles content translation for nodes and blocks seamlessly, developers often encounter a common hurdle: translating hardcoded text within custom themes and Twig templates. Whether you are building a 'Read More' link or a complex 'Submitted by' attribution, ensuring these strings are translatable is essential for a professional localized site.
In this guide, you will learn the various methods to wrap your Twig strings for translation, how to handle dynamic variables, and the specific steps required to make these strings appear in the Drupal administrative interface. By the end of this tutorial, you will be able to manage your site's interface translation with confidence.
Using the |t and |trans Filters
The most straightforward way to translate a simple string in a Drupal Twig template is by using a filter. Drupal provides two filters for this purpose: |t and |trans. In the context of Drupal's Twig implementation, these filters are functionally identical and act as wrappers for the PHP t() function.
You should use these filters for short, single-line strings that do not contain complex HTML. Here is how you can implement them in your .html.twig files:
{# Using the |t filter #}
{{ 'Read more'|t }}
{# Using the |trans filter #}
{{ 'Search'|trans }}
Using |t is often preferred by developers who are accustomed to the PHP side of Drupal, while |trans is part of the standard Twig i18n extension syntax. Both are perfectly valid and will register the string for translation in the Drupal database.
Handling Complex Strings with the {% trans %} Tag
When you need to translate larger blocks of text or strings that include variables and logic, the {% trans %} tag is a more powerful alternative. Unlike filters, the {% trans %} tag allows you to wrap multiple lines and easily handle pluralization.
This is particularly useful for attribution lines or status messages. For example:
{% trans %}
Submitted by {{ author.username }} on {{ node.created }}
{% endtrans %}
One of the greatest advantages of the {% trans %} tag is its built-in support for pluralization. You can define how a string should look for a single item versus multiple items using the {% plural %} sub-tag:
{% set count = comments|length %}
{% trans %}
{{ count }} comment was deleted successfully.
{% plural count %}
{{ count }} comments were deleted successfully.
{% endtrans %}
Working with Variables and Placeholders
Hardcoding variables directly into translated strings is a recipe for broken translations. When translating strings that contain dynamic data, you must use placeholders. This allows translators to move the variable within the sentence to match the grammatical structure of the target language.
In Twig, you can pass an array of mapping variables to the |t filter:
{{ 'Subscribe to @title'|t({'@title': title}) }}
In Drupal, there are three main types of placeholders:
1. @variable: Escaped HTML (the safest and most common choice).
2. %variable: Escaped HTML and wrapped in an <em> tag for emphasis.
3. !variable: Raw data (use with extreme caution to avoid XSS vulnerabilities).
Here is an example using multiple placeholders in a paragraph:
<p class="submitted">
{{ "Submitted by @author on @date"|t({ '@author': author, '@date': date }) }}
</p>
Providing Context and Language Codes
Sometimes, the same word can have different meanings depending on where it is used. For instance, the word "May" could refer to the month or a permission. To help translators, you can provide a "context" for your string.
You can also explicitly provide a language code if you need to force a string to translate into a specific language regardless of the site's current interface language. This is often used in PDF generation or email notifications.
{# Providing context and a specific language code #}
{{ 'von'|t([], {'langcode': currentLanguageCode, 'context': 'Seitenzahl PDF'}) }}
In this example, the context Seitenzahl PDF helps the translator understand that 'von' refers to 'Page X of Y' rather than 'From [Author]'.
Registering Your Strings in the Translation UI
A common point of frustration for Drupal developers is adding a |t filter and then finding that the string does not appear at admin/config/regional/translate. This is because Drupal does not proactively scan all files for strings; instead, it populates the translation database as strings are encountered during page rendering.
To ensure your Twig strings are registered, follow these steps:
- Enable Core Modules: Ensure that the Interface Translation and Content Translation modules are enabled.
- Add the Filter: Add your
{{ 'My String'|t }}to the template. - Clear Cache: Rebuild the Drupal cache so the new template logic is recognized.
- Visit the Page in a Non-English Language: This is the most critical step. You must view the page where the string exists in a language other than the site's default (usually English). When Drupal renders the page in French, Spanish, or any other enabled language, it notices the new string and adds it to the translation table.
- Translate the String: Navigate to
Configuration > Regional and language > User interface translation(/admin/config/regional/translate). Search for your string and provide the translation.
Frequently Asked Questions
Why isn't my Twig string showing up in the translation interface?
Drupal only adds strings to the locales_source table when they are actually rendered in a language other than the site's default. Visit the page using a language prefix (e.g., /fr/your-page) and then check the translation interface again.
Can I use HTML inside a translated Twig string?
While you can use the {% trans %} tag with HTML, it is generally better to keep HTML outside of the translation string whenever possible. This prevents translators from accidentally breaking the site's layout. If you must use HTML, ensure you are using placeholders for dynamic values to maintain security.
What is the difference between |t and |trans?
In Drupal Twig, there is no functional difference. Both call the same underlying translation system. |t is shorter and consistent with Drupal's PHP coding standards, while |trans is standard for developers coming from other Symfony-based projects.
Wrapping Up
Translating strings in Twig is a fundamental skill for any Drupal developer working on global sites. By using the |t filter for simple strings, the {% trans %} tag for complex blocks, and placeholders for dynamic data, you create a flexible and localizable user interface. Remember that the key to seeing your strings in the administrative UI is to trigger their rendering by visiting the site in a secondary language. With these tools in your kit, you can ensure your Drupal site speaks to your audience in their own language, regardless of how complex your theme becomes.