Merge remote-tracking branch 'origin/main' into feat/oauth

pull/22550/head
Harry 10 months ago
commit 32fc208e35

@ -27,19 +27,19 @@ class InvalidTokenError(BaseHTTPException):
class PasswordResetRateLimitExceededError(BaseHTTPException):
error_code = "password_reset_rate_limit_exceeded"
description = "Too many password reset emails have been sent. Please try again in 1 minutes."
description = "Too many password reset emails have been sent. Please try again in 1 minute."
code = 429
class EmailChangeRateLimitExceededError(BaseHTTPException):
error_code = "email_change_rate_limit_exceeded"
description = "Too many email change emails have been sent. Please try again in 1 minutes."
description = "Too many email change emails have been sent. Please try again in 1 minute."
code = 429
class OwnerTransferRateLimitExceededError(BaseHTTPException):
error_code = "owner_transfer_rate_limit_exceeded"
description = "Too many owner tansfer emails have been sent. Please try again in 1 minutes."
description = "Too many owner transfer emails have been sent. Please try again in 1 minute."
code = 429

@ -264,11 +264,9 @@ class OwnerTransfer(Resource):
transfer_token_data = AccountService.get_owner_transfer_data(args["token"])
if not transfer_token_data:
print(transfer_token_data, "transfer_token_data")
raise InvalidTokenError()
if transfer_token_data.get("email") != current_user.email:
print(transfer_token_data.get("email"), current_user.email)
raise InvalidEmailError()
AccountService.revoke_owner_transfer_token(args["token"])

