TL;DR
Append your locale keys with _html to have them marked as
html_safe
and translate them with= t('.text_html')
.
When you're localizing a Rails application, sometimes there is this urge to include a little HTML. Be it some localized link, or a set of <em>
tags, you'd like to have it included in the locale file. Example:
# Locale file
en:
page:
text: 'Please visit our <a href="https://www.corporate.com/en">corporate website</a> to learn more about <em>the corporation</em>.'
# HAML
= t('.text')
# Desired output
Please visit our <a href="https://www.corporate.com/en">corporate website</a> to learn more about <em>the corporation</em>.
# Actually rendered as ...
Please visit our <a href="www.corporate.com/en">corporate website</a> to learn more about <em>the corporation</em>.
# ... which looks like this in the HTML source:
Please visit our <a href="https://www.corporate.com/en">corporate website</a> to learn more about <em>the corporation</em>.
Alright. Rails is being helpful here and saves you from accidentally injecting HTML into the page. But how could you insert the desired HTML intentionally?
While blindly calling t(...).html_safe
renders the text as desired, it removes the protection and leaves you vulnerable to rendering bad HTML
A workaround would be to split the translations around the HTML fragments.
= t('.please')
= link_to t('.website'), t('.corporate_url')
= t('.learn_more')
= succeed '.' do
%em
= t('.corporation')
This is annoying, especially in HAML where you need the #succeed
helper to end the line with a dot.
The solution
Fortunately, they've built something into Rails. Namely: The t()
helper (but not I18n.t()
) will mark translations as .html_safe
if their key ends with _html
:
# locale file
en:
page:
text_html: 'Please visit our <a href="https://www.corporate.com/en">corporate website</a> to learn more about <em>the corporation</em>.'
# HAML
= t('.text_html')
# Output
Please visit our <a href="https://www.corporate.com/en">corporate website</a> to learn more about <em>the corporation</em>.
This will also properly escape unsafe interpolations:
# locale file
en:
page:
text_html: 'Please visit our %{link} to learn more about <em>the corporation</em>.'
# HAML
= t('.text_html', link: '<script>alert("hacked")</script>')
# Output
Please visit our <script>alert("hacked")</script> to learn more about <em>the corporation</em>.