Login to bookmark this video
Buy Access to Course
07.

HTML in Translations

|

Share this awesome video!

|

Keep on Learning!

With a Subscription, click any sentence in the script to jump to that part of the video!

Login Subscribe

Here's another complex scenario. On our homepage, scroll down to the footer.

I want to translate this text... but, it contains an icon and link HTML... You might think to just translate the two text parts separately, but again, in different languages, they may need to be ordered differently.

So we need the HTML in the translation text. Let's look at two different approaches.

Raw HTML in Translation Text

In base.html.twig, find the footer text.

The simplest solution is to just straight up, add the text, HTML and all, as the translation value. So, select all the text and cut it. For the key, use 'base.footer'|trans:

88 lines | templates/base.html.twig
// ... line 1
<html lang="{{ app.locale }}">
// ... lines 3 - 17
<body class="bg-[url('../images/bg-planet.png')] bg-contain bg-no-repeat">
// ... lines 19 - 80
<footer class="py-8">
<div class="text-white text-center">
{{ 'base.footer'|trans }}
</div>
</footer>
</body>
</html>

Over in messages.en.yaml, under base:, add footer:, and inside single quotes, paste. We need to use single quotes here because the HTML contains double quotes:

8 lines | translations/messages.en.yaml
base:
// ... line 2
footer: 'Made with <i class="fa fa-heart text-red-600"></i> by the guys and gals at <a class="underline text-[#0286C4]" href="https://symfonycasts.com">SymfonyCasts</a>'
// ... lines 4 - 8

Go back to our app and refresh... Whoa, this ain't right. The HTML was escaped. Twig does this by default to prevent XSS attacks from user-submitted data. For this particular case, we can safely disable this behavior since we're in full control of the text.

Back in base.html.twig, add |raw after trans to disable escaping:

88 lines | templates/base.html.twig
// ... line 1
<html lang="{{ app.locale }}">
// ... lines 3 - 17
<body class="bg-[url('../images/bg-planet.png')] bg-contain bg-no-repeat">
// ... lines 19 - 80
<footer class="py-8">
<div class="text-white text-center">
{{ 'base.footer'|trans|raw }}
</div>
</footer>
</body>
</html>

Refresh... and Voila! It works!

This is quick and easy, but has some downsides. First, it mixes HTML into our translation text, which can make it harder to read and maintain. Second, it duplicates the HTML in every translation file, which can make it harder to update the HTML down the road.

Let's try a different approach: adding the HTML as placeholders.

HTML Placeholders

In messages.en.yaml, copy the full text, and in base.html.twig, below our footer translation, paste it temporarily.

First, copy the icon HTML, and in the trans filter, add it as a placeholder: '%heart%': '', and paste. Now, copy the link HTML and add it as another placeholder: '%link%': '', paste:

88 lines | templates/base.html.twig
// ... line 1
<html lang="{{ app.locale }}">
// ... lines 3 - 17
<body class="bg-[url('../images/bg-planet.png')] bg-contain bg-no-repeat">
// ... lines 19 - 80
<footer class="py-8">
<div class="text-white text-center">
{{ 'base.footer'|trans|raw }}
</div>
</footer>
</body>
</html>

Because we're still rendering HTML, the |raw filter is still required.

Delete the temporary line we pasted and jump back to messages.en.yaml. Replace the icon's HTML with '%heart%' and the link's HTML with '%link%':

8 lines | translations/messages.en.yaml
base:
// ... line 2
footer: 'Made with %heart% by the guys and gals at %link%'
// ... lines 4 - 8

Right away, this looks a lot cleaner and easier to read.

Ok, back to the app and refresh... Oi! A syntax error!

Ahh, the trans placeholders need to be wrapped in an array. In base.html.twig, wrap them in curly braces.

Refresh... scroll down... there we go!

This approach is much cleaner, but also has a downside. What if our link HTML had text or an attribute that needed to be translated? There's no simple way to handle this. You'd have to either translate the elements separately or do some nested translations: like translate the placeholder. Hopefully, this problem doesn't come up too often.

Translation Workflow

So that covers all the common scenarios. I won't have you watch me translate the rest of the site as it would be more of the same, boring, Kevin blah blah blah. So, I'll leave that as a homework assignment: Vous pouvez l'envoyer vers /dev/null une fois que c'est fait!

Oh man... that was bad!

Next, we'll look at the translation debugging tools Symfony provides!