You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Express+EJS+i18next SSR项目:前端语言切换及路由优化问题

解决方案

1. 配置前缀式路由与i18next语言检测

调整入口文件(app.js)的配置,实现路径前缀语言识别、Cookie缓存及多方式语言检测:

const express = require('express');
const i18next = require('i18next');
const i18nextMiddleware = require('i18next-http-middleware');
const Backend = require('i18next-fs-backend');
const cookieParser = require('cookie-parser');

const app = express();
app.use(cookieParser());

// 初始化i18next
i18next
  .use(Backend)
  .use(i18nextMiddleware.LanguageDetector)
  .init({
    fallbackLng: 'en',
    supportedLngs: ['en', 'de'], // 替换为你支持的语言列表
    backend: {
      loadPath: './locales/{{lng}}/{{ns}}.json' // 翻译文件存储路径
    },
    detection: {
      order: ['path', 'cookie', 'querystring'], // 优先级:路径前缀 > Cookie > 查询参数
      lookupPath: 'lng',
      lookupCookie: 'i18next',
      lookupQuerystring: 'lang',
      caches: ['cookie'], // 将语言偏好缓存到Cookie
      excludeRoutes: ['/api'] // 排除不需要国际化的路由(如API)
    }
  });

// 应用i18next中间件
app.use(i18nextMiddleware.handle(i18next));

// 处理语言前缀路由:提取路径中的语言标识,修正路由匹配
app.use((req, res, next) => {
  const supportedLngs = i18next.options.supportedLngs;
  const urlSegments = req.path.split('/');
  const detectedLng = urlSegments[1];

  if (supportedLngs.includes(detectedLng)) {
    req.i18n.changeLanguage(detectedLng);
    // 移除语言前缀,让后续路由正常匹配
    req.url = urlSegments.slice(2).join('/') || '/';
  }
  next();
});

// 配置EJS模板引擎
app.set('view engine', 'ejs');
app.set('views', './views');

// 挂载路由
const routes = require('./routes');
app.use('/', routes);

app.listen(3000, () => console.log('Server running on port 3000'));

2. 简化路由文件

路由文件(routes/index.js)无需重复编写语言前缀,直接保留原有路由结构即可:

const express = require('express');
const router = express.Router();

router.get('/', (req, res) => {
  res.render('index', {
    currentLng: req.i18n.language,
    supportedLngs: req.i18n.options.supportedLngs
  });
});

router.get('/about', (req, res) => {
  res.render('about', {
    currentLng: req.i18n.language,
    supportedLngs: req.i18n.options.supportedLngs
  });
});

module.exports = router;

3. 实现前端语言切换器

在EJS模板中添加语言切换组件,动态生成对应语言前缀的路由:

语言切换组件(views/partials/language-switcher.ejs)

<div class="language-switcher">
  <% supportedLngs.forEach(lng => { %>
    <% if (lng !== currentLng) { %>
      <%// 生成当前页面的对应语言路由 %>
      <% const cleanPath = req.originalUrl.replace(/^\/[a-z]{2}/, '') || '/'; %>
      <a href="/<%= lng %><%= cleanPath %>" class="lang-link"><%= lng.toUpperCase() %></a>
    <% } else { %>
      <span class="lang-active"><%= lng.toUpperCase() %></span>
    <% } %>
  <% }) %>
</div>

在页面模板中引入组件(如views/index.ejs)

<!DOCTYPE html>
<html lang="<%= currentLng %>">
<head>
  <meta charset="UTF-8">
  <title><%= t('home.title') %></title>
</head>
<body>
  <% include partials/language-switcher.ejs %>
  <h1><%= t('home.heading') %></h1>
  <p><%= t('home.description') %></p>
</body>
</html>

4. 前端JS触发语言切换(可选)

如果需要用按钮而非链接触发切换,可添加以下JS逻辑(嵌入模板或单独JS文件):

function changeLanguage(targetLng) {
  // 设置Cookie存储语言偏好
  document.cookie = `i18next=${targetLng}; path=/; max-age=31536000`;
  // 生成对应语言的当前页面路由并跳转
  const cleanPath = window.location.pathname.replace(/^\/[a-z]{2}/, '') || '/';
  window.location.href = `/${targetLng}${cleanPath}`;
}

// 绑定按钮事件
document.querySelectorAll('.lang-btn').forEach(btn => {
  btn.addEventListener('click', (e) => {
    e.preventDefault();
    changeLanguage(btn.dataset.lng);
  });
});

对应的按钮形式切换组件:

<div class="language-switcher">
  <% supportedLngs.forEach(lng => { %>
    <% if (lng !== currentLng) { %>
      <button class="lang-btn" data-lng="<%= lng %>"><%= lng.toUpperCase() %></button>
    <% } else { %>
      <span class="lang-active"><%= lng.toUpperCase() %></span>
    <% } %>
  <% }) %>
</div>

5. 验证依赖配置

确保package.json包含必要依赖:

{
  "name": "ssr-i18n-app",
  "version": "1.0.0",
  "dependencies": {
    "express": "^4.18.2",
    "ejs": "^3.1.9",
    "i18next": "^23.7.16",
    "i18next-fs-backend": "^2.3.1",
    "i18next-http-middleware": "^3.5.0",
    "cookie-parser": "^1.4.6"
  }
}

关键说明

  • 路径前缀匹配:访问/de/about会自动识别德语,渲染对应翻译内容;访问/en/about则用英语。
  • Cookie缓存:切换语言后,Cookie会存储偏好,下次访问自动加载对应语言。
  • 查询参数兼容:临时切换可使用/?lang=de,访问后Cookie会更新该语言偏好。

内容的提问来源于stack exchange,提问作者druj_nasu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 12:57:24