pnpm add next-intl
使用 App Router with routing 的国际化配置,根据官网配置完成后,文件结构如下:
├── messages
│ ├── en.json
│ └── ...
├── next.config.ts
└── src
├── i18n
│ ├── routing.ts
│ ├── navigation.ts
│ └── request.ts
├── middleware.ts
└── app
└── [locale]
├── layout.tsx
└── page.tsx
支持静态渲染
1.在 layout.tsx 中添加 generateStaticParams 方法,为所有路由开启静态渲染
// src/app/[locale]/layout.tsx
import {routing} from '@/i18n/routing';
export function generateStaticParams() {
return routing.locales.map((locale) => ({locale}));
}
setRequestLocale
设置请求的国际化语言// src/app/[locale]/layout.tsx
import { setRequestLocale } from 'next-intl'
setRequestLocale(locale)
// src/app/[locale]/page.tsx
import { setRequestLocale } from 'next-intl'
setRequestLocale(locale)
根域名需要重定向到默认语言
// src/app/page.tsx
import { redirect } from 'next/navigation'
export default function RootPage() {
redirect('/en')
}
切换域名使用i18n自带的router.replace()
,保留当前用户访问路径
// LocaleSwitcherSelect.tsx
'use client'
import { useParams, usePathname, useRouter } from '@/i18n/navigation'
import { Locale, routing } from '@/i18n/routing'
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu'
import { Languages } from 'lucide-react'
import { useLocale, useTranslations } from 'next-intl'
import { useTransition } from 'react'
type Props = {
defaultValue: string
items: Array<{ value: string; label: string }>
label: string
}
function LocaleSwitcherSelect({ defaultValue, items, label }: Props) {
const [isPending, startTransition] = useTransition()
const router = useRouter()
const pathname = usePathname()
const params = useParams()
function onChange(value: string) {
const nextLocale = value as Locale
startTransition(() => {
router.replace(
{ pathname, params },
{ locale: nextLocale },
)
})
}
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<div className="hover:bg-accent hover:text-accent-foreground cursor-pointer p-2 transition-colors">
<Languages className="size-4" />
</div>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
{items.map((item) => (
<DropdownMenuItem
key={item.value}
onClick={() => onChange(item.value)}
>
{item.label}
</DropdownMenuItem>
))}
</DropdownMenuContent>
</DropdownMenu>
)
}
export default function LocaleSwitcher() {
const t = useTranslations('LocaleSwitcher')
const locale = useLocale()
return (
<LocaleSwitcherSelect
defaultValue={locale}
items={routing.locales.map((locale) => ({
value: locale,
label: t(locale),
}))}
label={t('label')}
/>
)
}