# Component interpolation

# Basic Usage

Support Version

🆕 7.0+

Sometimes, we need to localize with a locale message that was included in a HTML tag or component. For example:

<p>I accept xxx <a href="/term">Terms of Service Agreement</a></p>

In the above message, if you use $t, you will probably try to compose the following locale messages:

const messages = {
  en: {
    term1: 'I Accept xxx\'s',
    term2: 'Terms of Service Agreement'
  }
}

And your localized template may look like this:

<p>{{ $t('term1') }}<a href="/term">{{ $t('term2') }}</a></p>

Output:

<p>I accept xxx <a href="/term">Terms of Service Agreement</a></p>

This is very cumbersome, and if you configure the <a> tag in a locale message, there is a possibility of XSS vulnerabilities due to localizing with v-html="$t('term')".

You can avoid it using the i18n functional component. For example:

<div id="app">
  <!-- ... -->
  <i18n path="term" tag="label" for="tos">
    <a :href="url" target="_blank">{{ $t('tos') }}</a>
  </i18n>
  <!-- ... -->
</div>
const messages = {
  en: {
    tos: 'Term of Service',
    term: 'I accept xxx {0}.'
  },
  ja: {
    tos: '利用規約',
    term: '私は xxx の{0}に同意します。'
  }
}

const i18n = new VueI18n({
  locale: 'en',
  messages
})
new Vue({
  i18n,
  data: {
    url: '/term'
  }
}).$mount('#app')

the following output:

<div id="app">
  <!-- ... -->
  <label for="tos">
    I accept xxx <a href="/term" target="_blank">Term of Service</a>.
  </label>
  <!-- ... -->
</div>

About the above example, see the example (opens new window)

The children of i18n functional component are interpolated with locale message of path prop.

In the above example:

<a :href="url" target="_blank">{{ $t('tos') }}</a>

is interpolated with term locale message.

In the above example, the component interpolation follows the list formatting. The children of i18n functional component are interpolated by their order of appearance.

You can choose the root container's node type by specifying a tag prop. If omitted, it defaults to 'span'. You can also set it to the boolean value false to insert the child nodes directly without creating a root element.

# Slots syntax usage

Support Version

🆕 8.14+

It's more convenient to use the named slots syntax. For example:

<div id="app">
  <!-- ... -->
  <i18n path="info" tag="p">
    <template v-slot:limit>
      <span>{{ changeLimit }}</span>
    </template>
    <template v-slot:action>
      <a :href="changeUrl">{{ $t('change') }}</a>
    </template>
  </i18n>
  <!-- ... -->
</div>
const messages = {
  en: {
    info: 'You can {action} until {limit} minutes from departure.',
    change: 'change your flight',
    refund: 'refund the ticket'
  }
}

const i18n = new VueI18n({
  locale: 'en',
  messages
})

new Vue({
  i18n,
  data: {
    changeUrl: '/change',
    refundUrl: '/refund',
    changeLimit: 15,
    refundLimit: 30
  }
}).$mount('#app')

Outputs:

<div id="app">
  <!-- ... -->
  <p>
    You can <a href="/change">change your flight</a> until <span>15</span> minutes from departure.
  </p>
  <!-- ... -->
</div>

In Vue 2.6 and later, you can use the following slots syntax in templates:

<div id="app">
  <!-- ... -->
  <i18n path="info" tag="p">
    <template #limit>
      <span>{{ changeLimit }}</span>
    </template>
    <template #action>
      <a :href="changeUrl">{{ $t('change') }}</a>
    </template>
  </i18n>
  <!-- ... -->
</div>

Limitation

⚠️ In i18n component, slots props are not supported.

# Places syntax usage

Important!!

In the next major version, the place and places props will be deprecated. Please switch to slots syntax.

Support Version

🆕 7.2+

Notice

⚠️ In i18n component, text content consisting of only white spaces will be omitted.

Named formatting is supported with the help of place attribute. For example:

<div id="app">
  <!-- ... -->
  <i18n path="info" tag="p">
    <span place="limit">{{ changeLimit }}</span>
    <a place="action" :href="changeUrl">{{ $t('change') }}</a>
  </i18n>
  <!-- ... -->
</div>
const messages = {
  en: {
    info: 'You can {action} until {limit} minutes from departure.',
    change: 'change your flight',
    refund: 'refund the ticket'
  }
}

const i18n = new VueI18n({
  locale: 'en',
  messages
})
new Vue({
  i18n,
  data: {
    changeUrl: '/change',
    refundUrl: '/refund',
    changeLimit: 15,
    refundLimit: 30
  }
}).$mount('#app')

Outputs:

<div id="app">
  <!-- ... -->
  <p>
    You can <a href="/change">change your flight</a> until <span>15</span> minutes from departure.
  </p>
  <!-- ... -->
</div>

Notice

⚠️ To use named formatting, all children of i18n component must have place attribute set. Otherwise it will fallback to list formatting.

If you still want to interpolate text content in named formatting, you could define places property on i18n component. For example:

<div id="app">
  <!-- ... -->
  <i18n path="info" tag="p" :places="{ limit: refundLimit }">
    <a place="action" :href="refundUrl">{{ $t('refund') }}</a>
  </i18n>
  <!-- ... -->
</div>

Outputs:

<div id="app">
  <!-- ... -->
  <p>
    You can <a href="/refund">refund your ticket</a> until 30 minutes from departure.
  </p>
  <!-- ... -->
</div>