news 2026/9/17 20:10:56

NocoBase RunJS 国际化翻译指南:精通 ctx.t() 的多语言文案方案

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
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/nocobase

ctx.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.ts):

runCtx.defineMethod('t', (key: string, options?: any) => { return this.t(key, { ns: 'runjs', ...options }); });

这段实现揭示了两个关键事实:

  1. ctx.t()底层委托给引擎的翻译方法,并自动注入默认命名空间runjs
  2. 你传入的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.tsJSFieldRunJSContext.tsJSColumnRunJSContext.tsJSItemRunJSContext.tsJSCollectionActionRunJSContext.tsJSRecordActionRunJSContext.ts等上下文实现,它们统一通过createJSRunner获得t方法(见 flowContext.ts)。

类型定义

t(key: string, options?: Record<string, any>): string

参数说明

参数类型说明
keystring翻译 key 或带占位符的模板(如Hello {{name}}{{count}} rows
optionsobject可选。插值变量(如{ name: '张三', count: 5 }),或 i18n 选项(如defaultValuens

参数语义的源码印证

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; }

也就是说:只要翻译实例存在,keyoptions会被原样透传给 i18next;若翻译结果为空或翻译函数缺失,则回退返回 key 本身。这决定了下方“返回值”的行为。

返回值

  • 返回翻译后的字符串;
  • 若 key 无对应翻译且未提供defaultValue,可能返回 key 本身或经插值后的字符串;
  • 若翻译函数缺失(例如本地化能力未就绪),直接返回 key 原样(源码见 flowI18n.ts)。

命名空间(ns)

RunJS 环境的默认命名空间为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命名空间下,便于本地化管理与复用。

示例

简单 key

ctx.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.success(Ant 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.i18n):

interface i18n: { language: string; changeLanguage(lng: string): Promise<any>; }

常用组合用法:

// 读取当前语言 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.ts):

flowEngine.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.ts:ctx.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),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/17 20:10:17

基于树莓派与Python的黄瓜病斑识别系统设计与部署

简介&#xff1a;基于树莓派和Python的黄瓜病斑识别系统设计文档&#xff0c;面向农业信息化、嵌入式视觉方向的开发者与相关专业学生&#xff0c;系统讲解利用树莓派3B、摄像头及Python完成黄瓜叶片图像采集、预处理、OTSU分割、灰度化与中值滤波去噪&#xff0c;并依据病斑面…

作者头像 李华
网站建设 2026/9/17 20:05:45

UL 2271-2018英文原版解读:锂电池BMS充放电管理与试验落地

简介&#xff1a;面向轻型电动车&#xff08;LEV&#xff09;锂电池研发、认证与检测人员的ANSI/CAN/UL/ULC 2271-2018英文原版标准&#xff0c;文字可直接复制&#xff0c;便于检索条款、摘录原文与翻译对照。该标准由ANSI、SCC、ULC与UL联合发布&#xff0c;第二版日期为2018…

作者头像 李华
网站建设 2026/9/17 20:05:38

控制流分析实战:CFG、支配树、数据流与循环优化

做静态分析或者编译器后端的人&#xff0c;大概都遇到过这种场面&#xff1a;一条自己觉得逻辑很清楚的检查规则&#xff0c;丢到真实项目里一跑&#xff0c;误报多到自己都不信&#xff1b;或者写了一个本地小例子跑得飞起的优化 pass&#xff0c;到了大工程上就开始把程序逻辑…

作者头像 李华
网站建设 2026/9/17 20:04:45

Swish与Hard-Swish激活函数:从原理到移动端部署实践

1. 先从激活函数说起&#xff1a;为什么 ReLU 不够用&#xff1f;1.1 激活函数的本质做深度学习的人&#xff0c;几乎每天都会跟激活函数打交道&#xff0c;但说实话&#xff0c;很多人对它的理解停留在“加一个非线性”这个层面。神经网络如果只有卷积、全连接这类线性操作&am…

作者头像 李华