全栈开发个人博客02:国际化

next-intl 是一个用于 Next.js 应用的国际化库,简化了多语言支持,通过 useTranslations 和 FormattedMessage 等组件来管理翻译内容,支持构建时静态渲染,服务端组件和客户端组件都可以使用。

1. 配置国际化

  • 安装依赖
bash 复制代码
pnpm add next-intl
  • 使用 App Router with routing 的国际化配置,根据官网配置完成后,文件结构如下:
bash 复制代码
├── messages
│   ├── en.json
│   └── ...
├── next.config.ts
└── src
    ├── i18n
    │   ├── routing.ts
    │   ├── navigation.ts
    │   └── request.ts
    ├── middleware.ts
    └── app
        └── [locale]
            ├── layout.tsx
            └── page.tsx

2. 支持静态渲染

  1. 在 layout.tsx 中添加 generateStaticParams 方法,为所有路由开启静态渲染
tsx 复制代码
// src/app/[locale]/layout.tsx
import { routing } from '@/i18n/routing'
export function generateStaticParams() {
  return routing.locales.map((locale) => ({ locale }))
}
  1. 在 所有 layout.tsx 和 page.tsx 中使用 setRequestLocale 设置请求的国际化语言
tsx 复制代码
// src/app/[locale]/layout.tsx
import { setRequestLocale } from 'next-intl'

setRequestLocale(locale)
tsx 复制代码
// src/app/[locale]/page.tsx
import { setRequestLocale } from 'next-intl'

setRequestLocale(locale)

3. 根域名需要重定向到默认语言

tsx 复制代码
// src/app/page.tsx
import { redirect } from 'next/navigation'

export default function RootPage() {
  redirect('/en')
}

4. 切换域名使用i18n自带的router.replace(),保留当前用户访问路径

tsx 复制代码
// LocaleSwitcherSelect.tsx

'use client'
import { useParams } from 'next/navigation'
import { 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')}
    />
  )
}
相关推荐
濮水大叔33 分钟前
Cabloy 双引擎架构详解:Vona 与 Zova 是如何协作的
typescript·node.js·全栈
全栈Agent 小李12 小时前
【无标题】
前端·后端·agent·ai编程·全栈·cursor·mcp
三天不学习1 天前
Egg.js 4 突然爆火,原因是否归结于AI 原生落地需求爆发?
前端·javascript·全栈·egg.js
濮水大叔2 天前
AI 编码实战:一句提示词,实现 CRUD、SSR 与多任务
node.js·ai编程·全栈
SL_staff2 天前
Excel如何自动升级为可搜索的知识节点:JVS文档平台的语义解析实践
开源·github·全栈
白兰地空瓶2 天前
项目要上线了,我连夜学完 Docker:从底层原理到容器化部署全记录
docker·全栈
SL_staff3 天前
3分钟零代码配置带审批流的报销单:JVS三引擎可视化串联实战
spring boot·开源·全栈
泡泡oO3 天前
“如果你还在用Superpowers,那我不要和你说话”
前端·后端·全栈
布丁丁3 天前
测试通过但业务结果错误:断言应该怎么设计
测试·全栈
SL_staff3 天前
制造业数字化协同:为什么甘特图只是起点,不是终点
java·开源·全栈