mirror of
https://github.com/langgenius/dify.git
synced 2026-04-24 21:05:48 +08:00
Merge remote-tracking branch 'origin/main' into feat/support-agent-sandbox
# Conflicts: # web/app/components/header/account-setting/model-provider-page/model-selector/popup-item.tsx # web/package.json
This commit is contained in:
19
.github/workflows/translate-i18n-claude.yml
vendored
19
.github/workflows/translate-i18n-claude.yml
vendored
@ -134,6 +134,9 @@ jobs:
|
||||
with:
|
||||
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
# Allow github-actions bot to trigger this workflow via repository_dispatch
|
||||
# See: https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md
|
||||
allowed_bots: 'github-actions[bot]'
|
||||
prompt: |
|
||||
You are a professional i18n synchronization engineer for the Dify project.
|
||||
Your task is to keep all language translations in sync with the English source (en-US).
|
||||
@ -285,6 +288,22 @@ jobs:
|
||||
- `${variable}` - Template literal
|
||||
- `<tag>content</tag>` - HTML tags
|
||||
- `_one`, `_other` - Pluralization suffixes (these are KEY suffixes, not values)
|
||||
|
||||
**CRITICAL: Variable names and tag names MUST stay in English - NEVER translate them**
|
||||
|
||||
✅ CORRECT examples:
|
||||
- English: "{{count}} items" → Japanese: "{{count}} 個のアイテム"
|
||||
- English: "{{name}} updated" → Korean: "{{name}} 업데이트됨"
|
||||
- English: "<email>{{email}}</email>" → Chinese: "<email>{{email}}</email>"
|
||||
- English: "<CustomLink>Marketplace</CustomLink>" → Japanese: "<CustomLink>マーケットプレイス</CustomLink>"
|
||||
|
||||
❌ WRONG examples (NEVER do this - will break the application):
|
||||
- "{{count}}" → "{{カウント}}" ❌ (variable name translated to Japanese)
|
||||
- "{{name}}" → "{{이름}}" ❌ (variable name translated to Korean)
|
||||
- "{{email}}" → "{{邮箱}}" ❌ (variable name translated to Chinese)
|
||||
- "<email>" → "<メール>" ❌ (tag name translated)
|
||||
- "<CustomLink>" → "<自定义链接>" ❌ (component name translated)
|
||||
|
||||
- Use appropriate language register (formal/informal) based on existing translations
|
||||
- Match existing translation style in each language
|
||||
- Technical terms: check existing conventions per language
|
||||
|
||||
1
web/.npmrc
Normal file
1
web/.npmrc
Normal file
@ -0,0 +1 @@
|
||||
save-exact=true
|
||||
@ -71,7 +71,7 @@ const DatasetInfo: FC<DatasetInfoProps> = ({
|
||||
</div>
|
||||
<div className="system-2xs-medium-uppercase text-text-tertiary">
|
||||
{isExternalProvider && t('externalTag', { ns: 'dataset' })}
|
||||
{!isExternalProvider && isPipelinePublished && dataset.doc_form && dataset.indexing_technique && (
|
||||
{!!(!isExternalProvider && isPipelinePublished && dataset.doc_form && dataset.indexing_technique) && (
|
||||
<div className="flex items-center gap-x-2">
|
||||
<span>{t(`chunkingMode.${DOC_FORM_TEXT[dataset.doc_form]}`, { ns: 'dataset' })}</span>
|
||||
<span>{formatIndexingTechniqueAndMethod(dataset.indexing_technique, dataset.retrieval_model_dict?.search_method)}</span>
|
||||
|
||||
@ -114,7 +114,7 @@ const DatasetSidebarDropdown = ({
|
||||
</div>
|
||||
<div className="system-2xs-medium-uppercase text-text-tertiary">
|
||||
{isExternalProvider && t('externalTag', { ns: 'dataset' })}
|
||||
{!isExternalProvider && dataset.doc_form && dataset.indexing_technique && (
|
||||
{!!(!isExternalProvider && dataset.doc_form && dataset.indexing_technique) && (
|
||||
<div className="flex items-center gap-x-2">
|
||||
<span>{t(`chunkingMode.${DOC_FORM_TEXT[dataset.doc_form]}`, { ns: 'dataset' })}</span>
|
||||
<span>{formatIndexingTechniqueAndMethod(dataset.indexing_technique, dataset.retrieval_model_dict?.search_method)}</span>
|
||||
|
||||
@ -144,7 +144,7 @@ const EditAnnotationModal: FC<Props> = ({
|
||||
<MessageCheckRemove />
|
||||
<div>{t('editModal.removeThisCache', { ns: 'appAnnotation' })}</div>
|
||||
</div>
|
||||
{createdAt && (
|
||||
{!!createdAt && (
|
||||
<div>
|
||||
{t('editModal.createdAt', { ns: 'appAnnotation' })}
|
||||
|
||||
|
||||
@ -28,16 +28,16 @@ const FeaturePanel: FC<IFeaturePanelProps> = ({
|
||||
<div className={cn('px-3 pt-2', hasHeaderBottomBorder && 'border-b border-divider-subtle')} data-testid="feature-panel-header">
|
||||
<div className="flex h-8 items-center justify-between">
|
||||
<div className="flex shrink-0 items-center space-x-1">
|
||||
{headerIcon && <div className="flex h-6 w-6 items-center justify-center">{headerIcon}</div>}
|
||||
{!!headerIcon && <div className="flex h-6 w-6 items-center justify-center">{headerIcon}</div>}
|
||||
<div className="system-sm-semibold text-text-secondary">{title}</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
{headerRight && <div>{headerRight}</div>}
|
||||
{!!headerRight && <div>{headerRight}</div>}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/* Body */}
|
||||
{children && (
|
||||
{!!children && (
|
||||
<div className={cn(!noBodySpacing && 'mt-1 px-3')} data-testid="feature-panel-body">
|
||||
{children}
|
||||
</div>
|
||||
|
||||
@ -91,7 +91,7 @@ const Item: FC<ItemProps> = ({
|
||||
</ActionButton>
|
||||
</div>
|
||||
{
|
||||
config.indexing_technique && (
|
||||
!!config.indexing_technique && (
|
||||
<Badge
|
||||
className="shrink-0 group-hover:hidden"
|
||||
text={formatIndexingTechniqueAndMethod(config.indexing_technique, config.retrieval_model_dict?.search_method)}
|
||||
|
||||
@ -175,7 +175,7 @@ const SelectDataSet: FC<ISelectDataSetProps> = ({
|
||||
</div>
|
||||
)}
|
||||
{
|
||||
item.indexing_technique && (
|
||||
!!item.indexing_technique && (
|
||||
<Badge
|
||||
className="shrink-0"
|
||||
text={formatIndexingTechniqueAndMethod(item.indexing_technique, item.retrieval_model_dict?.search_method)}
|
||||
|
||||
@ -247,7 +247,7 @@ const SettingsModal: FC<SettingsModalProps> = ({
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{currentDataset && currentDataset.indexing_technique && (
|
||||
{!!(currentDataset && currentDataset.indexing_technique) && (
|
||||
<div className={cn(rowClass)}>
|
||||
<div className={labelClass}>
|
||||
<div className="system-sm-semibold text-text-secondary">{t('form.indexMethod', { ns: 'datasetSettings' })}</div>
|
||||
|
||||
@ -465,8 +465,8 @@ vi.mock('@/app/components/base/chat/chat', () => ({
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
{questionIcon && <div data-testid="question-icon">{questionIcon}</div>}
|
||||
{answerIcon && <div data-testid="answer-icon">{answerIcon}</div>}
|
||||
{!!questionIcon && <div data-testid="question-icon">{questionIcon}</div>}
|
||||
{!!answerIcon && <div data-testid="answer-icon">{answerIcon}</div>}
|
||||
<textarea
|
||||
data-testid="chat-input"
|
||||
placeholder="Type a message"
|
||||
|
||||
@ -72,7 +72,7 @@ const ToolCallItem: FC<Props> = ({ toolCall, isLLM = false, isFinal, tokens, obs
|
||||
{toolName}
|
||||
</div>
|
||||
<div className="shrink-0 text-xs leading-[18px] text-text-tertiary">
|
||||
{toolCall.time_cost && (
|
||||
{!!toolCall.time_cost && (
|
||||
<span>{getTime(toolCall.time_cost || 0)}</span>
|
||||
)}
|
||||
{isLLM && (
|
||||
|
||||
@ -219,7 +219,7 @@ const Answer: FC<AnswerProps> = ({
|
||||
)
|
||||
}
|
||||
{
|
||||
item.siblingCount && item.siblingCount > 1 && item.siblingIndex !== undefined && (
|
||||
!!(item.siblingCount && item.siblingCount > 1 && item.siblingIndex !== undefined) && (
|
||||
<ContentSwitch
|
||||
count={item.siblingCount}
|
||||
currentIndex={item.siblingIndex}
|
||||
|
||||
@ -29,7 +29,7 @@ const More: FC<MoreProps> = ({
|
||||
>
|
||||
{`${t('detail.tokenCost', { ns: 'appLog' })} ${formatNumber(more.tokens)}`}
|
||||
</div>
|
||||
{more.tokens_per_second && (
|
||||
{!!more.tokens_per_second && (
|
||||
<div
|
||||
className="mr-2 max-w-[25%] shrink-0 truncate"
|
||||
title={`${more.tokens_per_second} tokens/s`}
|
||||
|
||||
@ -146,7 +146,7 @@ const Popup: FC<PopupProps> = ({
|
||||
icon={<BezierCurve03 className="mr-1 h-3 w-3" />}
|
||||
/>
|
||||
{
|
||||
source.score && (
|
||||
!!source.score && (
|
||||
<ProgressTooltip data={Number(source.score.toFixed(2))} />
|
||||
)
|
||||
}
|
||||
|
||||
@ -90,7 +90,7 @@ const UploaderButton: FC<UploaderButtonProps> = ({
|
||||
<PortalToFollowElemContent className="z-50">
|
||||
<div className="w-[260px] rounded-lg border-[0.5px] border-gray-200 bg-white p-2 shadow-lg">
|
||||
<ImageLinkInput onUpload={handleUpload} disabled={disabled} />
|
||||
{hasUploadFromLocal && (
|
||||
{!!hasUploadFromLocal && (
|
||||
<>
|
||||
<div className="mt-2 flex items-center px-2 text-xs font-medium text-gray-400">
|
||||
<div className="mr-3 h-px w-[93px] bg-gradient-to-l from-[#F3F4F6]" />
|
||||
|
||||
@ -109,7 +109,7 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(({
|
||||
disabled={disabled}
|
||||
{...props}
|
||||
/>
|
||||
{showClearIcon && value && !disabled && !destructive && (
|
||||
{!!(showClearIcon && value && !disabled && !destructive) && (
|
||||
<div
|
||||
className={cn('group absolute right-2 top-1/2 -translate-y-1/2 cursor-pointer p-[1px]')}
|
||||
onClick={onClear}
|
||||
|
||||
@ -52,7 +52,7 @@ export default function Modal({
|
||||
<div className={cn('flex min-h-full items-center justify-center p-4 text-center', containerClassName)}>
|
||||
<TransitionChild>
|
||||
<DialogPanel className={cn('relative w-full max-w-[480px] rounded-2xl bg-components-panel-bg p-6 text-left align-middle shadow-xl transition-all', overflowVisible ? 'overflow-visible' : 'overflow-hidden', 'duration-100 ease-in data-[closed]:scale-95 data-[closed]:opacity-0', 'data-[enter]:scale-100 data-[enter]:opacity-100', 'data-[enter]:scale-95 data-[leave]:opacity-0', className)}>
|
||||
{title && (
|
||||
{!!title && (
|
||||
<DialogTitle
|
||||
as="h3"
|
||||
className="title-2xl-semi-bold text-text-primary"
|
||||
@ -60,7 +60,7 @@ export default function Modal({
|
||||
{title}
|
||||
</DialogTitle>
|
||||
)}
|
||||
{description && (
|
||||
{!!description && (
|
||||
<div className="body-md-regular mt-2 text-text-secondary">
|
||||
{description}
|
||||
</div>
|
||||
|
||||
@ -87,7 +87,7 @@ const Modal = ({
|
||||
</div>
|
||||
</div>
|
||||
{
|
||||
children && (
|
||||
!!children && (
|
||||
<div className="min-h-0 flex-1 overflow-y-auto px-6 py-3">{children}</div>
|
||||
)
|
||||
}
|
||||
@ -126,7 +126,7 @@ const Modal = ({
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
{bottomSlot && (
|
||||
{!!bottomSlot && (
|
||||
<div className="shrink-0">
|
||||
{bottomSlot}
|
||||
</div>
|
||||
|
||||
@ -56,7 +56,7 @@ const RadioCard: FC<Props> = ({
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{((isChosen && chosenConfig) || noRadio) && (
|
||||
{!!((isChosen && chosenConfig) || noRadio) && (
|
||||
<div className="mt-2 flex gap-x-2">
|
||||
<div className="size-8 shrink-0"></div>
|
||||
<div className={cn(chosenConfigWrapClassName, 'grow')}>
|
||||
|
||||
@ -52,7 +52,7 @@ export default function Radio({
|
||||
)}
|
||||
onClick={() => handleChange(value)}
|
||||
>
|
||||
{children && (
|
||||
{!!children && (
|
||||
<label
|
||||
className={
|
||||
cn(labelClassName, 'cursor-pointer text-sm')
|
||||
|
||||
@ -130,7 +130,7 @@ export const SegmentedControl = <T extends string | number | symbol>({
|
||||
{text && (
|
||||
<div className={cn('inline-flex items-center gap-x-1', ItemTextWrapperVariants({ size }))}>
|
||||
<span>{text}</span>
|
||||
{count && size === 'large' && (
|
||||
{!!(count && size === 'large') && (
|
||||
<div className="system-2xs-medium-uppercase inline-flex h-[18px] min-w-[18px] items-center justify-center rounded-[5px] border border-divider-deep bg-components-badge-bg-dimm px-[5px] text-text-tertiary">
|
||||
{count}
|
||||
</div>
|
||||
|
||||
@ -379,7 +379,7 @@ const PortalSelect: FC<PortalSelectProps> = ({
|
||||
{selectedItem?.name ?? localPlaceholder}
|
||||
</span>
|
||||
<div className="mx-0.5">
|
||||
{installedValue && selectedItem && selectedItem.value !== installedValue && (
|
||||
{!!(installedValue && selectedItem && selectedItem.value !== installedValue) && (
|
||||
<Badge>
|
||||
{installedValue}
|
||||
{' '}
|
||||
|
||||
@ -80,7 +80,7 @@ const Toast = ({
|
||||
<div className="system-sm-semibold text-text-primary [word-break:break-word]">{message}</div>
|
||||
{customComponent}
|
||||
</div>
|
||||
{children && (
|
||||
{!!children && (
|
||||
<div className="system-xs-regular text-text-secondary">
|
||||
{children}
|
||||
</div>
|
||||
|
||||
@ -12,11 +12,11 @@ export const ToolTipContent: FC<ToolTipContentProps> = ({
|
||||
}) => {
|
||||
return (
|
||||
<div className="w-[180px]">
|
||||
{title && (
|
||||
{!!title && (
|
||||
<div className="mb-1.5 font-semibold text-text-secondary">{title}</div>
|
||||
)}
|
||||
<div className="mb-1.5 text-text-tertiary">{children}</div>
|
||||
{action && <div className="cursor-pointer text-text-accent">{action}</div>}
|
||||
{!!action && <div className="cursor-pointer text-text-accent">{action}</div>}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@ -109,7 +109,7 @@ const Tooltip: FC<TooltipProps> = ({
|
||||
<PortalToFollowElemContent
|
||||
className={cn('z-[9999]', portalContentClassName || '')}
|
||||
>
|
||||
{popupContent && (
|
||||
{!!popupContent && (
|
||||
<div
|
||||
className={cn(
|
||||
!noDecoration && 'system-xs-regular relative max-w-[300px] break-words rounded-md bg-components-panel-bg px-3 py-2 text-left text-text-tertiary shadow-lg',
|
||||
|
||||
@ -87,10 +87,10 @@ export const OptionCard: FC<OptionCardProps> = (
|
||||
disabled={disabled}
|
||||
/>
|
||||
{/** Body */}
|
||||
{isActive && (children || actions) && (
|
||||
{!!(isActive && (children || actions)) && (
|
||||
<div className="rounded-b-xl bg-components-panel-bg px-4 py-3">
|
||||
{children}
|
||||
{actions && (
|
||||
{!!actions && (
|
||||
<div className="mt-4 flex gap-2">
|
||||
{actions}
|
||||
</div>
|
||||
|
||||
@ -508,7 +508,7 @@ const DocumentList: FC<IDocumentListProps> = ({
|
||||
/>
|
||||
)}
|
||||
{/* Show Pagination only if the total is more than the limit */}
|
||||
{pagination.total && (
|
||||
{!!pagination.total && (
|
||||
<Pagination
|
||||
{...pagination}
|
||||
className="w-full shrink-0"
|
||||
|
||||
@ -24,7 +24,7 @@ vi.mock('@/app/components/datasets/documents/detail/metadata', () => ({
|
||||
<div data-testid="field-info" data-label={label}>
|
||||
<span data-testid="field-label">{label}</span>
|
||||
<span data-testid="field-value">{displayedValue}</span>
|
||||
{valueIcon && <span data-testid="field-icon">{valueIcon}</span>}
|
||||
{!!valueIcon && <span data-testid="field-icon">{valueIcon}</span>}
|
||||
</div>
|
||||
),
|
||||
}))
|
||||
|
||||
@ -49,7 +49,7 @@ const DocModeInfo = ({
|
||||
|
||||
return (
|
||||
<div className="system-2xs-medium-uppercase flex items-center gap-x-3 text-text-tertiary">
|
||||
{dataset.doc_form && (
|
||||
{!!dataset.doc_form && (
|
||||
<span
|
||||
className="min-w-0 max-w-full truncate"
|
||||
title={t(`chunkingMode.${DOC_FORM_TEXT[dataset.doc_form]}`, { ns: 'dataset' })}
|
||||
|
||||
@ -27,7 +27,7 @@ vi.mock('../../../base/modal-like-wrap', () => ({
|
||||
default: ({ children, title, onClose, onConfirm, beforeHeader }: ModalLikeWrapProps) => (
|
||||
<div data-testid="modal-wrap">
|
||||
<div data-testid="modal-title">{title}</div>
|
||||
{beforeHeader && <div data-testid="before-header">{beforeHeader}</div>}
|
||||
{!!beforeHeader && <div data-testid="before-header">{beforeHeader}</div>}
|
||||
<div data-testid="modal-content">{children}</div>
|
||||
<button data-testid="close-btn" onClick={onClose}>Close</button>
|
||||
<button data-testid="confirm-btn" onClick={onConfirm}>Confirm</button>
|
||||
|
||||
@ -265,7 +265,7 @@ const Form = () => {
|
||||
</div>
|
||||
</div>
|
||||
{
|
||||
currentDataset?.doc_form && (
|
||||
!!currentDataset?.doc_form && (
|
||||
<>
|
||||
<Divider
|
||||
type="horizontal"
|
||||
@ -298,13 +298,13 @@ const Form = () => {
|
||||
</>
|
||||
)
|
||||
}
|
||||
{(isShowIndexMethod || indexMethod === 'high_quality') && (
|
||||
{!!(isShowIndexMethod || indexMethod === 'high_quality') && (
|
||||
<Divider
|
||||
type="horizontal"
|
||||
className="my-1 h-px bg-divider-subtle"
|
||||
/>
|
||||
)}
|
||||
{isShowIndexMethod && (
|
||||
{!!isShowIndexMethod && (
|
||||
<div className={rowClass}>
|
||||
<div className={labelClass}>
|
||||
<div className="system-sm-semibold text-text-secondary">{t('form.indexMethod', { ns: 'datasetSettings' })}</div>
|
||||
|
||||
@ -77,7 +77,7 @@ const OptionCard = <T,>({
|
||||
)
|
||||
}
|
||||
{
|
||||
icon && (
|
||||
!!icon && (
|
||||
<div className={cn(
|
||||
'flex size-6 shrink-0 items-center justify-center text-text-tertiary',
|
||||
isActive && iconActiveColor,
|
||||
@ -110,7 +110,7 @@ const OptionCard = <T,>({
|
||||
</div>
|
||||
</div>
|
||||
{
|
||||
children && showChildren && (
|
||||
!!(children && showChildren) && (
|
||||
<div className="relative rounded-b-xl bg-components-panel-bg p-4">
|
||||
<ArrowShape className="absolute left-[14px] top-[-11px] size-4 text-components-panel-bg" />
|
||||
{children}
|
||||
|
||||
@ -48,21 +48,21 @@ const ModelName: FC<ModelNameProps> = ({
|
||||
</div>
|
||||
<div className="flex items-center gap-0.5">
|
||||
{
|
||||
showModelType && modelItem.model_type && (
|
||||
!!(showModelType && modelItem.model_type) && (
|
||||
<ModelBadge className={modelTypeClassName}>
|
||||
{modelTypeFormat(modelItem.model_type)}
|
||||
</ModelBadge>
|
||||
)
|
||||
}
|
||||
{
|
||||
modelItem.model_properties.mode && showMode && (
|
||||
!!(modelItem.model_properties.mode && showMode) && (
|
||||
<ModelBadge className={modeClassName}>
|
||||
{(modelItem.model_properties.mode as string).toLocaleUpperCase()}
|
||||
</ModelBadge>
|
||||
)
|
||||
}
|
||||
{
|
||||
showContextSize && modelItem.model_properties.context_size && (
|
||||
!!(showContextSize && modelItem.model_properties.context_size) && (
|
||||
<ModelBadge>
|
||||
{sizeFormat(modelItem.model_properties.context_size as number)}
|
||||
</ModelBadge>
|
||||
|
||||
@ -104,17 +104,17 @@ const PopupItem: FC<PopupItemProps> = ({
|
||||
/>
|
||||
)
|
||||
}
|
||||
{modelItem.model_type && (
|
||||
{!!modelItem.model_type && (
|
||||
<ModelBadge>
|
||||
{modelTypeFormat(modelItem.model_type)}
|
||||
</ModelBadge>
|
||||
)}
|
||||
{modelItem.model_properties.mode && (
|
||||
{!!modelItem.model_properties.mode && (
|
||||
<ModelBadge>
|
||||
{(modelItem.model_properties.mode as string).toLocaleUpperCase()}
|
||||
</ModelBadge>
|
||||
)}
|
||||
{modelItem.model_properties.context_size && (
|
||||
{!!modelItem.model_properties.context_size && (
|
||||
<ModelBadge>
|
||||
{sizeFormat(modelItem.model_properties.context_size as number)}
|
||||
</ModelBadge>
|
||||
|
||||
@ -5,7 +5,7 @@ import { useBoolean } from 'ahooks'
|
||||
import * as React from 'react'
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { AnthropicShortLight, Deepseek, Gemini, Grok, OpenaiSmall, Tongyi } from '@/app/components/base/icons/src/public/llm'
|
||||
import { OpenaiSmall } from '@/app/components/base/icons/src/public/llm'
|
||||
import Loading from '@/app/components/base/loading'
|
||||
import Tooltip from '@/app/components/base/tooltip'
|
||||
import InstallFromMarketplace from '@/app/components/plugins/install-plugin/install-from-marketplace'
|
||||
@ -19,11 +19,11 @@ import { modelNameMap, ModelProviderQuotaGetPaid } from '../utils'
|
||||
|
||||
const allProviders = [
|
||||
{ key: ModelProviderQuotaGetPaid.OPENAI, Icon: OpenaiSmall },
|
||||
{ key: ModelProviderQuotaGetPaid.ANTHROPIC, Icon: AnthropicShortLight },
|
||||
{ key: ModelProviderQuotaGetPaid.GEMINI, Icon: Gemini },
|
||||
{ key: ModelProviderQuotaGetPaid.X, Icon: Grok },
|
||||
{ key: ModelProviderQuotaGetPaid.DEEPSEEK, Icon: Deepseek },
|
||||
{ key: ModelProviderQuotaGetPaid.TONGYI, Icon: Tongyi },
|
||||
// { key: ModelProviderQuotaGetPaid.ANTHROPIC, Icon: AnthropicShortLight },
|
||||
// { key: ModelProviderQuotaGetPaid.GEMINI, Icon: Gemini },
|
||||
// { key: ModelProviderQuotaGetPaid.X, Icon: Grok },
|
||||
// { key: ModelProviderQuotaGetPaid.DEEPSEEK, Icon: Deepseek },
|
||||
// { key: ModelProviderQuotaGetPaid.TONGYI, Icon: Tongyi },
|
||||
] as const
|
||||
|
||||
// Map provider key to plugin ID
|
||||
|
||||
@ -81,7 +81,7 @@ vi.mock('@/app/components/base/app-icon', () => ({
|
||||
data-size={size}
|
||||
data-icon-type={iconType}
|
||||
>
|
||||
{innerIcon && <div data-testid="inner-icon">{innerIcon}</div>}
|
||||
{!!innerIcon && <div data-testid="inner-icon">{innerIcon}</div>}
|
||||
</div>
|
||||
),
|
||||
}))
|
||||
|
||||
@ -95,7 +95,7 @@ const Card = ({
|
||||
text={getLocalizedText(brief)}
|
||||
descriptionLineRows={descriptionLineRows}
|
||||
/>
|
||||
{footer && <div>{footer}</div>}
|
||||
{!!footer && <div>{footer}</div>}
|
||||
</div>
|
||||
{limitedInstall
|
||||
&& (
|
||||
|
||||
@ -32,7 +32,7 @@ vi.mock('../../../card', () => ({
|
||||
default: ({ payload, titleLeft }: { payload: Plugin, titleLeft?: React.ReactNode }) => (
|
||||
<div data-testid="plugin-card">
|
||||
<span data-testid="card-name">{payload.name}</span>
|
||||
{titleLeft && <span data-testid="title-left">{titleLeft}</span>}
|
||||
{!!titleLeft && <span data-testid="title-left">{titleLeft}</span>}
|
||||
</div>
|
||||
),
|
||||
}))
|
||||
|
||||
@ -118,7 +118,7 @@ vi.mock('../../../card', () => ({
|
||||
<div data-testid="plugin-card">
|
||||
<span data-testid="card-payload-name">{payload?.name}</span>
|
||||
<span data-testid="card-limited-install">{limitedInstall ? 'true' : 'false'}</span>
|
||||
{titleLeft && <div data-testid="card-title-left">{titleLeft}</div>}
|
||||
{!!titleLeft && <div data-testid="card-title-left">{titleLeft}</div>}
|
||||
</div>
|
||||
),
|
||||
}))
|
||||
|
||||
@ -279,7 +279,7 @@ vi.mock('@/app/components/plugins/card', () => ({
|
||||
default: ({ payload, footer }: { payload: Plugin, footer?: React.ReactNode }) => (
|
||||
<div data-testid={`card-${payload.name}`}>
|
||||
<div data-testid="card-name">{payload.name}</div>
|
||||
{footer && <div data-testid="card-footer">{footer}</div>}
|
||||
{!!footer && <div data-testid="card-footer">{footer}</div>}
|
||||
</div>
|
||||
),
|
||||
}))
|
||||
|
||||
@ -126,7 +126,7 @@ vi.mock('@/app/components/plugins/card', () => ({
|
||||
<div data-testid={`card-${payload.name}`}>
|
||||
<div data-testid="card-name">{payload.name}</div>
|
||||
<div data-testid="card-label">{payload.label?.['en-US'] || payload.name}</div>
|
||||
{footer && <div data-testid="card-footer">{footer}</div>}
|
||||
{!!footer && <div data-testid="card-footer">{footer}</div>}
|
||||
</div>
|
||||
),
|
||||
}))
|
||||
|
||||
@ -229,7 +229,7 @@ const DetailHeader = ({
|
||||
<div className="flex h-5 items-center">
|
||||
<Title title={label[locale]} />
|
||||
{verified && !isReadmeView && <Verified className="ml-0.5 h-4 w-4" text={t('marketplace.verifiedTip', { ns: 'plugin' })} />}
|
||||
{version && (
|
||||
{!!version && (
|
||||
<PluginVersionPicker
|
||||
disabled={!isFromMarketplace || isReadmeView}
|
||||
isShow={isShow}
|
||||
@ -297,7 +297,7 @@ const DetailHeader = ({
|
||||
orgName={author}
|
||||
packageName={name?.includes('/') ? (name.split('/').pop() || '') : name}
|
||||
/>
|
||||
{source && (
|
||||
{!!source && (
|
||||
<>
|
||||
<div className="system-xs-regular ml-1 mr-0.5 text-text-quaternary">·</div>
|
||||
{source === PluginSource.marketplace && (
|
||||
|
||||
@ -196,7 +196,7 @@ vi.mock('@/app/components/base/modal/modal', () => ({
|
||||
{extraButtonText}
|
||||
</button>
|
||||
)}
|
||||
{bottomSlot && <div data-testid="modal-bottom-slot">{bottomSlot}</div>}
|
||||
{!!bottomSlot && <div data-testid="modal-bottom-slot">{bottomSlot}</div>}
|
||||
</div>
|
||||
),
|
||||
}))
|
||||
|
||||
@ -78,7 +78,7 @@ vi.mock('@/app/components/base/app-icon', () => ({
|
||||
data-size={size}
|
||||
data-icon-type={iconType}
|
||||
>
|
||||
{innerIcon && <div data-testid="inner-icon">{innerIcon}</div>}
|
||||
{!!innerIcon && <div data-testid="inner-icon">{innerIcon}</div>}
|
||||
</div>
|
||||
),
|
||||
}))
|
||||
|
||||
@ -41,7 +41,7 @@ const Empty = ({
|
||||
<div className="mb-1 mt-2 text-[13px] font-medium leading-[18px] text-text-primary">
|
||||
{(hasTitle && renderType) ? t(`addToolModal.${renderType}.title`, { ns: 'tools' }) : 'No tools available'}
|
||||
</div>
|
||||
{(!isAgent && hasTitle && renderType) && (
|
||||
{!!(!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(`addToolModal.${renderType}.tip`, { ns: 'tools' })}
|
||||
{' '}
|
||||
|
||||
@ -95,7 +95,7 @@ const Base: FC<Props> = ({
|
||||
}}
|
||||
>
|
||||
{headerRight}
|
||||
{showCodeGenerator && codeLanguages && (
|
||||
{!!(showCodeGenerator && codeLanguages) && (
|
||||
<div className="ml-1">
|
||||
<CodeGeneratorButton
|
||||
onGenerated={onGenerated}
|
||||
@ -119,7 +119,7 @@ const Base: FC<Props> = ({
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{tip && <div className="px-1 py-0.5">{tip}</div>}
|
||||
{!!tip && <div className="px-1 py-0.5">{tip}</div>}
|
||||
<PromptEditorHeightResizeWrap
|
||||
height={isExpand ? editorExpandHeight : editorContentHeight}
|
||||
minHeight={editorContentMinHeight}
|
||||
|
||||
@ -46,7 +46,7 @@ const Field: FC<Props> = ({
|
||||
{' '}
|
||||
{required && <span className="text-text-destructive">*</span>}
|
||||
</div>
|
||||
{tooltip && (
|
||||
{!!tooltip && (
|
||||
<Tooltip
|
||||
popupContent={tooltip}
|
||||
popupClassName="ml-1"
|
||||
@ -55,13 +55,13 @@ const Field: FC<Props> = ({
|
||||
)}
|
||||
</div>
|
||||
<div className="flex">
|
||||
{operations && <div>{operations}</div>}
|
||||
{!!operations && <div>{operations}</div>}
|
||||
{supportFold && (
|
||||
<RiArrowDownSLine className="h-4 w-4 cursor-pointer text-text-tertiary transition-transform" style={{ transform: fold ? 'rotate(-90deg)' : 'rotate(0deg)' }} />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{children && (!supportFold || (supportFold && !fold)) && <div className={cn(!inline && 'mt-1')}>{children}</div>}
|
||||
{!!(children && (!supportFold || (supportFold && !fold))) && <div className={cn(!inline && 'mt-1')}>{children}</div>}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@ -167,7 +167,7 @@ const Editor: FC<Props> = ({
|
||||
{' '}
|
||||
{required && <span className="text-text-destructive">*</span>}
|
||||
</div>
|
||||
{titleTooltip && <Tooltip popupContent={titleTooltip} />}
|
||||
{!!titleTooltip && <Tooltip popupContent={titleTooltip} />}
|
||||
</div>
|
||||
<div className="flex items-center">
|
||||
<div className="text-xs font-medium leading-[18px] text-text-tertiary">{value?.length || 0}</div>
|
||||
|
||||
@ -61,7 +61,7 @@ const VariableLabel = ({
|
||||
notShowFullPath={notShowFullPath}
|
||||
/>
|
||||
{
|
||||
variableType && (
|
||||
!!variableType && (
|
||||
<div className="system-xs-regular shrink-0 text-text-tertiary">
|
||||
{capitalize(variableType)}
|
||||
</div>
|
||||
|
||||
@ -322,7 +322,7 @@ const BaseNode: FC<BaseNodeProps> = ({
|
||||
}
|
||||
</div>
|
||||
{
|
||||
data._iterationLength && data._iterationIndex && data._runningStatus === NodeRunningStatus.Running && (
|
||||
!!(data._iterationLength && data._iterationIndex && data._runningStatus === NodeRunningStatus.Running) && (
|
||||
<div className="mr-1.5 text-xs font-medium text-text-accent">
|
||||
{data._iterationIndex > data._iterationLength ? data._iterationLength : data._iterationIndex}
|
||||
/
|
||||
@ -331,7 +331,7 @@ const BaseNode: FC<BaseNodeProps> = ({
|
||||
)
|
||||
}
|
||||
{
|
||||
data.type === BlockEnum.Loop && data._loopIndex && LoopIndex
|
||||
!!(data.type === BlockEnum.Loop && data._loopIndex) && LoopIndex
|
||||
}
|
||||
{
|
||||
isLoading
|
||||
@ -374,7 +374,7 @@ const BaseNode: FC<BaseNodeProps> = ({
|
||||
)
|
||||
}
|
||||
{
|
||||
data.desc && data.type !== BlockEnum.Iteration && data.type !== BlockEnum.Loop && (
|
||||
!!(data.desc && data.type !== BlockEnum.Iteration && data.type !== BlockEnum.Loop) && (
|
||||
<div className="system-xs-regular whitespace-pre-line break-words px-3 pb-2 pt-1 text-text-tertiary">
|
||||
{data.desc}
|
||||
</div>
|
||||
|
||||
@ -178,7 +178,7 @@ const VarList: FC<Props> = ({
|
||||
className="w-full"
|
||||
/>
|
||||
)}
|
||||
{item.operation === WriteMode.set && assignedVarType && (
|
||||
{!!(item.operation === WriteMode.set && assignedVarType) && (
|
||||
<>
|
||||
{assignedVarType === 'number' && (
|
||||
<Input
|
||||
|
||||
@ -51,7 +51,7 @@ const NodeComponent: FC<NodeProps<AssignerNodeType>> = ({
|
||||
nodeType={node?.data.type}
|
||||
nodeTitle={node?.data.title}
|
||||
rightSlot={
|
||||
value.operation && <Badge className="!ml-auto shrink-0" text={t(`${i18nPrefix}.operations.${value.operation}`, { ns: 'workflow' })} />
|
||||
!!value.operation && <Badge className="!ml-auto shrink-0" text={t(`${i18nPrefix}.operations.${value.operation}`, { ns: 'workflow' })} />
|
||||
}
|
||||
/>
|
||||
)
|
||||
|
||||
@ -41,7 +41,7 @@ const ChunkStructure = ({
|
||||
}}
|
||||
>
|
||||
{
|
||||
chunkStructure && (
|
||||
!!chunkStructure && (
|
||||
<OptionCard
|
||||
{...optionMap[chunkStructure]}
|
||||
selectedId={chunkStructure}
|
||||
|
||||
@ -100,7 +100,7 @@ const OptionCard = memo(({
|
||||
>
|
||||
{effectElement}
|
||||
{
|
||||
icon && (
|
||||
!!icon && (
|
||||
<div className="mr-1 flex h-[18px] w-[18px] shrink-0 items-center justify-center">
|
||||
{typeof icon === 'function' ? icon(isActive) : icon}
|
||||
</div>
|
||||
@ -139,7 +139,7 @@ const OptionCard = memo(({
|
||||
</div>
|
||||
</div>
|
||||
{
|
||||
children && isActive && (
|
||||
!!(children && isActive) && (
|
||||
<div className="relative rounded-b-xl bg-components-panel-bg p-3">
|
||||
<ArrowShape className="absolute left-[14px] top-[-11px] h-4 w-4 text-components-panel-bg" />
|
||||
{children}
|
||||
|
||||
@ -118,7 +118,7 @@ const Panel: FC<NodePanelProps<KnowledgeBaseNodeType>> = ({
|
||||
/>
|
||||
</Group>
|
||||
{
|
||||
data.chunk_structure && (
|
||||
!!data.chunk_structure && (
|
||||
<>
|
||||
<BoxGroupField
|
||||
boxGroupProps={{
|
||||
|
||||
@ -110,7 +110,7 @@ const DatasetItem: FC<Props> = ({
|
||||
</div>
|
||||
)}
|
||||
{
|
||||
payload.indexing_technique && (
|
||||
!!payload.indexing_technique && (
|
||||
<Badge
|
||||
className="shrink-0 group-hover/dataset-item:hidden"
|
||||
text={formatIndexingTechniqueAndMethod(payload.indexing_technique, payload.retrieval_model_dict?.search_method)}
|
||||
|
||||
@ -46,7 +46,7 @@ const ConditionDate = ({
|
||||
}
|
||||
</div>
|
||||
{
|
||||
value && (
|
||||
!!value && (
|
||||
<RiCloseCircleFill
|
||||
className={cn(
|
||||
'hidden h-4 w-4 shrink-0 cursor-pointer hover:text-components-input-text-filled group-hover:block',
|
||||
|
||||
@ -123,7 +123,7 @@ const ConfigPromptItem: FC<Props> = ({
|
||||
|
||||
<Tooltip
|
||||
popupContent={
|
||||
<div className="max-w-[180px]">{payload.role && t(`${i18nPrefix}.roleDescription.${payload.role}`, { ns: 'workflow' })}</div>
|
||||
<div className="max-w-[180px]">{!!payload.role && t(`${i18nPrefix}.roleDescription.${payload.role}`, { ns: 'workflow' })}</div>
|
||||
}
|
||||
triggerClassName="w-4 h-4"
|
||||
/>
|
||||
|
||||
@ -86,7 +86,7 @@ const ConditionList = ({
|
||||
className="absolute right-1 top-1/2 flex h-[21px] -translate-y-1/2 cursor-pointer select-none items-center rounded-md border-[0.5px] border-components-button-secondary-border bg-components-button-secondary-bg px-1 text-[10px] font-semibold text-text-accent-secondary shadow-xs"
|
||||
onClick={() => doToggleConditionLogicalOperator(conditionId)}
|
||||
>
|
||||
{logicalOperator && logicalOperator.toUpperCase()}
|
||||
{!!logicalOperator && logicalOperator.toUpperCase()}
|
||||
<RiLoopLeftLine className="ml-0.5 h-3 w-3" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -115,7 +115,7 @@ const ConversationVariableModal = ({
|
||||
}}
|
||||
>
|
||||
</div>
|
||||
{latestValueTimestampMap[currentVar.id] && (
|
||||
{!!latestValueTimestampMap[currentVar.id] && (
|
||||
<div className="system-xs-regular shrink-0 text-text-tertiary">
|
||||
{t('chatVariable.updatedAt', { ns: 'workflow' })}
|
||||
{formatTime(latestValueTimestampMap[currentVar.id], t('dateTimeFormat', { ns: 'appLog' }) as string)}
|
||||
|
||||
@ -79,7 +79,7 @@ const AgentLogItem = ({
|
||||
{label}
|
||||
</div>
|
||||
{
|
||||
metadata?.elapsed_time && (
|
||||
!!metadata?.elapsed_time && (
|
||||
<div className="system-xs-regular mr-2 shrink-0 text-text-tertiary">
|
||||
{metadata?.elapsed_time?.toFixed(3)}
|
||||
s
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
import consistentPlaceholders from './rules/consistent-placeholders.js'
|
||||
import noAsAnyInT from './rules/no-as-any-in-t.js'
|
||||
import noExtraKeys from './rules/no-extra-keys.js'
|
||||
import noLegacyNamespacePrefix from './rules/no-legacy-namespace-prefix.js'
|
||||
import noVersionPrefix from './rules/no-version-prefix.js'
|
||||
import requireNsOption from './rules/require-ns-option.js'
|
||||
import validI18nKeys from './rules/valid-i18n-keys.js'
|
||||
|
||||
@ -11,9 +13,11 @@ const plugin = {
|
||||
version: '1.0.0',
|
||||
},
|
||||
rules: {
|
||||
'consistent-placeholders': consistentPlaceholders,
|
||||
'no-as-any-in-t': noAsAnyInT,
|
||||
'no-extra-keys': noExtraKeys,
|
||||
'no-legacy-namespace-prefix': noLegacyNamespacePrefix,
|
||||
'no-version-prefix': noVersionPrefix,
|
||||
'require-ns-option': requireNsOption,
|
||||
'valid-i18n-keys': validI18nKeys,
|
||||
},
|
||||
|
||||
109
web/eslint-rules/rules/consistent-placeholders.js
Normal file
109
web/eslint-rules/rules/consistent-placeholders.js
Normal file
@ -0,0 +1,109 @@
|
||||
import fs from 'node:fs'
|
||||
import path, { normalize, sep } from 'node:path'
|
||||
import { cleanJsonText } from '../utils.js'
|
||||
|
||||
/**
|
||||
* Extract placeholders from a string
|
||||
* Matches patterns like {{name}}, {{count}}, etc.
|
||||
* @param {string} str
|
||||
* @returns {string[]} Sorted array of placeholder names
|
||||
*/
|
||||
function extractPlaceholders(str) {
|
||||
const matches = str.match(/\{\{\w+\}\}/g) || []
|
||||
return matches.map(m => m.slice(2, -2)).sort()
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare two arrays and return if they're equal
|
||||
* @param {string[]} arr1
|
||||
* @param {string[]} arr2
|
||||
* @returns {boolean} True if arrays contain the same elements in the same order
|
||||
*/
|
||||
function arraysEqual(arr1, arr2) {
|
||||
if (arr1.length !== arr2.length)
|
||||
return false
|
||||
return arr1.every((val, i) => val === arr2[i])
|
||||
}
|
||||
|
||||
/** @type {import('eslint').Rule.RuleModule} */
|
||||
export default {
|
||||
meta: {
|
||||
type: 'problem',
|
||||
docs: {
|
||||
description: 'Ensure placeholders in translations match the en-US source',
|
||||
},
|
||||
},
|
||||
create(context) {
|
||||
return {
|
||||
Program(node) {
|
||||
const { filename, sourceCode } = context
|
||||
|
||||
if (!filename.endsWith('.json'))
|
||||
return
|
||||
|
||||
const parts = normalize(filename).split(sep)
|
||||
const jsonFile = parts.at(-1)
|
||||
const lang = parts.at(-2)
|
||||
|
||||
// Skip English files - they are the source of truth
|
||||
if (lang === 'en-US')
|
||||
return
|
||||
|
||||
let currentJson = {}
|
||||
let englishJson = {}
|
||||
|
||||
try {
|
||||
currentJson = JSON.parse(cleanJsonText(sourceCode.text))
|
||||
const englishFilePath = path.join(path.dirname(filename), '..', 'en-US', jsonFile ?? '')
|
||||
englishJson = JSON.parse(fs.readFileSync(englishFilePath, 'utf8'))
|
||||
}
|
||||
catch (error) {
|
||||
context.report({
|
||||
node,
|
||||
message: `Error parsing JSON: ${error instanceof Error ? error.message : String(error)}`,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// Check each key in the current translation
|
||||
for (const key of Object.keys(currentJson)) {
|
||||
// Skip if the key doesn't exist in English (handled by no-extra-keys rule)
|
||||
if (!Object.prototype.hasOwnProperty.call(englishJson, key))
|
||||
continue
|
||||
|
||||
const currentValue = currentJson[key]
|
||||
const englishValue = englishJson[key]
|
||||
|
||||
// Skip non-string values
|
||||
if (typeof currentValue !== 'string' || typeof englishValue !== 'string')
|
||||
continue
|
||||
|
||||
const currentPlaceholders = extractPlaceholders(currentValue)
|
||||
const englishPlaceholders = extractPlaceholders(englishValue)
|
||||
|
||||
if (!arraysEqual(currentPlaceholders, englishPlaceholders)) {
|
||||
const missing = englishPlaceholders.filter(p => !currentPlaceholders.includes(p))
|
||||
const extra = currentPlaceholders.filter(p => !englishPlaceholders.includes(p))
|
||||
|
||||
let message = `Placeholder mismatch in "${key}": `
|
||||
const details = []
|
||||
|
||||
if (missing.length > 0)
|
||||
details.push(`missing {{${missing.join('}}, {{')}}}`)
|
||||
|
||||
if (extra.length > 0)
|
||||
details.push(`extra {{${extra.join('}}, {{')}}}`)
|
||||
|
||||
message += details.join('; ')
|
||||
message += `. Expected: {{${englishPlaceholders.join('}}, {{') || 'none'}}}`
|
||||
|
||||
context.report({
|
||||
node,
|
||||
message,
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
45
web/eslint-rules/rules/no-version-prefix.js
Normal file
45
web/eslint-rules/rules/no-version-prefix.js
Normal file
@ -0,0 +1,45 @@
|
||||
const DEPENDENCY_KEYS = ['dependencies', 'devDependencies', 'peerDependencies', 'optionalDependencies']
|
||||
const VERSION_PREFIXES = ['^', '~']
|
||||
|
||||
/** @type {import('eslint').Rule.RuleModule} */
|
||||
export default {
|
||||
meta: {
|
||||
type: 'problem',
|
||||
docs: {
|
||||
description: `Ensure package.json dependencies do not use version prefixes (${VERSION_PREFIXES.join(' or ')})`,
|
||||
},
|
||||
fixable: 'code',
|
||||
},
|
||||
create(context) {
|
||||
const { filename } = context
|
||||
|
||||
if (!filename.endsWith('package.json'))
|
||||
return {}
|
||||
|
||||
const selector = `JSONProperty:matches(${DEPENDENCY_KEYS.map(k => `[key.value="${k}"]`).join(', ')}) > JSONObjectExpression > JSONProperty`
|
||||
|
||||
return {
|
||||
[selector](node) {
|
||||
const versionNode = node.value
|
||||
|
||||
if (versionNode && versionNode.type === 'JSONLiteral' && typeof versionNode.value === 'string') {
|
||||
const version = versionNode.value
|
||||
const foundPrefix = VERSION_PREFIXES.find(prefix => version.startsWith(prefix))
|
||||
|
||||
if (foundPrefix) {
|
||||
const packageName = node.key.value || node.key.name
|
||||
const cleanVersion = version.substring(1)
|
||||
const canAutoFix = /^\d+\.\d+\.\d+$/.test(cleanVersion)
|
||||
context.report({
|
||||
node: versionNode,
|
||||
message: `Dependency "${packageName}" has version prefix "${foundPrefix}" that should be removed (found: "${version}", expected: "${cleanVersion}")`,
|
||||
fix: canAutoFix
|
||||
? fixer => fixer.replaceText(versionNode, `"${cleanVersion}"`)
|
||||
: undefined,
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
@ -131,6 +131,17 @@ export default antfu(
|
||||
|
||||
'dify-i18n/valid-i18n-keys': 'error',
|
||||
'dify-i18n/no-extra-keys': 'error',
|
||||
'dify-i18n/consistent-placeholders': 'error',
|
||||
},
|
||||
},
|
||||
// package.json version prefix validation
|
||||
{
|
||||
files: ['**/package.json'],
|
||||
plugins: {
|
||||
'dify-i18n': difyI18n,
|
||||
},
|
||||
rules: {
|
||||
'dify-i18n/no-version-prefix': 'error',
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
@ -61,6 +61,7 @@
|
||||
"account.workspaceName": "اسم مساحة العمل",
|
||||
"account.workspaceNamePlaceholder": "أدخل اسم مساحة العمل",
|
||||
"actionMsg.copySuccessfully": "تم النسخ بنجاح",
|
||||
"actionMsg.downloadUnsuccessfully": "فشل التنزيل. يرجى المحاولة مرة أخرى لاحقًا.",
|
||||
"actionMsg.generatedSuccessfully": "تم الإنشاء بنجاح",
|
||||
"actionMsg.generatedUnsuccessfully": "فشل الإنشاء",
|
||||
"actionMsg.modifiedSuccessfully": "تم التعديل بنجاح",
|
||||
@ -91,6 +92,7 @@
|
||||
"apiBasedExtension.title": "توفر ملحقات API إدارة مركزية لواجهة برمجة التطبيقات، مما يبسط التكوين لسهولة الاستخدام عبر تطبيقات Dify.",
|
||||
"apiBasedExtension.type": "النوع",
|
||||
"appMenus.apiAccess": "وصول API",
|
||||
"appMenus.apiAccessTip": "يمكن الوصول إلى قاعدة المعرفة هذه عبر واجهة برمجة تطبيقات الخدمة",
|
||||
"appMenus.logAndAnn": "السجلات والتعليقات التوضيحية",
|
||||
"appMenus.logs": "السجلات",
|
||||
"appMenus.overview": "المراقبة",
|
||||
|
||||
@ -26,6 +26,7 @@
|
||||
"list.action.archive": "أرشيف",
|
||||
"list.action.batchAdd": "إضافة دفعة",
|
||||
"list.action.delete": "حذف",
|
||||
"list.action.download": "تحميل",
|
||||
"list.action.enableWarning": "لا يمكن تمكين الملف المؤرشف",
|
||||
"list.action.pause": "إيقاف مؤقت",
|
||||
"list.action.resume": "استئناف",
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
"batchAction.cancel": "إلغاء",
|
||||
"batchAction.delete": "حذف",
|
||||
"batchAction.disable": "تعطيل",
|
||||
"batchAction.download": "تحميل",
|
||||
"batchAction.enable": "تمكين",
|
||||
"batchAction.reIndex": "إعادة الفهرسة",
|
||||
"batchAction.selected": "محدد",
|
||||
|
||||
@ -236,7 +236,7 @@
|
||||
"task.installSuccess": "تم تثبيت {{successLength}} من الإضافات بنجاح",
|
||||
"task.installed": "مثبت",
|
||||
"task.installedError": "{{errorLength}} إضافات فشل تثبيتها",
|
||||
"task.installing": "تثبيت {{installingLength}} إضافات، 0 تم.",
|
||||
"task.installing": "جارٍ تثبيت الإضافات.",
|
||||
"task.installingWithError": "تثبيت {{installingLength}} إضافات، {{successLength}} نجاح، {{errorLength}} فشل",
|
||||
"task.installingWithSuccess": "تثبيت {{installingLength}} إضافات، {{successLength}} نجاح.",
|
||||
"task.runningPlugins": "تثبيت الإضافات",
|
||||
|
||||
@ -251,10 +251,10 @@
|
||||
"openingStatement.notIncludeKey": "Das Anfangsprompt enthält nicht die Variable: {{key}}. Bitte fügen Sie sie dem Anfangsprompt hinzu.",
|
||||
"openingStatement.openingQuestion": "Eröffnungsfragen",
|
||||
"openingStatement.openingQuestionPlaceholder": "Sie können Variablen verwenden, versuchen Sie {{variable}} einzugeben.",
|
||||
"openingStatement.placeholder": "Schreiben Sie hier Ihre Eröffnungsnachricht, Sie können Variablen verwenden, versuchen Sie {{Variable}} zu tippen.",
|
||||
"openingStatement.placeholder": "Schreiben Sie hier Ihre Eröffnungsnachricht, Sie können Variablen verwenden, versuchen Sie {{variable}} zu tippen.",
|
||||
"openingStatement.title": "Gesprächseröffner",
|
||||
"openingStatement.tooShort": "Für die Erzeugung von Eröffnungsbemerkungen für das Gespräch werden mindestens 20 Wörter des Anfangsprompts benötigt.",
|
||||
"openingStatement.varTip": "Sie können Variablen verwenden, versuchen Sie {{Variable}} zu tippen",
|
||||
"openingStatement.varTip": "Sie können Variablen verwenden, versuchen Sie {{variable}} zu tippen",
|
||||
"openingStatement.writeOpener": "Eröffnung schreiben",
|
||||
"operation.addFeature": "Funktion hinzufügen",
|
||||
"operation.agree": "gefällt mir",
|
||||
|
||||
@ -83,7 +83,7 @@
|
||||
"gotoAnything.emptyState.noKnowledgeBasesFound": "Keine Wissensdatenbanken gefunden",
|
||||
"gotoAnything.emptyState.noPluginsFound": "Keine Plugins gefunden",
|
||||
"gotoAnything.emptyState.noWorkflowNodesFound": "Keine Workflow-Knoten gefunden",
|
||||
"gotoAnything.emptyState.tryDifferentTerm": "Versuchen Sie einen anderen Suchbegriff oder entfernen Sie den {{mode}}-Filter",
|
||||
"gotoAnything.emptyState.tryDifferentTerm": "Versuchen Sie einen anderen Suchbegriff",
|
||||
"gotoAnything.emptyState.trySpecificSearch": "Versuchen Sie {{shortcuts}} für spezifische Suchen",
|
||||
"gotoAnything.groups.apps": "Apps",
|
||||
"gotoAnything.groups.commands": "Befehle",
|
||||
|
||||
@ -65,7 +65,7 @@
|
||||
"plansCommon.annotatedResponse.title": "Kontingentgrenzen für Annotationen",
|
||||
"plansCommon.annotatedResponse.tooltip": "Manuelle Bearbeitung und Annotation von Antworten bieten anpassbare, hochwertige Frage-Antwort-Fähigkeiten für Apps. (Nur anwendbar in Chat-Apps)",
|
||||
"plansCommon.annotationQuota": "Kontingent für Anmerkungen",
|
||||
"plansCommon.annualBilling": "Jährliche Abrechnung",
|
||||
"plansCommon.annualBilling": "Jährliche Abrechnung, sparen Sie {{percent}}%",
|
||||
"plansCommon.apiRateLimit": "API-Datenlimit",
|
||||
"plansCommon.apiRateLimitTooltip": "Die API-Datenbeschränkung gilt für alle Anfragen, die über die Dify-API gemacht werden, einschließlich Textgenerierung, Chat-Konversationen, Workflow-Ausführungen und Dokumentenverarbeitung.",
|
||||
"plansCommon.apiRateLimitUnit": "{{count,number}}",
|
||||
@ -91,7 +91,7 @@
|
||||
"plansCommon.freeTrialTipPrefix": "Melden Sie sich an und erhalten Sie ein",
|
||||
"plansCommon.freeTrialTipSuffix": "Keine Kreditkarte erforderlich",
|
||||
"plansCommon.getStarted": "Loslegen",
|
||||
"plansCommon.logsHistory": "Protokollverlauf",
|
||||
"plansCommon.logsHistory": "{{days}} Protokollverlauf",
|
||||
"plansCommon.member": "Mitglied",
|
||||
"plansCommon.memberAfter": "Mitglied",
|
||||
"plansCommon.messageRequest.title": "Nachrichtenguthaben",
|
||||
@ -144,7 +144,7 @@
|
||||
"plansCommon.unavailable": "Nicht verfügbar",
|
||||
"plansCommon.unlimited": "Unbegrenzt",
|
||||
"plansCommon.unlimitedApiRate": "Keine API-Ratebeschränkung",
|
||||
"plansCommon.vectorSpace": "Vektorraum",
|
||||
"plansCommon.vectorSpace": "{{size}} Vektorraum",
|
||||
"plansCommon.vectorSpaceTooltip": "Vektorraum ist das Langzeitspeichersystem, das erforderlich ist, damit LLMs Ihre Daten verstehen können.",
|
||||
"plansCommon.workflowExecution.faster": "Schnellere Arbeitsablauf-Ausführung",
|
||||
"plansCommon.workflowExecution.priority": "Prioritäts-Workflow-Ausführung",
|
||||
|
||||
@ -61,6 +61,7 @@
|
||||
"account.workspaceName": "Arbeitsbereichsname",
|
||||
"account.workspaceNamePlaceholder": "Arbeitsbereichnamen eingeben",
|
||||
"actionMsg.copySuccessfully": "Erfolgreich kopiert",
|
||||
"actionMsg.downloadUnsuccessfully": "Download fehlgeschlagen. Bitte versuchen Sie es später erneut.",
|
||||
"actionMsg.generatedSuccessfully": "Erfolgreich generiert",
|
||||
"actionMsg.generatedUnsuccessfully": "Generierung nicht erfolgreich",
|
||||
"actionMsg.modifiedSuccessfully": "Erfolgreich geändert",
|
||||
@ -91,6 +92,7 @@
|
||||
"apiBasedExtension.title": "API-Erweiterungen bieten zentralisiertes API-Management und vereinfachen die Konfiguration für eine einfache Verwendung in Difys Anwendungen.",
|
||||
"apiBasedExtension.type": "Typ",
|
||||
"appMenus.apiAccess": "API-Zugriff",
|
||||
"appMenus.apiAccessTip": "Diese Wissensdatenbank ist über die Service-API zugänglich",
|
||||
"appMenus.logAndAnn": "Protokolle & Ank.",
|
||||
"appMenus.logs": "Baumstämme",
|
||||
"appMenus.overview": "Übersicht",
|
||||
@ -172,7 +174,7 @@
|
||||
"fileUploader.pasteFileLinkInvalid": "Ungültiger Dateilink",
|
||||
"fileUploader.uploadDisabled": "Datei-Upload ist deaktiviert",
|
||||
"fileUploader.uploadFromComputer": "Lokaler Upload",
|
||||
"fileUploader.uploadFromComputerLimit": "Datei hochladen darf {{size}} nicht überschreiten",
|
||||
"fileUploader.uploadFromComputerLimit": "Der Upload von {{type}} darf {{size}} nicht überschreiten",
|
||||
"fileUploader.uploadFromComputerReadError": "Lesen der Datei fehlgeschlagen, bitte versuchen Sie es erneut.",
|
||||
"fileUploader.uploadFromComputerUploadError": "Datei-Upload fehlgeschlagen, bitte erneut hochladen.",
|
||||
"imageInput.browse": "blättern",
|
||||
|
||||
@ -140,7 +140,7 @@
|
||||
"stepTwo.preview": "Bestätigen & Vorschau",
|
||||
"stepTwo.previewButton": "Umschalten zum Frage-und-Antwort-Format",
|
||||
"stepTwo.previewChunk": "Vorschau Chunk",
|
||||
"stepTwo.previewChunkCount": "{{Anzahl}} Geschätzte Chunks",
|
||||
"stepTwo.previewChunkCount": "{{count}} Geschätzte Chunks",
|
||||
"stepTwo.previewChunkTip": "Klicken Sie auf die Schaltfläche \"Preview Chunk\" auf der linken Seite, um die Vorschau zu laden",
|
||||
"stepTwo.previewSwitchTipEnd": " zusätzliche Tokens verbrauchen",
|
||||
"stepTwo.previewSwitchTipStart": "Die aktuelle Chunk-Vorschau ist im Textformat, ein Wechsel zur Vorschau im Frage-und-Antwort-Format wird",
|
||||
|
||||
@ -26,6 +26,7 @@
|
||||
"list.action.archive": "Archivieren",
|
||||
"list.action.batchAdd": "Batch hinzufügen",
|
||||
"list.action.delete": "Löschen",
|
||||
"list.action.download": "Herunterladen",
|
||||
"list.action.enableWarning": "Archivierte Datei kann nicht aktiviert werden",
|
||||
"list.action.pause": "Pause",
|
||||
"list.action.resume": "Fortsetzen",
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
"dateTimeFormat": "MM/DD/YYYY hh:mm A",
|
||||
"desc": "Testen Sie die Treffereffektivität des Wissens anhand des gegebenen Abfragetextes.",
|
||||
"hit.emptyTip": "Ergebnisse des Abruf-Tests werden hier angezeigt",
|
||||
"hit.title": "ABRUFPARAGRAFEN",
|
||||
"hit.title": "{{num}} Abgerufene Chunks",
|
||||
"hitChunks": "Klicken Sie auf {{num}} untergeordnete Chunks",
|
||||
"imageUploader.dropZoneTip": "Datei hierher ziehen, um sie hochzuladen",
|
||||
"imageUploader.singleChunkAttachmentLimitTooltip": "Die Anzahl der Einzelblock-Anhänge darf {{limit}} nicht überschreiten",
|
||||
|
||||
@ -16,7 +16,7 @@
|
||||
"form.indexMethod": "Indexierungsmethode",
|
||||
"form.indexMethodChangeToEconomyDisabledTip": "Nicht verfügbar für ein Downgrade von HQ auf ECO",
|
||||
"form.indexMethodEconomy": "Ökonomisch",
|
||||
"form.indexMethodEconomyTip": "Verwendet Offline-Vektor-Engines, Schlagwortindizes usw., um die Genauigkeit ohne Tokenverbrauch zu reduzieren",
|
||||
"form.indexMethodEconomyTip": "Verwendet {{count}} Schlüsselwörter pro Chunk für den Abruf, ohne Tokenverbrauch, auf Kosten geringerer Genauigkeit.",
|
||||
"form.indexMethodHighQuality": "Hohe Qualität",
|
||||
"form.indexMethodHighQualityTip": "Den Embedding-Modell zur Verarbeitung aufrufen, um bei Benutzeranfragen eine höhere Genauigkeit zu bieten.",
|
||||
"form.me": "(Sie)",
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
"batchAction.cancel": "Abbrechen",
|
||||
"batchAction.delete": "Löschen",
|
||||
"batchAction.disable": "Abschalten",
|
||||
"batchAction.download": "Herunterladen",
|
||||
"batchAction.enable": "Ermöglichen",
|
||||
"batchAction.reIndex": "Neu indexieren",
|
||||
"batchAction.selected": "Ausgewählt",
|
||||
|
||||
@ -81,7 +81,7 @@
|
||||
"debugInfo.title": "Debuggen",
|
||||
"debugInfo.viewDocs": "Dokumente anzeigen",
|
||||
"deprecated": "Abgelehnt",
|
||||
"detailPanel.actionNum": "{{num}} {{Aktion}} IINKLUSIVE",
|
||||
"detailPanel.actionNum": "{{num}} {{action}} IINKLUSIVE",
|
||||
"detailPanel.categoryTip.debugging": "Debuggen-Plugin",
|
||||
"detailPanel.categoryTip.github": "Installiert von Github",
|
||||
"detailPanel.categoryTip.local": "Lokales Plugin",
|
||||
@ -116,7 +116,7 @@
|
||||
"detailPanel.operation.update": "Aktualisieren",
|
||||
"detailPanel.operation.viewDetail": "Im Detail sehen",
|
||||
"detailPanel.serviceOk": "Service in Ordnung",
|
||||
"detailPanel.strategyNum": "{{num}} {{Strategie}} IINKLUSIVE",
|
||||
"detailPanel.strategyNum": "{{num}} {{strategy}} IINKLUSIVE",
|
||||
"detailPanel.switchVersion": "Version wechseln",
|
||||
"detailPanel.toolSelector.auto": "Auto",
|
||||
"detailPanel.toolSelector.descriptionLabel": "Beschreibung des Werkzeugs",
|
||||
@ -236,7 +236,7 @@
|
||||
"task.installSuccess": "{{successLength}} plugins installed successfully",
|
||||
"task.installed": "Installed",
|
||||
"task.installedError": "{{errorLength}} Plugins konnten nicht installiert werden",
|
||||
"task.installing": "Installation von {{installingLength}} Plugins, 0 erledigt.",
|
||||
"task.installing": "Plugins werden installiert.",
|
||||
"task.installingWithError": "Installation von {{installingLength}} Plugins, {{successLength}} erfolgreich, {{errorLength}} fehlgeschlagen",
|
||||
"task.installingWithSuccess": "Installation von {{installingLength}} Plugins, {{successLength}} erfolgreich.",
|
||||
"task.runningPlugins": "Installing Plugins",
|
||||
|
||||
@ -99,7 +99,7 @@
|
||||
"createTool.viewSchemaSpec": "Die OpenAPI-Swagger-Spezifikation anzeigen",
|
||||
"customToolTip": "Erfahren Sie mehr über benutzerdefinierte Dify-Tools",
|
||||
"howToGet": "Wie erhält man",
|
||||
"includeToolNum": "{{num}} Werkzeuge inkludiert",
|
||||
"includeToolNum": "{{num}} {{action}} inkludiert",
|
||||
"mcp.authorize": "Autorisieren",
|
||||
"mcp.authorizeTip": "Nach der Autorisierung werden Tools hier angezeigt.",
|
||||
"mcp.authorizing": "Wird autorisiert...",
|
||||
|
||||
@ -363,7 +363,7 @@
|
||||
"nodes.agent.strategyNotFoundDescAndSwitchVersion": "Die installierte Plugin-Version bietet diese Strategie nicht. Klicken Sie hier, um die Version zu wechseln.",
|
||||
"nodes.agent.strategyNotInstallTooltip": "{{strategy}} ist nicht installiert",
|
||||
"nodes.agent.strategyNotSet": "Agentische Strategie nicht festgelegt",
|
||||
"nodes.agent.toolNotAuthorizedTooltip": "{{Werkzeug}} Nicht autorisiert",
|
||||
"nodes.agent.toolNotAuthorizedTooltip": "{{tool}} Nicht autorisiert",
|
||||
"nodes.agent.toolNotInstallTooltip": "{{tool}} ist nicht installiert",
|
||||
"nodes.agent.toolbox": "Werkzeugkasten",
|
||||
"nodes.agent.tools": "Werkzeuge",
|
||||
@ -549,8 +549,8 @@
|
||||
"nodes.iteration.deleteDesc": "Das Löschen des Iterationsknotens löscht alle untergeordneten Knoten",
|
||||
"nodes.iteration.deleteTitle": "Iterationsknoten löschen?",
|
||||
"nodes.iteration.errorResponseMethod": "Methode der Fehlerantwort",
|
||||
"nodes.iteration.error_one": "{{Anzahl}} Fehler",
|
||||
"nodes.iteration.error_other": "{{Anzahl}} Irrtümer",
|
||||
"nodes.iteration.error_one": "{{count}} Fehler",
|
||||
"nodes.iteration.error_other": "{{count}} Fehler",
|
||||
"nodes.iteration.flattenOutput": "Ausgabe abflachen",
|
||||
"nodes.iteration.flattenOutputDesc": "Wenn aktiviert, werden alle Iterationsergebnisse, die Arrays sind, in ein einzelnes Array zusammengeführt. Wenn deaktiviert, behalten die Ergebnisse eine verschachtelte Array-Struktur bei.",
|
||||
"nodes.iteration.input": "Eingabe",
|
||||
|
||||
@ -83,7 +83,7 @@
|
||||
"gotoAnything.emptyState.noKnowledgeBasesFound": "No se han encontrado bases de conocimiento",
|
||||
"gotoAnything.emptyState.noPluginsFound": "No se encontraron complementos",
|
||||
"gotoAnything.emptyState.noWorkflowNodesFound": "No se encontraron nodos de flujo de trabajo",
|
||||
"gotoAnything.emptyState.tryDifferentTerm": "Intenta un término de búsqueda diferente o elimina el filtro {{mode}}",
|
||||
"gotoAnything.emptyState.tryDifferentTerm": "Intenta un término de búsqueda diferente",
|
||||
"gotoAnything.emptyState.trySpecificSearch": "Prueba {{shortcuts}} para búsquedas específicas",
|
||||
"gotoAnything.groups.apps": "Aplicaciones",
|
||||
"gotoAnything.groups.commands": "Comandos",
|
||||
@ -161,8 +161,8 @@
|
||||
"newApp.dropDSLToCreateApp": "Suelta el archivo DSL aquí para crear la aplicación",
|
||||
"newApp.forAdvanced": "PARA USUARIOS AVANZADOS",
|
||||
"newApp.forBeginners": "Tipos de aplicación más básicos",
|
||||
"newApp.foundResult": "{{conteo}} Resultado",
|
||||
"newApp.foundResults": "{{conteo}} Resultados",
|
||||
"newApp.foundResult": "{{count}} Resultado",
|
||||
"newApp.foundResults": "{{count}} Resultados",
|
||||
"newApp.hideTemplates": "Volver a la selección de modo",
|
||||
"newApp.import": "Importación",
|
||||
"newApp.learnMore": "Aprende más",
|
||||
|
||||
@ -65,7 +65,7 @@
|
||||
"plansCommon.annotatedResponse.title": "Límites de Cuota de Anotación",
|
||||
"plansCommon.annotatedResponse.tooltip": "Edición manual y anotación de respuestas proporciona habilidades de respuesta a preguntas personalizadas y de alta calidad para aplicaciones (aplicable solo en aplicaciones de chat).",
|
||||
"plansCommon.annotationQuota": "Cuota de Anotación",
|
||||
"plansCommon.annualBilling": "Facturación Anual",
|
||||
"plansCommon.annualBilling": "Facturación anual, ahorra {{percent}}%",
|
||||
"plansCommon.apiRateLimit": "Límite de tasa de API",
|
||||
"plansCommon.apiRateLimitTooltip": "El límite de tasa de la API se aplica a todas las solicitudes realizadas a través de la API de Dify, incluidos la generación de texto, las conversaciones de chat, las ejecuciones de flujo de trabajo y el procesamiento de documentos.",
|
||||
"plansCommon.apiRateLimitUnit": "{{count, número}}",
|
||||
@ -91,7 +91,7 @@
|
||||
"plansCommon.freeTrialTipPrefix": "Regístrate y obtén un",
|
||||
"plansCommon.freeTrialTipSuffix": "No se requiere tarjeta de crédito",
|
||||
"plansCommon.getStarted": "Comenzar",
|
||||
"plansCommon.logsHistory": "Historial de Registros",
|
||||
"plansCommon.logsHistory": "{{days}} Historial de registros",
|
||||
"plansCommon.member": "Miembro",
|
||||
"plansCommon.memberAfter": "Miembro",
|
||||
"plansCommon.messageRequest.title": "Créditos de Mensajes",
|
||||
@ -144,7 +144,7 @@
|
||||
"plansCommon.unavailable": "No disponible",
|
||||
"plansCommon.unlimited": "Ilimitado",
|
||||
"plansCommon.unlimitedApiRate": "Sin límite de tasa de API",
|
||||
"plansCommon.vectorSpace": "Espacio Vectorial",
|
||||
"plansCommon.vectorSpace": "{{size}} Espacio vectorial",
|
||||
"plansCommon.vectorSpaceTooltip": "El Espacio Vectorial es el sistema de memoria a largo plazo necesario para que los LLMs comprendan tus datos.",
|
||||
"plansCommon.workflowExecution.faster": "Ejecución de flujo de trabajo más rápida",
|
||||
"plansCommon.workflowExecution.priority": "Ejecución de flujo de trabajo prioritaria",
|
||||
|
||||
@ -61,6 +61,7 @@
|
||||
"account.workspaceName": "Nombre del espacio de trabajo",
|
||||
"account.workspaceNamePlaceholder": "Ingrese el nombre del espacio de trabajo",
|
||||
"actionMsg.copySuccessfully": "Copiado exitosamente",
|
||||
"actionMsg.downloadUnsuccessfully": "Descarga fallida. Por favor, inténtelo de nuevo más tarde.",
|
||||
"actionMsg.generatedSuccessfully": "Generado exitosamente",
|
||||
"actionMsg.generatedUnsuccessfully": "Generación no exitosa",
|
||||
"actionMsg.modifiedSuccessfully": "Modificado exitosamente",
|
||||
@ -91,6 +92,7 @@
|
||||
"apiBasedExtension.title": "Las extensiones basadas en API proporcionan una gestión centralizada de API, simplificando la configuración para su fácil uso en las aplicaciones de Dify.",
|
||||
"apiBasedExtension.type": "Tipo",
|
||||
"appMenus.apiAccess": "Acceso API",
|
||||
"appMenus.apiAccessTip": "Esta base de conocimiento es accesible a través de la API de servicio",
|
||||
"appMenus.logAndAnn": "Registros y Anuncios",
|
||||
"appMenus.logs": "Registros",
|
||||
"appMenus.overview": "Monitoreo",
|
||||
@ -172,7 +174,7 @@
|
||||
"fileUploader.pasteFileLinkInvalid": "Enlace de archivo no válido",
|
||||
"fileUploader.uploadDisabled": "La carga de archivos está deshabilitada",
|
||||
"fileUploader.uploadFromComputer": "Carga local",
|
||||
"fileUploader.uploadFromComputerLimit": "El archivo de carga no puede exceder {{size}}",
|
||||
"fileUploader.uploadFromComputerLimit": "La carga de {{type}} no puede exceder {{size}}",
|
||||
"fileUploader.uploadFromComputerReadError": "Error en la lectura del archivo, inténtelo de nuevo.",
|
||||
"fileUploader.uploadFromComputerUploadError": "Error en la carga del archivo, vuelva a cargarlo.",
|
||||
"imageInput.browse": "navegar",
|
||||
|
||||
@ -140,7 +140,7 @@
|
||||
"stepTwo.preview": "Confirmar y vista previa",
|
||||
"stepTwo.previewButton": "Cambiar a formato de pregunta y respuesta",
|
||||
"stepTwo.previewChunk": "Fragmento de vista previa",
|
||||
"stepTwo.previewChunkCount": "{{conteo}} Fragmentos estimados",
|
||||
"stepTwo.previewChunkCount": "{{count}} Fragmentos estimados",
|
||||
"stepTwo.previewChunkTip": "Haga clic en el botón 'Vista previa de fragmento' a la izquierda para cargar la vista previa",
|
||||
"stepTwo.previewSwitchTipEnd": " consumirá tokens adicionales",
|
||||
"stepTwo.previewSwitchTipStart": "La vista previa actual del fragmento está en formato de texto, cambiar a una vista previa en formato de pregunta y respuesta",
|
||||
|
||||
@ -26,6 +26,7 @@
|
||||
"list.action.archive": "Archivar",
|
||||
"list.action.batchAdd": "Agregar en lotes",
|
||||
"list.action.delete": "Eliminar",
|
||||
"list.action.download": "Descargar",
|
||||
"list.action.enableWarning": "El archivo archivado no puede habilitarse",
|
||||
"list.action.pause": "Pausa",
|
||||
"list.action.resume": "Reanudar",
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
"dateTimeFormat": "MM/DD/YYYY hh:mm A",
|
||||
"desc": "Prueba del efecto de impacto del conocimiento basado en el texto de consulta proporcionado.",
|
||||
"hit.emptyTip": "Los resultados de la prueba de recuperación se mostrarán aquí",
|
||||
"hit.title": "PÁRRAFOS DE RECUPERACIÓN",
|
||||
"hit.title": "{{num}} Párrafos recuperados",
|
||||
"hitChunks": "Golpea {{num}} fragmentos secundarios",
|
||||
"imageUploader.dropZoneTip": "Arrastra el archivo aquí para subirlo",
|
||||
"imageUploader.singleChunkAttachmentLimitTooltip": "El número de archivos adjuntos de un solo bloque no puede superar {{limit}}",
|
||||
|
||||
@ -16,7 +16,7 @@
|
||||
"form.indexMethod": "Método de indexación",
|
||||
"form.indexMethodChangeToEconomyDisabledTip": "No disponible para degradar de HQ a ECO",
|
||||
"form.indexMethodEconomy": "Económico",
|
||||
"form.indexMethodEconomyTip": "Utiliza motores de vectores sin conexión, índices de palabras clave, etc. para reducir la precisión sin gastar tokens.",
|
||||
"form.indexMethodEconomyTip": "Utiliza {{count}} palabras clave por fragmento para la recuperación, sin consumir tokens a costa de una menor precisión.",
|
||||
"form.indexMethodHighQuality": "Alta calidad",
|
||||
"form.indexMethodHighQualityTip": "Llama al modelo de incrustación para procesar y proporcionar una mayor precisión cuando los usuarios realizan consultas.",
|
||||
"form.me": "(Tú)",
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
"batchAction.cancel": "Cancelar",
|
||||
"batchAction.delete": "Borrar",
|
||||
"batchAction.disable": "Inutilizar",
|
||||
"batchAction.download": "Descargar",
|
||||
"batchAction.enable": "Habilitar",
|
||||
"batchAction.reIndex": "Reindexar",
|
||||
"batchAction.selected": "Seleccionado",
|
||||
|
||||
@ -81,7 +81,7 @@
|
||||
"debugInfo.title": "Depuración",
|
||||
"debugInfo.viewDocs": "Ver documentos",
|
||||
"deprecated": "Obsoleto",
|
||||
"detailPanel.actionNum": "{{num}} {{acción}} INCLUIDO",
|
||||
"detailPanel.actionNum": "{{num}} {{action}} INCLUIDO",
|
||||
"detailPanel.categoryTip.debugging": "Complemento de depuración",
|
||||
"detailPanel.categoryTip.github": "Instalado desde Github",
|
||||
"detailPanel.categoryTip.local": "Plugin Local",
|
||||
@ -96,7 +96,7 @@
|
||||
"detailPanel.deprecation.reason.noMaintainer": "sin mantenedor",
|
||||
"detailPanel.deprecation.reason.ownershipTransferred": "propiedad transferida",
|
||||
"detailPanel.disabled": "Deshabilitado",
|
||||
"detailPanel.endpointDeleteContent": "¿Te gustaría eliminar {{nombre}}?",
|
||||
"detailPanel.endpointDeleteContent": "¿Te gustaría eliminar {{name}}?",
|
||||
"detailPanel.endpointDeleteTip": "Eliminar punto de conexión",
|
||||
"detailPanel.endpointDisableContent": "¿Te gustaría desactivar {{name}}?",
|
||||
"detailPanel.endpointDisableTip": "Deshabilitar punto de conexión",
|
||||
@ -116,7 +116,7 @@
|
||||
"detailPanel.operation.update": "Actualizar",
|
||||
"detailPanel.operation.viewDetail": "Ver Detalle",
|
||||
"detailPanel.serviceOk": "Servicio OK",
|
||||
"detailPanel.strategyNum": "{{num}} {{estrategia}} INCLUIDO",
|
||||
"detailPanel.strategyNum": "{{num}} {{strategy}} INCLUIDO",
|
||||
"detailPanel.switchVersion": "Versión del interruptor",
|
||||
"detailPanel.toolSelector.auto": "Auto",
|
||||
"detailPanel.toolSelector.descriptionLabel": "Descripción de la herramienta",
|
||||
@ -236,7 +236,7 @@
|
||||
"task.installSuccess": "{{successLength}} plugins installed successfully",
|
||||
"task.installed": "Installed",
|
||||
"task.installedError": "Los complementos {{errorLength}} no se pudieron instalar",
|
||||
"task.installing": "Instalando plugins {{installingLength}}, 0 hecho.",
|
||||
"task.installing": "Instalando plugins.",
|
||||
"task.installingWithError": "Instalando plugins {{installingLength}}, {{successLength}} éxito, {{errorLength}} fallido",
|
||||
"task.installingWithSuccess": "Instalando plugins {{installingLength}}, {{successLength}} éxito.",
|
||||
"task.runningPlugins": "Installing Plugins",
|
||||
|
||||
@ -99,7 +99,7 @@
|
||||
"createTool.viewSchemaSpec": "Ver la Especificación OpenAPI-Swagger",
|
||||
"customToolTip": "Aprende más sobre las herramientas personalizadas de Dify",
|
||||
"howToGet": "Cómo obtener",
|
||||
"includeToolNum": "{{num}} herramientas incluidas",
|
||||
"includeToolNum": "{{num}} {{action}} incluidas",
|
||||
"mcp.authorize": "Autorizar",
|
||||
"mcp.authorizeTip": "Tras la autorización, las herramientas se mostrarán aquí.",
|
||||
"mcp.authorizing": "Autorizando...",
|
||||
|
||||
@ -303,10 +303,10 @@
|
||||
"errorMsg.fields.visionVariable": "Variable de visión",
|
||||
"errorMsg.invalidJson": "{{field}} no es un JSON válido",
|
||||
"errorMsg.invalidVariable": "Variable no válida",
|
||||
"errorMsg.noValidTool": "{{campo}} no se ha seleccionado ninguna herramienta válida",
|
||||
"errorMsg.noValidTool": "{{field}} no se ha seleccionado ninguna herramienta válida",
|
||||
"errorMsg.rerankModelRequired": "Antes de activar el modelo de reclasificación, confirme que el modelo se ha configurado correctamente en la configuración.",
|
||||
"errorMsg.startNodeRequired": "Por favor, agregue primero un nodo de inicio antes de {{operation}}",
|
||||
"errorMsg.toolParameterRequired": "{{campo}}: el parámetro [{{param}}] es obligatorio",
|
||||
"errorMsg.toolParameterRequired": "{{field}}: el parámetro [{{param}}] es obligatorio",
|
||||
"globalVar.description": "Las variables del sistema son variables globales que cualquier nodo puede usar sin conexiones cuando el tipo es correcto, como el ID del usuario final y el ID del flujo de trabajo.",
|
||||
"globalVar.fieldsDescription.appId": "ID de la aplicación",
|
||||
"globalVar.fieldsDescription.conversationId": "ID de la conversación",
|
||||
@ -361,10 +361,10 @@
|
||||
"nodes.agent.strategy.tooltip": "Diferentes estrategias agentic determinan cómo el sistema planifica y ejecuta las llamadas a herramientas de varios pasos",
|
||||
"nodes.agent.strategyNotFoundDesc": "La versión del plugin instalado no proporciona esta estrategia.",
|
||||
"nodes.agent.strategyNotFoundDescAndSwitchVersion": "La versión del plugin instalado no proporciona esta estrategia. Haga clic para cambiar de versión.",
|
||||
"nodes.agent.strategyNotInstallTooltip": "{{estrategia}} no está instalado",
|
||||
"nodes.agent.strategyNotInstallTooltip": "{{strategy}} no está instalado",
|
||||
"nodes.agent.strategyNotSet": "Estrategia agentica No establecida",
|
||||
"nodes.agent.toolNotAuthorizedTooltip": "{{herramienta}} No autorizado",
|
||||
"nodes.agent.toolNotInstallTooltip": "{{herramienta}} no está instalada",
|
||||
"nodes.agent.toolNotAuthorizedTooltip": "{{tool}} No autorizado",
|
||||
"nodes.agent.toolNotInstallTooltip": "{{tool}} no está instalada",
|
||||
"nodes.agent.toolbox": "caja de herramientas",
|
||||
"nodes.agent.tools": "Herramientas",
|
||||
"nodes.agent.unsupportedStrategy": "Estrategia no respaldada",
|
||||
@ -438,7 +438,7 @@
|
||||
"nodes.common.retry.retries": "{{num}} Reintentos",
|
||||
"nodes.common.retry.retry": "Reintentar",
|
||||
"nodes.common.retry.retryFailed": "Error en el reintento",
|
||||
"nodes.common.retry.retryFailedTimes": "{{veces}} reintentos fallidos",
|
||||
"nodes.common.retry.retryFailedTimes": "{{times}} reintentos fallidos",
|
||||
"nodes.common.retry.retryInterval": "Intervalo de reintento",
|
||||
"nodes.common.retry.retryOnFailure": "Volver a intentarlo en caso de error",
|
||||
"nodes.common.retry.retrySuccessful": "Volver a intentarlo correctamente",
|
||||
@ -453,7 +453,7 @@
|
||||
"nodes.docExtractor.inputVar": "Variable de entrada",
|
||||
"nodes.docExtractor.learnMore": "Aprende más",
|
||||
"nodes.docExtractor.outputVars.text": "Texto extraído",
|
||||
"nodes.docExtractor.supportFileTypes": "Tipos de archivos de soporte: {{tipos}}.",
|
||||
"nodes.docExtractor.supportFileTypes": "Tipos de archivos de soporte: {{types}}.",
|
||||
"nodes.end.output.type": "tipo de salida",
|
||||
"nodes.end.output.variable": "variable de salida",
|
||||
"nodes.end.outputs": "Salidas",
|
||||
@ -549,8 +549,8 @@
|
||||
"nodes.iteration.deleteDesc": "Eliminar el nodo de iteración eliminará todos los nodos secundarios",
|
||||
"nodes.iteration.deleteTitle": "¿Eliminar nodo de iteración?",
|
||||
"nodes.iteration.errorResponseMethod": "Método de respuesta a errores",
|
||||
"nodes.iteration.error_one": "{{conteo}} Error",
|
||||
"nodes.iteration.error_other": "{{conteo}} Errores",
|
||||
"nodes.iteration.error_one": "{{count}} Error",
|
||||
"nodes.iteration.error_other": "{{count}} Errores",
|
||||
"nodes.iteration.flattenOutput": "Aplanar salida",
|
||||
"nodes.iteration.flattenOutputDesc": "Cuando está habilitado, si todas las salidas de la iteración son arrays, se aplanarán en un solo array. Cuando está deshabilitado, las salidas mantendrán una estructura de array anidada.",
|
||||
"nodes.iteration.input": "Entrada",
|
||||
|
||||
@ -83,7 +83,7 @@
|
||||
"gotoAnything.emptyState.noKnowledgeBasesFound": "هیچ پایگاه دانش یافت نشد",
|
||||
"gotoAnything.emptyState.noPluginsFound": "هیچ افزونه ای یافت نشد",
|
||||
"gotoAnything.emptyState.noWorkflowNodesFound": "هیچ گره گردش کاری یافت نشد",
|
||||
"gotoAnything.emptyState.tryDifferentTerm": "یک عبارت جستجوی متفاوت را امتحان کنید یا فیلتر {{mode}} را حذف کنید",
|
||||
"gotoAnything.emptyState.tryDifferentTerm": "یک عبارت جستجوی متفاوت را امتحان کنید",
|
||||
"gotoAnything.emptyState.trySpecificSearch": "{{shortcuts}} را برای جستجوهای خاص امتحان کنید",
|
||||
"gotoAnything.groups.apps": "برنامهها",
|
||||
"gotoAnything.groups.commands": "دستورات",
|
||||
|
||||
@ -65,7 +65,7 @@
|
||||
"plansCommon.annotatedResponse.title": "محدودیتهای سهمیه حاشیهنویسی",
|
||||
"plansCommon.annotatedResponse.tooltip": "ویرایش دستی و حاشیهنویسی پاسخها، قابلیتهای پرسش و پاسخ با کیفیت بالا و قابل تنظیم برای اپلیکیشنها را فراهم میکند. (فقط در اپلیکیشنهای چت اعمال میشود)",
|
||||
"plansCommon.annotationQuota": "سهمیه حاشیهنویسی",
|
||||
"plansCommon.annualBilling": "صورتحساب سالانه",
|
||||
"plansCommon.annualBilling": "صورتحساب سالانه، صرفهجویی {{percent}}%",
|
||||
"plansCommon.apiRateLimit": "محدودیت نرخ API",
|
||||
"plansCommon.apiRateLimitTooltip": "محدودیت نرخ API برای همه درخواستهای انجام شده از طریق API Dify اعمال میشود، از جمله تولید متن، محاورههای چت، اجرای گردشهای کار و پردازش اسناد.",
|
||||
"plansCommon.apiRateLimitUnit": "{{count,number}}",
|
||||
@ -91,7 +91,7 @@
|
||||
"plansCommon.freeTrialTipPrefix": "ثبتنام کنید و یک",
|
||||
"plansCommon.freeTrialTipSuffix": "نیاز به کارت اعتباری نیست",
|
||||
"plansCommon.getStarted": "شروع کنید",
|
||||
"plansCommon.logsHistory": "تاریخچه گزارشات",
|
||||
"plansCommon.logsHistory": "{{days}} تاریخچه گزارشات",
|
||||
"plansCommon.member": "عضو",
|
||||
"plansCommon.memberAfter": "عضو",
|
||||
"plansCommon.messageRequest.title": "اعتبارات پیام",
|
||||
@ -144,7 +144,7 @@
|
||||
"plansCommon.unavailable": "غیرقابل دسترس",
|
||||
"plansCommon.unlimited": "نامحدود",
|
||||
"plansCommon.unlimitedApiRate": "هیچ محدودیتی برای نرخ API وجود ندارد.",
|
||||
"plansCommon.vectorSpace": "فضای وکتور",
|
||||
"plansCommon.vectorSpace": "{{size}} فضای وکتور",
|
||||
"plansCommon.vectorSpaceTooltip": "فضای وکتور سیستم حافظه بلند مدت است که برای درک دادههای شما توسط LLMها مورد نیاز است.",
|
||||
"plansCommon.workflowExecution.faster": "اجرای سریعتر جریان کاری",
|
||||
"plansCommon.workflowExecution.priority": "اجرای جریان کاری اولویتدار",
|
||||
|
||||
@ -61,6 +61,7 @@
|
||||
"account.workspaceName": "نام فضای کاری",
|
||||
"account.workspaceNamePlaceholder": "نام فضای کاری را وارد کنید",
|
||||
"actionMsg.copySuccessfully": "با موفقیت کپی شد",
|
||||
"actionMsg.downloadUnsuccessfully": "دانلود ناموفق بود. لطفاً بعداً دوباره امتحان کنید.",
|
||||
"actionMsg.generatedSuccessfully": "با موفقیت تولید شد",
|
||||
"actionMsg.generatedUnsuccessfully": "تولید ناموفق بود",
|
||||
"actionMsg.modifiedSuccessfully": "با موفقیت تغییر یافت",
|
||||
@ -91,6 +92,7 @@
|
||||
"apiBasedExtension.title": "افزونههای مبتنی بر API مدیریت متمرکز API را فراهم میکنند و پیکربندی را برای استفاده آسان در برنامههای Dify ساده میکنند.",
|
||||
"apiBasedExtension.type": "نوع",
|
||||
"appMenus.apiAccess": "دسترسی API",
|
||||
"appMenus.apiAccessTip": "این پایگاه دانش از طریق API سرویس قابل دسترسی است",
|
||||
"appMenus.logAndAnn": "گزارشها و اعلانات",
|
||||
"appMenus.logs": "گزارشها",
|
||||
"appMenus.overview": "نظارت",
|
||||
@ -108,7 +110,7 @@
|
||||
"chat.conversationName": "نام مکالمه",
|
||||
"chat.conversationNameCanNotEmpty": "نام مکالمه الزامی است",
|
||||
"chat.conversationNamePlaceholder": "لطفاً نام مکالمه را وارد کنید",
|
||||
"chat.inputPlaceholder": "با ربات صحبت کنید",
|
||||
"chat.inputPlaceholder": "با {{botName}} صحبت کنید",
|
||||
"chat.renameConversation": "تغییر نام مکالمه",
|
||||
"chat.resend": "دوباره ارسال کنید",
|
||||
"chat.thinking": "تفکر...",
|
||||
@ -172,7 +174,7 @@
|
||||
"fileUploader.pasteFileLinkInvalid": "پیوند فایل نامعتبر",
|
||||
"fileUploader.uploadDisabled": "بارگذاری فایل غیرفعال است",
|
||||
"fileUploader.uploadFromComputer": "آپلود محلی",
|
||||
"fileUploader.uploadFromComputerLimit": "آپلود فایل نمی تواند از {{size}} تجاوز کند",
|
||||
"fileUploader.uploadFromComputerLimit": "آپلود {{type}} نمی تواند از {{size}} تجاوز کند",
|
||||
"fileUploader.uploadFromComputerReadError": "خواندن فایل انجام نشد، لطفا دوباره امتحان کنید.",
|
||||
"fileUploader.uploadFromComputerUploadError": "آپلود فایل انجام نشد، لطفا دوباره آپلود کنید.",
|
||||
"imageInput.browse": "مرورگر",
|
||||
|
||||
@ -140,7 +140,7 @@
|
||||
"stepTwo.preview": "تأیید و پیشنمایش",
|
||||
"stepTwo.previewButton": "تغییر به قالب پرسش و پاسخ",
|
||||
"stepTwo.previewChunk": "پیش نمایش تکه",
|
||||
"stepTwo.previewChunkCount": "{{تعداد}} تکه های تخمینی",
|
||||
"stepTwo.previewChunkCount": "{{count}} تکه های تخمینی",
|
||||
"stepTwo.previewChunkTip": "روی دکمه \"پیش نمایش قطعه\" در سمت چپ کلیک کنید تا پیش نمایش بارگیری شود",
|
||||
"stepTwo.previewSwitchTipEnd": " توکنهای اضافی مصرف خواهد کرد",
|
||||
"stepTwo.previewSwitchTipStart": "پیشنمایش بخش فعلی در قالب متن است، تغییر به پیشنمایش قالب پرسش و پاسخ",
|
||||
|
||||
@ -26,6 +26,7 @@
|
||||
"list.action.archive": "بایگانی",
|
||||
"list.action.batchAdd": "افزودن گروهی",
|
||||
"list.action.delete": "حذف",
|
||||
"list.action.download": "دانلود",
|
||||
"list.action.enableWarning": "فایل بایگانی شده نمیتواند فعال شود",
|
||||
"list.action.pause": "مکث",
|
||||
"list.action.resume": "ادامه",
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
"dateTimeFormat": "MM/DD/YYYY hh:mm A",
|
||||
"desc": "آزمون اثرگذاری دانش بر اساس متن پرسش داده شده.",
|
||||
"hit.emptyTip": "نتایج آزمون بازیابی اینجا نمایش داده میشوند",
|
||||
"hit.title": "پاراگرافهای بازیابی",
|
||||
"hit.title": "{{num}} پاراگرافهای بازیابی",
|
||||
"hitChunks": "{{num}} را بزنید تکه های فرزند",
|
||||
"imageUploader.dropZoneTip": "فایل را اینجا بکشید تا بارگذاری شود",
|
||||
"imageUploader.singleChunkAttachmentLimitTooltip": "تعداد پیوستهای تک قطعهای نمیتواند از {{limit}} بیشتر باشد",
|
||||
|
||||
@ -16,7 +16,7 @@
|
||||
"form.indexMethod": "روش نمایهسازی",
|
||||
"form.indexMethodChangeToEconomyDisabledTip": "برای تنزل رتبه از HQ به ECO در دسترس نیست",
|
||||
"form.indexMethodEconomy": "اقتصادی",
|
||||
"form.indexMethodEconomyTip": "استفاده از موتورهای برداری آفلاین، شاخصهای کلمات کلیدی و غیره برای کاهش دقت بدون صرف توکنها",
|
||||
"form.indexMethodEconomyTip": "استفاده از {{count}} کلمه کلیدی برای هر تکه در بازیابی، بدون مصرف توکنها با کاهش دقت.",
|
||||
"form.indexMethodHighQuality": "کیفیت بالا",
|
||||
"form.indexMethodHighQualityTip": "مدل تعبیه را برای پردازش فراخوانی کنید تا دقت بالاتری هنگام جستجوی کاربران فراهم شود.",
|
||||
"form.me": "(شما)",
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
"batchAction.cancel": "لغو",
|
||||
"batchAction.delete": "حذف",
|
||||
"batchAction.disable": "غیر فعال کردن",
|
||||
"batchAction.download": "دانلود",
|
||||
"batchAction.enable": "فعال",
|
||||
"batchAction.reIndex": "بازفهرستگذاری",
|
||||
"batchAction.selected": "انتخاب",
|
||||
@ -147,7 +148,7 @@
|
||||
"parentMode.paragraph": "پاراگراف",
|
||||
"partialEnabled_one": "مجموعاً {{count}} سند، {{num}} موجود",
|
||||
"partialEnabled_other": "مجموع {{count}} سند، {{num}} موجود",
|
||||
"preprocessDocument": "{{عدد}} اسناد پیش پردازش",
|
||||
"preprocessDocument": "{{num}} اسناد پیش پردازش",
|
||||
"rerankSettings": "تنظیمات دوباره رتبهبندی",
|
||||
"retrieval.change": "تغییر",
|
||||
"retrieval.changeRetrievalMethod": "تغییر روش بازیابی",
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user