Next.js 16 Page Router 国际化

Next.js 16 Page Router 国际化 🌐

引言

在现代 Web 应用开发中,国际化(i18n)已经成为一个必备功能。传统的 Next.js 国际化方案通常采用 URL 前缀方式(如 /en/page/zh-CN/page),这种方式虽然实现简单,但存在一些明显的问题:

  1. URL 频繁变更:用户切换语言时,页面 URL 会发生变化
  2. SEO 分散:相同内容分散在不同 URL 下,影响搜索引擎优化
  3. 用户体验不佳:复制链接时需要考虑语言前缀

那么,有没有一种方式可以在不改变 URL 的情况下实现国际化呢?答案是肯定的!本文将详细介绍我在 Next.js 16 项目中实现的无 URL 变更的国际化方案,采用浏览器缓存 + Cookie 机制管理语言切换,保持 URL 稳定的同时提供流畅的国际化体验。

技术栈

技术 版本 用途
Next.js 16.0.7 前端框架
React 19.2.0 UI 库
TypeScript 5.5.4 类型系统
next-i18next 15.4.3 国际化核心库
react-i18next 16.3.5 React 国际化集成
js-cookie 3.0.5 Cookie 管理
ahooks 3.9.6 React Hooks 工具库

项目结构

src/
├── components/            # 组件目录
│   └── I18nLngSelector.tsx  # 语言选择器组件
├── i18n/                 # 国际化配置目录
│   ├── hooks/            # 自定义 Hooks
│   │   └── useI18n.ts    # 语言切换钩子
│   ├── locales/          # 翻译资源文件
│   │   ├── en/           # 英文翻译
│   │   │   ├── common.json       # 通用翻译
│   │   │   └── index_page.json   # 首页翻译
│   │   └── zh-CN/        # 中文翻译
│   │       ├── common.json       # 通用翻译
│   │       └── index_page.json   # 首页翻译
│   ├── type.ts           # TypeScript 类型定义
│   └── i18next.d.ts      # 类型声明文件
└── pages/                # 页面目录
    ├── _app.tsx          # 应用入口(语言初始化)
    └── index.tsx         # 首页

核心实现

1. next-i18next 配置

首先,我们需要配置 next-i18next,创建 next-i18next.config.js 文件:

// next-i18next.config.js
// @ts-check

/**
 * @type {import('next-i18next').UserConfig}
 */
module.exports = {
   
   
  // 开发环境下启用调试模式
  debug: process.env.NODE_ENV === 'development',
  // 国际化配置
  i18n: {
   
   
    // 默认语言
    defaultLocale: 'zh-CN',
    // 支持的语言列表
    locales: ['zh-CN', 'en'],
    // 禁用自动语言检测,使用自定义逻辑
    localeDetection: false,
  },
  // 语言资源文件路径
  localePath: './src/i18n/locales',
  // 开发环境下在预渲染时重新加载语言资源
  reloadOnPrerender: process.env.NODE_ENV === 'development',
}

配置说明

  • debug: true:开发环境下启用调试模式,便于开发调试
  • defaultLocale: 'zh-CN':设置默认语言为中文
  • locales: ['zh-CN', 'en']:配置支持的语言列表
  • localeDetection: false:禁用自动语言检测,使用自定义的语言检测和切换逻辑
  • localePath: './src/i18n/locales':指定语言资源文件的存放路径

2. 自定义语言切换钩子

核心逻辑在于自定义的 useI18nLng 钩子,它负责处理语言的存储、切换和初始化:

// src/i18n/hooks/useI18n.ts
import {
   
    useTranslation } from 'next-i18next';
import {
   
    LangEnum } from '@/i18n/type';
import Cookies from "js-cookie";

// 语言存储的键名
const LANG_KEY = 'NEXT_LOCALE';

/**
 * 检查当前是否在 iframe 中
 */
const isInIframe = () => {
   
   
  try {
   
   
    return window.self !== window.top;
  } catch (e) {
   
   
    return true; // 发生异常时默认认为在 iframe 中
  }
};

/**
 * 设置语言到存储中
 */
const setLang = (value: string) => {
   
   
  if (isInIframe()) {
   
   
    // 在 iframe 中只使用 localStorage
    localStorage.setItem(LANG_KEY, value);
  } else {
   
   
    // 不在 iframe 中,同时使用 Cookie 和 localStorage
    Cookies.set(LANG_KEY, value, {
   
    expires: 30 }); // Cookie 有效期30天
    localStorage.setItem(LANG_KEY, value);
  }
};

/**
 * 从存储中获取语言
 */
const getLang = () => {
   
   
  return localStorage.getItem(LANG_KEY) || Cookies.get(LANG_KEY);
};

/**
 * 自定义 i18n 语言切换钩子
 */
export const useI18nLng = () => {
   
   
  // 获取 i18n 实例
  const {
   
    i18n } = useTranslation();
  
  // 语言映射表,确保语言代码的一致性
  const languageMap: Record<string, string> = {
   
   
    'zh-CN': LangEnum.zh_CN,
    en: LangEnum.en
### Next.js 路由 `Router` 的使用方法及配置 #### Pages Router 和 App Router 概述 Next.js 提供两种不同的路由机制:“Pages Router”和“App Router”。这两种方案可以共存于同一个项目中,允许开发者逐步迁移现有应用到新的路由体系[^1]。 #### 定义页面与路由 对于 **App Router** ,路由通过文件系统的结构来定义。每一个位于 `app` 目录下的 `.js` 或者 `.tsx` 文件都代表了一个独立的页面路径。例如,在 `app/about/page.tsx` 创建一个名为 "About" 页面,则访问 `/about` 将会加载这个组件作为响应。 ```javascript // app/about/page.jsx export default function AboutPage() { return ( <div> <h1>About Us</h1> {/* Page content */} </div> ); } ``` #### 动态路由支持 为了实现动态参数捕获,可以在文件名中加入方括号语法 `[param]` 来表示可变部分。比如要创建一个能够处理不同用户的个人资料页: ```bash app/users/[id]/page.jsx ``` 这使得当请求像 `/users/john` 这样的 URL 时,Next.js 自动解析并传递 `{ id: 'john' }` 给对应的 React 组件作为 props。 #### 国际化路由设置 如果应用程序需要多语言支持,可以通过安装第三方库如 `next-i18n-router` 实现国际化路由管理以及本地检测功能[^2]。此插件可以帮助简化跨多个地区版本的应用开发过程中的复杂度。 #### 测试环境下的模拟路由器行为 在编写单元测试期间,可能希望隔离真实的历史位置变化逻辑而采用虚拟替代品。为此目的,推荐利用 `jest` 结合 `next-router-mock` 库来进行模拟操作[^3]。 ```javascript // setupTests.js or at the top of your test file import { useRouter } from 'next/router'; jest.mock('next/router', () => require('next-router-mock')); ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值