Placeholders and Pluralization
Keep on Learning!
If you liked what you've learned so far, dive in! Subscribe to get access to this tutorial plus video, code and script downloads.
With a Subscription, click any sentence in the script to jump to that part of the video!
Login SubscribeOnward! Let's find a complex translation scenario. On the article page, scroll down and find the comments section. This "3 Comments" header is dynamic, the number changes based on the comment count.
Find this text in templates/article/show.html.twig
. Here's the dynamic value: comments|length
. You might think to just translate "Comments" and not worry about the dynamic part, but certain languages might have alternate word order variations. Like "3 Comments" in English versus "Comments 3" in a different language. So, we need the translation text to include the dynamic part.
How do we handle this? Translation placeholders to the rescue!
Translation Placeholders
Clear out all this text, and come up with a key: since we're in article/show.html.twig
, use article.show.comments
. Add |trans
, and as the first argument of the filter, add an array. This is a key-value array, where the key is the placeholder, and the value is the dynamic value. For the key, use %count%
. Keys wrapped in %
's are a standard Symfony convention. For the value, use comments|length
:
// ... lines 1 - 4 | |
{% block body %} | |
// ... lines 6 - 44 | |
<div class="bg-white rounded-lg py-10 mt-5 px-5 lg:px-0"> | |
<div class="article-text max-w-4xl mx-auto"> | |
// ... lines 47 - 55 | |
<h3 class="my-6 text-2xl font-medium"><i class="pr-3 fa fa-comment"></i>{{ 'article.show.comments'|trans({'%count%': comments|length}) }}</h3> | |
// ... lines 57 - 83 | |
</div> | |
</div> | |
// ... lines 86 - 87 | |
{% endblock %} | |
// ... lines 89 - 95 |
Now, open our messages.en.yaml
file and add the new key, article: show: comments:
. For the value, use %count% Comments
:
// ... lines 1 - 3 | |
article: | |
show: | |
comments: '%count% Comments' |
Most translation services know to ignore text in %
's, so you shouldn't need to worry about "count" accidentally being translated.
Back to the app and refresh. Nothing super exciting but it is working!
Let's make sure it changes dynamically. Back in show.html.twig
, temporarily replace comments|length
with just 1
:
// ... lines 1 - 4 | |
{% block body %} | |
// ... lines 6 - 44 | |
<div class="bg-white rounded-lg py-10 mt-5 px-5 lg:px-0"> | |
<div class="article-text max-w-4xl mx-auto"> | |
// ... lines 47 - 55 | |
<h3 class="my-6 text-2xl font-medium"><i class="pr-3 fa fa-comment"></i>{{ 'article.show.comments'|trans({'%count%': 1}) }}</h3> | |
// ... lines 57 - 83 | |
</div> | |
</div> | |
// ... lines 86 - 87 | |
{% endblock %} | |
// ... lines 89 - 95 |
Refresh the page, and great! "1 Comments". But, hmm, maybe it's not the end of the world, but this should really read "1 Comment" - without the "s".
Pluralization
Back in messages.en.yaml
, at the beginning of the value, add 1 Comment|
:
// ... lines 1 - 3 | |
article: | |
show: | |
comments: '1 Comment|%count% Comments' |
This pipe (|
) signals to Symfony that you have multiple versions for pluralization. Go back and refresh the page, and it now correctly displays "1 Comment". Make sure it still works with more than one comment by switching back to comments|length
in show.html.twig
:
// ... lines 1 - 4 | |
{% block body %} | |
// ... lines 6 - 44 | |
<div class="bg-white rounded-lg py-10 mt-5 px-5 lg:px-0"> | |
<div class="article-text max-w-4xl mx-auto"> | |
// ... lines 47 - 55 | |
<h3 class="my-6 text-2xl font-medium"><i class="pr-3 fa fa-comment"></i>{{ 'article.show.comments'|trans({'%count%': comments|length}) }}</h3> | |
// ... lines 57 - 83 | |
</div> | |
</div> | |
// ... lines 86 - 87 | |
{% endblock %} | |
// ... lines 89 - 95 |
Refresh the app, and yep, the pluralization works! Symfony knows to use the 1 Comment
version when the count is 1, and the %count% Comments
version when the count isn't 1.
ICU MessageFormat
It's worth noting that Symfony supports the official ICU MessageFormat.
To enable it, you need to adjust the filenames of your translation files to add this +intl-icu
text.
Placeholders are handled a bit differently. In the translation text, wrap the placeholder key in curly braces. Then, when passing the placeholder key, you don't need to wrap it in anything.
There's also a powerful condition system. This example shows how you can change the message based on a gender
placeholder.
Pluralization is also more powerful. You can use the condition system to create really fine-grained pluralization rules.
Something to check out if you need it, but for now, we'll stick with the basic system.
Next, we'll look at how to handle translation text that contains HTML.