Skip to content

Conversation

@caohuilin
Copy link
Member

Summary

背景

目前,在 Modern.js 中实现基于路径的国际化 (Pathname-based Internationalization) 路由需要开发者手动处理许多重复性工作,例如:

  1. 初始重定向:在服务端将访问根路径 (/) 的用户重定向到默认语言路径 (如 /en)。
  2. 状态同步:确保 URL 中的语言参数 (:lang)、i18n 实例状态和应用状态在 SSR 和 CSR 之间保持一致。
  3. 语言切换:在切换语言时,需要手动操作 URL,这不仅繁琐而且容易出错。

为了解决这些痛点,我们引入了一个新的官方插件 @modern-js/plugin-i18n,旨在提供一套开箱即用、遵循最佳实践的 i18n 路由解决方案。

方案描述

本 PR 引入了 @modern-js/plugin-i18n,其核心设计理念是“明确优于隐式”。插件要求开发者在文件系统中显式创建 [lang] 动态路由,并在此基础上提供一系列自动化工具来简化开发。

主要特性包括:

  1. 自动服务端重定向
  • 实现:通过 Server 插件注册一个全局中间件。

  • 行为:当请求的路径不带语言前缀时(如 /about),中间件会返回一个 Redirect 响应,将其重定向到配置的回退语言路径(如 /en/about)。这确保了良好的 SEO 和用户体验。

  1. 语言状态自动初始化
  • 实现:利用 Runtime 插件的 onBeforeRender 钩子。

  • 行为:在每次页面渲染前(SSR/CSR),插件会从 URL 的 params.lang 中读取当前语言,并用它来初始化 i18next 实例。这确保了在 SSR 场景下每个请求的语言状态都是隔离且正确的。

  1. 便捷的运行时 API

    我们提供了两个核心的运行时工具,从 @modern-js/plugin-i18n/runtime 导出:

a. useModernI18n

  • 返回 { language, changeLanguage }。
    • language: 当前的语言字符串,派生自 URL。
    • changeLanguage(newLang): 一个函数,调用它会同时更新 i18next 状态和 URL 路径,自动处理路由跳转。

b. I18nLink 组件:

封装了 Modern.js 的原生 Link 组件。

开发者只需提供不带语言前缀的路径,如 ,组件会自动将其转换为带当前语言前缀的完整路径,如 /en/about。

使用示例

  1. 项目安装 i18nextreact-i18next 依赖

  2. 配置 modern.config.ts

import { appTools, defineConfig } from '@modern-js/app-tools';
import { i18nPlugin } from '@modern-js/plugin-i18n';
export default defineConfig({
  plugins: [
    appTools(),
    i18nPlugin({
      localeDetection: {
        enable: true,
        languages: ['en', 'zh'],
        fallbackLanguage: 'en',
      },
    }),
  ]
});
  1. 配置 src/modern.runtime.ts
import { defineRuntimeConfig } from '@modern-js/runtime';

export default defineRuntimeConfig({
  i18n: {
    initOptions: {
      resources: {
        en: {
          translation: {
            key: 'Hello World',
            about: 'About',
          },
        },
        zh: {
          translation: {
            key: '你好,世界',
            about: '关于',
          },
        },
      },
    },
  },
});
  1. 创建路由文件,将当前路由都移动到 routes/[lang] 下面
src
├── modern.runtime.ts
└── routes
    ├── [lang]             // 用户显式创建的动态路由目录
    │   ├── about
    │   │   ├── page.data.ts
    │   │   └── page.tsx
    │   ├── layout.tsx     // 这个布局可以获取到 lang 参数
    │   └── page.tsx       // 对应 /:lang
    └── layout.tsx         // 全局根布局

其他使用姿势可以参考 PR 中测试用例

Related Links

Checklist

  • I have added changeset via pnpm run change.
  • I have updated the documentation.
  • I have added tests to cover my changes.

@changeset-bot
Copy link

changeset-bot bot commented Oct 17, 2025

⚠️ No Changeset found

Latest commit: dea0b9f

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@caohuilin caohuilin enabled auto-merge (squash) October 20, 2025 11:17
@caohuilin caohuilin merged commit ad93c32 into main Oct 20, 2025
13 of 14 checks passed
@caohuilin caohuilin deleted the chore/i18n-plugin branch October 20, 2025 11:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants