How can I make vue-i18n / vue2 work with Storybook mdx type story?

Viewed 433

I couldn't make it work for a long time so I thought to put here for others fighting with the same issue.

The setup is:

- "vue": "^2.6.12",
- @storybook/vue": "^6.4.19",
- "vue-i18n": "^8.22.4",

Following the i18n documentation I had updated my preview.js file to include:

import Vue from 'vue';
import VueI18n from 'vue-i18n';

Vue.use(VueI18n);

Then I created the story for my component: Avatar.stories.mdx

<!-- Avatar.stories.mdx -->

import { Meta, Description, Canvas, Story, ArgsTable } from '@storybook/addon-docs';

import Avatar from '../app/js/components/common/Avatar';


<Meta
  title="Components/Common/Avatar"
  component={Avatar}
  argTypes={{
    username: {
      control: 'string',
    },
  }}
  args={{
    username: 'Tom Thomson',
  }}
/>

export const Template = (args, { argTypes }) => ({
  props: Object.keys(argTypes),
  components: { Avatar },
  template: `
    <div class="wrapper">
      <Avatar v-bind="$props">
      </Avatar>
    </div>
  `,
});

# Avatar

<Description />

Basic style

<Canvas>
  <Story
    name="Basic"
    args={{
    }}>
    {Template.bind({})}
  </Story>
</Canvas>

<ArgsTable of={Avatar} />

But this alone wasn't enough, $t() function was visible to my component used in the story because the function didn't get the context throwing errors like:

vue.esm.js:628 [Vue warn]: 
    Error in render: "TypeError: Cannot read properties of undefined (reading '_t')"

Really nothing more in the docs or Google that I could find.

1 Answers

The solution was easy, but hard to figure out or to find.

To make $t() function work in your .mdx storybook story files you need two things:

  • include vue-i18n in your .mdx file
  • add i18n section to your Template configuration (in the same file)

and it goes like this - this is the working file:

<!-- Avatar.stories.mdx -->

import { Meta, Description, Canvas, Story, ArgsTable } from '@storybook/addon-docs';

import Avatar from '../app/js/components/common/Avatar';

import VueI18n from 'vue-i18n';

<Meta
  title="Components/Common/Avatar"
  component={Avatar}
  argTypes={{
    username: {
      control: 'string',
    },
  }}
  args={{
    username: 'Tom Thomson',
  }}
/>

export const Template = (args, { argTypes }) => ({
  props: Object.keys(argTypes),
  components: { Avatar },
  i18n: new VueI18n({
    locale: 'en',
    fallbackLocale: 'en',
    messages: {
      en: messagesEn,
      ar: messagesAr,
    },
  }),
  template: `
    <div class="wrapper">
      <Avatar v-bind="$props">
      </Avatar>
    </div>
  `,
});

# Avatar

<Description />

Basic style

<Canvas>
  <Story
    name="Basic"
    args={{
    }}>
    {Template.bind({})}
  </Story>
</Canvas>

<ArgsTable of={Avatar} />

I hope that helps someone.

Related