Fix(i18n): Added new translations #3221 (#9727)

### What problem does this PR solve?

Fix(i18n): Added new translations #3221

- Added and updated internationalization translations in multiple
components


### Type of change

- [x] Bug Fix (non-breaking change which fixes an issue)

---------

Co-authored-by: Kevin Hu <kevinhu.sh@gmail.com>
This commit is contained in:
chanx
2025-08-26 17:57:53 +08:00
committed by GitHub
parent 11cf6ae313
commit 2b4bca4447
37 changed files with 347 additions and 111 deletions

View File

@ -12,6 +12,7 @@ import {
FormMessage,
} from '@/components/ui/form';
import { LlmModelType } from '@/constants/knowledge';
import { t } from 'i18next';
import { Funnel } from 'lucide-react';
import { useFormContext, useWatch } from 'react-hook-form';
import { useTranslation } from 'react-i18next';
@ -21,15 +22,15 @@ import { Button } from './ui/button';
const ModelTypes = [
{
title: 'All Models',
title: t('flow.allModels'),
value: 'all',
},
{
title: 'Text-only Models',
title: t('flow.textOnlyModels'),
value: LlmModelType.Chat,
},
{
title: 'Multimodal Models',
title: t('flow.multimodalModels'),
value: LlmModelType.Image2text,
},
];

View File

