You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在Express Node.js控制器中实现同步翻译助手?

嘿,这个需求我太懂了——在Express控制器里搞同步翻译,避开烦人的异步嵌套,还要给AJAX请求返回结构化的JSON错误信息,对吧?我给你几个实用的方案,都是我实际项目里用过的:

方案1:预加载翻译文件到内存(同步读取)

直接在启动时用Node.js的fs.readFileSync把所有翻译JSON文件同步读到内存里,之后控制器里就能直接同步获取翻译值,完全没异步问题。

先整个翻译模块translations.js

const fs = require('fs');
const path = require('path');

// 启动时一次性同步加载所有语言的翻译文件
const translations = {
  en: JSON.parse(fs.readFileSync(path.join(__dirname, 'locales/en.json'), 'utf8')),
  es: JSON.parse(fs.readFileSync(path.join(__dirname, 'locales/es.json'), 'utf8'))
};

// 同步翻译函数,支持嵌套key(比如'errors.email.invalid')
function translate(key, lang = 'en') {
  return key.split('.').reduce((current, keyPart) => current?.[keyPart], translations[lang]) || key;
}

module.exports = translate;

然后在控制器里直接用:

const translate = require('./translations');

exports.handleAjaxError = (req, res) => {
  // 从请求里拿当前语言(比如session、headers或者query参数)
  const userLang = req.session.lang || req.headers['accept-language']?.split(',')[0] || 'en';
  
  // 一次性获取多个翻译值,完全同步
  const errorMessages = {
    emailInvalid: translate('errors.email.invalid', userLang),
    passwordShort: translate('errors.password.short', userLang),
    authFailed: translate('errors.auth.failed', userLang)
  };

  res.status(400).json({ errors: errorMessages });
};
方案2:利用Node.js的require同步加载翻译模块

Node.js的require本身就是同步的,还会自动缓存模块,所以可以把每个翻译文件做成JS模块,直接require进来,比手动读JSON更简洁。

比如locales/en.js

module.exports = {
  errors: {
    email: {
      invalid: 'Invalid email address'
    },
    password: {
      short: 'Password must be at least 8 characters'
    },
    auth: {
      failed: 'Authentication failed'
    }
  }
};

然后翻译模块translations.js

// 同步加载各个语言的翻译模块
const translations = {
  en: require('./locales/en'),
  es: require('./locales/es')
};

function translate(key, lang = 'en') {
  return key.split('.').reduce((current, keyPart) => current?.[keyPart], translations[lang]) || key;
}

module.exports = translate;

控制器里的用法和方案1完全一样,这个方案更适合翻译内容有复杂逻辑的场景(比如翻译值是函数?不过一般很少用),而且不用手动解析JSON,Node.js会帮你处理。

方案3:用成熟的i18n库实现同步翻译

如果项目已经在用i18n相关的库,比如i18n这个npm包,它本身就支持同步翻译,只要配置时开启同步加载就行。

先安装并配置:

const i18n = require('i18n');
const express = require('express');
const app = express();

i18n.configure({
  locales: ['en', 'es'],
  directory: __dirname + '/locales', // 翻译文件放在这里,格式是en.json、es.json
  syncFiles: true, // 关键:同步加载翻译文件
  defaultLocale: 'en',
  register: global // 可选,把翻译方法挂到全局,方便使用
});

// 把i18n挂载到Express请求对象上
app.use(i18n.init);

然后控制器里直接用同步方法:

exports.handleAjaxError = (req, res) => {
  // 设置当前语言(从session、headers等地方取)
  req.setLocale(req.session.lang || 'en');
  
  // 用res.__()或者i18n.__()同步获取翻译值
  const errorMessages = {
    emailInvalid: res.__('errors.email.invalid'),
    passwordShort: res.__('errors.password.short'),
    authFailed: i18n.__('errors.auth.failed')
  };

  res.status(400).json({ errors: errorMessages });
};
几个关键注意点
  • 预加载/同步加载的好处是启动时加载一次,之后全是内存读取,速度极快,完全没有异步嵌套的问题,非常适合AJAX错误返回这种场景。
  • 如果翻译文件特别大,启动时加载可能会稍微慢一点,但对于绝大多数Web应用来说,这个代价完全可以接受。
  • 嵌套key的处理:用split('.')reduce的方法可以轻松解析像errors.email.invalid这种点分隔的嵌套键,不用写一堆translations.lang.errors.email.invalid的链式调用。
  • 如果需要动态更新翻译(比如不用重启服务器),可以加个定时任务,每隔一段时间用fs.readFileSync重新加载翻译文件,但如果没有这个需求,预加载就足够了。

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

火山引擎 最新活动