Vue-i18n: Render html tags with component interpolation

Created on 27 May 2020  路  8Comments  路  Source: kazupon/vue-i18n

It's possible to render html tags with component interpolation?

Example:

const messages = {
  en: {
    text: '<p>Lorem ipsum, dolor sit amet consectetur adipisicing elit.</p><p>Lorem ipsum, dolor {email}.</p>',
    email: '[email protected]'
  }
}
<i18n path="text" tag="div">
  <my-link place="email" :href="`mailto:$t('email')`">{{ $t('args.email') }}</my-link>
</i18n>

I expect two paragraphs, and in the second paragraph, one link with my custom link component, but, the paragraphs was rendering as strings and not as html tags.

Maybe it's is a bug? Or is impossible to render an html tags inside a component?

Feature

Most helpful comment

This has the big advantage of keeping the markup out of the translation content and in your template (where it belongs).

In general I agree with that statement. But I think there are still some use-cases where html in the translations makes sense, like if you want to highlight 1 word by using a <b> tag, or like the use-case of @leandromatos-hotmart.
Would it make sense to add something like a isHtml option to the i18n tag?

All 8 comments

I believe the purpose of component interpolation is precisely to avoid having markup inside the translation strings. Instead, you can do this:

<i18n path="text" tag="p">
  <template #link>
    <a href="https://kazupon.github.io/vue-i18n/guide/interpolation.html">
      {{ $t('linkText') }}
    </a>
  </template>
</i18n>
const messages = {
  en: {
    text: 'Go to {link}',
    linkText: 'vue-i18n: Component interpolation'
  }
}

producing:

<p>
  Go to,
  <a href="https://kazupon.github.io/vue-i18n/guide/interpolation.html">
    vue-i18n: Component interpolation
  </a>
</p>

This has the big advantage of keeping the markup out of the translation content and in your template (where it belongs).

This has the big advantage of keeping the markup out of the translation content and in your template (where it belongs).

In general I agree with that statement. But I think there are still some use-cases where html in the translations makes sense, like if you want to highlight 1 word by using a <b> tag, or like the use-case of @leandromatos-hotmart.
Would it make sense to add something like a isHtml option to the i18n tag?

Excellent example @tho-masn

In many cases, in projects I work on, I need to make something bold in the middle of the text or even create simple paragraphs to break the text, and in the middle of them, I need to use an i18n tag to interpolate with a hyperlink component for example.

An prop isHtml would be a amazing!

I have the same issue. I need to place a <strong>...</strong> inside a localized text.

As the docs says, you can use v-html (https://kazupon.github.io/vue-i18n/guide/formatting.html#html-formatting)

const messages = {
  en: {
   test: 'this is just a <strong>test</strong> message',
  }
}

<div v-html="$t('test')" />
output: this is just a test message

But it can be dangerous (see the warning in the doc links)

Or take a look at component interpolation: https://kazupon.github.io/vue-i18n/guide/interpolation.html#basic-usage

@Pochwar The problema is the component interpolation, he not render html.

Do you saw my example?

I believe the purpose of component interpolation is precisely to avoid having markup inside the translation strings. Instead, you can do this:

<i18n path="text" tag="p">
  <template #link>
    <a href="https://kazupon.github.io/vue-i18n/guide/interpolation.html">
      {{ $t('linkText') }}
    </a>
  </template>
</i18n>
const messages = {
  en: {
    text: 'Go to {link}',
    linkText: 'vue-i18n: Component interpolation'
  }
}

producing:

<p>
  Go to,
  <a href="https://kazupon.github.io/vue-i18n/guide/interpolation.html">
    vue-i18n: Component interpolation
  </a>
</p>

This has the big advantage of keeping the markup out of the translation content and in your template (where it belongs).

That doesn't solve the bold text problem. I agree on the security point, I also agree on the separation of concern, but handling bold text with interpolation is a pain.
All the exemples and use cases show short sentences translation. But When you have a full paragraph with 4, 5 or more bold texts, italic + some links, well, welcome in hell. You have to cut the paragraph into too many pieces that translators don't understand what they have to do anymore.

A feature is definitely missing here.

A quick fix will be to allow v-html inside the <i18n> component, through a props for exemple. Quick, but dirty.

Another solution is to design a feature to allow some basic text stylisation. What about interpreting markdown? It could be a very handy solution, but it's a more complex feature. Maybe not all markdown properties but some of them could be a really nice improvement.

I'd like also support the idea that adding things like a, li, p, strong, etc tags in translation files makes life much simpler. This content is going to be generated by internal team members, stored in source control, reviewed, etc, and from my perspective is trusted content. Content from translators that enter markdown is going to be sanitized when converting to html, and is then subject to the same review & QA process as an engineer adding the copy to the files.

I'd also like to offer the perspective that in trying to prevent malicious copy with component interpolation, the approach adds more security concerns than it resolves. This relies on allowing unescaped html to be injected into template placeholders. An engineer might look at a copy section and think that an anchor tag is safe, and they can use v-html for this one specific copy. If that section also has something like company_name and that supplied variable has say a script tag in it, it is not escaped, and causes a security issue.

For comparison, Rails allows html in translations, uses an explicit _html suffix on keys containing such content, and escapes any arguments supplied to the template. This results in a safe translation process, and one that I think should be mirrored in vue-i18n, maybe with a $tSafe or something like that.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

thelinuxlich picture thelinuxlich  路  66Comments

francoisromain picture francoisromain  路  19Comments

nchutchind picture nchutchind  路  17Comments

tobeorla picture tobeorla  路  18Comments

flaird picture flaird  路  15Comments