| @@ -25,9 +25,8 @@ import Loading from '@/app/components/base/loading' | |||
| import DatasetDetailContext from '@/context/dataset-detail' | |||
| import { DataSourceType } from '@/models/datasets' | |||
| import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints' | |||
| import { LanguagesSupported } from '@/i18n/language' | |||
| import { useStore } from '@/app/components/app/store' | |||
| import { getLocaleOnClient } from '@/i18n' | |||
| 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' | |||
| @@ -45,9 +44,9 @@ type IExtraInfoProps = { | |||
| } | |||
| const ExtraInfo = ({ isMobile, relatedApps, expand }: IExtraInfoProps) => { | |||
| const locale = getLocaleOnClient() | |||
| const [isShowTips, { toggle: toggleTips, set: setShowTips }] = useBoolean(!isMobile) | |||
| const { t } = useTranslation() | |||
| const docLink = useDocLink() | |||
| const hasRelatedApps = relatedApps?.data && relatedApps?.data?.length > 0 | |||
| const relatedAppsTotal = relatedApps?.data?.length || 0 | |||
| @@ -97,11 +96,7 @@ const ExtraInfo = ({ isMobile, relatedApps, expand }: IExtraInfoProps) => { | |||
| <div className='my-2 text-xs text-text-tertiary'>{t('common.datasetMenus.emptyTip')}</div> | |||
| <a | |||
| className='mt-2 inline-flex cursor-pointer items-center text-xs text-text-accent' | |||
| href={ | |||
| locale === LanguagesSupported[1] | |||
| ? 'https://docs.dify.ai/zh-hans/guides/knowledge-base/integrate-knowledge-within-application' | |||
| : 'https://docs.dify.ai/guides/knowledge-base/integrate-knowledge-within-application' | |||
| } | |||
| href={docLink('/guides/knowledge-base/integrate-knowledge-within-application')} | |||
| target='_blank' rel='noopener noreferrer' | |||
| > | |||
| <RiBookOpenLine className='mr-1 text-text-accent' /> | |||
| @@ -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<Props> = ({ | |||
| onShowEditModal, | |||
| }) => { | |||
| const { t } = useTranslation() | |||
| const { locale } = useContext(I18n) | |||
| const docLink = useDocLink() | |||
| return ( | |||
| <Panel | |||
| @@ -45,9 +43,8 @@ const HistoryPanel: FC<Props> = ({ | |||
| {showWarning && ( | |||
| <div className='flex justify-between rounded-b-xl bg-background-section-burn px-3 py-2 text-xs text-text-secondary'> | |||
| <div>{t('appDebug.feature.conversationHistory.tip')} | |||
| <a href={`${locale === LanguagesSupported[1] | |||
| ? 'https://docs.dify.ai/zh-hans/learn-more/extended-reading/prompt-engineering/README' | |||
| : 'https://docs.dify.ai/en/features/prompt-engineering'}`} | |||
| <a href={docLink('/learn-more/extended-reading/what-is-llmops', | |||
| { 'zh-Hans': '/learn-more/extended-reading/prompt-engineering/README' })} | |||
| target='_blank' rel='noopener noreferrer' | |||
| className='text-[#155EEF]'>{t('appDebug.feature.conversationHistory.learnMore')} | |||
| </a> | |||
| @@ -31,6 +31,7 @@ import { | |||
| import { ModelTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations' | |||
| import { fetchMembers } from '@/service/common' | |||
| import type { Member } from '@/models/common' | |||
| import { useDocLink } from '@/context/i18n' | |||
| type SettingsModalProps = { | |||
| currentDataset: DataSet | |||
| @@ -58,6 +59,7 @@ const SettingsModal: FC<SettingsModalProps> = ({ | |||
| currentModel: isRerankDefaultModelValid, | |||
| } = useModelListAndDefaultModelAndCurrentProviderAndModel(ModelTypeEnum.rerank) | |||
| const { t } = useTranslation() | |||
| const docLink = useDocLink() | |||
| const { notify } = useToastContext() | |||
| const ref = useRef(null) | |||
| const isExternal = currentDataset.provider === 'external' | |||
| @@ -328,7 +330,7 @@ const SettingsModal: FC<SettingsModalProps> = ({ | |||
| <div> | |||
| <div className='system-sm-semibold text-text-secondary'>{t('datasetSettings.form.retrievalSetting.title')}</div> | |||
| <div className='text-xs font-normal leading-[18px] text-text-tertiary'> | |||
| <a target='_blank' rel='noopener noreferrer' href='https://docs.dify.ai/guides/knowledge-base/create-knowledge-and-upload-documents#id-4-retrieval-settings' className='text-text-accent'>{t('datasetSettings.form.retrievalSetting.learnMore')}</a> | |||
| <a target='_blank' rel='noopener noreferrer' href={docLink('/guides/knowledge-base/create-knowledge-and-upload-documents/setting-indexing-methods#setting-the-retrieval-setting')} className='text-text-accent'>{t('datasetSettings.form.retrievalSetting.learnMore')}</a> | |||
| {t('datasetSettings.form.retrievalSetting.description')} | |||
| </div> | |||
| </div> | |||
| @@ -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<Props> = ({ | |||
| 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<Props> = ({ | |||
| <span className='text-gray-700'>{t('appDebug.promptMode.advancedWarning.description')}</span> | |||
| <a | |||
| className='font-medium text-[#155EEF]' | |||
| href={`https://docs.dify.ai/${locale === LanguagesSupported[1] ? '/guides/features/prompt-engineering' : 'features/prompt-engineering'}`} | |||
| href={docLink('/guides/features/prompt-engineering')} | |||
| target='_blank' rel='noopener noreferrer' | |||
| > | |||
| {t('appDebug.promptMode.advancedWarning.learnMore')} | |||
| @@ -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] | |||
| @@ -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<IShareLinkProps> = ({ | |||
| mode, | |||
| }) => { | |||
| const { t } = useTranslation() | |||
| const { locale } = useContext(I18n) | |||
| const docLink = useDocLink() | |||
| const isChatApp = mode === 'chat' || mode === 'advanced-chat' | |||
| return <Modal | |||
| @@ -101,10 +99,7 @@ const CustomizeModal: FC<IShareLinkProps> = ({ | |||
| 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', | |||
| ) | |||
| } | |||
| @@ -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<ISettingsModalProps> = ({ | |||
| 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<AppIconSelection>( | |||
| @@ -238,7 +237,8 @@ const SettingsModal: FC<ISettingsModalProps> = ({ | |||
| </div> | |||
| <div className='system-xs-regular mt-0.5 text-text-tertiary'> | |||
| <span>{t(`${prefixSettings}.modalTip`)}</span> | |||
| <Link href={`${locale === LanguagesSupported[1] ? 'https://docs.dify.ai/zh-hans/guides/application-publishing/launch-your-webapp-quickly#she-zhi-ni-de-ai-zhan-dian' : 'https://docs.dify.ai/en/guides/application-publishing/launch-your-webapp-quickly/README'}`} target='_blank' rel='noopener noreferrer' className='text-text-accent'>{t('common.operation.learnMore')}</Link> | |||
| <Link href={docLink('/guides/application-publishing/launch-your-webapp-quickly/README')} | |||
| target='_blank' rel='noopener noreferrer' className='text-text-accent'>{t('common.operation.learnMore')}</Link> | |||
| </div> | |||
| </div> | |||
| {/* form body */} | |||
| @@ -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 = ({ | |||
| <span>{isChatMode ? t('workflow.common.fileUploadTip') : t('workflow.common.ImageUploadLegacyTip')}</span> | |||
| <a | |||
| className='text-text-accent' | |||
| href={`https://docs.dify.ai/${locale === LanguagesSupported[1] ? 'v/zh-hans/' : ''}guides/workflow/bulletin`} | |||
| href={docLink('/guides/workflow/bulletin')} | |||
| target='_blank' rel='noopener noreferrer' | |||
| >{t('workflow.common.featuresDocLink')}</a> | |||
| </div> | |||
| @@ -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<PropsWithChildren> = (props) => { | |||
| return <label className='system-sm-semibold text-text-secondary'>{props.children}</label> | |||
| @@ -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 | |||
| @@ -962,7 +964,9 @@ const StepTwo = ({ | |||
| <div className={'mb-1'}> | |||
| <div className='system-md-semibold mb-0.5 text-text-secondary'>{t('datasetSettings.form.retrievalSetting.title')}</div> | |||
| <div className='body-xs-regular text-text-tertiary'> | |||
| <a target='_blank' rel='noopener noreferrer' href='https://docs.dify.ai/guides/knowledge-base/create-knowledge-and-upload-documents#id-4-retrieval-settings' className='text-text-accent'>{t('datasetSettings.form.retrievalSetting.learnMore')}</a> | |||
| <a target='_blank' rel='noopener noreferrer' | |||
| href={docLink('/guides/knowledge-base/create-knowledge-and-upload-documents')} | |||
| className='text-text-accent'>{t('datasetSettings.form.retrievalSetting.learnMore')}</a> | |||
| {t('datasetSettings.form.retrievalSetting.longDescription')} | |||
| </div> | |||
| </div> | |||
| @@ -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<Props> = ({ | |||
| 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<Props> = ({ | |||
| <Input | |||
| value={url} | |||
| onChange={handleUrlChange} | |||
| placeholder='https://docs.dify.ai' | |||
| placeholder={docLink()} | |||
| /> | |||
| <Button | |||
| variant='primary' | |||
| @@ -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<Props> = ({ | |||
| 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<Props> = ({ | |||
| <Input | |||
| value={url} | |||
| onChange={handleUrlChange} | |||
| placeholder='https://docs.dify.ai' | |||
| placeholder={docLink()} | |||
| /> | |||
| <Button | |||
| variant='primary' | |||
| @@ -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<SVGElement>) => { | |||
| return <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg" className={className ?? ''}> | |||
| @@ -86,6 +85,7 @@ const DEFAULT_LIMIT = 10 | |||
| const Documents: FC<IDocumentsProps> = ({ datasetId }) => { | |||
| const { t } = useTranslation() | |||
| const docLink = useDocLink() | |||
| const { plan } = useProviderContext() | |||
| const isFreePlan = plan.type === 'sandbox' | |||
| const [inputValue, setInputValue] = useState<string>('') // the input value | |||
| @@ -100,7 +100,6 @@ const Documents: FC<IDocumentsProps> = ({ 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({ | |||
| @@ -262,11 +261,7 @@ const Documents: FC<IDocumentsProps> = ({ datasetId }) => { | |||
| <a | |||
| className='flex items-center text-text-accent' | |||
| target='_blank' | |||
| href={ | |||
| locale === LanguagesSupported[1] | |||
| ? 'https://docs.dify.ai/zh-hans/guides/knowledge-base/integrate-knowledge-within-application' | |||
| : 'https://docs.dify.ai/en/guides/knowledge-base/integrate-knowledge-within-application' | |||
| } | |||
| href={docLink('/guides/knowledge-base/integrate-knowledge-within-application')} | |||
| > | |||
| <span>{t('datasetDocuments.list.learnMore')}</span> | |||
| <RiExternalLinkLine className='h-3 w-3' /> | |||
| @@ -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<FormProps> = 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<FormProps> = React.memo(({ | |||
| </label> | |||
| {variable === 'endpoint' && ( | |||
| <a | |||
| href={'https://docs.dify.ai/guides/knowledge-base/external-knowledge-api-documentation' || '/'} | |||
| href={docLink('/guides/knowledge-base/external-knowledge-api-documentation') || '/'} | |||
| target='_blank' | |||
| rel='noopener noreferrer' | |||
| className='body-xs-regular flex items-center text-text-accent' | |||
| @@ -12,6 +12,7 @@ import ActionButton from '@/app/components/base/action-button' | |||
| import Button from '@/app/components/base/button' | |||
| import Loading from '@/app/components/base/loading' | |||
| import { useModalContext } from '@/context/modal-context' | |||
| import { useDocLink } from '@/context/i18n' | |||
| type ExternalAPIPanelProps = { | |||
| onClose: () => void | |||
| @@ -19,6 +20,7 @@ type ExternalAPIPanelProps = { | |||
| const ExternalAPIPanel: React.FC<ExternalAPIPanelProps> = ({ onClose }) => { | |||
| const { t } = useTranslation() | |||
| const docLink = useDocLink() | |||
| const { setShowExternalKnowledgeAPIModal } = useModalContext() | |||
| const { externalKnowledgeApiList, mutateExternalKnowledgeApis, isLoading } = useExternalKnowledgeApi() | |||
| @@ -50,7 +52,8 @@ const ExternalAPIPanel: React.FC<ExternalAPIPanelProps> = ({ onClose }) => { | |||
| <div className='flex grow flex-col items-start gap-1'> | |||
| <div className='system-xl-semibold self-stretch text-text-primary'>{t('dataset.externalAPIPanelTitle')}</div> | |||
| <div className='body-xs-regular self-stretch text-text-tertiary'>{t('dataset.externalAPIPanelDescription')}</div> | |||
| <a className='flex cursor-pointer items-center justify-center gap-1 self-stretch' href='https://docs.dify.ai/guides/knowledge-base/external-knowledge-api-documentation' target='_blank'> | |||
| <a className='flex cursor-pointer items-center justify-center gap-1 self-stretch' | |||
| href={docLink('/guides/knowledge-base/external-knowledge-api-documentation')} target='_blank'> | |||
| <RiBookOpenLine className='h-3 w-3 text-text-accent' /> | |||
| <div className='body-xs-regular grow text-text-accent'>{t('dataset.externalAPIPanelDocumentation')}</div> | |||
| </a> | |||
| @@ -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 ( | |||
| <div className='flex w-[360px] flex-col items-start pb-2 pr-8 pt-[108px]'> | |||
| @@ -16,12 +18,15 @@ const InfoPanel = () => { | |||
| </span> | |||
| <span className='system-sm-regular text-text-tertiary'> | |||
| {t('dataset.connectDatasetIntro.content.front')} | |||
| <a className='system-sm-regular ml-1 text-text-accent' href='https://docs.dify.ai/en/guides/knowledge-base/external-knowledge-api' target='_blank' rel="noopener noreferrer"> | |||
| <a className='system-sm-regular ml-1 text-text-accent' href={docLink('/guides/knowledge-base/external-knowledge-api')} target='_blank' rel="noopener noreferrer"> | |||
| {t('dataset.connectDatasetIntro.content.link')} | |||
| </a> | |||
| {t('dataset.connectDatasetIntro.content.end')} | |||
| </span> | |||
| <a className='system-sm-regular self-stretch text-text-accent' href='https://docs.dify.ai/en/guides/knowledge-base/connect-external-knowledge-base' target='_blank' rel="noopener noreferrer"> | |||
| <a className='system-sm-regular self-stretch text-text-accent' | |||
| href={docLink('/guides/knowledge-base/connect-external-knowledge-base')} | |||
| target='_blank' | |||
| rel="noopener noreferrer"> | |||
| {t('dataset.connectDatasetIntro.learnMore')} | |||
| </a> | |||
| </p> | |||
| @@ -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<ExternalKnowledgeBaseCreateProps> = ({ onConnect, loading }) => { | |||
| const { t } = useTranslation() | |||
| const docLink = useDocLink() | |||
| const router = useRouter() | |||
| const [formData, setFormData] = useState<CreateKnowledgeBaseReq>({ | |||
| name: '', | |||
| @@ -59,7 +61,7 @@ const ExternalKnowledgeBaseCreate: React.FC<ExternalKnowledgeBaseCreateProps> = | |||
| <span>{t('dataset.connectHelper.helper1')}</span> | |||
| <span className='system-sm-medium text-text-secondary'>{t('dataset.connectHelper.helper2')}</span> | |||
| <span>{t('dataset.connectHelper.helper3')}</span> | |||
| <a className='system-sm-regular self-stretch text-text-accent' href='https://docs.dify.ai/en/guides/knowledge-base/connect-external-knowledge-base' target='_blank' rel="noopener noreferrer"> | |||
| <a className='system-sm-regular self-stretch text-text-accent' href={docLink('/guides/knowledge-base/connect-external-knowledge-base')} target='_blank' rel="noopener noreferrer"> | |||
| {t('dataset.connectHelper.helper4')} | |||
| </a> | |||
| <span>{t('dataset.connectHelper.helper5')} </span> | |||
| @@ -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<Props> = ({ | |||
| }) => { | |||
| const ref = useRef(null) | |||
| const { t } = useTranslation() | |||
| const docLink = useDocLink() | |||
| const [retrievalConfig, setRetrievalConfig] = useState(value) | |||
| // useClickAway(() => { | |||
| @@ -72,7 +74,7 @@ const ModifyRetrievalModal: FC<Props> = ({ | |||
| <a | |||
| target='_blank' | |||
| rel='noopener noreferrer' | |||
| href='https://docs.dify.ai/guides/knowledge-base/create-knowledge-and-upload-documents#id-4-retrieval-settings' | |||
| href={docLink('/guides/knowledge-base/create-knowledge-and-upload-documents#id-4-retrieval-settings')} | |||
| className='text-text-accent' | |||
| > | |||
| {t('datasetSettings.form.retrievalSetting.learnMore')} | |||
| @@ -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 AlertTriangle from '@/app/components/base/icons/src/vender/solid/alertsAndFeedback/AlertTriangle' | |||
| import { useDocLink } from '@/context/i18n' | |||
| const rowClass = 'flex' | |||
| const labelClass = ` | |||
| @@ -46,6 +47,7 @@ const getKey = (pageIndex: number, previousPageData: DataSetListResponse) => { | |||
| const Form = () => { | |||
| const { t } = useTranslation() | |||
| const docLink = useDocLink() | |||
| const { notify } = useContext(ToastContext) | |||
| const { mutate } = useSWRConfig() | |||
| const { isCurrentWorkspaceDatasetOperator } = useAppContext() | |||
| @@ -308,7 +310,7 @@ const Form = () => { | |||
| <div> | |||
| <div className='system-sm-semibold text-text-secondary'>{t('datasetSettings.form.retrievalSetting.title')}</div> | |||
| <div className='body-xs-regular text-text-tertiary'> | |||
| <a target='_blank' rel='noopener noreferrer' href='https://docs.dify.ai/guides/knowledge-base/create-knowledge-and-upload-documents#id-4-retrieval-settings' className='text-text-accent'>{t('datasetSettings.form.retrievalSetting.learnMore')}</a> | |||
| <a target='_blank' rel='noopener noreferrer' href={docLink('/guides/knowledge-base/create-knowledge-and-upload-documents#id-4-retrieval-settings')} className='text-text-accent'>{t('datasetSettings.form.retrievalSetting.learnMore')}</a> | |||
| {t('datasetSettings.form.retrievalSetting.description')} | |||
| </div> | |||
| </div> | |||
| @@ -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'> | |||
| <RiBookOpenLine className='size-4 shrink-0 text-text-tertiary' /> | |||
| <div className='system-md-regular grow px-1 text-text-secondary'>{t('common.userProfile.helpCenter')}</div> | |||
| @@ -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) => { | |||
| </div> | |||
| <div className='system-xs-regular text-text-tertiary'>{t('plugin.detailPanel.endpointsTip')}</div> | |||
| <a | |||
| href={`https://docs.dify.ai/${locale === LanguagesSupported[1] ? 'v/zh-hans/' : ''}plugins/schema-definition/endpoint`} | |||
| href={docLink('/plugins/schema-definition/endpoint')} | |||
| target='_blank' | |||
| rel='noopener noreferrer' | |||
| > | |||
| @@ -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) | |||
| @@ -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={<div className='text-xs text-text-tertiary'> | |||
| {t('workflow.nodes.agent.strategy.configureTipDesc')} <br /> | |||
| <Link href={ | |||
| locale === LanguagesSupported[1] | |||
| ? 'https://docs.dify.ai/zh-hans/guides/workflow/node/agent#xuan-ze-agent-ce-le' | |||
| : 'https://docs.dify.ai/en/guides/workflow/node/agent#select-an-agent-strategy' | |||
| } className='text-text-accent-secondary' target='_blank'> | |||
| <Link href={docLink('/guides/workflow/node/agent#select-an-agent-strategy', { | |||
| 'zh-Hans': '/guides/workflow/node/agent#xuan-ze-agent-ce-le', | |||
| })} | |||
| className='text-text-accent-secondary' target='_blank'> | |||
| {t('workflow.nodes.agent.learnMore')} | |||
| </Link> | |||
| </div>} | |||
| @@ -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')} | |||
| | |||
| <a | |||
| href='https://docs.dify.ai/en/guides/workflow/error-handling/README' | |||
| href={docLink('/guides/workflow/error-handling/README')} | |||
| target='_blank' | |||
| className='text-text-accent' | |||
| > | |||
| @@ -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 ( | |||
| <div className='px-4 pt-2'> | |||
| @@ -17,7 +19,7 @@ const FailBranchCard = () => { | |||
| {t('workflow.nodes.common.errorHandle.failBranch.customizeTip')} | |||
| | |||
| <a | |||
| href='https://docs.dify.ai/guides/workflow/error-handling' | |||
| href={docLink('/guides/workflow/error-handling/error-type')} | |||
| target='_blank' | |||
| className='text-text-accent' | |||
| > | |||
| @@ -2,12 +2,10 @@ | |||
| import type { FC } from 'react' | |||
| import React 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 { useDocLink } from '@/context/i18n' | |||
| type Props = { | |||
| vars: NodeOutPutVar[] | |||
| @@ -24,7 +22,7 @@ const VarReferencePopup: FC<Props> = ({ | |||
| isSupportFileVar = true, | |||
| }) => { | |||
| const { t } = useTranslation() | |||
| const { locale } = useContext(I18n) | |||
| const docLink = useDocLink() | |||
| // max-h-[300px] overflow-y-auto todo: use portal to handle long list | |||
| return ( | |||
| <div className='space-y-1 rounded-lg border border-components-panel-border bg-components-panel-bg p-1 shadow-lg' style={{ | |||
| @@ -46,8 +44,10 @@ const VarReferencePopup: FC<Props> = ({ | |||
| description={<div className='system-xs-regular text-text-tertiary'> | |||
| {t('workflow.variableReference.assignedVarsDescription')} | |||
| <a target='_blank' rel='noopener noreferrer' | |||
| className='text-text-accent-secondary' | |||
| href={locale !== LanguagesSupported[1] ? 'https://docs.dify.ai/guides/workflow/variables#conversation-variables' : `https://docs.dify.ai/${locale.toLowerCase()}/guides/workflow/variables#hui-hua-bian-liang`}>{t('workflow.variableReference.conversationVars')}</a> | |||
| 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')} | |||
| </a> | |||
| </div>} | |||
| /> | |||
| )) | |||
| @@ -1,14 +1,12 @@ | |||
| import { useMemo } from 'react' | |||
| import { useGetLanguage } from '@/context/i18n' | |||
| import { useDocLink, useGetLanguage } from '@/context/i18n' | |||
| import { BlockEnum } from '@/app/components/workflow/types' | |||
| export const useNodeHelpLink = (nodeType: BlockEnum) => { | |||
| const language = useGetLanguage() | |||
| const docLink = useDocLink() | |||
| const prefixLink = useMemo(() => { | |||
| if (language === 'zh_Hans') | |||
| return 'https://docs.dify.ai/zh-hans/guides/workflow/node/' | |||
| return 'https://docs.dify.ai/en/guides/workflow/node/' | |||
| return docLink('/guides/workflow/node/') | |||
| }, [language]) | |||
| const linkMap = useMemo(() => { | |||
| if (language === 'zh_Hans') { | |||
| @@ -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<JsonSchemaConfigProps> = ({ | |||
| 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<JsonSchemaConfigProps> = ({ | |||
| <div className='flex items-center gap-x-2 p-6 pt-5'> | |||
| <a | |||
| className='flex grow items-center gap-x-1 text-text-accent' | |||
| href={`https://docs.dify.ai/${docLanguage}/guides/workflow/structured-outputs`} | |||
| href={docLink('/guides/workflow/structured-outputs')} | |||
| target='_blank' | |||
| rel='noopener noreferrer' | |||
| > | |||
| @@ -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 = () => { | |||
| <div className='system-2xs-medium-uppercase inline-block rounded-[5px] border border-divider-deep px-[5px] py-[3px] text-text-tertiary'>TIPS</div> | |||
| <div className='system-sm-regular mb-4 mt-1 text-text-secondary'> | |||
| {t('workflow.chatVariable.panelDescription')} | |||
| <a target='_blank' rel='noopener noreferrer' className='text-text-accent' href={locale !== LanguagesSupported[1] ? 'https://docs.dify.ai/guides/workflow/variables#conversation-variables' : `https://docs.dify.ai/${locale.toLowerCase()}/guides/workflow/variables#hui-hua-bian-liang`}>{t('workflow.chatVariable.docLink')}</a> | |||
| </div> | |||
| <a target='_blank' rel='noopener noreferrer' className='text-text-accent' | |||
| href={docLink('/guides/workflow/variables#conversation-variables', { 'zh-Hans': '/guides/workflow/variables#hui-hua-bian-liang' })}> | |||
| {t('workflow.chatVariable.docLink')} | |||
| </a> | |||
| </div> | |||
| <div className='flex items-center gap-2'> | |||
| <div className='radius-lg flex flex-col border border-workflow-block-border bg-workflow-block-bg p-3 pb-4 shadow-md'> | |||
| <BubbleX className='mb-1 h-4 w-4 shrink-0 text-util-colors-teal-teal-700' /> | |||
| @@ -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<Props> = ({ | |||
| doSetCollapseState(state) | |||
| }, [hideProcessDetail]) | |||
| const { t } = useTranslation() | |||
| const docLink = useDocLink() | |||
| const getTime = (time: number) => { | |||
| if (time < 1) | |||
| @@ -195,7 +197,7 @@ const NodePanel: FC<Props> = ({ | |||
| <StatusContainer status='stopped'> | |||
| {nodeInfo.error} | |||
| <a | |||
| href='https://docs.dify.ai/guides/workflow/error-handling/error-type' | |||
| href={docLink('/guides/workflow/error-handling/error-type')} | |||
| target='_blank' | |||
| className='text-text-accent' | |||
| > | |||
| @@ -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<ResultProps> = ({ | |||
| exceptionCounts, | |||
| }) => { | |||
| const { t } = useTranslation() | |||
| const docLink = useDocLink() | |||
| return ( | |||
| <StatusContainer status={status}> | |||
| @@ -134,7 +136,7 @@ const StatusPanel: FC<ResultProps> = ({ | |||
| <div className='system-xs-medium text-text-warning'> | |||
| {error} | |||
| <a | |||
| href='https://docs.dify.ai/guides/workflow/error-handling/error-type' | |||
| href={docLink('/guides/workflow/error-handling/error-type')} | |||
| target='_blank' | |||
| className='text-text-accent' | |||
| > | |||
| @@ -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 = () => { | |||
| <div className='mb-4 mt-5 h-[1px] bg-gradient-to-r from-[rgba(16,24,40,0.08)]'></div> | |||
| <a | |||
| className='system-xs-regular flex items-center text-text-accent' | |||
| href={docLink} | |||
| href={docLink('/getting-started/dify-for-education')} | |||
| target='_blank' | |||
| > | |||
| {t('education.learn')} | |||
| @@ -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<HTMLDivElement>(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({ | |||
| <div className='flex items-center gap-1'> | |||
| {showLink && ( | |||
| <> | |||
| <a onClick={handleClick} href={docLink} target='_blank' className='system-xs-regular cursor-pointer text-text-accent'>{t('education.learn')}</a> | |||
| <a onClick={handleClick} href={eduDocLink} target='_blank' className='system-xs-regular cursor-pointer text-text-accent'>{t('education.learn')}</a> | |||
| <RiExternalLinkLine className='h-3 w-3 text-text-accent' /> | |||
| </> | |||
| )} | |||
| @@ -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<typeof accountFormSchema> | |||
| 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 = () => { | |||
| <Link | |||
| className='text-text-accent' | |||
| target='_blank' rel='noopener noreferrer' | |||
| href={'https://docs.dify.ai/user-agreement/open-source'} | |||
| href={docLink('/policies/open-source')} | |||
| >{t('login.license.link')}</Link> | |||
| </div> | |||
| </div> | |||
| @@ -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() { | |||
| <Link | |||
| className='system-xs-medium text-text-accent-secondary' | |||
| target='_blank' rel='noopener noreferrer' | |||
| href={`https://docs.dify.ai/${language !== LanguagesSupported[1] ? 'user-agreement' : `v/${locale.toLowerCase()}/policies`}/open-source`} | |||
| href={docLink('/policies/open-source')} | |||
| >{t('login.license.link')}</Link> | |||
| </div> | |||
| </div> | |||
| @@ -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<IState, IAction> = (state: IState, action: IAction) => { | |||
| const OneMoreStep = () => { | |||
| const { t } = useTranslation() | |||
| const docLink = useDocLink() | |||
| const router = useRouter() | |||
| const searchParams = useSearchParams() | |||
| @@ -164,7 +166,7 @@ const OneMoreStep = () => { | |||
| <Link | |||
| className='system-xs-medium text-text-accent-secondary' | |||
| target='_blank' rel='noopener noreferrer' | |||
| href={'https://docs.dify.ai/en/policies/agreement/README'} | |||
| href={docLink('/policies/agreement/README')} | |||
| >{t('login.license.link')}</Link> | |||
| </div> | |||
| </div> | |||
| @@ -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 | |||