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.js build output
.next/ .next/
# AI Assistant
.roo/

View File

@ -9,7 +9,7 @@ class PackagingInfo(BaseSettings):
CURRENT_VERSION: str = Field( CURRENT_VERSION: str = Field(
description="Dify version", description="Dify version",
default="1.4.2", default="1.4.3",
) )
COMMIT_SHA: str = Field( 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.add(end_user)
db.session.commit() 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()) exp = int(exp_dt.timestamp())
payload = { payload = {
"iss": site.id, "iss": site.id,

View File

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

View File

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

View File

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

View File

@ -41,6 +41,12 @@ class WeaviateVector(BaseVector):
weaviate.connect.connection.has_grpc = False 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: try:
client = weaviate.Client( client = weaviate.Client(
url=config.endpoint, auth_client_secret=auth_config, timeout_config=(5, 60), startup_period=None 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 datetime import UTC, datetime
from typing import Any, Optional, cast 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 configs import dify_config
from core.app.apps.base_app_queue_manager import GenerateTaskStoppedError 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.enums import ErrorStrategy, FailBranchSourceHandle
from core.workflow.nodes.event import RunCompletedEvent, RunRetrieverResourceEvent, RunStreamChunkEvent from core.workflow.nodes.event import RunCompletedEvent, RunRetrieverResourceEvent, RunStreamChunkEvent
from core.workflow.nodes.node_mapping import NODE_TYPE_CLASSES_MAPPING 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.enums import UserFrom
from models.workflow import WorkflowType from models.workflow import WorkflowType
@ -537,24 +538,9 @@ class GraphEngine:
""" """
Run parallel nodes Run parallel nodes
""" """
for var, val in context.items():
var.set(val)
# FIXME(-LAN-): Save current user before entering new app context with preserve_flask_contexts(flask_app, context_vars=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():
try: try:
# Restore user in new app context
if saved_user is not None:
from flask import g
g._login_user = saved_user
q.put( q.put(
ParallelBranchRunStartedEvent( ParallelBranchRunStartedEvent(
parallel_id=parallel_id, parallel_id=parallel_id,

View File

@ -214,7 +214,7 @@ class AgentNode(ToolNode):
) )
if tool_runtime.entity.description: if tool_runtime.entity.description:
tool_runtime.entity.description.llm = ( 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: for tool_runtime_params in tool_runtime.entity.parameters:
tool_runtime_params.form = ( tool_runtime_params.form = (

View File

@ -7,7 +7,7 @@ from datetime import UTC, datetime
from queue import Empty, Queue from queue import Empty, Queue
from typing import TYPE_CHECKING, Any, Optional, cast 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 configs import dify_config
from core.variables import ArrayVariable, IntegerVariable, NoneVariable 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.enums import NodeType
from core.workflow.nodes.event import NodeEvent, RunCompletedEvent from core.workflow.nodes.event import NodeEvent, RunCompletedEvent
from core.workflow.nodes.iteration.entities import ErrorHandleMode, IterationNodeData from core.workflow.nodes.iteration.entities import ErrorHandleMode, IterationNodeData
from libs.flask_utils import preserve_flask_contexts
from .exc import ( from .exc import (
InvalidIteratorValueError, InvalidIteratorValueError,
@ -583,23 +584,8 @@ class IterationNode(BaseNode[IterationNodeData]):
""" """
run single iteration in parallel mode 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 parallel_mode_run_id = uuid.uuid4().hex
graph_engine_copy = graph_engine.create_copy() graph_engine_copy = graph_engine.create_copy()
variable_pool_copy = graph_engine_copy.graph_runtime_state.variable_pool 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 configs import dify_config
from core.helper.position_helper import is_filtered from core.helper.position_helper import is_filtered
from core.model_runtime.utils.encoders import jsonable_encoder 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.plugin.impl.exc import PluginDaemonClientSideError
from core.tools.builtin_tool.providers._positions import BuiltinToolProviderSort from core.tools.builtin_tool.providers._positions import BuiltinToolProviderSort
from core.tools.entities.api_entities import ToolApiEntity, ToolProviderApiEntity 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: def _fetch_builtin_provider(provider_name: str, tenant_id: str) -> BuiltinToolProvider | None:
try: try:
full_provider_name = provider_name full_provider_name = provider_name
provider_id_entity = GenericProviderID(provider_name) provider_id_entity = ToolProviderID(provider_name)
provider_name = provider_id_entity.provider_name provider_name = provider_id_entity.provider_name
if provider_id_entity.organization != "langgenius": if provider_id_entity.organization != "langgenius":
provider_obj = ( provider_obj = (
@ -315,7 +315,7 @@ class BuiltinToolManageService:
if provider_obj is None: if provider_obj is None:
return None return None
provider_obj.provider = GenericProviderID(provider_obj.provider).to_string() provider_obj.provider = ToolProviderID(provider_obj.provider).to_string()
return provider_obj return provider_obj
except Exception: except Exception:
# it's an old provider without organization # 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: services:
# API service # API service
api: api:
image: langgenius/dify-api:1.4.2 image: langgenius/dify-api:1.4.3
restart: always restart: always
environment: environment:
# Use the shared environment variables. # Use the shared environment variables.
@ -31,7 +31,7 @@ services:
# worker service # worker service
# The Celery worker for processing the queue. # The Celery worker for processing the queue.
worker: worker:
image: langgenius/dify-api:1.4.2 image: langgenius/dify-api:1.4.3
restart: always restart: always
environment: environment:
# Use the shared environment variables. # Use the shared environment variables.
@ -57,7 +57,7 @@ services:
# Frontend web application. # Frontend web application.
web: web:
image: langgenius/dify-web:1.4.2 image: langgenius/dify-web:1.4.3
restart: always restart: always
environment: environment:
CONSOLE_API_URL: ${CONSOLE_API_URL:-} CONSOLE_API_URL: ${CONSOLE_API_URL:-}

View File

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

View File

@ -15,7 +15,7 @@ const Overview = async (props: IDevelopProps) => {
} = params } = params
return ( 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 /> <ApikeyInfoPanel />
<ChartView <ChartView
appId={appId} appId={appId}

View File

@ -1,9 +1,23 @@
'use client' 'use client'
import Loading from '@/app/components/base/loading'
import { useAppContext } from '@/context/app-context'
import { ExternalApiPanelProvider } from '@/context/external-api-panel-context' import { ExternalApiPanelProvider } from '@/context/external-api-panel-context'
import { ExternalKnowledgeApiProvider } from '@/context/external-knowledge-api-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 }) { 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 ( return (
<ExternalKnowledgeApiProvider> <ExternalKnowledgeApiProvider>
<ExternalApiPanelProvider> <ExternalApiPanelProvider>

View File

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

View File

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

View File

@ -20,6 +20,7 @@ import type {
import { useToastContext } from '@/app/components/base/toast' import { useToastContext } from '@/app/components/base/toast'
import AppIcon from '@/app/components/base/app-icon' import AppIcon from '@/app/components/base/app-icon'
import { noop } from 'lodash-es' import { noop } from 'lodash-es'
import { useDocLink } from '@/context/i18n'
const systemTypes = ['api'] const systemTypes = ['api']
type ExternalDataToolModalProps = { type ExternalDataToolModalProps = {
@ -40,6 +41,7 @@ const ExternalDataToolModal: FC<ExternalDataToolModalProps> = ({
onValidateBeforeSave, onValidateBeforeSave,
}) => { }) => {
const { t } = useTranslation() const { t } = useTranslation()
const docLink = useDocLink()
const { notify } = useToastContext() const { notify } = useToastContext()
const { locale } = useContext(I18n) const { locale } = useContext(I18n)
const [localeData, setLocaleData] = useState(data.type ? data : { ...data, type: 'api' }) 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'> <div className='flex h-9 items-center justify-between text-sm font-medium text-gray-900'>
{t('common.apiBasedExtension.selector.title')} {t('common.apiBasedExtension.selector.title')}
<a <a
href={t('common.apiBasedExtension.linkUrl') || '/'} href={docLink('/guides/extension/api-based-extension/README')}
target='_blank' rel='noopener noreferrer' target='_blank' rel='noopener noreferrer'
className='group flex items-center text-xs font-normal text-gray-500 hover:text-primary-600' 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': { 'advanced-chat': {
title: t('app.types.advanced'), title: t('app.types.advanced'),
description: t('app.newApp.advancedUserDescription'), 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': { 'agent-chat': {
title: t('app.types.agent'), title: t('app.types.agent'),
@ -324,13 +327,18 @@ function AppPreview({ mode }: { mode: AppMode }) {
'completion': { 'completion': {
title: t('app.newApp.completeApp'), title: t('app.newApp.completeApp'),
description: t('app.newApp.completionUserDescription'), description: t('app.newApp.completionUserDescription'),
link: docLink('/guides/application-orchestrate/text-generator', link: docLink('/guides/application-orchestrate/text-generator', {
{ 'zh-Hans': '/guides/application-orchestrate/readme' }), 'zh-Hans': '/guides/application-orchestrate/readme',
'ja-JP': '/guides/application-orchestrate/README',
}),
}, },
'workflow': { 'workflow': {
title: t('app.types.workflow'), title: t('app.types.workflow'),
description: t('app.newApp.workflowUserDescription'), 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] const previewInfo = modeToPreviewInfoMap[mode]

View File

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

View File

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

View File

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

View File

@ -74,7 +74,10 @@ const ModifyRetrievalModal: FC<Props> = ({
<a <a
target='_blank' target='_blank'
rel='noopener noreferrer' 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' className='text-text-accent'
> >
{t('datasetSettings.form.retrievalSetting.learnMore')} {t('datasetSettings.form.retrievalSetting.learnMore')}

View File

@ -310,7 +310,16 @@ const Form = () => {
<div> <div>
<div className='system-sm-semibold text-text-secondary'>{t('datasetSettings.form.retrievalSetting.title')}</div> <div className='system-sm-semibold text-text-secondary'>{t('datasetSettings.form.retrievalSetting.title')}</div>
<div className='body-xs-regular text-text-tertiary'> <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')} {t('datasetSettings.form.retrievalSetting.description')}
</div> </div>
</div> </div>

View File

@ -31,22 +31,22 @@ const WorkplaceSelector = () => {
} }
return ( return (
<Menu as="div" className="relative h-full w-full"> <Menu as="div" className="min-w-0">
{ {
({ open }) => ( ({ open }) => (
<> <>
<MenuButton className={cn( <MenuButton className={cn(
` `
group flex w-full cursor-pointer items-center 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> <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>
<div className='flex flex-row'> <div className='flex min-w-0 items-center'>
<div className={'system-sm-medium max-w-[160px] truncate text-text-secondary'}>{currentWorkspace?.name}</div> <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 text-text-secondary' /> <RiArrowDownSLine className='h-4 w-4 shrink-0 text-text-secondary' />
</div> </div>
</MenuButton> </MenuButton>
<Transition <Transition
@ -59,10 +59,11 @@ const WorkplaceSelector = () => {
leaveTo="transform opacity-0 scale-95" leaveTo="transform opacity-0 scale-95"
> >
<MenuItems <MenuItems
anchor="bottom start"
className={cn( 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 shadows-shadow-lg absolute left-[-15px] z-[1000] mt-1 flex max-h-[400px] w-[280px] flex-col items-start overflow-y-auto
bg-components-panel-bg-blur backdrop-blur-[5px] rounded-xl bg-components-panel-bg-blur backdrop-blur-[5px]
`, `,
)} )}
> >
@ -73,7 +74,7 @@ const WorkplaceSelector = () => {
{ {
workspaces.map(workspace => ( 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 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> <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>
<div className='system-md-regular line-clamp-1 grow cursor-pointer overflow-hidden text-ellipsis text-text-secondary'>{workspace.name}</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, RiExternalLinkLine,
RiPuzzle2Line, RiPuzzle2Line,
} from '@remixicon/react' } from '@remixicon/react'
import { useDocLink } from '@/context/i18n'
const Empty = () => { const Empty = () => {
const { t } = useTranslation() const { t } = useTranslation()
const docLink = useDocLink()
return ( return (
<div className='mb-2 rounded-xl bg-background-section p-6'> <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> <div className='system-sm-medium mb-1 text-text-secondary'>{t('common.apiBasedExtension.title')}</div>
<a <a
className='system-xs-regular flex items-center text-text-accent' 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' target='_blank' rel='noopener noreferrer'
> >
{t('common.apiBasedExtension.link')} {t('common.apiBasedExtension.link')}

View File

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

View File

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

View File

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

View File

@ -20,22 +20,22 @@ const EnvNav = () => {
return ( return (
<div className={` <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]} ${headerEnvClassName[langeniusVersionInfo.current_env]}
`}> `}>
{ {
langeniusVersionInfo.current_env === 'TESTING' && ( langeniusVersionInfo.current_env === 'TESTING' && (
<> <>
<Beaker02 className='mr-1 h-3 w-3' /> <Beaker02 className='h-3 w-3' />
{t('common.environment.testing')} <div className='ml-1 max-[1280px]:hidden'>{t('common.environment.testing')}</div>
</> </>
) )
} }
{ {
langeniusVersionInfo.current_env === 'DEVELOPMENT' && ( langeniusVersionInfo.current_env === 'DEVELOPMENT' && (
<> <>
<TerminalSquare className='mr-1 h-3 w-3' /> <TerminalSquare className='h-3 w-3' />
{t('common.environment.development')} <div className='ml-1 max-[1280px]:hidden'>{t('common.environment.development')}</div>
</> </>
) )
} }

View File

@ -27,10 +27,12 @@ const ExploreNav = ({
)}> )}>
{ {
activated activated
? <RiPlanetFill className='mr-2 h-4 w-4' /> ? <RiPlanetFill className='h-4 w-4' />
: <RiPlanetLine className='mr-2 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> </Link>
) )
} }

View File

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

View File

@ -46,7 +46,7 @@ const Nav = ({
return ( return (
<div className={` <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'} ${isActivated && 'bg-components-main-nav-nav-button-bg-active font-semibold shadow-md'}
${!curNav && !isActivated && 'hover:bg-components-main-nav-nav-button-bg-hover'} ${!curNav && !isActivated && 'hover:bg-components-main-nav-nav-button-bg-hover'}
`}> `}>
@ -61,7 +61,7 @@ const Nav = ({
onMouseEnter={() => setHovered(true)} onMouseEnter={() => setHovered(true)}
onMouseLeave={() => setHovered(false)} onMouseLeave={() => setHovered(false)}
> >
<div className='mr-2'> <div>
{ {
(hovered && curNav) (hovered && curNav)
? <ArrowNarrowLeft className='h-4 w-4' /> ? <ArrowNarrowLeft className='h-4 w-4' />
@ -70,7 +70,9 @@ const Nav = ({
: icon : icon
} }
</div> </div>
{text} <div className='ml-2 max-[1024px]:hidden'>
{text}
</div>
</div> </div>
</Link> </Link>
{ {

View File

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

View File

@ -28,10 +28,12 @@ const ToolsNav = ({
)}> )}>
{ {
activated activated
? <RiHammerFill className='mr-2 h-4 w-4' /> ? <RiHammerFill className='h-4 w-4' />
: <RiHammerLine className='mr-2 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> </Link>
) )
} }

View File

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

View File

@ -31,10 +31,13 @@ const TestApi: FC<Props> = ({
const language = getLanguage(locale) const language = getLanguage(locale)
const [credentialsModalShow, setCredentialsModalShow] = useState(false) const [credentialsModalShow, setCredentialsModalShow] = useState(false)
const [tempCredential, setTempCredential] = React.useState<Credential>(customCollection.credentials) const [tempCredential, setTempCredential] = React.useState<Credential>(customCollection.credentials)
const [testing, setTesting] = useState(false)
const [result, setResult] = useState<string>('') const [result, setResult] = useState<string>('')
const { operation_id: toolName, parameters } = tool const { operation_id: toolName, parameters } = tool
const [parametersValue, setParametersValue] = useState<Record<string, string>>({}) const [parametersValue, setParametersValue] = useState<Record<string, string>>({})
const handleTest = async () => { const handleTest = async () => {
if (testing) return
setTesting(true)
// clone test schema // clone test schema
const credentials = JSON.parse(JSON.stringify(tempCredential)) as Credential const credentials = JSON.parse(JSON.stringify(tempCredential)) as Credential
if (credentials.auth_type === AuthType.none) { if (credentials.auth_type === AuthType.none) {
@ -52,6 +55,7 @@ const TestApi: FC<Props> = ({
} }
const res = await testAPIAvailable(data) as any const res = await testAPIAvailable(data) as any
setResult(res.error || res.result) setResult(res.error || res.result)
setTesting(false)
} }
return ( return (
@ -107,7 +111,7 @@ const TestApi: FC<Props> = ({
</div> </div>
</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='mt-6'>
<div className='flex items-center space-x-3'> <div className='flex items-center space-x-3'>
<div className='system-xs-semibold text-text-tertiary'>{t('tools.test.testResult')}</div> <div className='system-xs-semibold text-text-tertiary'>{t('tools.test.testResult')}</div>

View File

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

View File

@ -118,6 +118,7 @@ export const AgentStrategy = memo((props: AgentStrategyProps) => {
title={<> title={<>
{renderI18nObject(def.label)} {def.required && <span className='text-red-500'>*</span>} {renderI18nObject(def.label)} {def.required && <span className='text-red-500'>*</span>}
</>} </>}
key={def.variable}
tooltip={def.tooltip && renderI18nObject(def.tooltip)} tooltip={def.tooltip && renderI18nObject(def.tooltip)}
inline inline
> >
@ -222,7 +223,8 @@ export const AgentStrategy = memo((props: AgentStrategyProps) => {
description={<div className='text-xs text-text-tertiary'> description={<div className='text-xs text-text-tertiary'>
{t('workflow.nodes.agent.strategy.configureTipDesc')} <br /> {t('workflow.nodes.agent.strategy.configureTipDesc')} <br />
<Link href={docLink('/guides/workflow/node/agent#select-an-agent-strategy', { <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'> className='text-text-accent-secondary' target='_blank'>
{t('workflow.nodes.agent.learnMore')} {t('workflow.nodes.agent.learnMore')}

View File

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

View File

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

View File

@ -8,6 +8,8 @@ import VarReferencePicker from './var-reference-picker'
import Input from '@/app/components/base/input' import Input from '@/app/components/base/input'
import type { ValueSelector, Var, Variable } from '@/app/components/workflow/types' import type { ValueSelector, Var, Variable } from '@/app/components/workflow/types'
import { VarType as VarKindType } from '@/app/components/workflow/nodes/tool/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 = { type Props = {
nodeId: string nodeId: string
@ -36,9 +38,27 @@ const VarList: FC<Props> = ({
const handleVarNameChange = useCallback((index: number) => { const handleVarNameChange = useCallback((index: number) => {
return (e: React.ChangeEvent<HTMLInputElement>) => { 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) => { const newList = produce(list, (draft) => {
draft[index].variable = e.target.value draft[index].variable = newKey
}) })
onChange(newList) onChange(newList)
} }

View File

@ -44,8 +44,11 @@ const VarReferencePopup: FC<Props> = ({
description={<div className='system-xs-regular text-text-tertiary'> description={<div className='system-xs-regular text-text-tertiary'>
{t('workflow.variableReference.assignedVarsDescription')} {t('workflow.variableReference.assignedVarsDescription')}
<a target='_blank' rel='noopener noreferrer' <a target='_blank' rel='noopener noreferrer'
className='text-text-accent-secondary' className='text-text-accent-secondary'
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.variableReference.conversationVars')} {t('workflow.variableReference.conversationVars')}
</a> </a>
</div>} </div>}

View File

@ -260,6 +260,7 @@ type Props = {
maxHeightClass?: string maxHeightClass?: string
onClose?: () => void onClose?: () => void
onBlur?: () => void onBlur?: () => void
autoFocus?: boolean
} }
const VarReferenceVars: FC<Props> = ({ const VarReferenceVars: FC<Props> = ({
hideSearch, hideSearch,
@ -271,6 +272,7 @@ const VarReferenceVars: FC<Props> = ({
maxHeightClass, maxHeightClass,
onClose, onClose,
onBlur, onBlur,
autoFocus = true,
}) => { }) => {
const { t } = useTranslation() const { t } = useTranslation()
const [searchText, setSearchText] = useState('') const [searchText, setSearchText] = useState('')
@ -323,7 +325,7 @@ const VarReferenceVars: FC<Props> = ({
onKeyDown={handleKeyDown} onKeyDown={handleKeyDown}
onClear={() => setSearchText('')} onClear={() => setSearchText('')}
onBlur={onBlur} onBlur={onBlur}
autoFocus autoFocus={autoFocus}
/> />
</div> </div>
<div className='relative left-[-4px] h-[0.5px] bg-black/5' style={{ <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 field = param.name
const value = inputs.agent_parameters?.[field]?.value const value = inputs.agent_parameters?.[field]?.value
if (value) { if (value) {
(value as unknown as any[]).forEach((item) => { (value as unknown as any[]).forEach((item, idx) => {
tools.push({ tools.push({
id: `${param.name}-${i}`, id: `${param.name}-${idx}`,
providerName: item.provider_name, providerName: item.provider_name,
}) })
}) })

View File

@ -138,10 +138,13 @@ const ChatVariablePanel = () => {
<div className='system-sm-regular mb-4 mt-1 text-text-secondary'> <div className='system-sm-regular mb-4 mt-1 text-text-secondary'>
{t('workflow.chatVariable.panelDescription')} {t('workflow.chatVariable.panelDescription')}
<a target='_blank' rel='noopener noreferrer' className='text-text-accent' <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')} {t('workflow.chatVariable.docLink')}
</a> </a>
</div> </div>
<div className='flex items-center gap-2'> <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'> <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' /> <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>
</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>
</div> </div>
)} )}

View File

@ -139,7 +139,7 @@ const VariableModal = ({
<div className='flex'> <div className='flex'>
{ {
type !== 'number' ? <textarea 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} value={value}
placeholder={t('workflow.env.modal.valuePlaceholder') || ''} placeholder={t('workflow.env.modal.valuePlaceholder') || ''}
onChange={e => setValue(e.target.value)} onChange={e => setValue(e.target.value)}

View File

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

View File

@ -467,7 +467,6 @@ const translation = {
apiBasedExtension: { apiBasedExtension: {
title: 'API-Erweiterungen bieten zentralisiertes API-Management und vereinfachen die Konfiguration für eine einfache Verwendung in Difys Anwendungen.', 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.', 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', add: 'API-Erweiterung hinzufügen',
selector: { selector: {
title: 'API-Erweiterung', title: 'API-Erweiterung',

View File

@ -69,7 +69,6 @@ const translation = {
unknownError: 'Unbekannter Fehler', unknownError: 'Unbekannter Fehler',
resetAll: 'Alles zurücksetzen', resetAll: 'Alles zurücksetzen',
extractOnlyMainContent: 'Extrahieren Sie nur den Hauptinhalt (keine Kopf-, Navigations- und Fußzeilen usw.)', 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', 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.', 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', crawlSubPage: 'Unterseiten crawlen',
@ -85,7 +84,6 @@ const translation = {
configureJinaReader: 'Jina Reader konfigurieren', configureJinaReader: 'Jina Reader konfigurieren',
waterCrawlNotConfigured: 'Watercrawl ist nicht konfiguriert', waterCrawlNotConfigured: 'Watercrawl ist nicht konfiguriert',
configureWatercrawl: 'Wasserkrabbe konfigurieren', 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', watercrawlTitle: 'Webinhalt mit Watercrawl extrahieren',
watercrawlDoc: 'Wasserkriechen-Dokumente', watercrawlDoc: 'Wasserkriechen-Dokumente',
configureFirecrawl: 'Firecrawl konfigurieren', configureFirecrawl: 'Firecrawl konfigurieren',

View File

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

View File

@ -484,7 +484,6 @@ const translation = {
apiBasedExtension: { apiBasedExtension: {
title: 'API extensions provide centralized API management, simplifying configuration for easy use across Dify\'s applications.', 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.', 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', add: 'Add API Extension',
selector: { selector: {
title: 'API Extension', title: 'API Extension',

View File

@ -80,10 +80,8 @@ const translation = {
run: 'Run', run: 'Run',
firecrawlTitle: 'Extract web content with 🔥Firecrawl', firecrawlTitle: 'Extract web content with 🔥Firecrawl',
firecrawlDoc: 'Firecrawl docs', 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', watercrawlTitle: 'Extract web content with Watercrawl',
watercrawlDoc: 'Watercrawl docs', 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', jinaReaderTitle: 'Convert the entire site to Markdown',
jinaReaderDoc: 'Learn more about Jina Reader', jinaReaderDoc: 'Learn more about Jina Reader',
jinaReaderDocLink: 'https://jina.ai/reader', jinaReaderDocLink: 'https://jina.ai/reader',

View File

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

View File

@ -471,7 +471,6 @@ const translation = {
apiBasedExtension: { 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.', 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.', 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', add: 'Agregar Extensión API',
selector: { selector: {
title: 'Extensión API', title: 'Extensión API',

View File

@ -63,7 +63,6 @@ const translation = {
run: 'Ejecutar', run: 'Ejecutar',
firecrawlTitle: 'Extraer contenido web con 🔥Firecrawl', firecrawlTitle: 'Extraer contenido web con 🔥Firecrawl',
firecrawlDoc: 'Documentación de 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', options: 'Opciones',
crawlSubPage: 'Rastrear subpáginas', crawlSubPage: 'Rastrear subpáginas',
limit: 'Límite', limit: 'Límite',
@ -92,7 +91,6 @@ const translation = {
configureFirecrawl: 'Configurar Firecrawl', configureFirecrawl: 'Configurar Firecrawl',
watercrawlDoc: 'Documentos de Watercrawl', watercrawlDoc: 'Documentos de Watercrawl',
configureJinaReader: 'Configurar Jina Reader', 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', configureWatercrawl: 'Configurar Watercrawl',
waterCrawlNotConfiguredDescription: 'Configura Watercrawl con la clave de API para usarlo.', 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.', builtInDescription: 'Los metadatos integrados se extraen y generan automáticamente. Deben estar habilitados antes de su uso y no se pueden editar.',
name: 'Nombre', name: 'Nombre',
description: 'Puedes gestionar todos los metadatos en este conocimiento aquí. Las modificaciones se sincronizarán en todos los documentos.', description: 'Puedes gestionar todos los metadatos en este conocimiento aquí. Las modificaciones se sincronizarán en todos los documentos.',
disabled: 'desactivar',
}, },
documentMetadata: { documentMetadata: {
technicalParameters: 'Parámetros técnicos', technicalParameters: 'Parámetros técnicos',

View File

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

View File

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

View File

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

View File

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

View File

@ -467,7 +467,6 @@ const translation = {
apiBasedExtension: { apiBasedExtension: {
title: 'Les extensions API fournissent une gestion centralisée des API, simplifiant la configuration pour une utilisation facile à travers les applications de Dify.', 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.', 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', add: 'Ajouter l\'extension API',
selector: { selector: {
title: 'Extension de l\'API', title: 'Extension de l\'API',

View File

@ -61,7 +61,6 @@ const translation = {
preview: 'Aperçu', preview: 'Aperçu',
crawlSubPage: 'Explorer les sous-pages', crawlSubPage: 'Explorer les sous-pages',
configure: 'Configurer', 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', maxDepth: 'Profondeur maximale',
fireCrawlNotConfigured: 'Firecrawl nest pas configuré', fireCrawlNotConfigured: 'Firecrawl nest pas configuré',
firecrawlTitle: 'Extraire du contenu web avec 🔥Firecrawl', firecrawlTitle: 'Extraire du contenu web avec 🔥Firecrawl',
@ -88,7 +87,6 @@ const translation = {
configureJinaReader: 'Configurer le lecteur Jina', configureJinaReader: 'Configurer le lecteur Jina',
configureWatercrawl: 'Configurer Watercrawl', configureWatercrawl: 'Configurer Watercrawl',
waterCrawlNotConfigured: 'Watercrawl n\'est pas configuré', 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', configureFirecrawl: 'Configurer Firecrawl',
}, },
cancel: 'Annuler', cancel: 'Annuler',

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -66,8 +66,6 @@ const translation = {
run: 'Esegui', run: 'Esegui',
firecrawlTitle: 'Estrai contenuti web con 🔥Firecrawl', firecrawlTitle: 'Estrai contenuti web con 🔥Firecrawl',
firecrawlDoc: 'Documenti Firecrawl', firecrawlDoc: 'Documenti Firecrawl',
firecrawlDocLink:
'https://docs.dify.ai/guides/knowledge-base/sync_from_website',
options: 'Opzioni', options: 'Opzioni',
crawlSubPage: 'Crawl sotto-pagine', crawlSubPage: 'Crawl sotto-pagine',
limit: 'Limite', limit: 'Limite',
@ -101,7 +99,6 @@ const translation = {
configureJinaReader: 'Configura Jina Reader', configureJinaReader: 'Configura Jina Reader',
configureWatercrawl: 'Configura Watercrawl', configureWatercrawl: 'Configura Watercrawl',
waterCrawlNotConfigured: 'Watercrawl non è configurato', 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', cancel: 'Annulla',
}, },

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -481,7 +481,6 @@ const translation = {
title: title:
'Rozszerzenia oparte na interfejsie API zapewniają scentralizowane zarządzanie interfejsami API, upraszczając konfigurację dla łatwego użytkowania w aplikacjach Dify.', '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.', 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', add: 'Dodaj rozszerzenie interfejsu API',
selector: { selector: {
title: 'Rozszerzenie interfejsu API', title: 'Rozszerzenie interfejsu API',

View File

@ -54,7 +54,6 @@ const translation = {
}, },
website: { website: {
limit: 'Ograniczać', 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', firecrawlDoc: 'Dokumentacja Firecrawl',
unknownError: 'Nieznany błąd', unknownError: 'Nieznany błąd',
fireCrawlNotConfiguredDescription: 'Skonfiguruj Firecrawl z kluczem API, aby z niego korzystać.', 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.', jinaReaderNotConfiguredDescription: 'Skonfiguruj Jina Reader, wprowadzając bezpłatny klucz API, aby uzyskać dostęp.',
watercrawlTitle: 'Wyodrębnij treści z sieci za pomocą Watercrawl', watercrawlTitle: 'Wyodrębnij treści z sieci za pomocą Watercrawl',
configureWatercrawl: 'Skonfiguruj 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', configureJinaReader: 'Skonfiguruj Czytnik Jina',
configureFirecrawl: 'Skonfiguruj Firecrawl', configureFirecrawl: 'Skonfiguruj Firecrawl',
watercrawlDoc: 'Dokumentacja Watercrawl', watercrawlDoc: 'Dokumentacja Watercrawl',

View File

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

View File

@ -467,7 +467,6 @@ const translation = {
apiBasedExtension: { 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.', 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.', 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', add: 'Adicionar Extensão de API',
selector: { selector: {
title: 'Extensão de API', title: 'Extensão de API',

View File

@ -58,7 +58,6 @@ const translation = {
crawlSubPage: 'Rastrear subpáginas', crawlSubPage: 'Rastrear subpáginas',
selectAll: 'Selecionar tudo', selectAll: 'Selecionar tudo',
resetAll: 'Redefinir 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', includeOnlyPaths: 'Incluir apenas caminhos',
configure: 'Configurar', configure: 'Configurar',
limit: 'Limite', limit: 'Limite',
@ -87,7 +86,6 @@ const translation = {
configureJinaReader: 'Configurar o Leitor Jina', configureJinaReader: 'Configurar o Leitor Jina',
waterCrawlNotConfigured: 'Watercrawl não está configurado', waterCrawlNotConfigured: 'Watercrawl não está configurado',
waterCrawlNotConfiguredDescription: 'Configure o Watercrawl com a chave da API para usá-lo.', 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', watercrawlDoc: 'Documentos do Watercrawl',
configureWatercrawl: 'Configurar Watercrawl', configureWatercrawl: 'Configurar Watercrawl',
}, },

View File

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

View File

@ -467,7 +467,6 @@ const translation = {
apiBasedExtension: { 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.', 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.', 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', add: 'Adăugați extensie API',
selector: { selector: {
title: 'Extensie API', title: 'Extensie API',

View File

@ -65,7 +65,6 @@ const translation = {
firecrawlTitle: 'Extrageți conținut web cu 🔥Firecrawl', firecrawlTitle: 'Extrageți conținut web cu 🔥Firecrawl',
unknownError: 'Eroare necunoscută', unknownError: 'Eroare necunoscută',
scrapTimeInfo: 'Pagini răzuite {{total}} în total în {{timp}}s', 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', excludePaths: 'Excluderea căilor',
resetAll: 'Resetați toate', resetAll: 'Resetați toate',
extractOnlyMainContent: 'Extrageți doar conținutul principal (fără anteturi, navigări, subsoluri etc.)', 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', watercrawlTitle: 'Extrageți conținut web cu Watercrawl',
configureJinaReader: 'Configurează Jina Reader', configureJinaReader: 'Configurează Jina Reader',
waterCrawlNotConfiguredDescription: 'Configurează Watercrawl cu cheia API pentru a-l folosi.', 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', configureFirecrawl: 'Configurează Firecrawl',
watercrawlDoc: 'Documentele Watercrawl', watercrawlDoc: 'Documentele Watercrawl',
configureWatercrawl: 'Configurează Watercrawl', configureWatercrawl: 'Configurează Watercrawl',

View File

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

View File

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

View File

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

View File

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

View File

@ -464,7 +464,6 @@ const translation = {
apiBasedExtension: { apiBasedExtension: {
title: 'Razširitve API omogočajo centralizirano upravljanje API, kar poenostavi konfiguracijo za enostavno uporabo v aplikacijah Dify.', 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.', 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', add: 'Dodaj API razširitev',
selector: { selector: {
title: 'API razširitev', title: 'API razširitev',
@ -693,7 +692,6 @@ const translation = {
type: 'Vrsta', type: 'Vrsta',
link: 'Preberite, kako razvijete lastno razširitev API-ja.', 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.', 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', add: 'Dodajanje razširitve API-ja',
}, },
about: { about: {

View File

@ -71,7 +71,6 @@ const translation = {
run: 'Zaženi', run: 'Zaženi',
firecrawlTitle: 'Izvleci spletno vsebino z 🔥Firecrawl', firecrawlTitle: 'Izvleci spletno vsebino z 🔥Firecrawl',
firecrawlDoc: 'Firecrawl dokumentacija', 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', jinaReaderTitle: 'Pretvori celotno stran v Markdown',
jinaReaderDoc: 'Več o Jina Reader', jinaReaderDoc: 'Več o Jina Reader',
jinaReaderDocLink: 'https://jina.ai/reader', jinaReaderDocLink: 'https://jina.ai/reader',
@ -97,7 +96,6 @@ const translation = {
waterCrawlNotConfigured: 'Watercrawl ni konfiguriran', waterCrawlNotConfigured: 'Watercrawl ni konfiguriran',
watercrawlDoc: 'Watercrawl dokumentacija', watercrawlDoc: 'Watercrawl dokumentacija',
configureJinaReader: 'Konfigurirajte Jina Reader', 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', configureFirecrawl: 'Konfigurirajte Firecrawl',
watercrawlTitle: 'Izvleci vsebino z interneta z Watercrawl', 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: { apiBasedExtension: {
title: 'ส่วนขยาย API ให้การจัดการ API แบบรวมศูนย์ ทําให้การกําหนดค่าง่ายขึ้นเพื่อให้ใช้งานได้ง่ายในแอปพลิเคชันของ Dify', title: 'ส่วนขยาย API ให้การจัดการ API แบบรวมศูนย์ ทําให้การกําหนดค่าง่ายขึ้นเพื่อให้ใช้งานได้ง่ายในแอปพลิเคชันของ Dify',
link: 'เรียนรู้วิธีพัฒนาส่วนขยาย API ของคุณเอง', link: 'เรียนรู้วิธีพัฒนาส่วนขยาย API ของคุณเอง',
linkUrl: 'https://docs.dify.ai/en/guides/knowledge-base/create-knowledge-and-upload-documents/import-content-data/sync-from-website',
add: 'เพิ่มส่วนขยาย API', add: 'เพิ่มส่วนขยาย API',
selector: { selector: {
title: 'ส่วนขยาย API', title: 'ส่วนขยาย API',

View File

@ -71,7 +71,6 @@ const translation = {
run: 'วิ่ง', run: 'วิ่ง',
firecrawlTitle: 'แยกเนื้อหาเว็บด้วย 🔥Firecrawl', firecrawlTitle: 'แยกเนื้อหาเว็บด้วย 🔥Firecrawl',
firecrawlDoc: 'เอกสาร 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', jinaReaderTitle: 'แปลงทั้งไซต์เป็น Markdown',
jinaReaderDoc: 'เรียนรู้เพิ่มเติมเกี่ยวกับ Jina Reader', jinaReaderDoc: 'เรียนรู้เพิ่มเติมเกี่ยวกับ Jina Reader',
jinaReaderDocLink: 'https://jina.ai/reader', jinaReaderDocLink: 'https://jina.ai/reader',
@ -94,7 +93,6 @@ const translation = {
maxDepthTooltip: 'ความลึกสูงสุดในการรวบรวมข้อมูลเมื่อเทียบกับ URL ที่ป้อน ความลึก 0 เพียงแค่ขูดหน้าของ URL ที่ป้อนความลึก 1 ขูด url และทุกอย่างหลังจาก enteredURL + หนึ่ง / เป็นต้น', maxDepthTooltip: 'ความลึกสูงสุดในการรวบรวมข้อมูลเมื่อเทียบกับ URL ที่ป้อน ความลึก 0 เพียงแค่ขูดหน้าของ URL ที่ป้อนความลึก 1 ขูด url และทุกอย่างหลังจาก enteredURL + หนึ่ง / เป็นต้น',
watercrawlTitle: 'ดึงเนื้อหาจากเว็บด้วย Watercrawl', watercrawlTitle: 'ดึงเนื้อหาจากเว็บด้วย Watercrawl',
configureJinaReader: 'ตั้งค่า Jina Reader', 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', configureFirecrawl: 'กำหนดค่า Firecrawl',
configureWatercrawl: 'กำหนดค่าการเข้าถึงน้ำ', configureWatercrawl: 'กำหนดค่าการเข้าถึงน้ำ',
waterCrawlNotConfiguredDescription: 'กำหนดค่า Watercrawl ด้วย API key เพื่อใช้งาน.', waterCrawlNotConfiguredDescription: 'กำหนดค่า Watercrawl ด้วย API key เพื่อใช้งาน.',

View File

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

View File

@ -471,7 +471,6 @@ const translation = {
apiBasedExtension: { 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.', 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.', 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', add: 'API Uzantısı Ekle',
selector: { selector: {
title: 'API Uzantısı', title: 'API Uzantısı',

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