Merge branch 'main' into feat/r2

This commit is contained in:
jyong 2025-06-18 10:57:44 +08:00
commit f7a4e5d1a6
113 changed files with 1498 additions and 1809 deletions

3
.gitignore vendored
View File

@ -210,3 +210,6 @@ mise.toml
# Next.js build output
.next/
# AI Assistant
.roo/

View File

@ -9,7 +9,7 @@ class PackagingInfo(BaseSettings):
CURRENT_VERSION: str = Field(
description="Dify version",
default="1.4.2",
default="1.4.3",
)
COMMIT_SHA: str = Field(

View File

@ -163,7 +163,7 @@ def exchange_token_for_existing_web_user(app_code: str, enterprise_user_decoded:
)
db.session.add(end_user)
db.session.commit()
exp_dt = datetime.now(UTC) + timedelta(hours=dify_config.ACCESS_TOKEN_EXPIRE_MINUTES * 24)
exp_dt = datetime.now(UTC) + timedelta(minutes=dify_config.ACCESS_TOKEN_EXPIRE_MINUTES)
exp = int(exp_dt.timestamp())
payload = {
"iss": site.id,

View File

@ -5,7 +5,7 @@ import uuid
from collections.abc import Generator, Mapping
from typing import Any, Literal, Optional, Union, overload
from flask import Flask, copy_current_request_context, current_app, has_request_context
from flask import Flask, current_app
from pydantic import ValidationError
from sqlalchemy.orm import sessionmaker
@ -31,6 +31,7 @@ from core.workflow.repositories.workflow_execution_repository import WorkflowExe
from core.workflow.repositories.workflow_node_execution_repository import WorkflowNodeExecutionRepository
from extensions.ext_database import db
from factories import file_factory
from libs.flask_utils import preserve_flask_contexts
from models import Account, App, Conversation, EndUser, Message, Workflow, WorkflowNodeExecutionTriggeredFrom
from models.enums import WorkflowRunTriggeredFrom
from services.conversation_service import ConversationService
@ -399,20 +400,17 @@ class AdvancedChatAppGenerator(MessageBasedAppGenerator):
# new thread with request context and contextvars
context = contextvars.copy_context()
@copy_current_request_context
def worker_with_context():
# Run the worker within the copied context
return context.run(
self._generate_worker,
flask_app=current_app._get_current_object(), # type: ignore
application_generate_entity=application_generate_entity,
queue_manager=queue_manager,
conversation_id=conversation.id,
message_id=message.id,
context=context,
)
worker_thread = threading.Thread(target=worker_with_context)
worker_thread = threading.Thread(
target=self._generate_worker,
kwargs={
"flask_app": current_app._get_current_object(), # type: ignore
"application_generate_entity": application_generate_entity,
"queue_manager": queue_manager,
"conversation_id": conversation.id,
"message_id": message.id,
"context": context,
},
)
worker_thread.start()
@ -449,24 +447,9 @@ class AdvancedChatAppGenerator(MessageBasedAppGenerator):
:param message_id: message ID
:return:
"""
for var, val in context.items():
var.set(val)
# FIXME(-LAN-): Save current user before entering new app context
from flask import g
saved_user = None
if has_request_context() and hasattr(g, "_login_user"):
saved_user = g._login_user
with flask_app.app_context():
with preserve_flask_contexts(flask_app, context_vars=context):
try:
# Restore user in new app context
if saved_user is not None:
from flask import g
g._login_user = saved_user
# get conversation and message
conversation = self._get_conversation(conversation_id)
message = self._get_message(message_id)

View File

@ -5,7 +5,7 @@ import uuid
from collections.abc import Generator, Mapping
from typing import Any, Literal, Union, overload
from flask import Flask, copy_current_request_context, current_app, has_request_context
from flask import Flask, current_app
from pydantic import ValidationError
from configs import dify_config
@ -23,6 +23,7 @@ from core.model_runtime.errors.invoke import InvokeAuthorizationError
from core.ops.ops_trace_manager import TraceQueueManager
from extensions.ext_database import db
from factories import file_factory
from libs.flask_utils import preserve_flask_contexts
from models import Account, App, EndUser
from services.conversation_service import ConversationService
from services.errors.message import MessageNotExistsError
@ -182,20 +183,17 @@ class AgentChatAppGenerator(MessageBasedAppGenerator):
# new thread with request context and contextvars
context = contextvars.copy_context()
@copy_current_request_context
def worker_with_context():
# Run the worker within the copied context
return context.run(
self._generate_worker,
flask_app=current_app._get_current_object(), # type: ignore
context=context,
application_generate_entity=application_generate_entity,
queue_manager=queue_manager,
conversation_id=conversation.id,
message_id=message.id,
)
worker_thread = threading.Thread(target=worker_with_context)
worker_thread = threading.Thread(
target=self._generate_worker,
kwargs={
"flask_app": current_app._get_current_object(), # type: ignore
"context": context,
"application_generate_entity": application_generate_entity,
"queue_manager": queue_manager,
"conversation_id": conversation.id,
"message_id": message.id,
},
)
worker_thread.start()
@ -229,24 +227,9 @@ class AgentChatAppGenerator(MessageBasedAppGenerator):
:param message_id: message ID
:return:
"""
for var, val in context.items():
var.set(val)
# FIXME(-LAN-): Save current user before entering new app context
from flask import g
saved_user = None
if has_request_context() and hasattr(g, "_login_user"):
saved_user = g._login_user
with flask_app.app_context():
with preserve_flask_contexts(flask_app, context_vars=context):
try:
# Restore user in new app context
if saved_user is not None:
from flask import g
g._login_user = saved_user
# get conversation and message
conversation = self._get_conversation(conversation_id)
message = self._get_message(message_id)

View File

@ -5,7 +5,7 @@ import uuid
from collections.abc import Generator, Mapping, Sequence
from typing import Any, Literal, Optional, Union, overload
from flask import Flask, copy_current_request_context, current_app, has_request_context
from flask import Flask, current_app
from pydantic import ValidationError
from sqlalchemy.orm import sessionmaker
@ -29,6 +29,7 @@ from core.workflow.repositories.workflow_execution_repository import WorkflowExe
from core.workflow.repositories.workflow_node_execution_repository import WorkflowNodeExecutionRepository
from extensions.ext_database import db
from factories import file_factory
from libs.flask_utils import preserve_flask_contexts
from models import Account, App, EndUser, Workflow, WorkflowNodeExecutionTriggeredFrom
from models.enums import WorkflowRunTriggeredFrom
@ -209,19 +210,16 @@ class WorkflowAppGenerator(BaseAppGenerator):
# new thread with request context and contextvars
context = contextvars.copy_context()
@copy_current_request_context
def worker_with_context():
# Run the worker within the copied context
return context.run(
self._generate_worker,
flask_app=current_app._get_current_object(), # type: ignore
application_generate_entity=application_generate_entity,
queue_manager=queue_manager,
context=context,
workflow_thread_pool_id=workflow_thread_pool_id,
)
worker_thread = threading.Thread(target=worker_with_context)
worker_thread = threading.Thread(
target=self._generate_worker,
kwargs={
"flask_app": current_app._get_current_object(), # type: ignore
"application_generate_entity": application_generate_entity,
"queue_manager": queue_manager,
"context": context,
"workflow_thread_pool_id": workflow_thread_pool_id,
},
)
worker_thread.start()
@ -408,24 +406,9 @@ class WorkflowAppGenerator(BaseAppGenerator):
:param workflow_thread_pool_id: workflow thread pool id
:return:
"""
for var, val in context.items():
var.set(val)
# FIXME(-LAN-): Save current user before entering new app context
from flask import g
saved_user = None
if has_request_context() and hasattr(g, "_login_user"):
saved_user = g._login_user
with flask_app.app_context():
with preserve_flask_contexts(flask_app, context_vars=context):
try:
# Restore user in new app context
if saved_user is not None:
from flask import g
g._login_user = saved_user
# workflow app
runner = WorkflowAppRunner(
application_generate_entity=application_generate_entity,

View File

@ -41,6 +41,12 @@ class WeaviateVector(BaseVector):
weaviate.connect.connection.has_grpc = False
# Fix to minimize the performance impact of the deprecation check in weaviate-client 3.24.0,
# by changing the connection timeout to pypi.org from 1 second to 0.001 seconds.
# TODO: This can be removed once weaviate-client is updated to 3.26.7 or higher,
# which does not contain the deprecation check.
weaviate.connect.connection.PYPI_TIMEOUT = 0.001
try:
client = weaviate.Client(
url=config.endpoint, auth_client_secret=auth_config, timeout_config=(5, 60), startup_period=None

View File

@ -9,7 +9,7 @@ from copy import copy, deepcopy
from datetime import UTC, datetime
from typing import Any, Optional, cast
from flask import Flask, current_app, has_request_context
from flask import Flask, current_app
from configs import dify_config
from core.app.apps.base_app_queue_manager import GenerateTaskStoppedError
@ -53,6 +53,7 @@ from core.workflow.nodes.end.end_stream_processor import EndStreamProcessor
from core.workflow.nodes.enums import ErrorStrategy, FailBranchSourceHandle
from core.workflow.nodes.event import RunCompletedEvent, RunRetrieverResourceEvent, RunStreamChunkEvent
from core.workflow.nodes.node_mapping import NODE_TYPE_CLASSES_MAPPING
from libs.flask_utils import preserve_flask_contexts
from models.enums import UserFrom
from models.workflow import WorkflowType
@ -537,24 +538,9 @@ class GraphEngine:
"""
Run parallel nodes
"""
for var, val in context.items():
var.set(val)
# FIXME(-LAN-): Save current user before entering new app context
from flask import g
saved_user = None
if has_request_context() and hasattr(g, "_login_user"):
saved_user = g._login_user
with flask_app.app_context():
with preserve_flask_contexts(flask_app, context_vars=context):
try:
# Restore user in new app context
if saved_user is not None:
from flask import g
g._login_user = saved_user
q.put(
ParallelBranchRunStartedEvent(
parallel_id=parallel_id,

View File

@ -214,7 +214,7 @@ class AgentNode(ToolNode):
)
if tool_runtime.entity.description:
tool_runtime.entity.description.llm = (
extra.get("descrption", "") or tool_runtime.entity.description.llm
extra.get("description", "") or tool_runtime.entity.description.llm
)
for tool_runtime_params in tool_runtime.entity.parameters:
tool_runtime_params.form = (

View File

@ -7,7 +7,7 @@ from datetime import UTC, datetime
from queue import Empty, Queue
from typing import TYPE_CHECKING, Any, Optional, cast
from flask import Flask, current_app, has_request_context
from flask import Flask, current_app
from configs import dify_config
from core.variables import ArrayVariable, IntegerVariable, NoneVariable
@ -37,6 +37,7 @@ from core.workflow.nodes.base import BaseNode
from core.workflow.nodes.enums import NodeType
from core.workflow.nodes.event import NodeEvent, RunCompletedEvent
from core.workflow.nodes.iteration.entities import ErrorHandleMode, IterationNodeData
from libs.flask_utils import preserve_flask_contexts
from .exc import (
InvalidIteratorValueError,
@ -583,23 +584,8 @@ class IterationNode(BaseNode[IterationNodeData]):
"""
run single iteration in parallel mode
"""
for var, val in context.items():
var.set(val)
# FIXME(-LAN-): Save current user before entering new app context
from flask import g
saved_user = None
if has_request_context() and hasattr(g, "_login_user"):
saved_user = g._login_user
with flask_app.app_context():
# Restore user in new app context
if saved_user is not None:
from flask import g
g._login_user = saved_user
with preserve_flask_contexts(flask_app, context_vars=context):
parallel_mode_run_id = uuid.uuid4().hex
graph_engine_copy = graph_engine.create_copy()
variable_pool_copy = graph_engine_copy.graph_runtime_state.variable_pool

65
api/libs/flask_utils.py Normal file
View File

@ -0,0 +1,65 @@
import contextvars
from collections.abc import Iterator
from contextlib import contextmanager
from typing import TypeVar
from flask import Flask, g, has_request_context
T = TypeVar("T")
@contextmanager
def preserve_flask_contexts(
flask_app: Flask,
context_vars: contextvars.Context,
) -> Iterator[None]:
"""
A context manager that handles:
1. flask-login's UserProxy copy
2. ContextVars copy
3. flask_app.app_context()
This context manager ensures that the Flask application context is properly set up,
the current user is preserved across context boundaries, and any provided context variables
are set within the new context.
Note:
This manager aims to allow use current_user cross thread and app context,
but it's not the recommend use, it's better to pass user directly in parameters.
Args:
flask_app: The Flask application instance
context_vars: contextvars.Context object containing context variables to be set in the new context
Yields:
None
Example:
```python
with preserve_flask_contexts(flask_app, context_vars=context_vars):
# Code that needs Flask app context and context variables
# Current user will be preserved if available
```
"""
# Set context variables if provided
if context_vars:
for var, val in context_vars.items():
var.set(val)
# Save current user before entering new app context
saved_user = None
if has_request_context() and hasattr(g, "_login_user"):
saved_user = g._login_user
# Enter Flask app context
with flask_app.app_context():
try:
# Restore user in new app context if it was saved
if saved_user is not None:
g._login_user = saved_user
# Yield control back to the caller
yield
finally:
# Any cleanup can be added here if needed
pass

View File

@ -7,7 +7,7 @@ from sqlalchemy.orm import Session
from configs import dify_config
from core.helper.position_helper import is_filtered
from core.model_runtime.utils.encoders import jsonable_encoder
from core.plugin.entities.plugin import GenericProviderID, ToolProviderID
from core.plugin.entities.plugin import ToolProviderID
from core.plugin.impl.exc import PluginDaemonClientSideError
from core.tools.builtin_tool.providers._positions import BuiltinToolProviderSort
from core.tools.entities.api_entities import ToolApiEntity, ToolProviderApiEntity
@ -290,7 +290,7 @@ class BuiltinToolManageService:
def _fetch_builtin_provider(provider_name: str, tenant_id: str) -> BuiltinToolProvider | None:
try:
full_provider_name = provider_name
provider_id_entity = GenericProviderID(provider_name)
provider_id_entity = ToolProviderID(provider_name)
provider_name = provider_id_entity.provider_name
if provider_id_entity.organization != "langgenius":
provider_obj = (
@ -315,7 +315,7 @@ class BuiltinToolManageService:
if provider_obj is None:
return None
provider_obj.provider = GenericProviderID(provider_obj.provider).to_string()
provider_obj.provider = ToolProviderID(provider_obj.provider).to_string()
return provider_obj
except Exception:
# it's an old provider without organization

View File

@ -0,0 +1,124 @@
import contextvars
import threading
from typing import Optional
import pytest
from flask import Flask
from flask_login import LoginManager, UserMixin, current_user, login_user
from libs.flask_utils import preserve_flask_contexts
class User(UserMixin):
"""Simple User class for testing."""
def __init__(self, id: str):
self.id = id
def get_id(self) -> str:
return self.id
@pytest.fixture
def login_app(app: Flask) -> Flask:
"""Set up a Flask app with flask-login."""
# Set a secret key for the app
app.config["SECRET_KEY"] = "test-secret-key"
login_manager = LoginManager()
login_manager.init_app(app)
@login_manager.user_loader
def load_user(user_id: str) -> Optional[User]:
if user_id == "test_user":
return User("test_user")
return None
return app
@pytest.fixture
def test_user() -> User:
"""Create a test user."""
return User("test_user")
def test_current_user_not_accessible_across_threads(login_app: Flask, test_user: User):
"""
Test that current_user is not accessible in a different thread without preserve_flask_contexts.
This test demonstrates that without the preserve_flask_contexts, we cannot access
current_user in a different thread, even with app_context.
"""
# Log in the user in the main thread
with login_app.test_request_context():
login_user(test_user)
assert current_user.is_authenticated
assert current_user.id == "test_user"
# Store the result of the thread execution
result = {"user_accessible": True, "error": None}
# Define a function to run in a separate thread
def check_user_in_thread():
try:
# Try to access current_user in a different thread with app_context
with login_app.app_context():
# This should fail because current_user is not accessible across threads
# without preserve_flask_contexts
result["user_accessible"] = current_user.is_authenticated
except Exception as e:
result["error"] = str(e) # type: ignore
# Run the function in a separate thread
thread = threading.Thread(target=check_user_in_thread)
thread.start()
thread.join()
# Verify that we got an error or current_user is not authenticated
assert result["error"] is not None or (result["user_accessible"] is not None and not result["user_accessible"])
def test_current_user_accessible_with_preserve_flask_contexts(login_app: Flask, test_user: User):
"""
Test that current_user is accessible in a different thread with preserve_flask_contexts.
This test demonstrates that with the preserve_flask_contexts, we can access
current_user in a different thread.
"""
# Log in the user in the main thread
with login_app.test_request_context():
login_user(test_user)
assert current_user.is_authenticated
assert current_user.id == "test_user"
# Save the context variables
context_vars = contextvars.copy_context()
# Store the result of the thread execution
result = {"user_accessible": False, "user_id": None, "error": None}
# Define a function to run in a separate thread
def check_user_in_thread_with_manager():
try:
# Use preserve_flask_contexts to access current_user in a different thread
with preserve_flask_contexts(login_app, context_vars):
from flask_login import current_user
if current_user:
result["user_accessible"] = True
result["user_id"] = current_user.id
else:
result["user_accessible"] = False
except Exception as e:
result["error"] = str(e) # type: ignore
# Run the function in a separate thread
thread = threading.Thread(target=check_user_in_thread_with_manager)
thread.start()
thread.join()
# Verify that current_user is accessible and has the correct ID
assert result["error"] is None
assert result["user_accessible"] is True
assert result["user_id"] == "test_user"

View File

@ -2,7 +2,7 @@ x-shared-env: &shared-api-worker-env
services:
# API service
api:
image: langgenius/dify-api:1.4.2
image: langgenius/dify-api:1.4.3
restart: always
environment:
# Use the shared environment variables.
@ -31,7 +31,7 @@ services:
# worker service
# The Celery worker for processing the queue.
worker:
image: langgenius/dify-api:1.4.2
image: langgenius/dify-api:1.4.3
restart: always
environment:
# Use the shared environment variables.
@ -57,7 +57,7 @@ services:
# Frontend web application.
web:
image: langgenius/dify-web:1.4.2
image: langgenius/dify-web:1.4.3
restart: always
environment:
CONSOLE_API_URL: ${CONSOLE_API_URL:-}

View File

@ -509,7 +509,7 @@ x-shared-env: &shared-api-worker-env
services:
# API service
api:
image: langgenius/dify-api:1.4.2
image: langgenius/dify-api:1.4.3
restart: always
environment:
# Use the shared environment variables.
@ -538,7 +538,7 @@ services:
# worker service
# The Celery worker for processing the queue.
worker:
image: langgenius/dify-api:1.4.2
image: langgenius/dify-api:1.4.3
restart: always
environment:
# Use the shared environment variables.
@ -564,7 +564,7 @@ services:
# Frontend web application.
web:
image: langgenius/dify-web:1.4.2
image: langgenius/dify-web:1.4.3
restart: always
environment:
CONSOLE_API_URL: ${CONSOLE_API_URL:-}

View File

@ -15,7 +15,7 @@ const Overview = async (props: IDevelopProps) => {
} = params
return (
<div className="h-full overflow-scroll bg-chatbot-bg px-4 py-6 sm:px-12">
<div className="h-full overflow-y-auto bg-chatbot-bg px-4 py-6 sm:px-12">
<ApikeyInfoPanel />
<ChartView
appId={appId}

View File

@ -1,9 +1,23 @@
'use client'
import Loading from '@/app/components/base/loading'
import { useAppContext } from '@/context/app-context'
import { ExternalApiPanelProvider } from '@/context/external-api-panel-context'
import { ExternalKnowledgeApiProvider } from '@/context/external-knowledge-api-context'
import { useRouter } from 'next/navigation'
import { useEffect } from 'react'
export default function DatasetsLayout({ children }: { children: React.ReactNode }) {
const { isCurrentWorkspaceEditor, isCurrentWorkspaceDatasetOperator } = useAppContext()
const router = useRouter()
useEffect(() => {
if (!isCurrentWorkspaceEditor && !isCurrentWorkspaceDatasetOperator)
router.replace('/apps')
}, [isCurrentWorkspaceEditor, isCurrentWorkspaceDatasetOperator, router])
if (!isCurrentWorkspaceEditor && !isCurrentWorkspaceDatasetOperator)
return <Loading type='app' />
return (
<ExternalKnowledgeApiProvider>
<ExternalApiPanelProvider>

View File

@ -54,7 +54,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty, PropertyInstructi
</Property>
<Property name='indexing_technique' type='string' key='indexing_technique'>
Index mode
- <code>high_quality</code> High quality: embedding using embedding model, built as vector database index
- <code>high_quality</code> High quality: Embedding using embedding model, built as vector database index
- <code>economy</code> Economy: Build using inverted index of keyword table index
</Property>
<Property name='doc_form' type='string' key='doc_form'>

View File

@ -55,7 +55,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty, PropertyInstructi
<Property name='indexing_technique' type='string' key='indexing_technique'>
索引方式
- <code>high_quality</code> 高质量:使用
ding 模型进行嵌入,构建为向量数据库索引
Embedding 模型进行嵌入,构建为向量数据库索引
- <code>economy</code> 经济:使用 keyword table index 的倒排索引进行构建
</Property>
<Property name='doc_form' type='string' key='doc_form'>

View File

@ -19,7 +19,7 @@ const Layout: FC<{
const [isLoading, setIsLoading] = useState(true)
useEffect(() => {
(async () => {
if (!systemFeatures.webapp_auth.enabled) {
if (!isGlobalPending && !systemFeatures.webapp_auth.enabled) {
setIsLoading(false)
return
}
@ -37,7 +37,7 @@ const Layout: FC<{
setWebAppAccessMode(ret?.accessMode || AccessMode.PUBLIC)
setIsLoading(false)
})()
}, [pathname, redirectUrl, setWebAppAccessMode])
}, [pathname, redirectUrl, setWebAppAccessMode, isGlobalPending, systemFeatures.webapp_auth.enabled])
if (isLoading || isGlobalPending) {
return <div className='flex h-full w-full items-center justify-center'>
<Loading />

View File

@ -20,6 +20,7 @@ import type {
import { useToastContext } from '@/app/components/base/toast'
import AppIcon from '@/app/components/base/app-icon'
import { noop } from 'lodash-es'
import { useDocLink } from '@/context/i18n'
const systemTypes = ['api']
type ExternalDataToolModalProps = {
@ -40,6 +41,7 @@ const ExternalDataToolModal: FC<ExternalDataToolModalProps> = ({
onValidateBeforeSave,
}) => {
const { t } = useTranslation()
const docLink = useDocLink()
const { notify } = useToastContext()
const { locale } = useContext(I18n)
const [localeData, setLocaleData] = useState(data.type ? data : { ...data, type: 'api' })
@ -243,7 +245,7 @@ const ExternalDataToolModal: FC<ExternalDataToolModalProps> = ({
<div className='flex h-9 items-center justify-between text-sm font-medium text-gray-900'>
{t('common.apiBasedExtension.selector.title')}
<a
href={t('common.apiBasedExtension.linkUrl') || '/'}
href={docLink('/guides/extension/api-based-extension/README')}
target='_blank' rel='noopener noreferrer'
className='group flex items-center text-xs font-normal text-gray-500 hover:text-primary-600'
>

View File

@ -314,7 +314,10 @@ function AppPreview({ mode }: { mode: AppMode }) {
'advanced-chat': {
title: t('app.types.advanced'),
description: t('app.newApp.advancedUserDescription'),
link: docLink('/guides/workflow/readme'),
link: docLink('/guides/workflow/README', {
'zh-Hans': '/guides/workflow/readme',
'ja-JP': '/guides/workflow/concepts',
}),
},
'agent-chat': {
title: t('app.types.agent'),
@ -324,13 +327,18 @@ function AppPreview({ mode }: { mode: AppMode }) {
'completion': {
title: t('app.newApp.completeApp'),
description: t('app.newApp.completionUserDescription'),
link: docLink('/guides/application-orchestrate/text-generator',
{ 'zh-Hans': '/guides/application-orchestrate/readme' }),
link: docLink('/guides/application-orchestrate/text-generator', {
'zh-Hans': '/guides/application-orchestrate/readme',
'ja-JP': '/guides/application-orchestrate/README',
}),
},
'workflow': {
title: t('app.types.workflow'),
description: t('app.newApp.workflowUserDescription'),
link: docLink('/guides/workflow/readme'),
link: docLink('/guides/workflow/README', {
'zh-Hans': '/guides/workflow/readme',
'ja-JP': '/guides/workflow/concepts',
}),
},
}
const previewInfo = modeToPreviewInfoMap[mode]

View File

@ -237,7 +237,9 @@ const SettingsModal: FC<ISettingsModalProps> = ({
</div>
<div className='system-xs-regular mt-0.5 text-text-tertiary'>
<span>{t(`${prefixSettings}.modalTip`)}</span>
<Link href={docLink('/guides/application-publishing/launch-your-webapp-quickly/README')}
<Link href={docLink('/guides/application-publishing/launch-your-webapp-quickly/README', {
'zh-Hans': '/guides/application-publishing/launch-your-webapp-quickly/readme',
})}
target='_blank' rel='noopener noreferrer' className='text-text-accent'>{t('common.operation.learnMore')}</Link>
</div>
</div>

View File

@ -25,6 +25,7 @@ import { useModalContext } from '@/context/modal-context'
import { CustomConfigurationStatusEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
import cn from '@/utils/classnames'
import { noop } from 'lodash-es'
import { useDocLink } from '@/context/i18n'
const systemTypes = ['openai_moderation', 'keywords', 'api']
@ -46,6 +47,7 @@ const ModerationSettingModal: FC<ModerationSettingModalProps> = ({
onSave,
}) => {
const { t } = useTranslation()
const docLink = useDocLink()
const { notify } = useToastContext()
const { locale } = useContext(I18n)
const { data: modelProviders, isLoading, mutate } = useSWR('/workspaces/current/model-providers', fetchModelProviders)
@ -316,7 +318,7 @@ const ModerationSettingModal: FC<ModerationSettingModalProps> = ({
<div className='flex h-9 items-center justify-between'>
<div className='text-sm font-medium text-text-primary'>{t('common.apiBasedExtension.selector.title')}</div>
<a
href={t('common.apiBasedExtension.linkUrl') || '/'}
href={docLink('/guides/extension/api-based-extension/README')}
target='_blank' rel='noopener noreferrer'
className='group flex items-center text-xs text-text-tertiary hover:text-primary-600'
>

View File

@ -165,6 +165,7 @@ const ComponentPicker = ({
isSupportFileVar={isSupportFileVar}
onClose={handleClose}
onBlur={handleClose}
autoFocus={false}
/>
</div>
)

View File

@ -59,7 +59,7 @@ const Form: FC<FormProps> = React.memo(({
</label>
{variable === 'endpoint' && (
<a
href={docLink('/guides/knowledge-base/external-knowledge-api-documentation') || '/'}
href={docLink('/guides/knowledge-base/connect-external-knowledge-base') || '/'}
target='_blank'
rel='noopener noreferrer'
className='body-xs-regular flex items-center text-text-accent'

View File

@ -53,7 +53,7 @@ const ExternalAPIPanel: React.FC<ExternalAPIPanelProps> = ({ onClose }) => {
<div className='system-xl-semibold self-stretch text-text-primary'>{t('dataset.externalAPIPanelTitle')}</div>
<div className='body-xs-regular self-stretch text-text-tertiary'>{t('dataset.externalAPIPanelDescription')}</div>
<a className='flex cursor-pointer items-center justify-center gap-1 self-stretch'
href={docLink('/guides/knowledge-base/external-knowledge-api-documentation')} target='_blank'>
href={docLink('/guides/knowledge-base/connect-external-knowledge-base')} target='_blank'>
<RiBookOpenLine className='h-3 w-3 text-text-accent' />
<div className='body-xs-regular grow text-text-accent'>{t('dataset.externalAPIPanelDocumentation')}</div>
</a>

View File

@ -74,7 +74,10 @@ const ModifyRetrievalModal: FC<Props> = ({
<a
target='_blank'
rel='noopener noreferrer'
href={docLink('/guides/knowledge-base/create-knowledge-and-upload-documents#id-4-retrieval-settings')}
href={docLink('/guides/knowledge-base/retrieval-test-and-citation#modify-text-retrieval-setting', {
'zh-Hans': '/guides/knowledge-base/retrieval-test-and-citation#修改文本检索方式',
'ja-JP': '/guides/knowledge-base/retrieval-test-and-citation',
})}
className='text-text-accent'
>
{t('datasetSettings.form.retrievalSetting.learnMore')}

View File

@ -310,7 +310,16 @@ const Form = () => {
<div>
<div className='system-sm-semibold text-text-secondary'>{t('datasetSettings.form.retrievalSetting.title')}</div>
<div className='body-xs-regular text-text-tertiary'>
<a target='_blank' rel='noopener noreferrer' href={docLink('/guides/knowledge-base/create-knowledge-and-upload-documents#id-4-retrieval-settings')} className='text-text-accent'>{t('datasetSettings.form.retrievalSetting.learnMore')}</a>
<a
target='_blank'
rel='noopener noreferrer'
href={docLink('/guides/knowledge-base/create-knowledge-and-upload-documents/setting-indexing-methods#setting-the-retrieval-setting', {
'zh-Hans': '/guides/knowledge-base/create-knowledge-and-upload-documents/setting-indexing-methods#指定检索方式',
'ja-JP': '/guides/knowledge-base/create-knowledge-and-upload-documents/setting-indexing-methods#検索方法の指定',
})}
className='text-text-accent'>
{t('datasetSettings.form.retrievalSetting.learnMore')}
</a>
{t('datasetSettings.form.retrievalSetting.description')}
</div>
</div>

View File

@ -31,22 +31,22 @@ const WorkplaceSelector = () => {
}
return (
<Menu as="div" className="relative h-full w-full">
<Menu as="div" className="min-w-0">
{
({ open }) => (
<>
<MenuButton className={cn(
`
group flex w-full cursor-pointer items-center
gap-1.5 p-0.5 hover:bg-state-base-hover ${open && 'bg-state-base-hover'} rounded-[10px]
p-0.5 hover:bg-state-base-hover ${open && 'bg-state-base-hover'} rounded-[10px]
`,
)}>
<div className='flex h-6 w-6 items-center justify-center rounded-md bg-components-icon-bg-blue-solid text-[13px]'>
<div className='mr-1.5 flex h-6 w-6 shrink-0 items-center justify-center rounded-md bg-components-icon-bg-blue-solid text-[13px] max-[800px]:mr-0'>
<span className='h-6 bg-gradient-to-r from-components-avatar-shape-fill-stop-0 to-components-avatar-shape-fill-stop-100 bg-clip-text align-middle font-semibold uppercase leading-6 text-shadow-shadow-1 opacity-90'>{currentWorkspace?.name[0]?.toLocaleUpperCase()}</span>
</div>
<div className='flex flex-row'>
<div className={'system-sm-medium max-w-[160px] truncate text-text-secondary'}>{currentWorkspace?.name}</div>
<RiArrowDownSLine className='h-4 w-4 text-text-secondary' />
<div className='flex min-w-0 items-center'>
<div className={'system-sm-medium min-w-0 max-w-[149px] truncate text-text-secondary max-[800px]:hidden'}>{currentWorkspace?.name}</div>
<RiArrowDownSLine className='h-4 w-4 shrink-0 text-text-secondary' />
</div>
</MenuButton>
<Transition
@ -59,10 +59,11 @@ const WorkplaceSelector = () => {
leaveTo="transform opacity-0 scale-95"
>
<MenuItems
anchor="bottom start"
className={cn(
`
shadows-shadow-lg absolute left-[-15px] mt-1 flex max-h-[400px] w-[280px] flex-col items-start overflow-y-auto rounded-xl
bg-components-panel-bg-blur backdrop-blur-[5px]
shadows-shadow-lg absolute left-[-15px] z-[1000] mt-1 flex max-h-[400px] w-[280px] flex-col items-start overflow-y-auto
rounded-xl bg-components-panel-bg-blur backdrop-blur-[5px]
`,
)}
>
@ -73,7 +74,7 @@ const WorkplaceSelector = () => {
{
workspaces.map(workspace => (
<div className='flex items-center gap-2 self-stretch rounded-lg py-1 pl-3 pr-2 hover:bg-state-base-hover' key={workspace.id} onClick={() => handleSwitchWorkspace(workspace.id)}>
<div className='flex h-6 w-6 items-center justify-center rounded-md bg-components-icon-bg-blue-solid text-[13px]'>
<div className='flex h-6 w-6 shrink-0 items-center justify-center rounded-md bg-components-icon-bg-blue-solid text-[13px]'>
<span className='h-6 bg-gradient-to-r from-components-avatar-shape-fill-stop-0 to-components-avatar-shape-fill-stop-100 bg-clip-text align-middle font-semibold uppercase leading-6 text-shadow-shadow-1 opacity-90'>{workspace?.name[0]?.toLocaleUpperCase()}</span>
</div>
<div className='system-md-regular line-clamp-1 grow cursor-pointer overflow-hidden text-ellipsis text-text-secondary'>{workspace.name}</div>

View File

@ -3,9 +3,11 @@ import {
RiExternalLinkLine,
RiPuzzle2Line,
} from '@remixicon/react'
import { useDocLink } from '@/context/i18n'
const Empty = () => {
const { t } = useTranslation()
const docLink = useDocLink()
return (
<div className='mb-2 rounded-xl bg-background-section p-6'>
@ -15,7 +17,7 @@ const Empty = () => {
<div className='system-sm-medium mb-1 text-text-secondary'>{t('common.apiBasedExtension.title')}</div>
<a
className='system-xs-regular flex items-center text-text-accent'
href={t('common.apiBasedExtension.linkUrl') || '/'}
href={docLink('/guides/extension/api-based-extension/README')}
target='_blank' rel='noopener noreferrer'
>
{t('common.apiBasedExtension.link')}

View File

@ -1,6 +1,7 @@
import type { FC } from 'react'
import { useState } from 'react'
import { useTranslation } from 'react-i18next'
import { useDocLink } from '@/context/i18n'
import Modal from '@/app/components/base/modal'
import Button from '@/app/components/base/button'
import { BookOpen01 } from '@/app/components/base/icons/src/vender/line/education'
@ -29,6 +30,7 @@ const ApiBasedExtensionModal: FC<ApiBasedExtensionModalProps> = ({
onSave,
}) => {
const { t } = useTranslation()
const docLink = useDocLink()
const [localeData, setLocaleData] = useState(data)
const [loading, setLoading] = useState(false)
const { notify } = useToastContext()
@ -100,7 +102,7 @@ const ApiBasedExtensionModal: FC<ApiBasedExtensionModalProps> = ({
<div className='flex h-9 items-center justify-between text-sm font-medium text-text-primary'>
{t('common.apiBasedExtension.modal.apiEndpoint.title')}
<a
href={t('common.apiBasedExtension.linkUrl') || '/'}
href={docLink('/guides/extension/api-based-extension/README')}
target='_blank' rel='noopener noreferrer'
className='group flex items-center text-xs font-normal text-text-accent'
>

View File

@ -96,7 +96,7 @@ const AppNav = () => {
link,
}
})
setNavItems(navItems)
setNavItems(navItems as any)
}
}, [appsData, isCurrentWorkspaceEditor, setNavItems])
@ -122,7 +122,7 @@ const AppNav = () => {
text={t('common.menus.apps')}
activeSegment={['apps', 'app']}
link='/apps'
curNav={appDetail}
curNav={appDetail as any}
navs={navItems}
createText={t('common.menus.newApp')}
onCreate={openModal}

View File

@ -48,7 +48,7 @@ const DatasetNav = () => {
text={t('common.menus.datasets')}
activeSegment='datasets'
link='/datasets'
curNav={currentDataset as Omit<NavItem, 'link'>}
curNav={currentDataset as any}
navs={datasetItems.map(dataset => ({
id: dataset.id,
name: dataset.name,
@ -59,6 +59,7 @@ const DatasetNav = () => {
createText={t('common.menus.newDataset')}
onCreate={() => router.push(`${basePath}/datasets/create`)}
onLoadmore={handleLoadmore}
isApp={false}
/>
)
}

View File

@ -20,22 +20,22 @@ const EnvNav = () => {
return (
<div className={`
mr-4 flex h-[22px] items-center rounded-md border px-2 text-xs font-medium
mr-1 flex h-[22px] items-center rounded-md border px-2 text-xs font-medium
${headerEnvClassName[langeniusVersionInfo.current_env]}
`}>
{
langeniusVersionInfo.current_env === 'TESTING' && (
<>
<Beaker02 className='mr-1 h-3 w-3' />
{t('common.environment.testing')}
<Beaker02 className='h-3 w-3' />
<div className='ml-1 max-[1280px]:hidden'>{t('common.environment.testing')}</div>
</>
)
}
{
langeniusVersionInfo.current_env === 'DEVELOPMENT' && (
<>
<TerminalSquare className='mr-1 h-3 w-3' />
{t('common.environment.development')}
<TerminalSquare className='h-3 w-3' />
<div className='ml-1 max-[1280px]:hidden'>{t('common.environment.development')}</div>
</>
)
}

View File

@ -27,10 +27,12 @@ const ExploreNav = ({
)}>
{
activated
? <RiPlanetFill className='mr-2 h-4 w-4' />
: <RiPlanetLine className='mr-2 h-4 w-4' />
? <RiPlanetFill className='h-4 w-4' />
: <RiPlanetLine className='h-4 w-4' />
}
{t('common.menus.explore')}
<div className='ml-2 max-[1024px]:hidden'>
{t('common.menus.explore')}
</div>
</Link>
)
}

View File

@ -1,9 +1,6 @@
'use client'
import { useCallback, useEffect } from 'react'
import { useCallback } from 'react'
import Link from 'next/link'
import { useBoolean } from 'ahooks'
import { useSelectedLayoutSegment } from 'next/navigation'
import { Bars3Icon } from '@heroicons/react/20/solid'
import AccountDropdown from './account-dropdown'
import AppNav from './app-nav'
import DatasetNav from './dataset-nav'
@ -24,17 +21,15 @@ import { Plan } from '../billing/type'
import { useGlobalPublicStore } from '@/context/global-public-context'
const navClassName = `
flex items-center relative mr-0 sm:mr-3 px-3 h-8 rounded-xl
flex items-center relative px-3 h-8 rounded-xl
font-medium text-sm
cursor-pointer
`
const Header = () => {
const { isCurrentWorkspaceEditor, isCurrentWorkspaceDatasetOperator } = useAppContext()
const selectedSegment = useSelectedLayoutSegment()
const media = useBreakpoints()
const isMobile = media === MediaType.mobile
const [isShowNavMenu, { toggle, setFalse: hideNavMenu }] = useBoolean(false)
const { enableBilling, plan } = useProviderContext()
const { setShowPricingModal, setShowAccountSettingModal } = useModalContext()
const systemFeatures = useGlobalPublicStore(s => s.systemFeatures)
@ -46,23 +41,12 @@ const Header = () => {
setShowAccountSettingModal({ payload: 'billing' })
}, [isFreePlan, setShowAccountSettingModal, setShowPricingModal])
useEffect(() => {
hideNavMenu()
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [selectedSegment])
return (
<div className='relative flex flex-1 items-center justify-between bg-background-body'>
<div className='flex items-center'>
{isMobile && <div
className='flex h-8 w-8 cursor-pointer items-center justify-center'
onClick={toggle}
>
<Bars3Icon className="h-4 w-4 text-gray-500" />
</div>}
{
!isMobile
&& <div className='flex shrink-0 items-center gap-1.5 self-stretch pl-3'>
<Link href="/apps" className='flex h-8 shrink-0 items-center justify-center gap-2 px-0.5'>
if (isMobile) {
return (
<div className=''>
<div className='flex items-center justify-between px-2'>
<div className='flex items-center'>
<Link href="/apps" className='flex h-8 shrink-0 items-center justify-center px-0.5'>
{systemFeatures.branding.enabled && systemFeatures.branding.workspace_logo
? <img
src={systemFeatures.branding.workspace_logo}
@ -71,59 +55,61 @@ const Header = () => {
/>
: <DifyLogo />}
</Link>
<div className='font-light text-divider-deep'>/</div>
<div className='flex items-center gap-0.5'>
<WorkspaceProvider>
<WorkplaceSelector />
</WorkspaceProvider>
{enableBilling ? <PlanBadge allowHover sandboxAsUpgrade plan={plan.type} onClick={handlePlanClick} /> : <LicenseNav />}
<div className='mx-1.5 shrink-0 font-light text-divider-deep'>/</div>
<WorkspaceProvider>
<WorkplaceSelector />
</WorkspaceProvider>
{enableBilling ? <PlanBadge allowHover sandboxAsUpgrade plan={plan.type} onClick={handlePlanClick} /> : <LicenseNav />}
</div>
<div className='flex items-center'>
<div className='mr-2'>
<PluginsNav />
</div>
<AccountDropdown />
</div>
}
</div >
{isMobile && (
<div className='flex'>
<Link href="/apps" className='mr-4 flex items-center'>
{systemFeatures.branding.enabled && systemFeatures.branding.workspace_logo
? <img
src={systemFeatures.branding.workspace_logo}
className='block h-[22px] w-auto object-contain'
alt='logo'
/>
: <DifyLogo />}
</Link>
<div className='font-light text-divider-deep'>/</div>
{enableBilling ? <PlanBadge allowHover sandboxAsUpgrade plan={plan.type} onClick={handlePlanClick} /> : <LicenseNav />}
</div >
)}
{
!isMobile && (
<div className='absolute left-1/2 top-1/2 flex -translate-x-1/2 -translate-y-1/2 items-center'>
{!isCurrentWorkspaceDatasetOperator && <ExploreNav className={navClassName} />}
{!isCurrentWorkspaceDatasetOperator && <AppNav />}
{(isCurrentWorkspaceEditor || isCurrentWorkspaceDatasetOperator) && <DatasetNav />}
{!isCurrentWorkspaceDatasetOperator && <ToolsNav className={navClassName} />}
</div>
)
}
<div className='flex shrink-0 items-center pr-3'>
</div>
<div className='my-1 flex items-center justify-center space-x-1'>
{!isCurrentWorkspaceDatasetOperator && <ExploreNav className={navClassName} />}
{!isCurrentWorkspaceDatasetOperator && <AppNav />}
{(isCurrentWorkspaceEditor || isCurrentWorkspaceDatasetOperator) && <DatasetNav />}
{!isCurrentWorkspaceDatasetOperator && <ToolsNav className={navClassName} />}
</div>
</div>
)
}
return (
<div className='flex h-[60px] items-center'>
<div className='flex min-w-0 flex-[1] items-center pl-3 pr-2 min-[1280px]:pr-3'>
<Link href="/apps" className='flex h-8 shrink-0 items-center justify-center px-0.5'>
{systemFeatures.branding.enabled && systemFeatures.branding.workspace_logo
? <img
src={systemFeatures.branding.workspace_logo}
className='block h-[22px] w-auto object-contain'
alt='logo'
/>
: <DifyLogo />}
</Link>
<div className='mx-1.5 shrink-0 font-light text-divider-deep'>/</div>
<WorkspaceProvider>
<WorkplaceSelector />
</WorkspaceProvider>
{enableBilling ? <PlanBadge allowHover sandboxAsUpgrade plan={plan.type} onClick={handlePlanClick} /> : <LicenseNav />}
</div>
<div className='flex items-center space-x-2'>
{!isCurrentWorkspaceDatasetOperator && <ExploreNav className={navClassName} />}
{!isCurrentWorkspaceDatasetOperator && <AppNav />}
{(isCurrentWorkspaceEditor || isCurrentWorkspaceDatasetOperator) && <DatasetNav />}
{!isCurrentWorkspaceDatasetOperator && <ToolsNav className={navClassName} />}
</div>
<div className='flex min-w-0 flex-[1] items-center justify-end pl-2 pr-3 min-[1280px]:pl-3'>
<EnvNav />
<div className='mr-2'>
<PluginsNav />
</div>
<AccountDropdown />
</div>
{
(isMobile && isShowNavMenu) && (
<div className='flex w-full flex-col gap-y-1 p-2'>
{!isCurrentWorkspaceDatasetOperator && <ExploreNav className={navClassName} />}
{!isCurrentWorkspaceDatasetOperator && <AppNav />}
{(isCurrentWorkspaceEditor || isCurrentWorkspaceDatasetOperator) && <DatasetNav />}
{!isCurrentWorkspaceDatasetOperator && <ToolsNav className={navClassName} />}
</div>
)
}
</div >
</div>
)
}
export default Header

View File

@ -46,7 +46,7 @@ const Nav = ({
return (
<div className={`
mr-0 flex h-8 shrink-0 items-center rounded-xl px-0.5 text-sm font-medium sm:mr-3
flex h-8 max-w-[670px] shrink-0 items-center rounded-xl px-0.5 text-sm font-medium max-[1024px]:max-w-[400px]
${isActivated && 'bg-components-main-nav-nav-button-bg-active font-semibold shadow-md'}
${!curNav && !isActivated && 'hover:bg-components-main-nav-nav-button-bg-hover'}
`}>
@ -61,7 +61,7 @@ const Nav = ({
onMouseEnter={() => setHovered(true)}
onMouseLeave={() => setHovered(false)}
>
<div className='mr-2'>
<div>
{
(hovered && curNav)
? <ArrowNarrowLeft className='h-4 w-4' />
@ -70,7 +70,9 @@ const Nav = ({
: icon
}
</div>
{text}
<div className='ml-2 max-[1024px]:hidden'>
{text}
</div>
</div>
</Link>
{

View File

@ -53,136 +53,134 @@ const NavSelector = ({ curNav, navs, createText, isApp, onCreate, onLoadmore }:
}, 50), [])
return (
<div className="">
<Menu as="div" className="relative inline-block text-left">
{({ open }) => (
<>
<MenuButton className={cn(
'hover:hover:bg-components-main-nav-nav-button-bg-active-hover group inline-flex h-7 w-full items-center justify-center rounded-[10px] pl-2 pr-2.5 text-[14px] font-semibold text-components-main-nav-nav-button-text-active',
open && 'bg-components-main-nav-nav-button-bg-active',
)}>
<div className='max-w-[180px] truncate' title={curNav?.name}>{curNav?.name}</div>
<RiArrowDownSLine
className={cn('ml-1 h-3 w-3 shrink-0 opacity-50 group-hover:opacity-100', open && '!opacity-100')}
aria-hidden="true"
/>
</MenuButton>
<MenuItems
className="
absolute -left-11 right-0 mt-1.5 w-60 max-w-80
origin-top-right divide-y divide-divider-regular rounded-lg bg-components-panel-bg-blur
shadow-lg
"
>
<div className="overflow-auto px-1 py-1" style={{ maxHeight: '50vh' }} onScroll={handleScroll}>
{
navs.map(nav => (
<MenuItem key={nav.id}>
<div className='flex w-full cursor-pointer items-center truncate rounded-lg px-3 py-[6px] text-[14px] font-normal text-text-secondary hover:bg-state-base-hover' onClick={() => {
if (curNav?.id === nav.id)
return
setAppDetail()
router.push(nav.link)
}} title={nav.name}>
<div className='relative mr-2 h-6 w-6 rounded-md'>
<AppIcon size='tiny' iconType={nav.icon_type} icon={nav.icon} background={nav.icon_background} imageUrl={nav.icon_url} />
{!!nav.mode && (
<span className={cn(
'absolute -bottom-0.5 -right-0.5 h-3.5 w-3.5 rounded border-[0.5px] border-[rgba(0,0,0,0.02)] bg-white p-0.5 shadow-sm',
)}>
{nav.mode === 'advanced-chat' && (
<ChatBot className='h-2.5 w-2.5 text-[#1570EF]' />
)}
{nav.mode === 'agent-chat' && (
<CuteRobot className='h-2.5 w-2.5 text-indigo-600' />
)}
{nav.mode === 'chat' && (
<ChatBot className='h-2.5 w-2.5 text-[#1570EF]' />
)}
{nav.mode === 'completion' && (
<AiText className='h-2.5 w-2.5 text-[#0E9384]' />
)}
{nav.mode === 'workflow' && (
<Route className='h-2.5 w-2.5 text-[#f79009]' />
)}
</span>
)}
</div>
<div className='truncate'>
{nav.name}
</div>
<Menu as="div" className="relative">
{({ open }) => (
<>
<MenuButton className={cn(
'hover:hover:bg-components-main-nav-nav-button-bg-active-hover group inline-flex h-7 w-full items-center justify-center rounded-[10px] pl-2 pr-2.5 text-[14px] font-semibold text-components-main-nav-nav-button-text-active',
open && 'bg-components-main-nav-nav-button-bg-active',
)}>
<div className='max-w-[157px] truncate' title={curNav?.name}>{curNav?.name}</div>
<RiArrowDownSLine
className={cn('ml-1 h-3 w-3 shrink-0 opacity-50 group-hover:opacity-100', open && '!opacity-100')}
aria-hidden="true"
/>
</MenuButton>
<MenuItems
className="
absolute -left-11 right-0 mt-1.5 w-60 max-w-80
origin-top-right divide-y divide-divider-regular rounded-lg bg-components-panel-bg-blur
shadow-lg
"
>
<div className="overflow-auto px-1 py-1" style={{ maxHeight: '50vh' }} onScroll={handleScroll}>
{
navs.map(nav => (
<MenuItem key={nav.id}>
<div className='flex w-full cursor-pointer items-center truncate rounded-lg px-3 py-[6px] text-[14px] font-normal text-text-secondary hover:bg-state-base-hover' onClick={() => {
if (curNav?.id === nav.id)
return
setAppDetail()
router.push(nav.link)
}} title={nav.name}>
<div className='relative mr-2 h-6 w-6 rounded-md'>
<AppIcon size='tiny' iconType={nav.icon_type} icon={nav.icon} background={nav.icon_background} imageUrl={nav.icon_url} />
{!!nav.mode && (
<span className={cn(
'absolute -bottom-0.5 -right-0.5 h-3.5 w-3.5 rounded border-[0.5px] border-[rgba(0,0,0,0.02)] bg-white p-0.5 shadow-sm',
)}>
{nav.mode === 'advanced-chat' && (
<ChatBot className='h-2.5 w-2.5 text-[#1570EF]' />
)}
{nav.mode === 'agent-chat' && (
<CuteRobot className='h-2.5 w-2.5 text-indigo-600' />
)}
{nav.mode === 'chat' && (
<ChatBot className='h-2.5 w-2.5 text-[#1570EF]' />
)}
{nav.mode === 'completion' && (
<AiText className='h-2.5 w-2.5 text-[#0E9384]' />
)}
{nav.mode === 'workflow' && (
<Route className='h-2.5 w-2.5 text-[#f79009]' />
)}
</span>
)}
</div>
<div className='truncate'>
{nav.name}
</div>
</MenuItem>
))
}
</div>
{!isApp && isCurrentWorkspaceEditor && (
<MenuItem as="div" className='w-full p-1'>
<div onClick={() => onCreate('')} className={cn(
'flex cursor-pointer items-center gap-2 rounded-lg px-3 py-[6px] hover:bg-state-base-hover ',
)}>
<div className='flex h-6 w-6 shrink-0 items-center justify-center rounded-[6px] border-[0.5px] border-divider-regular bg-background-default'>
<RiAddLine className='h-4 w-4 text-text-primary' />
</div>
<div className='grow text-left text-[14px] font-normal text-text-secondary'>{createText}</div>
</MenuItem>
))
}
</div>
{!isApp && isCurrentWorkspaceEditor && (
<MenuItem as="div" className='w-full p-1'>
<div onClick={() => onCreate('')} className={cn(
'flex cursor-pointer items-center gap-2 rounded-lg px-3 py-[6px] hover:bg-state-base-hover ',
)}>
<div className='flex h-6 w-6 shrink-0 items-center justify-center rounded-[6px] border-[0.5px] border-divider-regular bg-background-default'>
<RiAddLine className='h-4 w-4 text-text-primary' />
</div>
</MenuItem>
)}
{isApp && isCurrentWorkspaceEditor && (
<Menu as="div" className="relative h-full w-full">
{({ open }) => (
<>
<MenuButton className='w-full p-1'>
<div className={cn(
'flex cursor-pointer items-center gap-2 rounded-lg px-3 py-[6px] hover:bg-state-base-hover',
open && '!bg-state-base-hover',
)}>
<div className='flex h-6 w-6 shrink-0 items-center justify-center rounded-[6px] border-[0.5px] border-divider-regular bg-background-default'>
<RiAddLine className='h-4 w-4 text-text-primary' />
</div>
<div className='grow text-left text-[14px] font-normal text-text-secondary'>{createText}</div>
<RiArrowRightSLine className='h-3.5 w-3.5 shrink-0 text-text-primary' />
<div className='grow text-left text-[14px] font-normal text-text-secondary'>{createText}</div>
</div>
</MenuItem>
)}
{isApp && isCurrentWorkspaceEditor && (
<Menu as="div" className="relative h-full w-full">
{({ open }) => (
<>
<MenuButton className='w-full p-1'>
<div className={cn(
'flex cursor-pointer items-center gap-2 rounded-lg px-3 py-[6px] hover:bg-state-base-hover',
open && '!bg-state-base-hover',
)}>
<div className='flex h-6 w-6 shrink-0 items-center justify-center rounded-[6px] border-[0.5px] border-divider-regular bg-background-default'>
<RiAddLine className='h-4 w-4 text-text-primary' />
</div>
</MenuButton>
<Transition
as={Fragment}
enter="transition ease-out duration-100"
enterFrom="transform opacity-0 scale-95"
enterTo="transform opacity-100 scale-100"
leave="transition ease-in duration-75"
leaveFrom="transform opacity-100 scale-100"
leaveTo="transform opacity-0 scale-95"
>
<MenuItems className={cn(
'absolute right-[-198px] top-[3px] z-10 min-w-[200px] rounded-lg bg-components-panel-bg-blur shadow-lg',
)}>
<div className='p-1'>
<div className={cn('flex cursor-pointer items-center rounded-lg px-3 py-[6px] font-normal text-text-secondary hover:bg-state-base-hover')} onClick={() => onCreate('blank')}>
<FilePlus01 className='mr-2 h-4 w-4 shrink-0 text-text-secondary' />
{t('app.newApp.startFromBlank')}
</div>
<div className={cn('flex cursor-pointer items-center rounded-lg px-3 py-[6px] font-normal text-text-secondary hover:bg-state-base-hover')} onClick={() => onCreate('template')}>
<FilePlus02 className='mr-2 h-4 w-4 shrink-0 text-text-secondary' />
{t('app.newApp.startFromTemplate')}
</div>
<div className='grow text-left text-[14px] font-normal text-text-secondary'>{createText}</div>
<RiArrowRightSLine className='h-3.5 w-3.5 shrink-0 text-text-primary' />
</div>
</MenuButton>
<Transition
as={Fragment}
enter="transition ease-out duration-100"
enterFrom="transform opacity-0 scale-95"
enterTo="transform opacity-100 scale-100"
leave="transition ease-in duration-75"
leaveFrom="transform opacity-100 scale-100"
leaveTo="transform opacity-0 scale-95"
>
<MenuItems className={cn(
'absolute right-[-198px] top-[3px] z-10 min-w-[200px] rounded-lg bg-components-panel-bg-blur shadow-lg',
)}>
<div className='p-1'>
<div className={cn('flex cursor-pointer items-center rounded-lg px-3 py-[6px] font-normal text-text-secondary hover:bg-state-base-hover')} onClick={() => onCreate('blank')}>
<FilePlus01 className='mr-2 h-4 w-4 shrink-0 text-text-secondary' />
{t('app.newApp.startFromBlank')}
</div>
<div className='border-t border-divider-regular p-1'>
<div className={cn('flex cursor-pointer items-center rounded-lg px-3 py-[6px] font-normal text-text-secondary hover:bg-state-base-hover')} onClick={() => onCreate('dsl')}>
<FileArrow01 className='mr-2 h-4 w-4 shrink-0 text-text-secondary' />
{t('app.importDSL')}
</div>
<div className={cn('flex cursor-pointer items-center rounded-lg px-3 py-[6px] font-normal text-text-secondary hover:bg-state-base-hover')} onClick={() => onCreate('template')}>
<FilePlus02 className='mr-2 h-4 w-4 shrink-0 text-text-secondary' />
{t('app.newApp.startFromTemplate')}
</div>
</MenuItems>
</Transition>
</>
)}
</Menu>
)}
</MenuItems>
</>
)}
</Menu>
</div>
</div>
<div className='border-t border-divider-regular p-1'>
<div className={cn('flex cursor-pointer items-center rounded-lg px-3 py-[6px] font-normal text-text-secondary hover:bg-state-base-hover')} onClick={() => onCreate('dsl')}>
<FileArrow01 className='mr-2 h-4 w-4 shrink-0 text-text-secondary' />
{t('app.importDSL')}
</div>
</div>
</MenuItems>
</Transition>
</>
)}
</Menu>
)}
</MenuItems>
</>
)}
</Menu>
)
}

View File

@ -28,10 +28,12 @@ const ToolsNav = ({
)}>
{
activated
? <RiHammerFill className='mr-2 h-4 w-4' />
: <RiHammerLine className='mr-2 h-4 w-4' />
? <RiHammerFill className='h-4 w-4' />
: <RiHammerLine className='h-4 w-4' />
}
{t('common.menus.tools')}
<div className='ml-2 max-[1024px]:hidden'>
{t('common.menus.tools')}
</div>
</Link>
)
}

View File

@ -83,6 +83,7 @@ const SelectPackage: React.FC<SelectPackageProps> = ({
installedValue={updatePayload?.originalPackageInfo.version}
placeholder={t(`${i18nPrefix}.selectVersionPlaceholder`) || ''}
popupClassName='w-[512px] z-[1001]'
triggerClassName='text-components-input-text-filled'
/>
<label
htmlFor='package'
@ -97,6 +98,7 @@ const SelectPackage: React.FC<SelectPackageProps> = ({
readonly={!selectedVersion}
placeholder={t(`${i18nPrefix}.selectPackagePlaceholder`) || ''}
popupClassName='w-[512px] z-[1001]'
triggerClassName='text-components-input-text-filled'
/>
<div className='mt-4 flex items-center justify-end gap-2 self-stretch'>
{!isEdit

View File

@ -31,10 +31,13 @@ const TestApi: FC<Props> = ({
const language = getLanguage(locale)
const [credentialsModalShow, setCredentialsModalShow] = useState(false)
const [tempCredential, setTempCredential] = React.useState<Credential>(customCollection.credentials)
const [testing, setTesting] = useState(false)
const [result, setResult] = useState<string>('')
const { operation_id: toolName, parameters } = tool
const [parametersValue, setParametersValue] = useState<Record<string, string>>({})
const handleTest = async () => {
if (testing) return
setTesting(true)
// clone test schema
const credentials = JSON.parse(JSON.stringify(tempCredential)) as Credential
if (credentials.auth_type === AuthType.none) {
@ -52,6 +55,7 @@ const TestApi: FC<Props> = ({
}
const res = await testAPIAvailable(data) as any
setResult(res.error || res.result)
setTesting(false)
}
return (
@ -107,7 +111,7 @@ const TestApi: FC<Props> = ({
</div>
</div>
<Button variant='primary' className=' mt-4 h-10 w-full' onClick={handleTest}>{t('tools.test.title')}</Button>
<Button variant='primary' className=' mt-4 h-10 w-full' loading={testing} disabled={testing} onClick={handleTest}>{t('tools.test.title')}</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>

View File

@ -61,7 +61,7 @@ export const useShortcuts = (): void => {
return !showFeaturesPanel && !isEventTargetInputArea(e.target as HTMLElement)
}, [workflowStore])
useKeyPress(['delete', 'backspace'], (e) => {
useKeyPress(['delete'], (e) => {
if (shouldHandleShortcut(e)) {
e.preventDefault()
handleNodesDelete()

View File

@ -118,6 +118,7 @@ export const AgentStrategy = memo((props: AgentStrategyProps) => {
title={<>
{renderI18nObject(def.label)} {def.required && <span className='text-red-500'>*</span>}
</>}
key={def.variable}
tooltip={def.tooltip && renderI18nObject(def.tooltip)}
inline
>
@ -222,7 +223,8 @@ export const AgentStrategy = memo((props: AgentStrategyProps) => {
description={<div className='text-xs text-text-tertiary'>
{t('workflow.nodes.agent.strategy.configureTipDesc')} <br />
<Link href={docLink('/guides/workflow/node/agent#select-an-agent-strategy', {
'zh-Hans': '/guides/workflow/node/agent#xuan-ze-agent-ce-le',
'zh-Hans': '/guides/workflow/node/agent#选择-agent-策略',
'ja-JP': '/guides/workflow/node/agent#エージェント戦略の選択',
})}
className='text-text-accent-secondary' target='_blank'>
{t('workflow.nodes.agent.learnMore')}

View File

@ -140,6 +140,7 @@ const CodeEditor: FC<Props> = ({
language={languageMap[language] || 'javascript'}
theme={isMounted ? theme : 'default-theme'} // sometimes not load the default theme
value={outPutValue}
loading={<span className='text-text-primary'>Loading...</span>}
onChange={handleEditorChange}
// https://microsoft.github.io/monaco-editor/typedoc/interfaces/editor.IEditorOptions.html
options={{

View File

@ -36,7 +36,9 @@ const DefaultValue = ({
{t('workflow.nodes.common.errorHandle.defaultValue.desc')}
&nbsp;
<a
href={docLink('/guides/workflow/error-handling/README')}
href={docLink('/guides/workflow/error-handling/README', {
'zh-Hans': '/guides/workflow/error-handling/readme',
})}
target='_blank'
className='text-text-accent'
>

View File

@ -8,6 +8,8 @@ import VarReferencePicker from './var-reference-picker'
import Input from '@/app/components/base/input'
import type { ValueSelector, Var, Variable } from '@/app/components/workflow/types'
import { VarType as VarKindType } from '@/app/components/workflow/nodes/tool/types'
import { checkKeys } from '@/utils/var'
import Toast from '@/app/components/base/toast'
type Props = {
nodeId: string
@ -36,9 +38,27 @@ const VarList: FC<Props> = ({
const handleVarNameChange = useCallback((index: number) => {
return (e: React.ChangeEvent<HTMLInputElement>) => {
onVarNameChange?.(list[index].variable, e.target.value)
const newKey = e.target.value
const { isValid, errorKey, errorMessageKey } = checkKeys([newKey], true)
if (!isValid) {
Toast.notify({
type: 'error',
message: t(`appDebug.varKeyError.${errorMessageKey}`, { key: errorKey }),
})
return
}
if (list.map(item => item.variable?.trim()).includes(newKey.trim())) {
Toast.notify({
type: 'error',
message: t('appDebug.varKeyError.keyAlreadyExists', { key: newKey }),
})
return
}
onVarNameChange?.(list[index].variable, newKey)
const newList = produce(list, (draft) => {
draft[index].variable = e.target.value
draft[index].variable = newKey
})
onChange(newList)
}

View File

@ -44,8 +44,11 @@ const VarReferencePopup: FC<Props> = ({
description={<div className='system-xs-regular text-text-tertiary'>
{t('workflow.variableReference.assignedVarsDescription')}
<a target='_blank' rel='noopener noreferrer'
className='text-text-accent-secondary'
href={docLink('/guides/workflow/variables#conversation-variables', { 'zh-Hans': '/guides/workflow/variables#hui-hua-bian-liang' })}>
className='text-text-accent-secondary'
href={docLink('/guides/workflow/variables#conversation-variables', {
'zh-Hans': '/guides/workflow/variables#会话变量',
'ja-JP': '/guides/workflow/variables#会話変数',
})}>
{t('workflow.variableReference.conversationVars')}
</a>
</div>}

View File

@ -260,6 +260,7 @@ type Props = {
maxHeightClass?: string
onClose?: () => void
onBlur?: () => void
autoFocus?: boolean
}
const VarReferenceVars: FC<Props> = ({
hideSearch,
@ -271,6 +272,7 @@ const VarReferenceVars: FC<Props> = ({
maxHeightClass,
onClose,
onBlur,
autoFocus = true,
}) => {
const { t } = useTranslation()
const [searchText, setSearchText] = useState('')
@ -323,7 +325,7 @@ const VarReferenceVars: FC<Props> = ({
onKeyDown={handleKeyDown}
onClear={() => setSearchText('')}
onBlur={onBlur}
autoFocus
autoFocus={autoFocus}
/>
</div>
<div className='relative left-[-4px] h-[0.5px] bg-black/5' style={{

View File

@ -54,9 +54,9 @@ const AgentNode: FC<NodeProps<AgentNodeType>> = (props) => {
const field = param.name
const value = inputs.agent_parameters?.[field]?.value
if (value) {
(value as unknown as any[]).forEach((item) => {
(value as unknown as any[]).forEach((item, idx) => {
tools.push({
id: `${param.name}-${i}`,
id: `${param.name}-${idx}`,
providerName: item.provider_name,
})
})

View File

@ -138,10 +138,13 @@ const ChatVariablePanel = () => {
<div className='system-sm-regular mb-4 mt-1 text-text-secondary'>
{t('workflow.chatVariable.panelDescription')}
<a target='_blank' rel='noopener noreferrer' className='text-text-accent'
href={docLink('/guides/workflow/variables#conversation-variables', { 'zh-Hans': '/guides/workflow/variables#hui-hua-bian-liang' })}>
href={docLink('/guides/workflow/variables#conversation-variables', {
'zh-Hans': '/guides/workflow/variables#会话变量',
'ja-JP': '/guides/workflow/variables#会話変数',
})}>
{t('workflow.chatVariable.docLink')}
</a>
</div>
</div>
<div className='flex items-center gap-2'>
<div className='radius-lg flex flex-col border border-workflow-block-border bg-workflow-block-bg p-3 pb-4 shadow-md'>
<BubbleX className='mb-1 h-4 w-4 shrink-0 text-util-colors-teal-teal-700' />
@ -167,7 +170,7 @@ const ChatVariablePanel = () => {
</div>
</div>
</div>
<div className='absolute right-[38px] top-[-4px] z-10 h-3 w-3 rotate-45 bg-background-section-burn'/>
<div className='absolute right-[38px] top-[-4px] z-10 h-3 w-3 rotate-45 bg-background-section-burn' />
</div>
</div>
)}

View File

@ -139,7 +139,7 @@ const VariableModal = ({
<div className='flex'>
{
type !== 'number' ? <textarea
className='system-sm-regular placeholder:system-sm-regular block h-20 w-full resize-none appearance-none rounded-lg border border-transparent bg-components-input-bg-normal p-2 caret-primary-600 outline-none placeholder:text-components-input-text-placeholder hover:border-components-input-border-hover hover:bg-components-input-bg-hover focus:border-components-input-border-active focus:bg-components-input-bg-active focus:shadow-xs'
className='system-sm-regular placeholder:system-sm-regular block h-20 w-full resize-none appearance-none rounded-lg border border-transparent bg-components-input-bg-normal p-2 text-components-input-text-filled caret-primary-600 outline-none placeholder:text-components-input-text-placeholder hover:border-components-input-border-hover hover:bg-components-input-bg-hover focus:border-components-input-border-active focus:bg-components-input-bg-active focus:shadow-xs'
value={value}
placeholder={t('workflow.env.modal.valuePlaceholder') || ''}
onChange={e => setValue(e.target.value)}

View File

@ -24,11 +24,6 @@ export const useGetLanguage = () => {
return getLanguage(locale)
}
export const useGetDocLanguage = () => {
const { locale } = useI18N()
return getDocLanguage(locale)
}
export const useGetPricingPageLanguage = () => {
const { locale } = useI18N()
@ -37,15 +32,15 @@ export const useGetPricingPageLanguage = () => {
const defaultDocBaseUrl = 'https://docs.dify.ai'
export const useDocLink = (baseUrl?: string): ((path?: string, pathMap?: { [index: string]: string }) => string) => {
let baseDocUrl = baseUrl || defaultDocBaseUrl
baseDocUrl = (baseDocUrl.endsWith('/')) ? baseDocUrl.slice(0, -1) : baseDocUrl
const { locale } = useI18N()
const docLanguage = getDocLanguage(locale)
return (path?: string, pathMap?: { [index: string]: string }): string => {
const pathUrl = path || ''
let targetPath = (pathMap) ? pathMap[locale] || pathUrl : pathUrl
targetPath = (targetPath.startsWith('/')) ? targetPath.slice(0, -1) : targetPath
return `${baseDocUrl}/${docLanguage}/${targetPath}`
}
let baseDocUrl = baseUrl || defaultDocBaseUrl
baseDocUrl = (baseDocUrl.endsWith('/')) ? baseDocUrl.slice(0, -1) : baseDocUrl
const { locale } = useI18N()
const docLanguage = getDocLanguage(locale)
return (path?: string, pathMap?: { [index: string]: string }): string => {
const pathUrl = path || ''
let targetPath = (pathMap) ? pathMap[locale] || pathUrl : pathUrl
targetPath = (targetPath.startsWith('/')) ? targetPath.slice(1) : targetPath
return `${baseDocUrl}/${docLanguage}/${targetPath}`
}
}
export default I18NContext

View File

@ -467,7 +467,6 @@ const translation = {
apiBasedExtension: {
title: 'API-Erweiterungen bieten zentralisiertes API-Management und vereinfachen die Konfiguration für eine einfache Verwendung in Difys Anwendungen.',
link: 'Erfahren Sie, wie Sie Ihre eigene API-Erweiterung entwickeln.',
linkUrl: 'https://docs.dify.ai/en/guides/extension/api-based-extension/README',
add: 'API-Erweiterung hinzufügen',
selector: {
title: 'API-Erweiterung',

View File

@ -69,7 +69,6 @@ const translation = {
unknownError: 'Unbekannter Fehler',
resetAll: 'Alles zurücksetzen',
extractOnlyMainContent: 'Extrahieren Sie nur den Hauptinhalt (keine Kopf-, Navigations- und Fußzeilen usw.)',
firecrawlDocLink: 'https://docs.dify.ai/en/guides/knowledge-base/create-knowledge-and-upload-documents/import-content-data/sync-from-website',
firecrawlTitle: 'Extrahieren von Webinhalten mit 🔥Firecrawl',
maxDepthTooltip: 'Maximale Tiefe für das Crawlen relativ zur eingegebenen URL. Tiefe 0 kratzt nur die Seite der eingegebenen URL, Tiefe 1 kratzt die URL und alles nach der eingegebenen URL + ein / und so weiter.',
crawlSubPage: 'Unterseiten crawlen',
@ -85,7 +84,6 @@ const translation = {
configureJinaReader: 'Jina Reader konfigurieren',
waterCrawlNotConfigured: 'Watercrawl ist nicht konfiguriert',
configureWatercrawl: 'Wasserkrabbe konfigurieren',
watercrawlDocLink: 'https://docs.dify.ai/de/guides/knowledge-base/create-knowledge-and-upload-documents/import-content-data/sync-from-website',
watercrawlTitle: 'Webinhalt mit Watercrawl extrahieren',
watercrawlDoc: 'Wasserkriechen-Dokumente',
configureFirecrawl: 'Firecrawl konfigurieren',

View File

@ -38,8 +38,6 @@ const translation = {
setVarValuePlaceholder: 'Variable setzen',
needConnectTip: 'Dieser Schritt ist mit nichts verbunden',
maxTreeDepth: 'Maximales Limit von {{depth}} Knoten pro Ast',
needEndNode: 'Der Endblock muss hinzugefügt werden',
needAnswerNode: 'Der Antwortblock muss hinzugefügt werden',
workflowProcess: 'Arbeitsablauf',
notRunning: 'Noch nicht ausgeführt',
previewPlaceholder: 'Geben Sie den Inhalt in das Feld unten ein, um das Debuggen des Chatbots zu starten',
@ -58,7 +56,6 @@ const translation = {
learnMore: 'Mehr erfahren',
copy: 'Kopieren',
duplicate: 'Duplizieren',
addBlock: 'Block hinzufügen',
pasteHere: 'Hier einfügen',
pointerMode: 'Zeigermodus',
handMode: 'Handmodus',
@ -115,6 +112,9 @@ const translation = {
exportJPEG: 'Als JPEG exportieren',
exitVersions: 'Ausgangsversionen',
exportPNG: 'Als PNG exportieren',
addBlock: 'Knoten hinzufügen',
needEndNode: 'Der Endknoten muss hinzugefügt werden.',
needAnswerNode: 'Der Antwortknoten muss hinzugefügt werden.',
},
env: {
envPanelTitle: 'Umgebungsvariablen',
@ -176,19 +176,19 @@ const translation = {
stepForward_other: '{{count}} Schritte vorwärts',
sessionStart: 'Sitzungsstart',
currentState: 'Aktueller Zustand',
nodeTitleChange: 'Blocktitel geändert',
nodeDescriptionChange: 'Blockbeschreibung geändert',
nodeDragStop: 'Block verschoben',
nodeChange: 'Block geändert',
nodeConnect: 'Block verbunden',
nodePaste: 'Block eingefügt',
nodeDelete: 'Block gelöscht',
nodeAdd: 'Block hinzugefügt',
nodeResize: 'Blockgröße geändert',
noteAdd: 'Notiz hinzugefügt',
noteChange: 'Notiz geändert',
noteDelete: 'Notiz gelöscht',
edgeDelete: 'Block getrennt',
edgeDelete: 'Knoten getrennt',
nodeAdd: 'Knoten hinzugefügt',
nodeTitleChange: 'Knotenüberschrift geändert',
nodePaste: 'Knoten eingefügt',
nodeResize: 'Knoten verkleinert',
nodeDescriptionChange: 'Die Knotenbeschreibung wurde geändert',
nodeChange: 'Knoten geändert',
nodeConnect: 'Node verbunden',
nodeDragStop: 'Knoten verschoben',
nodeDelete: 'Knoten gelöscht',
},
errorMsg: {
fieldRequired: '{{field}} ist erforderlich',
@ -217,8 +217,6 @@ const translation = {
loop: 'Schleife',
},
tabs: {
'searchBlock': 'Block suchen',
'blocks': 'Blöcke',
'tools': 'Werkzeuge',
'allTool': 'Alle',
'builtInTool': 'Eingebaut',
@ -232,6 +230,8 @@ const translation = {
'searchTool': 'Suchwerkzeug',
'plugin': 'Stecker',
'agent': 'Agenten-Strategie',
'searchBlock': 'Suchknoten',
'blocks': 'Knoten',
},
blocks: {
'start': 'Start',
@ -288,21 +288,21 @@ const translation = {
},
panel: {
userInputField: 'Benutzereingabefeld',
changeBlock: 'Block ändern',
helpLink: 'Hilfelink',
about: 'Über',
createdBy: 'Erstellt von ',
nextStep: 'Nächster Schritt',
addNextStep: 'Fügen Sie den nächsten Block in diesem Workflow hinzu',
selectNextStep: 'Nächsten Block auswählen',
runThisStep: 'Diesen Schritt ausführen',
checklist: 'Checkliste',
checklistTip: 'Stellen Sie sicher, dass alle Probleme vor der Veröffentlichung gelöst sind',
checklistResolved: 'Alle Probleme wurden gelöst',
organizeBlocks: 'Blöcke organisieren',
change: 'Ändern',
optional: '(optional)',
moveToThisNode: 'Bewege zu diesem Knoten',
selectNextStep: 'Nächsten Schritt auswählen',
addNextStep: 'Fügen Sie den nächsten Schritt in diesem Arbeitsablauf hinzu.',
organizeBlocks: 'Knoten organisieren',
changeBlock: 'Knoten ändern',
},
nodes: {
common: {

View File

@ -484,7 +484,6 @@ const translation = {
apiBasedExtension: {
title: 'API extensions provide centralized API management, simplifying configuration for easy use across Dify\'s applications.',
link: 'Learn how to develop your own API Extension.',
linkUrl: 'https://docs.dify.ai/en/guides/extension/api-based-extension/README',
add: 'Add API Extension',
selector: {
title: 'API Extension',

View File

@ -80,10 +80,8 @@ const translation = {
run: 'Run',
firecrawlTitle: 'Extract web content with 🔥Firecrawl',
firecrawlDoc: 'Firecrawl docs',
firecrawlDocLink: 'https://docs.dify.ai/en/guides/knowledge-base/create-knowledge-and-upload-documents/import-content-data/sync-from-website',
watercrawlTitle: 'Extract web content with Watercrawl',
watercrawlDoc: 'Watercrawl docs',
watercrawlDocLink: 'https://docs.dify.ai/en/guides/knowledge-base/create-knowledge-and-upload-documents/import-content-data/sync-from-website',
jinaReaderTitle: 'Convert the entire site to Markdown',
jinaReaderDoc: 'Learn more about Jina Reader',
jinaReaderDocLink: 'https://jina.ai/reader',

View File

@ -46,8 +46,8 @@ const translation = {
setVarValuePlaceholder: 'Set variable',
needConnectTip: 'This step is not connected to anything',
maxTreeDepth: 'Maximum limit of {{depth}} nodes per branch',
needEndNode: 'The End block must be added',
needAnswerNode: 'The Answer block must be added',
needEndNode: 'The End node must be added',
needAnswerNode: 'The Answer node must be added',
workflowProcess: 'Workflow Process',
notRunning: 'Not running yet',
previewPlaceholder: 'Enter content in the box below to start debugging the Chatbot',
@ -66,7 +66,7 @@ const translation = {
learnMore: 'Learn More',
copy: 'Copy',
duplicate: 'Duplicate',
addBlock: 'Add Block',
addBlock: 'Add Node',
pasteHere: 'Paste Here',
pointerMode: 'Pointer Mode',
handMode: 'Hand Mode',
@ -174,19 +174,19 @@ const translation = {
stepForward_other: '{{count}} steps forward',
sessionStart: 'Session Start',
currentState: 'Current State',
nodeTitleChange: 'Block title changed',
nodeDescriptionChange: 'Block description changed',
nodeDragStop: 'Block moved',
nodeChange: 'Block changed',
nodeConnect: 'Block connected',
nodePaste: 'Block pasted',
nodeDelete: 'Block deleted',
nodeAdd: 'Block added',
nodeResize: 'Block resized',
nodeTitleChange: 'Node title changed',
nodeDescriptionChange: 'Node description changed',
nodeDragStop: 'Node moved',
nodeChange: 'Node changed',
nodeConnect: 'Node connected',
nodePaste: 'Node pasted',
nodeDelete: 'Node deleted',
nodeAdd: 'Node added',
nodeResize: 'Node resized',
noteAdd: 'Note added',
noteChange: 'Note changed',
noteDelete: 'Note deleted',
edgeDelete: 'Block disconnected',
edgeDelete: 'Node disconnected',
},
errorMsg: {
fieldRequired: '{{field}} is required',
@ -215,8 +215,8 @@ const translation = {
loop: 'Loop',
},
tabs: {
'searchBlock': 'Search block',
'blocks': 'Blocks',
'searchBlock': 'Search node',
'blocks': 'Nodes',
'searchTool': 'Search tool',
'tools': 'Tools',
'allTool': 'All',
@ -292,19 +292,19 @@ const translation = {
},
panel: {
userInputField: 'User Input Field',
changeBlock: 'Change Block',
changeBlock: 'Change Node',
helpLink: 'Help Link',
about: 'About',
createdBy: 'Created By ',
nextStep: 'Next Step',
addNextStep: 'Add the next block in this workflow',
selectNextStep: 'Select Next Block',
addNextStep: 'Add the next step in this workflow',
selectNextStep: 'Select Next Step',
runThisStep: 'Run this step',
moveToThisNode: 'Move to this node',
checklist: 'Checklist',
checklistTip: 'Make sure all issues are resolved before publishing',
checklistResolved: 'All issues are resolved',
organizeBlocks: 'Organize blocks',
organizeBlocks: 'Organize nodes',
change: 'Change',
optional: '(optional)',
},

View File

@ -207,6 +207,7 @@ const translation = {
modelNotSupportedTip: 'El modelo actual no admite esta función y se degrada automáticamente a inyección de comandos.',
structuredTip: 'Las Salidas Estructuradas son una función que garantiza que el modelo siempre generará respuestas que se ajusten a su esquema JSON proporcionado.',
modelNotSupported: 'Modelo no soportado',
structured: 'sistemático',
},
accessItemsDescription: {
anyone: 'Cualquiera puede acceder a la aplicación web.',

View File

@ -471,7 +471,6 @@ const translation = {
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.',
link: 'Aprende cómo desarrollar tu propia Extensión API.',
linkUrl: 'https://docs.dify.ai/en/guides/extension/api-based-extension/README',
add: 'Agregar Extensión API',
selector: {
title: 'Extensión API',

View File

@ -63,7 +63,6 @@ const translation = {
run: 'Ejecutar',
firecrawlTitle: 'Extraer contenido web con 🔥Firecrawl',
firecrawlDoc: 'Documentación de Firecrawl',
firecrawlDocLink: 'https://docs.dify.ai/en/guides/knowledge-base/create-knowledge-and-upload-documents/import-content-data/sync-from-website',
options: 'Opciones',
crawlSubPage: 'Rastrear subpáginas',
limit: 'Límite',
@ -92,7 +91,6 @@ const translation = {
configureFirecrawl: 'Configurar Firecrawl',
watercrawlDoc: 'Documentos de Watercrawl',
configureJinaReader: 'Configurar Jina Reader',
watercrawlDocLink: 'https://docs.dify.ai/es/guías/base-de-conocimientos/crear-conocimientos-y-subir-documentos/importar-datos-de-contenido/sincronizar-desde-el-sitio-web',
configureWatercrawl: 'Configurar Watercrawl',
waterCrawlNotConfiguredDescription: 'Configura Watercrawl con la clave de API para usarlo.',
},

View File

@ -202,6 +202,7 @@ const translation = {
builtInDescription: 'Los metadatos integrados se extraen y generan automáticamente. Deben estar habilitados antes de su uso y no se pueden editar.',
name: 'Nombre',
description: 'Puedes gestionar todos los metadatos en este conocimiento aquí. Las modificaciones se sincronizarán en todos los documentos.',
disabled: 'desactivar',
},
documentMetadata: {
technicalParameters: 'Parámetros técnicos',

View File

@ -38,8 +38,6 @@ const translation = {
setVarValuePlaceholder: 'Establecer variable',
needConnectTip: 'Este paso no está conectado a nada',
maxTreeDepth: 'Límite máximo de {{depth}} nodos por rama',
needEndNode: 'Debe agregarse el bloque de Fin',
needAnswerNode: 'Debe agregarse el bloque de Respuesta',
workflowProcess: 'Proceso de flujo de trabajo',
notRunning: 'Aún no se está ejecutando',
previewPlaceholder: 'Ingrese contenido en el cuadro de abajo para comenzar a depurar el Chatbot',
@ -58,7 +56,6 @@ const translation = {
learnMore: 'Más información',
copy: 'Copiar',
duplicate: 'Duplicar',
addBlock: 'Agregar bloque',
pasteHere: 'Pegar aquí',
pointerMode: 'Modo puntero',
handMode: 'Modo mano',
@ -115,6 +112,9 @@ const translation = {
publishUpdate: 'Publicar actualización',
noExist: 'No existe tal variable',
exportImage: 'Exportar imagen',
needAnswerNode: 'Se debe agregar el nodo de respuesta',
needEndNode: 'Se debe agregar el nodo Final',
addBlock: 'Agregar nodo',
},
env: {
envPanelTitle: 'Variables de Entorno',
@ -176,19 +176,19 @@ const translation = {
stepForward_other: '{{count}} pasos hacia adelante',
sessionStart: 'Inicio de sesión',
currentState: 'Estado actual',
nodeTitleChange: 'Se cambió el título del bloque',
nodeDescriptionChange: 'Se cambió la descripción del bloque',
nodeDragStop: 'Bloque movido',
nodeChange: 'Bloque cambiado',
nodeConnect: 'Bloque conectado',
nodePaste: 'Bloque pegado',
nodeDelete: 'Bloque eliminado',
nodeAdd: 'Bloque agregado',
nodeResize: 'Bloque redimensionado',
noteAdd: 'Nota agregada',
noteChange: 'Nota cambiada',
noteDelete: 'Nota eliminada',
edgeDelete: 'Bloque desconectado',
nodeTitleChange: 'Título del nodo cambiado',
nodeAdd: 'Nodo añadido',
nodePaste: 'Nodo pegado',
nodeDragStop: 'Nodo movido',
nodeConnect: 'Nodo conectado',
edgeDelete: 'Nodo desconectado',
nodeDelete: 'Nodo eliminado',
nodeChange: 'Nodo cambiado',
nodeDescriptionChange: 'Descripción del nodo cambiada',
nodeResize: 'Nodo redimensionado',
},
errorMsg: {
fieldRequired: 'Se requiere {{field}}',
@ -217,8 +217,6 @@ const translation = {
loop: 'Bucle',
},
tabs: {
'searchBlock': 'Buscar bloque',
'blocks': 'Bloques',
'tools': 'Herramientas',
'allTool': 'Todos',
'builtInTool': 'Incorporadas',
@ -232,6 +230,8 @@ const translation = {
'searchTool': 'Herramienta de búsqueda',
'agent': 'Estrategia del agente',
'plugin': 'Plugin',
'searchBlock': 'Buscar nodo',
'blocks': 'Nodos',
},
blocks: {
'start': 'Inicio',
@ -288,21 +288,21 @@ const translation = {
},
panel: {
userInputField: 'Campo de entrada del usuario',
changeBlock: 'Cambiar bloque',
helpLink: 'Enlace de ayuda',
about: 'Acerca de',
createdBy: 'Creado por ',
nextStep: 'Siguiente paso',
addNextStep: 'Agregar el siguiente bloque en este flujo de trabajo',
selectNextStep: 'Seleccionar siguiente bloque',
runThisStep: 'Ejecutar este paso',
checklist: 'Lista de verificación',
checklistTip: 'Asegúrate de resolver todos los problemas antes de publicar',
checklistResolved: 'Se resolvieron todos los problemas',
organizeBlocks: 'Organizar bloques',
change: 'Cambiar',
optional: '(opcional)',
moveToThisNode: 'Mueve a este nodo',
organizeBlocks: 'Organizar nodos',
addNextStep: 'Agrega el siguiente paso en este flujo de trabajo',
changeBlock: 'Cambiar Nodo',
selectNextStep: 'Seleccionar siguiente paso',
},
nodes: {
common: {

View File

@ -471,7 +471,6 @@ const translation = {
apiBasedExtension: {
title: 'افزونه‌های مبتنی بر API مدیریت متمرکز API را فراهم می‌کنند و پیکربندی را برای استفاده آسان در برنامه‌های Dify ساده می‌کنند.',
link: 'نحوه توسعه افزونه API خود را بیاموزید.',
linkUrl: 'https://docs.dify.ai/en/guides/extension/api-based-extension/README',
add: 'افزودن افزونه API',
selector: {
title: 'افزونه API',

View File

@ -63,7 +63,6 @@ const translation = {
run: 'اجرا',
firecrawlTitle: 'استخراج محتوای وب با fireFirecrawl',
firecrawlDoc: 'مستندات Firecrawl',
firecrawlDocLink: '<a href="https://docs.dify.ai/en/guides/knowledge-base/create-knowledge-and-upload-documents/import-content-data/sync-from-website">https://docs.dify.ai/en/guides/knowledge-base/create-knowledge-and-upload-documents/import-content-data/sync-from-website</a>',
options: 'گزینهها',
crawlSubPage: 'خزش صفحات فرعی',
limit: 'محدودیت',
@ -92,7 +91,6 @@ const translation = {
waterCrawlNotConfiguredDescription: 'برای استفاده از Watercrawl، آن را با کلید API پیکربندی کنید.',
waterCrawlNotConfigured: 'Watercrawl پیکربندی نشده است',
configureJinaReader: 'پیکربندی خواننده جینا',
watercrawlDocLink: 'https://docs.dify.ai/fa/guides/knowledge-base/create-knowledge-and-upload-documents/import-content-data/sync-from-website',
watercrawlTitle: 'محتوای وب را با واترکرال استخراج کنید',
configureWatercrawl: 'تنظیم واترکراول',
},

View File

@ -38,8 +38,6 @@ const translation = {
setVarValuePlaceholder: 'تنظیم متغیر',
needConnectTip: 'این مرحله به هیچ چیزی متصل نیست',
maxTreeDepth: 'حداکثر عمق {{depth}} نود در هر شاخه',
needEndNode: 'بلوک پایان باید اضافه شود',
needAnswerNode: 'بلوک پاسخ باید اضافه شود',
workflowProcess: 'فرآیند جریان کار',
notRunning: 'هنوز در حال اجرا نیست',
previewPlaceholder: 'محتوا را در کادر زیر وارد کنید تا اشکال‌زدایی چت‌بات را شروع کنید',
@ -58,7 +56,6 @@ const translation = {
learnMore: 'اطلاعات بیشتر',
copy: 'کپی',
duplicate: 'تکرار',
addBlock: 'افزودن بلوک',
pasteHere: 'چسباندن اینجا',
pointerMode: 'حالت اشاره‌گر',
handMode: 'حالت دست',
@ -115,6 +112,9 @@ const translation = {
exportImage: 'تصویر را صادر کنید',
versionHistory: 'تاریخچه نسخه',
publishUpdate: 'به‌روزرسانی منتشر کنید',
needEndNode: 'باید گره پایان اضافه شود',
needAnswerNode: 'باید گره پاسخ اضافه شود',
addBlock: 'نود اضافه کنید',
},
env: {
envPanelTitle: 'متغیرهای محیطی',
@ -176,19 +176,19 @@ const translation = {
stepForward_other: '{{count}} قدم به جلو',
sessionStart: 'شروع جلسه',
currentState: 'وضعیت کنونی',
nodeTitleChange: 'عنوان بلوک تغییر کرده است',
nodeDescriptionChange: 'توضیحات بلوک تغییر کرده است',
nodeDragStop: 'بلوک جابجا شده است',
nodeChange: 'بلوک تغییر کرده است',
nodeConnect: 'بلوک متصل شده است',
nodePaste: 'بلوک چسبانده شده است',
nodeDelete: 'بلوک حذف شده است',
nodeAdd: 'بلوک اضافه شده است',
nodeResize: 'اندازه بلوک تغییر کرده است',
noteAdd: 'یادداشت اضافه شده است',
noteChange: 'یادداشت تغییر کرده است',
noteDelete: 'یادداشت حذف شده است',
edgeDelete: 'بلوک قطع شده است',
nodeDelete: 'نود حذف شد',
nodeAdd: 'نود اضافه شد',
nodeDragStop: 'گره منتقل شد',
edgeDelete: 'گره قطع شده است',
nodeResize: 'اندازه نود تغییر یافته است',
nodePaste: 'نود پیست شده است',
nodeTitleChange: 'عنوان نود تغییر کرد',
nodeConnect: 'گره متصل است',
nodeDescriptionChange: 'شرح نود تغییر کرد',
nodeChange: 'نود تغییر کرد',
},
errorMsg: {
fieldRequired: '{{field}} الزامی است',
@ -217,8 +217,6 @@ const translation = {
loop: 'حلقه',
},
tabs: {
'searchBlock': 'جستجوی بلوک',
'blocks': 'بلوک‌ها',
'tools': 'ابزارها',
'allTool': 'همه',
'builtInTool': 'درون‌ساخت',
@ -232,6 +230,8 @@ const translation = {
'searchTool': 'ابزار جستجو',
'plugin': 'افزونه',
'agent': 'استراتژی نمایندگی',
'blocks': 'گره‌ها',
'searchBlock': 'گره جستجو',
},
blocks: {
'start': 'شروع',
@ -288,21 +288,21 @@ const translation = {
},
panel: {
userInputField: 'فیلد ورودی کاربر',
changeBlock: 'تغییر بلوک',
helpLink: 'لینک کمک',
about: 'درباره',
createdBy: 'ساخته شده توسط',
nextStep: 'مرحله بعدی',
addNextStep: 'افزودن بلوک بعدی به این جریان کار',
selectNextStep: 'انتخاب بلوک بعدی',
runThisStep: 'اجرا کردن این مرحله',
checklist: 'چک‌لیست',
checklistTip: 'اطمینان حاصل کنید که همه مسائل قبل از انتشار حل شده‌اند',
checklistResolved: 'تمام مسائل حل شده‌اند',
organizeBlocks: 'سازماندهی بلوک‌ها',
change: 'تغییر',
optional: '(اختیاری)',
moveToThisNode: 'به این گره بروید',
selectNextStep: 'گام بعدی را انتخاب کنید',
changeBlock: 'تغییر گره',
organizeBlocks: 'گره‌ها را سازماندهی کنید',
addNextStep: 'مرحله بعدی را به این فرآیند اضافه کنید',
},
nodes: {
common: {

View File

@ -467,7 +467,6 @@ const translation = {
apiBasedExtension: {
title: 'Les extensions API fournissent une gestion centralisée des API, simplifiant la configuration pour une utilisation facile à travers les applications de Dify.',
link: 'Apprenez comment développer votre propre Extension API.',
linkUrl: 'https://docs.dify.ai/fonctionnalites/extension/extension_basee_sur_api',
add: 'Ajouter l\'extension API',
selector: {
title: 'Extension de l\'API',

View File

@ -61,7 +61,6 @@ const translation = {
preview: 'Aperçu',
crawlSubPage: 'Explorer les sous-pages',
configure: 'Configurer',
firecrawlDocLink: 'https://docs.dify.ai/en/guides/knowledge-base/create-knowledge-and-upload-documents/import-content-data/sync-from-website',
maxDepth: 'Profondeur maximale',
fireCrawlNotConfigured: 'Firecrawl nest pas configuré',
firecrawlTitle: 'Extraire du contenu web avec 🔥Firecrawl',
@ -88,7 +87,6 @@ const translation = {
configureJinaReader: 'Configurer le lecteur Jina',
configureWatercrawl: 'Configurer Watercrawl',
waterCrawlNotConfigured: 'Watercrawl n\'est pas configuré',
watercrawlDocLink: 'https://docs.dify.ai/fr/guide/base-de-connaissances/créer-des-connaissances-et-télécharger-des-documents/importer-des-données-de-contenu/synchroniser-depuis-un-site-web',
configureFirecrawl: 'Configurer Firecrawl',
},
cancel: 'Annuler',

View File

@ -38,8 +38,6 @@ const translation = {
setVarValuePlaceholder: 'Définir la valeur de la variable',
needConnectTip: 'Cette étape n\'est connectée à rien',
maxTreeDepth: 'Limite maximale de {{depth}} nœuds par branche',
needEndNode: 'Le bloc de fin doit être ajouté',
needAnswerNode: 'Le bloc de réponse doit être ajouté',
workflowProcess: 'Processus de flux de travail',
notRunning: 'Pas encore en cours d\'exécution',
previewPlaceholder: 'Entrez le contenu dans la boîte ci-dessous pour commencer à déboguer le Chatbot',
@ -58,7 +56,6 @@ const translation = {
learnMore: 'En savoir plus',
copy: 'Copier',
duplicate: 'Dupliquer',
addBlock: 'Ajouter un bloc',
pasteHere: 'Coller ici',
pointerMode: 'Mode pointeur',
handMode: 'Mode main',
@ -115,6 +112,9 @@ const translation = {
referenceVar: 'Variable de référence',
exportImage: 'Exporter l\'image',
exportJPEG: 'Exporter en JPEG',
needEndNode: 'Le nœud de fin doit être ajouté',
needAnswerNode: 'Le nœud de réponse doit être ajouté.',
addBlock: 'Ajouter un nœud',
},
env: {
envPanelTitle: 'Variables d\'Environnement',
@ -176,19 +176,19 @@ const translation = {
stepForward_other: '{{count}} pas en avant',
sessionStart: 'Début de la session',
currentState: 'État actuel',
nodeTitleChange: 'Titre du bloc modifié',
nodeDescriptionChange: 'Description du bloc modifiée',
nodeDragStop: 'Bloc déplacé',
nodeChange: 'Bloc modifié',
nodeConnect: 'Bloc connecté',
nodePaste: 'Bloc collé',
nodeDelete: 'Bloc supprimé',
nodeAdd: 'Bloc ajouté',
nodeResize: 'Bloc redimensionné',
noteAdd: 'Note ajoutée',
noteChange: 'Note modifiée',
noteDelete: 'Note supprimée',
edgeDelete: 'Bloc déconnecté',
nodeConnect: 'Node connecté',
nodeChange: 'Nœud changé',
nodeResize: 'Nœud redimensionné',
edgeDelete: 'Nœud déconnecté',
nodeDelete: 'Nœud supprimé',
nodePaste: 'Node collé',
nodeDragStop: 'Nœud déplacé',
nodeTitleChange: 'Titre du nœud modifié',
nodeAdd: 'Nœud ajouté',
nodeDescriptionChange: 'La description du nœud a changé',
},
errorMsg: {
fieldRequired: '{{field}} est requis',
@ -217,8 +217,6 @@ const translation = {
loop: 'Boucle',
},
tabs: {
'searchBlock': 'Rechercher un bloc',
'blocks': 'Blocs',
'tools': 'Outils',
'allTool': 'Tous',
'builtInTool': 'Intégré',
@ -232,6 +230,8 @@ const translation = {
'searchTool': 'Outil de recherche',
'plugin': 'Plugin',
'agent': 'Stratégie dagent',
'blocks': 'Nœuds',
'searchBlock': 'Nœud de recherche',
},
blocks: {
'start': 'Début',
@ -288,21 +288,21 @@ const translation = {
},
panel: {
userInputField: 'Champ de saisie de l\'utilisateur',
changeBlock: 'Changer de bloc',
helpLink: 'Lien d\'aide',
about: 'À propos',
createdBy: 'Créé par',
nextStep: 'Étape suivante',
addNextStep: 'Ajouter le prochain bloc dans ce flux de travail',
selectNextStep: 'Sélectionner le prochain bloc',
runThisStep: 'Exécuter cette étape',
checklist: 'Liste de contrôle',
checklistTip: 'Assurez-vous que tous les problèmes sont résolus avant de publier',
checklistResolved: 'Tous les problèmes ont été résolus',
organizeBlocks: 'Organiser les blocs',
change: 'Modifier',
optional: '(facultatif)',
moveToThisNode: 'Déplacer vers ce nœud',
organizeBlocks: 'Organiser les nœuds',
addNextStep: 'Ajoutez la prochaine étape dans ce flux de travail',
selectNextStep: 'Sélectionner la prochaine étape',
changeBlock: 'Changer de nœud',
},
nodes: {
common: {

View File

@ -488,7 +488,6 @@ const translation = {
title:
'एपीआई एक्सटेंशन केंद्रीकृत एपीआई प्रबंधन प्रदान करते हैं, जो Dify के अनुप्रयोगों में आसान उपयोग के लिए कॉन्फ़िगरेशन को सरल बनाते हैं।',
link: 'अपना खुद का एपीआई एक्सटेंशन कैसे विकसित करें, यह जानें।',
linkUrl: 'https://docs.dify.ai/en/guides/extension/api-based-extension/README',
add: 'एपीआई एक्सटेंशन जोड़ें',
selector: {
title: 'एपीआई एक्सटेंशन',

View File

@ -65,8 +65,6 @@ const translation = {
run: 'चलाएं',
firecrawlTitle: '🔥फायरक्रॉल के साथ वेब सामग्री निकालें',
firecrawlDoc: 'फायरक्रॉल दस्तावेज़',
firecrawlDocLink:
'https://docs.dify.ai/guides/knowledge-base/sync_from_website',
options: 'विकल्प',
crawlSubPage: 'उप-पृष्ठों को क्रॉल करें',
limit: 'सीमा',
@ -97,7 +95,6 @@ const translation = {
configureFirecrawl: 'फायरक्रॉल को कॉन्फ़िगर करें',
watercrawlDoc: 'वाटरक्रॉल दस्तावेज़',
waterCrawlNotConfiguredDescription: 'इसे उपयोग करने के लिए वॉटरक्रॉल को एपीआई कुंजी के साथ कॉन्फ़िगर करें।',
watercrawlDocLink: 'https://docs.dify.ai/en/guides/knowledge-base/create-knowledge-and-upload-documents/import-content-data/sync-from-website',
configureJinaReader: 'जिना रीडर कॉन्फ़िगर करें',
configureWatercrawl: 'वाटरक्रॉल कॉन्फ़िगर करें',
},

View File

@ -38,8 +38,6 @@ const translation = {
setVarValuePlaceholder: 'वेरिएबल सेट करें',
needConnectTip: 'यह चरण किसी से जुड़ा नहीं है',
maxTreeDepth: 'प्रति शाखा अधिकतम {{depth}} नोड्स की सीमा',
needEndNode: 'अंत ब्लॉक जोड़ा जाना चाहिए',
needAnswerNode: 'उत्तर ब्लॉक जोड़ा जाना चाहिए',
workflowProcess: 'कार्यप्रवाह प्रक्रिया',
notRunning: 'अभी तक नहीं चल रहा',
previewPlaceholder:
@ -60,7 +58,6 @@ const translation = {
learnMore: 'अधिक जानें',
copy: 'कॉपी करें',
duplicate: 'डुप्लिकेट करें',
addBlock: 'ब्लॉक जोड़ें',
pasteHere: 'यहां पेस्ट करें',
pointerMode: 'पॉइंटर मोड',
handMode: 'हैंड मोड',
@ -118,6 +115,9 @@ const translation = {
publishUpdate: 'अपडेट प्रकाशित करें',
exportSVG: 'SVG के रूप में निर्यात करें',
versionHistory: 'संस्करण इतिहास',
needAnswerNode: 'उत्तर नोड जोड़ा जाना चाहिए',
addBlock: 'नोड जोड़ें',
needEndNode: 'अंत नोड जोड़ा जाना चाहिए',
},
env: {
envPanelTitle: 'पर्यावरण चर',
@ -179,19 +179,19 @@ const translation = {
stepForward_other: '{{count}} कदम आगे',
sessionStart: 'सत्र प्रारंभ',
currentState: 'वर्तमान स्थिति',
nodeTitleChange: 'ब्लॉक शीर्षक बदला गया',
nodeDescriptionChange: 'ब्लॉक विवरण बदला गया',
nodeDragStop: 'ब्लॉक स्थानांतरित किया गया',
nodeChange: 'ब्लॉक बदला गया',
nodeConnect: 'ब्लॉक कनेक्ट किया गया',
nodePaste: 'ब्लॉक पेस्ट किया गया',
nodeDelete: 'ब्लॉक हटाया गया',
nodeAdd: 'ब्लॉक जोड़ा गया',
nodeResize: 'ब्लॉक का आकार बदला गया',
noteAdd: 'नोट जोड़ा गया',
noteChange: 'नोट बदला गया',
noteDelete: 'नोट हटाया गया',
edgeDelete: 'ब्लॉक डिस्कनेक्ट किया गया',
nodeConnect: 'नोड कनेक्टेड',
nodeResize: 'नोड का आकार बदला गया',
nodeDelete: 'नोड हटा दिया गया',
nodeDragStop: 'नोड स्थानांतरित किया गया',
nodeChange: 'नोड बदला गया',
nodeAdd: 'नोड जोड़ा गया',
nodeTitleChange: 'नोड का शीर्षक बदल दिया गया',
edgeDelete: 'नोड डिस्कनेक्ट हो गया',
nodePaste: 'नोड चिपका हुआ',
nodeDescriptionChange: 'नोड का वर्णन बदल गया',
},
errorMsg: {
fieldRequired: '{{field}} आवश्यक है',
@ -220,8 +220,6 @@ const translation = {
loop: 'लूप',
},
tabs: {
'searchBlock': 'ब्लॉक खोजें',
'blocks': 'ब्लॉक्स',
'tools': 'टूल्स',
'allTool': 'सभी',
'builtInTool': 'अंतर्निहित',
@ -235,6 +233,8 @@ const translation = {
'searchTool': 'खोज उपकरण',
'plugin': 'प्लगइन',
'agent': 'एजेंट रणनीति',
'searchBlock': 'खोज नोड',
'blocks': 'नोड्स',
},
blocks: {
'start': 'प्रारंभ',
@ -299,22 +299,22 @@ const translation = {
},
panel: {
userInputField: 'उपयोगकर्ता इनपुट फ़ील्ड',
changeBlock: 'ब्लॉक बदलें',
helpLink: 'सहायता लिंक',
about: 'के बारे में',
createdBy: 'द्वारा बनाया गया ',
nextStep: 'अगला कदम',
addNextStep: 'इस वर्कफ़्लो में अगला ब्लॉक जोड़ें',
selectNextStep: 'अगला ब्लॉक चुनें',
runThisStep: 'इस कदम को चलाएं',
checklist: 'चेकलिस्ट',
checklistTip:
'प्रकाशित करने से पहले सुनिश्चित करें कि सभी समस्याएं हल हो गई हैं',
checklistResolved: 'सभी समस्याएं हल हो गई हैं',
organizeBlocks: 'ब्लॉक्स को व्यवस्थित करें',
change: 'बदलें',
optional: '(वैकल्पिक)',
moveToThisNode: 'इस नोड पर जाएं',
changeBlock: 'नोड बदलें',
addNextStep: 'इस कार्यप्रवाह में अगला कदम जोड़ें',
selectNextStep: 'अगला कदम चुनें',
organizeBlocks: 'नोड्स का आयोजन करें',
},
nodes: {
common: {

View File

@ -495,7 +495,6 @@ const translation = {
title:
'Le estensioni API forniscono una gestione centralizzata delle API, semplificando la configurazione per un facile utilizzo nelle applicazioni di Dify.',
link: 'Scopri come sviluppare la tua estensione API.',
linkUrl: 'https://docs.dify.ai/en/guides/extension/api-based-extension/README',
add: 'Aggiungi Estensione API',
selector: {
title: 'Estensione API',

View File

@ -66,8 +66,6 @@ const translation = {
run: 'Esegui',
firecrawlTitle: 'Estrai contenuti web con 🔥Firecrawl',
firecrawlDoc: 'Documenti Firecrawl',
firecrawlDocLink:
'https://docs.dify.ai/guides/knowledge-base/sync_from_website',
options: 'Opzioni',
crawlSubPage: 'Crawl sotto-pagine',
limit: 'Limite',
@ -101,7 +99,6 @@ const translation = {
configureJinaReader: 'Configura Jina Reader',
configureWatercrawl: 'Configura Watercrawl',
waterCrawlNotConfigured: 'Watercrawl non è configurato',
watercrawlDocLink: 'https://docs.dify.ai/it/guides/knowledge-base/create-knowledge-and-upload-documents/import-content-data/sync-from-website',
},
cancel: 'Annulla',
},

View File

@ -38,8 +38,6 @@ const translation = {
setVarValuePlaceholder: 'Imposta variabile',
needConnectTip: 'Questo passaggio non è collegato a nulla',
maxTreeDepth: 'Limite massimo di {{depth}} nodi per ramo',
needEndNode: 'Deve essere aggiunto il blocco di Fine',
needAnswerNode: 'Deve essere aggiunto il blocco di Risposta',
workflowProcess: 'Processo di flusso di lavoro',
notRunning: 'Non ancora in esecuzione',
previewPlaceholder:
@ -60,7 +58,6 @@ const translation = {
learnMore: 'Scopri di più',
copy: 'Copia',
duplicate: 'Duplica',
addBlock: 'Aggiungi Blocco',
pasteHere: 'Incolla Qui',
pointerMode: 'Modalità Puntatore',
handMode: 'Modalità Mano',
@ -119,6 +116,9 @@ const translation = {
exportJPEG: 'Esporta come JPEG',
noExist: 'Nessuna variabile del genere',
exportPNG: 'Esporta come PNG',
needEndNode: 'Deve essere aggiunto il nodo finale',
addBlock: 'Aggiungi nodo',
needAnswerNode: 'Deve essere aggiunto il nodo di risposta',
},
env: {
envPanelTitle: 'Variabili d\'Ambiente',
@ -181,19 +181,19 @@ const translation = {
stepForward_other: '{{count}} passi avanti',
sessionStart: 'Inizio sessione',
currentState: 'Stato attuale',
nodeTitleChange: 'Titolo del blocco modificato',
nodeDescriptionChange: 'Descrizione del blocco modificata',
nodeDragStop: 'Blocco spostato',
nodeChange: 'Blocco modificato',
nodeConnect: 'Blocco collegato',
nodePaste: 'Blocco incollato',
nodeDelete: 'Blocco eliminato',
nodeAdd: 'Blocco aggiunto',
nodeResize: 'Blocco ridimensionato',
noteAdd: 'Nota aggiunta',
noteChange: 'Nota modificata',
noteDelete: 'Nota eliminata',
edgeDelete: 'Blocco scollegato',
nodeDescriptionChange: 'Descrizione del nodo cambiata',
nodePaste: 'Nodo incollato',
nodeChange: 'Nodo cambiato',
nodeResize: 'Nodo ridimensionato',
nodeDelete: 'Nodo eliminato',
nodeTitleChange: 'Titolo del nodo cambiato',
edgeDelete: 'Nodo disconnesso',
nodeAdd: 'Nodo aggiunto',
nodeDragStop: 'Nodo spostato',
nodeConnect: 'Nodo connesso',
},
errorMsg: {
fieldRequired: '{{field}} è richiesto',
@ -222,8 +222,6 @@ const translation = {
loop: 'Anello',
},
tabs: {
'searchBlock': 'Cerca blocco',
'blocks': 'Blocchi',
'tools': 'Strumenti',
'allTool': 'Tutti',
'builtInTool': 'Integrato',
@ -237,6 +235,8 @@ const translation = {
'searchTool': 'Strumento di ricerca',
'agent': 'Strategia dell\'agente',
'plugin': 'Plugin',
'searchBlock': 'Cerca nodo',
'blocks': 'Nodi',
},
blocks: {
'start': 'Inizio',
@ -302,22 +302,22 @@ const translation = {
},
panel: {
userInputField: 'Campo di Input Utente',
changeBlock: 'Cambia Blocco',
helpLink: 'Link di Aiuto',
about: 'Informazioni',
createdBy: 'Creato da ',
nextStep: 'Prossimo Passo',
addNextStep: 'Aggiungi il prossimo blocco in questo flusso di lavoro',
selectNextStep: 'Seleziona Prossimo Blocco',
runThisStep: 'Esegui questo passo',
checklist: 'Checklist',
checklistTip:
'Assicurati che tutti i problemi siano risolti prima di pubblicare',
checklistResolved: 'Tutti i problemi sono risolti',
organizeBlocks: 'Organizza blocchi',
change: 'Cambia',
optional: '(opzionale)',
moveToThisNode: 'Sposta a questo nodo',
changeBlock: 'Cambia Nodo',
selectNextStep: 'Seleziona il prossimo passo',
organizeBlocks: 'Organizzare i nodi',
addNextStep: 'Aggiungi il prossimo passo in questo flusso di lavoro',
},
nodes: {
common: {

View File

@ -485,7 +485,6 @@ const translation = {
apiBasedExtension: {
title: 'API 拡張機能は、Dify のアプリケーション全体での簡単な使用のための設定を簡素化し、集中的な API 管理を提供します。',
link: '独自の API 拡張機能を開発する方法について学ぶ。',
linkUrl: 'https://docs.dify.ai/en/guides/extension/api-based-extension/README',
add: 'API 拡張機能を追加',
selector: {
title: 'API 拡張機能',

View File

@ -72,7 +72,6 @@ const translation = {
run: '実行',
firecrawlTitle: '🔥Firecrawl を使っでウエブコンテンツを抽出',
firecrawlDoc: 'Firecrawl ドキュメント',
firecrawlDocLink: 'https://docs.dify.ai/en/guides/knowledge-base/create-knowledge-and-upload-documents/import-content-data/sync-from-website',
jinaReaderTitle: 'サイト全体を Markdown に変換する',
jinaReaderDoc: 'Jina Reader の詳細',
jinaReaderDocLink: 'https://jina.ai/reader',
@ -98,7 +97,6 @@ const translation = {
watercrawlDoc: 'ウォータークローリングの文書',
watercrawlTitle: 'Watercrawl を使用してウェブコンテンツを抽出する',
waterCrawlNotConfigured: 'Watercrawl は設定されていません',
watercrawlDocLink: 'https://docs.dify.ai/ja/guides/knowledge-base/create-knowledge-and-upload-documents/import-content-data/sync-from-website',
},
},
stepTwo: {

View File

@ -463,7 +463,6 @@ const translation = {
apiBasedExtension: {
title: 'API 기반 확장은 Dify 애플리케이션 전체에서 간편한 사용을 위한 설정을 단순화하고 집중적인 API 관리를 제공합니다.',
link: '사용자 정의 API 기반 확장을 개발하는 방법 배우기',
linkUrl: 'https://docs.dify.ai/en/guides/extension/api-based-extension/README',
add: 'API 기반 확장 추가',
selector: {
title: 'API 기반 확장',

View File

@ -52,7 +52,6 @@ const translation = {
failed: '생성에 실패했습니다',
},
website: {
firecrawlDocLink: 'https://docs.dify.ai/en/guides/knowledge-base/create-knowledge-and-upload-documents/import-content-data/sync-from-website',
limit: '한계',
options: '옵션',
firecrawlDoc: 'Firecrawl 문서',
@ -86,7 +85,6 @@ const translation = {
waterCrawlNotConfiguredDescription: 'API 키로 Watercrawl 을 구성하여 사용하십시오.',
watercrawlTitle: 'Watercrawl 로 웹 콘텐츠 추출하기',
configureFirecrawl: '파이어크롤 구성하기',
watercrawlDocLink: '웹사이트에서 동기화하기',
configureJinaReader: '지나 리더 설정하기',
waterCrawlNotConfigured: 'Watercrawl 이 설정되어 있지 않습니다.',
configureWatercrawl: '워터크롤 구성하기',

View File

@ -38,8 +38,6 @@ const translation = {
setVarValuePlaceholder: '변수 값 설정',
needConnectTip: '이 단계는 아무것도 연결되어 있지 않습니다',
maxTreeDepth: '분기당 최대 {{depth}} 노드 제한',
needEndNode: '종료 블록을 추가해야 합니다',
needAnswerNode: '답변 블록을 추가해야 합니다',
workflowProcess: '워크플로우 과정',
notRunning: '아직 실행되지 않음',
previewPlaceholder: '디버깅을 시작하려면 아래 상자에 내용을 입력하세요',
@ -58,7 +56,6 @@ const translation = {
learnMore: '더 알아보기',
copy: '복사',
duplicate: '복제',
addBlock: '블록 추가',
pasteHere: '여기에 붙여넣기',
pointerMode: '포인터 모드',
handMode: '핸드 모드',
@ -115,6 +112,9 @@ const translation = {
versionHistory: '버전 기록',
exportPNG: 'PNG 로 내보내기',
referenceVar: '참조 변수',
addBlock: '노드 추가',
needAnswerNode: '답변 노드를 추가해야 합니다.',
needEndNode: '종단 노드를 추가해야 합니다.',
},
env: {
envPanelTitle: '환경 변수',
@ -176,19 +176,19 @@ const translation = {
stepForward_other: '{{count}} 단계 앞으로',
sessionStart: '세션 시작',
currentState: '현재 상태',
nodeTitleChange: '블록 제목 변경됨',
nodeDescriptionChange: '블록 설명 변경됨',
nodeDragStop: '블록 이동됨',
nodeChange: '블록 변경됨',
nodeConnect: '블록 연결됨',
nodePaste: '블록 붙여넣기됨',
nodeDelete: '블록 삭제됨',
nodeAdd: '블록 추가됨',
nodeResize: '블록 크기 조정됨',
noteAdd: '노트 추가됨',
noteChange: '노트 변경됨',
noteDelete: '노트 삭제됨',
edgeDelete: '블록 연결 해제됨',
nodeConnect: '노드가 연결되었습니다.',
nodePaste: '노드 붙여넣기',
nodeDelete: '노드가 삭제되었습니다.',
nodeAdd: '노드가 추가되었습니다.',
nodeChange: '노드가 변경되었습니다.',
nodeDescriptionChange: '노드 설명이 변경됨',
nodeResize: '노드 크기 조정됨',
nodeDragStop: '노드가 이동했습니다.',
edgeDelete: '노드가 연결이 끊어졌습니다.',
nodeTitleChange: '노드 제목이 변경됨',
},
errorMsg: {
fieldRequired: '{{field}}가 필요합니다',
@ -217,8 +217,6 @@ const translation = {
loop: '루프',
},
tabs: {
'searchBlock': '블록 검색',
'blocks': '블록',
'tools': '도구',
'allTool': '전체',
'builtInTool': '내장',
@ -232,6 +230,8 @@ const translation = {
'searchTool': '검색 도구',
'plugin': '플러그인',
'agent': '에이전트 전략',
'blocks': '노드',
'searchBlock': '검색 노드',
},
blocks: {
'start': '시작',
@ -288,21 +288,21 @@ const translation = {
},
panel: {
userInputField: '사용자 입력 필드',
changeBlock: '블록 변경',
helpLink: '도움말 링크',
about: '정보',
createdBy: '작성자 ',
nextStep: '다음 단계',
addNextStep: '이 워크플로우의 다음 블록 추가',
selectNextStep: '다음 블록 선택',
runThisStep: '이 단계 실행',
checklist: '체크리스트',
checklistTip: '게시하기 전에 모든 문제가 해결되었는지 확인하세요',
checklistResolved: '모든 문제가 해결되었습니다',
organizeBlocks: '블록 정리',
change: '변경',
optional: '(선택사항)',
moveToThisNode: '이 노드로 이동',
organizeBlocks: '노드 정리하기',
selectNextStep: '다음 단계 선택',
changeBlock: '노드 변경',
addNextStep: '이 워크플로우에 다음 단계를 추가하세요.',
},
nodes: {
common: {

View File

@ -481,7 +481,6 @@ const translation = {
title:
'Rozszerzenia oparte na interfejsie API zapewniają scentralizowane zarządzanie interfejsami API, upraszczając konfigurację dla łatwego użytkowania w aplikacjach Dify.',
link: 'Dowiedz się, jak opracować własne rozszerzenie interfejsu API.',
linkUrl: 'https://docs.dify.ai/en/guides/extension/api-based-extension/README',
add: 'Dodaj rozszerzenie interfejsu API',
selector: {
title: 'Rozszerzenie interfejsu API',

View File

@ -54,7 +54,6 @@ const translation = {
},
website: {
limit: 'Ograniczać',
firecrawlDocLink: 'https://docs.dify.ai/en/guides/knowledge-base/create-knowledge-and-upload-documents/import-content-data/sync-from-website',
firecrawlDoc: 'Dokumentacja Firecrawl',
unknownError: 'Nieznany błąd',
fireCrawlNotConfiguredDescription: 'Skonfiguruj Firecrawl z kluczem API, aby z niego korzystać.',
@ -85,7 +84,6 @@ const translation = {
jinaReaderNotConfiguredDescription: 'Skonfiguruj Jina Reader, wprowadzając bezpłatny klucz API, aby uzyskać dostęp.',
watercrawlTitle: 'Wyodrębnij treści z sieci za pomocą Watercrawl',
configureWatercrawl: 'Skonfiguruj Watercrawl',
watercrawlDocLink: 'https://docs.dify.ai/en/guides/knowledge-base/create-knowledge-and-upload-documents/import-content-data/sync-from-website',
configureJinaReader: 'Skonfiguruj Czytnik Jina',
configureFirecrawl: 'Skonfiguruj Firecrawl',
watercrawlDoc: 'Dokumentacja Watercrawl',

View File

@ -38,8 +38,6 @@ const translation = {
setVarValuePlaceholder: 'Ustaw zmienną',
needConnectTip: 'Ten krok nie jest połączony z niczym',
maxTreeDepth: 'Maksymalny limit {{depth}} węzłów na gałąź',
needEndNode: 'Należy dodać blok końcowy',
needAnswerNode: 'Należy dodać blok odpowiedzi',
workflowProcess: 'Proces przepływu pracy',
notRunning: 'Jeszcze nie uruchomiono',
previewPlaceholder: 'Wprowadź treść w poniższym polu, aby rozpocząć debugowanie Chatbota',
@ -58,7 +56,6 @@ const translation = {
learnMore: 'Dowiedz się więcej',
copy: 'Kopiuj',
duplicate: 'Duplikuj',
addBlock: 'Dodaj blok',
pasteHere: 'Wklej tutaj',
pointerMode: 'Tryb wskaźnika',
handMode: 'Tryb ręczny',
@ -115,6 +112,9 @@ const translation = {
exportPNG: 'Eksportuj jako PNG',
publishUpdate: 'Opublikuj aktualizację',
referenceVar: 'Zmienna odniesienia',
addBlock: 'Dodaj węzeł',
needEndNode: 'Należy dodać węzeł końcowy',
needAnswerNode: 'Węzeł odpowiedzi musi zostać dodany',
},
env: {
envPanelTitle: 'Zmienne Środowiskowe',
@ -176,19 +176,19 @@ const translation = {
stepForward_other: '{{count}} kroki do przodu',
sessionStart: 'Początek sesji',
currentState: 'Aktualny stan',
nodeTitleChange: 'Tytuł bloku zmieniony',
nodeDescriptionChange: 'Opis bloku zmieniony',
nodeDragStop: 'Blok przeniesiony',
nodeChange: 'Blok zmieniony',
nodeConnect: 'Blok połączony',
nodePaste: 'Blok wklejony',
nodeDelete: 'Blok usunięty',
nodeAdd: 'Blok dodany',
nodeResize: 'Notatka zmieniona',
noteAdd: 'Notatka dodana',
noteChange: 'Notatka zmieniona',
noteDelete: 'Notatka usunięta',
edgeDelete: 'Blok rozłączony',
edgeDelete: 'Węzeł rozłączony',
nodeAdd: 'Węzeł dodany',
nodePaste: 'Węzeł wklejony',
nodeChange: 'Węzeł zmieniony',
nodeDelete: 'Węzeł usunięty',
nodeResize: 'Węzeł zmieniony rozmiar',
nodeConnect: 'Węzeł połączony',
nodeTitleChange: 'Tytuł węzła zmieniony',
nodeDescriptionChange: 'Opis węzła zmieniony',
nodeDragStop: 'Węzeł przeniesiony',
},
errorMsg: {
fieldRequired: '{{field}} jest wymagane',
@ -217,8 +217,6 @@ const translation = {
loop: 'Pętla',
},
tabs: {
'searchBlock': 'Szukaj bloku',
'blocks': 'Bloki',
'tools': 'Narzędzia',
'allTool': 'Wszystkie',
'builtInTool': 'Wbudowane',
@ -232,6 +230,8 @@ const translation = {
'searchTool': 'Wyszukiwarka',
'agent': 'Strategia agenta',
'plugin': 'Wtyczka',
'searchBlock': 'Wyszukaj węzeł',
'blocks': 'Węzły',
},
blocks: {
'start': 'Start',
@ -288,21 +288,21 @@ const translation = {
},
panel: {
userInputField: 'Pole wprowadzania użytkownika',
changeBlock: 'Zmień blok',
helpLink: 'Link do pomocy',
about: 'O',
createdBy: 'Stworzone przez ',
nextStep: 'Następny krok',
addNextStep: 'Dodaj następny blok w tym przepływie pracy',
selectNextStep: 'Wybierz następny blok',
runThisStep: 'Uruchom ten krok',
checklist: 'Lista kontrolna',
checklistTip: 'Upewnij się, że wszystkie problemy zostały rozwiązane przed opublikowaniem',
checklistResolved: 'Wszystkie problemy zostały rozwiązane',
organizeBlocks: 'Organizuj bloki',
change: 'Zmień',
optional: '(opcjonalne)',
moveToThisNode: 'Przenieś do tego węzła',
selectNextStep: 'Wybierz następny krok',
addNextStep: 'Dodaj następny krok w tym procesie roboczym',
changeBlock: 'Zmień węzeł',
organizeBlocks: 'Organizuj węzły',
},
nodes: {
common: {

View File

@ -467,7 +467,6 @@ const translation = {
apiBasedExtension: {
title: 'As extensões de API fornecem gerenciamento centralizado de API, simplificando a configuração para uso fácil em todos os aplicativos da Dify.',
link: 'Saiba como desenvolver sua própria Extensão de API.',
linkUrl: 'https://docs.dify.ai/en/guides/extension/api-based-extension/README',
add: 'Adicionar Extensão de API',
selector: {
title: 'Extensão de API',

View File

@ -58,7 +58,6 @@ const translation = {
crawlSubPage: 'Rastrear subpáginas',
selectAll: 'Selecionar tudo',
resetAll: 'Redefinir tudo',
firecrawlDocLink: 'https://docs.dify.ai/en/guides/knowledge-base/create-knowledge-and-upload-documents/import-content-data/sync-from-website',
includeOnlyPaths: 'Incluir apenas caminhos',
configure: 'Configurar',
limit: 'Limite',
@ -87,7 +86,6 @@ const translation = {
configureJinaReader: 'Configurar o Leitor Jina',
waterCrawlNotConfigured: 'Watercrawl não está configurado',
waterCrawlNotConfiguredDescription: 'Configure o Watercrawl com a chave da API para usá-lo.',
watercrawlDocLink: 'https://docs.dify.ai/pt/guias/base-de-conhecimentos/criar-conhecimento-e-enviar-documentos/importar-dados-de-conteudo/sincronizar-a-partir-do-site',
watercrawlDoc: 'Documentos do Watercrawl',
configureWatercrawl: 'Configurar Watercrawl',
},

View File

@ -38,8 +38,6 @@ const translation = {
setVarValuePlaceholder: 'Definir valor da variável',
needConnectTip: 'Este passo não está conectado a nada',
maxTreeDepth: 'Limite máximo de {{depth}} nós por ramo',
needEndNode: 'O bloco de fim deve ser adicionado',
needAnswerNode: 'O bloco de resposta deve ser adicionado',
workflowProcess: 'Processo de fluxo de trabalho',
notRunning: 'Ainda não está em execução',
previewPlaceholder: 'Digite o conteúdo na caixa abaixo para começar a depurar o Chatbot',
@ -58,7 +56,6 @@ const translation = {
learnMore: 'Saiba mais',
copy: 'Copiar',
duplicate: 'Duplicar',
addBlock: 'Adicionar bloco',
pasteHere: 'Colar aqui',
pointerMode: 'Modo ponteiro',
handMode: 'Modo mão',
@ -115,6 +112,9 @@ const translation = {
exitVersions: 'Versões de Sair',
exportSVG: 'Exportar como SVG',
exportJPEG: 'Exportar como JPEG',
addBlock: 'Adicionar Nó',
needEndNode: 'O nó de Fim deve ser adicionado',
needAnswerNode: 'O nó de resposta deve ser adicionado',
},
env: {
envPanelTitle: 'Variáveis de Ambiente',
@ -176,19 +176,19 @@ const translation = {
stepForward_other: '{{count}} passos para frente',
sessionStart: 'Início da sessão',
currentState: 'Estado atual',
nodeTitleChange: 'Título do bloco alterado',
nodeDescriptionChange: 'Descrição do bloco alterada',
nodeDragStop: 'Bloco movido',
nodeChange: 'Bloco alterado',
nodeConnect: 'Bloco conectado',
nodePaste: 'Bloco colado',
nodeDelete: 'Bloco excluído',
nodeAdd: 'Bloco adicionado',
nodeResize: 'Nota redimensionada',
noteAdd: 'Nota adicionada',
noteChange: 'Nota alterada',
noteDelete: 'Conexão excluída',
edgeDelete: 'Bloco desconectado',
nodeConnect: 'Nó conectado',
nodeDelete: 'Nó deletado',
nodePaste: 'Nó colado',
nodeTitleChange: 'Título do nó alterado',
nodeAdd: 'Nó adicionado',
nodeDescriptionChange: 'Descrição do nó alterada',
edgeDelete: 'Nó desconectado',
nodeResize: 'Nó redimensionado',
nodeChange: 'Nó alterado',
nodeDragStop: 'Nó movido',
},
errorMsg: {
fieldRequired: '{{field}} é obrigatório',
@ -217,8 +217,6 @@ const translation = {
loop: 'Laço',
},
tabs: {
'searchBlock': 'Buscar bloco',
'blocks': 'Blocos',
'tools': 'Ferramentas',
'allTool': 'Todos',
'builtInTool': 'Integrado',
@ -232,6 +230,8 @@ const translation = {
'searchTool': 'Ferramenta de pesquisa',
'plugin': 'Plug-in',
'agent': 'Estratégia do agente',
'blocks': 'Nodos',
'searchBlock': 'Nó de busca',
},
blocks: {
'start': 'Iniciar',
@ -288,21 +288,21 @@ const translation = {
},
panel: {
userInputField: 'Campo de entrada do usuário',
changeBlock: 'Mudar bloco',
helpLink: 'Link de ajuda',
about: 'Sobre',
createdBy: 'Criado por ',
nextStep: 'Próximo passo',
addNextStep: 'Adicionar o próximo bloco neste fluxo de trabalho',
selectNextStep: 'Selecionar próximo bloco',
runThisStep: 'Executar este passo',
checklist: 'Lista de verificação',
checklistTip: 'Certifique-se de que todos os problemas foram resolvidos antes de publicar',
checklistResolved: 'Todos os problemas foram resolvidos',
organizeBlocks: 'Organizar blocos',
change: 'Mudar',
optional: '(opcional)',
moveToThisNode: 'Mova-se para este nó',
changeBlock: 'Mudar Nó',
addNextStep: 'Adicione o próximo passo neste fluxo de trabalho',
organizeBlocks: 'Organizar nós',
selectNextStep: 'Selecione o próximo passo',
},
nodes: {
common: {

View File

@ -467,7 +467,6 @@ const translation = {
apiBasedExtension: {
title: 'Extensiile bazate pe API oferă o gestionare centralizată a API-urilor, simplificând configurația pentru o utilizare ușoară în aplicațiile Dify.',
link: 'Aflați cum să dezvoltați propria extensie bazată pe API.',
linkUrl: 'https://docs.dify.ai/en/guides/extension/api-based-extension/README',
add: 'Adăugați extensie API',
selector: {
title: 'Extensie API',

View File

@ -65,7 +65,6 @@ const translation = {
firecrawlTitle: 'Extrageți conținut web cu 🔥Firecrawl',
unknownError: 'Eroare necunoscută',
scrapTimeInfo: 'Pagini răzuite {{total}} în total în {{timp}}s',
firecrawlDocLink: 'https://docs.dify.ai/en/guides/knowledge-base/create-knowledge-and-upload-documents/import-content-data/sync-from-website',
excludePaths: 'Excluderea căilor',
resetAll: 'Resetați toate',
extractOnlyMainContent: 'Extrageți doar conținutul principal (fără anteturi, navigări, subsoluri etc.)',
@ -86,7 +85,6 @@ const translation = {
watercrawlTitle: 'Extrageți conținut web cu Watercrawl',
configureJinaReader: 'Configurează Jina Reader',
waterCrawlNotConfiguredDescription: 'Configurează Watercrawl cu cheia API pentru a-l folosi.',
watercrawlDocLink: 'https://docs.dify.ai/en/guides/knowledge-base/create-knowledge-and-upload-documents/import-content-data/sync-from-website',
configureFirecrawl: 'Configurează Firecrawl',
watercrawlDoc: 'Documentele Watercrawl',
configureWatercrawl: 'Configurează Watercrawl',

View File

@ -38,8 +38,6 @@ const translation = {
setVarValuePlaceholder: 'Setează valoarea variabilei',
needConnectTip: 'Acest pas nu este conectat la nimic',
maxTreeDepth: 'Limită maximă de {{depth}} noduri pe ramură',
needEndNode: 'Trebuie adăugat blocul de sfârșit',
needAnswerNode: 'Trebuie adăugat blocul de răspuns',
workflowProcess: 'Proces de flux de lucru',
notRunning: 'Încă nu rulează',
previewPlaceholder: 'Introduceți conținutul în caseta de mai jos pentru a începe depanarea Chatbotului',
@ -58,7 +56,6 @@ const translation = {
learnMore: 'Află mai multe',
copy: 'Copiază',
duplicate: 'Duplică',
addBlock: 'Adaugă bloc',
pasteHere: 'Lipește aici',
pointerMode: 'Modul pointer',
handMode: 'Modul mână',
@ -115,6 +112,9 @@ const translation = {
publishUpdate: 'Publicați actualizarea',
referenceVar: 'Variabilă de referință',
exportJPEG: 'Exportă ca JPEG',
addBlock: 'Adaugă nod',
needAnswerNode: 'Nodul de răspuns trebuie adăugat',
needEndNode: 'Nodul de sfârșit trebuie adăugat',
},
env: {
envPanelTitle: 'Variabile de Mediu',
@ -176,19 +176,19 @@ const translation = {
stepForward_other: '{{count}} pași înainte',
sessionStart: 'Începutul sesiuni',
currentState: 'Stare actuală',
nodeTitleChange: 'Titlul blocului a fost schimbat',
nodeDescriptionChange: 'Descrierea blocului a fost schimbată',
nodeDragStop: 'Bloc mutat',
nodeChange: 'Bloc schimbat',
nodeConnect: 'Bloc conectat',
nodePaste: 'Bloc lipit',
nodeDelete: 'Bloc șters',
nodeAdd: 'Bloc adăugat',
nodeResize: 'Bloc redimensionat',
noteAdd: 'Notă adăugată',
noteChange: 'Notă modificată',
noteDelete: 'Notă ștearsă',
edgeDelete: 'Bloc deconectat',
nodeResize: 'Nod redimensionat',
nodeConnect: 'Nod conectat',
nodeTitleChange: 'Titlul nodului a fost schimbat',
nodeChange: 'Nodul s-a schimbat',
nodePaste: 'Node lipit',
nodeDelete: 'Nod șters',
nodeDescriptionChange: 'Descrierea nodului a fost modificată',
edgeDelete: 'Nod deconectat',
nodeAdd: 'Nod adăugat',
nodeDragStop: 'Nod mutat',
},
errorMsg: {
fieldRequired: '{{field}} este obligatoriu',
@ -217,8 +217,6 @@ const translation = {
loop: 'Loop',
},
tabs: {
'searchBlock': 'Caută bloc',
'blocks': 'Blocuri',
'tools': 'Instrumente',
'allTool': 'Toate',
'builtInTool': 'Integrat',
@ -232,6 +230,8 @@ const translation = {
'searchTool': 'Instrument de căutare',
'agent': 'Strategia agentului',
'plugin': 'Plugin',
'blocks': 'Noduri',
'searchBlock': 'Căutare nod',
},
blocks: {
'start': 'Începe',
@ -288,21 +288,21 @@ const translation = {
},
panel: {
userInputField: 'Câmp de introducere utilizator',
changeBlock: 'Schimbă blocul',
helpLink: 'Link de ajutor',
about: 'Despre',
createdBy: 'Creat de ',
nextStep: 'Pasul următor',
addNextStep: 'Adăugați următorul bloc în acest flux de lucru',
selectNextStep: 'Selectați următorul bloc',
runThisStep: 'Rulează acest pas',
checklist: 'Lista de verificare',
checklistTip: 'Asigurați-vă că toate problemele sunt rezolvate înainte de publicare',
checklistResolved: 'Toate problemele au fost rezolvate',
organizeBlocks: 'Organizează blocurile',
change: 'Schimbă',
optional: '(opțional)',
moveToThisNode: 'Mutați la acest nod',
organizeBlocks: 'Organizează nodurile',
addNextStep: 'Adăugați următorul pas în acest flux de lucru',
changeBlock: 'Schimbă nodul',
selectNextStep: 'Selectați Pasul Următor',
},
nodes: {
common: {

View File

@ -471,7 +471,6 @@ const translation = {
apiBasedExtension: {
title: 'API-расширения обеспечивают централизованное управление API, упрощая настройку для удобного использования в приложениях Dify.',
link: 'Узнайте, как разработать собственное API-расширение.',
linkUrl: 'https://docs.dify.ai/en/guides/extension/api-based-extension/README',
add: 'Добавить API Extension',
selector: {
title: 'API Extension',

View File

@ -63,7 +63,6 @@ const translation = {
run: 'Запустить',
firecrawlTitle: 'Извлечь веб-контент с помощью 🔥Firecrawl',
firecrawlDoc: 'Документация Firecrawl',
firecrawlDocLink: 'https://docs.dify.ai/en/guides/knowledge-base/create-knowledge-and-upload-documents/import-content-data/sync-from-website',
options: 'Опции',
crawlSubPage: 'Сканировать подстраницы',
limit: 'Лимит',
@ -88,7 +87,6 @@ const translation = {
jinaReaderTitle: 'Конвертируйте весь сайт в Markdown',
useSitemapTooltip: 'Следуйте карте сайта, чтобы просканировать сайт. Если нет, Jina Reader будет сканировать итеративно в зависимости от релевантности страницы, выдавая меньшее количество страниц, но более высокого качества.',
watercrawlTitle: 'Извлечение веб-контента с помощью Watercrawl',
watercrawlDocLink: 'https://docs.dify.ai/ru/guides/knowledge-base/create-knowledge-and-upload-documents/import-content-data/sync-from-website',
configureWatercrawl: 'Настроить Watercrawl',
waterCrawlNotConfigured: 'Watercrawl не настроен',
configureFirecrawl: 'Настроить Firecrawl',

View File

@ -38,8 +38,6 @@ const translation = {
setVarValuePlaceholder: 'Установить значение переменной',
needConnectTip: 'Этот шаг ни к чему не подключен',
maxTreeDepth: 'Максимальный предел {{depth}} узлов на ветку',
needEndNode: 'Необходимо добавить блок "Конец"',
needAnswerNode: 'Необходимо добавить блок "Ответ"',
workflowProcess: 'Процесс рабочего процесса',
notRunning: 'Еще не запущено',
previewPlaceholder: 'Введите текст в поле ниже, чтобы начать отладку чат-бота',
@ -58,7 +56,6 @@ const translation = {
learnMore: 'Узнать больше',
copy: 'Копировать',
duplicate: 'Дублировать',
addBlock: 'Добавить блок',
pasteHere: 'Вставить сюда',
pointerMode: 'Режим указателя',
handMode: 'Режим руки',
@ -115,6 +112,9 @@ const translation = {
exitVersions: 'Выходные версии',
exportSVG: 'Экспортировать как SVG',
publishUpdate: 'Опубликовать обновление',
addBlock: 'Добавить узел',
needAnswerNode: 'В узел ответа необходимо добавить',
needEndNode: 'Узел конца должен быть добавлен',
},
env: {
envPanelTitle: 'Переменные среды',
@ -176,19 +176,19 @@ const translation = {
stepForward_other: '{{count}} шагов вперед',
sessionStart: 'Начало сеанса',
currentState: 'Текущее состояние',
nodeTitleChange: 'Изменено название блока',
nodeDescriptionChange: 'Изменено описание блока',
nodeDragStop: 'Блок перемещен',
nodeChange: 'Блок изменен',
nodeConnect: 'Блок подключен',
nodePaste: 'Блок вставлен',
nodeDelete: 'Блок удален',
nodeAdd: 'Блок добавлен',
nodeResize: 'Размер блока изменен',
noteAdd: 'Заметка добавлена',
noteChange: 'Заметка изменена',
noteDelete: 'Заметка удалена',
edgeDelete: 'Блок отключен',
nodeDragStop: 'Узел перемещен',
nodeResize: 'Узел изменен в размере',
nodeTitleChange: 'Название узла изменено',
edgeDelete: 'Узел отключен',
nodeConnect: 'Узел подключен',
nodeDelete: 'Узел удален',
nodePaste: 'Узел вставлен',
nodeChange: 'Узел изменен',
nodeAdd: 'Узел добавлен',
nodeDescriptionChange: 'Описание узла изменено',
},
errorMsg: {
fieldRequired: '{{field}} обязательно для заполнения',
@ -217,8 +217,6 @@ const translation = {
loop: 'Цикл',
},
tabs: {
'searchBlock': 'Поиск блока',
'blocks': 'Блоки',
'searchTool': 'Поиск инструмента',
'tools': 'Инструменты',
'allTool': 'Все',
@ -232,6 +230,8 @@ const translation = {
'noResult': 'Ничего не найдено',
'plugin': 'Плагин',
'agent': 'Агентская стратегия',
'blocks': 'Узлы',
'searchBlock': 'Поиск узла',
},
blocks: {
'start': 'Начало',
@ -288,21 +288,21 @@ const translation = {
},
panel: {
userInputField: 'Поле ввода пользователя',
changeBlock: 'Изменить блок',
helpLink: 'Ссылка на справку',
about: 'О программе',
createdBy: 'Создано ',
nextStep: 'Следующий шаг',
addNextStep: 'Добавить следующий блок в этот рабочий процесс',
selectNextStep: 'Выбрать следующий блок',
runThisStep: 'Выполнить этот шаг',
checklist: 'Контрольный список',
checklistTip: 'Убедитесь, что все проблемы решены перед публикацией',
checklistResolved: 'Все проблемы решены',
organizeBlocks: 'Организовать блоки',
change: 'Изменить',
optional: '(необязательно)',
moveToThisNode: 'Перейдите к этому узлу',
selectNextStep: 'Выберите следующий шаг',
organizeBlocks: 'Организовать узлы',
addNextStep: 'Добавьте следующий шаг в этот рабочий процесс',
changeBlock: 'Изменить узел',
},
nodes: {
common: {

View File

@ -464,7 +464,6 @@ const translation = {
apiBasedExtension: {
title: 'Razširitve API omogočajo centralizirano upravljanje API, kar poenostavi konfiguracijo za enostavno uporabo v aplikacijah Dify.',
link: 'Naučite se, kako razviti svojo API razširitev.',
linkUrl: 'https://docs.dify.ai/en/guides/extension/api-based-extension/README',
add: 'Dodaj API razširitev',
selector: {
title: 'API razširitev',
@ -693,7 +692,6 @@ const translation = {
type: 'Vrsta',
link: 'Preberite, kako razvijete lastno razširitev API-ja.',
title: 'Razširitve API zagotavljajo centralizirano upravljanje API, kar poenostavlja konfiguracijo za enostavno uporabo v aplikacijah Dify.',
linkUrl: 'https://docs.dify.ai/en/guides/extension/api-based-extension/README',
add: 'Dodajanje razširitve API-ja',
},
about: {

View File

@ -71,7 +71,6 @@ const translation = {
run: 'Zaženi',
firecrawlTitle: 'Izvleci spletno vsebino z 🔥Firecrawl',
firecrawlDoc: 'Firecrawl dokumentacija',
firecrawlDocLink: 'https://docs.dify.ai/en/guides/knowledge-base/create-knowledge-and-upload-documents/import-content-data/sync-from-website',
jinaReaderTitle: 'Pretvori celotno stran v Markdown',
jinaReaderDoc: 'Več o Jina Reader',
jinaReaderDocLink: 'https://jina.ai/reader',
@ -97,7 +96,6 @@ const translation = {
waterCrawlNotConfigured: 'Watercrawl ni konfiguriran',
watercrawlDoc: 'Watercrawl dokumentacija',
configureJinaReader: 'Konfigurirajte Jina Reader',
watercrawlDocLink: 'https://docs.dify.ai/sl/guides/knowledge-base/create-knowledge-and-upload-documents/import-content-data/sync-from-website',
configureFirecrawl: 'Konfigurirajte Firecrawl',
watercrawlTitle: 'Izvleci vsebino z interneta z Watercrawl',
},

File diff suppressed because it is too large Load Diff

View File

@ -466,7 +466,6 @@ const translation = {
apiBasedExtension: {
title: 'ส่วนขยาย API ให้การจัดการ API แบบรวมศูนย์ ทําให้การกําหนดค่าง่ายขึ้นเพื่อให้ใช้งานได้ง่ายในแอปพลิเคชันของ Dify',
link: 'เรียนรู้วิธีพัฒนาส่วนขยาย API ของคุณเอง',
linkUrl: 'https://docs.dify.ai/en/guides/knowledge-base/create-knowledge-and-upload-documents/import-content-data/sync-from-website',
add: 'เพิ่มส่วนขยาย API',
selector: {
title: 'ส่วนขยาย API',

View File

@ -71,7 +71,6 @@ const translation = {
run: 'วิ่ง',
firecrawlTitle: 'แยกเนื้อหาเว็บด้วย 🔥Firecrawl',
firecrawlDoc: 'เอกสาร Firecrawl',
firecrawlDocLink: 'https://docs.dify.ai/en/guides/knowledge-base/create-knowledge-and-upload-documents/import-content-data/sync-from-website',
jinaReaderTitle: 'แปลงทั้งไซต์เป็น Markdown',
jinaReaderDoc: 'เรียนรู้เพิ่มเติมเกี่ยวกับ Jina Reader',
jinaReaderDocLink: 'https://jina.ai/reader',
@ -94,7 +93,6 @@ const translation = {
maxDepthTooltip: 'ความลึกสูงสุดในการรวบรวมข้อมูลเมื่อเทียบกับ URL ที่ป้อน ความลึก 0 เพียงแค่ขูดหน้าของ URL ที่ป้อนความลึก 1 ขูด url และทุกอย่างหลังจาก enteredURL + หนึ่ง / เป็นต้น',
watercrawlTitle: 'ดึงเนื้อหาจากเว็บด้วย Watercrawl',
configureJinaReader: 'ตั้งค่า Jina Reader',
watercrawlDocLink: 'https://docs.dify.ai/th/guides/knowledge-base/create-knowledge-and-upload-documents/import-content-data/sync-from-website',
configureFirecrawl: 'กำหนดค่า Firecrawl',
configureWatercrawl: 'กำหนดค่าการเข้าถึงน้ำ',
waterCrawlNotConfiguredDescription: 'กำหนดค่า Watercrawl ด้วย API key เพื่อใช้งาน.',

View File

@ -42,8 +42,6 @@ const translation = {
setVarValuePlaceholder: 'ตั้งค่าตัวแปร',
needConnectTip: 'ขั้นตอนนี้ไม่ได้เชื่อมต่อกับสิ่งใด',
maxTreeDepth: 'ขีดจํากัดสูงสุดของ {{depth}} โหนดต่อสาขา',
needEndNode: 'ต้องเพิ่มบล็อก End',
needAnswerNode: 'ต้องเพิ่มบล็อกคําตอบ',
workflowProcess: 'กระบวนการเวิร์กโฟลว์',
notRunning: 'ยังไม่ได้ทํางาน',
previewPlaceholder: 'ป้อนเนื้อหาในช่องด้านล่างเพื่อเริ่มแก้ไขข้อบกพร่องของแชทบอท',
@ -62,7 +60,6 @@ const translation = {
learnMore: 'ศึกษาเพิ่มเติม',
copy: 'ลอก',
duplicate: 'สำเนา',
addBlock: 'เพิ่มบล็อก',
pasteHere: 'วางที่นี่',
pointerMode: 'โหมดตัวชี้',
handMode: 'โหมดมือ',
@ -115,6 +112,9 @@ const translation = {
exitVersions: 'ออกเวอร์ชัน',
exportImage: 'ส่งออกภาพ',
exportSVG: 'ส่งออกเป็น SVG',
needAnswerNode: 'ต้องเพิ่มโหนดคำตอบ',
addBlock: 'เพิ่มโนด',
needEndNode: 'ต้องเพิ่มโหนดจบ',
},
env: {
envPanelTitle: 'ตัวแปรสภาพแวดล้อม',
@ -176,19 +176,19 @@ const translation = {
stepForward_other: '{{count}} ก้าวไปข้างหน้า',
sessionStart: 'เริ่มเซสชัน',
currentState: 'สถานะปัจจุบัน',
nodeTitleChange: 'เปลี่ยนชื่อบล็อก',
nodeDescriptionChange: 'คําอธิบายบล็อกเปลี่ยนไป',
nodeDragStop: 'บล็อกย้าย',
nodeChange: 'บล็อกเปลี่ยนไป',
nodeConnect: 'บล็อกเชื่อมต่อ',
nodePaste: 'บล็อกวาง',
nodeDelete: 'บล็อกลบ',
nodeAdd: 'เพิ่มบล็อก',
nodeResize: 'บล็อกปรับขนาด',
noteAdd: 'เพิ่มหมายเหตุ',
noteChange: 'เปลี่ยนหมายเหตุ',
noteDelete: 'ลบโน้ต',
edgeDelete: 'บล็อกตัดการเชื่อมต่อ',
nodeDelete: 'โหนดถูกลบแล้ว',
nodeDescriptionChange: 'คำอธิบายของโหนดถูกเปลี่ยน',
nodeDragStop: 'โหนดถูกย้าย',
edgeDelete: 'เชื่อมต่อ Node ขาดหาย',
nodeTitleChange: 'ชื่อโหนดเปลี่ยน',
nodeAdd: 'เพิ่มโนด',
nodeChange: 'โหนดเปลี่ยนแปลง',
nodeResize: 'ขนาดของโหนดถูกปรับขนาด',
nodeConnect: 'เชื่อมต่อ Node',
nodePaste: 'โนดที่วางไว้',
},
errorMsg: {
fieldRequired: '{{field}} เป็นสิ่งจําเป็น',
@ -217,8 +217,6 @@ const translation = {
loop: 'ลูป',
},
tabs: {
'searchBlock': 'บล็อกการค้นหา',
'blocks': 'บล็อก',
'searchTool': 'เครื่องมือค้นหา',
'tools': 'เครื่อง มือ',
'allTool': 'ทั้งหมด',
@ -232,6 +230,8 @@ const translation = {
'noResult': 'ไม่พบการจับคู่',
'agent': 'กลยุทธ์ตัวแทน',
'plugin': 'ปลั๊กอิน',
'searchBlock': 'ค้นหาโหนด',
'blocks': 'โหนด',
},
blocks: {
'start': 'เริ่ม',
@ -288,21 +288,21 @@ const translation = {
},
panel: {
userInputField: 'ฟิลด์ป้อนข้อมูลของผู้ใช้',
changeBlock: 'เปลี่ยนบล็อก',
helpLink: 'ลิงค์ช่วยเหลือ',
about: 'ประมาณ',
createdBy: 'สร้างโดย',
nextStep: 'ขั้นตอนถัดไป',
addNextStep: 'เพิ่มบล็อกถัดไปในเวิร์กโฟลว์นี้',
selectNextStep: 'เลือกบล็อกถัดไป',
runThisStep: 'เรียกใช้ขั้นตอนนี้',
checklist: 'ตรวจ สอบ',
checklistTip: 'ตรวจสอบให้แน่ใจว่าปัญหาทั้งหมดได้รับการแก้ไขแล้วก่อนที่จะเผยแพร่',
checklistResolved: 'ปัญหาทั้งหมดได้รับการแก้ไขแล้ว',
organizeBlocks: 'จัดระเบียบบล็อก',
change: 'เปลี่ยน',
optional: '(ไม่บังคับ)',
moveToThisNode: 'ย้ายไปที่โหนดนี้',
organizeBlocks: 'จัดระเบียบโหนด',
addNextStep: 'เพิ่มขั้นตอนถัดไปในกระบวนการทำงานนี้',
changeBlock: 'เปลี่ยนโหนด',
selectNextStep: 'เลือกขั้นตอนถัดไป',
},
nodes: {
common: {

View File

@ -471,7 +471,6 @@ const translation = {
apiBasedExtension: {
title: 'API uzantıları merkezi API yönetimi sağlar, Dify\'nin uygulamaları arasında kolay kullanım için yapılandırmayı basitleştirir.',
link: 'Kendi API Uzantınızı nasıl geliştireceğinizi öğrenin.',
linkUrl: 'https://docs.dify.ai/en/guides/extension/api-based-extension/README',
add: 'API Uzantısı Ekle',
selector: {
title: 'API Uzantısı',

Some files were not shown because too many files have changed in this diff Show More