如何在 Next.js 中重新加载时强制执行 i18n locale slugs 并实现 i18n 一致性?

How to enforce i18n locale slugs and achieve i18n consistency upon reload in Next.js?

我正在使用 next-translate。默认情况下,我的路线被识别如下:

/about         <---
/de/about
/es/about

但我想为所有 路径强制执行区域设置:

/en/about      <---
/de/about
/es/about

这是我的配置:

next.config.js

const nextTranslate = require('next-translate');

module.exports = nextTranslate({
    ...
    i18n: {
        localeDetection: false,
        locales: ['en', 'de', 'es'],
        defaultLocale: 'en',
    }
});

i18n.js

module.exports = {
    locales: ['en', 'de', 'es'],
    defaultLocale: 'en',
    pages: {
        '*': ['common']
    },
    interpolation: {
        prefix: '${',
        suffix: '}',
    },
    loadLocaleFrom: (locale, namespace) =>
        import(`./translations/${locale}/${namespace}`).then((m) => m.default),
}

请注意,我还有一个保留 NEXT_LOCALE cookie 的语言更改组件。因此,我希望当我访问 /about 并且我的 NEXT_LOCALE cookie 之前已设置为 de 时,路由器会将我重定向到 /de/about但它没有。它停留在 /about 并将 cookie 重写为 en...

这是当前的 pages 文件夹结构:

...
pages/
  _app.tsx
  _document.tsx
  about.tsx
  ...

我需要将其重组为这个吗?

pages/
  _app.tsx
  _document.tsx
  [lang]/         <---
    about.tsx
    ...

如果是,下一步是什么?

然后决定哪个优先级高?我应该在哪里做?在 _app.tsx / 一些 HOC 中?

我的 next.config.js 中是否需要任何 rewritesredirects,或者我应该通过 Router.push 动态处理这些?

持久的 NEXT_LOCALE cookie 不会根据其值自动重定向是因为您已通过设置 localeDetection: false 明确禁用它。这会影响 header-based 重定向以及 cookie-based 重定向。

只需将其从您的 next.config.js 中删除即可解决该问题。


没有 built-in 方法可以在所有路径上强制使用默认语言环境。但是,有一些解决方法可以帮助在 URL.

上为默认语言环境添加前缀

解决方法 #1:将默认语言环境设置为 default,并在中间件中重定向

i18n Routing 文档中所述,添加一个名为 default 的新“虚拟”语言环境并将其设置为默认语言环境。请注意,实际上不会使用此语言环境,它只是允许我们始终在其路径上添加 en 语言环境前缀。

// next.config.js
module.exports = {
    i18n: {
        locales: ['default', 'en', 'de', 'es'],
        defaultLocale: 'default'
    }
}

接下来,创建一个 _middleware 文件以在向 default 语言环境发出请求时重定向到 /en 前缀。

// pages/_middleware.ts
import { NextRequest, NextResponse } from 'next/server'

const PUBLIC_FILE = /\.(.*)$/

export function middleware(request: NextRequest) {
    const shouldHandleLocale = !PUBLIC_FILE.test(request.nextUrl.pathname)
        && !request.nextUrl.pathname.includes('/api/') 
        && request.nextUrl.locale === 'default'

    if (shouldHandleLocale) {
        const url = request.nextUrl.clone()
        url.pathname = `/en${request.nextUrl.pathname}`
        return NextResponse.redirect(url)
    }

    return undefined
}

解决方法 #2:浅路由到 client-side

上的前缀路径

或者,您可以检查默认语言环境并在通过 router.push 首次安装时在 URL 中明确设置它。

让我们假设以下自定义 useDefaultLocale 钩子将逻辑抽象为 re-used.

import { useState, useEffect } from 'react';
import { useRouter } from 'next/router';

export const useDefaultLocale = () => {
    const router = useRouter();

    useEffect(() => {
        if (router.locale === router.defaultLocale) {
            router.push(`/${router.locale}${router.asPath}`, undefined, {
                locale: false,
                shallow: true // Optionally add this if you don't want to rerun data fetching methods
            });
        }
    }, [router.asPath]);
};

然后可以在您的页面中使用或 _app.js

import { useDefaultLocale } from '<path-to>/use-default-locale';

const AboutPage = () => {
    useDefaultLocale()

    return <>About Page</>;
};