Skip to content

ExpressJS - 国际化 (i18n)

国际化,通常缩写为 i18n,是指在不进行工程更改的情况下,设计软件应用程序以使其能够适应各种语言和地区的过程。本教程将演示如何在现代 Express.js 应用程序中实现 i18n。

我们将使用一套强大且流行的库来处理翻译:

  • i18next:核心 i18n 框架,提供主要的翻译功能。
  • i18next-http-middleware:一个现代的中间件,用于检测用户语言并将 i18n 功能集成到 Express 的请求和响应中。
  • i18next-fs-backend:i18next 的一个后端模块,用于从本地文件系统加载翻译资源。

首先,初始化一个新的 Node.js 项目,并安装 Express 和所需的 i18n 模块。

# 1. Create a new project directory
mkdir express-i18n-example && cd express-i18n-example
# 2. Initialize a Node.js project
npm init -y
# 3. Install dependencies
npm install express i18next i18next-http-middleware i18next-fs-backend

以结构化的方式组织你的翻译文件。一种常见的做法是创建一个 locales 目录,并在其中为每种语言创建子目录。

.
├── locales/
│ ├── en/
│ │ └── translation.json
│ └── fr/
│ └── translation.json
├── node_modules/
├── index.js
└── package.json
{
"welcome": "Welcome to our modern Express application!",
"greeting": "Hello, {{name}}! We are glad to have you here."
}
{
"welcome": "Bienvenue dans notre application Express moderne !",
"greeting": "Bonjour, {{name}} ! Nous sommes ravis de vous avoir ici."
}

现在,让我们在主应用程序文件 index.js 中配置 i18next 并应用其中间件。

// index.js
import express from 'express';
import i18next from 'i18next';
import Backend from 'i18next-fs-backend';
import middleware from 'i18next-http-middleware';
// 初始化 i18next
i18next
.use(Backend) // 从文件系统加载翻译
.use(middleware.LanguageDetector) // 从请求中检测用户语言
.init({
fallbackLng: 'en',
backend: {
loadPath: './locales/{{lng}}/translation.json',
},
detection: {
order: ['querystring', 'cookie', 'header'],
caches: ['cookie'],
lookupQuerystring: 'lang', // e.g., /?lang=fr
lookupCookie: 'i18next',
},
// 建议对值进行转义以防止 XSS 攻击
// 如果不使用已执行此操作的前端库。
interpolation: {
escapeValue: true
}
});
const app = express();
const PORT = process.env.PORT || 3000;
// 应用 i18next 中间件
app.use(middleware.handle(i18next));
// --- 路由 ---
app.get('/', (req, res) => {
// t 函数由中间件添加到 req 对象中
res.status(200).send(req.t('welcome'));
});
app.get('/greet/:name', (req, res) => {
const { name } = req.params;
res.status(200).send(req.t('greeting', { name }));
});
// 基本错误处理
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).send('Something broke!');
});
app.listen(PORT, () => {
console.log(`Server is running on http://localhost:${PORT}`);
});
  • import 语法:我们使用现代 ES6 模块语法。要启用此功能,请在 package.json 文件中添加 "type": "module"。
  • .use(Backend):配置 i18next-fs-backend 以读取翻译 JSON 文件。
  • .use(middleware.LanguageDetector):这个强大的检测器通过检查(按顺序)查询字符串参数 (?lang=fr)、cookie 和 Accept-Language HTTP 头来自动查找用户首选语言。
  • fallbackLng: 'en':如果在检测到的语言中找不到翻译键,它将回退到英语。
  • app.use(middleware.handle(i18next)):这是将 i18next 集成到 Express 请求-响应生命周期的关键步骤,使 req.t() 函数在所有后续路由中可用。

使用 node index.js 运行你的服务器。现在你可以测试不同的语言输出了。

  • 默认(英语):打开你的浏览器或使用 curl:curl http://localhost:3000/
  • 通过查询字符串设置法语:curl "http://localhost:3000/?lang=fr"
  • 英语问候语:curl http://localhost:3000/greet/Alex
  • 法语问候语:curl "http://localhost:3000/greet/Alex?lang=fr"
  • 翻译未加载:仔细检查 i18next.init() 配置中的 loadPath。确保它正确指向相对于你运行 Node 进程的 locales 目录。
  • req.t is not a function:此错误表示 i18next-http-middleware 配置不正确或放置在你的路由之后。确保 app.use(middleware.handle(i18next)); 在定义任何路由之前调用。
  • ESM import 语法错误:如果你看到类似 SyntaxError: Cannot use import statement outside a module 的错误,请确保你已在 package.json 文件中添加了 "type": "module"。