Search code examples
javascriptvue.jsvue-i18n

Make VueI18n react to router link tag


I have this Vue app which is composed of a simple home page, a title, and a home text. You can view this app online on my JSFiddle. Here is the code:

HTML

<div id="app">
  My header app
  <router-view></router-view>
</div>

JavaScript

const Home = {
    template: `
      <div>
        <h1>{{ $t('home.title') }}</h1>
        <p v-html="$t('home.text')"></p>
      </div>
    `
};

const messages = {
    en: {
    home: {
        title: 'Hello world',
        text: 'Find all post by clicking <router-link to="/post">this link</router-link>!'
    }
  }
};

const routes = [
    { name: 'home', path: '*', component: Home }
];

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

const router = new VueRouter({
    mode: 'history',
    routes: routes
});

const vue = new Vue({
    el: '#app',
    router: router,
    i18n: i18n
});

Problem

As you can see, there is no "router-link" link visible, and clicking the link will not redirect to the desired route.

Question

Is it possible to make VueI18n interpret <router-link> tag inside a v-html directive?


Solution

  • v-html replaces content of an element with a plain HTML, so custom elements used inside a replacing string are not compiled to Vue.js components.

    You may want to check component interpolation way suggested by VueI18n documentation, that involves usage of i18n functional component and template strings.

    Here is the fork of the provided fiddle that implements this approach: http://jsfiddle.net/u5vx1mLq/

    In a nutshell, i18n component has path prop into which you can path a template string and tag prop which defines a tag, i18n component is to be replaced with. i18n also has a slot, which can be used to define a child component within which you can interpolate partials of the template string.

    Sorry for the awkward explanation, hopefully the code snippet will shed some light on this matter:

    const Home = {
      template: `
        <div>
          <h1>{{ $t('home.title') }}</h1>
          <i18n path="home.linkLabel" tag="label" for="home.linkText">
            <router-link to="/post">{{ $t('home.linkText') }}</router-link>
          </i18n>
        </div>
      `
    };
    
    const messages = {
      en: {
        home: {
          title: 'Hello world',
          linkText: 'this link',
          linkLabel: 'Find all post by clicking {0}'
        }
      }
    };