@ -145,9 +145,9 @@ export const SelectWithSearch = forwardRef<
align="start"
>
<Command>
<CommandInput placeholder="Search ..." />
<CommandInput placeholder={t('common.search') + '...'} />
<CommandList>
<CommandEmpty>No data found.</CommandEmpty>
<CommandEmpty>{t('common.noDataFound')}</CommandEmpty>
{options.map((group, idx) => {
if (group.options) {
return (

View File

@ -1,3 +1,4 @@
import { t } from 'i18next';
import { Loader2 } from 'lucide-react';
import { PropsWithChildren } from 'react';
import { TableCell, TableRow } from './ui/table';
@ -28,5 +29,5 @@ export function TableSkeleton({
}
export function TableEmpty({ columnsLength }: { columnsLength: number }) {
return <Row columnsLength={columnsLength}>No results.</Row>;
return <Row columnsLength={columnsLength}>{t('common.noResults')}</Row>;
}

View File

@ -1,6 +1,7 @@
export default {
translation: {
common: {
noResults: 'No results.',
selectPlaceholder: 'select value',
delete: 'Delete',
deleteModalTitle: 'Are you sure to delete this item?',
@ -40,6 +41,9 @@ export default {
previousPage: 'Previous',
nextPage: 'Next',
add: 'Add',
remove: 'Remove',
search: 'Search',
noDataFound: 'No data found.',
promptPlaceholder: `Please input or use / to quickly insert variables.`,
mcp: {
namePlaceholder: 'My MCP Server',
@ -860,11 +864,85 @@ This auto-tagging feature enhances retrieval by adding another layer of domain-s
pleaseUploadAtLeastOneFile: 'Please upload at least one file',
},
flow: {
beginInput: 'Begin Input',
ref: 'Variable',
stockCode: 'Stock Code',
apiKeyPlaceholder:
'YOUR_API_KEY (obtained from https://serpapi.com/manage-api-key)',
flowStart: 'Start',
flowNum: 'Num',
test: 'Test',
extractDepth: 'Extract Depth',
format: 'Format',
basic: 'basic',
advanced: 'advanced',
general: 'general',
searchDepth: 'Search Depth',
tavilyTopic: 'Tavily Topic',
maxResults: 'Max Results',
includeAnswer: 'Include Answer',
includeRawContent: 'Include Raw Content',
includeImages: 'Include Images',
includeImageDescriptions: 'Include Image Descriptions',
includeDomains: 'Include Domains',
ExcludeDomains: 'Exclude Domains',
Days: 'Days',
comma: 'Comma',
semicolon: 'Semicolon',
period: 'Period',
lineBreak: 'Line Break',
tab: 'Tab',
space: 'Space',
delimiters: 'Delimiters',
merge: 'Merge',
split: 'Split',
script: 'Script',
iterationItemDescription:
'It represents the current element in the iteration, which can be referenced and manipulated in subsequent steps.',
guidingQuestion: 'Guidance Question',
onFailure: 'On Failure',
userPromptDefaultValue:
'This is the order you need to send to the agent.',
search: 'Search',
communication: 'Communication',
developer: 'Developer',
typeCommandOrsearch: 'Type a command or search...',
builtIn: 'Built-in',
ExceptionDefaultValue: 'Exception default value',
exceptionMethod: 'Exception method',
maxRounds: 'Max rounds',
delayEfterError: 'Delay after error',
maxRetries: 'Max retries',
advancedSettings: 'Advanced Settings',
addTools: 'Add Tools',
sysPromptDefultValue: `<role>
You are {{agent_name}}, an AI assistant specialized in {{domain_or_task}}.
</role>
<instructions>
1. Understand the users request.
2. Decompose it into logical subtasks.
3. Execute each subtask step by step, reasoning transparently.
4. Validate accuracy and consistency.
5. Summarize the final result clearly.
</instructions>`,
singleLineText: 'Single-line text',
multimodalModels: 'Multimodal Models',
textOnlyModels: 'Text-only Models',
allModels: 'All Models',
codeExecDescription: 'Write your custom Python or Javascript logic.',
stringTransformDescription:
'Modifies text content. Currently supports: Splitting or concatenating text.',
foundation: 'Foundation',
tools: 'Tools',
dataManipulation: 'Data Manipulation',
flow: 'Flow',
dialog: 'Dialogue',
cite: 'Cite',
citeTip: 'citeTip',
name: 'Name',
nameMessage: 'Please input name',
description: 'Description',
descriptionMessage: 'This is an agent for a specific task.',
examples: 'Examples',
to: 'To',
msg: 'Messages',
@ -1289,6 +1367,7 @@ This delimiter is used to split the input text into several text pieces echo of
variableSettings: 'Variable settings',
globalVariables: 'Global variables',
systemPrompt: 'System prompt',
userPrompt: 'User prompt',
addCategory: 'Add category',
categoryName: 'Category name',
nextStep: 'Next step',
@ -1352,10 +1431,15 @@ This delimiter is used to split the input text into several text pieces echo of
openingSwitchTip:
'Your users will see this welcome message at the beginning.',
modeTip: 'The mode defines how the workflow is initiated.',
mode: 'Mode',
conversational: 'conversational',
task: 'task',
beginInputTip:
'By defining input parameters, this content can be accessed by other components in subsequent processes.',
query: 'Query variables',
queryTip: 'Select the variable you want to use',
agent: 'Agent',
addAgent: 'Add Agent',
agentDescription:
'Builds agent components equipped with reasoning, tool usage, and multi-agent collaboration. ',
maxRecords: 'Max records',

View File

@ -69,7 +69,7 @@ export default {
setting: '用戶設置',
logout: '登出',
fileManager: '文件管理',
flow: 'Agent',
flow: '智能體',
search: '搜尋',
welcome: '歡迎來到',
},
@ -764,6 +764,23 @@ export default {
destinationFolder: '目標資料夾',
},
flow: {
line: '單行文本',
paragraph: '段落文字',
options: '選項',
file: '文件',
integer: '數字',
boolean: '布爾值',
multimodalModels: '多模態模型',
textOnlyModels: '進文本模型',
allModels: '所有模型',
codeExecDescription: '用 Python 或者 Javascript 編寫自定義邏輯',
stringTransformDescription:
'修改文本内容,目前支持文本分割、文本拼接操作',
foundation: '基礎',
tools: '工具',
dataManipulation: '數據操控',
flow: '流程',
dialog: '對話',
cite: '引用',
citeTip: 'citeTip',
name: '名稱',
@ -805,7 +822,7 @@ export default {
promptText: `請總結以下段落。注意數字,不要胡編亂造。段落如下:
{input}
以上就是你需要總結的內容。`,
createGraph: '建立 Agent',
createGraph: '創建智能體',
createFromTemplates: '從模板創建',
retrieval: '知識檢索',
generate: '生成回答',

View File

@ -1,6 +1,7 @@
export default {
translation: {
common: {
noResults: '无结果。',
selectPlaceholder: '请选择',
delete: '删除',
deleteModalTitle: '确定删除吗?',
@ -39,6 +40,9 @@ export default {
previousPage: '上一页',
nextPage: '下一页',
add: '添加',
remove: '移除',
search: '搜索',
noDataFound: '没有找到数据。',
promptPlaceholder: '请输入或使用 / 快速插入变量。',
},
login: {
@ -71,7 +75,7 @@ export default {
setting: '用户设置',
logout: '登出',
fileManager: '文件管理',
flow: 'Agent',
flow: '智能体',
search: '搜索',
welcome: '欢迎来到',
dataset: '数据集',
@ -814,6 +818,89 @@ General实体和关系提取提示来自 GitHub - microsoft/graphrag基于
pleaseUploadAtLeastOneFile: '请上传至少一个文件',
},
flow: {
beginInput: '开始输入',
seconds: '秒',
ref: '引用变量',
stockCode: '股票代码',
apiKeyPlaceholder: '您的API密钥(从https://serpapi.com获取)',
flowStart: '开始',
flowNum: '编号',
test: '测试',
extractDepth: '深度提取',
format: '格式',
basic: '基本',
advanced: '高级',
general: '通用',
searchDepth: '深度搜索',
tavilyTopic: 'Tavily话题',
maxResults: '最大结果数',
includeAnswer: '包含答案',
includeRawContent: '包含原始内容',
includeImages: '包含图片',
includeImageDescriptions: '包含图片描述',
includeDomains: '包含域名',
ExcludeDomains: '排除域名',
Days: 'Days',
comma: '逗号',
semicolon: '分号',
period: '句点',
linebreak: '换行符',
tab: '制表符',
space: '空格',
delimiters: '分隔符',
merge: '合并',
split: '拆分',
script: '脚本',
iterationItemDescription:
'它是迭代过程中的当前元素,可以被后续流程引用和操作。',
guidingQuestion: '引导问题',
onFailure: '异常时',
userPromptDefaultValue:
'This is the order you need to send to the agent.',
descriptionMessage: '这是一个用于特定任务的代理。',
search: '搜索',
communication: '通信',
developer: '开发者',
typeCommandOrsearch: '输入命令或或搜索...',
builtIn: '内置',
goto: '异常分支',
comment: '默认值',
ExceptionDefaultValue: '异常处理默认值',
exceptionMethod: '异常处理方法',
maxRounds: '最大轮数',
delayEfterError: '错误后延迟',
maxRetries: '最大重试次数',
advancedSettings: '高级设置',
addTools: '添加工具',
sysPromptDefultValue: `<role>
您是{{agent_name}},一位专注于{{领域_or_任务}}的AI助手。
</role>
<instructions>
1. 理解用户请求。
2. 将其分解为逻辑子任务。
3. 逐步执行每个子任务,并清晰地进行推理。
4. 验证准确性和一致性。
5. 清晰地总结最终结果。
</instructions>`,
line: '单行文本',
paragraph: '段落文字',
options: '选项',
file: '文件',
integer: '数字',
boolean: '布尔值',
name: '名称',
singleLineText: '单行文本',
variableSettings: '变量设置',
multimodalModels: '多模态模型',
textOnlyModels: '仅文本模型',
allModels: '所有模型',
codeExecDescription: '用 Python 或者 Javascript 编写自定义逻辑',
stringTransformDescription:
'修改文本内容,目前支持文本分割、文本拼接操作',
foundation: '基础',
tools: '工具',
dataManipulation: '数据操控',
dialog: '对话',
flow: '工作流',
noMoreData: '没有更多数据了',
historyversion: '历史版本',
@ -823,7 +910,6 @@ General实体和关系提取提示来自 GitHub - microsoft/graphrag基于
},
cite: '引用',
citeTip: '引用',
name: '名称',
nameMessage: '请输入名称',
description: '描述',
examples: '示例',
@ -839,7 +925,7 @@ General实体和关系提取提示来自 GitHub - microsoft/graphrag基于
'loop为当前组件循环次数上限当循环次数超过loop的值时说明组件不能完成当前任务请重新优化agent',
yes: '是',
no: '否',
key: 'key',
key: '',
componentId: '组件ID',
add: '新增',
operation: '操作',
@ -861,7 +947,7 @@ General实体和关系提取提示来自 GitHub - microsoft/graphrag基于
promptText: `请总结以下段落。注意数字,不要胡编乱造。段落如下:
{input}
以上就是你需要总结的内容。`,
createGraph: '创建 Agent',
createGraph: '创建智能体',
createFromTemplates: '从模板创建',
retrieval: '知识检索',
generate: '生成回答',
@ -911,7 +997,7 @@ General实体和关系提取提示来自 GitHub - microsoft/graphrag基于
bing: 'Bing',
bingDescription:
'此组件用于从 https://www.bing.com/ 获取搜索结果。通常它作为知识库的补充。Top N 和 Bing Subscription-Key 指定您需要调整的搜索结果数量。',
apiKey: 'API KEY',
apiKey: 'API密钥',
country: '国家和地区',
language: '语言',
googleScholar: '谷歌学术',
@ -1255,6 +1341,7 @@ General实体和关系提取提示来自 GitHub - microsoft/graphrag基于
team: '团队',
},
systemPrompt: '系统提示词',
userPrompt: '用户提示词',
prompt: '提示词',
promptMessage: '提示词是必填项',
promptTip:
@ -1270,21 +1357,26 @@ General实体和关系提取提示来自 GitHub - microsoft/graphrag基于
openingCopy: '开场白文案',
openingSwitchTip: '您的用户将在开始时看到此欢迎消息。',
modeTip: '模式定义了工作流的启动方式。',
mode: '模式',
conversational: '对话式',
task: '任务',
beginInputTip: '通过定义输入参数,此内容可以被后续流程中的其他组件访问。',
query: '查询变量',
queryTip: '选择您想要使用的变量',
agent: '智能体',
addAgent: '添加智能体',
agentDescription: '构建具备推理、工具调用和多智能体协同的智能体组件。',
maxRecords: '最大记录数',
createAgent: 'Create Agent',
createAgent: '创建智能体',
stringTransform: '文本处理',
userFillUp: '等待输入',
userFillUpDescription: `此组件会暂停当前的流程并等待用户发送消息,接收到消息之后再进行之后的流程。`,
codeExec: '代码',
tavilySearch: 'Tavily Search',
tavilySearch: 'Tavily 搜索',
tavilySearchDescription: '通过 Tavily 服务搜索结果',
tavilyExtract: 'Tavily Extract',
tavilyExtractDescription: 'Tavily Extract',
tavilyExtract: 'Tavily 提取',
tavilyExtractDescription: 'Tavily 提取',
log: '日志',
management: '管理',
import: '导入',

View File

@ -89,7 +89,7 @@ function InnerAgentNode({
{(isGotoMethod ||
exceptionMethod === AgentExceptionMethod.Comment) && (
<div className="bg-bg-card rounded-sm p-1 flex justify-between gap-2">
<span className="text-text-secondary">On Failure</span>
<span className="text-text-secondary">{t('flow.onFailure')}</span>
<span className="truncate flex-1 text-right">
{t(`flow.${exceptionMethod}`)}
</span>

View File

@ -21,6 +21,7 @@ import { Operator } from '@/pages/agent/constant';
import { AgentInstanceContext, HandleContext } from '@/pages/agent/context';
import OperatorIcon from '@/pages/agent/operator-icon';
import { Position } from '@xyflow/react';
import { t } from 'i18next';
import { lowerFirst } from 'lodash';
import {
PropsWithChildren,
@ -128,7 +129,9 @@ function AccordionOperators({
defaultValue={['item-1', 'item-2', 'item-3', 'item-4', 'item-5']}
>
<AccordionItem value="item-1">
<AccordionTrigger className="text-xl">Foundation</AccordionTrigger>
<AccordionTrigger className="text-xl">
{t('flow.foundation')}
</AccordionTrigger>
<AccordionContent className="flex flex-col gap-4 text-balance">
<OperatorItemList
operators={[Operator.Agent, Operator.Retrieval]}
@ -138,7 +141,9 @@ function AccordionOperators({
</AccordionContent>
</AccordionItem>
<AccordionItem value="item-2">
<AccordionTrigger className="text-xl">Dialogue </AccordionTrigger>
<AccordionTrigger className="text-xl">
{t('flow.dialog')}
</AccordionTrigger>
<AccordionContent className="flex flex-col gap-4 text-balance">
<OperatorItemList
operators={[Operator.Message, Operator.UserFillUp]}
@ -148,7 +153,9 @@ function AccordionOperators({
</AccordionContent>
</AccordionItem>
<AccordionItem value="item-3">
<AccordionTrigger className="text-xl">Flow</AccordionTrigger>
<AccordionTrigger className="text-xl">
{t('flow.flow')}
</AccordionTrigger>
<AccordionContent className="flex flex-col gap-4 text-balance">
<OperatorItemList
operators={[
@ -163,7 +170,7 @@ function AccordionOperators({
</AccordionItem>
<AccordionItem value="item-4">
<AccordionTrigger className="text-xl">
Data Manipulation
{t('flow.dataManipulation')}
</AccordionTrigger>
<AccordionContent className="flex flex-col gap-4 text-balance">
<OperatorItemList
@ -174,7 +181,9 @@ function AccordionOperators({
</AccordionContent>
</AccordionItem>
<AccordionItem value="item-5">
<AccordionTrigger className="text-xl">Tools</AccordionTrigger>
<AccordionTrigger className="text-xl">
{t('flow.tools')}
</AccordionTrigger>
<AccordionContent className="flex flex-col gap-4 text-balance">
<OperatorItemList
operators={[
@ -244,7 +253,7 @@ export function InnerNextStepDropdown({
>
<div className="w-[300px] font-semibold bg-bg-base border border-border rounded-md shadow-lg">
<div className="px-3 py-2 border-b border-border">
<div className="text-sm font-medium">Next Step</div>
<div className="text-sm font-medium">{t('flow.nextStep')}</div>
</div>
<HideModalContext.Provider value={hideModal}>
<OnNodeCreatedContext.Provider value={onNodeCreated}>
@ -273,7 +282,7 @@ export function InnerNextStepDropdown({
onClick={(e) => e.stopPropagation()}
className="w-[300px] font-semibold"
>
<DropdownMenuLabel>Next Step</DropdownMenuLabel>
<DropdownMenuLabel>{t('flow.nextStep')}</DropdownMenuLabel>
<HideModalContext.Provider value={hideModal}>
<AccordionOperators></AccordionOperators>
</HideModalContext.Provider>

View File

@ -20,6 +20,7 @@ import {
import { ModelVariableType } from '@/constants/knowledge';
import i18n from '@/locales/config';
import { setInitialChatVariableEnabledFieldValue } from '@/utils/chat';
import { t } from 'i18next';
// DuckDuckGo's channel options
export enum Channel {
@ -630,16 +631,7 @@ export const initialAgentValues = {
...initialLlmBaseValues,
description: '',
user_prompt: '',
sys_prompt: `<role>
You are {{agent_name}}, an AI assistant specialized in {{domain_or_task}}.
</role>
<instructions>
1. Understand the users request.
2. Decompose it into logical subtasks.
3. Execute each subtask step by step, reasoning transparently.
4. Validate accuracy and consistency.
5. Summarize the final result clearly.
</instructions>`,
sys_prompt: t('flow.sysPromptDefultValue'),
prompts: [{ role: PromptRole.User, content: `{${AgentGlobals.SysQuery}}` }],
message_history_window_size: 12,
max_retries: 3,

View File

@ -6,6 +6,7 @@ import {
} from '@/components/ui/tooltip';
import { cn } from '@/lib/utils';
import { Position } from '@xyflow/react';
import { t } from 'i18next';
import { PencilLine, X } from 'lucide-react';
import {
MouseEventHandler,
@ -106,7 +107,7 @@ export function AgentTools() {
return (
<section className="space-y-2.5">
<span className="text-text-secondary">Tools</span>
<span className="text-text-secondary">{t('flow.tools')}</span>
<ul className="space-y-2">
{toolNames.map((x) => (
<ToolCard key={x}>
@ -133,7 +134,7 @@ export function AgentTools() {
))}
</ul>
<ToolPopover>
<BlockButton>Add Tool</BlockButton>
<BlockButton>{t('flow.addTools')}</BlockButton>
</ToolPopover>
</section>
);
@ -160,7 +161,7 @@ export function Agents({ node }: INextOperatorForm) {
return (
<section className="space-y-2.5">
<span className="text-text-secondary">Agents</span>
<span className="text-text-secondary">{t('flow.agent')}</span>
<ul className="space-y-2">
{subBottomAgentNodeIds.map((id) => {
const currentNode = getNode(id);
@ -183,7 +184,7 @@ export function Agents({ node }: INextOperatorForm) {
position: Position.Bottom,
})}
>
Add Agent
{t('flow.addAgent')}
</BlockButton>
</section>
);

View File

@ -144,7 +144,7 @@ function AgentForm({ node }: INextOperatorForm) {
name={`sys_prompt`}
render={({ field }) => (
<FormItem className="flex-1">
<FormLabel>System Prompt</FormLabel>
<FormLabel>{t('flow.systemPrompt')}</FormLabel>
<FormControl>
<PromptEditor
{...field}
@ -164,7 +164,7 @@ function AgentForm({ node }: INextOperatorForm) {
name={`prompts`}
render={({ field }) => (
<FormItem className="flex-1">
<FormLabel>User Prompt</FormLabel>
<FormLabel>{t('flow.userPrompt')}</FormLabel>
<FormControl>
<section>
<PromptEditor
@ -183,7 +183,7 @@ function AgentForm({ node }: INextOperatorForm) {
<AgentTools></AgentTools>
<Agents node={node}></Agents>
</FormContainer>
<Collapse title={<div>Advanced Settings</div>}>
<Collapse title={<div>{t('flow.advancedSettings')}</div>}>
<FormContainer>
<MessageHistoryWindowSizeFormField></MessageHistoryWindowSizeFormField>
<FormField
@ -208,7 +208,7 @@ function AgentForm({ node }: INextOperatorForm) {
name={`max_retries`}
render={({ field }) => (
<FormItem className="flex-1">
<FormLabel>Max retries</FormLabel>
<FormLabel>{t('flow.maxRetries')}</FormLabel>
<FormControl>
<NumberInput {...field} max={8}></NumberInput>
</FormControl>
@ -220,7 +220,7 @@ function AgentForm({ node }: INextOperatorForm) {
name={`delay_after_error`}
render={({ field }) => (
<FormItem className="flex-1">
<FormLabel>Delay after error</FormLabel>
<FormLabel>{t('flow.delayEfterError')}</FormLabel>
<FormControl>
<NumberInput {...field} max={5} step={0.1}></NumberInput>
</FormControl>
@ -232,7 +232,7 @@ function AgentForm({ node }: INextOperatorForm) {
name={`max_rounds`}
render={({ field }) => (
<FormItem className="flex-1">
<FormLabel>Max rounds</FormLabel>
<FormLabel>{t('flow.maxRounds')}</FormLabel>
<FormControl>
<NumberInput {...field}></NumberInput>
</FormControl>
@ -244,7 +244,7 @@ function AgentForm({ node }: INextOperatorForm) {
name={`exception_method`}
render={({ field }) => (
<FormItem className="flex-1">
<FormLabel>Exception method</FormLabel>
<FormLabel>{t('flow.exceptionMethod')}</FormLabel>
<FormControl>
<SelectWithSearch
{...field}
@ -261,7 +261,7 @@ function AgentForm({ node }: INextOperatorForm) {
name={`exception_default_value`}
render={({ field }) => (
<FormItem className="flex-1">
<FormLabel>Exception default value</FormLabel>
<FormLabel>{t('flow.ExceptionDefaultValue')}</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>

View File

@ -8,6 +8,7 @@ import { Operator } from '@/pages/agent/constant';
import { AgentFormContext, AgentInstanceContext } from '@/pages/agent/context';
import useGraphStore from '@/pages/agent/store';
import { Position } from '@xyflow/react';
import { t } from 'i18next';
import { PropsWithChildren, useCallback, useContext, useEffect } from 'react';
import { useGetAgentMCPIds, useGetAgentToolNames } from '../use-get-tools';
import { MCPCommand, ToolCommand } from './tool-command';
@ -65,8 +66,12 @@ export function ToolPopover({ children }: PropsWithChildren) {
<PopoverContent className="w-80 p-4">
<Tabs defaultValue={ToolType.Common}>
<TabsList>
<TabsTrigger value={ToolType.Common}>Built-in</TabsTrigger>
<TabsTrigger value={ToolType.MCP}>MCP</TabsTrigger>
<TabsTrigger value={ToolType.Common} className="bg-bg-card">
{t('flow.builtIn')}
</TabsTrigger>
<TabsTrigger value={ToolType.MCP} className="bg-bg-card">
MCP
</TabsTrigger>
</TabsList>
<TabsContent value={ToolType.Common}>
<ToolCommand

View File

@ -12,13 +12,14 @@ import { useListMcpServer } from '@/hooks/use-mcp-request';
import { cn } from '@/lib/utils';
import { Operator } from '@/pages/agent/constant';
import OperatorIcon from '@/pages/agent/operator-icon';
import { t } from 'i18next';
import { lowerFirst } from 'lodash';
import { PropsWithChildren, useCallback, useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
const Menus = [
{
label: 'Search',
label: t('flow.search'),
list: [
Operator.TavilySearch,
Operator.TavilyExtract,
@ -34,7 +35,7 @@ const Menus = [
],
},
{
label: 'Communication',
label: t('flow.communication'),
list: [Operator.Email],
},
// {
@ -42,7 +43,7 @@ const Menus = [
// list: [],
// },
{
label: 'Developer',
label: t('flow.developer'),
list: [Operator.GitHub, Operator.ExeSQL, Operator.Code, Operator.Retrieval],
},
];
@ -116,7 +117,7 @@ export function ToolCommand({ value, onChange }: ToolCommandProps) {
return (
<Command>
<CommandInput placeholder="Type a command or search..." />
<CommandInput placeholder={t('flow.typeCommandOrsearch')} />
<CommandList>
<CommandEmpty>No results found.</CommandEmpty>
{Menus.map((x) => (

View File

@ -12,8 +12,8 @@ import { RAGFlowSelect } from '@/components/ui/select';
import { Switch } from '@/components/ui/switch';
import { Textarea } from '@/components/ui/textarea';
import { FormTooltip } from '@/components/ui/tooltip';
import { buildSelectOptions } from '@/utils/component-util';
import { zodResolver } from '@hookform/resolvers/zod';
import { t } from 'i18next';
import { Plus } from 'lucide-react';
import { memo, useEffect, useRef } from 'react';
import { useForm, useWatch } from 'react-hook-form';
@ -27,10 +27,10 @@ import { useEditQueryRecord } from './use-edit-query';
import { useValues } from './use-values';
import { useWatchFormChange } from './use-watch-change';
const ModeOptions = buildSelectOptions([
AgentDialogueMode.Conversational,
AgentDialogueMode.Task,
]);
const ModeOptions = [
{ value: AgentDialogueMode.Conversational, label: t('flow.conversational') },
{ value: AgentDialogueMode.Task, label: t('flow.task') },
];
function BeginForm({ node }: INextOperatorForm) {
const { t } = useTranslation();
@ -103,7 +103,9 @@ function BeginForm({ node }: INextOperatorForm) {
name={'mode'}
render={({ field }) => (
<FormItem>
<FormLabel tooltip={t('flow.modeTip')}>Mode</FormLabel>
<FormLabel tooltip={t('flow.modeTip')}>
{t('flow.mode')}
</FormLabel>
<FormControl>
<RAGFlowSelect
placeholder={t('common.pleaseSelect')}

View File

@ -138,7 +138,7 @@ function ParameterForm({
control={form.control}
render={({ field }) => (
<FormItem>
<FormLabel>Type</FormLabel>
<FormLabel>{t('type')}</FormLabel>
<FormControl>
<RAGFlowSelect {...field} options={options} />
</FormControl>
@ -151,7 +151,7 @@ function ParameterForm({
control={form.control}
render={({ field }) => (
<FormItem>
<FormLabel>Key</FormLabel>
<FormLabel>{t('key')}</FormLabel>
<FormControl>
<Input {...field} autoComplete="off" onBlur={handleKeyChange} />
</FormControl>
@ -164,7 +164,7 @@ function ParameterForm({
control={form.control}
render={({ field }) => (
<FormItem>
<FormLabel>Name</FormLabel>
<FormLabel>{t('name')}</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
@ -177,7 +177,7 @@ function ParameterForm({
control={form.control}
render={({ field }) => (
<FormItem>
<FormLabel>Optional</FormLabel>
<FormLabel>{t('optional')}</FormLabel>
<FormControl>
<Switch
checked={field.value}
@ -217,7 +217,7 @@ export function ParameterDialog({
></ParameterForm>
<DialogFooter>
<Button type="submit" form={FormId}>
Confirm
{t('modal.okText')}
</Button>
</DialogFooter>
</DialogContent>

View File

@ -53,7 +53,7 @@ export function QueryTable({ data = [], deleteRecord, showModal }: IProps) {
const columns: ColumnDef<BeginQuery>[] = [
{
accessorKey: 'key',
header: 'Key',
header: t('flow.key'),
meta: { cellClassName: 'max-w-30' },
cell: ({ row }) => {
const key: string = row.getValue('key');

View File

@ -6,6 +6,7 @@ import {
FormMessage,
} from '@/components/ui/form';
import { Input } from '@/components/ui/input';
import { t } from 'i18next';
import { useFormContext } from 'react-hook-form';
interface IApiKeyFieldProps {
@ -19,7 +20,7 @@ export function ApiKeyField({ placeholder }: IApiKeyFieldProps) {
name="api_key"
render={({ field }) => (
<FormItem>
<FormLabel>Api Key</FormLabel>
<FormLabel>{t('flow.apiKey')}</FormLabel>
<FormControl>
<Input type="password" {...field} placeholder={placeholder}></Input>
</FormControl>

View File

@ -5,6 +5,7 @@ import {
FormLabel,
} from '@/components/ui/form';
import { Textarea } from '@/components/ui/textarea';
import { t } from 'i18next';
import { useFormContext } from 'react-hook-form';
export function DescriptionField() {
@ -15,7 +16,7 @@ export function DescriptionField() {
name={`description`}
render={({ field }) => (
<FormItem className="flex-1">
<FormLabel>Description</FormLabel>
<FormLabel>{t('flow.description')}</FormLabel>
<FormControl>
<Textarea {...field}></Textarea>
</FormControl>

View File

@ -1,3 +1,5 @@
import { t } from 'i18next';
export type OutputType = {
title: string;
type?: string;
@ -17,7 +19,7 @@ export function transferOutputs(outputs: Record<string, any>) {
export function Output({ list }: OutputProps) {
return (
<section className="space-y-2">
<div>Output</div>
<div>{t('flow.output')}</div>
<ul>
{list.map((x, idx) => (
<li

View File

@ -47,7 +47,7 @@ export function QueryVariable({
render={({ field }) => (
<FormItem>
{label || (
<FormLabel tooltip={t('chat.modelTip')}>
<FormLabel tooltip={t('flow.queryTip')}>
{t('flow.query')}
</FormLabel>
)}

View File

@ -132,7 +132,7 @@ export function ExeSQLFormWidgets({ loading }: { loading: boolean }) {
<div className="flex justify-end">
<ButtonLoading loading={loading} type="submit">
Test
{t('test')}
</ButtonLoading>
</div>
</>

View File

@ -99,13 +99,13 @@ const GoogleForm = ({ node }: INextOperatorForm) => {
<QueryVariable name="q"></QueryVariable>
</FormContainer>
<FormContainer>
<ApiKeyField placeholder="YOUR_API_KEY (obtained from https://serpapi.com/manage-api-key)"></ApiKeyField>
<ApiKeyField placeholder={t('apiKeyPlaceholder')}></ApiKeyField>
<FormField
control={form.control}
name={`start`}
render={({ field }) => (
<FormItem>
<FormLabel>{t('start')}</FormLabel>
<FormLabel>{t('flowStart')}</FormLabel>
<FormControl>
<NumberInput {...field} className="w-full"></NumberInput>
</FormControl>
@ -118,7 +118,7 @@ const GoogleForm = ({ node }: INextOperatorForm) => {
name={`num`}
render={({ field }) => (
<FormItem>
<FormLabel>{t('num')}</FormLabel>
<FormLabel>{t('flowNum')}</FormLabel>
<FormControl>
<NumberInput {...field} className="w-full"></NumberInput>
</FormControl>

View File

@ -134,7 +134,7 @@ export function VariableDialog({
></VariableForm>
<DialogFooter>
<Button type="submit" form={FormId}>
Confirm
{t('modal.okText')}
</Button>
</DialogFooter>
</DialogContent>

View File

@ -61,7 +61,7 @@ export function VariableTable({
const columns: ColumnDef<VariableFormSchemaType>[] = [
{
accessorKey: 'key',
header: 'key',
header: t('flow.key'),
meta: { cellClassName: 'max-w-30' },
cell: ({ row }) => {
const key: string = row.getValue('key');

View File

@ -12,6 +12,7 @@ import {
import { Input } from '@/components/ui/input';
import { Separator } from '@/components/ui/separator';
import { RAGFlowNodeType } from '@/interfaces/database/flow';
import { t } from 'i18next';
import { X } from 'lucide-react';
import { ReactNode, useCallback, useMemo } from 'react';
import { useFieldArray, useFormContext } from 'react-hook-form';
@ -107,7 +108,7 @@ export function DynamicOutputForm({ node }: IProps) {
);
})}
<BlockButton onClick={() => append({ name: '', ref: undefined })}>
Add
{t('common.add')}
</BlockButton>
</div>
);
@ -120,7 +121,7 @@ export function VariableTitle({ title }: { title: ReactNode }) {
export function DynamicOutput({ node }: IProps) {
return (
<FormContainer>
<VariableTitle title={'Output'}></VariableTitle>
<VariableTitle title={t('flow.output')}></VariableTitle>
<DynamicOutputForm node={node}></DynamicOutputForm>
</FormContainer>
);

View File

@ -104,7 +104,7 @@ function RetrievalForm({ node }: INextOperatorForm) {
</RAGFlowFormItem>
<KnowledgeBaseFormField showVariable></KnowledgeBaseFormField>
</FormContainer>
<Collapse title={<div>Advanced Settings</div>}>
<Collapse title={<div>{t('flow.advancedSettings')}</div>}>
<FormContainer>
<SimilaritySliderFormField
vectorSimilarityWeightName="keywords_similarity_weight"

View File

@ -9,8 +9,9 @@ import {
} from '@/components/ui/form';
import { MultiSelect } from '@/components/ui/multi-select';
import { RAGFlowSelect } from '@/components/ui/select';
import { buildOptions } from '@/utils/form';
import { zodResolver } from '@hookform/resolvers/zod';
import { t } from 'i18next';
import { toLower } from 'lodash';
import { memo, useCallback, useMemo } from 'react';
import { useForm, useWatch } from 'react-hook-form';
import { z } from 'zod';
@ -28,7 +29,7 @@ import { useValues } from './use-values';
import { useWatchFormChange } from './use-watch-form-change';
const DelimiterOptions = Object.entries(StringTransformDelimiter).map(
([key, val]) => ({ label: key, value: val }),
([key, val]) => ({ label: t('flow.' + toLower(key)), value: val }),
);
function StringTransformForm({ node }: INextOperatorForm) {
@ -84,11 +85,13 @@ function StringTransformForm({ node }: INextOperatorForm) {
name="method"
render={({ field }) => (
<FormItem>
<FormLabel>method</FormLabel>
<FormLabel>{t('flow.method')}</FormLabel>
<FormControl>
<RAGFlowSelect
{...field}
options={buildOptions(StringTransformMethod)}
options={Object.values(StringTransformMethod).map(
(val) => ({ label: t('flow.' + val), value: val }),
)}
onChange={(value) => {
handleMethodChange(value);
field.onChange(value);
@ -111,7 +114,7 @@ function StringTransformForm({ node }: INextOperatorForm) {
name="script"
render={({ field }) => (
<FormItem>
<FormLabel>script</FormLabel>
<FormLabel>{t('flow.script')}</FormLabel>
<FormControl>
<PromptEditor {...field} showToolbar={false}></PromptEditor>
</FormControl>
@ -125,7 +128,7 @@ function StringTransformForm({ node }: INextOperatorForm) {
name="delimiters"
render={({ field }) => (
<FormItem>
<FormLabel>delimiters</FormLabel>
<FormLabel>{t('flow.delimiters')}</FormLabel>
<FormControl>
{isSplit ? (
<MultiSelect

View File

@ -15,6 +15,7 @@ import { Separator } from '@/components/ui/separator';
import { Textarea } from '@/components/ui/textarea';
import { cn } from '@/lib/utils';
import { zodResolver } from '@hookform/resolvers/zod';
import { t } from 'i18next';
import { toLower } from 'lodash';
import { X } from 'lucide-react';
import { memo, useCallback, useMemo } from 'react';
@ -197,7 +198,7 @@ function ConditionCards({
className="mt-6"
onClick={() => append({ operator: switchOperatorOptions[0].value })}
>
Add
{t('common.add')}
</BlockButton>
</div>
</section>
@ -268,7 +269,7 @@ function SwitchForm({ node }: IOperatorForm) {
className="-translate-y-1"
onClick={() => remove(index)}
>
Remove <X />
{t('common.remove')} <X />
</Button>
)}
</div>
@ -317,7 +318,7 @@ function SwitchForm({ node }: IOperatorForm) {
})
}
>
Add
{t('common.add')}
</BlockButton>
</FormWrapper>
</Form>

View File

@ -10,6 +10,7 @@ import {
import { RAGFlowSelect } from '@/components/ui/select';
import { buildOptions } from '@/utils/form';
import { zodResolver } from '@hookform/resolvers/zod';
import { t } from 'i18next';
import { memo } from 'react';
import { useForm } from 'react-hook-form';
import { z } from 'zod';
@ -79,12 +80,12 @@ function TavilyExtractForm({ node }: INextOperatorForm) {
name="extract_depth"
render={({ field }) => (
<FormItem>
<FormLabel>Extract Depth</FormLabel>
<FormLabel>{t('flow.extractDepth')}</FormLabel>
<FormControl>
<RAGFlowSelect
placeholder="shadcn"
{...field}
options={buildOptions(TavilyExtractDepth)}
options={buildOptions(TavilyExtractDepth, t, 'flow')}
/>
</FormControl>
<FormMessage />
@ -96,7 +97,7 @@ function TavilyExtractForm({ node }: INextOperatorForm) {
name="format"
render={({ field }) => (
<FormItem>
<FormLabel>Format</FormLabel>
<FormLabel>{t('flow.format')}</FormLabel>
<FormControl>
<RAGFlowSelect
placeholder="shadcn"

View File

@ -7,6 +7,7 @@ import {
FormMessage,
} from '@/components/ui/form';
import { Input } from '@/components/ui/input';
import { t } from 'i18next';
import { X } from 'lucide-react';
import { ReactNode } from 'react';
import { useFieldArray, useFormContext } from 'react-hook-form';
@ -51,7 +52,9 @@ export const DynamicDomain = ({ name, label }: DynamicDomainProps) => {
))}
</div>
<FormMessage />
<BlockButton onClick={() => append({ value: '' })}>Add</BlockButton>
<BlockButton onClick={() => append({ value: '' })}>
{t('common.add')}
</BlockButton>
</FormItem>
);
};

View File

@ -12,6 +12,7 @@ import { RAGFlowSelect } from '@/components/ui/select';
import { Switch } from '@/components/ui/switch';
import { buildOptions } from '@/utils/form';
import { zodResolver } from '@hookform/resolvers/zod';
import { t } from 'i18next';
import { memo } from 'react';
import { useForm } from 'react-hook-form';
import { z } from 'zod';
@ -74,12 +75,12 @@ function TavilyForm({ node }: INextOperatorForm) {
name="search_depth"
render={({ field }) => (
<FormItem>
<FormLabel>Search Depth</FormLabel>
<FormLabel>{t('flow.searchDepth')}</FormLabel>
<FormControl>
<RAGFlowSelect
placeholder="shadcn"
{...field}
options={buildOptions(TavilySearchDepth)}
options={buildOptions(TavilySearchDepth, t, 'flow')}
/>
</FormControl>
<FormMessage />
@ -91,12 +92,12 @@ function TavilyForm({ node }: INextOperatorForm) {
name="topic"
render={({ field }) => (
<FormItem>
<FormLabel>TavilyTopic</FormLabel>
<FormLabel>{t('flow.tavilyTopic')}</FormLabel>
<FormControl>
<RAGFlowSelect
placeholder="shadcn"
{...field}
options={buildOptions(TavilyTopic)}
options={buildOptions(TavilyTopic, t, 'flow')}
/>
</FormControl>
<FormMessage />
@ -108,7 +109,7 @@ function TavilyForm({ node }: INextOperatorForm) {
name="max_results"
render={({ field }) => (
<FormItem>
<FormLabel>Max Results</FormLabel>
<FormLabel>{t('flow.maxResults')}</FormLabel>
<FormControl>
<Input type={'number'} {...field}></Input>
</FormControl>
@ -121,7 +122,7 @@ function TavilyForm({ node }: INextOperatorForm) {
name="days"
render={({ field }) => (
<FormItem>
<FormLabel>Days</FormLabel>
<FormLabel>{t('flow.days')}</FormLabel>
<FormControl>
<Input type={'number'} {...field}></Input>
</FormControl>
@ -134,7 +135,7 @@ function TavilyForm({ node }: INextOperatorForm) {
name="include_answer"
render={({ field }) => (
<FormItem>
<FormLabel>Include Answer</FormLabel>
<FormLabel>{t('flow.includeAnswer')}</FormLabel>
<FormControl>
<Switch
checked={field.value}
@ -150,7 +151,7 @@ function TavilyForm({ node }: INextOperatorForm) {
name="include_raw_content"
render={({ field }) => (
<FormItem>
<FormLabel>Include Raw Content</FormLabel>
<FormLabel>{t('flow.includeRawContent')}</FormLabel>
<FormControl>
<Switch
checked={field.value}
@ -166,7 +167,7 @@ function TavilyForm({ node }: INextOperatorForm) {
name="include_images"
render={({ field }) => (
<FormItem>
<FormLabel>Include Images</FormLabel>
<FormLabel>{t('flow.includeImages')}</FormLabel>
<FormControl>
<Switch
checked={field.value}
@ -182,7 +183,7 @@ function TavilyForm({ node }: INextOperatorForm) {
name="include_image_descriptions"
render={({ field }) => (
<FormItem>
<FormLabel>Include Image Descriptions</FormLabel>
<FormLabel>{t('flow.includeImageDescriptions')}</FormLabel>
<FormControl>
<Switch
checked={field.value}
@ -195,11 +196,11 @@ function TavilyForm({ node }: INextOperatorForm) {
/>
<DynamicDomain
name="include_domains"
label={'Include Domains'}
label={t('flow.includeDomains')}
></DynamicDomain>
<DynamicDomain
name="exclude_domains"
label={'Exclude Domains'}
label={t('flow.ExcludeDomains')}
></DynamicDomain>
</FormContainer>
</FormWrapper>

View File

@ -8,6 +8,7 @@ import { TopNFormField } from '@/components/top-n-item';
import { Form } from '@/components/ui/form';
import { UseKnowledgeGraphFormField } from '@/components/use-knowledge-graph-item';
import { zodResolver } from '@hookform/resolvers/zod';
import { t } from 'i18next';
import { useForm } from 'react-hook-form';
import { z } from 'zod';
import { DescriptionField } from '../../components/description-field';
@ -41,7 +42,7 @@ const RetrievalForm = () => {
<DescriptionField></DescriptionField>
<KnowledgeBaseFormField showVariable></KnowledgeBaseFormField>
</FormContainer>
<Collapse title={<div>Advanced Settings</div>}>
<Collapse title={<div>{t('flow.advancedSettings')}</div>}>
<FormContainer>
<SimilaritySliderFormField
vectorSimilarityWeightName="keywords_similarity_weight"

View File

@ -86,7 +86,7 @@ function UserFillUpForm({ node }: INextOperatorForm) {
render={({ field }) => (
<FormItem>
<FormLabel tooltip={t('flow.openingSwitchTip')}>
Guiding Question
{t('flow.guidingQuestion')}
</FormLabel>
<FormControl>
<Switch
@ -104,7 +104,9 @@ function UserFillUpForm({ node }: INextOperatorForm) {
name={'tips'}
render={({ field }) => (
<FormItem>
<FormLabel tooltip={t('chat.setAnOpenerTip')}>Message</FormLabel>
<FormLabel tooltip={t('chat.setAnOpenerTip')}>
{t('flow.msg')}
</FormLabel>
<FormControl>
<Textarea
rows={5}

View File

@ -1,6 +1,7 @@
import { useFetchModelId } from '@/hooks/logic-hooks';
import { Connection, Node, Position, ReactFlowInstance } from '@xyflow/react';
import humanId from 'human-id';
import { t } from 'i18next';
import { lowerFirst } from 'lodash';
import { useCallback, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
@ -122,8 +123,8 @@ export const useInitializeOperatorParams = () => {
if (isBottomSubAgent(operatorName, position)) {
return {
...initialValues,
description: 'This is an agent for a specific task.',
user_prompt: 'This is the order you need to send to the agent.',
description: t('flow.descriptionMessage'),
user_prompt: t('flow.userPromptDefaultValue'),
};
}

View File

@ -3,6 +3,7 @@ import { useFetchAgent } from '@/hooks/use-agent-request';
import { RAGFlowNodeType } from '@/interfaces/database/flow';
import { Edge } from '@xyflow/react';
import { DefaultOptionType } from 'antd/es/select';
import { t } from 'i18next';
import { isEmpty } from 'lodash';
import get from 'lodash/get';
import { useCallback, useContext, useEffect, useMemo, useState } from 'react';
@ -145,7 +146,7 @@ export function useBuildBeginVariableOptions() {
const options = useMemo(() => {
return [
{
label: <span>Begin Input</span>,
label: <span>{t('flow.beginInput')}</span>,
title: 'Begin Input',
options: inputs.map((x) => ({
label: x.name,

View File

@ -4,6 +4,7 @@ import { Button } from '@/components/ui/button';
import { RAGFlowPagination } from '@/components/ui/ragflow-pagination';
import { useNavigatePage } from '@/hooks/logic-hooks/navigate-hooks';
import { useFetchAgentListByPage } from '@/hooks/use-agent-request';
import { t } from 'i18next';
import { pick } from 'lodash';
import { Plus } from 'lucide-react';
import { useCallback } from 'react';
@ -41,7 +42,7 @@ export default function Agents() {
>
<Button onClick={navigateToAgentTemplates}>
<Plus className="mr-2 h-4 w-4" />
Create Agent
{t('flow.createGraph')}
</Button>
</ListFilterBar>
</div>

View File

@ -1,4 +1,5 @@
import { variableEnabledFieldMap } from '@/constants/chat';
import { TFunction } from 'i18next';
import omit from 'lodash/omit';
// chat model setting and generate operator
@ -27,7 +28,17 @@ export const removeUselessFieldsFromValues = (values: any, prefix?: string) => {
return nextValues;
};
export function buildOptions(data: Record<string, any>) {
export function buildOptions(
data: Record<string, any>,
t?: TFunction<['translation', ...string[]], undefined>,
prefix?: string,
) {
if (t) {
return Object.values(data).map((val) => ({
label: t(`${prefix ? prefix + '.' : ''}${val.toLowerCase()}`),
value: val,
}));
}
return Object.values(data).map((val) => ({ label: val, value: val }));
}