diff --git a/api/commands.py b/api/commands.py index 6262bfde6b..0a6cc61a68 100644 --- a/api/commands.py +++ b/api/commands.py @@ -27,7 +27,7 @@ from models.dataset import Dataset, DatasetCollectionBinding, DatasetMetadata, D from models.dataset import Document as DatasetDocument from models.model import Account, App, AppAnnotationSetting, AppMode, Conversation, MessageAnnotation from models.provider import Provider, ProviderModel -from services.account_service import RegisterService, TenantService +from services.account_service import AccountService, RegisterService, TenantService from services.clear_free_plan_tenant_expired_logs import ClearFreePlanTenantExpiredLogs from services.plugin.data_migration import PluginDataMigration from services.plugin.plugin_migration import PluginMigration @@ -68,6 +68,7 @@ def reset_password(email, new_password, password_confirm): account.password = base64_password_hashed account.password_salt = base64_salt db.session.commit() + AccountService.reset_login_error_rate_limit(email) click.echo(click.style("Password reset successfully.", fg="green")) diff --git a/api/controllers/service_api/app/app.py b/api/controllers/service_api/app/app.py index 2c03aba33d..89222d5e83 100644 --- a/api/controllers/service_api/app/app.py +++ b/api/controllers/service_api/app/app.py @@ -47,7 +47,13 @@ class AppInfoApi(Resource): def get(self, app_model: App): """Get app information""" tags = [tag.name for tag in app_model.tags] - return {"name": app_model.name, "description": app_model.description, "tags": tags, "mode": app_model.mode} + return { + "name": app_model.name, + "description": app_model.description, + "tags": tags, + "mode": app_model.mode, + "author_name": app_model.author_name, + } api.add_resource(AppParameterApi, "/parameters") diff --git a/api/tasks/retry_document_indexing_task.py b/api/tasks/retry_document_indexing_task.py index a6e7092216..8f8c3f9d81 100644 --- a/api/tasks/retry_document_indexing_task.py +++ b/api/tasks/retry_document_indexing_task.py @@ -30,11 +30,11 @@ def retry_document_indexing_task(dataset_id: str, document_ids: list[str]): logging.info(click.style("Dataset not found: {}".format(dataset_id), fg="red")) db.session.close() return - + tenant_id = dataset.tenant_id for document_id in document_ids: retry_indexing_cache_key = "document_{}_is_retried".format(document_id) # check document limit - features = FeatureService.get_features(dataset.tenant_id) + features = FeatureService.get_features(tenant_id) try: if features.billing.enabled: vector_space = features.vector_space diff --git a/docker/.env.example b/docker/.env.example index 4cf5e202d0..d4d59936eb 100644 --- a/docker/.env.example +++ b/docker/.env.example @@ -1067,6 +1067,7 @@ PLUGIN_MEDIA_CACHE_PATH=assets # Plugin oss bucket PLUGIN_STORAGE_OSS_BUCKET= # Plugin oss s3 credentials +PLUGIN_S3_USE_AWS= PLUGIN_S3_USE_AWS_MANAGED_IAM=false PLUGIN_S3_ENDPOINT= PLUGIN_S3_USE_PATH_STYLE=false diff --git a/docker/docker-compose-template.yaml b/docker/docker-compose-template.yaml index a409a729ce..648b82c918 100644 --- a/docker/docker-compose-template.yaml +++ b/docker/docker-compose-template.yaml @@ -168,6 +168,7 @@ services: PLUGIN_MEDIA_CACHE_PATH: ${PLUGIN_MEDIA_CACHE_PATH:-assets} PLUGIN_STORAGE_OSS_BUCKET: ${PLUGIN_STORAGE_OSS_BUCKET:-} S3_USE_AWS_MANAGED_IAM: ${PLUGIN_S3_USE_AWS_MANAGED_IAM:-false} + S3_USE_AWS: ${PLUGIN_S3_USE_AWS:-} S3_ENDPOINT: ${PLUGIN_S3_ENDPOINT:-} S3_USE_PATH_STYLE: ${PLUGIN_S3_USE_PATH_STYLE:-false} AWS_ACCESS_KEY: ${PLUGIN_AWS_ACCESS_KEY:-} diff --git a/docker/docker-compose.middleware.yaml b/docker/docker-compose.middleware.yaml index dceee484ca..4081bfd818 100644 --- a/docker/docker-compose.middleware.yaml +++ b/docker/docker-compose.middleware.yaml @@ -104,6 +104,7 @@ services: PLUGIN_PACKAGE_CACHE_PATH: ${PLUGIN_PACKAGE_CACHE_PATH:-plugin_packages} PLUGIN_MEDIA_CACHE_PATH: ${PLUGIN_MEDIA_CACHE_PATH:-assets} PLUGIN_STORAGE_OSS_BUCKET: ${PLUGIN_STORAGE_OSS_BUCKET:-} + S3_USE_AWS: ${PLUGIN_S3_USE_AWS:-} S3_USE_AWS_MANAGED_IAM: ${PLUGIN_S3_USE_AWS_MANAGED_IAM:-false} S3_ENDPOINT: ${PLUGIN_S3_ENDPOINT:-} S3_USE_PATH_STYLE: ${PLUGIN_S3_USE_PATH_STYLE:-false} diff --git a/docker/docker-compose.yaml b/docker/docker-compose.yaml index d927334118..ec910f6258 100644 --- a/docker/docker-compose.yaml +++ b/docker/docker-compose.yaml @@ -467,6 +467,7 @@ x-shared-env: &shared-api-worker-env PLUGIN_PACKAGE_CACHE_PATH: ${PLUGIN_PACKAGE_CACHE_PATH:-plugin_packages} PLUGIN_MEDIA_CACHE_PATH: ${PLUGIN_MEDIA_CACHE_PATH:-assets} PLUGIN_STORAGE_OSS_BUCKET: ${PLUGIN_STORAGE_OSS_BUCKET:-} + PLUGIN_S3_USE_AWS: ${PLUGIN_S3_USE_AWS:-} PLUGIN_S3_USE_AWS_MANAGED_IAM: ${PLUGIN_S3_USE_AWS_MANAGED_IAM:-false} PLUGIN_S3_ENDPOINT: ${PLUGIN_S3_ENDPOINT:-} PLUGIN_S3_USE_PATH_STYLE: ${PLUGIN_S3_USE_PATH_STYLE:-false} @@ -674,6 +675,7 @@ services: PLUGIN_MEDIA_CACHE_PATH: ${PLUGIN_MEDIA_CACHE_PATH:-assets} PLUGIN_STORAGE_OSS_BUCKET: ${PLUGIN_STORAGE_OSS_BUCKET:-} S3_USE_AWS_MANAGED_IAM: ${PLUGIN_S3_USE_AWS_MANAGED_IAM:-false} + S3_USE_AWS: ${PLUGIN_S3_USE_AWS:-} S3_ENDPOINT: ${PLUGIN_S3_ENDPOINT:-} S3_USE_PATH_STYLE: ${PLUGIN_S3_USE_PATH_STYLE:-false} AWS_ACCESS_KEY: ${PLUGIN_AWS_ACCESS_KEY:-} diff --git a/docker/middleware.env.example b/docker/middleware.env.example index 66037f281c..338b057ae8 100644 --- a/docker/middleware.env.example +++ b/docker/middleware.env.example @@ -133,6 +133,7 @@ PLUGIN_MEDIA_CACHE_PATH=assets PLUGIN_STORAGE_OSS_BUCKET= # Plugin oss s3 credentials PLUGIN_S3_USE_AWS_MANAGED_IAM=false +PLUGIN_S3_USE_AWS= PLUGIN_S3_ENDPOINT= PLUGIN_S3_USE_PATH_STYLE=false PLUGIN_AWS_ACCESS_KEY= diff --git a/web/app/(commonLayout)/datasets/(datasetDetailLayout)/[datasetId]/layout-main.tsx b/web/app/(commonLayout)/datasets/(datasetDetailLayout)/[datasetId]/layout-main.tsx index 5be674441e..e0436d6f5c 100644 --- a/web/app/(commonLayout)/datasets/(datasetDetailLayout)/[datasetId]/layout-main.tsx +++ b/web/app/(commonLayout)/datasets/(datasetDetailLayout)/[datasetId]/layout-main.tsx @@ -22,6 +22,7 @@ import DatasetDetailContext from '@/context/dataset-detail' import { DataSourceType } from '@/models/datasets' import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints' import { useStore } from '@/app/components/app/store' +import { useDocLink } from '@/context/i18n' import { useAppContext } from '@/context/app-context' import Tooltip from '@/app/components/base/tooltip' import LinkedAppsPanel from '@/app/components/base/linked-apps-panel' @@ -48,6 +49,7 @@ const ExtraInfo = React.memo(({ expand, }: IExtraInfoProps) => { const { t } = useTranslation() + const docLink = useDocLink() const hasRelatedApps = relatedApps?.data && relatedApps?.data?.length > 0 const relatedAppsTotal = relatedApps?.data?.length || 0 diff --git a/web/app/components/app/configuration/config-prompt/conversation-history/history-panel.tsx b/web/app/components/app/configuration/config-prompt/conversation-history/history-panel.tsx index 592c95261c..94a02945bb 100644 --- a/web/app/components/app/configuration/config-prompt/conversation-history/history-panel.tsx +++ b/web/app/components/app/configuration/config-prompt/conversation-history/history-panel.tsx @@ -1,13 +1,11 @@ 'use client' import type { FC } from 'react' import React from 'react' -import { useContext } from 'use-context-selector' import { useTranslation } from 'react-i18next' import OperationBtn from '@/app/components/app/configuration/base/operation-btn' import Panel from '@/app/components/app/configuration/base/feature-panel' import { MessageClockCircle } from '@/app/components/base/icons/src/vender/solid/general' -import I18n from '@/context/i18n' -import { LanguagesSupported } from '@/i18n/language' +import { useDocLink } from '@/context/i18n' type Props = { showWarning: boolean @@ -19,7 +17,7 @@ const HistoryPanel: FC = ({ onShowEditModal, }) => { const { t } = useTranslation() - const { locale } = useContext(I18n) + const docLink = useDocLink() return ( = ({ {showWarning && (
{t('appDebug.feature.conversationHistory.tip')} - {t('appDebug.feature.conversationHistory.learnMore')} diff --git a/web/app/components/app/configuration/dataset-config/settings-modal/index.tsx b/web/app/components/app/configuration/dataset-config/settings-modal/index.tsx index 5b01c36d40..62f1010b54 100644 --- a/web/app/components/app/configuration/dataset-config/settings-modal/index.tsx +++ b/web/app/components/app/configuration/dataset-config/settings-modal/index.tsx @@ -32,6 +32,7 @@ import { ModelTypeEnum } from '@/app/components/header/account-setting/model-pro import { fetchMembers } from '@/service/common' import type { Member } from '@/models/common' import { IndexingType } from '@/app/components/datasets/create/step-two' +import { useDocLink } from '@/context/i18n' type SettingsModalProps = { currentDataset: DataSet @@ -57,6 +58,7 @@ const SettingsModal: FC = ({ modelList: rerankModelList, } = useModelListAndDefaultModelAndCurrentProviderAndModel(ModelTypeEnum.rerank) const { t } = useTranslation() + const docLink = useDocLink() const { notify } = useToastContext() const ref = useRef(null) const isExternal = currentDataset.provider === 'external' @@ -330,7 +332,7 @@ const SettingsModal: FC = ({
{t('datasetSettings.form.retrievalSetting.title')}
diff --git a/web/app/components/app/configuration/prompt-mode/advanced-mode-waring.tsx b/web/app/components/app/configuration/prompt-mode/advanced-mode-waring.tsx index cca775c86e..f207cddd16 100644 --- a/web/app/components/app/configuration/prompt-mode/advanced-mode-waring.tsx +++ b/web/app/components/app/configuration/prompt-mode/advanced-mode-waring.tsx @@ -2,9 +2,7 @@ import type { FC } from 'react' import React from 'react' import { useTranslation } from 'react-i18next' -import { useContext } from 'use-context-selector' -import I18n from '@/context/i18n' -import { LanguagesSupported } from '@/i18n/language' +import { useDocLink } from '@/context/i18n' type Props = { onReturnToSimpleMode: () => void } @@ -13,7 +11,7 @@ const AdvancedModeWarning: FC = ({ onReturnToSimpleMode, }) => { const { t } = useTranslation() - const { locale } = useContext(I18n) + const docLink = useDocLink() const [show, setShow] = React.useState(true) if (!show) return null @@ -25,7 +23,7 @@ const AdvancedModeWarning: FC = ({ {t('appDebug.promptMode.advancedWarning.description')} {t('appDebug.promptMode.advancedWarning.learnMore')} diff --git a/web/app/components/app/create-app-modal/index.tsx b/web/app/components/app/create-app-modal/index.tsx index 6e5547d08a..bfb7c43c0d 100644 --- a/web/app/components/app/create-app-modal/index.tsx +++ b/web/app/components/app/create-app-modal/index.tsx @@ -29,6 +29,7 @@ import { NEED_REFRESH_APP_LIST_KEY } from '@/config' import { getRedirection } from '@/utils/app-redirection' import FullScreenModal from '@/app/components/base/fullscreen-modal' import useTheme from '@/hooks/use-theme' +import { useDocLink } from '@/context/i18n' type CreateAppProps = { onSuccess: () => void @@ -303,31 +304,33 @@ function AppTypeCard({ icon, title, description, active, onClick }: AppTypeCardP function AppPreview({ mode }: { mode: AppMode }) { const { t } = useTranslation() + const docLink = useDocLink() const modeToPreviewInfoMap = { 'chat': { title: t('app.types.chatbot'), description: t('app.newApp.chatbotUserDescription'), - link: 'https://docs.dify.ai/guides/application-orchestrate/readme', + link: docLink('/guides/application-orchestrate/chatbot-application'), }, 'advanced-chat': { title: t('app.types.advanced'), description: t('app.newApp.advancedUserDescription'), - link: 'https://docs.dify.ai/en/guides/workflow/README', + link: docLink('/guides/workflow/readme'), }, 'agent-chat': { title: t('app.types.agent'), description: t('app.newApp.agentUserDescription'), - link: 'https://docs.dify.ai/en/guides/application-orchestrate/agent', + link: docLink('/guides/application-orchestrate/agent'), }, 'completion': { title: t('app.newApp.completeApp'), description: t('app.newApp.completionUserDescription'), - link: null, + link: docLink('/guides/application-orchestrate/text-generator', + { 'zh-Hans': '/guides/application-orchestrate/readme' }), }, 'workflow': { title: t('app.types.workflow'), description: t('app.newApp.workflowUserDescription'), - link: 'https://docs.dify.ai/en/guides/workflow/README', + link: docLink('/guides/workflow/readme'), }, } const previewInfo = modeToPreviewInfoMap[mode] diff --git a/web/app/components/app/log/list.tsx b/web/app/components/app/log/list.tsx index 3062e3a911..208fddecd1 100644 --- a/web/app/components/app/log/list.tsx +++ b/web/app/components/app/log/list.tsx @@ -354,7 +354,8 @@ function DetailPanel({ detail, onFeedback }: IDetailPanel) { } useEffect(() => { - adjustModalWidth() + const raf = requestAnimationFrame(adjustModalWidth) + return () => cancelAnimationFrame(raf) }, []) return ( diff --git a/web/app/components/app/overview/customize/index.tsx b/web/app/components/app/overview/customize/index.tsx index 4e84dd8b1f..0fedd76f89 100644 --- a/web/app/components/app/overview/customize/index.tsx +++ b/web/app/components/app/overview/customize/index.tsx @@ -3,13 +3,11 @@ import type { FC } from 'react' import React from 'react' import { ArrowTopRightOnSquareIcon } from '@heroicons/react/24/outline' import { useTranslation } from 'react-i18next' -import { useContext } from 'use-context-selector' +import { useDocLink } from '@/context/i18n' import type { AppMode } from '@/types/app' -import I18n from '@/context/i18n' import Button from '@/app/components/base/button' import Modal from '@/app/components/base/modal' import Tag from '@/app/components/base/tag' -import { LanguagesSupported } from '@/i18n/language' type IShareLinkProps = { isShow: boolean @@ -43,7 +41,7 @@ const CustomizeModal: FC = ({ mode, }) => { const { t } = useTranslation() - const { locale } = useContext(I18n) + const docLink = useDocLink() const isChatApp = mode === 'chat' || mode === 'advanced-chat' return = ({ className='mt-2' onClick={() => window.open( - `https://docs.dify.ai/${locale !== LanguagesSupported[1] - ? 'user-guide/launching-dify-apps/developing-with-apis' - : `${locale.toLowerCase()}/guides/application-publishing/developing-with-apis` - }`, + docLink('/guides/application-publishing/developing-with-apis'), '_blank', ) } diff --git a/web/app/components/app/overview/settings/index.tsx b/web/app/components/app/overview/settings/index.tsx index 98e2cab681..c2d98383c4 100644 --- a/web/app/components/app/overview/settings/index.tsx +++ b/web/app/components/app/overview/settings/index.tsx @@ -4,7 +4,6 @@ import React, { useCallback, useEffect, useState } from 'react' import { RiArrowRightSLine, RiCloseLine } from '@remixicon/react' import Link from 'next/link' import { Trans, useTranslation } from 'react-i18next' -import { useContext } from 'use-context-selector' import { SparklesSoft } from '@/app/components/base/icons/src/public/common' import Modal from '@/app/components/base/modal' import ActionButton from '@/app/components/base/action-button' @@ -19,14 +18,14 @@ import { SimpleSelect } from '@/app/components/base/select' import type { AppDetailResponse } from '@/models/app' import type { AppIconType, AppSSO, Language } from '@/types/app' import { useToastContext } from '@/app/components/base/toast' -import { LanguagesSupported, languages } from '@/i18n/language' +import { languages } from '@/i18n/language' import Tooltip from '@/app/components/base/tooltip' import { useProviderContext } from '@/context/provider-context' import { useModalContext } from '@/context/modal-context' import type { AppIconSelection } from '@/app/components/base/app-icon-picker' import AppIconPicker from '@/app/components/base/app-icon-picker' -import I18n from '@/context/i18n' import cn from '@/utils/classnames' +import { useDocLink } from '@/context/i18n' export type ISettingsModalProps = { isChat: boolean @@ -98,7 +97,7 @@ const SettingsModal: FC = ({ const [language, setLanguage] = useState(default_language) const [saveLoading, setSaveLoading] = useState(false) const { t } = useTranslation() - const { locale } = useContext(I18n) + const docLink = useDocLink() const [showAppIconPicker, setShowAppIconPicker] = useState(false) const [appIcon, setAppIcon] = useState( @@ -238,7 +237,8 @@ const SettingsModal: FC = ({
{t(`${prefixSettings}.modalTip`)} - {t('common.operation.learnMore')} + {t('common.operation.learnMore')}
{/* form body */} diff --git a/web/app/components/base/features/new-feature-panel/index.tsx b/web/app/components/base/features/new-feature-panel/index.tsx index eee680596b..d00cd9038a 100644 --- a/web/app/components/base/features/new-feature-panel/index.tsx +++ b/web/app/components/base/features/new-feature-panel/index.tsx @@ -1,6 +1,5 @@ import React from 'react' import { useTranslation } from 'react-i18next' -import { useContext } from 'use-context-selector' import { RiCloseLine, RiInformation2Fill } from '@remixicon/react' import DialogWrapper from '@/app/components/base/features/new-feature-panel/dialog-wrapper' import { useDefaultModel } from '@/app/components/header/account-setting/model-provider-page/hooks' @@ -19,8 +18,7 @@ import Moderation from '@/app/components/base/features/new-feature-panel/moderat import AnnotationReply from '@/app/components/base/features/new-feature-panel/annotation-reply' import type { PromptVariable } from '@/models/debug' import type { InputVar } from '@/app/components/workflow/types' -import I18n from '@/context/i18n' -import { LanguagesSupported } from '@/i18n/language' +import { useDocLink } from '@/context/i18n' type Props = { show: boolean @@ -48,7 +46,7 @@ const NewFeaturePanel = ({ onAutoAddPromptVariable, }: Props) => { const { t } = useTranslation() - const { locale } = useContext(I18n) + const docLink = useDocLink() const { data: speech2textDefaultModel } = useDefaultModel(ModelTypeEnum.speech2text) const { data: text2speechDefaultModel } = useDefaultModel(ModelTypeEnum.tts) @@ -80,7 +78,7 @@ const NewFeaturePanel = ({ {isChatMode ? t('workflow.common.fileUploadTip') : t('workflow.common.ImageUploadLegacyTip')} {t('workflow.common.featuresDocLink')} diff --git a/web/app/components/datasets/create/step-two/index.tsx b/web/app/components/datasets/create/step-two/index.tsx index dbccc33f67..1564d7d54d 100644 --- a/web/app/components/datasets/create/step-two/index.tsx +++ b/web/app/components/datasets/create/step-two/index.tsx @@ -63,6 +63,7 @@ import CustomDialog from '@/app/components/base/dialog' import { PortalToFollowElem, PortalToFollowElemContent, PortalToFollowElemTrigger } from '@/app/components/base/portal-to-follow-elem' import { AlertTriangle } from '@/app/components/base/icons/src/vender/solid/alertsAndFeedback' import { noop } from 'lodash-es' +import { useDocLink } from '@/context/i18n' const TextLabel: FC = (props) => { return @@ -146,6 +147,7 @@ const StepTwo = ({ updateRetrievalMethodCache, }: StepTwoProps) => { const { t } = useTranslation() + const docLink = useDocLink() const { locale } = useContext(I18n) const media = useBreakpoints() const isMobile = media === MediaType.mobile @@ -963,7 +965,9 @@ const StepTwo = ({
{t('datasetSettings.form.retrievalSetting.title')}
- {t('datasetSettings.form.retrievalSetting.learnMore')} + {t('datasetSettings.form.retrievalSetting.learnMore')} {t('datasetSettings.form.retrievalSetting.longDescription')}
diff --git a/web/app/components/datasets/create/website/base/url-input.tsx b/web/app/components/datasets/create/website/base/url-input.tsx index b7dc9bfca5..ab965bebc3 100644 --- a/web/app/components/datasets/create/website/base/url-input.tsx +++ b/web/app/components/datasets/create/website/base/url-input.tsx @@ -4,6 +4,7 @@ import React, { useCallback, useState } from 'react' import { useTranslation } from 'react-i18next' import Input from './input' import Button from '@/app/components/base/button' +import { useDocLink } from '@/context/i18n' const I18N_PREFIX = 'datasetCreation.stepOne.website' @@ -17,6 +18,7 @@ const UrlInput: FC = ({ onRun, }) => { const { t } = useTranslation() + const docLink = useDocLink() const [url, setUrl] = useState('') const handleUrlChange = useCallback((url: string | number) => { setUrl(url as string) @@ -32,7 +34,7 @@ const UrlInput: FC = ({ + + ) +} +export default React.memo(UrlInput) diff --git a/web/app/components/datasets/documents/index.tsx b/web/app/components/datasets/documents/index.tsx index efb8294fe4..57f4cbc028 100644 --- a/web/app/components/datasets/documents/index.tsx +++ b/web/app/components/datasets/documents/index.tsx @@ -29,8 +29,7 @@ import { useChildSegmentListKey, useSegmentListKey } from '@/service/knowledge/u import useEditDocumentMetadata from '../metadata/hooks/use-edit-dataset-metadata' import DatasetMetadataDrawer from '../metadata/metadata-dataset/dataset-metadata-drawer' import StatusWithAction from '../common/document-status-with-action/status-with-action' -import { LanguagesSupported } from '@/i18n/language' -import { getLocaleOnClient } from '@/i18n' +import { useDocLink } from '@/context/i18n' const FolderPlusIcon = ({ className }: React.SVGProps) => { return @@ -86,6 +85,7 @@ const DEFAULT_LIMIT = 10 const Documents: FC = ({ datasetId }) => { const { t } = useTranslation() + const docLink = useDocLink() const { plan } = useProviderContext() const isFreePlan = plan.type === 'sandbox' const [inputValue, setInputValue] = useState('') // the input value @@ -100,7 +100,6 @@ const Documents: FC = ({ datasetId }) => { const isDataSourceWeb = dataset?.data_source_type === DataSourceType.WEB const isDataSourceFile = dataset?.data_source_type === DataSourceType.FILE const embeddingAvailable = !!dataset?.embedding_available - const locale = getLocaleOnClient() const debouncedSearchValue = useDebounce(searchValue, { wait: 500 }) const { data: documentsRes, isFetching: isListLoading } = useDocumentList({ @@ -267,11 +266,7 @@ const Documents: FC = ({ datasetId }) => { {t('datasetDocuments.list.learnMore')} diff --git a/web/app/components/datasets/external-api/external-api-modal/Form.tsx b/web/app/components/datasets/external-api/external-api-modal/Form.tsx index 2746a32a5b..7d244cce4f 100644 --- a/web/app/components/datasets/external-api/external-api-modal/Form.tsx +++ b/web/app/components/datasets/external-api/external-api-modal/Form.tsx @@ -5,6 +5,7 @@ import { RiBookOpenLine } from '@remixicon/react' import type { CreateExternalAPIReq, FormSchema } from '../declarations' import Input from '@/app/components/base/input' import cn from '@/utils/classnames' +import { useDocLink } from '@/context/i18n' type FormProps = { className?: string @@ -26,6 +27,7 @@ const Form: FC = React.memo(({ inputClassName, }) => { const { t, i18n } = useTranslation() + const docLink = useDocLink() const [changeKey, setChangeKey] = useState('') const handleFormChange = (key: string, val: string) => { @@ -57,7 +59,7 @@ const Form: FC = React.memo(({ {variable === 'endpoint' && ( void @@ -19,6 +20,7 @@ type ExternalAPIPanelProps = { const ExternalAPIPanel: React.FC = ({ onClose }) => { const { t } = useTranslation() + const docLink = useDocLink() const { setShowExternalKnowledgeAPIModal } = useModalContext() const { externalKnowledgeApiList, mutateExternalKnowledgeApis, isLoading } = useExternalKnowledgeApi() @@ -50,7 +52,8 @@ const ExternalAPIPanel: React.FC = ({ onClose }) => {
{t('dataset.externalAPIPanelTitle')}
{t('dataset.externalAPIPanelDescription')}
-
+
{t('dataset.externalAPIPanelDocumentation')}
diff --git a/web/app/components/datasets/external-knowledge-base/create/InfoPanel.tsx b/web/app/components/datasets/external-knowledge-base/create/InfoPanel.tsx index 5c3c1261b6..336e5dbb42 100644 --- a/web/app/components/datasets/external-knowledge-base/create/InfoPanel.tsx +++ b/web/app/components/datasets/external-knowledge-base/create/InfoPanel.tsx @@ -1,8 +1,10 @@ import { RiBookOpenLine } from '@remixicon/react' import { useTranslation } from 'react-i18next' +import { useDocLink } from '@/context/i18n' const InfoPanel = () => { const { t } = useTranslation() + const docLink = useDocLink() return (
@@ -16,12 +18,15 @@ const InfoPanel = () => { {t('dataset.connectDatasetIntro.content.front')} - + {t('dataset.connectDatasetIntro.content.link')} {t('dataset.connectDatasetIntro.content.end')} - + {t('dataset.connectDatasetIntro.learnMore')}

diff --git a/web/app/components/datasets/external-knowledge-base/create/index.tsx b/web/app/components/datasets/external-knowledge-base/create/index.tsx index 5fbddea06b..b8f754e9c4 100644 --- a/web/app/components/datasets/external-knowledge-base/create/index.tsx +++ b/web/app/components/datasets/external-knowledge-base/create/index.tsx @@ -11,6 +11,7 @@ import InfoPanel from './InfoPanel' import type { CreateKnowledgeBaseReq } from './declarations' import Divider from '@/app/components/base/divider' import Button from '@/app/components/base/button' +import { useDocLink } from '@/context/i18n' type ExternalKnowledgeBaseCreateProps = { onConnect: (formValue: CreateKnowledgeBaseReq) => void @@ -19,6 +20,7 @@ type ExternalKnowledgeBaseCreateProps = { const ExternalKnowledgeBaseCreate: React.FC = ({ onConnect, loading }) => { const { t } = useTranslation() + const docLink = useDocLink() const router = useRouter() const [formData, setFormData] = useState({ name: '', @@ -59,7 +61,7 @@ const ExternalKnowledgeBaseCreate: React.FC = {t('dataset.connectHelper.helper1')} {t('dataset.connectHelper.helper2')} {t('dataset.connectHelper.helper3')} - + {t('dataset.connectHelper.helper4')} {t('dataset.connectHelper.helper5')} diff --git a/web/app/components/datasets/hit-testing/modify-retrieval-modal.tsx b/web/app/components/datasets/hit-testing/modify-retrieval-modal.tsx index e66448b979..0b869be079 100644 --- a/web/app/components/datasets/hit-testing/modify-retrieval-modal.tsx +++ b/web/app/components/datasets/hit-testing/modify-retrieval-modal.tsx @@ -11,6 +11,7 @@ import EconomicalRetrievalMethodConfig from '@/app/components/datasets/common/ec import Button from '@/app/components/base/button' import { isReRankModelSelected } from '@/app/components/datasets/common/check-rerank-model' import { useModelListAndDefaultModelAndCurrentProviderAndModel } from '@/app/components/header/account-setting/model-provider-page/hooks' +import { useDocLink } from '@/context/i18n' type Props = { indexMethod: string @@ -29,6 +30,7 @@ const ModifyRetrievalModal: FC = ({ }) => { const ref = useRef(null) const { t } = useTranslation() + const docLink = useDocLink() const [retrievalConfig, setRetrievalConfig] = useState(value) // useClickAway(() => { @@ -72,7 +74,7 @@ const ModifyRetrievalModal: FC = ({ {t('datasetSettings.form.retrievalSetting.learnMore')} diff --git a/web/app/components/develop/template/template.en.mdx b/web/app/components/develop/template/template.en.mdx index 9682b51b39..f178645a8e 100755 --- a/web/app/components/develop/template/template.en.mdx +++ b/web/app/components/develop/template/template.en.mdx @@ -57,8 +57,8 @@ The text generation application offers non-session support and is ideal for tran Due to Cloudflare restrictions, the request will be interrupted without a return after 100 seconds. - User identifier, used to define the identity of the end-user for retrieval and statistics. - Should be uniquely defined by the developer within the application. + User identifier, used to define the identity of the end-user, convenient for retrieval and statistics. + The rules are defined by the developer and need to ensure that the user identifier is unique within the application. The Service API does not share conversations created by the WebApp. File list, suitable for inputting files (images) combined with text understanding and answering questions, available only when the model supports Vision capability. @@ -220,7 +220,7 @@ The text generation application offers non-session support and is ideal for tran - `file` (File) Required The file to be uploaded. - `user` (string) Required - User identifier, defined by the developer's rules, must be unique within the application. + User identifier, defined by the developer's rules, must be unique within the application. The Service API does not share conversations created by the WebApp. ### Response After a successful upload, the server will return the file's ID and related information. @@ -290,7 +290,7 @@ The text generation application offers non-session support and is ideal for tran - `task_id` (string) Task ID, can be obtained from the streaming chunk return Request Body - `user` (string) Required - User identifier, used to define the identity of the end-user, must be consistent with the user passed in the send message interface. + User identifier, used to define the identity of the end-user, must be consistent with the user passed in the send message interface. The Service API does not share conversations created by the WebApp. ### Response - `result` (string) Always returns "success" @@ -512,6 +512,8 @@ The text generation application offers non-session support and is ideal for tran - `name` (string) application name - `description` (string) application description - `tags` (array[string]) application tags + - `mode` (string) application mode + - `author_name` (string) author name @@ -528,7 +530,9 @@ The text generation application offers non-session support and is ideal for tran "tags": [ "tag1", "tag2" - ] + ], + "mode": "chat", + "author_name": "Dify" } ``` diff --git a/web/app/components/develop/template/template.ja.mdx b/web/app/components/develop/template/template.ja.mdx index fc6291f522..4dbefca8f8 100755 --- a/web/app/components/develop/template/template.ja.mdx +++ b/web/app/components/develop/template/template.ja.mdx @@ -220,7 +220,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from - `file` (File) 必須 アップロードするファイル。 - `user` (string) 必須 - 開発者のルールで定義されたユーザー識別子。アプリケーション内で一意である必要があります。 + 開発者のルールで定義されたユーザー識別子。アプリケーション内で一意である必要があります。サービス API は WebApp によって作成された会話を共有しません。 ### レスポンス アップロードが成功すると、サーバーはファイルの ID と関連情報を返します。 @@ -289,7 +289,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from - `task_id` (string) タスク ID、ストリーミングチャンクの返信から取得可能 リクエストボディ - `user` (string) 必須 - ユーザー識別子。エンドユーザーの身元を定義するために使用され、メッセージ送信インターフェースで渡されたユーザーと一致する必要があります。 + ユーザー識別子。エンドユーザーの身元を定義するために使用され、メッセージ送信インターフェースで渡されたユーザーと一致する必要があります。サービス API は WebApp によって作成された会話を共有しません。 ### レスポンス - `result` (string) 常に"success"を返します @@ -510,6 +510,8 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from - `name` (string) アプリケーションの名前 - `description` (string) アプリケーションの説明 - `tags` (array[string]) アプリケーションのタグ + - `mode` (string) アプリケーションのモード + - `author_name` (string) 作者の名前 @@ -526,7 +528,9 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from "tags": [ "tag1", "tag2" - ] + ], + "mode": "chat", + "author_name": "Dify" } ``` diff --git a/web/app/components/develop/template/template.zh.mdx b/web/app/components/develop/template/template.zh.mdx index 9e65a4bd9b..4af5a28050 100755 --- a/web/app/components/develop/template/template.zh.mdx +++ b/web/app/components/develop/template/template.zh.mdx @@ -266,7 +266,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx' ### Request Body - `user` (string) Required - 用户标识,用于定义终端用户的身份,必须和发送消息接口传入 user 保持一致。 + 用户标识,用于定义终端用户的身份,必须和发送消息接口传入 user 保持一致。API 无法访问 WebApp 创建的会话。 ### Response - `result` (string) 固定返回 success @@ -485,6 +485,8 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx' - `name` (string) 应用名称 - `description` (string) 应用描述 - `tags` (array[string]) 应用标签 + - `mode` (string) 应用模式 + - 'author_name' (string) 作者名称 @@ -501,7 +503,9 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx' "tags": [ "tag1", "tag2" - ] + ], + "mode": "chat", + "author_name": "Dify" } ``` diff --git a/web/app/components/develop/template/template_advanced_chat.en.mdx b/web/app/components/develop/template/template_advanced_chat.en.mdx index 76e336bdf4..2e0242427b 100644 --- a/web/app/components/develop/template/template_advanced_chat.en.mdx +++ b/web/app/components/develop/template/template_advanced_chat.en.mdx @@ -59,7 +59,7 @@ Chat applications support session persistence, allowing previous chat history to User identifier, used to define the identity of the end-user for retrieval and statistics. - Should be uniquely defined by the developer within the application. + Should be uniquely defined by the developer within the application. The Service API does not share conversations created by the WebApp. Conversation ID, to continue the conversation based on previous chat records, it is necessary to pass the previous message's conversation_id. @@ -324,7 +324,7 @@ Chat applications support session persistence, allowing previous chat history to - `file` (File) Required The file to be uploaded. - `user` (string) Required - User identifier, defined by the developer's rules, must be unique within the application. + User identifier, defined by the developer's rules, must be unique within the application. The Service API does not share conversations created by the WebApp. ### Response After a successful upload, the server will return the file's ID and related information. @@ -394,7 +394,7 @@ Chat applications support session persistence, allowing previous chat history to - `task_id` (string) Task ID, can be obtained from the streaming chunk return ### Request Body - `user` (string) Required - User identifier, used to define the identity of the end-user, must be consistent with the user passed in the send message interface. + User identifier, used to define the identity of the end-user, must be consistent with the user passed in the message sending interface. The Service API does not share conversations created by the WebApp. ### Response - `result` (string) Always returns "success" @@ -448,7 +448,7 @@ Chat applications support session persistence, allowing previous chat history to Upvote as `like`, downvote as `dislike`, revoke upvote as `null` - User identifier, defined by the developer's rules, must be unique within the application. + User identifier, defined by the developer's rules, must be unique within the application. The Service API does not share conversations created by the WebApp. The specific content of message feedback. @@ -1123,6 +1123,8 @@ Chat applications support session persistence, allowing previous chat history to - `name` (string) application name - `description` (string) application description - `tags` (array[string]) application tags + - `mode` (string) application mode + - `author_name` (string) application author name @@ -1139,7 +1141,9 @@ Chat applications support session persistence, allowing previous chat history to "tags": [ "tag1", "tag2" - ] + ], + "mode": "advanced-chat", + "author_name": "Dify" } ``` diff --git a/web/app/components/develop/template/template_advanced_chat.ja.mdx b/web/app/components/develop/template/template_advanced_chat.ja.mdx index 6f94cbb2c7..535de3aa0f 100644 --- a/web/app/components/develop/template/template_advanced_chat.ja.mdx +++ b/web/app/components/develop/template/template_advanced_chat.ja.mdx @@ -59,7 +59,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from ユーザー識別子、エンドユーザーの身元を定義するために使用され、統計のために使用されます。 - アプリケーション内で開発者によって一意に定義されるべきです。 + アプリケーション内で開発者によって一意に定義されるべきです。サービス API は WebApp によって作成された会話を共有しません。 会話ID、以前のチャット記録に基づいて会話を続けるには、以前のメッセージのconversation_idを渡す必要があります。 @@ -324,7 +324,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from - `file` (File) 必須 アップロードするファイル。 - `user` (string) 必須 - ユーザー識別子、開発者のルールによって定義され、アプリケーション内で一意でなければなりません。 + ユーザー識別子、開発者のルールによって定義され、アプリケーション内で一意でなければなりません。サービス API は WebApp によって作成された会話を共有しません。 ### 応答 アップロードが成功すると、サーバーはファイルの ID と関連情報を返します。 @@ -394,7 +394,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from - `task_id` (string) タスク ID、ストリーミングチャンクの返り値から取得できます ### リクエストボディ - `user` (string) 必須 - ユーザー識別子、エンドユーザーの身元を定義するために使用され、送信メッセージインターフェースで渡されたユーザーと一致している必要があります。 + ユーザー識別子、エンドユーザーの身元を定義するために使用され、送信メッセージインターフェースで渡されたユーザーと一致している必要があります。サービス API は WebApp によって作成された会話を共有しません。 ### 応答 - `result` (string) 常に"success"を返します @@ -1123,6 +1123,8 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from - `name` (string) アプリケーションの名前 - `description` (string) アプリケーションの説明 - `tags` (array[string]) アプリケーションのタグ + - `mode` (string) アプリケーションのモード + - `author_name` (string) 作者の名前 @@ -1139,7 +1141,9 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from "tags": [ "tag1", "tag2" - ] + ], + "mode": "advanced-chat", + "author_name": "Dify" } ``` diff --git a/web/app/components/develop/template/template_advanced_chat.zh.mdx b/web/app/components/develop/template/template_advanced_chat.zh.mdx index 3e268d6e65..fa3ad3f37f 100755 --- a/web/app/components/develop/template/template_advanced_chat.zh.mdx +++ b/web/app/components/develop/template/template_advanced_chat.zh.mdx @@ -56,7 +56,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx' 用户标识,用于定义终端用户的身份,方便检索、统计。 - 由开发者定义规则,需保证用户标识在应用内唯一。 + 由开发者定义规则,需保证用户标识在应用内唯一。服务 API 不会共享 WebApp 创建的对话。 (选填)会话 ID,需要基于之前的聊天记录继续对话,必须传之前消息的 conversation_id。 @@ -402,7 +402,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx' ### Request Body - `user` (string) Required - 用户标识,用于定义终端用户的身份,必须和发送消息接口传入 user 保持一致。 + 用户标识,用于定义终端用户的身份,必须和发送消息接口传入 user 保持一致。API 无法访问 WebApp 创建的会话。 ### Response - `result` (string) 固定返回 success @@ -1173,7 +1173,9 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx' "tags": [ "tag1", "tag2" - ] + ], + "mode": "advanced-chat", + "author_name": "Dify" } ``` diff --git a/web/app/components/develop/template/template_chat.en.mdx b/web/app/components/develop/template/template_chat.en.mdx index f0cb3cd513..add80fc9ea 100644 --- a/web/app/components/develop/template/template_chat.en.mdx +++ b/web/app/components/develop/template/template_chat.en.mdx @@ -287,7 +287,7 @@ Chat applications support session persistence, allowing previous chat history to - `file` (File) Required The file to be uploaded. - `user` (string) Required - User identifier, defined by the developer's rules, must be unique within the application. + User identifier, defined by the developer's rules, must be unique within the application. The Service API does not share conversations created by the WebApp. ### Response After a successful upload, the server will return the file's ID and related information. @@ -357,7 +357,7 @@ Chat applications support session persistence, allowing previous chat history to - `task_id` (string) Task ID, can be obtained from the streaming chunk return ### Request Body - `user` (string) Required - User identifier, used to define the identity of the end-user, must be consistent with the user passed in the send message interface. + User identifier, used to define the identity of the end-user, must be consistent with the user passed in the message sending interface. The Service API does not share conversations created by the WebApp. ### Response - `result` (string) Always returns "success" @@ -1151,6 +1151,8 @@ Chat applications support session persistence, allowing previous chat history to - `name` (string) application name - `description` (string) application description - `tags` (array[string]) application tags + - `mode` (string) application mode + - `author_name` (string) application author name @@ -1167,7 +1169,9 @@ Chat applications support session persistence, allowing previous chat history to "tags": [ "tag1", "tag2" - ] + ], + "mode": "advanced-chat", + "author_name": "Dify" } ``` diff --git a/web/app/components/develop/template/template_chat.ja.mdx b/web/app/components/develop/template/template_chat.ja.mdx index a1b2ae5f1d..8368326e40 100644 --- a/web/app/components/develop/template/template_chat.ja.mdx +++ b/web/app/components/develop/template/template_chat.ja.mdx @@ -287,7 +287,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from - `file` (File) 必須 アップロードするファイル。 - `user` (string) 必須 - ユーザー識別子、開発者のルールで定義され、アプリケーション内で一意でなければなりません。 + ユーザー識別子、開発者のルールで定義され、アプリケーション内で一意でなければなりません。サービス API は WebApp によって作成された会話を共有しません。 ### 応答 アップロードが成功すると、サーバーはファイルの ID と関連情報を返します。 @@ -357,7 +357,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from - `task_id` (string) タスク ID、ストリーミングチャンクの返り値から取得できます ### リクエストボディ - `user` (string) 必須 - ユーザー識別子、エンドユーザーのアイデンティティを定義するために使用され、メッセージ送信インターフェースで渡されたユーザーと一致している必要があります。 + ユーザー識別子、エンドユーザーのアイデンティティを定義するために使用され、メッセージ送信インターフェースで渡されたユーザーと一致している必要があります。サービス API は WebApp によって作成された会話を共有しません。 ### 応答 - `result` (string) 常に"success"を返します @@ -1150,6 +1150,8 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from - `name` (string) アプリケーションの名前 - `description` (string) アプリケーションの説明 - `tags` (array[string]) アプリケーションのタグ + - `mode` (string) アプリケーションのモード + - `author_name` (string) 作者の名前 @@ -1166,7 +1168,9 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from "tags": [ "tag1", "tag2" - ] + ], + "mode": "chat", + "author_name": "Dify" } ``` diff --git a/web/app/components/develop/template/template_chat.zh.mdx b/web/app/components/develop/template/template_chat.zh.mdx index 9c1a168bf5..325470ac62 100644 --- a/web/app/components/develop/template/template_chat.zh.mdx +++ b/web/app/components/develop/template/template_chat.zh.mdx @@ -56,7 +56,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx' 用户标识,用于定义终端用户的身份,方便检索、统计。 - 由开发者定义规则,需保证用户标识在应用内唯一。 + 由开发者定义规则,需保证用户标识在应用内唯一。服务 API 不会共享 WebApp 创建的对话。 (选填)会话 ID,需要基于之前的聊天记录继续对话,必须传之前消息的 conversation_id。 @@ -306,7 +306,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx' 要上传的文件。 - 用户标识,用于定义终端用户的身份,必须和发送消息接口传入 user 保持一致。 + 用户标识,用于定义终端用户的身份,必须和发送消息接口传入 user 保持一致。服务 API 不会共享 WebApp 创建的对话。 @@ -373,7 +373,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx' ### Request Body - `user` (string) Required - 用户标识,用于定义终端用户的身份,必须和发送消息接口传入 user 保持一致。 + 用户标识,用于定义终端用户的身份,必须和发送消息接口传入 user 保持一致。API 无法访问 WebApp 创建的会话。 ### Response - `result` (string) 固定返回 success @@ -425,7 +425,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx' 点赞 like, 点踩 dislike, 撤销点赞 null - 用户标识,由开发者定义规则,需保证用户标识在应用内唯一。 + 用户标识,由开发者定义规则,需保证用户标识在应用内唯一。服务 API 不会共享 WebApp 创建的对话。 消息反馈的具体信息。 @@ -1162,6 +1162,8 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx' - `name` (string) 应用名称 - `description` (string) 应用描述 - `tags` (array[string]) 应用标签 + - `mode` (string) 应用模式 + - 'author_name' (string) 作者名称 @@ -1178,7 +1180,9 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx' "tags": [ "tag1", "tag2" - ] + ], + "mode": "chat", + "author_name": "Dify" } ``` diff --git a/web/app/components/develop/template/template_workflow.en.mdx b/web/app/components/develop/template/template_workflow.en.mdx index 95e4971e67..0ceeadf4ed 100644 --- a/web/app/components/develop/template/template_workflow.en.mdx +++ b/web/app/components/develop/template/template_workflow.en.mdx @@ -64,6 +64,8 @@ Workflow applications offers non-session support and is ideal for translation, a - `user` (string) Required User identifier, used to define the identity of the end-user for retrieval and statistics. Should be uniquely defined by the developer within the application. +
+ The user identifier should be consistent with the user passed in the message sending interface. The Service API does not share conversations created by the WebApp. ### Response When `response_mode` is `blocking`, return a CompletionResponse object. @@ -401,7 +403,7 @@ Workflow applications offers non-session support and is ideal for translation, a - `task_id` (string) Task ID, can be obtained from the streaming chunk return ### Request Body - `user` (string) Required - User identifier, used to define the identity of the end-user, must be consistent with the user passed in the send message interface. + User identifier, used to define the identity of the end-user, must be consistent with the user passed in the message sending interface. The Service API does not share conversations created by the WebApp. ### Response - `result` (string) Always returns "success" @@ -448,7 +450,7 @@ Workflow applications offers non-session support and is ideal for translation, a - `file` (File) Required The file to be uploaded. - `user` (string) Required - User identifier, defined by the developer's rules, must be unique within the application. + User identifier, defined by the developer's rules, must be unique within the application. The Service API does not share conversations created by the WebApp. ### Response After a successful upload, the server will return the file's ID and related information. @@ -625,6 +627,8 @@ Workflow applications offers non-session support and is ideal for translation, a - `name` (string) application name - `description` (string) application description - `tags` (array[string]) application tags + - `mode` (string) application mode + - `author_name` (string) application author name @@ -641,7 +645,9 @@ Workflow applications offers non-session support and is ideal for translation, a "tags": [ "tag1", "tag2" - ] + ], + "mode": "workflow", + "author_name": "Dify" } ``` diff --git a/web/app/components/develop/template/template_workflow.ja.mdx b/web/app/components/develop/template/template_workflow.ja.mdx index ab53d05e81..4f7e423ea5 100644 --- a/web/app/components/develop/template/template_workflow.ja.mdx +++ b/web/app/components/develop/template/template_workflow.ja.mdx @@ -404,7 +404,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from - `task_id` (string) タスク ID、ストリーミングチャンクの返り値から取得可能 ### リクエストボディ - `user` (string) 必須 - ユーザー識別子、エンドユーザーのアイデンティティを定義するために使用され、送信メッセージインターフェースで渡されたユーザーと一致している必要があります。 + ユーザー識別子、エンドユーザーのアイデンティティを定義するために使用され、送信メッセージインターフェースで渡されたユーザーと一致している必要があります。サービス API は WebApp によって作成された会話を共有しません。 ### 応答 - `result` (string) 常に"success"を返します @@ -451,7 +451,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from - `file` (File) 必須 アップロードするファイル。 - `user` (string) 必須 - ユーザー識別子、開発者のルールで定義され、アプリケーション内で一意でなければなりません。 + ユーザー識別子、開発者のルールで定義され、アプリケーション内で一意でなければなりません。サービス API は WebApp によって作成された会話を共有しません。 ### 応答 アップロードが成功すると、サーバーはファイルの ID と関連情報を返します。 @@ -628,6 +628,8 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from - `name` (string) アプリケーションの名前 - `description` (string) アプリケーションの説明 - `tags` (array[string]) アプリケーションのタグ + - `mode` (string) アプリケーションのモード + - `author_name` (string) 作者の名前 @@ -644,7 +646,9 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from "tags": [ "tag1", "tag2" - ] + ], + "mode": "workflow", + "author_name": "Dify" } ``` diff --git a/web/app/components/develop/template/template_workflow.zh.mdx b/web/app/components/develop/template/template_workflow.zh.mdx index fe59988eda..d599cb503f 100644 --- a/web/app/components/develop/template/template_workflow.zh.mdx +++ b/web/app/components/develop/template/template_workflow.zh.mdx @@ -59,7 +59,7 @@ Workflow 应用无会话支持,适合用于翻译/文章写作/总结 AI 等 由于 Cloudflare 限制,请求会在 100 秒超时无返回后中断。 - `user` (string) Required 用户标识,用于定义终端用户的身份,方便检索、统计。 - 由开发者定义规则,需保证用户标识在应用内唯一。 + 由开发者定义规则,需保证用户标识在应用内唯一。API 无法访问 WebApp 创建的会话。 ### Response @@ -394,7 +394,7 @@ Workflow 应用无会话支持,适合用于翻译/文章写作/总结 AI 等 - `task_id` (string) 任务 ID,可在流式返回 Chunk 中获取 ### Request Body - `user` (string) Required - 用户标识,用于定义终端用户的身份,必须和发送消息接口传入 user 保持一致。 + 用户标识,用于定义终端用户的身份,必须和发送消息接口传入 user 保持一致。API 无法访问 WebApp 创建的会话。 ### Response - `result` (string) 固定返回 "success" @@ -443,7 +443,7 @@ Workflow 应用无会话支持,适合用于翻译/文章写作/总结 AI 等 要上传的文件。
- 用户标识,用于定义终端用户的身份,必须和发送消息接口传入 user 保持一致。 + 用户标识,用于定义终端用户的身份,必须和发送消息接口传入 user 保持一致。服务 API 不会共享 WebApp 创建的对话。 @@ -615,6 +615,8 @@ Workflow 应用无会话支持,适合用于翻译/文章写作/总结 AI 等 - `name` (string) 应用名称 - `description` (string) 应用描述 - `tags` (array[string]) 应用标签 + - `mode` (string) 应用模式 + - 'author_name' (string) 作者名称 @@ -631,7 +633,9 @@ Workflow 应用无会话支持,适合用于翻译/文章写作/总结 AI 等 "tags": [ "tag1", "tag2" - ] + ], + "mode": "workflow", + "author_name": "Dify" } ``` diff --git a/web/app/components/header/account-dropdown/index.tsx b/web/app/components/header/account-dropdown/index.tsx index 6648a4a2e8..08a61b7391 100644 --- a/web/app/components/header/account-dropdown/index.tsx +++ b/web/app/components/header/account-dropdown/index.tsx @@ -23,7 +23,6 @@ import GithubStar from '../github-star' import Support from './support' import Compliance from './compliance' import PremiumBadge from '@/app/components/base/premium-badge' -import { useGetDocLanguage } from '@/context/i18n' import Avatar from '@/app/components/base/avatar' import ThemeSwitcher from '@/app/components/base/theme-switcher' import { logout } from '@/service/common' @@ -33,6 +32,7 @@ import { useModalContext } from '@/context/modal-context' import { IS_CLOUD_EDITION } from '@/config' import cn from '@/utils/classnames' import { useGlobalPublicStore } from '@/context/global-public-context' +import { useDocLink } from '@/context/i18n' export default function AppSelector() { const itemClassName = ` @@ -44,10 +44,10 @@ export default function AppSelector() { const { systemFeatures } = useGlobalPublicStore() const { t } = useTranslation() + const docLink = useDocLink() const { userProfile, langeniusVersionInfo, isCurrentWorkspaceOwner } = useAppContext() const { isEducationAccount } = useProviderContext() const { setShowAccountSettingModal } = useModalContext() - const docLanguage = useGetDocLanguage() const handleLogout = async () => { await logout({ @@ -133,7 +133,7 @@ export default function AppSelector() { className={cn(itemClassName, 'group justify-between', 'data-[active]:bg-state-base-hover', )} - href={`https://docs.dify.ai/${docLanguage}/introduction`} + href={docLink('/introduction')} target='_blank' rel='noopener noreferrer'>
{t('common.userProfile.helpCenter')}
diff --git a/web/app/components/plugins/plugin-detail-panel/endpoint-list.tsx b/web/app/components/plugins/plugin-detail-panel/endpoint-list.tsx index 59a457ecbd..b31b45c0c7 100644 --- a/web/app/components/plugins/plugin-detail-panel/endpoint-list.tsx +++ b/web/app/components/plugins/plugin-detail-panel/endpoint-list.tsx @@ -1,6 +1,6 @@ import React, { useMemo } from 'react' import { useTranslation } from 'react-i18next' -import { useContext } from 'use-context-selector' +import { useDocLink } from '@/context/i18n' import { useBoolean } from 'ahooks' import { RiAddLine, @@ -20,8 +20,6 @@ import { useInvalidateEndpointList, } from '@/service/use-endpoints' import type { PluginDetail } from '@/app/components/plugins/types' -import { LanguagesSupported } from '@/i18n/language' -import I18n from '@/context/i18n' import cn from '@/utils/classnames' type Props = { @@ -29,7 +27,7 @@ type Props = { } const EndpointList = ({ detail }: Props) => { const { t } = useTranslation() - const { locale } = useContext(I18n) + const docLink = useDocLink() const pluginUniqueID = detail.plugin_unique_identifier const declaration = detail.declaration.endpoint const showTopBorder = detail.declaration.tool @@ -79,7 +77,7 @@ const EndpointList = ({ detail }: Props) => {
{t('plugin.detailPanel.endpointsTip')}
diff --git a/web/app/components/tools/provider/custom-create-card.tsx b/web/app/components/tools/provider/custom-create-card.tsx index 6dd268cb3a..f64daba8cd 100644 --- a/web/app/components/tools/provider/custom-create-card.tsx +++ b/web/app/components/tools/provider/custom-create-card.tsx @@ -14,6 +14,7 @@ import EditCustomToolModal from '@/app/components/tools/edit-custom-collection-m import { createCustomCollection } from '@/service/tools' import Toast from '@/app/components/base/toast' import { useAppContext } from '@/context/app-context' +import { useDocLink } from '@/context/i18n' type Props = { onRefreshData: () => void @@ -25,10 +26,11 @@ const Contribute = ({ onRefreshData }: Props) => { const language = getLanguage(locale) const { isCurrentWorkspaceManager } = useAppContext() + const docLink = useDocLink() const linkUrl = useMemo(() => { - if (language.startsWith('zh_')) - return 'https://docs.dify.ai/zh-hans/guides/tools#ru-he-chuang-jian-zi-ding-yi-gong-ju' - return 'https://docs.dify.ai/en/guides/tools#how-to-create-custom-tools' + return docLink('/guides/tools#how-to-create-custom-tools', { + 'zh-Hans': '/guides/tools#ru-he-chuang-jian-zi-ding-yi-gong-ju', + }) }, [language]) const [isShowEditCollectionToolModal, setIsShowEditCustomCollectionModal] = useState(false) diff --git a/web/app/components/workflow/nodes/_base/components/agent-strategy.tsx b/web/app/components/workflow/nodes/_base/components/agent-strategy.tsx index de23602e34..912d0b5853 100644 --- a/web/app/components/workflow/nodes/_base/components/agent-strategy.tsx +++ b/web/app/components/workflow/nodes/_base/components/agent-strategy.tsx @@ -19,9 +19,7 @@ import { useWorkflowStore } from '../../../store' import { useRenderI18nObject } from '@/hooks/use-i18n' import type { NodeOutPutVar } from '../../../types' import type { Node } from 'reactflow' -import { useContext } from 'use-context-selector' -import I18n from '@/context/i18n' -import { LanguagesSupported } from '@/i18n/language' +import { useDocLink } from '@/context/i18n' export type Strategy = { agent_strategy_provider_name: string @@ -52,7 +50,7 @@ type CustomField = ToolSelectorSchema | MultipleToolSelectorSchema export const AgentStrategy = memo((props: AgentStrategyProps) => { const { strategy, onStrategyChange, formSchema, formValue, onFormValueChange, nodeOutputVars, availableNodes, nodeId } = props const { t } = useTranslation() - const { locale } = useContext(I18n) + const docLink = useDocLink() const defaultModel = useDefaultModel(ModelTypeEnum.textGeneration) const renderI18nObject = useRenderI18nObject() const workflowStore = useWorkflowStore() @@ -223,11 +221,10 @@ export const AgentStrategy = memo((props: AgentStrategyProps) => { title={t('workflow.nodes.agent.strategy.configureTip')} description={
{t('workflow.nodes.agent.strategy.configureTipDesc')}
- + {t('workflow.nodes.agent.learnMore')}
} diff --git a/web/app/components/workflow/nodes/_base/components/error-handle/default-value.tsx b/web/app/components/workflow/nodes/_base/components/error-handle/default-value.tsx index 51969f8510..6bfb7755dc 100644 --- a/web/app/components/workflow/nodes/_base/components/error-handle/default-value.tsx +++ b/web/app/components/workflow/nodes/_base/components/error-handle/default-value.tsx @@ -5,6 +5,7 @@ import Input from '@/app/components/base/input' import { VarType } from '@/app/components/workflow/types' import { CodeLanguage } from '@/app/components/workflow/nodes/code/types' import CodeEditor from '@/app/components/workflow/nodes/_base/components/editor/code-editor' +import { useDocLink } from '@/context/i18n' type DefaultValueProps = { forms: DefaultValueForm[] @@ -15,6 +16,7 @@ const DefaultValue = ({ onFormChange, }: DefaultValueProps) => { const { t } = useTranslation() + const docLink = useDocLink() const getFormChangeHandler = useCallback(({ key, type }: DefaultValueForm) => { return (payload: any) => { let value @@ -34,7 +36,7 @@ const DefaultValue = ({ {t('workflow.nodes.common.errorHandle.defaultValue.desc')}  
diff --git a/web/app/components/workflow/nodes/_base/components/error-handle/fail-branch-card.tsx b/web/app/components/workflow/nodes/_base/components/error-handle/fail-branch-card.tsx index 05a6cb96af..fa9cff3dc8 100644 --- a/web/app/components/workflow/nodes/_base/components/error-handle/fail-branch-card.tsx +++ b/web/app/components/workflow/nodes/_base/components/error-handle/fail-branch-card.tsx @@ -1,8 +1,10 @@ import { RiMindMap } from '@remixicon/react' import { useTranslation } from 'react-i18next' +import { useDocLink } from '@/context/i18n' const FailBranchCard = () => { const { t } = useTranslation() + const docLink = useDocLink() return (
@@ -17,7 +19,7 @@ const FailBranchCard = () => { {t('workflow.nodes.common.errorHandle.failBranch.customizeTip')}   diff --git a/web/app/components/workflow/nodes/_base/components/variable/var-reference-popup.tsx b/web/app/components/workflow/nodes/_base/components/variable/var-reference-popup.tsx index 6be35ec146..f8d5426017 100644 --- a/web/app/components/workflow/nodes/_base/components/variable/var-reference-popup.tsx +++ b/web/app/components/workflow/nodes/_base/components/variable/var-reference-popup.tsx @@ -2,13 +2,11 @@ import type { FC } from 'react' import React, { useMemo } from 'react' import { useTranslation } from 'react-i18next' -import { useContext } from 'use-context-selector' import VarReferenceVars from './var-reference-vars' import type { NodeOutPutVar, ValueSelector, Var } from '@/app/components/workflow/types' import ListEmpty from '@/app/components/base/list-empty' -import { LanguagesSupported } from '@/i18n/language' -import I18n from '@/context/i18n' import { useStore } from '@/app/components/workflow/store' +import { useDocLink } from '@/context/i18n' type Props = { vars: NodeOutPutVar[] @@ -25,10 +23,10 @@ const VarReferencePopup: FC = ({ isSupportFileVar = true, }) => { const { t } = useTranslation() - const { locale } = useContext(I18n) const pipelineId = useStore(s => s.pipelineId) const showManageRagInputFields = useMemo(() => !!pipelineId, [pipelineId]) const setShowInputFieldDialog = useStore(s => s.setShowInputFieldDialog) + const docLink = useDocLink() // max-h-[300px] overflow-y-auto todo: use portal to handle long list return (
= ({ description={
{t('workflow.variableReference.assignedVarsDescription')} {t('workflow.variableReference.conversationVars')} + className='text-text-accent-secondary' + href={docLink('/guides/workflow/variables#conversation-variables', { 'zh-Hans': '/guides/workflow/variables#hui-hua-bian-liang' })}> + {t('workflow.variableReference.conversationVars')} +
} /> )) diff --git a/web/app/components/workflow/nodes/llm/components/json-schema-config-modal/json-schema-config.tsx b/web/app/components/workflow/nodes/llm/components/json-schema-config-modal/json-schema-config.tsx index 2b8574b285..fecd1093d9 100644 --- a/web/app/components/workflow/nodes/llm/components/json-schema-config-modal/json-schema-config.tsx +++ b/web/app/components/workflow/nodes/llm/components/json-schema-config-modal/json-schema-config.tsx @@ -21,8 +21,8 @@ import { MittProvider, VisualEditorContextProvider, useMittContext } from './vis import ErrorMessage from './error-message' import { useVisualEditorStore } from './visual-editor/store' import Toast from '@/app/components/base/toast' -import { useGetDocLanguage } from '@/context/i18n' import { JSON_SCHEMA_MAX_DEPTH } from '@/config' +import { useDocLink } from '@/context/i18n' type JsonSchemaConfigProps = { defaultSchema?: SchemaRoot @@ -53,7 +53,7 @@ const JsonSchemaConfig: FC = ({ onClose, }) => { const { t } = useTranslation() - const docLanguage = useGetDocLanguage() + const docLink = useDocLink() const [currentTab, setCurrentTab] = useState(SchemaView.VisualEditor) const [jsonSchema, setJsonSchema] = useState(defaultSchema || DEFAULT_SCHEMA) const [json, setJson] = useState(JSON.stringify(jsonSchema, null, 2)) @@ -252,7 +252,7 @@ const JsonSchemaConfig: FC = ({
diff --git a/web/app/components/workflow/panel/chat-variable-panel/index.tsx b/web/app/components/workflow/panel/chat-variable-panel/index.tsx index ad00bddd0c..be9ef36a6b 100644 --- a/web/app/components/workflow/panel/chat-variable-panel/index.tsx +++ b/web/app/components/workflow/panel/chat-variable-panel/index.tsx @@ -3,7 +3,6 @@ import { useCallback, useState, } from 'react' -import { useContext } from 'use-context-selector' import { useStoreApi, } from 'reactflow' @@ -22,13 +21,12 @@ import type { import { findUsedVarNodes, updateNodeVars } from '@/app/components/workflow/nodes/_base/components/variable/utils' import { useNodesSyncDraft } from '@/app/components/workflow/hooks/use-nodes-sync-draft' import { BlockEnum } from '@/app/components/workflow/types' -import I18n from '@/context/i18n' -import { LanguagesSupported } from '@/i18n/language' +import { useDocLink } from '@/context/i18n' import cn from '@/utils/classnames' const ChatVariablePanel = () => { const { t } = useTranslation() - const { locale } = useContext(I18n) + const docLink = useDocLink() const store = useStoreApi() const setShowChatVariablePanel = useStore(s => s.setShowChatVariablePanel) const varList = useStore(s => s.conversationVariables) as ConversationVariable[] @@ -139,8 +137,11 @@ const ChatVariablePanel = () => {
TIPS
+ + {t('workflow.chatVariable.docLink')} + +
diff --git a/web/app/components/workflow/run/node.tsx b/web/app/components/workflow/run/node.tsx index 10f641cc8f..9555cbd087 100644 --- a/web/app/components/workflow/run/node.tsx +++ b/web/app/components/workflow/run/node.tsx @@ -28,6 +28,7 @@ import type { } from '@/types/workflow' import ErrorHandleTip from '@/app/components/workflow/nodes/_base/components/error-handle/error-handle-tip' import { hasRetryNode } from '@/app/components/workflow/utils' +import { useDocLink } from '@/context/i18n' type Props = { className?: string @@ -65,6 +66,7 @@ const NodePanel: FC = ({ doSetCollapseState(state) }, [hideProcessDetail]) const { t } = useTranslation() + const docLink = useDocLink() const getTime = (time: number) => { if (time < 1) @@ -195,7 +197,7 @@ const NodePanel: FC = ({ {nodeInfo.error} diff --git a/web/app/components/workflow/run/status.tsx b/web/app/components/workflow/run/status.tsx index 2f870f2e06..253aaab3a1 100644 --- a/web/app/components/workflow/run/status.tsx +++ b/web/app/components/workflow/run/status.tsx @@ -4,6 +4,7 @@ import { useTranslation } from 'react-i18next' import cn from '@/utils/classnames' import Indicator from '@/app/components/header/indicator' import StatusContainer from '@/app/components/workflow/run/status-container' +import { useDocLink } from '@/context/i18n' type ResultProps = { status: string @@ -21,6 +22,7 @@ const StatusPanel: FC = ({ exceptionCounts, }) => { const { t } = useTranslation() + const docLink = useDocLink() return ( @@ -134,7 +136,7 @@ const StatusPanel: FC = ({
{error} diff --git a/web/app/education-apply/education-apply-page.tsx b/web/app/education-apply/education-apply-page.tsx index 980e36eb93..3925695895 100644 --- a/web/app/education-apply/education-apply-page.tsx +++ b/web/app/education-apply/education-apply-page.tsx @@ -1,7 +1,6 @@ 'use client' import { - useMemo, useState, } from 'react' import { useTranslation } from 'react-i18next' @@ -23,13 +22,11 @@ import { import { useProviderContext } from '@/context/provider-context' import { useToastContext } from '@/app/components/base/toast' import { EDUCATION_VERIFYING_LOCALSTORAGE_ITEM } from '@/app/education-apply/constants' -import { getLocaleOnClient } from '@/i18n' import { noop } from 'lodash-es' import DifyLogo from '../components/base/logo/dify-logo' - +import { useDocLink } from '@/context/i18n' const EducationApplyAge = () => { const { t } = useTranslation() - const locale = getLocaleOnClient() const [schoolName, setSchoolName] = useState('') const [role, setRole] = useState('Student') const [ageChecked, setAgeChecked] = useState(false) @@ -43,14 +40,7 @@ const EducationApplyAge = () => { const updateEducationStatus = useInvalidateEducationStatus() const { notify } = useToastContext() const router = useRouter() - - const docLink = useMemo(() => { - if (locale === 'zh-Hans') - return 'https://docs.dify.ai/zh-hans/getting-started/dify-for-education' - if (locale === 'ja-JP') - return 'https://docs.dify.ai/ja-jp/getting-started/dify-for-education' - return 'https://docs.dify.ai/getting-started/dify-for-education' - }, [locale]) + const docLink = useDocLink() const handleModalConfirm = () => { setShowModal(undefined) @@ -167,7 +157,7 @@ const EducationApplyAge = () => {
{t('education.learn')} diff --git a/web/app/education-apply/verify-state-modal.tsx b/web/app/education-apply/verify-state-modal.tsx index aace6a3bb1..2ea2fe5bae 100644 --- a/web/app/education-apply/verify-state-modal.tsx +++ b/web/app/education-apply/verify-state-modal.tsx @@ -1,11 +1,11 @@ -import React, { useEffect, useMemo, useRef, useState } from 'react' +import React, { useEffect, useRef, useState } from 'react' import { createPortal } from 'react-dom' import { useTranslation } from 'react-i18next' import { RiExternalLinkLine, } from '@remixicon/react' import Button from '@/app/components/base/button' -import { getLocaleOnClient } from '@/i18n' +import { useDocLink } from '@/context/i18n' export type IConfirm = { className?: string @@ -30,20 +30,13 @@ function Confirm({ email, }: IConfirm) { const { t } = useTranslation() - const locale = getLocaleOnClient() + const docLink = useDocLink() const dialogRef = useRef(null) const [isVisible, setIsVisible] = useState(isShow) - - const docLink = useMemo(() => { - if (locale === 'zh-Hans') - return 'https://docs.dify.ai/zh-hans/getting-started/dify-for-education' - if (locale === 'ja-JP') - return 'https://docs.dify.ai/ja-jp/getting-started/dify-for-education' - return 'https://docs.dify.ai/getting-started/dify-for-education' - }, [locale]) + const eduDocLink = docLink('/getting-started/dify-for-education') const handleClick = () => { - window.open(docLink, '_blank', 'noopener,noreferrer') + window.open(eduDocLink, '_blank', 'noopener,noreferrer') } useEffect(() => { @@ -106,7 +99,7 @@ function Confirm({
{showLink && ( <> - {t('education.learn')} + {t('education.learn')} )} diff --git a/web/app/install/installForm.tsx b/web/app/install/installForm.tsx index e549eba521..c4f4cae626 100644 --- a/web/app/install/installForm.tsx +++ b/web/app/install/installForm.tsx @@ -17,6 +17,7 @@ import Button from '@/app/components/base/button' import { fetchInitValidateStatus, fetchSetupStatus, setup } from '@/service/common' import type { InitValidateStatusResponse, SetupStatusResponse } from '@/models/common' import useDocumentTitle from '@/hooks/use-document-title' +import { useDocLink } from '@/context/i18n' const validPassword = /^(?=.*[a-zA-Z])(?=.*\d).{8,}$/ @@ -36,6 +37,7 @@ type AccountFormValues = z.infer const InstallForm = () => { useDocumentTitle('') const { t } = useTranslation() + const docLink = useDocLink() const router = useRouter() const [showPassword, setShowPassword] = React.useState(false) const [loading, setLoading] = React.useState(true) @@ -174,7 +176,7 @@ const InstallForm = () => { {t('login.license.link')}
diff --git a/web/app/signin/invite-settings/page.tsx b/web/app/signin/invite-settings/page.tsx index 925bc51f16..0480c2acb8 100644 --- a/web/app/signin/invite-settings/page.tsx +++ b/web/app/signin/invite-settings/page.tsx @@ -1,5 +1,6 @@ 'use client' import { useTranslation } from 'react-i18next' +import { useDocLink } from '@/context/i18n' import { useCallback, useState } from 'react' import Link from 'next/link' import { useContext } from 'use-context-selector' @@ -18,10 +19,11 @@ import Toast from '@/app/components/base/toast' export default function InviteSettingsPage() { const { t } = useTranslation() + const docLink = useDocLink() const router = useRouter() const searchParams = useSearchParams() const token = decodeURIComponent(searchParams.get('invite_token') as string) - const { locale, setLocaleOnClient } = useContext(I18n) + const { setLocaleOnClient } = useContext(I18n) const [name, setName] = useState('') const [language, setLanguage] = useState(LanguagesSupported[0]) const [timezone, setTimezone] = useState(Intl.DateTimeFormat().resolvedOptions().timeZone || 'America/Los_Angeles') @@ -147,7 +149,7 @@ export default function InviteSettingsPage() { {t('login.license.link')}
diff --git a/web/app/signin/oneMoreStep.tsx b/web/app/signin/oneMoreStep.tsx index 7a326a13de..06a9ddba90 100644 --- a/web/app/signin/oneMoreStep.tsx +++ b/web/app/signin/oneMoreStep.tsx @@ -12,6 +12,7 @@ import { timezones } from '@/utils/timezone' import { LanguagesSupported, languages } from '@/i18n/language' import { oneMoreStep } from '@/service/common' import Toast from '@/app/components/base/toast' +import { useDocLink } from '@/context/i18n' type IState = { formState: 'processing' | 'error' | 'success' | 'initial' @@ -51,6 +52,7 @@ const reducer: Reducer = (state: IState, action: IAction) => { const OneMoreStep = () => { const { t } = useTranslation() + const docLink = useDocLink() const router = useRouter() const searchParams = useSearchParams() @@ -164,7 +166,7 @@ const OneMoreStep = () => { {t('login.license.link')}
diff --git a/web/context/i18n.ts b/web/context/i18n.ts index 463e01d1c5..8a78c933fa 100644 --- a/web/context/i18n.ts +++ b/web/context/i18n.ts @@ -35,4 +35,17 @@ export const useGetPricingPageLanguage = () => { return getPricingPageLanguage(locale) } +const defaultDocBaseUrl = 'https://docs.dify.ai' +export const useDocLink = (baseUrl?: string): ((path?: string, pathMap?: { [index: string]: string }) => string) => { + let baseDocUrl = baseUrl || defaultDocBaseUrl + baseDocUrl = (baseDocUrl.endsWith('/')) ? baseDocUrl.slice(0, -1) : baseDocUrl + const { locale } = useI18N() + const docLanguage = getDocLanguage(locale) + return (path?: string, pathMap?: { [index: string]: string }): string => { + const pathUrl = path || '' + let targetPath = (pathMap) ? pathMap[locale] || pathUrl : pathUrl + targetPath = (targetPath.startsWith('/')) ? targetPath.slice(0, -1) : targetPath + return `${baseDocUrl}/${docLanguage}/${targetPath}` + } +} export default I18NContext diff --git a/web/i18n/ja-JP/education.ts b/web/i18n/ja-JP/education.ts index 4fae5ac28e..20544b1dee 100644 --- a/web/i18n/ja-JP/education.ts +++ b/web/i18n/ja-JP/education.ts @@ -2,7 +2,7 @@ const translation = { toVerified: '教育認証を取得', toVerifiedTip: { front: '現在、教育認証ステータスを取得する資格があります。以下に教育情報を入力し、認証プロセスを完了すると、Dify プロフェッショナルプランの', - coupon: '50%割引クーポン', + coupon: '100%割引クーポン', end: 'を受け取ることができます。', }, currentSigned: '現在ログイン中のアカウントは', @@ -38,9 +38,9 @@ const translation = { submitError: 'フォームの送信に失敗しました。しばらくしてから再度ご提出ください。', learn: '教育認証の取得方法はこちら', successTitle: 'Dify 教育認証を取得しました!', - successContent: 'お客様のアカウントに Dify プロフェッショナルプランの 50% 割引クーポン を発行しました。有効期間は 1 年間 ですので、期限内にご利用ください。', + successContent: 'お客様のアカウントに Dify プロフェッショナルプランの 100% 割引クーポン を発行しました。有効期間は 1 年間 ですので、期限内にご利用ください。', rejectTitle: 'Dify 教育認証が拒否されました', - rejectContent: '申し訳ございませんが、このメールアドレスでは 教育認証 の資格を取得できず、Dify プロフェッショナルプランの 50%割引クーポン を受け取ることはできません。', + rejectContent: '申し訳ございませんが、このメールアドレスでは 教育認証 の資格を取得できず、Dify プロフェッショナルプランの 100%割引クーポン を受け取ることはできません。', emailLabel: '現在のメールアドレス', }