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
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值