问题描述
我们有一个现有的应用,默认情况下,根 "/"
被重定向到 "/search"
。通过我们的 next-redirects.js
文件运行良好:
async function redirects() {
return [
{
source: '/',destination: '/search',permanent: true,},];
}
我必须使用 next-i18next
实现对应用程序的翻译,以便我们可以使用 NextJS 进行文本翻译 + 开箱即用的路由。我已按照 next-i8next docs 中的步骤操作。我将 next-i18next.config.js
文件添加为:
const path = require('path');
module.exports = {
i18n: {
defaultLocale: 'en',locales: ['en','es'],localePath: path.resolve('./public/static/locales'),// custom path file route
};
next.config 看起来像:
const { i18n } = require('./next-i18next.config');
const defaultConfig = {
env: {
SOME_ENV,images: {
deviceSizes: [980],domains: [
'd1','d2',],i18n,redirects: require('./next-redirects'),webpack: (config,options) => {
if (!options.isServer) {
config.resolve.alias['@sentry/node'] = '@sentry/browser';
}
if (
NODE_ENV === 'production'
) {
config.plugins.push(
new SentryWebpackPlugin({
include: '.next',ignore: ['node_modules'],urlPrefix: '~/_next',release: VERCEL_GITHUB_COMMIT_SHA,})
);
}
return config;
},};
module.exports = withPlugins([withSourceMaps],defaultConfig);
根据 nextJS 文档,我们有一个 custom _app
文件被 appWithTranslation
HOC 包裹,并且使用 getinitialProps 进行设置:
function MyApp({ Component,pageProps }) {
const [mounted,setMounted] = useState(false);
useEffect(() => {
// Remove the server-side injected CSS.
const jssstyles = document.querySelector('#jss-server-side');
if (jssstyles) {
jssstyles.parentNode.removeChild(jssstyles);
}
TagManager.initialize(tagManagerArgs);
setMounted(true);
},[]);
const Layout = Component.Layout || Page;
return (
<>
<Head>
<link rel="icon" href="/favicon.png" type="image/ico" />
<Meta name="viewport" content="width=device-width,initial-scale=1" />
</Head>
<AppProviders>
<Context {...pageProps}>
<Layout {...pageProps}>
<>
<Component {...pageProps} />
<Feedback />
<PageLoader />
</>
</Layout>
</Context>
</AppProviders>
</>
);
}
MyApp.getinitialProps = async ({ Component,ctx }) => {
let pageProps = {};
if (Component.getinitialProps) {
pageProps = await Component.getinitialProps({ ctx });
}
const cookies = Cookie.parse(ctx?.req?.headers?.cookie || '');
if (Object.keys(cookies).length) {
const { token } = JSON.parse(cookies?.user || '{}');
let user = null;
if (token) {
const { data } = await get('api/users',{ token });
if (data) {
user = data;
user.token = token;
}
}
pageProps.user = user;
pageProps.cart = cookies?.cart;
pageProps.defaultBilling = cookies?.defaultBilling;
pageProps.reservationestimateItem = cookies?.reservationestimateItem;
pageProps.reservationestimate = cookies?.reservationestimate;
}
return { pageProps };
};
export default appWithTranslation(MyApp);
export default class MyDocument extends Document {
static async getinitialProps(ctx) {
const initialProps = await Document.getinitialProps(ctx);
const styles = extractCritical(initialProps.html);
return {
...initialProps,styles: (
<>
{initialProps.styles}
<style
data-emotion-css={styles.ids.join(' ')}
// eslint-disable-next-line react/no-danger
dangerouslySetInnerHTML={{ __html: styles.css }}
/>
</>
),};
}
render() {
return (
<Html lang="en">
<Head />
<body>
<Main />
<NextScript />
<script
type="text/javascript"
src="https://js.stripe.com/v2/"
async
/>
</body>
</Html>
);
}
}
// `getinitialProps` belongs to `_document` (instead of `_app`),// it's compatible with server-side generation (SSG).
MyDocument.getinitialProps = async ctx => {
const sheets = new ServerStyleSheets();
const originalRenderPage = ctx.renderPage;
ctx.renderPage = () =>
originalRenderPage({
enhanceApp: App => props => sheets.collect(<App {...props} />),});
const initialProps = await Document.getinitialProps(ctx);
return {
...initialProps,// Styles fragment is rendered after the app and page rendering finish.
styles: [
...React.Children.toArray(initialProps.styles),sheets.getStyleElement(),};
};
此时重定向逻辑应继续导航到 search
页面,其设置如下:
export const SearchPage = () => {
const router = useRouter();
const { t } = useTranslation('search');
return (
<>
<Head>
<title>{`${t('searchTitle')}`}</title>
<Meta
property="og:title"
content={`${t('searchTitle')}`}
key="title"
/>
<Meta
name="description"
content={t('MetaDescription')}
/>
</Head>
<Search />
</>
);
};
SearchPage.namespace = 'SearchPage';
export const getStaticPaths = () => ({
paths: [],// indicates that no page needs be created at build time
fallback: 'blocking' // indicates the type of fallback
});
export const getStaticProps = async ({ locale }) => ({
// exposes `_nextI18Next` as props which includes our namespaced files
props: {
...await serverSideTranslations(locale,['common','search']),}
});
export default SearchPage;
搜索页面具有 getStaticPaths
和 getStaticProps
函数,根据 next-i18next
的所有页面级文件的需要。
为什么此设置不再适用于重定向?
这意味着重写不起作用。但是 i18n 怎么办呢?
它是否在 _app 或 _document 文件中?
- 如果我直接导航到
/search
,它可以正常加载,因此页面路由似乎没问题。
其他注意事项:
- NextJS
"next": "^10.0.2",
- next-i18next
"next-i18next": "^7.0.1",
解决方法
Next & Locales 似乎存在一些可能的问题... https://github.com/vercel/next.js/issues/20488 https://github.com/vercel/next.js/issues/18349
我的解决方法并不漂亮,但有效:
- 删除原来的 next-rewrite
- 添加一个新的
index.js
页面文件来处理getServerSideProps
中的重定向:
const Index = () => null;
export async function getServerSideProps({ locale }) {
return {
redirect: {
destination: `${locale !== 'en' ? `/${locale}` : ''}/search`,permanent: true,},};
}
export default Index;