Use vue-i18n in a plugin library mode

91 Views Asked by At

Hello I'm developing a set of UI components using the library mode of vue3/rollup. Everything is build into a local npm package. The idea is to have a set of .vue files that can be used in several projects.

My library project contains several .vue files and everything works good when I'm not using translation. I'm assuming that all my applications likely to use my library will also use vue-i18n. I therefore tried to add my translations to my .vue files via the tags and I imported t from use-i18n, assuming that when the file was executed there would be the i18n context in the application but nothing works... I've done a lot of research on using vue-i18n in the context of library mode, but I keep coming back to the same issue, which is to add the i18n plugin to the application, but in my library project I don't have a createApp...

UI-Library > index.ts

import type { App } from "vue";
import { provide } from "vue";
import Hello from "./Hello.vue";

export function createBusinessComponent() {
    const install = (app: App) => {
        app.component("Hello", Hello);
    };

    return { install };
}

UI-Library > Hello.vue

<template>
 <p>{{ t('hello') }}</p>
</template>

<script lang="ts">
  import { defineComponent } from "vue";
 
  import { useI18n,  } from "vue-i18n";

  export default defineComponent({
    setup: (props, { emit }) => {
      const { t } = useI18n();
      return {
        t,
      };
    },
  });
</script>
<i18n>{
    "en": {
        "hello": " Hello world",
    },
    "fr": {
        "hello": " Bonjour",
    }   
}</i18n>

I build everything with rollup and that's works good. And I add my build package to the package.json of my application project

My-Application > main.ts

import { createPinia } from 'pinia'
import { createApp } from 'vue'
import App from './App.vue'
import i18n from './i18n'
import router from './router'

import { createBusinessComponent } from 'ui-library'

const businessComp = createBusinessComponent({})

const app = createApp(App)
app.use(createPinia())
app.use(i18n)
app.use(router)
app.use(businessComp)
app.mount('#app')

My-Application > i18n.ts (to use translation from application too)

import { createI18n } from 'vue-i18n'
import EN from '../assets/props/en.json'
import FR from '../assets/props/fr.json'

const translations = {
  en: EN,
  fr: FR,
}

export default createI18n({
  legacy: false,
  locale: 'en',
  fallbackLocale: 'en',
  globalInjection: true,
  messages: translations,
})

My-Application > App.vue

<template>
   <hello></hello>
</template>

Error in the web console

SyntaxError: Must be called at the top of a setup function (at index-6cfa2a26.js:70354:94) at h6 (index-6cfa2a26.js:70354:94) at Lh (index-6cfa2a26.js:71311:10) at ql (index-6cfa2a26.js:71804:11) at setup (index-6cfa2a26.js:73154:12) at callWithErrorHandling (runtime-core.esm-bundler.js:6656:22) at setupStatefulComponent (runtime-core.esm-bundler.js:6272:29) at setupComponent (runtime-core.esm-bundler.js:6228:11) at mountComponent (runtime-core.esm-bundler.js:4081:13) at processComponent (runtime-core.esm-bundler.js:4056:17) at patch (runtime-core.esm-bundler.js:3651:21)

I'm sure I'm not the first person to want to use library mode with i18n but I can't find anything...

1

There are 1 best solutions below

2
Meriodas.Z On

try this in your library project add i18n as dependency, then change the build script

export default defineConfig({
  plugins: [vue()],
  build: {
    lib: {
      // src/indext.ts is where we have exported the component(s)
      entry: resolve(__dirname, "src/index.ts"),
      name: "BrianComponentLibrary",
      // the name of the output files when the build is run
      fileName: "brian-component-lib",
    },
    rollupOptions: {
      // make sure to externalize deps that shouldn't be bundled
      // into your library
      external: ["vue", "vue-i18n"],
      output: {
        // Provide global variables to use in the UMD build
        // for externalized deps
        globals: {
          vue: "Vue",
        },
      },
    },
  },
});