国际化
RuleGo-Editor 支持国际化(i18n),允许你为编辑器界面提供多语言支持。通过配置语言包,可以自定义组件名称、表单标签、提示信息等文本内容。
# 用法
# 初始化时传入语言包
通过 options.locales 传入自定义语言包:
<RuleGoEditor
ref="ruleGoEditorRef"
:data="data"
:options="options"/>
<script setup>
import RuleGoEditor from './components/RuleGoEditor.vue'
import {ref} from "vue";
const ruleGoEditorRef = ref();
const data = ref();
// 自定义语言包
const locales = {
category: {
endpoints: { label: '输入端', background: '#A6BBCFFF', nodeType: 'endpoint-node' },
common: { label: '公共', background: '#D1D5DB', nodeType: 'simple-node' },
// ...其他分类
},
component: {
nodes: {
'jsFilter': {
label: 'JavaScript过滤器',
icon: '/images/jsFilter.svg',
desc: '使用JavaScript脚本进行过滤',
jsScript: { label: '脚本内容', desc: '输入JavaScript代码' }
}
// ...其他组件
}
},
relationTypes: {
'Success': '成功',
'Failure': '失败',
'True': '真',
'False': '假',
}
};
const options = ref({
locales: locales
});
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# 运行时设置语言包
通过 setLocales 方法动态设置语言包:
<RuleGoEditor ref="ruleGoEditorRef"/>
<script setup>
import RuleGoEditor from './components/RuleGoEditor.vue'
import {ref, onMounted} from "vue";
const ruleGoEditorRef = ref();
onMounted(() => {
// 动态设置语言包
const locales = {
// ...语言包内容
};
ruleGoEditorRef.value.setLocales(locales);
});
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 通过扩展方式注册
使用 extensions 扩展机制注册语言包:
<RuleGoEditor :extensions="extensions"/>
<script setup>
const extensions = [
{
locales: customLocales
}
]
</script>
2
3
4
5
6
7
8
9
# 语言包结构
语言包是一个 JavaScript 对象,包含以下几个主要部分:
# category - 组件分类
定义左侧工具栏中组件分类的显示名称和样式。
{
category: {
endpoints: {
label: '输入端', // 分类显示名称
background: '#A6BBCFFF', // 分类背景色
nodeType: 'endpoint-node' // 节点类型标识
},
common: { label: '公共', background: '#D1D5DB', nodeType: 'simple-node' },
filter: { label: '过滤器', background: '#f1e861', nodeType: 'simple-node' },
transform: { label: '转换器', background: '#79cef1', nodeType: 'simple-node' },
action: { label: '动作', background: '#f1928f', nodeType: 'simple-node' },
external: { label: '外部的', background: '#fbc766', nodeType: 'simple-node' },
ai: { label: 'AI', background: '#7cbaf8', nodeType: 'simple-node' },
knowledge: { label: '知识库', background: '#D1C4E9', nodeType: 'simple-node' },
ci: { label: 'CI/CD', background: '#9ec9c9', nodeType: 'simple-node' },
iot: { label: 'IoT', background: '#FFA500', nodeType: 'simple-node' },
flow: { label: '子规则链', background: '#E6E0F8FF', nodeType: 'simple-node' },
stats: { label: '流式计算', background: '#f1cfbd', nodeType: 'simple-node' },
storage: { label: '存储', background: '#b2d8d8', nodeType: 'simple-node' },
file: { label: '文件', background: '#ffe5b4', nodeType: 'simple-node' },
custom: { label: '自定义', background: '#C6EFCB', nodeType: 'simple-node' },
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# component - 组件定义
定义每个组件的详细信息,包括标签、图标、描述和表单字段。
# 输入端组件(endpoint)
{
component: {
endpoints: {
'endpoint/http': {
label: 'HTTP', // 组件显示名称
icon: '/images/endpoint/http.svg', // 组件图标路径
desc: 'HTTP服务器接入端', // 组件描述(支持 HTML)
notInput: true, // 标记为非普通输入节点
server: {
ref: 'primary', // 引用类型(连接池复用)
label: '监听地址',
rules: [{ required: true, message: '该项是必须的' }],
desc: '示例: :6335'
},
router: {
from: {
path: {
label: 'Path',
rules: [{ required: true, message: '该项是必须的' }],
desc: '客户端请求该URL触发,如:/api/v1/msg'
},
}
}
},
'endpoint/mqtt': {
label: 'MQTT',
icon: '/images/endpoint/mqtt.svg',
desc: 'MQTT订阅端点'
}
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# 规则链节点组件(nodes)
{
component: {
nodes: {
'jsFilter': {
label: 'js过滤',
icon: '/images/jsFilter.svg',
desc: '<a href="https://rulego.cc/pages/js-filter/" target="_blank">帮助文档</a>',
jsScript: {
label: 'function Filter(msg, metadata, msgType, dataType) {',
desc: '}'
}
},
'mqttClient': {
label: 'MQTT发布者',
icon: '/images/mqtt.svg',
desc: '<a href="https://rulego.cc/pages/mqtt-client/" target="_blank">帮助文档</a>',
server: {
ref: 'primary', // 使用连接池
label: 'MQTT 服务器地址',
rules: [{ required: true, message: '该项是必须的' }],
desc: '示例: 127.0.0.1:1883',
component: {
type: 'select',
filterable: true,
allowCreate: true,
multiple: false,
}
},
topic: { label: '发布主题', desc: '...' },
}
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# relationTypes - 连接关系类型
定义节点之间连接线的显示文本。
{
relationTypes: {
'Success': '成功',
'Failure': '失败',
'True': '真',
'False': '假',
'Other': '其他',
'window_event': '窗口事件',
}
}
2
3
4
5
6
7
8
9
10
组件也可以自定义关系类型:
'ai/agent': {
label: "智能体",
relationTypes: [
{label: "成功", value: "Success"},
{label: "失败", value: "Failure"},
{label: "流式", value: "Stream"}
],
}
2
3
4
5
6
7
8
# 其他文本
{
'Input': '输入',
'Input node already exists': '输入节点只能存在一个',
}
2
3
4
# 字段配置详解
# 字段通用属性
| 属性 | 类型 | 说明 |
|---|---|---|
label | string | 字段显示标签 |
desc | string | 字段描述/提示信息 |
rules | array | 表单验证规则 |
component | object | 表单组件配置 |
ref | string | 引用类型:primary(连接池复用)、shared(共享配置) |
defaultValue | any | 默认值 |
# 表单组件类型(component.type)
| 类型 | 说明 |
|---|---|
select | 下拉选择框,支持 filterable、allowCreate、multiple |
textarea | 多行文本输入 |
codeEditor | 代码编辑器 |
table | 表格编辑器(动态行),通过 options 定义列 |
slider | 滑块,支持 min、max、step、showInput、showTooltip |
input-number | 数字输入框,支持 min、max、step |
switch | 开关 |
expr | 表达式编辑器 |
sql | SQL 编辑器 |
datePicker | 日期选择器 |
tools | 工具配置编辑器 |
ruleChainSelector | 规则链选择器 |
switchNode | 条件分支配置 |
json-editor | JSON 编辑器 |
# 动态数据加载
字段可以通过 loadData 函数动态加载选项:
fetchNodeOutput: {
label: '取回节点输出',
nodeId: {
label: '目标节点',
desc: '选择要获取输出的目标节点',
component: {
type: 'select',
filterable: true,
allowCreate: true,
multiple: false,
loadData: function(lf, currentNodeModel, field, query) {
// lf: LogicFlow 实例
// currentNodeModel: 当前节点模型
// field: 字段配置
// query: 搜索关键字
let options = []
let ruleChainDSL = lf.getGraphData()
ruleChainDSL?.metadata?.nodes.forEach(item => {
if (item.id && item.id !== currentNodeModel.id) {
options.push({value: item.id, label: item.name})
}
})
field.component.options = options
return options
}
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# 嵌套字段(分组)
字段支持嵌套结构,用于分组显示相关配置:
sendEmail: {
label: '发邮件',
email: {
label: '邮件内容',
from: { label: '发件人邮箱' },
to: { label: '收件人邮箱' },
subject: { label: '邮件主题' },
body: { label: '邮件内容' },
}
}
2
3
4
5
6
7
8
9
10
# 表格字段(type: table)
用于编辑列表数据,通过 options 定义列:
cacheSet: {
items: {
label: '缓存项',
component: {
type: 'table',
options: [
{
name: 'level',
label: '缓存级别',
type: 'string',
rules: [{ required: true, message: '该项是必须的' }],
component: {
type: 'select',
options: [
{ label: '规则链', value: 'chain' },
{ label: '全局', value: 'global' }
]
},
},
{ name: 'key', label: '键', type: 'string', rules: [...] },
{ name: 'value', label: '值', type: 'string', rules: [...] },
{ name: 'ttl', label: '过期时间', type: 'string' },
]
},
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 特殊属性
| 属性 | 说明 |
|---|---|
notInput | 标记节点不需要输入连接(用于输入端节点) |
notOutput | 标记节点不需要输出连接 |
hide | 隐藏字段(如 router: { hide: true }) |
nodeType | 自定义节点画布类型(如 group-node、comment-node、end-node) |
relationTypeAllowCreate | 允许用户自定义关系类型 |
relationTypeDynamics | 启用动态关系类型 |
# 语言包文件组织
项目的语言包文件位于 src/components/i18n/ 目录下:
src/components/i18n/
├── zh/
│ ├── index.js # 中文语言包主入口(分类 + 内置组件)
│ ├── ai.js # AI 组件语言包
│ ├── endpoint.js # 输入端组件语言包
│ ├── extend.js # 扩展组件语言包
│ └── locales_registry.js # 语言包注册(导出扩展语言包数组)
└── core/
└── I18n.js # I18n 核心类(位于 src/components/core/)
2
3
4
5
6
7
8
9
# 文件说明
zh/index.js — 主入口,包含:
category:所有节点分类定义component.endpoints:空对象,由endpoint.js填充component.nodes:内置组件翻译(comment、end、delay、log、for、while 等)relationTypes:连接关系类型翻译- 通用文本翻译
zh/locales_registry.js — 统一注册扩展语言包:
import aiLocales from './ai'
import endpointLocales from './endpoint'
import extendLocales from './extend'
export const extensionLocales = [
aiLocales,
endpointLocales,
extendLocales
];
2
3
4
5
6
7
8
9
# AI 组件语言包 (ai.js)
包含 AI 相关组件:
ai/llm:AI 文本生成ai/agent:智能体(ReAct 框架)ai/createImage:图像生成ai/intent:意图识别ai/localIntent:本地意图识别ai/mcpClient:MCP 客户端ai/transform/documentLoader:文档加载器ai/transform/textChunker:文本分块器ai/embedding/openai:OpenAI 嵌入ai/indexer/milvus:Milvus 索引ai/indexer/redis:Redis 索引ai/retriever/milvus:Milvus 检索ai/retriever/redis:Redis 检索
# 输入端语言包 (endpoint.js)
包含输入端组件:
endpoint/http:HTTP 服务器endpoint/ws:WebSocket 服务器endpoint/ws_client:WebSocket 客户端endpoint/mqtt:MQTT 订阅endpoint/kafka:Kafka 订阅endpoint/redis:Redis 订阅endpoint/redis/stream:Redis 流endpoint/schedule:定时调度endpoint/net:TCP/UDP 服务器endpoint/net_client:TCP/UDP 客户端endpoint/rabbitmq:RabbitMQendpoint/nats:NATSendpoint/nsq:NSQendpoint/pulsar:Pulsarendpoint/mysql_cdc:MySQL CDCendpoint/opcua:OPC UA 订阅endpoint/grpc/stream:gRPC 流客户端endpoint/mcpServer:MCP 服务器endpoint/beanstalkdTubeset:Beanstalkdendpoint/wukongim:WuKongIM
# 扩展组件语言包 (extend.js)
包含扩展组件:
x/redisClient:Redis 客户端x/redisPub:Redis 发布者x/kafkaProducer:Kafka 发布者x/pulsarClient:Pulsar 发布者x/nsqClient:NSQ 发布者x/natsClient:NATS 客户端x/rabbitmqClient:RabbitMQ 客户端x/mongodbClient:MongoDB 客户端x/grpcClient:gRPC 客户端x/opengeminiWrite/x/opengeminiQuery:OpenGemini 读写x/opcuaRead/x/opcuaWrite:OPC UA 读写x/modbus:Modbus 读写x/serialIn/x/serialOut/x/serialRequest/x/serialControl:串口操作x/otel:OpenTelemetryx/wukongimSender:WuKongIM 发送x/beanstalkdWorker/x/beanstalkdTube:Beanstalkdx/luaFilter/x/luaTransform:Lua 脚本x/streamTransform/x/streamAggregator:流计算x/fileRead/x/fileWrite/x/fileDelete/x/fileList:文件操作x/receiveEmail:收邮件
# I18n 类 API
# 类定义
import { deepAssign } from '../utils/common';
export class I18n {
constructor(initialLocales = {}) {
this.locales = initialLocales;
this.t = this.t.bind(this);
}
// 注册或合并新的语言包(深度合并)
register(data) {
if (data) {
deepAssign(this.locales, data);
}
}
// 翻译函数
t(key, parentKey) {
if (key && parentKey) {
let locale = this.locales[parentKey];
if (locale) {
return locale[key] || key;
}
} else if (key) {
return this.locales[key] || key;
}
return key;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# 方法
# register(data)
注册或合并语言包数据。使用深度合并(deepAssign),可以只覆盖需要修改的部分。
const i18n = new I18n();
i18n.register({
category: {
common: {label: '公共'}
}
});
2
3
4
5
6
# t(key, parentKey)
获取翻译文本。
// 获取分类标签
const label = i18n.t('common', 'category'); // 返回 '公共'
// 获取组件标签
const componentLabel = i18n.t('jsFilter', 'component.nodes'); // 返回 'js过滤'
// 直接翻译文本
const text = i18n.t('Input'); // 返回 '输入'
// 如果找不到翻译,返回 key 本身
const unknown = i18n.t('unknown'); // 返回 'unknown'
2
3
4
5
6
7
8
9
10
11
# 自定义语言包示例
# 部分覆盖现有翻译
语言包注册使用深度合并,可以只覆盖需要修改的部分:
const customLocales = {
category: {
common: {label: '通用组件'} // 只覆盖"公共"为"通用组件"
},
component: {
nodes: {
'jsFilter': {
label: '自定义JS过滤器' // 只覆盖标签
}
}
}
};
// 使用
ruleGoEditorRef.value.setLocales(customLocales);
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 添加新组件翻译
const customLocales = {
component: {
nodes: {
'myCustomComponent': {
label: '我的组件',
icon: '/images/custom.svg',
desc: '自定义组件描述',
fieldName: {
label: '字段名称',
desc: '字段描述',
rules: [{ required: true, message: '该项是必须的' }]
}
}
}
}
};
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 禁用组件
const customLocales = {
component: {
endpoints: {
'endpoint/kafka': {
disabled: true // 禁用 Kafka 输入端
}
}
}
};
2
3
4
5
6
7
8
9
# 动态语言切换
结合 Vue 的响应式系统,实现运行时语言切换:
<template>
<div>
<select v-model="currentLang" @change="switchLanguage">
<option value="zh">中文</option>
<option value="en">English</option>
</select>
<RuleGoEditor ref="ruleGoEditorRef" :options="options"/>
</div>
</template>
<script setup>
import RuleGoEditor from './components/RuleGoEditor.vue'
import {ref, computed} from "vue";
import zhLocales from './i18n/zh';
import enLocales from './i18n/en';
const ruleGoEditorRef = ref();
const currentLang = ref('zh');
const localesMap = {
zh: zhLocales,
en: enLocales
};
const options = computed(() => ({
locales: localesMap[currentLang.value]
}));
const switchLanguage = () => {
// 语言切换会自动通过 computed 触发更新
};
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# 最佳实践
# 1. 保持语言包结构一致
自定义语言包应保持与内置语言包相同的结构(category、component、relationTypes),确保正确合并。
# 2. 利用深度合并
语言包注册使用深度合并,可以只覆盖需要修改的部分,无需提供完整的语言包。
# 3. 字段描述使用 desc
字段的 desc 应清晰描述字段用途和格式,帮助用户理解:
{
dsn: {
label: '数据库连接',
desc: 'Mysql: username:password@tcp(127.0.0.1:3306)/db Postgres: postgres://username:password@127.0.0.1:5432/db',
}
}
2
3
4
5
6
# 4. 描述支持 HTML
desc 字段支持 HTML,常用于添加帮助文档链接:
{
desc: '<a href="https://rulego.cc/pages/js-filter/" target="_blank">帮助文档</a>',
}
2
3
# 5. 合理使用 ref 连接池
对于需要复用连接的组件(如 MQTT、Redis、Kafka),使用 ref: 'primary' 标记连接字段:
{
server: {
ref: 'primary', // 允许选择已有连接池
label: '服务器地址',
component: {
type: 'select',
filterable: true,
allowCreate: true,
multiple: false,
}
}
}
2
3
4
5
6
7
8
9
10
11
12
# 相关配置
更多配置选项请参考: