How to interpolate the result of link function into translated string

I’m trying to output translated strings like:
<%= gettext("User %{user} is assigned as %{assignment_type} to %{entity}", bindings) %>;
in my .eex template where bindings user and entity would be links and the links are created with the help of the Phoenix.HTML.Link module:

<% user = link(user.name, to: Routes.user_path(@conn, :show, @user) %>
<% entity = link("#{entity.type} #{entity.id}", to: Routes.entity_path(@conn, :show, @entity) %>

But when I provide such bindings I get error:
** (Protocol.UndefinedError) protocol String.Chars not implemented for {:safe, [60, “a”, [[32, “href”, 61, 34, “/ru/users/6”, 34]], 62, “╨á╨╛╨▒╨╡╤Ç╤é ╨ó╤Ç╨╛╨╕╤å╨║╨╕╨╣(#6)”, 60, 47, “a”, 62]}.

And if I try to convert tuple to iolist like:

<% user = link(user.name, to: Routes.user_path(@conn, :show, @user) |> Phoenix.HTML.safe_to_string %>
<% entity = link("#{entity.type} #{entity.id}", to: Routes.entity_path(@conn, :show, @entity) |> Phoenix.HTML.safe_to_string %>

it escapes the html and i just get html on the page instead of links.

If I try to use Phoenix.HTML.raw function instead of safe_to_string, the first error returns.

So, what’s the way to do it properly?

I was looking in the wrong direction. Actually, gettext returned html string without escaping, it was happening on the later stage when my .eex template was rendered. So the only thing I needed to change is to wrap gettext call into raw function like this:
<%= gettext("User %{user} is assigned as %{assignment_type} to %{entity}", bindings) |> raw() %>
and everything worked as expected.

2 Likes