refactor(i18n): use JSON with flattened key and namespace (#30114)

Co-authored-by: yyh <yuanyouhuilyz@gmail.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This commit is contained in:
Stephen Zhou
2025-12-29 14:52:32 +08:00
committed by GitHub
parent 09be869f58
commit 6d0e36479b
2552 changed files with 111159 additions and 142972 deletions

View File

@ -51,7 +51,7 @@ const ConfigCredential: FC<Props> = ({
isShow
positionCenter={positionCenter}
onHide={onHide}
title={t('tools.createTool.authMethod.title')!}
title={t('createTool.authMethod.title', { ns: 'tools' })!}
dialogClassName="z-[60]"
dialogBackdropClassName="z-[70]"
panelClassName="mt-2 !w-[520px] h-fit z-[80]"
@ -62,10 +62,10 @@ const ConfigCredential: FC<Props> = ({
<div className="px-6 pt-2">
<div className="space-y-4">
<div>
<div className="system-sm-medium py-2 text-text-primary">{t('tools.createTool.authMethod.type')}</div>
<div className="system-sm-medium py-2 text-text-primary">{t('createTool.authMethod.type', { ns: 'tools' })}</div>
<div className="flex space-x-3">
<SelectItem
text={t('tools.createTool.authMethod.types.none')}
text={t('createTool.authMethod.types.none', { ns: 'tools' })}
value={AuthType.none}
isChecked={tempCredential.auth_type === AuthType.none}
onClick={value => setTempCredential({
@ -73,7 +73,7 @@ const ConfigCredential: FC<Props> = ({
})}
/>
<SelectItem
text={t('tools.createTool.authMethod.types.api_key_header')}
text={t('createTool.authMethod.types.api_key_header', { ns: 'tools' })}
value={AuthType.apiKeyHeader}
isChecked={tempCredential.auth_type === AuthType.apiKeyHeader}
onClick={value => setTempCredential({
@ -84,7 +84,7 @@ const ConfigCredential: FC<Props> = ({
})}
/>
<SelectItem
text={t('tools.createTool.authMethod.types.api_key_query')}
text={t('createTool.authMethod.types.api_key_query', { ns: 'tools' })}
value={AuthType.apiKeyQuery}
isChecked={tempCredential.auth_type === AuthType.apiKeyQuery}
onClick={value => setTempCredential({
@ -98,22 +98,22 @@ const ConfigCredential: FC<Props> = ({
{tempCredential.auth_type === AuthType.apiKeyHeader && (
<>
<div>
<div className="system-sm-medium py-2 text-text-primary">{t('tools.createTool.authHeaderPrefix.title')}</div>
<div className="system-sm-medium py-2 text-text-primary">{t('createTool.authHeaderPrefix.title', { ns: 'tools' })}</div>
<div className="flex space-x-3">
<SelectItem
text={t('tools.createTool.authHeaderPrefix.types.basic')}
text={t('createTool.authHeaderPrefix.types.basic', { ns: 'tools' })}
value={AuthHeaderPrefix.basic}
isChecked={tempCredential.api_key_header_prefix === AuthHeaderPrefix.basic}
onClick={value => setTempCredential({ ...tempCredential, api_key_header_prefix: value as AuthHeaderPrefix })}
/>
<SelectItem
text={t('tools.createTool.authHeaderPrefix.types.bearer')}
text={t('createTool.authHeaderPrefix.types.bearer', { ns: 'tools' })}
value={AuthHeaderPrefix.bearer}
isChecked={tempCredential.api_key_header_prefix === AuthHeaderPrefix.bearer}
onClick={value => setTempCredential({ ...tempCredential, api_key_header_prefix: value as AuthHeaderPrefix })}
/>
<SelectItem
text={t('tools.createTool.authHeaderPrefix.types.custom')}
text={t('createTool.authHeaderPrefix.types.custom', { ns: 'tools' })}
value={AuthHeaderPrefix.custom}
isChecked={tempCredential.api_key_header_prefix === AuthHeaderPrefix.custom}
onClick={value => setTempCredential({ ...tempCredential, api_key_header_prefix: value as AuthHeaderPrefix })}
@ -122,11 +122,11 @@ const ConfigCredential: FC<Props> = ({
</div>
<div>
<div className="system-sm-medium flex items-center py-2 text-text-primary">
{t('tools.createTool.authMethod.key')}
{t('createTool.authMethod.key', { ns: 'tools' })}
<Tooltip
popupContent={(
<div className="w-[261px] text-text-tertiary">
{t('tools.createTool.authMethod.keyTooltip')}
{t('createTool.authMethod.keyTooltip', { ns: 'tools' })}
</div>
)}
triggerClassName="ml-0.5 w-4 h-4"
@ -135,15 +135,15 @@ const ConfigCredential: FC<Props> = ({
<Input
value={tempCredential.api_key_header}
onChange={e => setTempCredential({ ...tempCredential, api_key_header: e.target.value })}
placeholder={t('tools.createTool.authMethod.types.apiKeyPlaceholder')!}
placeholder={t('createTool.authMethod.types.apiKeyPlaceholder', { ns: 'tools' })!}
/>
</div>
<div>
<div className="system-sm-medium py-2 text-text-primary">{t('tools.createTool.authMethod.value')}</div>
<div className="system-sm-medium py-2 text-text-primary">{t('createTool.authMethod.value', { ns: 'tools' })}</div>
<Input
value={tempCredential.api_key_value}
onChange={e => setTempCredential({ ...tempCredential, api_key_value: e.target.value })}
placeholder={t('tools.createTool.authMethod.types.apiValuePlaceholder')!}
placeholder={t('createTool.authMethod.types.apiValuePlaceholder', { ns: 'tools' })!}
/>
</div>
</>
@ -152,11 +152,11 @@ const ConfigCredential: FC<Props> = ({
<>
<div>
<div className="system-sm-medium flex items-center py-2 text-text-primary">
{t('tools.createTool.authMethod.queryParam')}
{t('createTool.authMethod.queryParam', { ns: 'tools' })}
<Tooltip
popupContent={(
<div className="w-[261px] text-text-tertiary">
{t('tools.createTool.authMethod.queryParamTooltip')}
{t('createTool.authMethod.queryParamTooltip', { ns: 'tools' })}
</div>
)}
triggerClassName="ml-0.5 w-4 h-4"
@ -165,15 +165,15 @@ const ConfigCredential: FC<Props> = ({
<Input
value={tempCredential.api_key_query_param}
onChange={e => setTempCredential({ ...tempCredential, api_key_query_param: e.target.value })}
placeholder={t('tools.createTool.authMethod.types.queryParamPlaceholder')!}
placeholder={t('createTool.authMethod.types.queryParamPlaceholder', { ns: 'tools' })!}
/>
</div>
<div>
<div className="system-sm-medium py-2 text-text-primary">{t('tools.createTool.authMethod.value')}</div>
<div className="system-sm-medium py-2 text-text-primary">{t('createTool.authMethod.value', { ns: 'tools' })}</div>
<Input
value={tempCredential.api_key_value}
onChange={e => setTempCredential({ ...tempCredential, api_key_value: e.target.value })}
placeholder={t('tools.createTool.authMethod.types.apiValuePlaceholder')!}
placeholder={t('createTool.authMethod.types.apiValuePlaceholder', { ns: 'tools' })!}
/>
</div>
</>
@ -182,7 +182,7 @@ const ConfigCredential: FC<Props> = ({
</div>
<div className="mt-4 flex shrink-0 justify-end space-x-2 py-4">
<Button onClick={onHide}>{t('common.operation.cancel')}</Button>
<Button onClick={onHide}>{t('operation.cancel', { ns: 'common' })}</Button>
<Button
variant="primary"
onClick={() => {
@ -190,7 +190,7 @@ const ConfigCredential: FC<Props> = ({
onHide()
}}
>
{t('common.operation.save')}
{t('operation.save', { ns: 'common' })}
</Button>
</div>
</div>

View File

@ -176,6 +176,6 @@ const examples = [
}
}`,
},
]
] as const
export default examples

View File

@ -29,7 +29,7 @@ const GetSchema: FC<Props> = ({
if (!importUrl.startsWith('http://') && !importUrl.startsWith('https://')) {
Toast.notify({
type: 'error',
message: t('tools.createTool.urlError'),
message: t('createTool.urlError', { ns: 'tools' }),
})
return
}
@ -65,7 +65,7 @@ const GetSchema: FC<Props> = ({
onClick={() => { setShowImportFromUrl(!showImportFromUrl) }}
>
<RiAddLine className="h-3 w-3" />
<div className="system-xs-medium text-text-secondary">{t('tools.createTool.importFromUrl')}</div>
<div className="system-xs-medium text-text-secondary">{t('createTool.importFromUrl', { ns: 'tools' })}</div>
</Button>
{showImportFromUrl && (
<div className=" absolute left-[-35px] top-[26px] rounded-lg border border-components-panel-border bg-components-panel-bg p-2 shadow-lg">
@ -73,7 +73,7 @@ const GetSchema: FC<Props> = ({
<Input
type="text"
className="w-[244px]"
placeholder={t('tools.createTool.importFromUrlPlaceHolder')!}
placeholder={t('createTool.importFromUrlPlaceHolder', { ns: 'tools' })!}
value={importUrl}
onChange={e => setImportUrl(e.target.value)}
/>
@ -85,7 +85,7 @@ const GetSchema: FC<Props> = ({
onClick={handleImportFromUrl}
loading={isParsing}
>
{isParsing ? '' : t('common.operation.ok')}
{isParsing ? '' : t('operation.ok', { ns: 'common' })}
</Button>
</div>
</div>
@ -97,7 +97,7 @@ const GetSchema: FC<Props> = ({
className="space-x-1"
onClick={() => { setShowExamples(!showExamples) }}
>
<div className="system-xs-medium text-text-secondary">{t('tools.createTool.examples')}</div>
<div className="system-xs-medium text-text-secondary">{t('createTool.examples', { ns: 'tools' })}</div>
<RiArrowDownSLine className="h-3 w-3" />
</Button>
{showExamples && (
@ -111,7 +111,7 @@ const GetSchema: FC<Props> = ({
}}
className="system-sm-regular cursor-pointer whitespace-nowrap rounded-lg px-3 py-1.5 leading-5 text-text-secondary hover:bg-components-panel-on-panel-item-bg-hover"
>
{t(`tools.createTool.exampleOptions.${item.key}` as any) as string}
{t(`createTool.exampleOptions.${item.key}`, { ns: 'tools' })}
</div>
))}
</div>

View File

@ -154,10 +154,10 @@ const EditCustomCollectionModal: FC<Props> = ({
let errorMessage = ''
if (!postData.provider)
errorMessage = t('common.errorMsg.fieldRequired', { field: t('tools.createTool.name') })
errorMessage = t('errorMsg.fieldRequired', { ns: 'common', field: t('createTool.name', { ns: 'tools' }) })
if (!postData.schema)
errorMessage = t('common.errorMsg.fieldRequired', { field: t('tools.createTool.schema') })
errorMessage = t('errorMsg.fieldRequired', { ns: 'common', field: t('createTool.schema', { ns: 'tools' }) })
if (errorMessage) {
Toast.notify({
@ -197,7 +197,7 @@ const EditCustomCollectionModal: FC<Props> = ({
isShow
positionCenter={isAdd && !positionLeft}
onHide={onHide}
title={t(`tools.createTool.${isAdd ? 'title' : 'editTitle'}`)!}
title={t(`createTool.${isAdd ? 'title' : 'editTitle'}`, { ns: 'tools' })!}
dialogClassName={dialogClassName}
panelClassName="mt-2 !w-[640px]"
maxWidthClassName="!max-w-[640px]"
@ -208,7 +208,7 @@ const EditCustomCollectionModal: FC<Props> = ({
<div className="h-0 grow space-y-4 overflow-y-auto px-6 py-3">
<div>
<div className="system-sm-medium py-2 text-text-primary">
{t('tools.createTool.name')}
{t('createTool.name', { ns: 'tools' })}
{' '}
<span className="ml-1 text-red-500">*</span>
</div>
@ -216,7 +216,7 @@ const EditCustomCollectionModal: FC<Props> = ({
<AppIcon size="large" onClick={() => { setShowEmojiPicker(true) }} className="cursor-pointer" icon={emoji.content} background={emoji.background} />
<Input
className="h-10 grow"
placeholder={t('tools.createTool.toolNamePlaceHolder')!}
placeholder={t('createTool.toolNamePlaceHolder', { ns: 'tools' })!}
value={customCollection.provider}
onChange={(e) => {
const newCollection = produce(customCollection, (draft) => {
@ -233,7 +233,7 @@ const EditCustomCollectionModal: FC<Props> = ({
<div className="flex items-center justify-between">
<div className="flex items-center">
<div className="system-sm-medium py-2 text-text-primary">
{t('tools.createTool.schema')}
{t('createTool.schema', { ns: 'tools' })}
<span className="ml-1 text-red-500">*</span>
</div>
<div className="mx-2 h-3 w-px bg-divider-regular"></div>
@ -243,7 +243,7 @@ const EditCustomCollectionModal: FC<Props> = ({
rel="noopener noreferrer"
className="flex h-[18px] items-center space-x-1 text-text-accent"
>
<div className="text-xs font-normal">{t('tools.createTool.viewSchemaSpec')}</div>
<div className="text-xs font-normal">{t('createTool.viewSchemaSpec', { ns: 'tools' })}</div>
<LinkExternal02 className="h-3 w-3" />
</a>
</div>
@ -254,22 +254,22 @@ const EditCustomCollectionModal: FC<Props> = ({
className="h-[240px] resize-none"
value={schema}
onChange={e => setSchema(e.target.value)}
placeholder={t('tools.createTool.schemaPlaceHolder')!}
placeholder={t('createTool.schemaPlaceHolder', { ns: 'tools' })!}
/>
</div>
{/* Available Tools */}
<div>
<div className="system-sm-medium py-2 text-text-primary">{t('tools.createTool.availableTools.title')}</div>
<div className="system-sm-medium py-2 text-text-primary">{t('createTool.availableTools.title', { ns: 'tools' })}</div>
<div className="w-full overflow-x-auto rounded-lg border border-divider-regular">
<table className="system-xs-regular w-full text-text-secondary">
<thead className="uppercase text-text-tertiary">
<tr className={cn(paramsSchemas.length > 0 && 'border-b', 'border-divider-regular')}>
<th className="p-2 pl-3 font-medium">{t('tools.createTool.availableTools.name')}</th>
<th className="w-[236px] p-2 pl-3 font-medium">{t('tools.createTool.availableTools.description')}</th>
<th className="p-2 pl-3 font-medium">{t('tools.createTool.availableTools.method')}</th>
<th className="p-2 pl-3 font-medium">{t('tools.createTool.availableTools.path')}</th>
<th className="w-[54px] p-2 pl-3 font-medium">{t('tools.createTool.availableTools.action')}</th>
<th className="p-2 pl-3 font-medium">{t('createTool.availableTools.name', { ns: 'tools' })}</th>
<th className="w-[236px] p-2 pl-3 font-medium">{t('createTool.availableTools.description', { ns: 'tools' })}</th>
<th className="p-2 pl-3 font-medium">{t('createTool.availableTools.method', { ns: 'tools' })}</th>
<th className="p-2 pl-3 font-medium">{t('createTool.availableTools.path', { ns: 'tools' })}</th>
<th className="w-[54px] p-2 pl-3 font-medium">{t('createTool.availableTools.action', { ns: 'tools' })}</th>
</tr>
</thead>
<tbody>
@ -287,7 +287,7 @@ const EditCustomCollectionModal: FC<Props> = ({
setIsShowTestApi(true)
}}
>
{t('tools.createTool.availableTools.test')}
{t('createTool.availableTools.test', { ns: 'tools' })}
</Button>
</td>
</tr>
@ -299,22 +299,22 @@ const EditCustomCollectionModal: FC<Props> = ({
{/* Authorization method */}
<div>
<div className="system-sm-medium py-2 text-text-primary">{t('tools.createTool.authMethod.title')}</div>
<div className="system-sm-medium py-2 text-text-primary">{t('createTool.authMethod.title', { ns: 'tools' })}</div>
<div className="flex h-9 cursor-pointer items-center justify-between rounded-lg bg-components-input-bg-normal px-2.5" onClick={() => setCredentialsModalShow(true)}>
<div className="system-xs-regular text-text-primary">{t(`tools.createTool.authMethod.types.${credential.auth_type}` as any) as string}</div>
<div className="system-xs-regular text-text-primary">{t(`createTool.authMethod.types.${credential.auth_type}`, { ns: 'tools' })}</div>
<RiSettings2Line className="h-4 w-4 text-text-secondary" />
</div>
</div>
{/* Labels */}
<div>
<div className="system-sm-medium py-2 text-text-primary">{t('tools.createTool.toolInput.label')}</div>
<div className="system-sm-medium py-2 text-text-primary">{t('createTool.toolInput.label', { ns: 'tools' })}</div>
<LabelSelector value={labels} onChange={handleLabelSelect} />
</div>
{/* Privacy Policy */}
<div>
<div className="system-sm-medium py-2 text-text-primary">{t('tools.createTool.privacyPolicy')}</div>
<div className="system-sm-medium py-2 text-text-primary">{t('createTool.privacyPolicy', { ns: 'tools' })}</div>
<Input
value={customCollection.privacy_policy}
onChange={(e) => {
@ -324,12 +324,12 @@ const EditCustomCollectionModal: FC<Props> = ({
setCustomCollection(newCollection)
}}
className="h-10 grow"
placeholder={t('tools.createTool.privacyPolicyPlaceholder') || ''}
placeholder={t('createTool.privacyPolicyPlaceholder', { ns: 'tools' }) || ''}
/>
</div>
<div>
<div className="system-sm-medium py-2 text-text-primary">{t('tools.createTool.customDisclaimer')}</div>
<div className="system-sm-medium py-2 text-text-primary">{t('createTool.customDisclaimer', { ns: 'tools' })}</div>
<Input
value={customCollection.custom_disclaimer}
onChange={(e) => {
@ -339,7 +339,7 @@ const EditCustomCollectionModal: FC<Props> = ({
setCustomCollection(newCollection)
}}
className="h-10 grow"
placeholder={t('tools.createTool.customDisclaimerPlaceholder') || ''}
placeholder={t('createTool.customDisclaimerPlaceholder', { ns: 'tools' }) || ''}
/>
</div>
@ -347,12 +347,12 @@ const EditCustomCollectionModal: FC<Props> = ({
<div className={cn(isEdit ? 'justify-between' : 'justify-end', 'mt-2 flex shrink-0 rounded-b-[10px] border-t border-divider-regular bg-background-section-burn px-6 py-4')}>
{
isEdit && (
<Button variant="warning" onClick={onRemove}>{t('common.operation.delete')}</Button>
<Button variant="warning" onClick={onRemove}>{t('operation.delete', { ns: 'common' })}</Button>
)
}
<div className="flex space-x-2 ">
<Button onClick={onHide}>{t('common.operation.cancel')}</Button>
<Button variant="primary" onClick={handleSave}>{t('common.operation.save')}</Button>
<Button onClick={onHide}>{t('operation.cancel', { ns: 'common' })}</Button>
<Button variant="primary" onClick={handleSave}>{t('operation.save', { ns: 'common' })}</Button>
</div>
</div>
{showEmojiPicker && (

View File

@ -67,7 +67,7 @@ const TestApi: FC<Props> = ({
isShow
positionCenter={positionCenter}
onHide={onHide}
title={`${t('tools.test.title')} ${toolName}`}
title={`${t('test.title', { ns: 'tools' })} ${toolName}`}
panelClassName="mt-2 !w-[600px]"
maxWidthClassName="!max-w-[600px]"
height="calc(100vh - 16px)"
@ -76,21 +76,21 @@ const TestApi: FC<Props> = ({
<div className="overflow-y-auto px-6 pt-2">
<div className="space-y-4">
<div>
<div className="system-sm-medium py-2 text-text-primary">{t('tools.createTool.authMethod.title')}</div>
<div className="system-sm-medium py-2 text-text-primary">{t('createTool.authMethod.title', { ns: 'tools' })}</div>
<div className="flex h-9 cursor-pointer items-center justify-between rounded-lg bg-components-input-bg-normal px-2.5" onClick={() => setCredentialsModalShow(true)}>
<div className="system-xs-regular text-text-primary">{t(`tools.createTool.authMethod.types.${tempCredential.auth_type}` as any) as string}</div>
<div className="system-xs-regular text-text-primary">{t(`createTool.authMethod.types.${tempCredential.auth_type}`, { ns: 'tools' })}</div>
<RiSettings2Line className="h-4 w-4 text-text-secondary" />
</div>
</div>
<div>
<div className="system-sm-medium py-2 text-text-primary">{t('tools.test.parametersValue')}</div>
<div className="system-sm-medium py-2 text-text-primary">{t('test.parametersValue', { ns: 'tools' })}</div>
<div className="rounded-lg border border-divider-regular">
<table className="system-xs-regular w-full font-normal text-text-secondary">
<thead className="uppercase text-text-tertiary">
<tr className="border-b border-divider-regular">
<th className="p-2 pl-3 font-medium">{t('tools.test.parameters')}</th>
<th className="p-2 pl-3 font-medium">{t('tools.test.value')}</th>
<th className="p-2 pl-3 font-medium">{t('test.parameters', { ns: 'tools' })}</th>
<th className="p-2 pl-3 font-medium">{t('test.value', { ns: 'tools' })}</th>
</tr>
</thead>
<tbody>
@ -115,14 +115,14 @@ const TestApi: FC<Props> = ({
</div>
</div>
<Button variant="primary" className=" mt-4 h-10 w-full" loading={testing} disabled={testing} onClick={handleTest}>{t('tools.test.title')}</Button>
<Button variant="primary" className=" mt-4 h-10 w-full" loading={testing} disabled={testing} onClick={handleTest}>{t('test.title', { ns: 'tools' })}</Button>
<div className="mt-6">
<div className="flex items-center space-x-3">
<div className="system-xs-semibold text-text-tertiary">{t('tools.test.testResult')}</div>
<div className="system-xs-semibold text-text-tertiary">{t('test.testResult', { ns: 'tools' })}</div>
<div className="bg-[rgb(243, 244, 246)] h-px w-0 grow"></div>
</div>
<div className="system-xs-regular mt-2 h-[200px] overflow-y-auto overflow-x-hidden rounded-lg bg-components-input-bg-normal px-3 py-2 text-text-secondary">
{result || <span className="text-text-quaternary">{t('tools.test.testResultPlaceholder')}</span>}
{result || <span className="text-text-quaternary">{t('test.testResultPlaceholder', { ns: 'tools' })}</span>}
</div>
</div>
</div>

View File

@ -76,7 +76,7 @@ const LabelFilter: FC<LabelFilterProps> = ({
<Tag01 className="h-3.5 w-3.5 text-text-tertiary" />
</div>
<div className="text-[13px] leading-[18px] text-text-tertiary">
{!value.length && t('common.tag.placeholder')}
{!value.length && t('tag.placeholder', { ns: 'common' })}
{!!value.length && currentLabel?.label}
</div>
{value.length > 1 && (
@ -125,7 +125,7 @@ const LabelFilter: FC<LabelFilterProps> = ({
{!filteredLabelList.length && (
<div className="flex flex-col items-center gap-1 p-3">
<Tag03 className="h-6 w-6 text-text-quaternary" />
<div className="text-xs leading-[14px] text-text-tertiary">{t('common.tag.noTag')}</div>
<div className="text-xs leading-[14px] text-text-tertiary">{t('tag.noTag', { ns: 'common' })}</div>
</div>
)}
</div>

View File

@ -72,7 +72,7 @@ const LabelSelector: FC<LabelSelectorProps> = ({
)}
>
<div title={value.length > 0 ? selectedLabels : ''} className={cn('grow truncate text-[13px] leading-[18px] text-text-secondary', !value.length && '!text-text-quaternary')}>
{!value.length && t('tools.createTool.toolInput.labelPlaceholder')}
{!value.length && t('createTool.toolInput.labelPlaceholder', { ns: 'tools' })}
{!!value.length && selectedLabels}
</div>
<div className="ml-1 shrink-0 text-text-secondary opacity-60">
@ -109,7 +109,7 @@ const LabelSelector: FC<LabelSelectorProps> = ({
{!filteredLabelList.length && (
<div className="flex flex-col items-center gap-1 p-3">
<Tag03 className="h-6 w-6 text-text-quaternary" />
<div className="text-xs leading-[14px] text-text-tertiary">{t('common.tag.noTag')}</div>
<div className="text-xs leading-[14px] text-text-tertiary">{t('tag.noTag', { ns: 'common' })}</div>
</div>
)}
</div>

View File

@ -46,44 +46,44 @@ const Marketplace = ({
)}
<div className="pb-3 pt-4">
<div className="title-2xl-semi-bold bg-gradient-to-r from-[rgba(11,165,236,0.95)] to-[rgba(21,90,239,0.95)] bg-clip-text text-transparent">
{t('plugin.marketplace.moreFrom')}
{t('marketplace.moreFrom', { ns: 'plugin' })}
</div>
<div className="body-md-regular flex items-center text-center text-text-tertiary">
{t('plugin.marketplace.discover')}
{t('marketplace.discover', { ns: 'plugin' })}
<span className="body-md-medium relative ml-1 text-text-secondary after:absolute after:bottom-[1.5px] after:left-0 after:h-2 after:w-full after:bg-text-text-selected after:content-['']">
{t('plugin.category.models')}
{t('category.models', { ns: 'plugin' })}
</span>
,
<span className="body-md-medium relative ml-1 text-text-secondary after:absolute after:bottom-[1.5px] after:left-0 after:h-2 after:w-full after:bg-text-text-selected after:content-['']">
{t('plugin.category.tools')}
{t('category.tools', { ns: 'plugin' })}
</span>
,
<span className="body-md-medium relative ml-1 text-text-secondary after:absolute after:bottom-[1.5px] after:left-0 after:h-2 after:w-full after:bg-text-text-selected after:content-['']">
{t('plugin.category.datasources')}
{t('category.datasources', { ns: 'plugin' })}
</span>
,
<span className="body-md-medium relative ml-1 text-text-secondary after:absolute after:bottom-[1.5px] after:left-0 after:h-2 after:w-full after:bg-text-text-selected after:content-['']">
{t('plugin.category.triggers')}
{t('category.triggers', { ns: 'plugin' })}
</span>
,
<span className="body-md-medium relative ml-1 text-text-secondary after:absolute after:bottom-[1.5px] after:left-0 after:h-2 after:w-full after:bg-text-text-selected after:content-['']">
{t('plugin.category.agents')}
{t('category.agents', { ns: 'plugin' })}
</span>
,
<span className="body-md-medium relative ml-1 mr-1 text-text-secondary after:absolute after:bottom-[1.5px] after:left-0 after:h-2 after:w-full after:bg-text-text-selected after:content-['']">
{t('plugin.category.extensions')}
{t('category.extensions', { ns: 'plugin' })}
</span>
{t('plugin.marketplace.and')}
{t('marketplace.and', { ns: 'plugin' })}
<span className="body-md-medium relative ml-1 mr-1 text-text-secondary after:absolute after:bottom-[1.5px] after:left-0 after:h-2 after:w-full after:bg-text-text-selected after:content-['']">
{t('plugin.category.bundles')}
{t('category.bundles', { ns: 'plugin' })}
</span>
{t('common.operation.in')}
{t('operation.in', { ns: 'common' })}
<a
href={getMarketplaceUrl('', { language: locale, q: searchPluginText, tags: filterPluginTags.join(','), theme })}
className="system-sm-medium ml-1 flex items-center text-text-accent"
target="_blank"
>
{t('plugin.marketplace.difyMarketplace')}
{t('marketplace.difyMarketplace', { ns: 'plugin' })}
<RiArrowRightUpLine className="h-4 w-4" />
</a>
</div>

View File

@ -50,13 +50,13 @@ const NewMCPCard = ({ handleCreate }: Props) => {
<div className="flex h-10 w-10 items-center justify-center rounded-lg border border-dashed border-divider-deep group-hover:border-solid group-hover:border-state-accent-hover-alt group-hover:bg-state-accent-hover">
<RiAddCircleFill className="h-4 w-4 text-text-quaternary group-hover:text-text-accent" />
</div>
<div className="system-md-semibold ml-3 text-text-secondary group-hover:text-text-accent">{t('tools.mcp.create.cardTitle')}</div>
<div className="system-md-semibold ml-3 text-text-secondary group-hover:text-text-accent">{t('mcp.create.cardTitle', { ns: 'tools' })}</div>
</div>
</div>
<div className="rounded-b-xl border-t-[0.5px] border-divider-subtle px-4 py-3 text-text-tertiary hover:text-text-accent">
<a href={linkUrl} target="_blank" rel="noopener noreferrer" className="flex items-center space-x-1">
<RiBookOpenLine className="h-3 w-3 shrink-0" />
<div className="system-xs-regular grow truncate" title={t('tools.mcp.create.cardLink') || ''}>{t('tools.mcp.create.cardLink')}</div>
<div className="system-xs-regular grow truncate" title={t('mcp.create.cardLink', { ns: 'tools' }) || ''}>{t('mcp.create.cardLink', { ns: 'tools' })}</div>
<RiArrowRightUpLine className="h-3 w-3 shrink-0" />
</a>
</div>

View File

@ -159,11 +159,11 @@ const MCPDetailContent: FC<Props> = ({
<div className="system-md-semibold truncate text-text-primary" title={detail.name}>{detail.name}</div>
</div>
<div className="mt-0.5 flex items-center gap-1">
<Tooltip popupContent={t('tools.mcp.identifier')}>
<Tooltip popupContent={t('mcp.identifier', { ns: 'tools' })}>
<div className="system-xs-regular shrink-0 cursor-pointer text-text-secondary" onClick={() => copy(detail.server_identifier || '')}>{detail.server_identifier}</div>
</Tooltip>
<div className="system-xs-regular shrink-0 text-text-quaternary">·</div>
<Tooltip popupContent={t('tools.mcp.modal.serverUrl')}>
<Tooltip popupContent={t('mcp.modal.serverUrl', { ns: 'tools' })}>
<div className="system-xs-regular truncate text-text-secondary">{detail.server_url}</div>
</Tooltip>
</div>
@ -187,7 +187,7 @@ const MCPDetailContent: FC<Props> = ({
disabled={!isCurrentWorkspaceManager}
>
<Indicator className="mr-2" color="green" />
{t('tools.auth.authorized')}
{t('auth.authorized', { ns: 'tools' })}
</Button>
)}
{!detail.is_team_authorization && !isAuthorizing && (
@ -197,7 +197,7 @@ const MCPDetailContent: FC<Props> = ({
onClick={handleAuthorize}
disabled={!isCurrentWorkspaceManager}
>
{t('tools.mcp.authorize')}
{t('mcp.authorize', { ns: 'tools' })}
</Button>
)}
{isAuthorizing && (
@ -207,7 +207,7 @@ const MCPDetailContent: FC<Props> = ({
disabled
>
<RiLoader2Line className={cn('mr-1 h-4 w-4 animate-spin')} />
{t('tools.mcp.authorizing')}
{t('mcp.authorizing', { ns: 'tools' })}
</Button>
)}
</div>
@ -217,8 +217,8 @@ const MCPDetailContent: FC<Props> = ({
<>
<div className="flex shrink-0 justify-between gap-2 px-4 pb-1 pt-2">
<div className="flex h-6 items-center">
{!isUpdating && <div className="system-sm-semibold-uppercase text-text-secondary">{t('tools.mcp.gettingTools')}</div>}
{isUpdating && <div className="system-sm-semibold-uppercase text-text-secondary">{t('tools.mcp.updateTools')}</div>}
{!isUpdating && <div className="system-sm-semibold-uppercase text-text-secondary">{t('mcp.gettingTools', { ns: 'tools' })}</div>}
{isUpdating && <div className="system-sm-semibold-uppercase text-text-secondary">{t('mcp.updateTools', { ns: 'tools' })}</div>}
</div>
<div></div>
</div>
@ -229,12 +229,12 @@ const MCPDetailContent: FC<Props> = ({
)}
{!isUpdating && detail.is_team_authorization && !isGettingTools && !toolList.length && (
<div className="flex h-full w-full flex-col items-center justify-center">
<div className="system-sm-regular mb-3 text-text-tertiary">{t('tools.mcp.toolsEmpty')}</div>
<div className="system-sm-regular mb-3 text-text-tertiary">{t('mcp.toolsEmpty', { ns: 'tools' })}</div>
<Button
variant="primary"
onClick={handleUpdateTools}
>
{t('tools.mcp.getTools')}
{t('mcp.getTools', { ns: 'tools' })}
</Button>
</div>
)}
@ -242,13 +242,13 @@ const MCPDetailContent: FC<Props> = ({
<>
<div className="flex shrink-0 justify-between gap-2 px-4 pb-1 pt-2">
<div className="flex h-6 items-center">
{toolList.length > 1 && <div className="system-sm-semibold-uppercase text-text-secondary">{t('tools.mcp.toolsNum', { count: toolList.length })}</div>}
{toolList.length === 1 && <div className="system-sm-semibold-uppercase text-text-secondary">{t('tools.mcp.onlyTool')}</div>}
{toolList.length > 1 && <div className="system-sm-semibold-uppercase text-text-secondary">{t('mcp.toolsNum', { ns: 'tools', count: toolList.length })}</div>}
{toolList.length === 1 && <div className="system-sm-semibold-uppercase text-text-secondary">{t('mcp.onlyTool', { ns: 'tools' })}</div>}
</div>
<div>
<Button size="small" onClick={showUpdateConfirm}>
<RiLoopLeftLine className="mr-1 h-3.5 w-3.5" />
{t('tools.mcp.update')}
{t('mcp.update', { ns: 'tools' })}
</Button>
</div>
</div>
@ -265,9 +265,9 @@ const MCPDetailContent: FC<Props> = ({
{!isUpdating && !detail.is_team_authorization && (
<div className="flex h-full w-full flex-col items-center justify-center">
{!isAuthorizing && <div className="system-md-medium mb-1 text-text-secondary">{t('tools.mcp.authorizingRequired')}</div>}
{isAuthorizing && <div className="system-md-medium mb-1 text-text-secondary">{t('tools.mcp.authorizing')}</div>}
<div className="system-sm-regular text-text-tertiary">{t('tools.mcp.authorizeTip')}</div>
{!isAuthorizing && <div className="system-md-medium mb-1 text-text-secondary">{t('mcp.authorizingRequired', { ns: 'tools' })}</div>}
{isAuthorizing && <div className="system-md-medium mb-1 text-text-secondary">{t('mcp.authorizing', { ns: 'tools' })}</div>}
<div className="system-sm-regular text-text-tertiary">{t('mcp.authorizeTip', { ns: 'tools' })}</div>
</div>
)}
</div>
@ -282,10 +282,10 @@ const MCPDetailContent: FC<Props> = ({
{isShowDeleteConfirm && (
<Confirm
isShow
title={t('tools.mcp.delete')}
title={t('mcp.delete', { ns: 'tools' })}
content={(
<div>
{t('tools.mcp.deleteConfirmTitle', { mcp: detail.name })}
{t('mcp.deleteConfirmTitle', { ns: 'tools', mcp: detail.name })}
</div>
)}
onCancel={hideDeleteConfirm}
@ -297,8 +297,8 @@ const MCPDetailContent: FC<Props> = ({
{isShowUpdateConfirm && (
<Confirm
isShow
title={t('tools.mcp.toolUpdateConfirmTitle')}
content={t('tools.mcp.toolUpdateConfirmContent')}
title={t('mcp.toolUpdateConfirmTitle', { ns: 'tools' })}
content={t('mcp.toolUpdateConfirmContent', { ns: 'tools' })}
onCancel={hideUpdateConfirm}
onConfirm={handleUpdateTools}
/>

View File

@ -69,7 +69,7 @@ const OperationDropdown: FC<Props> = ({
}}
>
<RiEditLine className="h-4 w-4 text-text-tertiary" />
<div className="system-md-regular ml-2 text-text-secondary">{t('tools.mcp.operation.edit')}</div>
<div className="system-md-regular ml-2 text-text-secondary">{t('mcp.operation.edit', { ns: 'tools' })}</div>
</div>
<div
className="group flex cursor-pointer items-center rounded-lg px-3 py-1.5 hover:bg-state-destructive-hover"
@ -79,7 +79,7 @@ const OperationDropdown: FC<Props> = ({
}}
>
<RiDeleteBinLine className="h-4 w-4 text-text-tertiary group-hover:text-text-destructive-secondary" />
<div className="system-md-regular ml-2 text-text-secondary group-hover:text-text-destructive">{t('tools.mcp.operation.remove')}</div>
<div className="system-md-regular ml-2 text-text-secondary group-hover:text-text-destructive">{t('mcp.operation.remove', { ns: 'tools' })}</div>
</div>
</div>
</PortalToFollowElemContent>

View File

@ -28,12 +28,12 @@ const MCPToolItem = ({
return (
<div className="mt-2">
<div className="title-xs-semi-bold mb-1 text-text-primary">
{t('tools.mcp.toolItem.parameters')}
{t('mcp.toolItem.parameters', { ns: 'tools' })}
:
</div>
<ul className="space-y-1">
{parameters.map((parameter) => {
const descriptionContent = parameter.human_description[language] || t('tools.mcp.toolItem.noDescription')
const descriptionContent = parameter.human_description[language] || t('mcp.toolItem.noDescription', { ns: 'tools' })
return (
<li key={parameter.name} className="pl-2">
<span className="system-xs-regular font-bold text-text-secondary">{parameter.name}</span>

View File

@ -52,7 +52,7 @@ const HeadersInput = ({
return (
<div className="space-y-2">
<div className="body-xs-regular text-text-tertiary">
{t('tools.mcp.modal.noHeaders')}
{t('mcp.modal.noHeaders', { ns: 'tools' })}
</div>
{!readonly && (
<Button
@ -62,7 +62,7 @@ const HeadersInput = ({
className="w-full"
>
<RiAddLine className="mr-1 h-4 w-4" />
{t('tools.mcp.modal.addHeader')}
{t('mcp.modal.addHeader', { ns: 'tools' })}
</Button>
)}
</div>
@ -73,13 +73,13 @@ const HeadersInput = ({
<div className="space-y-2">
{isMasked && (
<div className="body-xs-regular text-text-tertiary">
{t('tools.mcp.modal.maskedHeadersTip')}
{t('mcp.modal.maskedHeadersTip', { ns: 'tools' })}
</div>
)}
<div className="overflow-hidden rounded-lg border border-divider-regular">
<div className="system-xs-medium-uppercase bg-background-secondary flex h-7 items-center leading-7 text-text-tertiary">
<div className="h-full w-1/2 border-r border-divider-regular pl-3">{t('tools.mcp.modal.headerKey')}</div>
<div className="h-full w-1/2 pl-3 pr-1">{t('tools.mcp.modal.headerValue')}</div>
<div className="h-full w-1/2 border-r border-divider-regular pl-3">{t('mcp.modal.headerKey', { ns: 'tools' })}</div>
<div className="h-full w-1/2 pl-3 pr-1">{t('mcp.modal.headerValue', { ns: 'tools' })}</div>
</div>
{headersItems.map((item, index) => (
<div
@ -93,7 +93,7 @@ const HeadersInput = ({
<Input
value={item.key}
onChange={e => handleItemChange(index, 'key', e.target.value)}
placeholder={t('tools.mcp.modal.headerKeyPlaceholder')}
placeholder={t('mcp.modal.headerKeyPlaceholder', { ns: 'tools' })}
className="rounded-none border-0"
readOnly={readonly}
/>
@ -102,7 +102,7 @@ const HeadersInput = ({
<Input
value={item.value}
onChange={e => handleItemChange(index, 'value', e.target.value)}
placeholder={t('tools.mcp.modal.headerValuePlaceholder')}
placeholder={t('mcp.modal.headerValuePlaceholder', { ns: 'tools' })}
className="flex-1 rounded-none border-0"
readOnly={readonly}
/>
@ -126,7 +126,7 @@ const HeadersInput = ({
className="w-full"
>
<RiAddLine className="mr-1 h-4 w-4" />
{t('tools.mcp.modal.addHeader')}
{t('mcp.modal.addHeader', { ns: 'tools' })}
</Button>
)}
</div>

View File

@ -97,18 +97,18 @@ const MCPServerModal = ({
<RiCloseLine className="h-5 w-5 text-text-tertiary" />
</div>
<div className="title-2xl-semi-bold relative p-6 pb-3 text-xl text-text-primary">
{!data ? t('tools.mcp.server.modal.addTitle') : t('tools.mcp.server.modal.editTitle')}
{!data ? t('mcp.server.modal.addTitle', { ns: 'tools' }) : t('mcp.server.modal.editTitle', { ns: 'tools' })}
</div>
<div className="space-y-5 px-6 py-3">
<div className="space-y-0.5">
<div className="flex h-6 items-center gap-1">
<div className="system-sm-medium text-text-secondary">{t('tools.mcp.server.modal.description')}</div>
<div className="system-sm-medium text-text-secondary">{t('mcp.server.modal.description', { ns: 'tools' })}</div>
<div className="system-xs-regular text-text-destructive-secondary">*</div>
</div>
<Textarea
className="h-[96px] resize-none"
value={description}
placeholder={t('tools.mcp.server.modal.descriptionPlaceholder')}
placeholder={t('mcp.server.modal.descriptionPlaceholder', { ns: 'tools' })}
onChange={e => setDescription(e.target.value)}
>
</Textarea>
@ -116,10 +116,10 @@ const MCPServerModal = ({
{latestParams.length > 0 && (
<div>
<div className="mb-1 flex items-center gap-2">
<div className="system-xs-medium-uppercase shrink-0 text-text-primary">{t('tools.mcp.server.modal.parameters')}</div>
<div className="system-xs-medium-uppercase shrink-0 text-text-primary">{t('mcp.server.modal.parameters', { ns: 'tools' })}</div>
<Divider type="horizontal" className="!m-0 !h-px grow bg-divider-subtle" />
</div>
<div className="body-xs-regular mb-2 text-text-tertiary">{t('tools.mcp.server.modal.parametersTip')}</div>
<div className="body-xs-regular mb-2 text-text-tertiary">{t('mcp.server.modal.parametersTip', { ns: 'tools' })}</div>
<div className="space-y-3">
{latestParams.map(paramItem => (
<MCPServerParamItem
@ -134,8 +134,8 @@ const MCPServerModal = ({
)}
</div>
<div className="flex flex-row-reverse p-6 pt-5">
<Button disabled={!description || creating || updating} className="ml-2" variant="primary" onClick={submit}>{data ? t('tools.mcp.modal.save') : t('tools.mcp.server.modal.confirm')}</Button>
<Button onClick={onHide}>{t('tools.mcp.modal.cancel')}</Button>
<Button disabled={!description || creating || updating} className="ml-2" variant="primary" onClick={submit}>{data ? t('mcp.modal.save', { ns: 'tools' }) : t('mcp.server.modal.confirm', { ns: 'tools' })}</Button>
<Button onClick={onHide}>{t('mcp.modal.cancel', { ns: 'tools' })}</Button>
</div>
</Modal>
)

View File

@ -27,7 +27,7 @@ const MCPServerParamItem = ({
<Textarea
className="h-8 resize-none"
value={value}
placeholder={t('tools.mcp.server.modal.parametersPlaceholder')}
placeholder={t('mcp.server.modal.parametersPlaceholder', { ns: 'tools' })}
onChange={e => onChange(e.target.value)}
>
</Textarea>

View File

@ -172,7 +172,7 @@ function MCPServiceCard({
</div>
<div className="group w-full">
<div className="system-md-semibold min-w-0 overflow-hidden text-ellipsis break-normal text-text-secondary group-hover:text-text-primary">
{t('tools.mcp.server.title')}
{t('mcp.server.title', { ns: 'tools' })}
</div>
</div>
</div>
@ -180,8 +180,8 @@ function MCPServiceCard({
<Indicator color={serverActivated ? 'green' : 'yellow'} />
<div className={`${serverActivated ? 'text-text-success' : 'text-text-warning'} system-xs-semibold-uppercase`}>
{serverActivated
? t('appOverview.overview.status.running')
: t('appOverview.overview.status.disable')}
? t('overview.status.running', { ns: 'appOverview' })
: t('overview.status.disable', { ns: 'appOverview' })}
</div>
</div>
<Tooltip
@ -190,19 +190,19 @@ function MCPServiceCard({
? (
appUnpublished
? (
t('tools.mcp.server.publishTip')
t('mcp.server.publishTip', { ns: 'tools' })
)
: missingStartNode
? (
<>
<div className="mb-1 text-xs font-normal text-text-secondary">
{t('appOverview.overview.appInfo.enableTooltip.description')}
{t('overview.appInfo.enableTooltip.description', { ns: 'appOverview' })}
</div>
<div
className="cursor-pointer text-xs font-normal text-text-accent hover:underline"
onClick={() => window.open(docLink('/guides/workflow/node/user-input'), '_blank')}
>
{t('appOverview.overview.appInfo.enableTooltip.learnMore')}
{t('overview.appInfo.enableTooltip.learnMore', { ns: 'appOverview' })}
</div>
</>
)
@ -222,7 +222,7 @@ function MCPServiceCard({
{!isMinimalState && (
<div className="flex flex-col items-start justify-center self-stretch">
<div className="system-xs-medium pb-1 text-text-tertiary">
{t('tools.mcp.server.url')}
{t('mcp.server.url', { ns: 'tools' })}
</div>
<div className="inline-flex h-9 w-full items-center gap-0.5 rounded-lg bg-components-input-bg-normal p-1 pl-2">
<div className="flex h-4 min-w-0 flex-1 items-start justify-start gap-2 px-1">
@ -239,7 +239,7 @@ function MCPServiceCard({
<Divider type="vertical" className="!mx-0.5 !h-3.5 shrink-0" />
{isCurrentWorkspaceManager && (
<Tooltip
popupContent={t('appOverview.overview.appInfo.regenerate') || ''}
popupContent={t('overview.appInfo.regenerate', { ns: 'appOverview' }) || ''}
>
<div
className="cursor-pointer rounded-md p-1 hover:bg-state-base-hover"
@ -266,7 +266,7 @@ function MCPServiceCard({
<div className="flex items-center justify-center gap-[1px]">
<RiEditLine className="h-3.5 w-3.5" />
<div className="system-xs-medium px-[3px] text-text-tertiary">{serverPublished ? t('tools.mcp.server.edit') : t('tools.mcp.server.addDescription')}</div>
<div className="system-xs-medium px-[3px] text-text-tertiary">{serverPublished ? t('mcp.server.edit', { ns: 'tools' }) : t('mcp.server.addDescription', { ns: 'tools' })}</div>
</div>
</Button>
</div>
@ -287,8 +287,8 @@ function MCPServiceCard({
{showConfirmDelete && (
<Confirm
type="warning"
title={t('appOverview.overview.appInfo.regenerate')}
content={t('tools.mcp.server.reGen')}
title={t('overview.appInfo.regenerate', { ns: 'appOverview' })}
content={t('mcp.server.reGen', { ns: 'tools' })}
isShow={showConfirmDelete}
onConfirm={() => {
onGenCode()

View File

@ -81,15 +81,15 @@ const MCPModal = ({
const authMethods = [
{
text: t('tools.mcp.modal.authentication'),
text: t('mcp.modal.authentication', { ns: 'tools' }),
value: MCPAuthMethod.authentication,
},
{
text: t('tools.mcp.modal.headers'),
text: t('mcp.modal.headers', { ns: 'tools' }),
value: MCPAuthMethod.headers,
},
{
text: t('tools.mcp.modal.configurations'),
text: t('mcp.modal.configurations', { ns: 'tools' }),
value: MCPAuthMethod.configurations,
},
]
@ -231,33 +231,33 @@ const MCPModal = ({
<div className="absolute right-5 top-5 z-10 cursor-pointer p-1.5" onClick={onHide}>
<RiCloseLine className="h-5 w-5 text-text-tertiary" />
</div>
<div className="title-2xl-semi-bold relative pb-3 text-xl text-text-primary">{!isCreate ? t('tools.mcp.modal.editTitle') : t('tools.mcp.modal.title')}</div>
<div className="title-2xl-semi-bold relative pb-3 text-xl text-text-primary">{!isCreate ? t('mcp.modal.editTitle', { ns: 'tools' }) : t('mcp.modal.title', { ns: 'tools' })}</div>
<div className="space-y-5 py-3">
<div>
<div className="mb-1 flex h-6 items-center">
<span className="system-sm-medium text-text-secondary">{t('tools.mcp.modal.serverUrl')}</span>
<span className="system-sm-medium text-text-secondary">{t('mcp.modal.serverUrl', { ns: 'tools' })}</span>
</div>
<Input
value={url}
onChange={e => setUrl(e.target.value)}
onBlur={e => handleBlur(e.target.value.trim())}
placeholder={t('tools.mcp.modal.serverUrlPlaceholder')}
placeholder={t('mcp.modal.serverUrlPlaceholder', { ns: 'tools' })}
/>
{originalServerUrl && originalServerUrl !== url && (
<div className="mt-1 flex h-5 items-center">
<span className="body-xs-regular text-text-warning">{t('tools.mcp.modal.serverUrlWarning')}</span>
<span className="body-xs-regular text-text-warning">{t('mcp.modal.serverUrlWarning', { ns: 'tools' })}</span>
</div>
)}
</div>
<div className="flex space-x-3">
<div className="grow pb-1">
<div className="mb-1 flex h-6 items-center">
<span className="system-sm-medium text-text-secondary">{t('tools.mcp.modal.name')}</span>
<span className="system-sm-medium text-text-secondary">{t('mcp.modal.name', { ns: 'tools' })}</span>
</div>
<Input
value={name}
onChange={e => setName(e.target.value)}
placeholder={t('tools.mcp.modal.namePlaceholder')}
placeholder={t('mcp.modal.namePlaceholder', { ns: 'tools' })}
/>
</div>
<div className="pt-2" ref={appIconRef}>
@ -284,17 +284,17 @@ const MCPModal = ({
</div>
<div>
<div className="flex h-6 items-center">
<span className="system-sm-medium text-text-secondary">{t('tools.mcp.modal.serverIdentifier')}</span>
<span className="system-sm-medium text-text-secondary">{t('mcp.modal.serverIdentifier', { ns: 'tools' })}</span>
</div>
<div className="body-xs-regular mb-1 text-text-tertiary">{t('tools.mcp.modal.serverIdentifierTip')}</div>
<div className="body-xs-regular mb-1 text-text-tertiary">{t('mcp.modal.serverIdentifierTip', { ns: 'tools' })}</div>
<Input
value={serverIdentifier}
onChange={e => setServerIdentifier(e.target.value)}
placeholder={t('tools.mcp.modal.serverIdentifierPlaceholder')}
placeholder={t('mcp.modal.serverIdentifierPlaceholder', { ns: 'tools' })}
/>
{originalServerID && originalServerID !== serverIdentifier && (
<div className="mt-1 flex h-5 items-center">
<span className="body-xs-regular text-text-warning">{t('tools.mcp.modal.serverIdentifierWarning')}</span>
<span className="body-xs-regular text-text-warning">{t('mcp.modal.serverIdentifierWarning', { ns: 'tools' })}</span>
</div>
)}
</div>
@ -317,13 +317,13 @@ const MCPModal = ({
defaultValue={isDynamicRegistration}
onChange={setIsDynamicRegistration}
/>
<span className="system-sm-medium text-text-secondary">{t('tools.mcp.modal.useDynamicClientRegistration')}</span>
<span className="system-sm-medium text-text-secondary">{t('mcp.modal.useDynamicClientRegistration', { ns: 'tools' })}</span>
</div>
{!isDynamicRegistration && (
<div className="mt-2 flex gap-2 rounded-lg bg-state-warning-hover p-3">
<AlertTriangle className="mt-0.5 h-4 w-4 shrink-0 text-text-warning" />
<div className="system-xs-regular text-text-secondary">
<div className="mb-1">{t('tools.mcp.modal.redirectUrlWarning')}</div>
<div className="mb-1">{t('mcp.modal.redirectUrlWarning', { ns: 'tools' })}</div>
<code className="system-xs-medium block break-all rounded bg-state-warning-active px-2 py-1 text-text-secondary">
{`${API_PREFIX}/mcp/oauth/callback`}
</code>
@ -333,25 +333,25 @@ const MCPModal = ({
</div>
<div>
<div className={cn('mb-1 flex h-6 items-center', isDynamicRegistration && 'opacity-50')}>
<span className="system-sm-medium text-text-secondary">{t('tools.mcp.modal.clientID')}</span>
<span className="system-sm-medium text-text-secondary">{t('mcp.modal.clientID', { ns: 'tools' })}</span>
</div>
<Input
value={clientID}
onChange={e => setClientID(e.target.value)}
onBlur={e => handleBlur(e.target.value.trim())}
placeholder={t('tools.mcp.modal.clientID')}
placeholder={t('mcp.modal.clientID', { ns: 'tools' })}
disabled={isDynamicRegistration}
/>
</div>
<div>
<div className={cn('mb-1 flex h-6 items-center', isDynamicRegistration && 'opacity-50')}>
<span className="system-sm-medium text-text-secondary">{t('tools.mcp.modal.clientSecret')}</span>
<span className="system-sm-medium text-text-secondary">{t('mcp.modal.clientSecret', { ns: 'tools' })}</span>
</div>
<Input
value={credentials}
onChange={e => setCredentials(e.target.value)}
onBlur={e => handleBlur(e.target.value.trim())}
placeholder={t('tools.mcp.modal.clientSecretPlaceholder')}
placeholder={t('mcp.modal.clientSecretPlaceholder', { ns: 'tools' })}
disabled={isDynamicRegistration}
/>
</div>
@ -362,9 +362,9 @@ const MCPModal = ({
authMethod === MCPAuthMethod.headers && (
<div>
<div className="mb-1 flex h-6 items-center">
<span className="system-sm-medium text-text-secondary">{t('tools.mcp.modal.headers')}</span>
<span className="system-sm-medium text-text-secondary">{t('mcp.modal.headers', { ns: 'tools' })}</span>
</div>
<div className="body-xs-regular mb-2 text-text-tertiary">{t('tools.mcp.modal.headersTip')}</div>
<div className="body-xs-regular mb-2 text-text-tertiary">{t('mcp.modal.headersTip', { ns: 'tools' })}</div>
<HeadersInput
headersItems={headers}
onChange={setHeaders}
@ -379,26 +379,26 @@ const MCPModal = ({
<>
<div>
<div className="mb-1 flex h-6 items-center">
<span className="system-sm-medium text-text-secondary">{t('tools.mcp.modal.timeout')}</span>
<span className="system-sm-medium text-text-secondary">{t('mcp.modal.timeout', { ns: 'tools' })}</span>
</div>
<Input
type="number"
value={timeout}
onChange={e => setMcpTimeout(Number(e.target.value))}
onBlur={e => handleBlur(e.target.value.trim())}
placeholder={t('tools.mcp.modal.timeoutPlaceholder')}
placeholder={t('mcp.modal.timeoutPlaceholder', { ns: 'tools' })}
/>
</div>
<div>
<div className="mb-1 flex h-6 items-center">
<span className="system-sm-medium text-text-secondary">{t('tools.mcp.modal.sseReadTimeout')}</span>
<span className="system-sm-medium text-text-secondary">{t('mcp.modal.sseReadTimeout', { ns: 'tools' })}</span>
</div>
<Input
type="number"
value={sseReadTimeout}
onChange={e => setSseReadTimeout(Number(e.target.value))}
onBlur={e => handleBlur(e.target.value.trim())}
placeholder={t('tools.mcp.modal.timeoutPlaceholder')}
placeholder={t('mcp.modal.timeoutPlaceholder', { ns: 'tools' })}
/>
</div>
</>
@ -406,8 +406,8 @@ const MCPModal = ({
}
</div>
<div className="flex flex-row-reverse pt-5">
<Button disabled={!name || !url || !serverIdentifier || isFetchingIcon} className="ml-2" variant="primary" onClick={submit}>{data ? t('tools.mcp.modal.save') : t('tools.mcp.modal.confirm')}</Button>
<Button onClick={onHide}>{t('tools.mcp.modal.cancel')}</Button>
<Button disabled={!name || !url || !serverIdentifier || isFetchingIcon} className="ml-2" variant="primary" onClick={submit}>{data ? t('mcp.modal.save', { ns: 'tools' }) : t('mcp.modal.confirm', { ns: 'tools' })}</Button>
<Button onClick={onHide}>{t('mcp.modal.cancel', { ns: 'tools' })}</Button>
</div>
</Modal>
{showAppIconPicker && (

View File

@ -96,19 +96,19 @@ const MCPCard = ({
<div className="flex items-center gap-1">
<RiHammerFill className="h-3 w-3 shrink-0 text-text-quaternary" />
{data.tools.length > 0 && (
<div className="system-xs-regular shrink-0 text-text-tertiary">{t('tools.mcp.toolsCount', { count: data.tools.length })}</div>
<div className="system-xs-regular shrink-0 text-text-tertiary">{t('mcp.toolsCount', { ns: 'tools', count: data.tools.length })}</div>
)}
{!data.tools.length && (
<div className="system-xs-regular shrink-0 text-text-tertiary">{t('tools.mcp.noTools')}</div>
<div className="system-xs-regular shrink-0 text-text-tertiary">{t('mcp.noTools', { ns: 'tools' })}</div>
)}
</div>
<div className={cn('system-xs-regular text-divider-deep', (!data.is_team_authorization || !data.tools.length) && 'sm:hidden')}>/</div>
<div className={cn('system-xs-regular truncate text-text-tertiary', (!data.is_team_authorization || !data.tools.length) && ' sm:hidden')} title={`${t('tools.mcp.updateTime')} ${formatTimeFromNow(data.updated_at! * 1000)}`}>{`${t('tools.mcp.updateTime')} ${formatTimeFromNow(data.updated_at! * 1000)}`}</div>
<div className={cn('system-xs-regular truncate text-text-tertiary', (!data.is_team_authorization || !data.tools.length) && ' sm:hidden')} title={`${t('mcp.updateTime', { ns: 'tools' })} ${formatTimeFromNow(data.updated_at! * 1000)}`}>{`${t('mcp.updateTime', { ns: 'tools' })} ${formatTimeFromNow(data.updated_at! * 1000)}`}</div>
</div>
{data.is_team_authorization && data.tools.length > 0 && <Indicator color="green" className="shrink-0" />}
{(!data.is_team_authorization || !data.tools.length) && (
<div className="system-xs-medium flex shrink-0 items-center gap-1 rounded-md border border-util-colors-red-red-500 bg-components-badge-bg-red-soft px-1.5 py-0.5 text-util-colors-red-red-500">
{t('tools.mcp.noConfigured')}
{t('mcp.noConfigured', { ns: 'tools' })}
<Indicator color="red" />
</div>
)}
@ -134,10 +134,10 @@ const MCPCard = ({
{isShowDeleteConfirm && (
<Confirm
isShow
title={t('tools.mcp.delete')}
title={t('mcp.delete', { ns: 'tools' })}
content={(
<div>
{t('tools.mcp.deleteConfirmTitle', { mcp: data.name })}
{t('mcp.deleteConfirmTitle', { ns: 'tools', mcp: data.name })}
</div>
)}
onCancel={hideDeleteConfirm}

View File

@ -49,9 +49,9 @@ const ProviderList = () => {
defaultValue: 'builtin',
})
const options = [
{ value: 'builtin', text: t('tools.type.builtIn') },
{ value: 'api', text: t('tools.type.custom') },
{ value: 'workflow', text: t('tools.type.workflow') },
{ value: 'builtin', text: t('type.builtIn', { ns: 'tools' }) },
{ value: 'api', text: t('type.custom', { ns: 'tools' }) },
{ value: 'workflow', text: t('type.workflow', { ns: 'tools' }) },
{ value: 'mcp', text: 'MCP' },
]
const [tagFilterValue, setTagFilterValue] = useState<string[]>([])
@ -194,7 +194,7 @@ const ProviderList = () => {
</div>
)}
{!filteredCollectionList.length && activeTab === 'builtin' && (
<Empty lightCard text={t('tools.noTools')} className="h-[224px] shrink-0 px-12" />
<Empty lightCard text={t('noTools', { ns: 'tools' })} className="h-[224px] shrink-0 px-12" />
)}
<div ref={toolListTailRef} />
{enable_marketplace && activeTab === 'builtin' && (

View File

@ -37,7 +37,7 @@ const Contribute = ({ onRefreshData }: Props) => {
await createCustomCollection(data)
Toast.notify({
type: 'success',
message: t('common.api.actionSuccess'),
message: t('api.actionSuccess', { ns: 'common' }),
})
setIsShowEditCustomCollectionModal(false)
onRefreshData()
@ -52,13 +52,13 @@ const Contribute = ({ onRefreshData }: Props) => {
<div className="flex h-10 w-10 items-center justify-center rounded-lg border border-dashed border-divider-deep group-hover:border-solid group-hover:border-state-accent-hover-alt group-hover:bg-state-accent-hover">
<RiAddCircleFill className="h-4 w-4 text-text-quaternary group-hover:text-text-accent" />
</div>
<div className="system-md-semibold ml-3 text-text-secondary group-hover:text-text-accent">{t('tools.createCustomTool')}</div>
<div className="system-md-semibold ml-3 text-text-secondary group-hover:text-text-accent">{t('createCustomTool', { ns: 'tools' })}</div>
</div>
</div>
<div className="rounded-b-xl border-t-[0.5px] border-divider-subtle px-4 py-3 text-text-tertiary hover:text-text-accent">
<a href={linkUrl} target="_blank" rel="noopener noreferrer" className="flex items-center space-x-1">
<RiBookOpenLine className="h-3 w-3 shrink-0" />
<div className="system-xs-regular grow truncate" title={t('tools.customToolTip') || ''}>{t('tools.customToolTip')}</div>
<div className="system-xs-regular grow truncate" title={t('customToolTip', { ns: 'tools' }) || ''}>{t('customToolTip', { ns: 'tools' })}</div>
<RiArrowRightUpLine className="h-3 w-3 shrink-0" />
</a>
</div>

View File

@ -124,7 +124,7 @@ const ProviderDetail = ({
setCustomCollection(prev => prev ? { ...prev, labels: data.labels } : null)
Toast.notify({
type: 'success',
message: t('common.api.actionSuccess'),
message: t('api.actionSuccess', { ns: 'common' }),
})
setIsShowEditCustomCollectionModal(false)
}
@ -133,7 +133,7 @@ const ProviderDetail = ({
onRefreshData()
Toast.notify({
type: 'success',
message: t('common.api.actionSuccess'),
message: t('api.actionSuccess', { ns: 'common' }),
})
setIsShowEditCustomCollectionModal(false)
}
@ -163,7 +163,7 @@ const ProviderDetail = ({
onRefreshData()
Toast.notify({
type: 'success',
message: t('common.api.actionSuccess'),
message: t('api.actionSuccess', { ns: 'common' }),
})
setIsShowEditWorkflowToolModal(false)
}
@ -177,7 +177,7 @@ const ProviderDetail = ({
getWorkflowToolProvider()
Toast.notify({
type: 'success',
message: t('common.api.actionSuccess'),
message: t('api.actionSuccess', { ns: 'common' }),
})
setIsShowEditWorkflowToolModal(false)
}
@ -275,7 +275,7 @@ const ProviderDetail = ({
onClick={() => setIsShowEditCustomCollectionModal(true)}
>
<Settings01 className="mr-1 h-4 w-4 text-text-tertiary" />
<div className="system-sm-medium text-text-secondary">{t('tools.createTool.editAction')}</div>
<div className="system-sm-medium text-text-secondary">{t('createTool.editAction', { ns: 'tools' })}</div>
</Button>
)}
{collection.type === CollectionType.workflow && !isDetailLoading && customCollection && (
@ -285,7 +285,7 @@ const ProviderDetail = ({
className={cn('my-3 w-[183px] shrink-0')}
>
<a className="flex items-center" href={`${basePath}/app/${(customCollection as WorkflowToolProviderResponse).workflow_app_id}/workflow`} rel="noreferrer" target="_blank">
<div className="system-sm-medium">{t('tools.openInStudio')}</div>
<div className="system-sm-medium">{t('openInStudio', { ns: 'tools' })}</div>
<LinkExternal02 className="ml-1 h-4 w-4" />
</a>
</Button>
@ -294,7 +294,7 @@ const ProviderDetail = ({
onClick={() => setIsShowEditWorkflowToolModal(true)}
disabled={!isCurrentWorkspaceManager}
>
<div className="system-sm-medium text-text-secondary">{t('tools.createTool.editAction')}</div>
<div className="system-sm-medium text-text-secondary">{t('createTool.editAction', { ns: 'tools' })}</div>
</Button>
</>
)}
@ -306,7 +306,7 @@ const ProviderDetail = ({
<div className="shrink-0">
{(collection.type === CollectionType.builtIn || collection.type === CollectionType.model) && isAuthed && (
<div className="system-sm-semibold-uppercase mb-1 flex h-6 items-center justify-between text-text-secondary">
{t('plugin.detailPanel.actionNum', { num: toolList.length, action: toolList.length > 1 ? 'actions' : 'action' })}
{t('detailPanel.actionNum', { ns: 'plugin', num: toolList.length, action: toolList.length > 1 ? 'actions' : 'action' })}
{needAuth && (
<Button
variant="secondary"
@ -318,7 +318,7 @@ const ProviderDetail = ({
disabled={!isCurrentWorkspaceManager}
>
<Indicator className="mr-2" color="green" />
{t('tools.auth.authorized')}
{t('auth.authorized', { ns: 'tools' })}
</Button>
)}
</div>
@ -326,9 +326,9 @@ const ProviderDetail = ({
{(collection.type === CollectionType.builtIn || collection.type === CollectionType.model) && needAuth && !isAuthed && (
<>
<div className="system-sm-semibold-uppercase text-text-secondary">
<span className="">{t('tools.includeToolNum', { num: toolList.length, action: toolList.length > 1 ? 'actions' : 'action' }).toLocaleUpperCase()}</span>
<span className="">{t('includeToolNum', { ns: 'tools', num: toolList.length, action: toolList.length > 1 ? 'actions' : 'action' }).toLocaleUpperCase()}</span>
<span className="px-1">·</span>
<span className="text-util-colors-orange-orange-600">{t('tools.auth.setup').toLocaleUpperCase()}</span>
<span className="text-util-colors-orange-orange-600">{t('auth.setup', { ns: 'tools' }).toLocaleUpperCase()}</span>
</div>
<Button
variant="primary"
@ -339,18 +339,18 @@ const ProviderDetail = ({
}}
disabled={!isCurrentWorkspaceManager}
>
{t('tools.auth.unauthorized')}
{t('auth.unauthorized', { ns: 'tools' })}
</Button>
</>
)}
{(collection.type === CollectionType.custom) && (
<div className="system-sm-semibold-uppercase text-text-secondary">
<span className="">{t('tools.includeToolNum', { num: toolList.length, action: toolList.length > 1 ? 'actions' : 'action' }).toLocaleUpperCase()}</span>
<span className="">{t('includeToolNum', { ns: 'tools', num: toolList.length, action: toolList.length > 1 ? 'actions' : 'action' }).toLocaleUpperCase()}</span>
</div>
)}
{(collection.type === CollectionType.workflow) && (
<div className="system-sm-semibold-uppercase text-text-secondary">
<span className="">{t('tools.createTool.toolInput.title').toLocaleUpperCase()}</span>
<span className="">{t('createTool.toolInput.title', { ns: 'tools' }).toLocaleUpperCase()}</span>
</div>
)}
</div>
@ -370,7 +370,7 @@ const ProviderDetail = ({
<div className="mb-1 flex items-center gap-2">
<span className="code-sm-semibold text-text-secondary">{item.name}</span>
<span className="system-xs-regular text-text-tertiary">{item.type}</span>
<span className="system-xs-medium text-text-warning-secondary">{item.required ? t('tools.createTool.toolInput.required') : ''}</span>
<span className="system-xs-medium text-text-warning-secondary">{item.required ? t('createTool.toolInput.required', { ns: 'tools' }) : ''}</span>
</div>
<div className="system-xs-regular text-text-tertiary">{item.llm_description}</div>
</div>
@ -387,7 +387,7 @@ const ProviderDetail = ({
await updateBuiltInToolCredential(collection.name, value)
Toast.notify({
type: 'success',
message: t('common.api.actionSuccess'),
message: t('api.actionSuccess', { ns: 'common' }),
})
await onRefreshData()
setShowSettingAuth(false)
@ -396,7 +396,7 @@ const ProviderDetail = ({
await removeBuiltInToolCredential(collection.name)
Toast.notify({
type: 'success',
message: t('common.api.actionSuccess'),
message: t('api.actionSuccess', { ns: 'common' }),
})
await onRefreshData()
setShowSettingAuth(false)
@ -421,8 +421,8 @@ const ProviderDetail = ({
)}
{showConfirmDelete && (
<Confirm
title={t('tools.createTool.deleteToolConfirmTitle')}
content={t('tools.createTool.deleteToolConfirmContent')}
title={t('createTool.deleteToolConfirmTitle', { ns: 'tools' })}
content={t('createTool.deleteToolConfirmContent', { ns: 'tools' })}
isShow={showConfirmDelete}
onConfirm={handleConfirmDelete}
onCancel={() => setShowConfirmDelete(false)}

View File

@ -32,18 +32,18 @@ const Empty = ({
const hasLink = type && [ToolTypeEnum.Custom, ToolTypeEnum.MCP].includes(type)
const Comp = (hasLink ? Link : 'div') as any
const linkProps = hasLink ? { href: getLink(type), target: '_blank' } : {}
const renderType = isAgent ? 'agent' : type
const hasTitle = t(`tools.addToolModal.${renderType}.title` as any) as string !== `tools.addToolModal.${renderType}.title`
const renderType = isAgent ? 'agent' as const : type
const hasTitle = renderType && t(`addToolModal.${renderType}.title`, { ns: 'tools' }) !== `addToolModal.${renderType}.title`
return (
<div className="flex flex-col items-center justify-center">
<NoToolPlaceholder className={theme === 'dark' ? 'invert' : ''} />
<div className="mb-1 mt-2 text-[13px] font-medium leading-[18px] text-text-primary">
{hasTitle ? t(`tools.addToolModal.${renderType}.title` as any) as string : 'No tools available'}
{(hasTitle && renderType) ? t(`addToolModal.${renderType}.title`, { ns: 'tools' }) : 'No tools available'}
</div>
{(!isAgent && hasTitle) && (
{(!isAgent && hasTitle && renderType) && (
<Comp className={cn('flex items-center text-[13px] leading-[18px] text-text-tertiary', hasLink && 'cursor-pointer hover:text-text-accent')} {...linkProps}>
{t(`tools.addToolModal.${renderType}.tip` as any) as string}
{t(`addToolModal.${renderType}.tip`, { ns: 'tools' })}
{' '}
{hasLink && <RiArrowRightUpLine className="ml-0.5 h-3 w-3" />}
</Comp>

View File

@ -53,7 +53,7 @@ const ConfigCredential: FC<Props> = ({
const handleSave = async () => {
for (const field of credentialSchema) {
if (field.required && !tempCredential[field.name]) {
Toast.notify({ type: 'error', message: t('common.errorMsg.fieldRequired', { field: field.label[language] || field.label.en_US }) })
Toast.notify({ type: 'error', message: t('errorMsg.fieldRequired', { ns: 'common', field: field.label[language] || field.label.en_US }) })
return
}
}
@ -71,8 +71,8 @@ const ConfigCredential: FC<Props> = ({
<Drawer
isShow
onHide={onCancel}
title={t('tools.auth.setupModalTitle') as string}
titleDescription={t('tools.auth.setupModalTitleDescription') as string}
title={t('auth.setupModalTitle', { ns: 'tools' }) as string}
titleDescription={t('auth.setupModalTitleDescription', { ns: 'tools' }) as string}
panelClassName="mt-[64px] mb-2 !w-[420px] border-components-panel-border"
maxWidthClassName="!max-w-[420px]"
height="calc(100vh - 64px)"
@ -102,7 +102,7 @@ const ConfigCredential: FC<Props> = ({
rel="noopener noreferrer"
className="inline-flex items-center text-xs text-text-accent"
>
{t('tools.howToGet')}
{t('howToGet', { ns: 'tools' })}
<LinkExternal02 className="ml-1 h-3 w-3" />
</a>
)
@ -111,12 +111,12 @@ const ConfigCredential: FC<Props> = ({
<div className={cn((collection.is_team_authorization && !isHideRemoveBtn) ? 'justify-between' : 'justify-end', 'mt-2 flex ')}>
{
(collection.is_team_authorization && !isHideRemoveBtn) && (
<Button onClick={onRemove}>{t('common.operation.remove')}</Button>
<Button onClick={onRemove}>{t('operation.remove', { ns: 'common' })}</Button>
)
}
<div className="flex space-x-2">
<Button onClick={onCancel}>{t('common.operation.cancel')}</Button>
<Button loading={isLoading || isSaving} disabled={isLoading || isSaving} variant="primary" onClick={handleSave}>{t('common.operation.save')}</Button>
<Button onClick={onCancel}>{t('operation.cancel', { ns: 'common' })}</Button>
<Button loading={isLoading || isSaving} disabled={isLoading || isSaving} variant="primary" onClick={handleSave}>{t('operation.save', { ns: 'common' })}</Button>
</div>
</div>
</>

View File

@ -166,7 +166,7 @@ const WorkflowToolConfigureButton = ({
getDetail(workflowAppId)
Toast.notify({
type: 'success',
message: t('common.api.actionSuccess'),
message: t('api.actionSuccess', { ns: 'common' }),
})
setShowModal(false)
}
@ -187,7 +187,7 @@ const WorkflowToolConfigureButton = ({
getDetail(workflowAppId)
Toast.notify({
type: 'success',
message: t('common.api.actionSuccess'),
message: t('api.actionSuccess', { ns: 'common' }),
})
setShowModal(false)
}
@ -214,14 +214,14 @@ const WorkflowToolConfigureButton = ({
>
<RiHammerLine className={cn('relative h-4 w-4 text-text-secondary', !disabled && !published && 'group-hover:text-text-accent')} />
<div
title={t('workflow.common.workflowAsTool') || ''}
title={t('common.workflowAsTool', { ns: 'workflow' }) || ''}
className={cn('system-sm-medium shrink grow basis-0 truncate text-text-secondary', !disabled && !published && 'group-hover:text-text-accent')}
>
{t('workflow.common.workflowAsTool')}
{t('common.workflowAsTool', { ns: 'workflow' })}
</div>
{!published && (
<span className="system-2xs-medium-uppercase shrink-0 rounded-[5px] border border-divider-deep bg-components-badge-bg-dimm px-1 py-0.5 text-text-tertiary">
{t('workflow.common.configureRequired')}
{t('common.configureRequired', { ns: 'workflow' })}
</span>
)}
</div>
@ -232,10 +232,10 @@ const WorkflowToolConfigureButton = ({
>
<RiHammerLine className="h-4 w-4 text-text-tertiary" />
<div
title={t('workflow.common.workflowAsTool') || ''}
title={t('common.workflowAsTool', { ns: 'workflow' }) || ''}
className="system-sm-medium shrink grow basis-0 truncate text-text-tertiary"
>
{t('workflow.common.workflowAsTool')}
{t('common.workflowAsTool', { ns: 'workflow' })}
</div>
</div>
)}
@ -253,7 +253,7 @@ const WorkflowToolConfigureButton = ({
onClick={() => setShowModal(true)}
disabled={!isCurrentWorkspaceManager || disabled}
>
{t('workflow.common.configure')}
{t('common.configure', { ns: 'workflow' })}
{outdated && <Indicator className="ml-1" color="yellow" />}
</Button>
<Button
@ -262,13 +262,13 @@ const WorkflowToolConfigureButton = ({
onClick={() => router.push('/tools?category=workflow')}
disabled={disabled}
>
{t('workflow.common.manageInTools')}
{t('common.manageInTools', { ns: 'workflow' })}
<RiArrowRightUpLine className="ml-1 h-4 w-4" />
</Button>
</div>
{outdated && (
<div className="mt-1 text-xs leading-[18px] text-text-warning">
{t('workflow.common.workflowAsToolTip')}
{t('common.workflowAsToolTip', { ns: 'workflow' })}
</div>
)}
</div>

View File

@ -29,14 +29,14 @@ const ConfirmModal = ({ show, onConfirm, onClose }: ConfirmModalProps) => {
<div className="h-12 w-12 rounded-xl border-[0.5px] border-divider-regular bg-background-section p-3 shadow-xl">
<AlertTriangle className="h-6 w-6 text-[rgb(247,144,9)]" />
</div>
<div className="relative mt-3 text-xl font-semibold leading-[30px] text-text-primary">{t('tools.createTool.confirmTitle')}</div>
<div className="relative mt-3 text-xl font-semibold leading-[30px] text-text-primary">{t('createTool.confirmTitle', { ns: 'tools' })}</div>
<div className="my-1 text-sm leading-5 text-text-tertiary">
{t('tools.createTool.confirmTip')}
{t('createTool.confirmTip', { ns: 'tools' })}
</div>
<div className="flex items-center justify-end pt-6">
<div className="flex items-center">
<Button className="mr-2" onClick={onClose}>{t('common.operation.cancel')}</Button>
<Button variant="warning" onClick={onConfirm}>{t('common.operation.confirm')}</Button>
<Button className="mr-2" onClick={onClose}>{t('operation.cancel', { ns: 'common' })}</Button>
<Button variant="warning" onClick={onConfirm}>{t('operation.confirm', { ns: 'common' })}</Button>
</div>
</div>
</Modal>

View File

@ -55,19 +55,19 @@ const WorkflowToolAsModal: FC<Props> = ({
const reservedOutputParameters: WorkflowToolProviderOutputParameter[] = [
{
name: 'text',
description: t('workflow.nodes.tool.outputVars.text'),
description: t('nodes.tool.outputVars.text', { ns: 'workflow' }),
type: VarType.string,
reserved: true,
},
{
name: 'files',
description: t('workflow.nodes.tool.outputVars.files.title'),
description: t('nodes.tool.outputVars.files.title', { ns: 'workflow' }),
type: VarType.arrayFile,
reserved: true,
},
{
name: 'json',
description: t('workflow.nodes.tool.outputVars.json'),
description: t('nodes.tool.outputVars.json', { ns: 'workflow' }),
type: VarType.arrayObject,
reserved: true,
},
@ -104,13 +104,13 @@ const WorkflowToolAsModal: FC<Props> = ({
const onConfirm = () => {
let errorMessage = ''
if (!label)
errorMessage = t('common.errorMsg.fieldRequired', { field: t('tools.createTool.name') })
errorMessage = t('errorMsg.fieldRequired', { ns: 'common', field: t('createTool.name', { ns: 'tools' }) })
if (!name)
errorMessage = t('common.errorMsg.fieldRequired', { field: t('tools.createTool.nameForToolCall') })
errorMessage = t('errorMsg.fieldRequired', { ns: 'common', field: t('createTool.nameForToolCall', { ns: 'tools' }) })
if (!isNameValid(name))
errorMessage = t('tools.createTool.nameForToolCall') + t('tools.createTool.nameForToolCallTip')
errorMessage = t('createTool.nameForToolCall', { ns: 'tools' }) + t('createTool.nameForToolCallTip', { ns: 'tools' })
if (errorMessage) {
Toast.notify({
@ -152,7 +152,7 @@ const WorkflowToolAsModal: FC<Props> = ({
<Drawer
isShow
onHide={onHide}
title={t('workflow.common.workflowAsTool')!}
title={t('common.workflowAsTool', { ns: 'workflow' })!}
panelClassName="mt-2 !w-[640px]"
maxWidthClassName="!max-w-[640px]"
height="calc(100vh - 16px)"
@ -163,7 +163,7 @@ const WorkflowToolAsModal: FC<Props> = ({
{/* name & icon */}
<div>
<div className="system-sm-medium py-2 text-text-primary">
{t('tools.createTool.name')}
{t('createTool.name', { ns: 'tools' })}
{' '}
<span className="ml-1 text-red-500">*</span>
</div>
@ -171,7 +171,7 @@ const WorkflowToolAsModal: FC<Props> = ({
<AppIcon size="large" onClick={() => { setShowEmojiPicker(true) }} className="cursor-pointer" iconType="emoji" icon={emoji.content} background={emoji.background} />
<Input
className="h-10 grow"
placeholder={t('tools.createTool.toolNamePlaceHolder')!}
placeholder={t('createTool.toolNamePlaceHolder', { ns: 'tools' })!}
value={label}
onChange={e => setLabel(e.target.value)}
/>
@ -180,46 +180,46 @@ const WorkflowToolAsModal: FC<Props> = ({
{/* name for tool call */}
<div>
<div className="system-sm-medium flex items-center py-2 text-text-primary">
{t('tools.createTool.nameForToolCall')}
{t('createTool.nameForToolCall', { ns: 'tools' })}
{' '}
<span className="ml-1 text-red-500">*</span>
<Tooltip
popupContent={(
<div className="w-[180px]">
{t('tools.createTool.nameForToolCallPlaceHolder')}
{t('createTool.nameForToolCallPlaceHolder', { ns: 'tools' })}
</div>
)}
/>
</div>
<Input
className="h-10"
placeholder={t('tools.createTool.nameForToolCallPlaceHolder')!}
placeholder={t('createTool.nameForToolCallPlaceHolder', { ns: 'tools' })!}
value={name}
onChange={e => setName(e.target.value)}
/>
{!isNameValid(name) && (
<div className="text-xs leading-[18px] text-red-500">{t('tools.createTool.nameForToolCallTip')}</div>
<div className="text-xs leading-[18px] text-red-500">{t('createTool.nameForToolCallTip', { ns: 'tools' })}</div>
)}
</div>
{/* description */}
<div>
<div className="system-sm-medium py-2 text-text-primary">{t('tools.createTool.description')}</div>
<div className="system-sm-medium py-2 text-text-primary">{t('createTool.description', { ns: 'tools' })}</div>
<Textarea
placeholder={t('tools.createTool.descriptionPlaceholder') || ''}
placeholder={t('createTool.descriptionPlaceholder', { ns: 'tools' }) || ''}
value={description}
onChange={e => setDescription(e.target.value)}
/>
</div>
{/* Tool Input */}
<div>
<div className="system-sm-medium py-2 text-text-primary">{t('tools.createTool.toolInput.title')}</div>
<div className="system-sm-medium py-2 text-text-primary">{t('createTool.toolInput.title', { ns: 'tools' })}</div>
<div className="w-full overflow-x-auto rounded-lg border border-divider-regular">
<table className="w-full text-xs font-normal leading-[18px] text-text-secondary">
<thead className="uppercase text-text-tertiary">
<tr className="border-b border-divider-regular">
<th className="w-[156px] p-2 pl-3 font-medium">{t('tools.createTool.toolInput.name')}</th>
<th className="w-[102px] p-2 pl-3 font-medium">{t('tools.createTool.toolInput.method')}</th>
<th className="p-2 pl-3 font-medium">{t('tools.createTool.toolInput.description')}</th>
<th className="w-[156px] p-2 pl-3 font-medium">{t('createTool.toolInput.name', { ns: 'tools' })}</th>
<th className="w-[102px] p-2 pl-3 font-medium">{t('createTool.toolInput.method', { ns: 'tools' })}</th>
<th className="p-2 pl-3 font-medium">{t('createTool.toolInput.description', { ns: 'tools' })}</th>
</tr>
</thead>
<tbody>
@ -229,7 +229,7 @@ const WorkflowToolAsModal: FC<Props> = ({
<div className="text-[13px] leading-[18px]">
<div title={item.name} className="flex">
<span className="truncate font-medium text-text-primary">{item.name}</span>
<span className="shrink-0 pl-1 text-xs leading-[18px] text-[#ec4a0a]">{item.required ? t('tools.createTool.toolInput.required') : ''}</span>
<span className="shrink-0 pl-1 text-xs leading-[18px] text-[#ec4a0a]">{item.required ? t('createTool.toolInput.required', { ns: 'tools' }) : ''}</span>
</div>
<div className="text-text-tertiary">{item.type}</div>
</div>
@ -241,7 +241,7 @@ const WorkflowToolAsModal: FC<Props> = ({
)}
>
<div className={cn('grow truncate text-[13px] leading-[18px] text-text-secondary')}>
{t('tools.createTool.toolInput.methodParameter')}
{t('createTool.toolInput.methodParameter', { ns: 'tools' })}
</div>
</div>
)}
@ -253,7 +253,7 @@ const WorkflowToolAsModal: FC<Props> = ({
<input
type="text"
className="w-full appearance-none bg-transparent text-[13px] font-normal leading-[18px] text-text-secondary caret-primary-600 outline-none placeholder:text-text-quaternary"
placeholder={t('tools.createTool.toolInput.descriptionPlaceholder')!}
placeholder={t('createTool.toolInput.descriptionPlaceholder', { ns: 'tools' })!}
value={item.description}
onChange={e => handleParameterChange('description', e.target.value, index)}
/>
@ -266,13 +266,13 @@ const WorkflowToolAsModal: FC<Props> = ({
</div>
{/* Tool Output */}
<div>
<div className="system-sm-medium py-2 text-text-primary">{t('tools.createTool.toolOutput.title')}</div>
<div className="system-sm-medium py-2 text-text-primary">{t('createTool.toolOutput.title', { ns: 'tools' })}</div>
<div className="w-full overflow-x-auto rounded-lg border border-divider-regular">
<table className="w-full text-xs font-normal leading-[18px] text-text-secondary">
<thead className="uppercase text-text-tertiary">
<tr className="border-b border-divider-regular">
<th className="w-[156px] p-2 pl-3 font-medium">{t('tools.createTool.name')}</th>
<th className="p-2 pl-3 font-medium">{t('tools.createTool.toolOutput.description')}</th>
<th className="w-[156px] p-2 pl-3 font-medium">{t('createTool.name', { ns: 'tools' })}</th>
<th className="p-2 pl-3 font-medium">{t('createTool.toolOutput.description', { ns: 'tools' })}</th>
</tr>
</thead>
<tbody>
@ -282,14 +282,14 @@ const WorkflowToolAsModal: FC<Props> = ({
<div className="text-[13px] leading-[18px]">
<div title={item.name} className="flex items-center">
<span className="truncate font-medium text-text-primary">{item.name}</span>
<span className="shrink-0 pl-1 text-xs leading-[18px] text-[#ec4a0a]">{item.reserved ? t('tools.createTool.toolOutput.reserved') : ''}</span>
<span className="shrink-0 pl-1 text-xs leading-[18px] text-[#ec4a0a]">{item.reserved ? t('createTool.toolOutput.reserved', { ns: 'tools' }) : ''}</span>
{
!item.reserved && isOutputParameterReserved(item.name)
? (
<Tooltip
popupContent={(
<div className="w-[180px]">
{t('tools.createTool.toolOutput.reservedParameterDuplicateTip')}
{t('createTool.toolOutput.reservedParameterDuplicateTip', { ns: 'tools' })}
</div>
)}
>
@ -313,26 +313,26 @@ const WorkflowToolAsModal: FC<Props> = ({
</div>
{/* Tags */}
<div>
<div className="system-sm-medium py-2 text-text-primary">{t('tools.createTool.toolInput.label')}</div>
<div className="system-sm-medium py-2 text-text-primary">{t('createTool.toolInput.label', { ns: 'tools' })}</div>
<LabelSelector value={labels} onChange={handleLabelSelect} />
</div>
{/* Privacy Policy */}
<div>
<div className="system-sm-medium py-2 text-text-primary">{t('tools.createTool.privacyPolicy')}</div>
<div className="system-sm-medium py-2 text-text-primary">{t('createTool.privacyPolicy', { ns: 'tools' })}</div>
<Input
className="h-10"
value={privacyPolicy}
onChange={e => setPrivacyPolicy(e.target.value)}
placeholder={t('tools.createTool.privacyPolicyPlaceholder') || ''}
placeholder={t('createTool.privacyPolicyPlaceholder', { ns: 'tools' }) || ''}
/>
</div>
</div>
<div className={cn((!isAdd && onRemove) ? 'justify-between' : 'justify-end', 'mt-2 flex shrink-0 rounded-b-[10px] border-t border-divider-regular bg-background-section-burn px-6 py-4')}>
{!isAdd && onRemove && (
<Button variant="warning" onClick={onRemove}>{t('common.operation.delete')}</Button>
<Button variant="warning" onClick={onRemove}>{t('operation.delete', { ns: 'common' })}</Button>
)}
<div className="flex space-x-2 ">
<Button onClick={onHide}>{t('common.operation.cancel')}</Button>
<Button onClick={onHide}>{t('operation.cancel', { ns: 'common' })}</Button>
<Button
variant="primary"
onClick={() => {
@ -342,7 +342,7 @@ const WorkflowToolAsModal: FC<Props> = ({
setShowModal(true)
}}
>
{t('common.operation.save')}
{t('operation.save', { ns: 'common' })}
</Button>
</div>
</div>

View File

@ -39,7 +39,7 @@ const MethodSelector: FC<MethodSelectorProps> = ({
)}
>
<div className={cn('grow truncate text-[13px] leading-[18px] text-text-secondary')}>
{value === 'llm' ? t('tools.createTool.toolInput.methodParameter') : t('tools.createTool.toolInput.methodSetting')}
{value === 'llm' ? t('createTool.toolInput.methodParameter', { ns: 'tools' }) : t('createTool.toolInput.methodSetting', { ns: 'tools' })}
</div>
<div className="ml-1 shrink-0 text-text-secondary opacity-60">
<RiArrowDownSLine className="h-4 w-4" />
@ -54,18 +54,18 @@ const MethodSelector: FC<MethodSelectorProps> = ({
<div className="h-4 w-4 shrink-0">
{value === 'llm' && <Check className="h-4 w-4 shrink-0 text-text-accent" />}
</div>
<div className="text-[13px] font-medium leading-[18px] text-text-secondary">{t('tools.createTool.toolInput.methodParameter')}</div>
<div className="text-[13px] font-medium leading-[18px] text-text-secondary">{t('createTool.toolInput.methodParameter', { ns: 'tools' })}</div>
</div>
<div className="pl-5 text-[13px] leading-[18px] text-text-tertiary">{t('tools.createTool.toolInput.methodParameterTip')}</div>
<div className="pl-5 text-[13px] leading-[18px] text-text-tertiary">{t('createTool.toolInput.methodParameterTip', { ns: 'tools' })}</div>
</div>
<div className="cursor-pointer rounded-lg py-2.5 pl-3 pr-2 hover:bg-components-panel-on-panel-item-bg-hover" onClick={() => onChange('form')}>
<div className="item-center flex gap-1">
<div className="h-4 w-4 shrink-0">
{value === 'form' && <Check className="h-4 w-4 shrink-0 text-text-accent" />}
</div>
<div className="text-[13px] font-medium leading-[18px] text-text-secondary">{t('tools.createTool.toolInput.methodSetting')}</div>
<div className="text-[13px] font-medium leading-[18px] text-text-secondary">{t('createTool.toolInput.methodSetting', { ns: 'tools' })}</div>
</div>
<div className="pl-5 text-[13px] leading-[18px] text-text-tertiary">{t('tools.createTool.toolInput.methodSettingTip')}</div>
<div className="pl-5 text-[13px] leading-[18px] text-text-tertiary">{t('createTool.toolInput.methodSettingTip', { ns: 'tools' })}</div>
</div>
</div>
</div>