ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Sails.js `req.setLocale()` 详解:按请求覆盖语言偏好实现用户自定义国际化

Sails.js `req.setLocale()` 详解:按请求覆盖语言偏好实现用户自定义国际化 Sails.jsreq.setLocale()详解按请求覆盖语言偏好实现用户自定义国际化【免费下载链接】sailsRealtime MVC Framework for Node.js项目地址: https://gitcode.com/gh_mirrors/sa/sailsreq.setLocale()是 Sails.js 内置国际化i18n能力中用于按单个请求覆盖语言推断的实例方法。正常情况下Sails 会依据请求头如浏览器的Accept-Language为每个请求自动确定 locale而req.setLocale(override)允许你在控制器、策略policies或 action 中主动指定该请求后续使用的语言典型场景是让登录用户选择自己的偏好语言。读完本文你将掌握该方法的调用语法、底层实现原理以及结合数据库用户偏好与视图渲染的完整实战方案。为什么需要req.setLocale()Sails 的 i18n 机制默认通过 i18n hook见 lib/hooks/i18n/index.js在每次请求时读取请求头推断用户的语言偏好浏览器、移动设备通常会自动携带Accept-Language头服务端据此在已配置的 locales 中选择匹配项用于翻译。问题在于语言头大多数时候是对的但并不总是。例如用户借用了别人的设备、浏览器语言设置与用户实际习惯不符或请求来自不发送语言头的客户端cURL、Postman、IoT 设备、命令行脚本等。此时 Sails 会回退到defaultLocale而应用可能需要让用户显式指定语言——这正是req.setLocale()存在的意义在单次请求的生命周期内覆盖自动推断出的 locale 设置。相关概念文档 Internationalization 中明确指出Sometimes, it is useful to override browser/device language headers -- for example, if you want to allow a user to set their own language preference. Whether such a preference is session-based or associated with their account in the database, this is pretty straightforward to accomplish usingreq.setLocale().调用语法req.setLocale(override);参数override是一个字符串表示目标语言环境的唯一代码locale code例如de、es、fr。该代码必须与config/locales/目录下的翻译文件名stringfile对应例如调用req.setLocale(de)后本次请求的翻译将使用config/locales/de.json中的字符串。底层实现从源码看req.setLocale()如何工作i18n hook 中的注册逻辑req.setLocale并非框架核心自带的方法而是由 i18n hook 在expressMiddleware阶段注入的。查看 lib/hooks/i18n/index.js 的expressMiddleware实现// Try to create a new i18n instance. This is necessary because // locale is set on a per-instance basis, and the request header // may change the locale for a given instance (but we wouldnt // want it to change for the instance connected to sails.__() ) try { req.i18n new i18nFactory({ locales: sails.config.i18n.locales, defaultLocale: sails.config.i18n.defaultLocale, directory: resolvedLocalesDirectory, extension: I18N_LOCALES_FILE_EXTENSION, request: req }); // Mix translation capabilities into res.locals. i18nFactory.registerMethods(res.locals, req); // Add setLocale() method for convenience. // (This is documented and fully supported as of Sails v1.0 and beyond.) req.setLocale req.i18n.setLocale.bind(req.i18n); // For backwards compatibility: // • Add i18n method as alias to __ // • Add getLocale() method to req res.locals.i18n res.locals.__; req.getLocale req.i18n.getLocale.bind(req.i18n); } catch (e) { ... }从中可以提炼出几个关键实现事实每个请求独立实例hook 为每个请求基于i18nFactory底层是i18n-2包见 package.json 中i18n-2: 0.7.3创建独立的req.i18n实例并把request: req传入。这样req.setLocale()只影响当前请求不会污染全局的sails.__()服务于 shell 脚本等场景的默认 locale 实例。绑定方式req.setLocale req.i18n.setLocale.bind(req.i18n)即直接复用 i18n-2 库实例的setLocale方法因此方法行为与 i18n-2 保持一致。视图侧可用i18nFactory.registerMethods(res.locals, req)把__等翻译方法混入res.locals并保持res.locals.i18n作为__的别名所以视图模板EJS 等里可以直接用% __(Hello) %。触发时机该 middleware 通过 shadow route 绑定到all /*即所有路由都会经过它因此在任何 action/控制器中调用req.setLocale()时方法一定可用前提是 i18n hook 未被禁用且sails.config.i18n.locales非空。视图渲染时如何继承覆盖结果req.setLocale()覆盖的是本次请求的 locale视图渲染会继承这一结果查看 lib/hooks/views/render.js渲染视图前会检查 i18n hook 是否启用并依据请求头 / 显式 locale 选项设置accept-language后调用expressMiddleware。因此在控制器中先req.setLocale(es)再return res.view(...)页面中所有% __(...) %都会按西班牙语翻译输出。完整示例让用户选择自己的语言原文档给出了两种风格的使用示例这里完整保留并展开。场景一使用 actions2Web app 模板 / 现代写法在 actions2 风格的 action 中req通过this.req访问。示例中先从当前登录用户记录里读取preferredLocale字段若存在则覆盖本次请求的语言// api/controllers/...actions2 风格 if (this.req.me.preferredLocale) { this.req.setLocale(this.req.me.preferredLocale); } return exits.success();this.req.me是经策略policies注入的当前登录用户对象。假设用户偏好存于User模型的preferredLocale属性此写法即实现了用户语言偏好跟随账号。场景二不使用 actions2 / 传统写法如果未使用 Web app 模板或 actions2可在控制器中手动查询用户并覆盖var me await User.findOne({ id: req.session.userId }); if (me.preferredLocale) { req.setLocale(me.preferredLocale); } return res.view(pages/homepage);该写法把语言覆盖放在渲染视图之前后续res.view(pages/homepage)渲染出的页面内容即按用户偏好语言输出。实战扩展会话级偏好 默认值兜底结合req.session与defaultLocale的完整兜底逻辑可以写成// api/controllers/account/... 或某个 policy 中 module.exports function (req, res, next) { // 1. 会话中已选择的语言优先 if (req.session.language) { req.setLocale(req.session.language); } // 2. 其次读数据库中的账号偏好 else if (req.me req.me.preferredLocale) { req.setLocale(req.me.preferredLocale); } // 3. 否则保持请求头推断 / defaultLocale return next(); };配套配置sails.config.i18nreq.setLocale()只负责选语言而支持哪些语言、默认语言是什么、翻译文件放哪由 sails.config.i18n 决定按惯例配置在config/i18n.js参见 config/i18n.js 文档。三个核心属性如下属性类型默认值说明locales((array))[en,es,fr,de]支持的 BCP 47 语言代码列表。注意这些值及其对应翻译文件的文件名必须是小写localesDirectory((string))config/locales存放翻译字符串文件stringfiles的目录支持应用相对路径或绝对路径defaultLocale((string))en站点默认语言。对携带Accept-Language头的请求多数浏览器会被覆盖但对不发送语言头的客户端移动设备、IoT、cURL、Postman 等仍然生效从 lib/hooks/i18n/index.js 的configure阶段可以看到框架对配置的校验与规整sails.config.i18n.locales必须是字符串数组否则抛出错误localesDirectory必须是字符串若defaultLocale出现在locales列表中会被移动到列表最前用于规避 i18n-2 的一个已知问题。另外若locales为空数组i18n hook 会自行停用见 lib/hooks/i18n/index.js此时sails.__/sails.i18n退化为直接返回输入字符串并打印警告req.setLocale()也不会再被注入——这是调试时值得注意的前提条件。准备 locale 文件stringfiles要保证req.setLocale(es)真的能翻出西班牙语config/locales/目录下必须有es.json。文件是 JSON 键值对键名即翻译条目详见 Locales 文档。示例config/locales/es.json{ Hello!: Hola!, Hello %s, how are you today?: ¿Hola %s, como estas? }几个实用要点键名区分大小写、要求精确匹配例如Welcome与welcome是两个不同的条目支持%s占位符翻译时传入参数即可如sails.__(Welcome, %s, Mary)用.表示嵌套键便于组织页面级字符串例如editProfile.heading: Edit your profile更易于手工维护的做法是使用全小写键名如hello: hola配合英文 fallback 文件en.json。仓库测试中使用的语言文件可参考 test/hooks/views/locales/en.jsonhello: Hello与 test/hooks/views/locales/es.jsonhello: Hola。测试验证req.setLocale()的行为证据仓库的集成测试 test/integration/hook.i18n.test.js 为该方法提供了可复现的行为验证。关键用例L44-L108/test_req_setlocale: function(req, res) { req.setLocale(es); res.send(req.i18n.__(Welcome)); },测试断言req.setLocale(es)之后req.i18n.__(Welcome)返回Bienvenido。同类用例还验证了默认未覆盖时sailsApp.__(Welcome)返回Welcome英文req.getLocale()依据Accept-Language: es请求头返回es证明自动推断确实来自请求头sails.hooks.i18n.setLocale(fr)后翻译输出Bienvenue法语de对应Willkommen德语当config/i18n.js配置locales: [en, de], defaultLocale: de时见 L156-L201sailsApp.__(Welcome)直接返回Willkommen验证了默认 locale 的兜底作用。这些测试同时演示了req.i18n()与__()两种翻译调用方式的等价性源码中res.locals.i18n res.locals.__即为后向兼容别名。注意事项与边界仅作用于当前请求req.setLocale()覆盖的是单次请求的生命周期不改变全局默认 locale也不影响其他并发请求。若需在 shell 脚本或全局范围翻译应使用sails.__()默认 locale 实例。hook 启用的前提i18n hook 默认开启但若sails.config.i18n.locales为空数组hook 会停用req.setLocale将不存在且sails.__变为透传函数。locale 代码必须受支持传入的代码最好在sails.config.i18n.locales列表内并且目录中存在对应的翻译文件否则翻译会回退到默认语言或直接返回原字符串。自定义与替代方案Sails 允许通过loadHooks/hooks配置完全禁用或替换 i18n hook也可以在任何位置require()第三方 Node 模块实现自己的国际化策略。客户端 i18nreq.setLocale()只影响服务端渲染若使用纯前端 SPA静态模板托管于 CDN 等需要引入客户端侧 i18n 方案或借助 Sails 的 i18n 支持在构建期预编译并翻译/views下的客户端模板。小结req.setLocale(override)是 Sails 国际化体系中按请求粒度控制语言的官方入口它基于请求头自动推断通过 i18n hook 为每个请求创建独立实例实现按需覆盖。配合sails.config.i18n的 locales 声明、config/locales/下的 JSON stringfiles以及数据库/会话中保存的用户偏好即可用寥寥数行代码交付完整的用户可选语言体验。相关配套文档可继续阅读 Internationalization、Locales 与 sails.config.i18n。【免费下载链接】sailsRealtime MVC Framework for Node.js项目地址: https://gitcode.com/gh_mirrors/sa/sails创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表