如何在Storybook中配置Nuxt3自定义i18n插件
问题
我是Nuxt.js和Storybook新手,在Nuxt3项目中配置Storybook时遇到问题。项目里有一个自定义i18n插件(代码如下),现在渲染使用$getLang()函数的组件Story时,报错:TypeError: _ctx.$getLang is not a function。
自定义i18n插件代码:
import { createI18n } from 'vue3-i18n' import en from '@/locales/en.json' import ja from '@/locales/ja.json' import zh_TW from '@/locales/zh_TW.json' import zh_CN from '@/locales/zh_CN.json' interface I18nOptions { locale: string messages: Record<string, object> } const getBrowserLanguage = (): string => { if (process.client) { return window.navigator.language } return 'en' } const getLocaleFromCookie = (): string | null => { // Read from cookie const cookie = useCookie<string>('locale') if (cookie.value) { return cookie.value } return null } const LANGS = { EN: 'en', JP: 'ja', TW: 'zh-TW', CN: 'zh-CN', } const getLocale = (): string => { const browserLanguage = getBrowserLanguage() if (Object.values(LANGS).includes(browserLanguage)) { return browserLanguage } const cookieLocale = getLocaleFromCookie() if (cookieLocale && Object.values(LANGS).includes(cookieLocale)) { return cookieLocale } return 'en' } const messages: Record<string, object> = { en, ja, 'zh-tw': zh_TW, 'zh-cn': zh_CN } const i18nOptions: I18nOptions = { locale: getLocale().toLowerCase(), messages, } const i18n = createI18n(i18nOptions) export default defineNuxtPlugin((nuxt) => { nuxt.vueApp.use(i18n) return { provide: { t: () => null, getLang: (key: string, params?: Array<string>) => { if (!key) return '' return i18n.t(key, params) }, setLocale: (value: string) => { i18n.setLocale(value) }, getLocale: () => i18n.getLocale(), }, } })
项目devDependencies:
"devDependencies": { "@nuxtjs/tailwindcss": "^6.8.0", "@storybook/addon-essentials": "^7.0.27", "@storybook/addon-interactions": "^7.0.27", "@storybook/addon-links": "^7.0.27", "@storybook/blocks": "^7.0.27", "@storybook/testing-library": "^0.0.14-next.2", "@storybook/vue3": "^7.0.27", "@storybook/vue3-vite": "^7.0.27", "eslint": "^8.44.0", "eslint-plugin-storybook": "^0.6.12", "nuxt": "^3.5.0", "react": "^18.2.0", "react-dom": "^18.2.0", "storybook": "^7.0.27", "storybook-addon-nuxt": "^1.3.3", "typescript": "^5.1.6", "vue3-i18n": "^1.1.5" }
当前.storybook/main.ts:
import type { StorybookConfig } from '@storybook/vue3-vite' export const config: StorybookConfig = { stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'], addons: ['@storybook/addon-links', '@storybook/addon-essentials', '@storybook/addon-interactions'], framework: { name: '@storybook/vue3-vite', options: {}, }, docs: { autodocs: 'tag', }, }
当前.storybook/preview.ts:
import type { Preview } from '@storybook/vue3' export const preview: Preview = { parameters: { actions: { argTypesRegex: '^on[A-Z].*' }, controls: { matchers: { color: /(background|color)$/i, date: /Date$/, }, }, }, }
需要知道如何在.storybook/preview.ts中配置这个自定义插件。
解决方案
1. 适配i18n实例(处理Nuxt专属API)
原插件使用的useCookie和process.client是Nuxt专属API,Storybook环境无法直接识别。需要重新创建适配Storybook的i18n实例,保留原有语言配置和核心方法。
2. 修改.storybook/main.ts(配置路径别名)
Storybook默认不识别Nuxt的@别名,需在Vite配置中添加别名解析:
import type { StorybookConfig } from '@storybook/vue3-vite' import { resolve } from 'path' export const config: StorybookConfig = { stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'], addons: ['@storybook/addon-links', '@storybook/addon-essentials', '@storybook/addon-interactions'], framework: { name: '@storybook/vue3-vite', options: {}, }, docs: { autodocs: 'tag', }, viteFinal: async (config) => { config.resolve!.alias = { ...config.resolve!.alias, '@': resolve(__dirname, '../src'), } return config }, }
3. 修改.storybook/preview.ts(挂载i18n和全局方法)
在preview中初始化i18n,并将$getLang、$setLocale、$getLocale挂载到Vue全局属性:
import type { Preview } from '@storybook/vue3' import { createI18n } from 'vue3-i18n' import en from '@/locales/en.json' import ja from '@/locales/ja.json' import zh_TW from '@/locales/zh_TW.json' import zh_CN from '@/locales/zh_CN.json' // 初始化适配Storybook的i18n实例 const messages = { en, ja, 'zh-tw': zh_TW, 'zh-cn': zh_CN } const i18n = createI18n({ locale: 'en', // Storybook默认语言,可按需调整 messages, }) export const preview: Preview = { parameters: { actions: { argTypesRegex: '^on[A-Z].*' }, controls: { matchers: { color: /(background|color)$/i, date: /Date$/, }, }, }, // 全局注入方法 decorators: [ (story) => ({ components: { story }, setup() { return { $getLang: (key: string, params?: Array<string>) => { if (!key) return '' return i18n.t(key, params) }, $setLocale: (value: string) => { i18n.global.locale.value = value }, $getLocale: () => i18n.global.locale.value, } }, template: '<story />', }), ], // 全局应用i18n async setup(app) { app.use(i18n) }, }
4. 验证效果
重启Storybook后,组件中的$getLang即可正常调用。如需切换语言,可在Story的controls中添加自定义控件,或直接调用$setLocale方法。
内容的提问来源于stack exchange,提问作者yosuke.kom
相关产品推荐
相关产品推荐

