NocoBase RunJS 国际化翻译指南:精通 ctx.t() 的多语言文案方案
NocoBase RunJS 国际化翻译指南精通 ctx.t() 的多语言文案方案【免费下载链接】nocobaseNocoBase is an open-source AI no-code platform for building business systems fast. Instead of generating everything from scratch, AI works on top of production-proven infrastructure and a WYSIWYG no-code interface, so you get both speed and reliability.项目地址: https://gitcode.com/GitHub_Trending/no/nocobasectx.t()是 NocoBase RunJS 执行环境提供的 i18n 快捷翻译函数用于在 JS 区块、JS 字段、JS 操作、事件流等场景中实现按钮、标题、提示等内联文案的国际化。本文以 RunJS 上下文 API 为基础结合 flow-engine 源码实现完整讲解ctx.t()的类型定义、参数语义、命名空间机制、插值用法以及与本地化插件、ctx.i18n的协作方式帮助你在多语言业务系统中写出可直接落地的翻译代码。RunJS 与 ctx.t() 的定位RunJS 是 NocoBase 中用于JS 区块JSBlock、JS 字段JSField、JS 操作等场景的 JavaScript 执行环境代码运行在受限沙箱中可安全访问ctx上下文 API并支持顶层await、导入外部模块、容器内渲染与全局变量见 RunJS 概述。ctx.t()正是该上下文中负责“翻译文案”的入口。从源码结构看RunJS 上下文的t方法由引擎在创建执行环境时统一注入见 flowContext.tsrunCtx.defineMethod(t, (key: string, options?: any) { return this.t(key, { ns: runjs, ...options }); });这段实现揭示了两个关键事实ctx.t()底层委托给引擎的翻译方法并自动注入默认命名空间runjs你传入的options会覆盖默认值因此可通过ns显式指定其他命名空间。在 RunJS 上下文的元数据声明中t被描述为“国际化函数用于翻译文案”见 runjs-context/contexts/base.ts其补全示例即ctx.t(你好 {{name}}, { name: 世界 })。适用场景所有 RunJS 执行环境均可使用ctx.t()包括但不限于JS 区块JSBlock整块自定义渲染内容中的文案JS 字段 / 可编辑字段JSField / JSEditableField字段展示与编辑界面的文案JS 项 / JS 列JSItem / JSColumn列表项与列头文案JS 操作JSCollectionAction / JSRecordAction按钮、确认提示等操作文案事件流、联动规则流程节点与联动逻辑中的动态文案。上述各场景分别对应 runjs-context/contexts 目录下的JSBlockRunJSContext.ts、JSFieldRunJSContext.ts、JSColumnRunJSContext.ts、JSItemRunJSContext.ts、JSCollectionActionRunJSContext.ts、JSRecordActionRunJSContext.ts等上下文实现它们统一通过createJSRunner获得t方法见 flowContext.ts。类型定义t(key: string, options?: Recordstring, any): string参数说明参数类型说明keystring翻译 key 或带占位符的模板如Hello {{name}}、{{count}} rowsoptionsobject可选。插值变量如{ name: 张三, count: 5 }或 i18n 选项如defaultValue、ns参数语义的源码印证options中的ns命名空间与插值变量是同时传递的。在 flowI18n.ts 的translateKey实现中翻译最终委托给 i18next 风格的实例private translateKey(key: string, options?: any): string { if (this.context?.i18n?.t) { const translated this.context.i18n.t(key, options); return translated null || translated ? key : translated; } // 如果没有翻译函数返回原始键值 return key; }也就是说只要翻译实例存在key与options会被原样透传给 i18next若翻译结果为空或翻译函数缺失则回退返回 key 本身。这决定了下方“返回值”的行为。返回值返回翻译后的字符串若 key 无对应翻译且未提供defaultValue可能返回 key 本身或经插值后的字符串若翻译函数缺失例如本地化能力未就绪直接返回 key 原样源码见 flowI18n.ts。命名空间nsRunJS 环境的默认命名空间为runjs。在不指定ns时ctx.t(key)会从runjs命名空间查找 key。这正对应上文createJSRunner注入时自动拼接的{ ns: runjs, ...options }。// 默认从 runjs 命名空间取 key ctx.t(Submit); // 等价于 ctx.t(Submit, { ns: runjs }) // 从指定命名空间取 key ctx.t(Submit, { ns: myModule }); // 从多个命名空间依次查找先 runjs再 common ctx.t(Save, { ns: [runjs, common] });说明ns支持字符串或字符串数组。传数组时按顺序依次查找适合“业务模块优先、公共词条兜底”的常见场景。默认命名空间runjs意味着 RunJS 相关文案应统一维护在runjs命名空间下便于本地化管理与复用。示例简单 keyctx.t(Submit); ctx.t(No data);带插值变量i18next 风格插值在 key 中使用{{变量名}}在options中传入同名变量即可替换。options中的值既可以是普通字符串/数字也可以是动态计算的结果。const text ctx.t(Hello {{name}}, { name: ctx.user?.nickname || Guest }); ctx.render(div${text}/div);ctx.message.success(ctx.t(Processed {{count}} rows, { count: rows.length }));上例结合ctx.message.successAnt Design 全局消息 API见 runjs-context/contexts/base.ts 的上下文元数据与ctx.render容器内渲染见 RunJS 概述 的“容器内渲染”小节可构造带数量的操作反馈。相对时间等动态文案if (minutes 60) return ctx.t({{count}} minutes ago, { count: minutes }); if (hours 24) return ctx.t({{count}} hours ago, { count: hours });这类“复数相对时间”文案同样走{{count}}插值翻译词条在目标语言中可按语言习惯组织例如中文可维护为“{{count}} 分钟前”“{{count}} 小时前”。指定命名空间ctx.t(Hello {{name}}, { name: Guest, ns: myModule });指定ns后本次翻译从myModule命名空间查找Hello {{name}}同时仍可携带插值变量二者互不干扰。渲染 JSX 中的翻译结合 RunJS 的 JSX 渲染能力RunJS 概述ctx.t()也常直接嵌入组件ctx.render(button{ctx.t(Submit)}/button);与 ctx.i18n 协作读取与切换语言翻译的语言由当前上下文决定如ctx.i18n.language、用户 locale。RunJS 上下文同时暴露ctx.i18n实例用于读取或切换语言官方约定翻译文案统一使用ctx.t()不要使用ctx.i18n.t见 ctx.i18n。ctx.i18n的类型定义见 ctx.i18ninterface i18n: { language: string; changeLanguage(lng: string): Promiseany; }常用组合用法// 读取当前语言 const lang ctx.i18n.language; // zh-CN | en-US | ... if (lang.startsWith(zh)) { ctx.render(ctx.t(中文界面)); } else { ctx.render(ctx.t(English UI)); }// 切换语言 await ctx.i18n.changeLanguage(en-US); await ctx.i18n.changeLanguage(zh-CN);一个完整的语言切换按钮示例复用ctx.libs.antd与 JSX 渲染const { Button } ctx.libs.antd; const isZh ctx.i18n.language.startsWith(zh); ctx.render( Button onClick{async () { await ctx.i18n.changeLanguage(isZh ? en-US : zh-CN); }} {ctx.t(isZh ? Switch to English : 切换到中文)} /Button, );引擎在定义locale属性时同样遵循该语言优先级api?.auth?.locale || i18n?.language见 flowContext.ts这与文档中“语言由当前上下文如ctx.i18n.language、用户 locale决定”的描述一致。引擎层的翻译机制模板编译与兜底插值除了简单 key引擎的FlowI18n还支持模板编译若 key 本身包含{{ t(...) }}形式的表达式会先编译再翻译见 flowI18n.tsflowEngine.t(Hello {name}, { name: John }); // 简单翻译 flowEngine.t({{ t(User Name, { ns: fields }) }}); // 模板编译 指定命名空间 flowEngine.t(前缀 {{ t(User Name) }} 后缀); // 混合文本对应的单元测试flowI18n.test.ts验证了以下行为普通 key 与{{ t(Hello) }}模板均能正确翻译Hello - 你好key 内嵌不同类型引号如含Post-action event的 key不会被错误截断畸形 options如{{ t(X, oops) }}会被安全降级为无 options 翻译并输出警告日志。此外当翻译函数不可用时如警告/降级提示路径引擎会执行轻量级兜底插值将{{var}}替换为options中的字符串或数字值见 flowContext.ts// lightweight interpolation for fallback strings (i18next-style: {{var}}) return fallback.replace(/\{\{\s*([a-zA-Z0-9_])\s*\}\}/g, (_m, k) { const v options?.[k]; return typeof v string || typeof v number ? String(v) : ; });这意味着即便在部分无法访问完整 i18next 实例的降级路径上{{变量}}插值仍能尽力工作。注意事项本地化插件如需翻译文案需先激活本地化插件。缺失翻译的词条会自动提取到本地化管理列表便于统一维护和翻译。仓库中对应插件位于 plugin-localization其服务端动作如 actions/localizationTexts.ts负责词条的提取与维护。插值语法支持 i18next 风格插值在 key 中使用{{变量名}}在options中传入同名变量即可替换。语言来源语言由当前上下文如ctx.i18n.language、用户 locale决定切换语言后再次调用ctx.t()即返回新语言文案。统一入口翻译文案一律使用ctx.t()不要使用ctx.i18n.tctx.i18n仅用于读取语言与切换语言见 ctx.i18n。默认命名空间ctx.t(key)默认从runjs命名空间取 key跨模块词条可通过ns显式指定。空结果回退当翻译结果为空字符串或 null 时引擎返回原始 key见 flowI18n.ts避免界面出现空白文案。相关ctx.i18n读取或切换语言RunJS 概述RunJS 执行环境、渲染与模块导入能力flowContext.tsctx.t()的注入实现flowI18n.ts引擎翻译与模板编译核心flowI18n.test.ts翻译行为单元测试【免费下载链接】nocobaseNocoBase is an open-source AI no-code platform for building business systems fast. Instead of generating everything from scratch, AI works on top of production-proven infrastructure and a WYSIWYG no-code interface, so you get both speed and reliability.项目地址: https://gitcode.com/GitHub_Trending/no/nocobase创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考