Vue3/Rollup库模式下集成vue-i18n遇错误求助
我用Vue3+Rollup以库模式开发UI组件,打包成本地npm包供多项目复用。未添加国际化时组件功能正常,现在尝试在.vue文件中通过<i18n>标签添加翻译,并从vue-i18n导入t函数,预期组件运行时能获取应用的i18n上下文,但实际报错且完全未生效。
相关代码
UI组件库代码
index.ts
import type { App } from "vue"; import Hello from "./Hello.vue"; export function createBusinessComponent() { const install = (app: App) => { app.component("Hello", Hello); }; return { install }; }
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>
应用端代码
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')
i18n.ts
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, })
App.vue
<template> <hello></hello> </template>
控制台报错
SyntaxError: Must be called at the top of a
setupfunction (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)
解决方案
1. 组件库中配置vue-i18n为peer依赖
修改组件库的package.json,将vue-i18n从dependencies移至peerDependencies,确保组件库使用应用端提供的vue-i18n实例,避免打包时重复引入:
{ "peerDependencies": { "vue-i18n": "^9.0.0" } }
2. 组件内指定useI18n的全局作用域
在Hello.vue的useI18n调用中添加useScope: 'global'参数,明确使用应用全局的i18n上下文:
<script lang="ts"> import { defineComponent } from "vue"; import { useI18n } from "vue-i18n"; export default defineComponent({ setup: () => { const { t } = useI18n({ useScope: 'global' }); return { t }; }, }); </script>
3. Rollup配置排除vue和vue-i18n
在组件库的Rollup配置中,将vue和vue-i18n标记为外部依赖,不打包进组件库:
// rollup.config.js import { nodeResolve } from '@rollup/plugin-node-resolve'; import vue from 'rollup-plugin-vue'; export default { input: 'src/index.ts', output: [ { format: 'es', file: 'dist/index.es.js' }, { format: 'cjs', file: 'dist/index.cjs.js' } ], plugins: [vue(), nodeResolve()], external: ['vue', 'vue-i18n'] };
4. 合并组件库翻译到应用端
组件内<i18n>标签的内容不会自动合并到应用的i18n实例,可通过两种方式处理:
- 手动导入合并:在应用的i18n配置中导入组件翻译并合并
// My-Application > i18n.ts import { createI18n } from 'vue-i18n' import EN from '../assets/props/en.json' import FR from '../assets/props/fr.json' import { en as HelloEN, fr as HelloFR } from 'ui-library/dist/Hello.i18n.json' const translations = { en: { ...EN, ...HelloEN }, fr: { ...FR, ...HelloFR }, } export default createI18n({ legacy: false, locale: 'en', fallbackLocale: 'en', globalInjection: true, messages: translations, })
- 自动注入:在组件库的install方法中自动合并翻译
// UI-Library > index.ts import type { App } from "vue"; import Hello from "./Hello.vue"; import helloMessages from './Hello.i18n.json' export function createBusinessComponent() { const install = (app: App) => { app.component("Hello", Hello); const i18n = app.config.globalProperties.$i18n; if (i18n) { Object.keys(helloMessages).forEach(locale => { if (!i18n.messages[locale]) { i18n.messages[locale] = {}; } Object.assign(i18n.messages[locale], helloMessages[locale]); }); } }; return { install }; }
关键原因说明
- 组件库若打包自身的vue-i18n,会与应用端实例冲突,导致
useI18n无法获取正确上下文 useI18n默认是局部作用域,需显式指定useScope: 'global'才能访问全局i18n实例- 组件内
<i18n>标签的翻译内容不会自动合并到应用的i18n消息池,必须手动处理
内容的提问来源于stack exchange,提问作者Gregory Frerot

