如何在 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
...
如果是,下一步是什么?
- 通过
useRouter()
解析首选语言环境
- 解析
NEXT_LOCALE
cookie
- 解析
lang
slug
然后决定哪个优先级高?我应该在哪里做?在 _app.tsx
/ 一些 HOC 中?
我的 next.config.js
中是否需要任何 rewrites
或 redirects
,或者我应该通过 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</>;
};
我正在使用 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
...
如果是,下一步是什么?
- 通过
useRouter()
解析首选语言环境
- 解析
NEXT_LOCALE
cookie - 解析
lang
slug
然后决定哪个优先级高?我应该在哪里做?在 _app.tsx
/ 一些 HOC 中?
我的 next.config.js
中是否需要任何 rewrites
或 redirects
,或者我应该通过 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</>;
};