I have the next-i18next
in my Next.js Project. And also add the storybook to my project.
When I try to add the story for the home page. I got error
Module not found: Error: Can't resolve 'next-i18next/serverSideTranslations' in "xxxx\xxx\"
When I remove export const getStaticProps
, the storybook works fine.
How to resolve this issue.
The following are my configurations
This is the translation in level 1 page.
import {serverSideTranslations} from 'next-i18next/serverSideTranslations'
export const getStaticProps = async ({locale}) => ({
props: {
...await serverSideTranslations(locale, ['index']),
},
})
.storybook/main.js
const path = require('path')
module.exports = {
"stories": [
"../src/**/*.stories.mdx",
"../src/**/*.stories.@(js|jsx|ts|tsx)"
],
"addons": [
"@storybook/addon-links",
"@storybook/addon-essentials",
"@storybook/addon-interactions",
{
name: 'storybook-addon-next',
options: {
nextConfigPath: path.resolve(__dirname, '../next.config.js')
}
}
],
staticDirs: ['../public'],
"framework": "@storybook/react",
core: {
builder: '@storybook/builder-webpack5'
},
webpackFinal: async (config, {configType}) => {
config.resolve.alias = {
...config.resolve.alias,
"@": path.resolve(__dirname, "../src/"),
'next-i18next': 'react-i18next'
};
config.resolve.modules = [path.resolve(__dirname, '..'), 'node_modules'];
// this modifies the existing image rule to exclude .svg files
// since we want to handle those files with @svgr/webpack
const imageRule = config.module.rules.find(rule => rule.test.test('.svg'))
imageRule.exclude = /\.svg$/
// configure .svg files to be loaded with @svgr/webpack
config.module.rules.push({
test: /\.svg$/,
use: ['@svgr/webpack']
})
// Return the altered config
return config;
},
typescript: {
check: true, // type-check stories during Storybook build
}
}
.storybook/preview.js
//reset styles
import '../src/assets/styles/common.css'
import '../src/assets/styles/reset.css'
import '../src/assets/styles/other.scss'
//add antd style
import 'antd/dist/antd.css'
import React, {Suspense, useEffect} from "react";
import { initReactI18next, I18nextProvider } from 'react-i18next'
// import i18n from './i18n';
import i18next from 'i18next'
import * as NextImage from "next/image";
import { CUSTOM_VIEWPORTS } from './viewports'
import HttpApi from 'i18next-http-backend';
const OriginalNextImage = NextImage.default;
Object.defineProperty(NextImage, "default", {
configurable: true,
value: (props) => <OriginalNextImage {...props} unoptimized/>,
});
export const parameters = {
actions: {argTypesRegex: "^on[A-Z].*"},
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/,
},
expanded: true
},
viewport: {
viewports: CUSTOM_VIEWPORTS,
},
storySort: {
method: 'alphabetical',
order: ['Common', 'Ant Design', 'Others'],
},
}
// Create a global variable called locale in storybook
// and add a menu in the toolbar to change your locale
export const globalTypes = {
locale: {
name: 'Locale',
description: 'Internationalization locale',
toolbar: {
icon: 'globe',
items: [
{value: 'En', title: 'English'},
{value: 'Fr', title: 'French'},
],
showName: true,
},
},
};
// Wrap your stories in the I18nextProvider component
const i18nextStoryDecorator = (Story, context) => {
const { locale } = context.globals;
i18next
.use(HttpApi)
.use(initReactI18next)
.init({
whitelist:['En','Fr'],
lng: locale,
fallbackLng: 'En',
ns: 'index',
defaultNS: 'index',
defaultLocale: "En",
debug: true,
})
// When the locale global changes
// Set the new locale in i18n
useEffect(() => {
i18next.changeLanguage(locale);
}, [locale]);
return (
// here catches the suspense from components not yet ready (still loading translations)
// alternative set useSuspense false on i18next.options.react when initializing i18next
<Suspense fallback={<div>loading translations...</div>}>
<I18nextProvider i18n={i18next}>
<Story />
</I18nextProvider>
</Suspense>
);
};
// export decorators for storybook to wrap your stories in
export const decorators = [i18nextStoryDecorator];