2

I'm creating a Vue web component using vue-cli 3 and the --target wc option. I also need the component to use the vue-i18n plugin, which requires some options to be passed to the main Vue instance like this:

new Vue({
    i18n: new VueI18n({ ... ])
    ...
})

In a regular Vue app this is fine because I control construction of the main Vue instance. However, when building as a web component, the construction of the main Vue object is generated by vue-web-component-wrapper and I don't see any obvious way to affect it.

How can I use the vue-18n plugin in my web component?

executable
  • 3,365
  • 6
  • 24
  • 52
StrongFish
  • 493
  • 7
  • 16
  • I think 'local component registration' might solve your problem. Check this out: https://stackoverflow.com/questions/48066237/how-to-use-a-vue-js-plugin-inside-a-custom-component – Jim B. Nov 16 '18 at 17:19
  • @JimB., I'm not having a problem with component registration. The vue-i18n install instructions require that I add a new object to the root Vue vm. In a web component the only "root" vm is the entry component and adding a VueI18n object there doesn't seem to work. – StrongFish Nov 19 '18 at 16:19

3 Answers3

3

The i18n plugin needs to be initialized on the "entry" component (i.e. the one that forms the base of the web component) instead of the root component.

But even doing that, it's important that all messages are defined on the entry component. Defining messages on a child component, either directly in the component or using the <i18n> element, effectively overrides the vue-i18n config from the entry component and causes that child component to use the default language of en-US.

Here is a simple working example:

Entry Component

<template>
  <div>
    <p>{{ $t('hello') }}</p>
    <child-component />
  </div>
</template>

<script>
import ChildComponent from "./child.vue"
import Vue from "vue"
import VueI18n from "vue-i18n"
Vue.use(VueI18n)

export default {
  name: "App",
  i18n: new VueI18n({
    locale: 'ja',
    messages: {
      en: {
        hello: "hello in en",
        test: "test in en"
      },
      ja: {
        hello: "hello in ja",
        test: "test in ja"
      },
    }
  }),
  components: { ChildComponent }
};
</script>

Child Component

<template>
  <div>{{ $t("test") }}</div>
</template>

<script>
export default {
  name: "child-component"
};
</script>
StrongFish
  • 493
  • 7
  • 16
1

Since we are using combination of script setup and web components I ended up with following solution.

Created i18n service module:

import { createI18n } from 'vue-i18n';
import messages from '@/assets/locales/messages.json';

export const i18n = createI18n<false>({
  legacy: false, // must set to `false`
  locale: 'sk',
  fallbackLocale: 'en',
  messages,
});

export const t = i18n.global.t.bind(i18n.global);

then usage in component

<script setup lang="ts">
  import { t } from '@/services/i18n';
</script>

<template>
  <span class="text">{{ t('global.next') }}</span>
</template>

Happy coding

Luckylooke
  • 4,061
  • 4
  • 36
  • 49
0

The problem with @tctimmeh solution is that the i18n plugin needs to passed actually into the new Vue constructor but while using the web components wrapper we don't have access to the new Vue as it is inside the wrapper lib therefore, luckily thanks to this PR https://github.com/kazupon/vue-i18n/pull/420/commits/13ed0488caf70ab454ffd5cb2affa36ec31c4c50 we can extend the Vue object before instantiation with the instant of the VueI18n

import Vue from 'vue'
import wrap from '@vue/web-component-wrapper'
import VueI18n from 'vue-i18n';


const Component = {
  // any component options
}

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

const VueExtended = Vue.extend({ i18n });

const CustomElement = wrap(VueExtended, Component)

window.customElements.define('my-element', CustomElement)
EranGrin
  • 258
  • 4
  • 9