diff --git a/.storybook/main.ts b/.storybook/main.ts index b3d43469b4..14b9305e21 100644 --- a/.storybook/main.ts +++ b/.storybook/main.ts @@ -2,7 +2,12 @@ import type { StorybookConfig } from '@storybook-vue/nuxt' const config = { stories: ['../.storybook/*.mdx', '../app/**/*.stories.@(js|ts)'], - addons: ['@storybook/addon-a11y', '@storybook/addon-docs', '@storybook/addon-themes'], + addons: [ + '@storybook/addon-a11y', + '@storybook/addon-docs', + '@storybook/addon-themes', + 'storybook-i18n', + ], framework: '@storybook-vue/nuxt', staticDirs: ['./.public'], features: { @@ -23,7 +28,7 @@ const config = { // Minimal shims for Storybook v10 module federation system // These will be replaced when Storybook runtime loads window.__STORYBOOK_MODULE_GLOBAL__ = { global: window }; - window.__STORYBOOK_MODULE_CLIENT_LOGGER__ = { + window.__STORYBOOK_MODULE_CLIENT_LOGGER__ = { deprecate: console.warn.bind(console, '[deprecated]'), once: console.log.bind(console), logger: console diff --git a/.storybook/preview.ts b/.storybook/preview.ts index 0d62d33be0..a31da335cd 100644 --- a/.storybook/preview.ts +++ b/.storybook/preview.ts @@ -1,5 +1,6 @@ import type { Preview } from '@storybook-vue/nuxt' import { withThemeByDataAttribute } from '@storybook/addon-themes' +import { addons } from 'storybook/preview-api' import { currentLocales } from '../config/i18n' import { fn } from 'storybook/test' import { ACCENT_COLORS } from '../shared/utils/constants' @@ -19,6 +20,12 @@ globalThis['__NUXT_COLOR_MODE__'] ??= { // @ts-expect-error - dynamic global name globalThis.defineOgImageComponent = fn() +// Subscribe to locale changes from storybook-i18n addon (once, outside decorator) +let currentI18nInstance: any = null +addons.getChannel().on('LOCALE_CHANGED', (newLocale: string) => { + currentI18nInstance?.setLocale(newLocale) +}) + const preview: Preview = { parameters: { controls: { @@ -31,24 +38,18 @@ const preview: Preview = { theme: npmxDark, }, }, + initialGlobals: { + locale: 'en-US', + locales: currentLocales.reduce( + (acc, locale) => { + acc[locale.code] = locale.name + return acc + }, + {} as Record, + ), + }, // Provides toolbars to switch things like theming and language globalTypes: { - locale: { - name: 'Locale', - description: 'UI language', - defaultValue: 'en-US', - toolbar: { - icon: 'globe', - dynamicTitle: true, - items: [ - // English is at the top so it's easier to reset to it - { value: 'en-US', title: 'English (US)' }, - ...currentLocales - .filter(locale => locale.code !== 'en-US') - .map(locale => ({ value: locale.code, title: locale.name })), - ], - }, - }, accentColor: { name: 'Accent Color', description: 'Accent color', @@ -75,9 +76,9 @@ const preview: Preview = { attributeName: 'data-theme', }), (story, context) => { - const { locale, accentColor } = context.globals as { - locale: string + const { accentColor, locale } = context.globals as { accentColor?: string + locale?: string } // Set accent color from globals @@ -89,14 +90,12 @@ const preview: Preview = { return { template: '', - // Set locale from globals created() { - if (this.$i18n) { - this.$i18n.setLocale(locale) - } - }, - updated() { - if (this.$i18n) { + // Store i18n instance for LOCALE_CHANGED events + currentI18nInstance = this.$i18n + + // Set initial locale when component is created + if (locale && this.$i18n) { this.$i18n.setLocale(locale) } }, diff --git a/app/components/Link/Link.stories.ts b/app/components/Link/Link.stories.ts index 9ceeaeb7eb..8bf47715b2 100644 --- a/app/components/Link/Link.stories.ts +++ b/app/components/Link/Link.stories.ts @@ -5,14 +5,17 @@ const meta = { component: LinkBase, args: { to: '/', - default: 'Click me', }, } satisfies Meta export default meta type Story = StoryObj -export const Default: Story = {} +export const Default: Story = { + args: { + default: 'Click me', + }, +} export const ExternalLink: Story = { args: { @@ -75,16 +78,28 @@ export const WithIconButton: Story = { args: { variant: 'button-primary', classicon: 'i-lucide:copy', - default: 'Copy', }, + render: args => ({ + components: { LinkBase }, + setup() { + return { args } + }, + template: `{{ $t("package.readme.copy_as_markdown") }}`, + }), } export const WithKeyboardShortcut: Story = { args: { variant: 'button-secondary', ariaKeyshortcuts: 's', - default: 'Search', }, + render: args => ({ + components: { LinkBase }, + setup() { + return { args } + }, + template: `{{ $t("search.button") }}`, + }), } export const BlockLink: Story = { diff --git a/package.json b/package.json index ae1fd762d5..97b2e316ae 100644 --- a/package.json +++ b/package.json @@ -138,6 +138,7 @@ "markdown-it-anchor": "9.2.0", "schema-dts": "1.1.5", "storybook": "catalog:storybook", + "storybook-i18n": "catalog:storybook", "typescript": "5.9.3", "unplugin-vue-markdown": "30.0.0", "vitest": "npm:@voidzero-dev/vite-plus-test@0.1.12", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2c9a5d5165..62896004f4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -18,6 +18,9 @@ catalogs: '@storybook/addon-themes': specifier: ^10.3.1 version: 10.3.1 + storybook-i18n: + specifier: ^10.1.1 + version: 10.1.1 overrides: sharp: 0.34.5 @@ -313,6 +316,9 @@ importers: storybook: specifier: ^10.3.1 version: 10.3.1(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + storybook-i18n: + specifier: catalog:storybook + version: 10.1.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.3.1(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)) typescript: specifier: 5.9.3 version: 5.9.3 @@ -9617,6 +9623,11 @@ packages: resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==} engines: {node: '>= 0.4'} + storybook-i18n@10.1.1: + resolution: {integrity: sha512-A2cFaGCysU2VkjDQUFY0aQsppAFIhZU3Tx38/NYLhWShTRkUpE3huGHP59CAgArxLQEzEjLmieiTSuNT2bwA4Q==} + peerDependencies: + storybook: ^10.3.1 + storybook@10.3.1: resolution: {integrity: sha512-i/CA1dUyVcF6cNL3tgPTQ/G6Evh6r3QdATuiiKObrA3QkEKmt3jrY+WeuQA7FCcmHk/vKabeliNrblaff8aY6Q==} hasBin: true @@ -22193,6 +22204,14 @@ snapshots: es-errors: 1.3.0 internal-slot: 1.1.0 + storybook-i18n@10.1.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.3.1(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)): + dependencies: + '@storybook/icons': 2.0.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + storybook: 10.3.1(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + transitivePeerDependencies: + - react + - react-dom + storybook@10.3.1(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4): dependencies: '@storybook/global': 5.0.0 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index a8d4142d80..ab32009332 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -47,3 +47,4 @@ catalogs: '@storybook/addon-docs': '^10.3.1' '@storybook/addon-themes': '^10.3.1' 'storybook': '^10.3.1' + 'storybook-i18n': '^10.1.1'