diff --git a/web/app/components/app/create-from-dsl-modal/index.tsx b/web/app/components/app/create-from-dsl-modal/index.tsx index 4b5ae92c39..2c540e2897 100644 --- a/web/app/components/app/create-from-dsl-modal/index.tsx +++ b/web/app/components/app/create-from-dsl-modal/index.tsx @@ -1,5 +1,6 @@ 'use client' +import type { DocPathWithoutLang } from '@/types/doc-paths' import { useDebounceFn, useKeyPress } from 'ahooks' import { noop } from 'es-toolkit/function' import { useRouter } from 'next/navigation' @@ -15,7 +16,6 @@ import AppsFull from '@/app/components/billing/apps-full-in-dialog' import { usePluginDependencies } from '@/app/components/workflow/plugin-dependency/hooks' import { NEED_REFRESH_APP_LIST_KEY } from '@/config' import { useAppContext } from '@/context/app-context' -import { appManagementAnchorMap } from '@/context/doc-anchors' import { useDocLink } from '@/context/i18n' import { useProviderContext } from '@/context/provider-context' import { @@ -47,6 +47,13 @@ export enum CreateFromDSLModalTab { FROM_URL = 'from-url', } +const appManagementLocalizedPathMap = { + 'zh-Hans': '/use-dify/workspace/app-management#应用导出和导入' as DocPathWithoutLang, + 'zh_Hans': '/use-dify/workspace/app-management#应用导出和导入' as DocPathWithoutLang, + 'ja-JP': '/use-dify/workspace/app-management#アプリのエクスポートとインポート' as DocPathWithoutLang, + 'ja_JP': '/use-dify/workspace/app-management#アプリのエクスポートとインポート' as DocPathWithoutLang, +} + const CreateFromDSLModal = ({ show, onSuccess, onClose, activeTab = CreateFromDSLModalTab.FROM_FILE, dslUrl = '', droppedFile }: CreateFromDSLModalProps) => { const { push } = useRouter() const { t } = useTranslation() @@ -313,7 +320,7 @@ const CreateFromDSLModal = ({ show, onSuccess, onClose, activeTab = CreateFromDS
diff --git a/web/app/components/workflow/variable-inspect/artifacts-tab.tsx b/web/app/components/workflow/variable-inspect/artifacts-tab.tsx index f914204b3b..16eae84004 100644 --- a/web/app/components/workflow/variable-inspect/artifacts-tab.tsx +++ b/web/app/components/workflow/variable-inspect/artifacts-tab.tsx @@ -9,7 +9,6 @@ import { FileDownload01 } from '@/app/components/base/icons/src/vender/line/file import Loading from '@/app/components/base/loading' import ArtifactsTree from '@/app/components/workflow/skill/file-tree/artifacts/artifacts-tree' import ReadOnlyFilePreview from '@/app/components/workflow/skill/viewer/read-only-file-preview' -import { fileSystemArtifactsAnchorMap } from '@/context/doc-anchors' import { useDocLink } from '@/context/i18n' import { useDownloadSandboxFile, useSandboxFileDownloadUrl, useSandboxFilesTree } from '@/service/use-sandbox-file' import { cn } from '@/utils/classnames' @@ -19,6 +18,13 @@ import { WorkflowRunningStatus } from '../types' import InspectLayout from './inspect-layout' import SplitPanel from './split-panel' +const fileSystemArtifactsLocalizedPathMap = { + 'zh-Hans': '/use-dify/build/file-system#产物' as DocPathWithoutLang, + 'zh_Hans': '/use-dify/build/file-system#产物' as DocPathWithoutLang, + 'ja-JP': '/use-dify/build/file-system#アーティファクト' as DocPathWithoutLang, + 'ja_JP': '/use-dify/build/file-system#アーティファクト' as DocPathWithoutLang, +} + const ArtifactsEmpty = ({ description }: { description: string }) => { const { t } = useTranslation('workflow') const docLink = useDocLink() @@ -33,7 +39,7 @@ const ArtifactsEmpty = ({ description }: { description: string }) => {
{description}
diff --git a/web/context/doc-anchors.ts b/web/context/doc-anchors.ts deleted file mode 100644 index 7325025aca..0000000000 --- a/web/context/doc-anchors.ts +++ /dev/null @@ -1,15 +0,0 @@ -import type { DocAnchorMap } from './i18n' - -export const appManagementAnchorMap = { - 'zh-Hans': '应用导出和导入', - 'zh_Hans': '应用导出和导入', - 'ja-JP': 'アプリのエクスポートとインポート', - 'ja_JP': 'アプリのエクスポートとインポート', -} satisfies DocAnchorMap - -export const fileSystemArtifactsAnchorMap = { - 'zh-Hans': '产物', - 'zh_Hans': '产物', - 'ja-JP': 'アーティファクト', - 'ja_JP': 'アーティファクト', -} satisfies DocAnchorMap diff --git a/web/context/i18n.spec.ts b/web/context/i18n.spec.ts index 4bb2d20c19..7fb05b8aed 100644 --- a/web/context/i18n.spec.ts +++ b/web/context/i18n.spec.ts @@ -1,4 +1,4 @@ -import type { DocAnchorMap, DocPathMap } from './i18n' +import type { DocPathMap } from './i18n' import type { DocPathWithoutLang } from '@/types/doc-paths' import { useTranslation } from '#i18n' import { renderHook } from '@testing-library/react' @@ -103,7 +103,7 @@ describe('useDocLink', () => { } const { result } = renderHook(() => useDocLink()) - const url = result.current('/use-dify/getting-started/quick-start' as DocPathWithoutLang, { pathMap }) + const url = result.current('/use-dify/getting-started/quick-start' as DocPathWithoutLang, pathMap) expect(url).toBe(`${defaultDocBaseUrl}/zh/use-dify/getting-started/introduction`) }) @@ -119,7 +119,7 @@ describe('useDocLink', () => { } const { result } = renderHook(() => useDocLink()) - const url = result.current('/use-dify/getting-started/quick-start' as DocPathWithoutLang, { pathMap }) + const url = result.current('/use-dify/getting-started/quick-start' as DocPathWithoutLang, pathMap) expect(url).toBe(`${defaultDocBaseUrl}/ja/use-dify/getting-started/quick-start`) }) @@ -234,17 +234,6 @@ describe('useDocLink', () => { const url = result.current('/use-dify/getting-started/introduction') expect(url).toBe(`${defaultDocBaseUrl}/zh/use-dify/getting-started/introduction`) }) - - it('should preserve anchor while translating API reference path', () => { - vi.mocked(useTranslation).mockReturnValue({ - i18n: { language: 'zh-Hans' }, - } as ReturnType) - vi.mocked(getDocLanguage).mockReturnValue('zh') - - const { result } = renderHook(() => useDocLink()) - const url = result.current('/api-reference/annotations/create-annotation#request-body') - expect(url).toBe(`${defaultDocBaseUrl}/api-reference/标注管理/创建标注#request-body`) - }) }) describe('Edge Cases', () => { @@ -254,20 +243,22 @@ describe('useDocLink', () => { expect(url).toBe(`${defaultDocBaseUrl}/en/use-dify/getting-started/introduction#overview`) }) - it('should support locale-specific anchors via anchorMap', () => { + it('should support locale-specific anchors via pathMap', () => { vi.mocked(useTranslation).mockReturnValue({ i18n: { language: 'zh-Hans' }, } as ReturnType) vi.mocked(getDocLanguage).mockReturnValue('zh') - const anchorMap: DocAnchorMap = { - 'zh-Hans': '应用导出和导入', - 'ja-JP': 'アプリのエクスポートとインポート', + const pathMap: DocPathMap = { + 'zh-Hans': '/use-dify/workspace/app-management#应用导出和导入' as DocPathWithoutLang, + 'zh_Hans': '/use-dify/workspace/app-management#应用导出和导入' as DocPathWithoutLang, + 'ja-JP': '/use-dify/workspace/app-management#アプリのエクスポートとインポート' as DocPathWithoutLang, + 'ja_JP': '/use-dify/workspace/app-management#アプリのエクスポートとインポート' as DocPathWithoutLang, } const { result } = renderHook(() => useDocLink()) - const url = result.current('/use-dify/workspace/app-management#app-export-and-import', { anchorMap }) - expect(url).toBe(`${defaultDocBaseUrl}/zh/use-dify/workspace/app-management#${encodeURIComponent('应用导出和导入')}`) + const url = result.current('/use-dify/workspace/app-management#app-export-and-import', pathMap) + expect(url).toBe(`${defaultDocBaseUrl}/zh/use-dify/workspace/app-management#应用导出和导入`) }) it('should handle multiple calls with same hook instance', () => { diff --git a/web/context/i18n.ts b/web/context/i18n.ts index 8b0e89e8fd..6c84d01903 100644 --- a/web/context/i18n.ts +++ b/web/context/i18n.ts @@ -1,7 +1,7 @@ import type { Locale } from '@/i18n-config/language' import type { DocPathWithoutLang } from '@/types/doc-paths' import { useTranslation } from '#i18n' -import { useCallback, useMemo } from 'react' +import { useCallback } from 'react' import { getDocLanguage, getLanguage, getPricingPageLanguage } from '@/i18n-config/language' import { apiReferencePathTranslations } from '@/types/doc-paths' @@ -23,63 +23,29 @@ export const useGetPricingPageLanguage = () => { export const defaultDocBaseUrl = 'https://docs.bash-is-all-you-need.dify.dev' export type DocPathMap = Partial> -export type DocAnchorMap = Partial> -export type DocLinkOptions = { - pathMap?: DocPathMap - anchorMap?: DocAnchorMap -} -export type BuildDocLink = (path?: DocPathWithoutLang, options?: DocLinkOptions) => string -const splitPathWithHash = (path: string) => { - const [pathname, ...hashParts] = path.split('#') - return { - pathname, - hash: hashParts.join('#'), - } -} - -const normalizeAnchor = (anchor: string) => { - const normalizedAnchor = anchor.startsWith('#') ? anchor.slice(1) : anchor - if (!normalizedAnchor) - return '' - - const isAsciiOnly = Array.from(normalizedAnchor).every(char => char.codePointAt(0)! <= 0x7F) - if (isAsciiOnly) - return normalizedAnchor - - return encodeURIComponent(normalizedAnchor) -} - -export const useDocLink = (baseUrl?: string): BuildDocLink => { - const baseDocUrl = useMemo(() => { - const resolvedBaseUrl = baseUrl || defaultDocBaseUrl - return resolvedBaseUrl.endsWith('/') ? resolvedBaseUrl.slice(0, -1) : resolvedBaseUrl - }, [baseUrl]) +export const useDocLink = (baseUrl?: string): ((path?: DocPathWithoutLang, pathMap?: DocPathMap) => string) => { + let baseDocUrl = baseUrl || defaultDocBaseUrl + baseDocUrl = (baseDocUrl.endsWith('/')) ? baseDocUrl.slice(0, -1) : baseDocUrl const locale = useLocale() return useCallback( - (path?: DocPathWithoutLang, options?: DocLinkOptions): string => { + (path?: DocPathWithoutLang, pathMap?: DocPathMap): string => { const docLanguage = getDocLanguage(locale) const pathUrl = path || '' - const { pathMap, anchorMap } = options || {} - const targetPath = (pathMap) ? pathMap[locale] || pathUrl : pathUrl - const { pathname: pathWithoutHash, hash: pathAnchor } = splitPathWithHash(targetPath) - let targetPathWithoutHash = pathWithoutHash + let targetPath = (pathMap) ? pathMap[locale] || pathUrl : pathUrl let languagePrefix = `/${docLanguage}` - if (targetPathWithoutHash.startsWith('/api-reference/')) { + if (targetPath.startsWith('/api-reference/')) { languagePrefix = '' if (docLanguage !== 'en') { - const translatedPath = apiReferencePathTranslations[targetPathWithoutHash]?.[docLanguage] + const translatedPath = apiReferencePathTranslations[targetPath]?.[docLanguage] if (translatedPath) { - targetPathWithoutHash = translatedPath + targetPath = translatedPath } } } - const anchor = normalizeAnchor(anchorMap?.[locale] || pathAnchor) - const anchorSuffix = anchor ? `#${anchor}` : '' - - return `${baseDocUrl}${languagePrefix}${targetPathWithoutHash}${anchorSuffix}` + return `${baseDocUrl}${languagePrefix}${targetPath}` }, [baseDocUrl, locale], )