3

我们有一个现有的应用程序,默认情况下将根目录"/"重定向到该应用程序。"/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 文档,我们有一个使用 HOC 包装的自定义_app文件,并使用 getInitialProps 进行设置:appWithTranslation

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);

我们有我们的_document文件来处理一些情感主题:

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.

为什么此设置不再适用于重定向?

  • 终端中没有错误。
  • 网络选项卡404在根路由上显示错误"/" 在此处输入图像描述

这意味着重写不起作用。但是 i18n 怎么办?

它是 _app 或 _document 文件中的内容吗?

  • 如果我/search直接导​​航到,它加载得很好,所以页面路由似乎没问题。

其他注意事项:

  • NextJS"next": "^10.0.2",
  • 下一个-i18下一个"next-i18next": "^7.0.1",
4

1 回答 1

0

Next & Locales 似乎存在一些可能的问题... https://github.com/vercel/next.js/issues/20488 https://github.com/vercel/next.js/issues/18349

我的解决方法并不漂亮,但它有效:

  1. 删除原来的next-rewrite
  2. 添加一个index.js处理重定向的新页面文件getServerSideProps
const Index = () => null;

export async function getServerSideProps({ locale }) {
  return {
    redirect: {
      destination: `${locale !== 'en' ? `/${locale}` : ''}/search`,
      permanent: true,
    },
  };
}

export default Index;
于 2021-03-24T17:12:02.057 回答