为什么国际化在使用app/上的[locale]子文件夹的NextJS 13上不起作用



如何让i18n在Next 13上工作

我在app/中创建了一个嵌套的[locale]/文件夹,但它只提供了一个404

请参阅我的next.config.js

const nextConfig = {
experimental: {
appDir: true,
},
i18n: {
defaultLocale: 'fr,
locales: ['fr', 'en'],
localeDetection: true
}
}

您是否找到了使用React Server组件支持i18n的方法?

编辑:

在beta.nextjs文档上,它说:

我们目前不打算在应用程序中包含以下功能:国际化(i18n(

我也发现了一个悬而未决的问题,它还没有提供任何解决方法。

[EDIT]Next.js文档中现在有一个指南。

中间件是Next.js 13中i18n的解决方案。直到有一个官方推荐的方式。

  1. 要在Next.js 13中使用带有/app目录的中间件,您必须创建/page目录(即使您的所有页面都将在/app目录中(和其中的.keep文件
  2. app目录中创建一个动态路由[locale],并将所有其他路由放在那里
  3. 设置中间件,使其将所有流量从没有locale参数的路由重定向到有参数的路由(例如,基于Accept-language标头或客户端位置(
  4. 从params中获取页面上locale的值

受Eric Howey文章启发的最小middleware.ts内容:

import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";
// Regex to check whether something has an extension, e.g. .jpg
const PUBLIC_FILE = /.(.*)$/;
export function middleware(request: NextRequest) {
const { nextUrl, headers } = request;
// Cloned url to work with
const url = nextUrl.clone();
// Client language, defaults to en
const language =
headers
.get("accept-language")
?.split(",")?.[0]
.split("-")?.[0]
.toLowerCase() || "en";
try {
// Early return if it is a public file such as an image or an api call
if (PUBLIC_FILE.test(nextUrl.pathname) || nextUrl.pathname.includes("/api")) {
return undefined;
}
// Proceed without redirection if on a localized path
if (
nextUrl.pathname.startsWith("/en") ||
nextUrl.pathname.startsWith("/de") ||
nextUrl.pathname.startsWith("/fr")
) {
return undefined;
}
if (language === "fr") {
url.pathname = `/fr${nextUrl.pathname}`;
return NextResponse.redirect(url);
}
if (language === "de") {
url.pathname = `/de${nextUrl.pathname}`;
return NextResponse.redirect(url);
}
if (!["de", "fr"].includes(language)) {
url.pathname = `/en${nextUrl.pathname}`;
return NextResponse.redirect(url);
}
return undefined;
} catch (error) {
console.log(error);
}
}

即使Next.js不再直接支持i18n与新的应用程序目录相结合,仍然有办法解决这个问题。。。

在中间件的帮助下,通过使用i18next、react-i18next和i18next资源来后端,这是可以解决的。

它适用于服务器端和客户端。

有一个小例子展示了如何通过在服务器端和客户端使用i18next和react-i18next来直接工作。

这里是相应的博客文章。

关于这可能是什么样子的剪报:

服务器端:

import Link from 'next/link'
import { useTranslation } from '../i18n'
import { Footer } from './components/Footer'
export default async function Page({ params: { lng } }) {
const { t } = await useTranslation(lng)
return (
<>
<h1>{t('title')}</h1>
<Link href={`/${lng}/second-page`}>
{t('to-second-page')}
</Link>
<br />
<Link href={`/${lng}/client-page`}>
{t('to-client-page')}
</Link>
<Footer lng={lng}/>
</>
)
}

客户端:

'use client'
import Link from 'next/link'
import { useTranslation } from '../../i18n/client'
import { Footer } from '../components/Footer/client'
import { useState } from 'react'
export default function Page({ params: { lng } }) {
const { t } = useTranslation(lng, 'client-page')
const [counter, setCounter] = useState(0)
return (
<>
<h1>{t('title')}</h1>
<p>{t('counter', { count: counter })}</p>
<div>
<button onClick={() => setCounter(Math.max(0, counter - 1))}>-</button>
<button onClick={() => setCounter(Math.min(10, counter + 1))}>+</button>
</div>
<Link href={`/${lng}`}>
<button type="button">
{t('back-to-home')}
</button>
</Link>
<Footer lng={lng} />
</>
)
}

最新更新