@ -148,9 +148,11 @@ class LLMGenerator:
model_manager = ModelManager()
model_instance = model_manager.get_default_model_instance(
model_instance = model_manager.get_model_instance(
tenant_id=tenant_id,
model_type=ModelType.LLM,
provider=model_config.get("provider", ""),
model=model_config.get("name", ""),
)
try:

@ -205,7 +205,7 @@ def init_app(app: DifyApp):
metric_endpoint = dify_config.OTLP_METRIC_ENDPOINT
if not metric_endpoint:
metric_endpoint = dify_config.OTLP_BASE_ENDPOINT + "/v1/traces"
metric_endpoint = dify_config.OTLP_BASE_ENDPOINT + "/v1/metrics"
metric_exporter = HTTPMetricExporter(
endpoint=metric_endpoint,
headers=headers,

@ -111,7 +111,6 @@
<p class="title">验证您的邮箱变更请求</p>
<div class="description">
<p class="content1">我们收到了一个变更您 Dify 账户关联邮箱地址的请求。</p>
<p class="content2">我们收到了一个变更您 Dify 账户关联邮箱地址的请求。</p>
<p class="content3">此验证码仅在接下来的5分钟内有效</p>
</div>
<div class="code-content">

@ -143,7 +143,7 @@
<div class="warning">Please note:</div>
<ul class="warningList">
<li>The ownership transfer will take effect immediately once confirmed and cannot be undone.</li>
<li>Youll become a admin member, and the new owner will have full control of the workspace.</li>
<li>Youll become an admin member, and the new owner will have full control of the workspace.</li>
</ul>
<p class="tips">If you didnt make this request, please ignore this email or contact support immediately.</p>
</div>

@ -108,7 +108,6 @@
<p class="title">验证您的邮箱变更请求</p>
<div class="description">
<p class="content1">我们收到了一个变更您 Dify 账户关联邮箱地址的请求。</p>
<p class="content2">我们收到了一个变更您 Dify 账户关联邮箱地址的请求。</p>
<p class="content3">此验证码仅在接下来的5分钟内有效</p>
</div>
<div class="code-content">

@ -140,7 +140,7 @@
<div class="warning">Please note:</div>
<ul class="warningList">
<li>The ownership transfer will take effect immediately once confirmed and cannot be undone.</li>
<li>Youll become a admin member, and the new owner will have full control of the workspace.</li>
<li>Youll become an admin member, and the new owner will have full control of the workspace.</li>
</ul>
<p class="tips">If you didnt make this request, please ignore this email or contact support immediately.</p>
</div>

@ -0,0 +1,496 @@
from unittest.mock import MagicMock, patch
import pytest
from flask import Flask
from controllers.console.auth.oauth import (
OAuthCallback,
OAuthLogin,
_generate_account,
_get_account_by_openid_or_email,
get_oauth_providers,
)
from libs.oauth import OAuthUserInfo
from models.account import AccountStatus
from services.errors.account import AccountNotFoundError
class TestGetOAuthProviders:
@pytest.fixture
def app(self):
app = Flask(__name__)
app.config["TESTING"] = True
return app
@pytest.mark.parametrize(
("github_config", "google_config", "expected_github", "expected_google"),
[
# Both providers configured
(
{"id": "github_id", "secret": "github_secret"},
{"id": "google_id", "secret": "google_secret"},
True,
True,
),
# Only GitHub configured
({"id": "github_id", "secret": "github_secret"}, {"id": None, "secret": None}, True, False),
# Only Google configured
({"id": None, "secret": None}, {"id": "google_id", "secret": "google_secret"}, False, True),
# No providers configured
({"id": None, "secret": None}, {"id": None, "secret": None}, False, False),
],
)
@patch("controllers.console.auth.oauth.dify_config")
def test_should_configure_oauth_providers_correctly(
self, mock_config, app, github_config, google_config, expected_github, expected_google
):
mock_config.GITHUB_CLIENT_ID = github_config["id"]
mock_config.GITHUB_CLIENT_SECRET = github_config["secret"]
mock_config.GOOGLE_CLIENT_ID = google_config["id"]
mock_config.GOOGLE_CLIENT_SECRET = google_config["secret"]
mock_config.CONSOLE_API_URL = "http://localhost"
with app.app_context():
providers = get_oauth_providers()
assert (providers["github"] is not None) == expected_github
assert (providers["google"] is not None) == expected_google
class TestOAuthLogin:
@pytest.fixture
def resource(self):
return OAuthLogin()
@pytest.fixture
def app(self):
app = Flask(__name__)
app.config["TESTING"] = True
return app
@pytest.fixture
def mock_oauth_provider(self):
provider = MagicMock()
provider.get_authorization_url.return_value = "https://github.com/login/oauth/authorize?..."
return provider
@pytest.mark.parametrize(
("invite_token", "expected_token"),
[
(None, None),
("test_invite_token", "test_invite_token"),
("", None),
],
)
@patch("controllers.console.auth.oauth.get_oauth_providers")
@patch("controllers.console.auth.oauth.redirect")
def test_should_handle_oauth_login_with_various_tokens(
self,
mock_redirect,
mock_get_providers,
resource,
app,
mock_oauth_provider,
invite_token,
expected_token,
):
mock_get_providers.return_value = {"github": mock_oauth_provider, "google": None}
query_string = f"invite_token={invite_token}" if invite_token else ""
with app.test_request_context(f"/auth/oauth/github?{query_string}"):
resource.get("github")
mock_oauth_provider.get_authorization_url.assert_called_once_with(invite_token=expected_token)
mock_redirect.assert_called_once_with("https://github.com/login/oauth/authorize?...")
@pytest.mark.parametrize(
("provider", "expected_error"),
[
("invalid_provider", "Invalid provider"),
("github", "Invalid provider"), # When GitHub is not configured
("google", "Invalid provider"), # When Google is not configured
],
)
@patch("controllers.console.auth.oauth.get_oauth_providers")
def test_should_return_error_for_invalid_providers(
self, mock_get_providers, resource, app, provider, expected_error
):
mock_get_providers.return_value = {"github": None, "google": None}
with app.test_request_context(f"/auth/oauth/{provider}"):
response, status_code = resource.get(provider)
assert status_code == 400
assert response["error"] == expected_error
class TestOAuthCallback:
@pytest.fixture
def resource(self):
return OAuthCallback()
@pytest.fixture
def app(self):
app = Flask(__name__)
app.config["TESTING"] = True
return app
@pytest.fixture
def oauth_setup(self):
"""Common OAuth setup for callback tests"""
oauth_provider = MagicMock()
oauth_provider.get_access_token.return_value = "access_token"
oauth_provider.get_user_info.return_value = OAuthUserInfo(id="123", name="Test User", email="test@example.com")
account = MagicMock()
account.status = AccountStatus.ACTIVE.value
token_pair = MagicMock()
token_pair.access_token = "jwt_access_token"
token_pair.refresh_token = "jwt_refresh_token"
return {"provider": oauth_provider, "account": account, "token_pair": token_pair}
@patch("controllers.console.auth.oauth.dify_config")
@patch("controllers.console.auth.oauth.get_oauth_providers")
@patch("controllers.console.auth.oauth._generate_account")
@patch("controllers.console.auth.oauth.AccountService")
@patch("controllers.console.auth.oauth.TenantService")
@patch("controllers.console.auth.oauth.redirect")
def test_should_handle_successful_oauth_callback(
self,
mock_redirect,
mock_tenant_service,
mock_account_service,
mock_generate_account,
mock_get_providers,
mock_config,
resource,
app,
oauth_setup,
):
mock_config.CONSOLE_WEB_URL = "http://localhost:3000"
mock_get_providers.return_value = {"github": oauth_setup["provider"]}
mock_generate_account.return_value = oauth_setup["account"]
mock_account_service.login.return_value = oauth_setup["token_pair"]
with app.test_request_context("/auth/oauth/github/callback?code=test_code"):
resource.get("github")
oauth_setup["provider"].get_access_token.assert_called_once_with("test_code")
oauth_setup["provider"].get_user_info.assert_called_once_with("access_token")
mock_redirect.assert_called_once_with(
"http://localhost:3000?access_token=jwt_access_token&refresh_token=jwt_refresh_token"
)
@pytest.mark.parametrize(
("exception", "expected_error"),
[
(Exception("OAuth error"), "OAuth process failed"),
(ValueError("Invalid token"), "OAuth process failed"),
(KeyError("Missing key"), "OAuth process failed"),
],
)
@patch("controllers.console.auth.oauth.db")
@patch("controllers.console.auth.oauth.get_oauth_providers")
def test_should_handle_oauth_exceptions(
self, mock_get_providers, mock_db, resource, app, exception, expected_error
):
# Mock database session
mock_db.session = MagicMock()
mock_db.session.rollback = MagicMock()
# Import the real requests module to create a proper exception
import requests
request_exception = requests.exceptions.RequestException("OAuth error")
request_exception.response = MagicMock()
request_exception.response.text = str(exception)
mock_oauth_provider = MagicMock()
mock_oauth_provider.get_access_token.side_effect = request_exception
mock_get_providers.return_value = {"github": mock_oauth_provider}
with app.test_request_context("/auth/oauth/github/callback?code=test_code"):
response, status_code = resource.get("github")
assert status_code == 400
assert response["error"] == expected_error
@pytest.mark.parametrize(
("account_status", "expected_redirect"),
[
(AccountStatus.BANNED.value, "http://localhost:3000/signin?message=Account is banned."),
# CLOSED status: Currently NOT handled, will proceed to login (security issue)
# This documents actual behavior. See test_defensive_check_for_closed_account_status for details
(
AccountStatus.CLOSED.value,
"http://localhost:3000?access_token=jwt_access_token&refresh_token=jwt_refresh_token",
),
],
)
@patch("controllers.console.auth.oauth.AccountService")
@patch("controllers.console.auth.oauth.TenantService")
@patch("controllers.console.auth.oauth.db")
@patch("controllers.console.auth.oauth.dify_config")
@patch("controllers.console.auth.oauth.get_oauth_providers")
@patch("controllers.console.auth.oauth._generate_account")
@patch("controllers.console.auth.oauth.redirect")
def test_should_redirect_based_on_account_status(
self,
mock_redirect,
mock_generate_account,
mock_get_providers,
mock_config,
mock_db,
mock_tenant_service,
mock_account_service,
resource,
app,
oauth_setup,
account_status,
expected_redirect,
):
# Mock database session
mock_db.session = MagicMock()
mock_db.session.rollback = MagicMock()
mock_db.session.commit = MagicMock()
mock_config.CONSOLE_WEB_URL = "http://localhost:3000"
mock_get_providers.return_value = {"github": oauth_setup["provider"]}
account = MagicMock()
account.status = account_status
account.id = "123"
mock_generate_account.return_value = account
# Mock login for CLOSED status
mock_token_pair = MagicMock()
mock_token_pair.access_token = "jwt_access_token"
mock_token_pair.refresh_token = "jwt_refresh_token"
mock_account_service.login.return_value = mock_token_pair
with app.test_request_context("/auth/oauth/github/callback?code=test_code"):
resource.get("github")
mock_redirect.assert_called_once_with(expected_redirect)
@patch("controllers.console.auth.oauth.dify_config")
@patch("controllers.console.auth.oauth.get_oauth_providers")
@patch("controllers.console.auth.oauth._generate_account")
@patch("controllers.console.auth.oauth.db")
@patch("controllers.console.auth.oauth.TenantService")
@patch("controllers.console.auth.oauth.AccountService")
def test_should_activate_pending_account(
self,
mock_account_service,
mock_tenant_service,
mock_db,
mock_generate_account,
mock_get_providers,
mock_config,
resource,
app,
oauth_setup,
):
mock_get_providers.return_value = {"github": oauth_setup["provider"]}
mock_account = MagicMock()
mock_account.status = AccountStatus.PENDING.value
mock_generate_account.return_value = mock_account
with app.test_request_context("/auth/oauth/github/callback?code=test_code"):
resource.get("github")
assert mock_account.status == AccountStatus.ACTIVE.value
assert mock_account.initialized_at is not None
mock_db.session.commit.assert_called_once()
@patch("controllers.console.auth.oauth.dify_config")
@patch("controllers.console.auth.oauth.get_oauth_providers")
@patch("controllers.console.auth.oauth._generate_account")
@patch("controllers.console.auth.oauth.db")
@patch("controllers.console.auth.oauth.TenantService")
@patch("controllers.console.auth.oauth.AccountService")
@patch("controllers.console.auth.oauth.redirect")
def test_defensive_check_for_closed_account_status(
self,
mock_redirect,
mock_account_service,
mock_tenant_service,
mock_db,
mock_generate_account,
mock_get_providers,
mock_config,
resource,
app,
oauth_setup,
):
"""Defensive test for CLOSED account status handling in OAuth callback.
This is a defensive test documenting expected security behavior for CLOSED accounts.
Current behavior: CLOSED status is NOT checked, allowing closed accounts to login.
Expected behavior: CLOSED accounts should be rejected like BANNED accounts.
Context:
- AccountStatus.CLOSED is defined in the enum but never used in production
- The close_account() method exists but is never called
- Account deletion uses external service instead of status change
- All authentication services (OAuth, password, email) don't check CLOSED status
TODO: If CLOSED status is implemented in the future:
1. Update OAuth callback to check for CLOSED status
2. Add similar checks to all authentication services for consistency
3. Update this test to verify the rejection behavior
Security consideration: Until properly implemented, CLOSED status provides no protection.
"""
# Setup
mock_config.CONSOLE_WEB_URL = "http://localhost:3000"
mock_get_providers.return_value = {"github": oauth_setup["provider"]}
# Create account with CLOSED status
closed_account = MagicMock()
closed_account.status = AccountStatus.CLOSED.value
closed_account.id = "123"
closed_account.name = "Closed Account"
mock_generate_account.return_value = closed_account
# Mock successful login (current behavior)
mock_token_pair = MagicMock()
mock_token_pair.access_token = "jwt_access_token"
mock_token_pair.refresh_token = "jwt_refresh_token"
mock_account_service.login.return_value = mock_token_pair
# Execute OAuth callback
with app.test_request_context("/auth/oauth/github/callback?code=test_code"):
resource.get("github")
# Verify current behavior: login succeeds (this is NOT ideal)
mock_redirect.assert_called_once_with(
"http://localhost:3000?access_token=jwt_access_token&refresh_token=jwt_refresh_token"
)
mock_account_service.login.assert_called_once()
# Document expected behavior in comments:
# Expected: mock_redirect.assert_called_once_with(
# "http://localhost:3000/signin?message=Account is closed."
# )
# Expected: mock_account_service.login.assert_not_called()
class TestAccountGeneration:
@pytest.fixture
def user_info(self):
return OAuthUserInfo(id="123", name="Test User", email="test@example.com")
@pytest.fixture
def mock_account(self):
account = MagicMock()
account.name = "Test User"
return account
@patch("controllers.console.auth.oauth.db")
@patch("controllers.console.auth.oauth.Account")
@patch("controllers.console.auth.oauth.Session")
@patch("controllers.console.auth.oauth.select")
def test_should_get_account_by_openid_or_email(
self, mock_select, mock_session, mock_account_model, mock_db, user_info, mock_account
):
# Mock db.engine for Session creation
mock_db.engine = MagicMock()
# Test OpenID found
mock_account_model.get_by_openid.return_value = mock_account
result = _get_account_by_openid_or_email("github", user_info)
assert result == mock_account
mock_account_model.get_by_openid.assert_called_once_with("github", "123")
# Test fallback to email
mock_account_model.get_by_openid.return_value = None
mock_session_instance = MagicMock()
mock_session_instance.execute.return_value.scalar_one_or_none.return_value = mock_account
mock_session.return_value.__enter__.return_value = mock_session_instance
result = _get_account_by_openid_or_email("github", user_info)
assert result == mock_account
@pytest.mark.parametrize(
("allow_register", "existing_account", "should_create"),
[
(True, None, True), # New account creation allowed
(True, "existing", False), # Existing account
(False, None, False), # Registration not allowed
],
)
@patch("controllers.console.auth.oauth._get_account_by_openid_or_email")
@patch("controllers.console.auth.oauth.FeatureService")
@patch("controllers.console.auth.oauth.RegisterService")
@patch("controllers.console.auth.oauth.AccountService")
@patch("controllers.console.auth.oauth.TenantService")
@patch("controllers.console.auth.oauth.db")
def test_should_handle_account_generation_scenarios(
self,
mock_db,
mock_tenant_service,
mock_account_service,
mock_register_service,
mock_feature_service,
mock_get_account,
app,
user_info,
mock_account,
allow_register,
existing_account,
should_create,
):
mock_get_account.return_value = mock_account if existing_account else None
mock_feature_service.get_system_features.return_value.is_allow_register = allow_register
mock_register_service.register.return_value = mock_account
with app.test_request_context(headers={"Accept-Language": "en-US,en;q=0.9"}):
if not allow_register and not existing_account:
with pytest.raises(AccountNotFoundError):
_generate_account("github", user_info)
else:
result = _generate_account("github", user_info)
assert result == mock_account
if should_create:
mock_register_service.register.assert_called_once_with(
email="test@example.com", name="Test User", password=None, open_id="123", provider="github"
)
@patch("controllers.console.auth.oauth._get_account_by_openid_or_email")
@patch("controllers.console.auth.oauth.TenantService")
@patch("controllers.console.auth.oauth.FeatureService")
@patch("controllers.console.auth.oauth.AccountService")
@patch("controllers.console.auth.oauth.tenant_was_created")
def test_should_create_workspace_for_account_without_tenant(
self,
mock_event,
mock_account_service,
mock_feature_service,
mock_tenant_service,
mock_get_account,
app,
user_info,
mock_account,
):
mock_get_account.return_value = mock_account
mock_tenant_service.get_join_tenants.return_value = []
mock_feature_service.get_system_features.return_value.is_allow_create_workspace = True
mock_new_tenant = MagicMock()
mock_tenant_service.create_tenant.return_value = mock_new_tenant
with app.test_request_context(headers={"Accept-Language": "en-US,en;q=0.9"}):
result = _generate_account("github", user_info)
assert result == mock_account
mock_tenant_service.create_tenant.assert_called_once_with("Test User's Workspace")
mock_tenant_service.create_tenant_member.assert_called_once_with(
mock_new_tenant, mock_account, role="owner"
)
mock_event.send.assert_called_once_with(mock_new_tenant)

@ -0,0 +1,249 @@
import urllib.parse
from unittest.mock import MagicMock, patch
import pytest
import requests
from libs.oauth import GitHubOAuth, GoogleOAuth, OAuthUserInfo
class BaseOAuthTest:
"""Base class for OAuth provider tests with common fixtures"""
@pytest.fixture
def oauth_config(self):
return {
"client_id": "test_client_id",
"client_secret": "test_client_secret",
"redirect_uri": "http://localhost/callback",
}
@pytest.fixture
def mock_response(self):
response = MagicMock()
response.json.return_value = {}
return response
def parse_auth_url(self, url):
"""Helper to parse authorization URL"""
parsed = urllib.parse.urlparse(url)
params = urllib.parse.parse_qs(parsed.query)
return parsed, params
class TestGitHubOAuth(BaseOAuthTest):
@pytest.fixture
def oauth(self, oauth_config):
return GitHubOAuth(oauth_config["client_id"], oauth_config["client_secret"], oauth_config["redirect_uri"])
@pytest.mark.parametrize(
("invite_token", "expected_state"),
[
(None, None),
("test_invite_token", "test_invite_token"),
("", None),
],
)
def test_should_generate_authorization_url_correctly(self, oauth, oauth_config, invite_token, expected_state):
url = oauth.get_authorization_url(invite_token)
parsed, params = self.parse_auth_url(url)
assert parsed.scheme == "https"
assert parsed.netloc == "github.com"
assert parsed.path == "/login/oauth/authorize"
assert params["client_id"][0] == oauth_config["client_id"]
assert params["redirect_uri"][0] == oauth_config["redirect_uri"]
assert params["scope"][0] == "user:email"
if expected_state:
assert params["state"][0] == expected_state
else:
assert "state" not in params
@pytest.mark.parametrize(
("response_data", "expected_token", "should_raise"),
[
({"access_token": "test_token"}, "test_token", False),
({"error": "invalid_grant"}, None, True),
({}, None, True),
],
)
@patch("requests.post")
def test_should_retrieve_access_token(
self, mock_post, oauth, mock_response, response_data, expected_token, should_raise
):
mock_response.json.return_value = response_data
mock_post.return_value = mock_response
if should_raise:
with pytest.raises(ValueError) as exc_info:
oauth.get_access_token("test_code")
assert "Error in GitHub OAuth" in str(exc_info.value)
else:
token = oauth.get_access_token("test_code")
assert token == expected_token
@pytest.mark.parametrize(
("user_data", "email_data", "expected_email"),
[
# User with primary email
(
{"id": 12345, "login": "testuser", "name": "Test User"},
[
{"email": "secondary@example.com", "primary": False},
{"email": "primary@example.com", "primary": True},
],
"primary@example.com",
),
# User with no emails - fallback to noreply
({"id": 12345, "login": "testuser", "name": "Test User"}, [], "12345+testuser@users.noreply.github.com"),
# User with only secondary email - fallback to noreply
(
{"id": 12345, "login": "testuser", "name": "Test User"},
[{"email": "secondary@example.com", "primary": False}],
"12345+testuser@users.noreply.github.com",
),
],
)
@patch("requests.get")
def test_should_retrieve_user_info_correctly(self, mock_get, oauth, user_data, email_data, expected_email):
user_response = MagicMock()
user_response.json.return_value = user_data
email_response = MagicMock()
email_response.json.return_value = email_data
mock_get.side_effect = [user_response, email_response]
user_info = oauth.get_user_info("test_token")
assert user_info.id == str(user_data["id"])
assert user_info.name == user_data["name"]
assert user_info.email == expected_email
@patch("requests.get")
def test_should_handle_network_errors(self, mock_get, oauth):
mock_get.side_effect = requests.exceptions.RequestException("Network error")
with pytest.raises(requests.exceptions.RequestException):
oauth.get_raw_user_info("test_token")
class TestGoogleOAuth(BaseOAuthTest):
@pytest.fixture
def oauth(self, oauth_config):
return GoogleOAuth(oauth_config["client_id"], oauth_config["client_secret"], oauth_config["redirect_uri"])
@pytest.mark.parametrize(
("invite_token", "expected_state"),
[
(None, None),
("test_invite_token", "test_invite_token"),
("", None),
],
)
def test_should_generate_authorization_url_correctly(self, oauth, oauth_config, invite_token, expected_state):
url = oauth.get_authorization_url(invite_token)
parsed, params = self.parse_auth_url(url)
assert parsed.scheme == "https"
assert parsed.netloc == "accounts.google.com"
assert parsed.path == "/o/oauth2/v2/auth"
assert params["client_id"][0] == oauth_config["client_id"]
assert params["redirect_uri"][0] == oauth_config["redirect_uri"]
assert params["response_type"][0] == "code"
assert params["scope"][0] == "openid email"
if expected_state:
assert params["state"][0] == expected_state
else:
assert "state" not in params
@pytest.mark.parametrize(
("response_data", "expected_token", "should_raise"),
[
({"access_token": "test_token"}, "test_token", False),
({"error": "invalid_grant"}, None, True),
({}, None, True),
],
)
@patch("requests.post")
def test_should_retrieve_access_token(
self, mock_post, oauth, oauth_config, mock_response, response_data, expected_token, should_raise
):
mock_response.json.return_value = response_data
mock_post.return_value = mock_response
if should_raise:
with pytest.raises(ValueError) as exc_info:
oauth.get_access_token("test_code")
assert "Error in Google OAuth" in str(exc_info.value)
else:
token = oauth.get_access_token("test_code")
assert token == expected_token
mock_post.assert_called_once_with(
oauth._TOKEN_URL,
data={
"client_id": oauth_config["client_id"],
"client_secret": oauth_config["client_secret"],
"code": "test_code",
"grant_type": "authorization_code",
"redirect_uri": oauth_config["redirect_uri"],
},
headers={"Accept": "application/json"},
)
@pytest.mark.parametrize(
("user_data", "expected_name"),
[
({"sub": "123", "email": "test@example.com", "email_verified": True}, ""),
({"sub": "123", "email": "test@example.com", "name": "Test User"}, ""), # Always returns empty string
],
)
@patch("requests.get")
def test_should_retrieve_user_info_correctly(self, mock_get, oauth, mock_response, user_data, expected_name):
mock_response.json.return_value = user_data
mock_get.return_value = mock_response
user_info = oauth.get_user_info("test_token")
assert user_info.id == user_data["sub"]
assert user_info.name == expected_name
assert user_info.email == user_data["email"]
mock_get.assert_called_once_with(oauth._USER_INFO_URL, headers={"Authorization": "Bearer test_token"})
@pytest.mark.parametrize(
"exception_type",
[
requests.exceptions.HTTPError,
requests.exceptions.ConnectionError,
requests.exceptions.Timeout,
],
)
@patch("requests.get")
def test_should_handle_http_errors(self, mock_get, oauth, exception_type):
mock_response = MagicMock()
mock_response.raise_for_status.side_effect = exception_type("Error")
mock_get.return_value = mock_response
with pytest.raises(exception_type):
oauth.get_raw_user_info("invalid_token")
class TestOAuthUserInfo:
@pytest.mark.parametrize(
"user_data",
[
{"id": "123", "name": "Test User", "email": "test@example.com"},
{"id": "456", "name": "", "email": "user@domain.com"},
{"id": "789", "name": "Another User", "email": "another@test.org"},
],
)
def test_should_create_user_info_dataclass(self, user_data):
user_info = OAuthUserInfo(**user_data)
assert user_info.id == user_data["id"]
assert user_info.name == user_data["name"]
assert user_info.email == user_data["email"]

@ -183,3 +183,42 @@ rename_conversation_response.raise_for_status()
print('[rename result]')
print(rename_conversation_response.json())
```
* Using the Workflow Client
```python
import json
import requests
from dify_client import WorkflowClient
api_key = "your_api_key"
# Initialize Workflow Client
client = WorkflowClient(api_key)
# Prepare parameters for Workflow Client
user_id = "your_user_id"
context = "previous user interaction / metadata"
user_prompt = "What is the capital of France?"
inputs = {
"context": context,
"user_prompt": user_prompt,
# Add other input fields expected by your workflow (e.g., additional context, task parameters)
}
# Set response mode (default: streaming)
response_mode = "blocking"
# Run the workflow
response = client.run(inputs=inputs, response_mode=response_mode, user=user_id)
response.raise_for_status()
# Parse result
result = json.loads(response.text)
answer = result.get("data").get("outputs")
print(answer["answer"])
```

@ -1 +1 @@
from dify_client.client import ChatClient, CompletionClient, DifyClient
from dify_client.client import ChatClient, CompletionClient, WorkflowClient, KnowledgeBaseClient, DifyClient

@ -308,7 +308,7 @@ const AppCard = ({ app, onRefresh }: AppCardProps) => {
const EditTimeText = useMemo(() => {
const timeText = formatTime({
date: (app.updated_at || app.created_at) * 1000,
dateFormat: 'MM/DD/YYYY h:mm',
dateFormat: `${t('datasetDocuments.segment.dateTimeFormat')}`,
})
return `${t('datasetDocuments.segment.editedAt')} ${timeText}`
// eslint-disable-next-line react-hooks/exhaustive-deps

@ -113,8 +113,8 @@ const EmailChangeModal = ({ onClose, email, show }: Props) => {
}
const isValidEmail = (email: string): boolean => {
const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/
return emailRegex.test(email)
const rfc5322emailRegex = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/
return rfc5322emailRegex.test(email) && email.length <= 254
}
const checkNewEmailExisted = async (email: string) => {

@ -17,8 +17,8 @@ import PromptEditorHeightResizeWrap from './prompt-editor-height-resize-wrap'
import cn from '@/utils/classnames'
import type { PromptRole, PromptVariable } from '@/models/debug'
import {
Clipboard,
ClipboardCheck,
Copy,
CopyCheck,
} from '@/app/components/base/icons/src/vender/line/files'
import Button from '@/app/components/base/button'
import Tooltip from '@/app/components/base/tooltip'
@ -188,13 +188,13 @@ const AdvancedPromptInput: FC<Props> = ({
)}
{!isCopied
? (
<Clipboard className='h-6 w-6 cursor-pointer p-1 text-text-tertiary' onClick={() => {
<Copy className='h-6 w-6 cursor-pointer p-1 text-text-tertiary' onClick={() => {
copy(value)
setIsCopied(true)
}} />
)
: (
<ClipboardCheck className='h-6 w-6 p-1 text-text-tertiary' />
<CopyCheck className='h-6 w-6 p-1 text-text-tertiary' />
)}
</div>
</div>

@ -6,8 +6,8 @@ import { useContext } from 'use-context-selector'
import { useTranslation } from 'react-i18next'
import cn from '@/utils/classnames'
import {
Clipboard,
ClipboardCheck,
Copy,
CopyCheck,
} from '@/app/components/base/icons/src/vender/line/files'
import PromptEditor from '@/app/components/base/prompt-editor'
import type { ExternalDataTool } from '@/models/common'
@ -81,13 +81,13 @@ const Editor: FC<Props> = ({
<div className={cn(s.optionWrap, 'items-center space-x-1')}>
{!isCopied
? (
<Clipboard className='h-6 w-6 cursor-pointer p-1 text-gray-500' onClick={() => {
<Copy className='h-6 w-6 cursor-pointer p-1 text-gray-500' onClick={() => {
copy(value)
setIsCopied(true)
}} />
)
: (
<ClipboardCheck className='h-6 w-6 p-1 text-gray-500' />
<CopyCheck className='h-6 w-6 p-1 text-gray-500' />
)}
</div>
</div>

@ -5,8 +5,8 @@ import { debounce } from 'lodash-es'
import copy from 'copy-to-clipboard'
import Tooltip from '../tooltip'
import {
Clipboard,
ClipboardCheck,
Copy,
CopyCheck,
} from '@/app/components/base/icons/src/vender/line/files'
type Props = {
@ -39,10 +39,10 @@ export const CopyIcon = ({ content }: Props) => {
<div onMouseLeave={onMouseLeave}>
{!isCopied
? (
<Clipboard className='mx-1 h-3.5 w-3.5 cursor-pointer text-text-tertiary' onClick={onClickCopy} />
<Copy className='mx-1 h-3.5 w-3.5 cursor-pointer text-text-tertiary' onClick={onClickCopy} />
)
: (
<ClipboardCheck className='mx-1 h-3.5 w-3.5 text-text-tertiary' />
<CopyCheck className='mx-1 h-3.5 w-3.5 text-text-tertiary' />
)
}
</div>

@ -1,3 +0,0 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M16 4C16.93 4 17.395 4 17.7765 4.10222C18.8117 4.37962 19.6204 5.18827 19.8978 6.22354C20 6.60504 20 7.07003 20 8V17.2C20 18.8802 20 19.7202 19.673 20.362C19.3854 20.9265 18.9265 21.3854 18.362 21.673C17.7202 22 16.8802 22 15.2 22H8.8C7.11984 22 6.27976 22 5.63803 21.673C5.07354 21.3854 4.6146 20.9265 4.32698 20.362C4 19.7202 4 18.8802 4 17.2V8C4 7.07003 4 6.60504 4.10222 6.22354C4.37962 5.18827 5.18827 4.37962 6.22354 4.10222C6.60504 4 7.07003 4 8 4M9 15L11 17L15.5 12.5M9.6 6H14.4C14.9601 6 15.2401 6 15.454 5.89101C15.6422 5.79513 15.7951 5.64215 15.891 5.45399C16 5.24008 16 4.96005 16 4.4V3.6C16 3.03995 16 2.75992 15.891 2.54601C15.7951 2.35785 15.6422 2.20487 15.454 2.10899C15.2401 2 14.9601 2 14.4 2H9.6C9.03995 2 8.75992 2 8.54601 2.10899C8.35785 2.20487 8.20487 2.35785 8.10899 2.54601C8 2.75992 8 3.03995 8 3.6V4.4C8 4.96005 8 5.24008 8.10899 5.45399C8.20487 5.64215 8.35785 5.79513 8.54601 5.89101C8.75992 6 9.03995 6 9.6 6Z" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

@ -1,3 +0,0 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M16 4C16.93 4 17.395 4 17.7765 4.10222C18.8117 4.37962 19.6204 5.18827 19.8978 6.22354C20 6.60504 20 7.07003 20 8V17.2C20 18.8802 20 19.7202 19.673 20.362C19.3854 20.9265 18.9265 21.3854 18.362 21.673C17.7202 22 16.8802 22 15.2 22H8.8C7.11984 22 6.27976 22 5.63803 21.673C5.07354 21.3854 4.6146 20.9265 4.32698 20.362C4 19.7202 4 18.8802 4 17.2V8C4 7.07003 4 6.60504 4.10222 6.22354C4.37962 5.18827 5.18827 4.37962 6.22354 4.10222C6.60504 4 7.07003 4 8 4M9.6 6H14.4C14.9601 6 15.2401 6 15.454 5.89101C15.6422 5.79513 15.7951 5.64215 15.891 5.45399C16 5.24008 16 4.96005 16 4.4V3.6C16 3.03995 16 2.75992 15.891 2.54601C15.7951 2.35785 15.6422 2.20487 15.454 2.10899C15.2401 2 14.9601 2 14.4 2H9.6C9.03995 2 8.75992 2 8.54601 2.10899C8.35785 2.20487 8.20487 2.35785 8.10899 2.54601C8 2.75992 8 3.03995 8 3.6V4.4C8 4.96005 8 5.24008 8.10899 5.45399C8.20487 5.64215 8.35785 5.79513 8.54601 5.89101C8.75992 6 9.03995 6 9.6 6Z" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M10.6665 2.66683C11.2865 2.66683 11.5965 2.66683 11.8508 2.73498C12.541 2.91991 13.0801 3.45901 13.265 4.14919C13.3332 4.40352 13.3332 4.71352 13.3332 5.3335V11.4668C13.3332 12.5869 13.3332 13.147 13.1152 13.5748C12.9234 13.9511 12.6175 14.2571 12.2412 14.4488C11.8133 14.6668 11.2533 14.6668 10.1332 14.6668H5.8665C4.7464 14.6668 4.18635 14.6668 3.75852 14.4488C3.3822 14.2571 3.07624 13.9511 2.88449 13.5748C2.6665 13.147 2.6665 12.5869 2.6665 11.4668V5.3335C2.6665 4.71352 2.6665 4.40352 2.73465 4.14919C2.91959 3.45901 3.45868 2.91991 4.14887 2.73498C4.4032 2.66683 4.71319 2.66683 5.33317 2.66683M5.99984 10.0002L7.33317 11.3335L10.3332 8.3335M6.39984 4.00016H9.59984C9.9732 4.00016 10.1599 4.00016 10.3025 3.9275C10.4279 3.86359 10.5299 3.7616 10.5938 3.63616C10.6665 3.49355 10.6665 3.30686 10.6665 2.9335V2.40016C10.6665 2.02679 10.6665 1.84011 10.5938 1.6975C10.5299 1.57206 10.4279 1.47007 10.3025 1.40616C10.1599 1.3335 9.97321 1.3335 9.59984 1.3335H6.39984C6.02647 1.3335 5.83978 1.3335 5.69718 1.40616C5.57174 1.47007 5.46975 1.57206 5.40583 1.6975C5.33317 1.84011 5.33317 2.02679 5.33317 2.40016V2.9335C5.33317 3.30686 5.33317 3.49355 5.40583 3.63616C5.46975 3.7616 5.57174 3.86359 5.69718 3.9275C5.83978 4.00016 6.02647 4.00016 6.39984 4.00016Z" stroke="#1D2939" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M10.6665 2.66634H11.9998C12.3535 2.66634 12.6926 2.80682 12.9426 3.05687C13.1927 3.30691 13.3332 3.64605 13.3332 3.99967V13.333C13.3332 13.6866 13.1927 14.0258 12.9426 14.2758C12.6926 14.5259 12.3535 14.6663 11.9998 14.6663H3.99984C3.64622 14.6663 3.30708 14.5259 3.05703 14.2758C2.80698 14.0258 2.6665 13.6866 2.6665 13.333V3.99967C2.6665 3.64605 2.80698 3.30691 3.05703 3.05687C3.30708 2.80682 3.64622 2.66634 3.99984 2.66634H5.33317M5.99984 1.33301H9.99984C10.368 1.33301 10.6665 1.63148 10.6665 1.99967V3.33301C10.6665 3.7012 10.368 3.99967 9.99984 3.99967H5.99984C5.63165 3.99967 5.33317 3.7012 5.33317 3.33301V1.99967C5.33317 1.63148 5.63165 1.33301 5.99984 1.33301Z" stroke="#667085" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 875 B

@ -1,29 +0,0 @@
{
"icon": {
"type": "element",
"isRootNode": true,
"name": "svg",
"attributes": {
"width": "24",
"height": "24",
"viewBox": "0 0 24 24",
"fill": "none",
"xmlns": "http://www.w3.org/2000/svg"
},
"children": [
{
"type": "element",
"name": "path",
"attributes": {
"d": "M16 4C16.93 4 17.395 4 17.7765 4.10222C18.8117 4.37962 19.6204 5.18827 19.8978 6.22354C20 6.60504 20 7.07003 20 8V17.2C20 18.8802 20 19.7202 19.673 20.362C19.3854 20.9265 18.9265 21.3854 18.362 21.673C17.7202 22 16.8802 22 15.2 22H8.8C7.11984 22 6.27976 22 5.63803 21.673C5.07354 21.3854 4.6146 20.9265 4.32698 20.362C4 19.7202 4 18.8802 4 17.2V8C4 7.07003 4 6.60504 4.10222 6.22354C4.37962 5.18827 5.18827 4.37962 6.22354 4.10222C6.60504 4 7.07003 4 8 4M9.6 6H14.4C14.9601 6 15.2401 6 15.454 5.89101C15.6422 5.79513 15.7951 5.64215 15.891 5.45399C16 5.24008 16 4.96005 16 4.4V3.6C16 3.03995 16 2.75992 15.891 2.54601C15.7951 2.35785 15.6422 2.20487 15.454 2.10899C15.2401 2 14.9601 2 14.4 2H9.6C9.03995 2 8.75992 2 8.54601 2.10899C8.35785 2.20487 8.20487 2.35785 8.10899 2.54601C8 2.75992 8 3.03995 8 3.6V4.4C8 4.96005 8 5.24008 8.10899 5.45399C8.20487 5.64215 8.35785 5.79513 8.54601 5.89101C8.75992 6 9.03995 6 9.6 6Z",
"stroke": "currentColor",
"stroke-width": "2",
"stroke-linecap": "round",
"stroke-linejoin": "round"
},
"children": []
}
]
},
"name": "Clipboard"
}

@ -1,29 +0,0 @@
{
"icon": {
"type": "element",
"isRootNode": true,
"name": "svg",
"attributes": {
"width": "24",
"height": "24",
"viewBox": "0 0 24 24",
"fill": "none",
"xmlns": "http://www.w3.org/2000/svg"
},
"children": [
{
"type": "element",
"name": "path",
"attributes": {
"d": "M16 4C16.93 4 17.395 4 17.7765 4.10222C18.8117 4.37962 19.6204 5.18827 19.8978 6.22354C20 6.60504 20 7.07003 20 8V17.2C20 18.8802 20 19.7202 19.673 20.362C19.3854 20.9265 18.9265 21.3854 18.362 21.673C17.7202 22 16.8802 22 15.2 22H8.8C7.11984 22 6.27976 22 5.63803 21.673C5.07354 21.3854 4.6146 20.9265 4.32698 20.362C4 19.7202 4 18.8802 4 17.2V8C4 7.07003 4 6.60504 4.10222 6.22354C4.37962 5.18827 5.18827 4.37962 6.22354 4.10222C6.60504 4 7.07003 4 8 4M9 15L11 17L15.5 12.5M9.6 6H14.4C14.9601 6 15.2401 6 15.454 5.89101C15.6422 5.79513 15.7951 5.64215 15.891 5.45399C16 5.24008 16 4.96005 16 4.4V3.6C16 3.03995 16 2.75992 15.891 2.54601C15.7951 2.35785 15.6422 2.20487 15.454 2.10899C15.2401 2 14.9601 2 14.4 2H9.6C9.03995 2 8.75992 2 8.54601 2.10899C8.35785 2.20487 8.20487 2.35785 8.10899 2.54601C8 2.75992 8 3.03995 8 3.6V4.4C8 4.96005 8 5.24008 8.10899 5.45399C8.20487 5.64215 8.35785 5.79513 8.54601 5.89101C8.75992 6 9.03995 6 9.6 6Z",
"stroke": "currentColor",
"stroke-width": "2",
"stroke-linecap": "round",
"stroke-linejoin": "round"
},
"children": []
}
]
},
"name": "ClipboardCheck"
}

@ -0,0 +1,29 @@
{
"icon": {
"type": "element",
"isRootNode": true,
"name": "svg",
"attributes": {
"width": "16",
"height": "16",
"viewBox": "0 0 16 16",
"fill": "none",
"xmlns": "http://www.w3.org/2000/svg"
},
"children": [
{
"type": "element",
"name": "path",
"attributes": {
"d": "M10.6665 2.66634H11.9998C12.3535 2.66634 12.6926 2.80682 12.9426 3.05687C13.1927 3.30691 13.3332 3.64605 13.3332 3.99967V13.333C13.3332 13.6866 13.1927 14.0258 12.9426 14.2758C12.6926 14.5259 12.3535 14.6663 11.9998 14.6663H3.99984C3.64622 14.6663 3.30708 14.5259 3.05703 14.2758C2.80698 14.0258 2.6665 13.6866 2.6665 13.333V3.99967C2.6665 3.64605 2.80698 3.30691 3.05703 3.05687C3.30708 2.80682 3.64622 2.66634 3.99984 2.66634H5.33317M5.99984 1.33301H9.99984C10.368 1.33301 10.6665 1.63148 10.6665 1.99967V3.33301C10.6665 3.7012 10.368 3.99967 9.99984 3.99967H5.99984C5.63165 3.99967 5.33317 3.7012 5.33317 3.33301V1.99967C5.33317 1.63148 5.63165 1.33301 5.99984 1.33301Z",
"stroke": "currentColor",
"stroke-width": "1.5",
"stroke-linecap": "round",
"stroke-linejoin": "round"
},
"children": []
}
]
},
"name": "Copy"
}

@ -2,7 +2,7 @@
// DON NOT EDIT IT MANUALLY
import * as React from 'react'
import data from './Clipboard.json'
import data from './Copy.json'
import IconBase from '@/app/components/base/icons/IconBase'
import type { IconData } from '@/app/components/base/icons/IconBase'
@ -15,6 +15,6 @@ const Icon = (
},
) => <IconBase {...props} ref={ref} data={data as IconData} />
Icon.displayName = 'Clipboard'
Icon.displayName = 'Copy'
export default Icon

@ -0,0 +1,29 @@
{
"icon": {
"type": "element",
"isRootNode": true,
"name": "svg",
"attributes": {
"width": "16",
"height": "16",
"viewBox": "0 0 16 16",
"fill": "none",
"xmlns": "http://www.w3.org/2000/svg"
},
"children": [
{
"type": "element",
"name": "path",
"attributes": {
"d": "M10.6665 2.66683C11.2865 2.66683 11.5965 2.66683 11.8508 2.73498C12.541 2.91991 13.0801 3.45901 13.265 4.14919C13.3332 4.40352 13.3332 4.71352 13.3332 5.3335V11.4668C13.3332 12.5869 13.3332 13.147 13.1152 13.5748C12.9234 13.9511 12.6175 14.2571 12.2412 14.4488C11.8133 14.6668 11.2533 14.6668 10.1332 14.6668H5.8665C4.7464 14.6668 4.18635 14.6668 3.75852 14.4488C3.3822 14.2571 3.07624 13.9511 2.88449 13.5748C2.6665 13.147 2.6665 12.5869 2.6665 11.4668V5.3335C2.6665 4.71352 2.6665 4.40352 2.73465 4.14919C2.91959 3.45901 3.45868 2.91991 4.14887 2.73498C4.4032 2.66683 4.71319 2.66683 5.33317 2.66683M5.99984 10.0002L7.33317 11.3335L10.3332 8.3335M6.39984 4.00016H9.59984C9.9732 4.00016 10.1599 4.00016 10.3025 3.9275C10.4279 3.86359 10.5299 3.7616 10.5938 3.63616C10.6665 3.49355 10.6665 3.30686 10.6665 2.9335V2.40016C10.6665 2.02679 10.6665 1.84011 10.5938 1.6975C10.5299 1.57206 10.4279 1.47007 10.3025 1.40616C10.1599 1.3335 9.97321 1.3335 9.59984 1.3335H6.39984C6.02647 1.3335 5.83978 1.3335 5.69718 1.40616C5.57174 1.47007 5.46975 1.57206 5.40583 1.6975C5.33317 1.84011 5.33317 2.02679 5.33317 2.40016V2.9335C5.33317 3.30686 5.33317 3.49355 5.40583 3.63616C5.46975 3.7616 5.57174 3.86359 5.69718 3.9275C5.83978 4.00016 6.02647 4.00016 6.39984 4.00016Z",
"stroke": "currentColor",
"stroke-width": "1.5",
"stroke-linecap": "round",
"stroke-linejoin": "round"
},
"children": []
}
]
},
"name": "CopyCheck"
}

@ -2,7 +2,7 @@
// DON NOT EDIT IT MANUALLY
import * as React from 'react'
import data from './ClipboardCheck.json'
import data from './CopyCheck.json'
import IconBase from '@/app/components/base/icons/IconBase'
import type { IconData } from '@/app/components/base/icons/IconBase'
@ -15,6 +15,6 @@ const Icon = (
},
) => <IconBase {...props} ref={ref} data={data as IconData} />
Icon.displayName = 'ClipboardCheck'
Icon.displayName = 'CopyCheck'
export default Icon

@ -1,5 +1,5 @@
export { default as ClipboardCheck } from './ClipboardCheck'
export { default as Clipboard } from './Clipboard'
export { default as CopyCheck } from './CopyCheck'
export { default as Copy } from './Copy'
export { default as File02 } from './File02'
export { default as FileArrow01 } from './FileArrow01'
export { default as FileCheck02 } from './FileCheck02'

@ -66,7 +66,7 @@ const ChildSegmentDetail: FC<IChildSegmentDetailProps> = ({
const EditTimeText = useMemo(() => {
const timeText = formatTime({
date: (childChunkInfo?.updated_at ?? 0) * 1000,
dateFormat: 'MM/DD/YYYY h:mm:ss',
dateFormat: `${t('datasetDocuments.segment.dateTimeFormat')}`,
})
return `${t('datasetDocuments.segment.editedAt')} ${timeText}`
// eslint-disable-next-line react-hooks/exhaustive-deps
@ -74,7 +74,7 @@ const ChildSegmentDetail: FC<IChildSegmentDetailProps> = ({
return (
<div className={'flex h-full flex-col'}>
<div className={classNames('flex items-center justify-between', fullScreen ? 'py-3 pr-4 pl-6 border border-divider-subtle' : 'pt-3 pr-3 pl-4')}>
<div className={classNames('flex items-center justify-between', fullScreen ? 'border border-divider-subtle py-3 pl-6 pr-4' : 'pl-4 pr-3 pt-3')}>
<div className='flex flex-col'>
<div className='system-xl-semibold text-text-primary'>{t('datasetDocuments.segment.editChildChunk')}</div>
<div className='flex items-center gap-x-2'>
@ -107,8 +107,8 @@ const ChildSegmentDetail: FC<IChildSegmentDetailProps> = ({
</div>
</div>
</div>
<div className={classNames('flex grow w-full', fullScreen ? 'flex-row justify-center px-6 pt-6' : 'py-3 px-4')}>
<div className={classNames('break-all overflow-hidden whitespace-pre-line h-full', fullScreen ? 'w-1/2' : 'w-full')}>
<div className={classNames('flex w-full grow', fullScreen ? 'flex-row justify-center px-6 pt-6' : 'px-4 py-3')}>
<div className={classNames('h-full overflow-hidden whitespace-pre-line break-all', fullScreen ? 'w-1/2' : 'w-full')}>
<ChunkContent
docForm={docForm}
question={content}

@ -6,7 +6,7 @@ import {
RiClipboardLine,
} from '@remixicon/react'
import { useTranslation } from 'react-i18next'
import { ClipboardCheck } from '../../base/icons/src/vender/line/files'
import { CopyCheck } from '../../base/icons/src/vender/line/files'
import Tooltip from '../../base/tooltip'
import cn from '@/utils/classnames'
import ActionButton from '@/app/components/base/action-button'
@ -44,7 +44,7 @@ const KeyValueItem: FC<Props> = ({
}
}, [isCopied])
const CopyIcon = isCopied ? ClipboardCheck : RiClipboardLine
const CopyIcon = isCopied ? CopyCheck : RiClipboardLine
return (
<div className='flex items-center gap-1'>

@ -7,7 +7,7 @@ import type { EndpointListItem } from '../types'
import EndpointModal from './endpoint-modal'
import { NAME_FIELD } from './utils'
import { addDefaultValue, toolCredentialToFormSchemas } from '@/app/components/tools/utils/to-form-schema'
import { ClipboardCheck } from '@/app/components/base/icons/src/vender/line/files'
import { CopyCheck } from '@/app/components/base/icons/src/vender/line/files'
import ActionButton from '@/app/components/base/action-button'
import Confirm from '@/app/components/base/confirm'
import Indicator from '@/app/components/header/indicator'
@ -130,7 +130,7 @@ const EndpointCard = ({
}
}, [isCopied])
const CopyIcon = isCopied ? ClipboardCheck : RiClipboardLine
const CopyIcon = isCopied ? CopyCheck : RiClipboardLine
return (
<div className='rounded-xl bg-background-section-burn p-0.5'>

@ -9,8 +9,8 @@ import Wrap from './wrap'
import cn from '@/utils/classnames'
import PromptEditorHeightResizeWrap from '@/app/components/app/configuration/config-prompt/prompt-editor-height-resize-wrap'
import {
Clipboard,
ClipboardCheck,
Copy,
CopyCheck,
} from '@/app/components/base/icons/src/vender/line/files'
import useToggleExpend from '@/app/components/workflow/nodes/_base/hooks/use-toggle-expend'
import type { FileEntity } from '@/app/components/base/file-uploader/types'
@ -92,10 +92,10 @@ const Base: FC<Props> = ({
<ActionButton className='ml-1' onClick={handleCopy}>
{!isCopied
? (
<Clipboard className='h-4 w-4 cursor-pointer' />
<Copy className='h-4 w-4 cursor-pointer' />
)
: (
<ClipboardCheck className='h-4 w-4' />
<CopyCheck className='h-4 w-4' />
)
}
</ActionButton>

@ -23,8 +23,8 @@ import ToggleExpandBtn from '@/app/components/workflow/nodes/_base/components/to
import useToggleExpend from '@/app/components/workflow/nodes/_base/hooks/use-toggle-expend'
import PromptEditor from '@/app/components/base/prompt-editor'
import {
Clipboard,
ClipboardCheck,
Copy,
CopyCheck,
} from '@/app/components/base/icons/src/vender/line/files'
import { useEventEmitterContextContext } from '@/context/event-emitter'
import { PROMPT_EDITOR_INSERT_QUICKLY } from '@/app/components/base/prompt-editor/plugins/update-block'
@ -204,12 +204,12 @@ const Editor: FC<Props> = ({
{!isCopied
? (
<ActionButton onClick={handleCopy}>
<Clipboard className='h-4 w-4' />
<Copy className='h-4 w-4' />
</ActionButton>
)
: (
<ActionButton>
<ClipboardCheck className='h-4 w-4' />
<CopyCheck className='h-4 w-4' />
</ActionButton>
)
}

@ -9,8 +9,8 @@ import Modal from '@/app/components/base/modal'
import { BubbleX } from '@/app/components/base/icons/src/vender/line/others'
import CodeEditor from '@/app/components/workflow/nodes/_base/components/editor/code-editor'
import {
Clipboard,
ClipboardCheck,
Copy,
CopyCheck,
} from '@/app/components/base/icons/src/vender/line/files'
import { useStore } from '@/app/components/workflow/store'
import type {
@ -122,10 +122,10 @@ const ConversationVariableModal = ({
<div className='flex items-center p-1'>
{!isCopied
? (
<Clipboard className='h-4 w-4 cursor-pointer text-text-tertiary' onClick={handleCopy} />
<Copy className='h-4 w-4 cursor-pointer text-text-tertiary' onClick={handleCopy} />
)
: (
<ClipboardCheck className='h-4 w-4 text-text-tertiary' />
<CopyCheck className='h-4 w-4 text-text-tertiary' />
)
}
</div>

@ -174,7 +174,10 @@ const translation = {
title: 'Weben',
description: 'Weave ist eine Open-Source-Plattform zur Bewertung, Testung und Überwachung von LLM-Anwendungen.',
},
aliyun: {},
aliyun: {
title: 'Cloud-Monitor',
description: 'Die vollständig verwaltete und wartungsfreie Observability-Plattform von Alibaba Cloud ermöglicht eine sofortige Überwachung, Verfolgung und Bewertung von Dify-Anwendungen.',
},
},
answerIcon: {
descriptionInExplore: 'Gibt an, ob das web app Symbol zum Ersetzen 🤖 in Explore verwendet werden soll',
@ -263,6 +266,8 @@ const translation = {
},
accessControl: 'Zugriffskontrolle für Webanwendungen',
noAccessPermission: 'Keine Berechtigung zum Zugriff auf die Webanwendung',
maxActiveRequests: 'Maximale gleichzeitige Anfragen',
maxActiveRequestsPlaceholder: 'Geben Sie 0 für unbegrenzt ein',
}
export default translation

@ -216,6 +216,28 @@ const translation = {
workspaceIcon: 'Arbeitsbereichssymbol',
workspaceName: 'Arbeitsbereichsname',
editWorkspaceInfo: 'Arbeitsbereichsinformationen bearbeiten',
changeEmail: {
codeLabel: 'Bestätigungscode',
sendVerifyCode: 'Überprüfungs-Code senden',
resend: 'Erneut senden',
continue: 'Fortsetzen',
verifyEmail: 'Überprüfen Sie Ihre aktuelle E-Mail',
newEmail: 'Richten Sie eine neue E-Mail-Adresse ein',
codePlaceholder: 'Geben Sie den 6-stelligen Code ein',
resendTip: 'Haben Sie keinen Code erhalten?',
title: 'E-Mail ändern',
content2: 'Ihre aktuelle E-Mail-Adresse lautet <email>{{email}}</email>. Der Bestätigungscode wurde an diese E-Mail-Adresse gesendet.',
verifyNew: 'Bestätigen Sie Ihre neue E-Mail',
changeTo: 'Ändern zu {{email}}',
content1: 'Wenn Sie fortfahren, senden wir einen Bestätigungscode an <email>{{email}}</email> zur erneuten Authentifizierung.',
resendCount: 'Erneut senden in {{count}}s',
content4: 'Wir haben Ihnen gerade einen vorübergehenden Verifizierungscode an <email>{{email}}</email> gesendet.',
emailPlaceholder: 'Geben Sie eine neue E-Mail-Adresse ein',
content3: 'Geben Sie eine neue E-Mail-Adresse ein, und wir senden Ihnen einen Bestätigungscode.',
existingEmail: 'Ein Benutzer mit dieser E-Mail-Adresse existiert bereits.',
emailLabel: 'Neue E-Mail',
authTip: 'Sobald Ihre E-Mail geändert wurde, können Google- oder GitHub-Konten, die mit Ihrer alten E-Mail verknüpft sind, nicht mehr auf dieses Konto zugreifen.',
},
},
members: {
team: 'Team',
@ -257,6 +279,26 @@ const translation = {
datasetOperatorTip: 'Kann die Wissensdatenbank nur verwalten',
builder: 'Bauherr',
builderTip: 'Kann eigene Apps erstellen und bearbeiten',
transferModal: {
verifyEmail: 'Überprüfen Sie Ihre aktuelle E-Mail',
resendTip: 'Haben Sie keinen Code erhalten?',
continue: 'Fortsetzen',
resend: 'Erneut senden',
sendVerifyCode: 'Überprüfungs-Code senden',
title: 'Übertragung des Besitzes des Arbeitsbereichs',
codePlaceholder: 'Geben Sie den 6-stelligen Code ein',
transfer: 'Übertragung des Besitzes des Arbeitsbereichs',
warningTip: 'Du wirst ein Administrationsmitglied, und der neue Eigentümer wird die volle Kontrolle haben.',
codeLabel: 'Bestätigungscode',
transferPlaceholder: 'Wählen Sie ein Arbeitsbereichsmitglied aus…',
verifyContent: 'Ihre aktuelle E-Mail ist <email>{{email}}</email>.',
resendCount: 'Erneut senden in {{count}}s',
transferLabel: 'Übertragen Sie die Eigentümerschaft des Arbeitsbereichs auf',
warning: 'Sie sind dabei, das Eigentum an „{{workspace}}“ zu übertragen. Dies tritt sofort in Kraft und kann nicht rückgängig gemacht werden.',
verifyContent2: 'Wir werden einen temporären Bestätigungscode an diese E-Mail senden, um die erneute Authentifizierung durchzuführen.',
sendTip: 'Wenn Sie fortfahren, senden wir einen Bestätigungscode an <email>{{email}}</email> zur erneuten Authentifizierung.',
},
transferOwnership: 'Eigentum übertragen',
},
integrations: {
connected: 'Verbunden',
@ -448,6 +490,7 @@ const translation = {
addPages: 'Seiten hinzufügen',
preview: 'VORSCHAU',
},
integratedAlert: 'Notion ist über interne Anmeldeinformationen integriert, es ist keine erneute Autorisierung erforderlich.',
},
website: {
inactive: 'Inaktiv',

@ -384,6 +384,7 @@ const translation = {
chunkAdded: '1 Stück hinzugefügt',
expandChunks: 'Blöcke erweitern',
editedAt: 'Bearbeitet am',
dateTimeFormat: 'MM/DD/YYYY h:mm',
addChunk: 'Block hinzufügen',
addAnother: 'Fügen Sie eine weitere hinzu',
regeneratingTitle: 'Regenerieren von untergeordneten Blöcken',

@ -109,6 +109,7 @@ const translation = {
noLoginMethod: 'Authentifizierungsmethode ist nicht für die Webanwendung konfiguriert',
noLoginMethodTip: 'Bitte kontaktieren Sie den Systemadministrator, um eine Authentifizierungsmethode hinzuzufügen.',
disabled: 'Die Webanmeldeauthentifizierung ist deaktiviert. Bitte kontaktieren Sie den Systemadministrator, um sie zu aktivieren. Sie können versuchen, die App direkt zu verwenden.',
login: 'Anmelden',
},
}

@ -63,6 +63,7 @@ const translation = {
toolLabel: 'Werkzeug',
uninstalledContent: 'Dieses Plugin wird aus dem lokalen/GitHub-Repository installiert. Bitte nach der Installation verwenden.',
toolSetting: 'Werkzeugs Einstellungen',
unsupportedMCPTool: 'Die derzeit ausgewählte Agentenstrategie-Plugin-Version unterstützt keine MCP-Tools.',
},
strategyNum: '{{num}} {{Strategie}} IINKLUSIVE',
configureApp: 'App konfigurieren',

@ -57,9 +57,14 @@ const translation = {
api_key: 'API-Key',
apiKeyPlaceholder: 'HTTP-Headername für API-Key',
apiValuePlaceholder: 'API-Key eingeben',
api_key_header: 'Kopfzeile',
queryParamPlaceholder: 'Abfrageparametername für den API-Schlüssel',
api_key_query: 'Abfrageparameter',
},
key: 'Schlüssel',
value: 'Wert',
queryParam: 'Abfrageparameter',
queryParamTooltip: 'Der Name des API-Schlüssel-Abfrageparameters, der übergeben werden soll, z. B. "key" in "https://example.com/test?key=API_KEY".',
},
authHeaderPrefix: {
title: 'Auth-Typ',

@ -115,6 +115,7 @@ const translation = {
addBlock: 'Knoten hinzufügen',
needEndNode: 'Der Endknoten muss hinzugefügt werden.',
needAnswerNode: 'Der Antwortknoten muss hinzugefügt werden.',
tagBound: 'Anzahl der Apps, die dieses Tag verwenden',
},
env: {
envPanelTitle: 'Umgebungsvariablen',
@ -234,6 +235,8 @@ const translation = {
'agent': 'Agenten-Strategie',
'searchBlock': 'Suchknoten',
'blocks': 'Knoten',
'allAdded': 'Alle hinzugefügt',
'addAll': 'Alles hinzufügen',
},
blocks: {
'start': 'Start',
@ -364,7 +367,10 @@ const translation = {
ms: 'Frau',
retries: '{{num}} Wiederholungen',
},
typeSwitch: {},
typeSwitch: {
input: 'Eingabewert',
variable: 'Verwende die Variable',
},
},
start: {
required: 'erforderlich',
@ -551,6 +557,7 @@ const translation = {
advancedDependencies: 'Erweiterte Abhängigkeiten',
advancedDependenciesTip: 'Fügen Sie hier einige vorinstallierte Abhängigkeiten hinzu, die mehr Zeit in Anspruch nehmen oder nicht standardmäßig eingebaut sind',
searchDependencies: 'Abhängigkeiten suchen',
syncFunctionSignature: 'Synchronisiere die Funktionssignatur mit dem Code',
},
templateTransform: {
inputVars: 'Eingabevariablen',
@ -670,6 +677,9 @@ const translation = {
json: 'von einem Tool generiertes JSON',
},
authorize: 'Autorisieren',
insertPlaceholder2: 'Fügen Sie die Variable ein.',
insertPlaceholder1: 'Tippen oder drücken',
settings: 'Einstellungen',
},
questionClassifiers: {
model: 'Modell',
@ -854,6 +864,8 @@ const translation = {
learnMore: 'Weitere Informationen',
configureModel: 'Modell konfigurieren',
linkToPlugin: 'Link zu Plugins',
parameterSchema: 'Parameter-Schema',
clickToViewParameterSchema: 'Klicken Sie hier, um das Parameterschema anzuzeigen.',
},
loop: {
ErrorMethod: {

@ -390,6 +390,7 @@ const translation = {
regenerationSuccessMessage: 'You can close this window.',
edited: 'EDITED',
editedAt: 'Edited at',
dateTimeFormat: 'MM/DD/YYYY h:mm',
expandChunks: 'Expand chunks',
collapseChunks: 'Collapse chunks',
},

@ -172,7 +172,10 @@ const translation = {
description: 'Weave es una plataforma de código abierto para evaluar, probar y monitorear aplicaciones de LLM.',
title: 'Tejer',
},
aliyun: {},
aliyun: {
title: 'Monitor de Nubes',
description: 'La plataforma de observabilidad totalmente gestionada y sin mantenimiento proporcionada por Alibaba Cloud, permite la monitorización, trazado y evaluación de aplicaciones Dify de manera inmediata.',
},
},
answerIcon: {
title: 'Usar el icono de la aplicación web para reemplazar 🤖',
@ -256,6 +259,8 @@ const translation = {
},
accessControl: 'Control de Acceso a la Aplicación Web',
noAccessPermission: 'No se permite el acceso a la aplicación web',
maxActiveRequestsPlaceholder: 'Introduce 0 para ilimitado',
maxActiveRequests: 'Máximas solicitudes concurrentes',
}
export default translation

@ -220,6 +220,28 @@ const translation = {
workspaceIcon: 'Icono de espacio de trabajo',
editWorkspaceInfo: 'Editar información del espacio de trabajo',
workspaceName: 'Nombre del espacio de trabajo',
changeEmail: {
continue: 'Continuar',
content3: 'Introduce un nuevo correo electrónico y te enviaremos un código de verificación.',
emailPlaceholder: 'Introduce un nuevo correo electrónico',
emailLabel: 'Nuevo correo electrónico',
sendVerifyCode: 'Enviar código de verificación',
changeTo: 'Cambia a {{email}}',
resendTip: '¿No recibiste un código?',
codePlaceholder: 'Pegue el código de 6 dígitos',
content4: 'Acabamos de enviarte un código de verificación temporal a <email>{{email}}</email>.',
newEmail: 'Configura una nueva dirección de correo electrónico',
resend: 'Reenviar',
resendCount: 'Reenviar en {{count}}s',
content2: 'Tu correo electrónico actual es <email>{{email}}</email>. Se ha enviado un código de verificación a esta dirección de correo electrónico.',
content1: 'Si continúas, enviaremos un código de verificación a <email>{{email}}</email> para la reautenticación.',
title: 'Cambiar Correo Electrónico',
verifyEmail: 'Verifica tu correo electrónico actual',
existingEmail: 'Ya existe un usuario con este correo electrónico.',
verifyNew: 'Verifica tu nuevo correo electrónico',
codeLabel: 'Código de verificación',
authTip: 'Una vez que tu correo electrónico sea cambiado, las cuentas de Google o GitHub vinculadas a tu antiguo correo electrónico ya no podrán iniciar sesión en esta cuenta.',
},
},
members: {
team: 'Equipo',
@ -261,6 +283,26 @@ const translation = {
disInvite: 'Cancelar la invitación',
deleteMember: 'Eliminar miembro',
you: '(Tú)',
transferModal: {
continue: 'Continuar',
codeLabel: 'Código de verificación',
verifyEmail: 'Verifica tu correo electrónico actual',
transfer: 'Transferir la propiedad del espacio de trabajo',
transferPlaceholder: 'Selecciona un miembro del espacio de trabajo...',
verifyContent: 'Tu correo electrónico actual es <email>{{email}}</email>.',
resendCount: 'Reenviar en {{count}}s',
resendTip: '¿No recibiste un código?',
sendVerifyCode: 'Enviar código de verificación',
title: 'Transferir la propiedad del espacio de trabajo',
verifyContent2: 'Enviaremos un código de verificación temporal a este correo electrónico para la re-autenticación.',
transferLabel: 'Transferir la propiedad del espacio de trabajo a',
resend: 'Reenviar',
sendTip: 'Si continúas, enviaremos un código de verificación a <email>{{email}}</email> para la reautenticación.',
warningTip: 'Te convertirás en un miembro administrador, y el nuevo propietario tendrá el control total.',
codePlaceholder: 'Pegue el código de 6 dígitos',
warning: 'Estás a punto de transferir la propiedad de “{{workspace}}”. Esto tendrá efecto inmediato y no se puede deshacer.',
},
transferOwnership: 'Transferir propiedad',
},
integrations: {
connected: 'Conectado',
@ -453,6 +495,7 @@ const translation = {
addPages: 'Agregar páginas',
preview: 'VISTA PREVIA',
},
integratedAlert: 'Notion está integrado a través de credenciales internas, no es necesario volver a autorizar.',
},
website: {
title: 'Sitio web',

@ -377,6 +377,7 @@ const translation = {
editChildChunk: 'Editar fragmento secundario',
regeneratingTitle: 'Regeneración de fragmentos secundarios',
editedAt: 'Editado en',
dateTimeFormat: 'MM/DD/YYYY h:mm',
searchResults_zero: 'RESULTADO',
clearFilter: 'Borrar filtro',
newChildChunk: 'Nuevo fragmento secundario',

@ -109,6 +109,7 @@ const translation = {
disabled: 'La autenticación de la aplicación web está desactivada. Por favor, contacte al administrador del sistema para habilitarla. Puede intentar usar la aplicación directamente.',
noLoginMethodTip: 'Por favor, contacta al administrador del sistema para agregar un método de autenticación.',
noLoginMethod: 'Método de autenticación no configurado para la aplicación web',
login: 'Iniciar sesión',
},
}

@ -63,6 +63,7 @@ const translation = {
params: 'CONFIGURACIÓN DE RAZONAMIENTO',
uninstalledLink: 'Administrar en Plugins',
toolSetting: 'Configuraciones de la herramienta',
unsupportedMCPTool: 'La versión actual del plugin de estrategia del agente seleccionado no es compatible con las herramientas MCP.',
},
endpointDeleteContent: '¿Te gustaría eliminar {{nombre}}?',
endpointDisableTip: 'Deshabilitar punto de conexión',

@ -85,9 +85,14 @@ const translation = {
api_key: 'Clave API',
apiKeyPlaceholder: 'Nombre del encabezado HTTP para la Clave API',
apiValuePlaceholder: 'Ingresa la Clave API',
api_key_header: 'Encabezado',
api_key_query: 'Parámetro de consulta',
queryParamPlaceholder: 'Nombre del parámetro de consulta para la clave de API',
},
key: 'Clave',
value: 'Valor',
queryParam: 'Parámetro de consulta',
queryParamTooltip: 'El nombre del parámetro de consulta de clave de API que se debe pasar, por ejemplo, "key" en "https://example.com/test?key=API_KEY".',
},
authHeaderPrefix: {
title: 'Tipo de Autenticación',

@ -115,6 +115,7 @@ const translation = {
needAnswerNode: 'Se debe agregar el nodo de respuesta',
needEndNode: 'Se debe agregar el nodo Final',
addBlock: 'Agregar nodo',
tagBound: 'Número de aplicaciones que utilizan esta etiqueta',
},
env: {
envPanelTitle: 'Variables de Entorno',
@ -234,6 +235,8 @@ const translation = {
'plugin': 'Plugin',
'searchBlock': 'Buscar nodo',
'blocks': 'Nodos',
'addAll': 'Agregar todo',
'allAdded': 'Todo añadido',
},
blocks: {
'start': 'Inicio',
@ -364,7 +367,10 @@ const translation = {
retries: '{{num}} Reintentos',
retry: 'Reintentar',
},
typeSwitch: {},
typeSwitch: {
input: 'Valor de entrada',
variable: 'Usa la variable',
},
},
start: {
required: 'requerido',
@ -549,6 +555,7 @@ const translation = {
advancedDependencies: 'Dependencias avanzadas',
advancedDependenciesTip: 'Agrega algunas dependencias precargadas que consumen más tiempo o no son incorporadas por defecto aquí',
searchDependencies: 'Buscar dependencias',
syncFunctionSignature: 'Sincronizar la firma de la función con el código',
},
templateTransform: {
inputVars: 'Variables de entrada',
@ -668,6 +675,9 @@ const translation = {
json: 'JSON generado por la herramienta',
},
authorize: 'autorizar',
insertPlaceholder2: 'insertar variable',
settings: 'Ajustes',
insertPlaceholder1: 'Escribe o presiona',
},
questionClassifiers: {
model: 'modelo',
@ -855,6 +865,8 @@ const translation = {
strategyNotFoundDescAndSwitchVersion: 'La versión del plugin instalado no proporciona esta estrategia. Haga clic para cambiar de versión.',
toolNotAuthorizedTooltip: '{{herramienta}} No autorizado',
modelNotSelected: 'Modelo no seleccionado',
clickToViewParameterSchema: 'Haga clic para ver el esquema de parámetros',
parameterSchema: 'Esquema de Parámetros',
},
loop: {
ErrorMethod: {

@ -176,7 +176,10 @@ const translation = {
title: 'بافندگی',
description: 'ویو یک پلتفرم متن باز برای ارزیابی، آزمایش و نظارت بر برنامه‌های LLM است.',
},
aliyun: {},
aliyun: {
title: 'نظارت بر ابر',
description: 'پلتفرم مشاهده‌پذیری کاملاً مدیریت‌شده و بدون نیاز به نگهداری که توسط Alibaba Cloud ارائه شده، امکان نظارت، ردیابی و ارزیابی برنامه‌های Dify را به‌صورت آماده و با تنظیمات اولیه فراهم می‌کند.',
},
},
answerIcon: {
descriptionInExplore: 'آیا از نماد web app برای جایگزینی 🤖 در Explore استفاده کنیم یا خیر',
@ -256,6 +259,8 @@ const translation = {
},
accessControl: 'کنترل دسترسی به وب اپلیکیشن',
noAccessPermission: 'دسترسی به برنامه وب مجاز نیست',
maxActiveRequests: 'بیشترین درخواست‌های همزمان',
maxActiveRequestsPlaceholder: 'برای نامحدود، 0 را وارد کنید',
}
export default translation

@ -220,6 +220,28 @@ const translation = {
editWorkspaceInfo: 'ویرایش اطلاعات فضای کار',
workspaceName: 'نام فضای کاری',
workspaceIcon: 'آیکون محیط کار',
changeEmail: {
changeTo: 'تغییر به {{email}}',
resendTip: 'کدی دریافت نکردید؟',
codeLabel: 'کد تأیید',
resend: 'دوباره ارسال کنید',
emailLabel: 'ایمیل جدید',
title: 'تغییر ایمیل',
verifyNew: 'ایمیل جدید خود را تأیید کنید',
sendVerifyCode: 'کد تأیید را ارسال کنید',
newEmail: 'یک آدرس ایمیل جدید راه‌اندازی کنید',
emailPlaceholder: 'یک ایمیل جدید وارد کنید',
codePlaceholder: 'کد ۶ رقمی را وارد کنید',
existingEmail: 'کاربری با این ایمیل از قبل وجود دارد.',
content2: 'ایمیل فعلی شما <email>{{email}}</email> است. کد تأیید به این آدرس ایمیل ارسال شده است.',
resendCount: 'دوباره ارسال کنید در {{count}} ثانیه',
continue: 'ادامه دهید',
verifyEmail: 'ایمیل فعلی خود را تأیید کنید',
content4: 'ما یک کد تأیید موقت برای شما به <email>{{email}}</email> ارسال کردیم.',
content1: 'اگر ادامه دهید، ما یک کد تأیید به <email>{{email}}</email> برای بازگشایی مجدد ارسال خواهیم کرد.',
content3: 'یک ایمیل جدید وارد کنید و ما یک کد تأیید برای شما ارسال خواهیم کرد.',
authTip: 'زمانی که ایمیل شما تغییر کند، حساب‌های گوگل یا گیت‌هاب مرتبط با ایمیل قدیمی شما دیگر قادر به ورود به این حساب نخواهند بود.',
},
},
members: {
team: 'تیم',
@ -261,6 +283,26 @@ const translation = {
disInvite: 'لغو دعوت',
deleteMember: 'حذف عضو',
you: '(شما)',
transferModal: {
resendTip: 'کدی دریافت نکردید؟',
resend: 'دوباره ارسال کنید',
continue: 'ادامه دهید',
codeLabel: 'کد تأیید',
sendVerifyCode: 'کد تأیید را ارسال کنید',
title: 'انتقال مالکیت فضای کاری',
verifyContent: 'ایمیل فعلی شما <email>{{email}}</email> است.',
transfer: 'انتقال مالکیت فضای کاری',
warning: 'شما در حال انتقال مالکیت "{{workspace}}" هستید. این بلافاصله اجرایی می‌شود و قابل بازگشت نیست.',
resendCount: 'دوباره ارسال کنید در {{count}} ثانیه',
warningTip: 'شما به یک عضو مدیر تبدیل خواهید شد و مالک جدید کنترل کامل خواهد داشت.',
transferLabel: 'مالکیت فضای کار را به منتقل کنید',
verifyEmail: 'ایمیل فعلی خود را تأیید کنید',
sendTip: 'اگر ادامه دهید، ما یک کد تأیید به <email>{{email}}</email> برای بازگشایی مجدد ارسال خواهیم کرد.',
codePlaceholder: 'کد ۶ رقمی را وارد کنید',
transferPlaceholder: 'یک عضو از فضای کاری را انتخاب کنید…',
verifyContent2: 'ما یک کد تأیید موقت به این ایمیل برای تأیید مجدد ارسال خواهیم کرد.',
},
transferOwnership: 'انتقال مالکیت',
},
integrations: {
connected: 'متصل شده',
@ -453,6 +495,7 @@ const translation = {
addPages: 'افزودن صفحات',
preview: 'پیش‌نمایش',
},
integratedAlert: 'نوشته به طور داخلی از طریق اعتبارنامه یکپارچه شده است، نیازی به دوباره مجاز کردن نیست.',
},
website: {
title: 'وب‌سایت',

@ -356,6 +356,7 @@ const translation = {
chunks_other: 'تکه',
characters_one: 'شخصیت',
editedAt: 'ویرایش شده در',
dateTimeFormat: 'MM/DD/YYYY h:mm',
parentChunks_other: 'تکه های والدین',
editChunk: 'ویرایش تکه',
collapseChunks: 'جمع کردن تکه ها',

@ -109,6 +109,7 @@ const translation = {
disabled: 'احراز هویت وب اپ غیرفعال است. لطفاً با مدیر سیستم تماس بگیرید تا آن را فعال کند. می‌توانید سعی کنید مستقیماً از اپلیکیشن استفاده کنید.',
noLoginMethodTip: 'لطفاً با مدیر سیستم تماس بگیرید تا یک روش احراز هویت اضافه کند.',
noLoginMethod: 'روش احراز هویت برای برنامه وب پیکربندی نشده است',
login: 'ورود',
},
}

@ -63,6 +63,7 @@ const translation = {
unsupportedTitle: 'اکشن پشتیبانی نشده',
unsupportedContent2: 'برای تغییر نسخه کلیک کنید.',
toolSetting: 'تنظیمات ابزار',
unsupportedMCPTool: 'نسخه فعلی پلاگین استراتژی عامل انتخاب‌شده از ابزارهای MCP پشتیبانی نمی‌کند.',
},
endpointDeleteTip: 'حذف نقطه پایانی',
disabled: 'غیر فعال',

@ -85,9 +85,14 @@ const translation = {
api_key: 'کلید API',
apiKeyPlaceholder: 'نام هدر HTTP برای کلید API',
apiValuePlaceholder: 'کلید API را وارد کنید',
api_key_header: 'عنوان',
api_key_query: 'پارامتر جستجو',
queryParamPlaceholder: 'نام پارامتر جستجو برای کلید API',
},
key: 'کلید',
value: 'مقدار',
queryParam: 'پارامتر جستجو',
queryParamTooltip: 'نام پارامتر پرس و جو کلید API که باید ارسال شود، به عنوان مثال "key" در "https://example.com/test?key=API_KEY".',
},
authHeaderPrefix: {
title: 'نوع مجوز',

@ -115,6 +115,7 @@ const translation = {
needEndNode: 'باید گره پایان اضافه شود',
needAnswerNode: 'باید گره پاسخ اضافه شود',
addBlock: 'نود اضافه کنید',
tagBound: 'تعداد برنامه‌هایی که از این برچسب استفاده می‌کنند',
},
env: {
envPanelTitle: 'متغیرهای محیطی',
@ -234,6 +235,8 @@ const translation = {
'agent': 'استراتژی نمایندگی',
'blocks': 'گره‌ها',
'searchBlock': 'گره جستجو',
'addAll': 'همه را اضافه کنید',
'allAdded': 'همه اضافه شده است',
},
blocks: {
'start': 'شروع',
@ -364,7 +367,10 @@ const translation = {
retrySuccessful: 'امتحان مجدد با موفقیت انجام دهید',
retryFailedTimes: '{{بار}} تلاش های مجدد ناموفق بود',
},
typeSwitch: {},
typeSwitch: {
input: 'مقدار ورودی',
variable: 'از متغیر استفاده کن',
},
},
start: {
required: 'الزامی',
@ -551,6 +557,7 @@ const translation = {
advancedDependencies: 'وابستگی‌های پیشرفته',
advancedDependenciesTip: 'برخی وابستگی‌های پیش‌بارگذاری شده که زمان بیشتری برای مصرف نیاز دارند یا به طور پیش‌فرض در اینجا موجود نیستند، اضافه کنید',
searchDependencies: 'جستجوی وابستگی‌ها',
syncFunctionSignature: 'امضای تابع همگام‌سازی را به کد متصل کنید',
},
templateTransform: {
inputVars: 'متغیرهای ورودی',
@ -670,6 +677,9 @@ const translation = {
json: 'json تولید شده توسط ابزار',
},
authorize: 'مجوز دادن',
settings: 'تنظیمات',
insertPlaceholder2: 'متغیر را وارد کنید',
insertPlaceholder1: 'نوع کنید یا فشار دهید',
},
questionClassifiers: {
model: 'مدل',
@ -854,6 +864,8 @@ const translation = {
strategyNotFoundDesc: 'نسخه افزونه نصب شده این استراتژی را ارائه نمی دهد.',
strategyNotFoundDescAndSwitchVersion: 'نسخه افزونه نصب شده این استراتژی را ارائه نمی دهد. برای تغییر نسخه کلیک کنید.',
model: 'مدل',
parameterSchema: 'طرح پارامتر',
clickToViewParameterSchema: 'برای مشاهده طرح پارامتر کلیک کنید',
},
loop: {
ErrorMethod: {

@ -172,7 +172,10 @@ const translation = {
title: 'Tisser',
description: 'Weave est une plateforme open-source pour évaluer, tester et surveiller les applications LLM.',
},
aliyun: {},
aliyun: {
title: 'Surveillance Cloud',
description: 'La plateforme d\'observabilité entièrement gérée et sans maintenance fournie par Alibaba Cloud permet une surveillance, un traçage et une évaluation prêts à l\'emploi des applications Dify.',
},
},
answerIcon: {
description: 'Sil faut utiliser licône web app pour remplacer 🤖 dans lapplication partagée',
@ -256,6 +259,8 @@ const translation = {
},
accessControl: 'Contrôle d\'accès à l\'application Web',
noAccessPermission: 'Pas de permission d\'accéder à l\'application web',
maxActiveRequestsPlaceholder: 'Entrez 0 pour illimité',
maxActiveRequests: 'Nombre maximal de requêtes simultanées',
}
export default translation

@ -216,6 +216,28 @@ const translation = {
workspaceName: 'Nom de l\'espace de travail',
workspaceIcon: 'Icône de l\'espace de travail',
editWorkspaceInfo: 'Modifier les informations de l\'espace de travail',
changeEmail: {
codePlaceholder: 'Collez le code à 6 chiffres',
emailLabel: 'Nouveau courriel',
newEmail: 'Créez une nouvelle adresse email',
verifyNew: 'Vérifiez votre nouvel e-mail',
existingEmail: 'Un utilisateur avec cet email existe déjà.',
title: 'Changer l\'email',
resendTip: 'Vous n\'avez pas reçu de code ?',
emailPlaceholder: 'Entrez un nouvel e-mail',
sendVerifyCode: 'Envoyer le code de vérification',
continue: 'Continuer',
changeTo: 'Changer pour {{email}}',
authTip: 'Une fois que votre email est changé, les comptes Google ou GitHub liés à votre ancien email ne pourront plus se connecter à ce compte.',
content3: 'Entrez un nouvel e-mail et nous vous enverrons un code de vérification.',
resendCount: 'Renvoyer dans {{count}}s',
content4: 'Nous vous avons juste envoyé un code de vérification temporaire à <email>{{email}}</email>.',
resend: 'Renvoyer',
verifyEmail: 'Vérifiez votre adresse e-mail actuelle',
content2: 'Votre adresse e-mail actuelle est <email>{{email}}</email>. Un code de vérification a été envoyé à cette adresse e-mail.',
codeLabel: 'Code de vérification',
content1: 'Si vous continuez, nous enverrons un code de vérification à <email>{{email}}</email> pour une nouvelle authentification.',
},
},
members: {
team: 'Équipe',
@ -257,6 +279,26 @@ const translation = {
datasetOperator: 'Administrateur des connaissances',
setBuilder: 'Définir en tant que constructeur',
builderTip: 'Peut créer et modifier ses propres applications',
transferModal: {
resend: 'Renvoyer',
continue: 'Continuer',
verifyEmail: 'Vérifiez votre adresse e-mail actuelle',
resendCount: 'Renvoyer dans {{count}}s',
verifyContent2: 'Nous enverrons un code de vérification temporaire à cet email pour la ré-authentification.',
codePlaceholder: 'Collez le code à 6 chiffres',
transfer: 'Transférer la propriété de l\'espace de travail',
sendVerifyCode: 'Envoyer le code de vérification',
title: 'Transférer la propriété de l\'espace de travail',
codeLabel: 'Code de vérification',
transferLabel: 'Transférer la propriété de l\'espace de travail à',
verifyContent: 'Votre adresse e-mail actuelle est <email>{{email}}</email>.',
transferPlaceholder: 'Sélectionnez un membre de l\'espace de travail…',
warningTip: 'Vous deviendrez membre administrateur, et le nouveau propriétaire aura le contrôle total.',
resendTip: 'Vous n\'avez pas reçu de code ?',
sendTip: 'Si vous continuez, nous enverrons un code de vérification à <email>{{email}}</email> pour la ré-authentification.',
warning: 'Vous êtes sur le point de transférer la propriété de « {{workspace}} ». Cela prend effet immédiatement et ne peut pas être annulé.',
},
transferOwnership: 'Transférer la propriété',
},
integrations: {
connected: 'Connecté',
@ -448,6 +490,7 @@ const translation = {
addPages: 'Ajouter des pages',
preview: 'APERÇU',
},
integratedAlert: 'Notion est intégré via des identifiants internes, aucune autorisation supplémentaire n\'est nécessaire.',
},
website: {
configuredCrawlers: 'Robots dexploration configurés',

@ -374,6 +374,7 @@ const translation = {
expandChunks: 'Développer des blocs',
characters_other: 'caractères',
editedAt: 'Édité le',
dateTimeFormat: 'DD/MM/YYYY HH:mm',
searchResults_other: 'RÉSULTATS',
regenerationSuccessMessage: 'Vous pouvez fermer cette fenêtre.',
parentChunks_one: 'MORCEAU PARENT',

@ -109,6 +109,7 @@ const translation = {
noLoginMethodTip: 'Veuillez contacter l\'administrateur système pour ajouter une méthode d\'authentification.',
noLoginMethod: 'Méthode d\'authentification non configurée pour l\'application web',
disabled: 'L\'authentification de l\'application web est désactivée. Veuillez contacter l\'administrateur du système pour l\'activer. Vous pouvez essayer d\'utiliser l\'application directement.',
login: 'Connexion',
},
}

@ -63,6 +63,7 @@ const translation = {
paramsTip2: 'Lorsque « Auto » est désactivé, la valeur par défaut est utilisée.',
paramsTip1: 'Contrôle les paramètres dinférence LLM.',
toolSetting: 'Paramètres de l\'outil',
unsupportedMCPTool: 'La version actuelle du plugin de stratégie d\'agent sélectionné ne prend pas en charge les outils MCP.',
},
modelNum: '{{num}} MODÈLES INCLUS',
endpointDeleteTip: 'Supprimer le point de terminaison',

@ -57,9 +57,14 @@ const translation = {
api_key: 'Clé API',
apiKeyPlaceholder: 'Nom de l\'en-tête HTTP pour la clé API',
apiValuePlaceholder: 'Entrez la clé API',
api_key_query: 'Paramètre de requête',
queryParamPlaceholder: 'Nom du paramètre de requête pour la clé API',
api_key_header: 'En-tête',
},
key: 'Clé',
value: 'Valeur',
queryParam: 'Paramètre de requête',
queryParamTooltip: 'Le nom du paramètre de requête de la clé API à passer, par exemple "key" dans "https://example.com/test?key=API_KEY".',
},
authHeaderPrefix: {
title: 'Type d\'Authentification',

@ -115,6 +115,7 @@ const translation = {
needEndNode: 'Le nœud de fin doit être ajouté',
needAnswerNode: 'Le nœud de réponse doit être ajouté.',
addBlock: 'Ajouter un nœud',
tagBound: 'Nombre d\'applications utilisant cette étiquette',
},
env: {
envPanelTitle: 'Variables d\'Environnement',
@ -234,6 +235,8 @@ const translation = {
'agent': 'Stratégie dagent',
'blocks': 'Nœuds',
'searchBlock': 'Nœud de recherche',
'addAll': 'Ajouter tout',
'allAdded': 'Tout ajouté',
},
blocks: {
'start': 'Début',
@ -364,7 +367,10 @@ const translation = {
ms: 'ms',
retries: '{{num}} Tentatives',
},
typeSwitch: {},
typeSwitch: {
input: 'Valeur d\'entrée',
variable: 'Utilisez une variable',
},
},
start: {
required: 'requis',
@ -551,6 +557,7 @@ const translation = {
advancedDependencies: 'Dépendances avancées',
advancedDependenciesTip: 'Ajoutez quelques dépendances préchargées qui prennent plus de temps à consommer ou ne sont pas par défaut ici',
searchDependencies: 'Rechercher des dépendances',
syncFunctionSignature: 'Synchroniser la signature de fonction avec le code',
},
templateTransform: {
inputVars: 'Variables de saisie',
@ -670,6 +677,9 @@ const translation = {
json: 'JSON généré par un outil',
},
authorize: 'Autoriser',
insertPlaceholder2: 'insérer une variable',
settings: 'Paramètres',
insertPlaceholder1: 'Tapez ou appuyez',
},
questionClassifiers: {
model: 'modèle',
@ -854,6 +864,8 @@ const translation = {
pluginNotInstalledDesc: 'Ce plugin est installé à partir de GitHub. Veuillez aller dans Plugins pour réinstaller',
maxIterations: 'Nombre maximal ditérations',
toolNotAuthorizedTooltip: '{{outil}} Non autorisé',
clickToViewParameterSchema: 'Cliquez pour voir le schéma des paramètres',
parameterSchema: 'Schéma de Paramètres',
},
loop: {
ErrorMethod: {

@ -172,7 +172,10 @@ const translation = {
title: 'बुनना',
description: 'वीव एक ओपन-सोर्स प्लेटफ़ॉर्म है जो LLM अनुप्रयोगों का मूल्यांकन, परीक्षण और निगरानी करने के लिए है।',
},
aliyun: {},
aliyun: {
title: 'क्लाउड मॉनिटर',
description: 'अलीबाबा क्लाउड द्वारा प्रदान की गई पूरी तरह से प्रबंधित और रखरखाव-मुक्त अवलोकन प्लेटफ़ॉर्म, Dify अनुप्रयोगों की स्वचालित निगरानी, ट्रेसिंग और मूल्यांकन का सक्षम बनाता है।',
},
},
answerIcon: {
title: 'बदलने 🤖 के लिए web app चिह्न का उपयोग करें',
@ -256,6 +259,8 @@ const translation = {
},
accessControl: 'वेब एप्लिकेशन पहुँच नियंत्रण',
noAccessPermission: 'वेब एप्लिकेशन तक पहुँचने की अनुमति नहीं है',
maxActiveRequests: 'अधिकतम समवर्ती अनुरोध',
maxActiveRequestsPlaceholder: 'असीमित के लिए 0 दर्ज करें',
}
export default translation

@ -226,6 +226,28 @@ const translation = {
workspaceIcon: 'कार्यस्थल आइकन',
editWorkspaceInfo: 'कार्यक्षेत्र की जानकारी संपादित करें',
workspaceName: 'कार्यस्थल का नाम',
changeEmail: {
title: 'ईमेल बदलें',
codePlaceholder: '6 अंकों का कोड पेस्ट करें',
continue: 'जारी रखें',
emailPlaceholder: 'नई ईमेल दर्ज करें',
changeTo: '{{email}} में परिवर्तन करें',
resendCount: '{{count}} सेकंड में दोबारा भेजें',
resend: 'फिर से भेजें',
newEmail: 'एक नया ईमेल पता सेट करें',
codeLabel: 'पुष्टि कोड',
verifyNew: 'अपने नए ईमेल की पुष्टि करें',
resendTip: 'कोई कोड नहीं मिला?',
verifyEmail: 'अपने वर्तमान ईमेल की पुष्टि करें',
existingEmail: 'इस ईमेल के साथ एक उपयोगकर्ता पहले से मौजूद है।',
sendVerifyCode: 'सत्यापन कोड भेजें',
content3: 'एक नया ईमेल दर्ज करें और हम आपको एक सत्यापन कोड भेजेंगे।',
emailLabel: 'नया ईमेल',
content4: 'हमने आपको <email>{{email}}</email> पर एक अस्थायी सत्यापन कोड भेजा है।',
content2: 'आपका वर्तमान ईमेल है <email>{{email}}</email>. सत्यापन कोड इस ईमेल पते पर भेजा गया है।',
authTip: 'एक बार जब आपका ईमेल बदल दिया जाता है, तो आपके पुराने ईमेल से जुड़े Google या GitHub खाते इस खाते में लॉग इन नहीं कर सकेंगे।',
content1: 'अगर आप जारी रखते हैं, तो हम सत्यापन के लिए <email>{{email}}</email> पर एक सत्यापन कोड भेजेंगे।',
},
},
members: {
team: 'टीम',
@ -270,6 +292,26 @@ const translation = {
you: '(आप)',
datasetOperator: 'ज्ञान व्यवस्थापक',
datasetOperatorTip: 'केवल नॉलेज बेस प्रबंधित कर सकते हैं',
transferModal: {
codePlaceholder: '6 अंकों का कोड पेस्ट करें',
transferPlaceholder: 'एक कार्यक्षेत्र सदस्य चुनें…',
resendTip: 'कोड प्राप्त नहीं हुआ?',
verifyContent: 'आपका वर्तमान ईमेल <email>{{email}}</email> है।',
sendVerifyCode: 'सत्यापन कोड भेजें',
verifyEmail: 'अपने वर्तमान ईमेल की पुष्टि करें',
codeLabel: 'पुष्टिकरण कोड',
warning: 'आप "{{workspace}}" की स्वामित्व स्थानांतरित करने वाले हैं। यह तुरंत प्रभावी होता है और इसे पूर्ववत नहीं किया जा सकता।',
title: 'वर्कस्पेस का मालिकाना हक स्थानांतरित करें',
resend: 'फिर से भेजें',
resendCount: '{{count}} सेकंड में दोबारा भेजें',
transferLabel: 'कार्यक्षेत्र की स्वामित्व स्थानांतरित करें',
sendTip: 'अगर आप जारी रखते हैं, तो हम सत्यापन के लिए <email>{{email}}</email> पर एक कोड भेजेंगे।',
continue: 'जारी रखें',
transfer: 'कार्यस्थान स्वामित्व स्थानांतरित करें',
verifyContent2: 'हम इस ईमेल पर पुनः प्रमाणन के लिए एक अस्थायी सत्यापन कोड भेजेंगे।',
warningTip: 'आप एक प्रशासनिक सदस्य बन जाएंगे, और नए मालिक के पास पूरी नियंत्रण होगा।',
},
transferOwnership: 'स्वामित्व हस्तांतरित करें',
},
integrations: {
connected: 'कनेक्टेड',
@ -469,6 +511,7 @@ const translation = {
addPages: 'पृष्ठ जोड़ें',
preview: 'पूर्वावलोकन',
},
integratedAlert: 'नोट्शन आंतरिक प्रमाण पत्र के माध्यम से एकीकृत है, फिर से प्रमाणित करने की आवश्यकता नहीं है।',
},
website: {
title: 'वेबसाइट',

@ -373,6 +373,7 @@ const translation = {
addChunk: 'चंक जोड़ें',
editChildChunk: 'संपादित करें बाल चंक',
editedAt: 'पर संपादित',
dateTimeFormat: 'MM/DD/YYYY h:mm',
childChunk: 'चाइल्ड-चंक',
parentChunk: 'माता-पिता-चंक',
empty: 'कोई हिस्सा नहीं मिला',

@ -114,6 +114,7 @@ const translation = {
noLoginMethodTip: 'कृपया एक प्रमाणीकरण विधि जोड़ने के लिए सिस्टम प्रशासक से संपर्क करें।',
noLoginMethod: 'वेब ऐप के लिए प्रमाणीकरण विधि कॉन्फ़िगर नहीं की गई है',
disabled: 'वेब ऐप प्रमाणीकरण अक्षम है। कृपया इसे सक्षम करने के लिए सिस्टम प्रशासक से संपर्क करें। आप सीधे ऐप का उपयोग करने की कोशिश कर सकते हैं।',
login: 'लॉगइन',
},
}

@ -63,6 +63,7 @@ const translation = {
descriptionPlaceholder: 'उपकरण के उद्देश्य का संक्षिप्त विवरण, जैसे, किसी विशेष स्थान के लिए तापमान प्राप्त करना।',
paramsTip1: 'एलएलएम अनुमान पैरामीटर को नियंत्रित करता है।',
toolSetting: 'टूल सेटिंग्स',
unsupportedMCPTool: 'वर्तमान में चयनित एजेंट रणनीति प्लगइन संस्करण MCP टूल का समर्थन नहीं करता है।',
},
switchVersion: 'स्विच संस्करण',
endpointModalDesc: 'एक बार कॉन्फ़िगर होने के बाद, प्लगइन द्वारा API एंडपॉइंट्स के माध्यम से प्रदान की गई सुविधाओं का उपयोग किया जा सकता है।',

@ -89,9 +89,14 @@ const translation = {
api_key: 'API कुंजी',
apiKeyPlaceholder: 'API कुंजी के लिए HTTP हैडर नाम',
apiValuePlaceholder: 'API कुंजी दर्ज करें',
api_key_query: 'अनुक्रमणिका पैरामीटर',
api_key_header: 'हेडर',
queryParamPlaceholder: 'एपीआई कुंजी के लिए क्वेरी पैरामीटर नाम',
},
key: 'कुंजी',
value: 'मूल्य',
queryParam: 'अनुक्रमणिका पैरामीटर',
queryParamTooltip: 'API कुंजी प्रश्न पैरा मीटर का नाम, जो पास करने के लिए है, जैसे कि "key" "https://example.com/test?key=API_KEY" में।',
},
authHeaderPrefix: {
title: 'अधिकृति प्रकार',

@ -118,6 +118,7 @@ const translation = {
needAnswerNode: 'उत्तर नोड जोड़ा जाना चाहिए',
addBlock: 'नोड जोड़ें',
needEndNode: 'अंत नोड जोड़ा जाना चाहिए',
tagBound: 'इस टैग का उपयोग करने वाले ऐप्स की संख्या',
},
env: {
envPanelTitle: 'पर्यावरण चर',
@ -237,6 +238,8 @@ const translation = {
'agent': 'एजेंट रणनीति',
'searchBlock': 'खोज नोड',
'blocks': 'नोड्स',
'addAll': 'सभी जोड़ें',
'allAdded': 'सभी जोड़े गए',
},
blocks: {
'start': 'प्रारंभ',
@ -376,7 +379,10 @@ const translation = {
retry: 'पुनर्प्रयास',
retryOnFailure: 'विफलता पर पुनः प्रयास करें',
},
typeSwitch: {},
typeSwitch: {
input: 'इनपुट मान',
variable: 'चर का प्रयोग करें',
},
},
start: {
required: 'आवश्यक',
@ -565,6 +571,7 @@ const translation = {
advancedDependenciesTip:
'कुछ प्रीलोडेड निर्भरताएँ जोड़ें जिनका उपयोग करने में अधिक समय लगता है या जो डिफ़ॉल्ट निर्मित में नहीं हैं',
searchDependencies: 'निर्भरताएँ खोजें',
syncFunctionSignature: 'कोड के साथ फ़ंक्शन हस्ताक्षर को सिंक करें',
},
templateTransform: {
inputVars: 'इनपुट वेरिएबल्स',
@ -686,6 +693,9 @@ const translation = {
json: 'उपकरण द्वारा उत्पन्न JSON',
},
authorize: 'अधिकृत करें',
insertPlaceholder1: 'टाइप करें या दबाएँ',
settings: 'सेटिंग्स',
insertPlaceholder2: 'वेरिएबल डालें',
},
questionClassifiers: {
model: 'मॉडल',
@ -874,6 +884,8 @@ const translation = {
maxIterations: 'अधिकतम पुनरावृत्तियाँ',
strategyNotSet: 'एजेंटिक रणनीति सेट नहीं की गई',
strategyNotFoundDescAndSwitchVersion: 'स्थापित प्लगइन संस्करण इस रणनीति को प्रदान नहीं करता है। संस्करण बदलने के लिए क्लिक करें।',
parameterSchema: 'पैरामीटर स्कीमा',
clickToViewParameterSchema: 'पैरामीटर स्कीमा देखने के लिए क्लिक करें',
},
loop: {
ErrorMethod: {

@ -184,7 +184,10 @@ const translation = {
title: 'Intrecciare',
description: 'Weave è una piattaforma open-source per valutare, testare e monitorare le applicazioni LLM.',
},
aliyun: {},
aliyun: {
title: 'Monitoraggio Cloud',
description: 'La piattaforma di osservabilità completamente gestita e senza manutenzione fornita da Alibaba Cloud consente il monitoraggio, il tracciamento e la valutazione delle applicazioni Dify fin da subito.',
},
},
answerIcon: {
description: 'Se utilizzare l\'icona web app per la sostituzione 🤖 nell\'applicazione condivisa',
@ -267,6 +270,8 @@ const translation = {
},
accessControl: 'Controllo di accesso all\'app web',
noAccessPermission: 'Nessun permesso per accedere all\'app web',
maxActiveRequestsPlaceholder: 'Inserisci 0 per illimitato',
maxActiveRequests: 'Massimo numero di richieste concorrenti',
}
export default translation

@ -228,6 +228,28 @@ const translation = {
workspaceIcon: 'Icona della workspace',
editWorkspaceInfo: 'Modifica informazioni dello spazio di lavoro',
workspaceName: 'Nome del Workspace',
changeEmail: {
changeTo: 'Cambia in {{email}}',
verifyEmail: 'Verifica la tua email attuale',
codePlaceholder: 'Inserisci il codice di 6 cifre',
resendTip: 'Non hai ricevuto un codice?',
newEmail: 'Crea un nuovo indirizzo email',
resend: 'Rimanda',
continue: 'Continua',
verifyNew: 'Verifica la tua nuova email',
resendCount: 'Reinvia in {{count}}s',
title: 'Cambia Email',
emailPlaceholder: 'Inserisci una nuova email',
emailLabel: 'Nuova email',
codeLabel: 'Codice di verifica',
existingEmail: 'Un utente con questa email esiste già.',
content2: 'La tua email attuale è <email>{{email}}</email>. Il codice di verifica è stato inviato a questo indirizzo email.',
authTip: 'Una volta che la tua email è cambiata, gli account Google o GitHub collegati alla tua vecchia email non potranno più accedere a questo account.',
content3: 'Inserisci una nuova email e ti invieremo un codice di verifica.',
content4: 'Ti abbiamo appena inviato un codice di verifica temporaneo a <email>{{email}}</email>.',
content1: 'Se continui, invieremo un codice di verifica a <email>{{email}}</email> per la riautenticazione.',
sendVerifyCode: 'Invia codice di verifica',
},
},
members: {
team: 'Team',
@ -272,6 +294,26 @@ const translation = {
disInvite: 'Annulla l\'invito',
deleteMember: 'Elimina Membro',
you: '(Tu)',
transferModal: {
continue: 'Continua',
resendTip: 'Non hai ricevuto un codice?',
title: 'Trasferire la proprietà dello spazio di lavoro',
codeLabel: 'Codice di verifica',
verifyEmail: 'Verifica la tua email attuale',
transferPlaceholder: 'Seleziona un membro del team...',
transfer: 'Trasferire la proprietà dello spazio di lavoro',
codePlaceholder: 'Inserisci il codice di 6 cifre',
warningTip: 'Diventerai un membro amministratore e il nuovo proprietario avrà il pieno controllo.',
resendCount: 'Reinvia in {{count}}s',
sendVerifyCode: 'Invia codice di verifica',
verifyContent2: 'Invieremo un codice di verifica temporaneo a questa email per la re-autenticazione.',
verifyContent: 'La tua email attuale è <email>{{email}}</email>.',
sendTip: 'Se continui, invieremo un codice di verifica a <email>{{email}}</email> per la riautenticazione.',
warning: 'Stai per trasferire la proprietà di "{{workspace}}". Questo avrà effetto immediato e non può essere annullato.',
transferLabel: 'Trasferisci la proprietà dello spazio di lavoro a',
resend: 'Rimanda',
},
transferOwnership: 'Trasferisci Proprietà',
},
integrations: {
connected: 'Connesso',
@ -476,6 +518,7 @@ const translation = {
addPages: 'Aggiungi pagine',
preview: 'ANTEPRIMA',
},
integratedAlert: 'Notion è integrato tramite credenziali interne, non è necessario ri-autorizzare.',
},
website: {
title: 'Sito web',

@ -380,6 +380,7 @@ const translation = {
regenerationConfirmTitle: 'Si desidera rigenerare i blocchi figlio?',
chunks_other: 'BLOCCHI',
editedAt: 'A cura di',
dateTimeFormat: 'DD/MM/YYYY HH:mm',
collapseChunks: 'Comprimi blocchi',
clearFilter: 'Cancella filtro',
chunks_one: 'PEZZO',

@ -119,6 +119,7 @@ const translation = {
noLoginMethod: 'Metodo di autenticazione non configurato per l\'app web',
noLoginMethodTip: 'Si prega di contattare l\'amministratore del sistema per aggiungere un metodo di autenticazione.',
disabled: 'L\'autenticazione dell\'app web è disabilitata. Si prega di contattare l\'amministratore di sistema per abilitarla. Puoi provare a utilizzare l\'app direttamente.',
login: 'Accesso',
},
}

@ -63,6 +63,7 @@ const translation = {
auto: 'Automatico',
paramsTip2: 'Quando \'Automatico\' è disattivato, viene utilizzato il valore predefinito.',
toolSetting: 'Impostazioni degli strumenti',
unsupportedMCPTool: 'La versione attualmente selezionata del plugin strategia agente non supporta gli strumenti MCP.',
},
modelNum: '{{num}} MODELLI INCLUSI',
endpointModalTitle: 'Endpoint di configurazione',

@ -89,9 +89,14 @@ const translation = {
api_key: 'API Key',
apiKeyPlaceholder: 'Nome dell\'intestazione HTTP per API Key',
apiValuePlaceholder: 'Inserisci API Key',
api_key_query: 'Parametro di query',
api_key_header: 'Intestazione',
queryParamPlaceholder: 'Nome del parametro di query per la chiave API',
},
key: 'Chiave',
value: 'Valore',
queryParam: 'Parametro di query',
queryParamTooltip: 'Il nome del parametro di query della chiave API da passare, ad esempio "key" in "https://example.com/test?key=API_KEY".',
},
authHeaderPrefix: {
title: 'Tipo di Auth',

@ -119,6 +119,7 @@ const translation = {
needEndNode: 'Deve essere aggiunto il nodo finale',
addBlock: 'Aggiungi nodo',
needAnswerNode: 'Deve essere aggiunto il nodo di risposta',
tagBound: 'Numero di app che utilizzano questo tag',
},
env: {
envPanelTitle: 'Variabili d\'Ambiente',
@ -239,6 +240,8 @@ const translation = {
'plugin': 'Plugin',
'searchBlock': 'Cerca nodo',
'blocks': 'Nodi',
'allAdded': 'Tutto aggiunto',
'addAll': 'Aggiungi tutto',
},
blocks: {
'start': 'Inizio',
@ -379,7 +382,10 @@ const translation = {
retryFailed: 'Nuovo tentativo non riuscito',
ms: 'ms',
},
typeSwitch: {},
typeSwitch: {
input: 'Valore di input',
variable: 'Usa la variabile',
},
},
start: {
required: 'richiesto',
@ -568,6 +574,7 @@ const translation = {
advancedDependenciesTip:
'Aggiungi alcune dipendenze precaricate che richiedono più tempo per essere consumate o che non sono predefinite qui',
searchDependencies: 'Cerca Dipendenze',
syncFunctionSignature: 'Sincronizza la firma della funzione con il codice',
},
templateTransform: {
inputVars: 'Variabili di Input',
@ -689,6 +696,9 @@ const translation = {
json: 'json generato dallo strumento',
},
authorize: 'Autorizza',
insertPlaceholder1: 'Digita o premi',
insertPlaceholder2: 'inserisci variabile',
settings: 'Impostazioni',
},
questionClassifiers: {
model: 'modello',
@ -878,6 +888,8 @@ const translation = {
strategyNotFoundDescAndSwitchVersion: 'La versione del plugin installata non fornisce questa strategia. Fare clic per cambiare versione.',
pluginNotInstalled: 'Questo plugin non è installato',
pluginNotFoundDesc: 'Questo plugin viene installato da GitHub. Vai su Plugin per reinstallare',
parameterSchema: 'Schema dei parametri',
clickToViewParameterSchema: 'Clicca per visualizzare lo schema dei parametri',
},
loop: {
ErrorMethod: {

@ -1,7 +1,7 @@
const translation = {
title: 'ログ',
description: 'ログは、アプリケーションの実行状態を記録します。ユーザーの入力や AI の応答などが含まれます。',
dateTimeFormat: 'MM/DD/YYYY hh:mm A',
dateTimeFormat: 'YYYY/MM/DD hh:mm A',
table: {
header: {
updatedTime: '更新時間',

@ -180,7 +180,10 @@ const translation = {
title: '織る',
description: 'Weave は、LLM アプリケーションを評価、テスト、および監視するためのオープンソースプラットフォームです。',
},
aliyun: {},
aliyun: {
title: 'クラウドモニター',
description: 'Alibaba Cloud が提供する完全管理型でメンテナンスフリーの可観測性プラットフォームは、Dify アプリケーションの即時監視、トレース、評価を可能にします。',
},
},
answerIcon: {
title: 'Web アプリアイコンを使用して🤖を置き換える',
@ -255,6 +258,8 @@ const translation = {
notSetDesc: '現在この Web アプリには誰もアクセスできません。権限を設定してください。',
},
noAccessPermission: 'Web アプリにアクセス権限がありません',
maxActiveRequestsPlaceholder: '無制限のために0を入力してください',
maxActiveRequests: '最大同時リクエスト数',
}
export default translation

@ -509,6 +509,7 @@ const translation = {
addPages: 'ページの追加',
preview: 'プレビュー',
},
integratedAlert: 'Notionは内部資格情報を通じて統合されており、再認証する必要はありません。',
},
website: {
title: 'ウェブサイト',

@ -388,6 +388,7 @@ const translation = {
regenerationSuccessMessage: 'ウィンドウを閉じても大丈夫です',
edited: '編集済み',
editedAt: '編集日時',
dateTimeFormat: 'YYYY/MM/DD HH:mm',
expandChunks: 'チャンクを展開',
collapseChunks: 'チャンクを折りたたむ',
keywordDuplicate: 'そのキーワードは既に存在しています',

@ -1,7 +1,7 @@
const translation = {
title: '検索テスト',
desc: '与えられたクエリテキストに基づいたナレッジのヒット効果をテストします。',
dateTimeFormat: 'MM/DD/YYYY hh:mm A',
dateTimeFormat: 'YYYY/MM/DD hh:mm A',
records: '記録',
table: {
header: {

@ -63,6 +63,7 @@ const translation = {
toolLabel: '道具',
unsupportedTitle: 'サポートされていないアクション',
toolSetting: 'ツール設定',
unsupportedMCPTool: '現在選択されているエージェント戦略プラグインのバージョンはMCPツールをサポートしていません。',
},
endpointDisableTip: 'エンドポイントを無効にする',
endpointModalDesc: '設定が完了すると、API エンドポイントを介してプラグインが提供する機能を使用できます。',

@ -85,9 +85,14 @@ const translation = {
api_key: 'API キー',
apiKeyPlaceholder: 'API キーの HTTP ヘッダー名',
apiValuePlaceholder: 'API キーを入力してください',
api_key_query: 'クエリパラメータ',
queryParamPlaceholder: 'APIキーのクエリパラメータ名',
api_key_header: 'ヘッダー',
},
key: 'キー',
value: '値',
queryParam: 'クエリパラメータ',
queryParamTooltip: 'APIキーのクエリパラメータとして渡す名前、例えば「https://example.com/test?key=API_KEY」の「key」。',
},
authHeaderPrefix: {
title: '認証タイプ',

@ -113,6 +113,7 @@ const translation = {
addFailureBranch: '失敗ブランチを追加',
loadMore: 'さらに読み込む',
noHistory: '履歴がありません',
tagBound: 'このタグを使用しているアプリの数',
},
env: {
envPanelTitle: '環境変数',
@ -232,6 +233,8 @@ const translation = {
'noResult': '該当なし',
'plugin': 'プラグイン',
'agent': 'エージェント戦略',
'addAll': 'すべてを追加する',
'allAdded': 'すべて追加されました',
},
blocks: {
'start': '開始',
@ -369,7 +372,10 @@ const translation = {
ms: 'ミリ秒',
retries: '再試行回数:{{num}}',
},
typeSwitch: {},
typeSwitch: {
input: '入力値',
variable: '変数を使用する',
},
},
start: {
required: '必須',
@ -677,6 +683,9 @@ const translation = {
json: 'ツールで生成された JSON',
},
authorize: '認証する',
settings: '設定',
insertPlaceholder1: 'タイプするか押してください',
insertPlaceholder2: '変数を挿入する',
},
questionClassifiers: {
model: 'モデル',
@ -893,6 +902,8 @@ const translation = {
unsupportedStrategy: 'サポートされていない戦略',
pluginNotFoundDesc: 'このプラグインは GitHub からインストールされています。再インストールするにはプラグインに移動してください。',
strategyNotFoundDesc: 'インストールされたプラグインのバージョンは、この戦略を提供していません。',
parameterSchema: 'パラメータスキーマ',
clickToViewParameterSchema: 'パラメータースキーマを見るにはクリックしてください',
},
},
tracing: {

@ -192,7 +192,10 @@ const translation = {
description:
'Weave 는 LLM 애플리케이션을 평가하고 테스트하며 모니터링하기 위한 오픈 소스 플랫폼입니다.',
},
aliyun: {},
aliyun: {
title: '클라우드 모니터',
description: '알리바바 클라우드에서 제공하는 완전 관리형 및 유지보수가 필요 없는 가시성 플랫폼은 Dify 애플리케이션의 모니터링, 추적 및 평가를 즉시 사용할 수 있도록 지원합니다.',
},
},
answerIcon: {
description:
@ -281,6 +284,8 @@ const translation = {
},
accessControl: '웹 애플리케이션 접근 제어',
noAccessPermission: '웹 앱에 대한 접근 권한이 없습니다.',
maxActiveRequests: '동시 최대 요청 수',
maxActiveRequestsPlaceholder: '무제한 사용을 원하시면 0을 입력하세요.',
}
export default translation

@ -212,6 +212,28 @@ const translation = {
workspaceIcon: '작업 공간 아이콘',
editWorkspaceInfo: '작업 공간 정보 편집',
workspaceName: '작업 공간 이름',
changeEmail: {
codeLabel: '검증 코드',
codePlaceholder: '6자리 코드를 붙여넣으세요',
title: '이메일 변경',
emailLabel: '새 이메일',
verifyEmail: '현재 이메일을 확인하세요',
sendVerifyCode: '인증 코드를 보내다',
continue: '계속하다',
resendCount: '{{count}}초 후에 다시 보내기',
verifyNew: '새 이메일 확인하기',
emailPlaceholder: '새 이메일을 입력하세요',
resend: '다시 보내기',
newEmail: '새 이메일 주소를 설정하세요',
existingEmail: '이미 이 이메일을 가진 사용자가 존재합니다.',
content4: '우리는 방금 귀하에게 임시 인증 코드를 <email>{{email}}</email>로 보냈습니다.',
changeTo: '{{email}}로 변경',
content2: '현재 이메일은 <email>{{email}}</email>입니다. 이 이메일 주소로 인증 코드가 전송되었습니다.',
resendTip: '코드를 받지 못하셨나요?',
content3: '새로운 이메일을 입력하시면 인증 코드를 보내드립니다.',
content1: '계속 진행하면, 재인증을 위해 <email>{{email}}</email>로 인증 코드를 전송하겠습니다.',
authTip: '이메일이 변경되면, 이전 이메일에 연결된 Google 또는 GitHub 계정은 더 이상 이 계정에 로그인할 수 없습니다.',
},
},
members: {
team: '팀',
@ -253,6 +275,26 @@ const translation = {
builder: '건설자',
builderTip: '자신의 앱을 구축 및 편집할 수 있습니다.',
datasetOperatorTip: '기술 자료만 관리할 수 있습니다.',
transferModal: {
codeLabel: '검증 코드',
sendVerifyCode: '인증 코드를 보내다',
verifyContent: '현재 이메일은 <email>{{email}}</email>입니다.',
verifyEmail: '현재 이메일을 확인하세요',
continue: '계속하다',
title: '작업 공간 소유권 이전',
resend: '다시 보내기',
transferLabel: '작업 공간 소유권을 이전하다',
transferPlaceholder: '작업 공간 구성원을 선택하세요…',
warning: '당신은 "{{workspace}}"의 소유권을 이전하려고 합니다. 이는 즉시 발효되며 되돌릴 수 없습니다.',
transfer: '작업 공간 소유권 이전',
resendCount: '{{count}}초 후에 다시 보내기',
verifyContent2: '재인증을 위해 이 이메일로 임시 인증 코드를 발송하겠습니다.',
warningTip: '당신은 관리자 회원이 될 것이고, 새로운 소유자는 완전한 제어 권한을 갖게 됩니다.',
codePlaceholder: '6자리 코드를 붙여넣으세요',
resendTip: '코드를 받지 못하셨나요?',
sendTip: '계속 진행하면, 재인증을 위해 <email>{{email}}</email>로 인증 코드를 전송하겠습니다.',
},
transferOwnership: '소유권 이전',
},
integrations: {
connected: '연결됨',
@ -444,6 +486,7 @@ const translation = {
addPages: '페이지 추가하기',
preview: '미리보기',
},
integratedAlert: 'Notion은 내부 자격 증명을 통해 통합되므로 다시 인증할 필요가 없습니다.',
},
website: {
inactive: '게으른',

@ -371,6 +371,7 @@ const translation = {
childChunks_one: '자식 청크 (CHILD CHUNK)',
regenerationSuccessTitle: '재생이 완료되었습니다.',
editedAt: '편집 위치',
dateTimeFormat: 'MM/DD/YYYY h:mm',
addAnother: '다른 항목 추가',
chunkAdded: '청크 1 개 추가됨',
searchResults_one: '결과',

@ -109,6 +109,7 @@ const translation = {
noLoginMethod: '웹 애플리케이션에 대한 인증 방법이 구성되어 있지 않습니다.',
disabled: '웹앱 인증이 비활성화되었습니다. 이를 활성화하려면 시스템 관리자에게 문의하십시오. 앱을 직접 사용해 볼 수 있습니다.',
noLoginMethodTip: '인증 방법을 추가하려면 시스템 관리자에게 연락하십시오.',
login: '로그인',
},
}

@ -63,6 +63,7 @@ const translation = {
paramsTip2: '\'자동\'이 꺼져 있으면 기본값이 사용됩니다.',
unsupportedContent: '설치된 플러그인 버전은 이 작업을 제공하지 않습니다.',
toolSetting: '도구 설정',
unsupportedMCPTool: '현재 선택된 에이전트 전략 플러그인 버전은 MCP 도구를 지원하지 않습니다.',
},
configureApp: '앱 구성',
strategyNum: '{{번호}} {{전략}} 포함',

@ -85,9 +85,14 @@ const translation = {
api_key: 'API 키',
apiKeyPlaceholder: 'API 키의 HTTP 헤더 이름',
apiValuePlaceholder: 'API 키를 입력하세요',
api_key_query: '쿼리 매개변수',
queryParamPlaceholder: 'API 키에 대한 쿼리 매개변수 이름',
api_key_header: '헤더',
},
key: '키',
value: '값',
queryParam: '쿼리 매개변수',
queryParamTooltip: '전달할 API 키 쿼리 매개변수의 이름, 예: "https://example.com/test?key=API_KEY"에서의 "key".',
},
authHeaderPrefix: {
title: '인증 유형',

@ -119,6 +119,7 @@ const translation = {
addBlock: '노드 추가',
needAnswerNode: '답변 노드를 추가해야 합니다.',
needEndNode: '종단 노드를 추가해야 합니다.',
tagBound: '이 태그를 사용하는 앱 수',
},
env: {
envPanelTitle: '환경 변수',
@ -243,6 +244,8 @@ const translation = {
'agent': '에이전트 전략',
'blocks': '노드',
'searchBlock': '검색 노드',
'allAdded': '모두 추가됨',
'addAll': '모두 추가',
},
blocks: {
'start': '시작',
@ -388,7 +391,10 @@ const translation = {
ms: '미에스',
retries: '{{숫자}} 재시도',
},
typeSwitch: {},
typeSwitch: {
input: '입력 값',
variable: '변수를 사용하세요',
},
},
start: {
required: '필수',
@ -580,6 +586,7 @@ const translation = {
advancedDependenciesTip:
'더 많은 시간이 소요되거나 기본으로 내장되지 않은 일부 미리 로드된 종속성을 여기에 추가하세요',
searchDependencies: '종속성 검색',
syncFunctionSignature: '코드에 함수 시그니처 동기화하기',
},
templateTransform: {
inputVars: '입력 변수',
@ -702,6 +709,9 @@ const translation = {
json: '도구로 생성된 JSON',
},
authorize: '권한 부여',
insertPlaceholder1: '타이프하거나 누르세요',
settings: '설정',
insertPlaceholder2: '변수를 삽입하다',
},
questionClassifiers: {
model: '모델',
@ -902,6 +912,8 @@ const translation = {
modelNotSelected: '모델이 선택되지 않음',
toolbox: '도구',
linkToPlugin: '플러그인에 대한 링크',
parameterSchema: '파라미터 스키마',
clickToViewParameterSchema: '매개변수 스키마 보려면 클릭하세요.',
},
loop: {
ErrorMethod: {

@ -179,7 +179,10 @@ const translation = {
title: 'Tkaj',
description: 'Weave to platforma open-source do oceny, testowania i monitorowania aplikacji LLM.',
},
aliyun: {},
aliyun: {
title: 'Monitor Chmury',
description: 'W pełni zarządzana i wolna od konserwacji platforma obserwowalności oferowana przez Alibaba Cloud umożliwia gotowe monitorowanie, śledzenie i oceny aplikacji Dify.',
},
},
answerIcon: {
description: 'Czy w aplikacji udostępnionej ma być używana ikona aplikacji internetowej do zamiany 🤖.',
@ -263,6 +266,8 @@ const translation = {
},
accessControl: 'Kontrola dostępu do aplikacji internetowej',
noAccessPermission: 'Brak uprawnień do dostępu do aplikacji internetowej',
maxActiveRequests: 'Maksymalne równoczesne żądania',
maxActiveRequestsPlaceholder: 'Wprowadź 0, aby uzyskać nielimitowane',
}
export default translation

@ -222,6 +222,28 @@ const translation = {
workspaceIcon: 'Ikona robocza',
workspaceName: 'Nazwa miejsca pracy',
editWorkspaceInfo: 'Edytuj informacje o przestrzeni roboczej',
changeEmail: {
emailLabel: 'Nowy e-mail',
emailPlaceholder: 'Wprowadź nowy adres e-mail',
changeTo: 'Zmień na {{email}}',
sendVerifyCode: 'Wyślij kod weryfikacyjny',
resend: 'Wyślij ponownie',
title: 'Zmień e-mail',
newEmail: 'Utwórz nowy adres e-mail',
existingEmail: 'Użytkownik z tym adresem e-mail już istnieje.',
content1: 'Jeśli będziesz kontynuować, wyślemy kod weryfikacyjny na <email>{{email}}</email> w celu ponownej autoryzacji.',
resendCount: 'Wyślij ponownie za {{count}}s',
codeLabel: 'Kod weryfikacyjny',
codePlaceholder: 'Wklej 6-cyfrowy kod',
continue: 'Kontynuuj',
content3: 'Wprowadź nowy adres e-mail, a my wyślemy ci kod weryfikacyjny.',
verifyEmail: 'Zweryfikuj swój aktualny adres e-mail',
verifyNew: 'Zweryfikuj swój nowy adres e-mail',
resendTip: 'Nie otrzymałeś kodu?',
content2: 'Twój aktualny adres email to <email>{{email}}</email>. Kod weryfikacyjny został wysłany na ten adres email.',
content4: 'Właśnie wysłaliśmy Ci tymczasowy kod weryfikacyjny na <email>{{email}}</email>.',
authTip: 'Gdy twoje e-mail zostanie zmienione, konta Google lub GitHub powiązane z twoim starym e-mailem nie będą mogły już logować się do tego konta.',
},
},
members: {
team: 'Zespół',
@ -265,6 +287,26 @@ const translation = {
builder: 'Budowniczy',
builderTip: 'Może tworzyć i edytować własne aplikacje',
datasetOperator: 'Wiedza Admin',
transferModal: {
sendVerifyCode: 'Wyślij kod weryfikacyjny',
resend: 'Wyślij ponownie',
codePlaceholder: 'Wklej 6-cyfrowy kod',
verifyContent: 'Twój aktualny adres e-mail to <email>{{email}}</email>.',
continue: 'Kontynuuj',
verifyEmail: 'Zweryfikuj swój aktualny adres e-mail',
resendTip: 'Nie otrzymałeś kodu?',
transferPlaceholder: 'Wybierz członka zespołu…',
transfer: 'Przenieś własność przestrzeni roboczej',
warning: 'Zaraz przekażesz własność „{{workspace}}”. To nastąpi natychmiast i nie można tego cofnąć.',
title: 'Przenieś własność przestrzeni roboczej',
codeLabel: 'Kod weryfikacyjny',
transferLabel: 'Przenieś właśność przestrzeni roboczej na',
resendCount: 'Wyślij ponownie za {{count}}s',
verifyContent2: 'Wyślemy tymczasowy kod weryfikacyjny na ten adres e-mail w celu ponownej autoryzacji.',
sendTip: 'Jeśli będziesz kontynuować, wyślemy kod weryfikacyjny na <email>{{email}}</email> w celu ponownej autoryzacji.',
warningTip: 'Staniesz się członkiem administracji, a nowy właściciel będzie miał pełną kontrolę.',
},
transferOwnership: 'Przenieś własność',
},
integrations: {
connected: 'Połączony',
@ -461,6 +503,7 @@ const translation = {
addPages: 'Dodaj strony',
preview: 'PODGLĄD',
},
integratedAlert: 'Notion jest zintegrowany za pomocą wewnętrznych poświadczeń, nie ma potrzeby ponownej autoryzacji.',
},
website: {
active: 'Aktywny',

@ -369,6 +369,7 @@ const translation = {
regenerationSuccessTitle: 'Regeneracja zakończona',
edited: 'EDYTOWANE',
editedAt: 'Zredagowane w',
dateTimeFormat: 'MM/DD/YYYY h:mm',
collapseChunks: 'Zwijanie fragmentów',
empty: 'Nie znaleziono fragmentu',
newChunk: 'Nowy fragment',

@ -114,6 +114,7 @@ const translation = {
noLoginMethod: 'Metoda uwierzytelniania nie jest skonfigurowana dla aplikacji internetowej',
noLoginMethodTip: 'Proszę skontaktować się z administratorem systemu, aby dodać metodę uwierzytelniania.',
disabled: 'Uwierzytelnianie aplikacji internetowej jest wyłączone. Proszę skontaktować się z administratorem systemu, aby je włączyć. Możesz spróbować użyć aplikacji bezpośrednio.',
login: 'Zaloguj się',
},
}

@ -63,6 +63,7 @@ const translation = {
paramsTip2: 'Gdy opcja "Auto" jest wyłączona, używana jest wartość domyślna.',
toolLabel: 'Narzędzie',
toolSetting: 'Ustawienia narzędzi',
unsupportedMCPTool: 'Obecnie wybrana wersja wtyczki strategii agenta nie obsługuje narzędzi MCP.',
},
strategyNum: '{{liczba}} {{strategia}} ZAWARTE',
endpointsEmpty: 'Kliknij przycisk "+", aby dodać punkt końcowy',

@ -59,9 +59,14 @@ const translation = {
api_key: 'Klucz API',
apiKeyPlaceholder: 'Nazwa nagłówka HTTP dla Klucza API',
apiValuePlaceholder: 'Wprowadź Klucz API',
api_key_query: 'Parametr zapytania',
api_key_header: 'Nagłówek',
queryParamPlaceholder: 'Nazwa parametru zapytania dla klucza API',
},
key: 'Klucz',
value: 'Wartość',
queryParam: 'Parametr zapytania',
queryParamTooltip: 'Nazwa parametru zapytania klucza API do przekazania, np. "key" w "https://example.com/test?key=API_KEY".',
},
authHeaderPrefix: {
title: 'Typ autoryzacji',

@ -115,6 +115,7 @@ const translation = {
addBlock: 'Dodaj węzeł',
needEndNode: 'Należy dodać węzeł końcowy',
needAnswerNode: 'Węzeł odpowiedzi musi zostać dodany',
tagBound: 'Liczba aplikacji korzystających z tego tagu',
},
env: {
envPanelTitle: 'Zmienne Środowiskowe',
@ -234,6 +235,8 @@ const translation = {
'plugin': 'Wtyczka',
'searchBlock': 'Wyszukaj węzeł',
'blocks': 'Węzły',
'addAll': 'Dodaj wszystko',
'allAdded': 'Wszystko dodane',
},
blocks: {
'start': 'Start',
@ -364,7 +367,10 @@ const translation = {
retryFailedTimes: '{{times}} ponawianie prób nie powiodło się',
ms: 'Ms',
},
typeSwitch: {},
typeSwitch: {
variable: 'Użyj zmiennej',
input: 'Wartość wejściowa',
},
},
start: {
required: 'wymagane',
@ -551,6 +557,7 @@ const translation = {
advancedDependencies: 'Zaawansowane zależności',
advancedDependenciesTip: 'Dodaj niektóre preładowane zależności, które zajmują więcej czasu lub nie są domyślnie wbudowane',
searchDependencies: 'Wyszukaj zależności',
syncFunctionSignature: 'Zsynchronizuj sygnaturę funkcji z kodem',
},
templateTransform: {
inputVars: 'Zmienne wejściowe',
@ -670,6 +677,9 @@ const translation = {
json: 'JSON wygenerowany przez narzędzien',
},
authorize: 'Autoryzuj',
insertPlaceholder2: 'wstaw zmienną',
settings: 'Ustawienia',
insertPlaceholder1: 'Wpisz lub naciśnij',
},
questionClassifiers: {
model: 'model',
@ -854,6 +864,8 @@ const translation = {
learnMore: 'Dowiedz się więcej',
strategyNotSet: 'Nie ustawiono strategii agentalnej',
model: 'model',
parameterSchema: 'Schemat parametrów',
clickToViewParameterSchema: 'Kliknij, aby zobaczyć schemat parametrów',
},
loop: {
ErrorMethod: {

@ -172,7 +172,10 @@ const translation = {
description: 'Weave é uma plataforma de código aberto para avaliar, testar e monitorar aplicações de LLM.',
title: 'Trançar',
},
aliyun: {},
aliyun: {
title: 'Monitoramento em Nuvem',
description: 'A plataforma de observabilidade totalmente gerenciada e sem manutenção fornecida pela Alibaba Cloud, permite monitoramento, rastreamento e avaliação prontos para uso de aplicações Dify.',
},
},
answerIcon: {
descriptionInExplore: 'Se o ícone do web app deve ser usado para substituir 🤖 no Explore',
@ -256,6 +259,8 @@ const translation = {
},
accessControl: 'Controle de Acesso do Aplicativo Web',
noAccessPermission: 'Sem permissão para acessar o aplicativo web',
maxActiveRequestsPlaceholder: 'Digite 0 para ilimitado',
maxActiveRequests: 'Máximo de solicitações simultâneas',
}
export default translation

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

Loading…
Cancel
Save