From 0ee35ca38fd61b1ee189b4bc8c893f15b52e795d Mon Sep 17 00:00:00 2001 From: Huixin615 Date: Tue, 23 Jun 2026 07:53:53 +0800 Subject: [PATCH] fix: preserve locale in documentation links (#3717) --- .../src/components/docs/localized-cards.tsx | 13 ++++ .../src/components/docs/localized-links.ts | 15 +++++ .../docs/localized-mdx-components.tsx | 43 ++++++++++++ .../en/application/agents-and-threads.mdx | 2 +- .../content/en/application/configuration.mdx | 2 +- .../en/application/deployment-guide.mdx | 2 +- frontend/src/content/en/application/index.mdx | 2 +- .../operations-and-troubleshooting.mdx | 2 +- .../content/en/application/quick-start.mdx | 2 +- .../en/application/workspace-usage.mdx | 2 +- .../src/content/en/harness/configuration.mdx | 2 +- .../src/content/en/harness/customization.mdx | 2 +- .../content/en/harness/design-principles.mdx | 2 +- frontend/src/content/en/harness/index.mdx | 2 +- .../content/en/harness/integration-guide.mdx | 2 +- .../src/content/en/harness/lead-agent.mdx | 2 +- frontend/src/content/en/harness/mcp.mdx | 2 +- frontend/src/content/en/harness/memory.mdx | 2 +- .../src/content/en/harness/quick-start.mdx | 2 +- frontend/src/content/en/harness/sandbox.mdx | 2 +- frontend/src/content/en/harness/skills.mdx | 2 +- frontend/src/content/en/harness/subagents.mdx | 2 +- frontend/src/content/en/harness/tools.mdx | 2 +- .../content/en/introduction/core-concepts.mdx | 2 +- .../en/introduction/harness-vs-app.mdx | 2 +- .../src/content/en/introduction/index.mdx | 1 - .../content/en/introduction/why-deerflow.mdx | 2 +- .../zh/application/agents-and-threads.mdx | 2 +- .../content/zh/application/configuration.mdx | 2 +- .../zh/application/deployment-guide.mdx | 2 +- frontend/src/content/zh/application/index.mdx | 2 +- .../operations-and-troubleshooting.mdx | 2 +- .../content/zh/application/quick-start.mdx | 2 +- .../zh/application/workspace-usage.mdx | 2 +- .../src/content/zh/harness/configuration.mdx | 2 +- .../src/content/zh/harness/customization.mdx | 2 +- .../content/zh/harness/design-principles.mdx | 2 +- frontend/src/content/zh/harness/index.mdx | 2 +- .../content/zh/harness/integration-guide.mdx | 2 +- .../src/content/zh/harness/lead-agent.mdx | 2 +- frontend/src/content/zh/harness/mcp.mdx | 2 +- frontend/src/content/zh/harness/memory.mdx | 2 +- .../src/content/zh/harness/quick-start.mdx | 2 +- frontend/src/content/zh/harness/sandbox.mdx | 2 +- frontend/src/content/zh/harness/skills.mdx | 2 +- frontend/src/content/zh/harness/subagents.mdx | 2 +- frontend/src/content/zh/harness/tools.mdx | 2 +- .../content/zh/introduction/core-concepts.mdx | 2 +- .../zh/introduction/harness-vs-app.mdx | 2 +- .../src/content/zh/introduction/index.mdx | 1 - .../content/zh/introduction/why-deerflow.mdx | 2 +- frontend/src/mdx-components.ts | 5 ++ .../tests/e2e/docs-localized-links.spec.ts | 54 +++++++++++++++ .../components/docs/localized-links.test.ts | 65 +++++++++++++++++++ 54 files changed, 241 insertions(+), 48 deletions(-) create mode 100644 frontend/src/components/docs/localized-cards.tsx create mode 100644 frontend/src/components/docs/localized-links.ts create mode 100644 frontend/src/components/docs/localized-mdx-components.tsx create mode 100644 frontend/tests/e2e/docs-localized-links.spec.ts create mode 100644 frontend/tests/unit/components/docs/localized-links.test.ts diff --git a/frontend/src/components/docs/localized-cards.tsx b/frontend/src/components/docs/localized-cards.tsx new file mode 100644 index 000000000..893e9fbe5 --- /dev/null +++ b/frontend/src/components/docs/localized-cards.tsx @@ -0,0 +1,13 @@ +import { Cards as NextraCards } from "nextra/components"; +import type { ComponentProps } from "react"; + +import { LocalizedCard } from "./localized-mdx-components"; + +function LocalizedCardsRoot(props: ComponentProps) { + return ; +} + +export const LocalizedCards = Object.assign(LocalizedCardsRoot, { + Card: LocalizedCard, + displayName: "LocalizedCards", +}); diff --git a/frontend/src/components/docs/localized-links.ts b/frontend/src/components/docs/localized-links.ts new file mode 100644 index 000000000..d566cccd9 --- /dev/null +++ b/frontend/src/components/docs/localized-links.ts @@ -0,0 +1,15 @@ +const SUPPORTED_DOC_LANGUAGES = new Set(["en", "zh"]); +const UNLOCALIZED_DOCS_PATH = /^\/docs(?=\/|[?#]|$)/; + +export function localizeDocsHref( + href: string, + lang: string | undefined, +): string { + if (!lang || !SUPPORTED_DOC_LANGUAGES.has(lang)) { + return href; + } + if (!UNLOCALIZED_DOCS_PATH.test(href)) { + return href; + } + return `/${lang}${href}`; +} diff --git a/frontend/src/components/docs/localized-mdx-components.tsx b/frontend/src/components/docs/localized-mdx-components.tsx new file mode 100644 index 000000000..3c729889c --- /dev/null +++ b/frontend/src/components/docs/localized-mdx-components.tsx @@ -0,0 +1,43 @@ +"use client"; + +import { useParams } from "next/navigation"; +import { Anchor, Cards as NextraCards } from "nextra/components"; +import type { ComponentProps } from "react"; + +import { cn } from "@/lib/utils"; + +import { localizeDocsHref } from "./localized-links"; + +const DOCS_LINK_CLASS_NAME = + "x:text-primary-600 x:underline x:hover:no-underline x:decoration-from-font x:[text-underline-position:from-font]"; + +function useDocumentLanguage(): string | undefined { + const { lang } = useParams<{ lang?: string }>(); + return lang; +} + +export function LocalizedDocsLink({ + href, + className, + ...props +}: ComponentProps) { + const lang = useDocumentLanguage(); + const localizedHref = + typeof href === "string" ? localizeDocsHref(href, lang) : href; + + return ( + + ); +} + +export function LocalizedCard({ + href, + ...props +}: ComponentProps) { + const lang = useDocumentLanguage(); + return ; +} diff --git a/frontend/src/content/en/application/agents-and-threads.mdx b/frontend/src/content/en/application/agents-and-threads.mdx index 0a281a33e..0b2662581 100644 --- a/frontend/src/content/en/application/agents-and-threads.mdx +++ b/frontend/src/content/en/application/agents-and-threads.mdx @@ -3,7 +3,7 @@ title: Agents and Threads description: DeerFlow App supports multiple named agents and maintains conversation state across sessions through threads and checkpointing. --- -import { Callout, Cards, Steps } from "nextra/components"; +import { Callout, Steps } from "nextra/components"; # Agents and Threads diff --git a/frontend/src/content/en/application/configuration.mdx b/frontend/src/content/en/application/configuration.mdx index 3eeca52a1..b94b252bf 100644 --- a/frontend/src/content/en/application/configuration.mdx +++ b/frontend/src/content/en/application/configuration.mdx @@ -3,7 +3,7 @@ title: Configuration description: DeerFlow App is configured through two files and a set of environment variables. This page covers the application-level configuration that most operators need to set up before deploying. --- -import { Callout, Cards, Tabs } from "nextra/components"; +import { Callout, Tabs } from "nextra/components"; # Configuration diff --git a/frontend/src/content/en/application/deployment-guide.mdx b/frontend/src/content/en/application/deployment-guide.mdx index 52b59cf01..c30f02257 100644 --- a/frontend/src/content/en/application/deployment-guide.mdx +++ b/frontend/src/content/en/application/deployment-guide.mdx @@ -3,7 +3,7 @@ title: Deployment Guide description: "This guide covers all supported deployment methods for DeerFlow App: local development, Docker Compose, and production with Kubernetes-managed sandboxes." --- -import { Callout, Cards, Steps, Tabs } from "nextra/components"; +import { Callout, Steps, Tabs } from "nextra/components"; # Deployment Guide diff --git a/frontend/src/content/en/application/index.mdx b/frontend/src/content/en/application/index.mdx index b45a6cbf0..aa585dce2 100644 --- a/frontend/src/content/en/application/index.mdx +++ b/frontend/src/content/en/application/index.mdx @@ -3,7 +3,7 @@ title: DeerFlow App description: DeerFlow App is the reference implementation of what a production DeerFlow experience looks like. It assembles the Harness runtime, a web-based conversation workspace, an API gateway, and a reverse proxy into a single deployable system. --- -import { Callout, Cards } from "nextra/components"; +import { Callout } from "nextra/components"; # DeerFlow App diff --git a/frontend/src/content/en/application/operations-and-troubleshooting.mdx b/frontend/src/content/en/application/operations-and-troubleshooting.mdx index 0f8d7e44c..52230bd97 100644 --- a/frontend/src/content/en/application/operations-and-troubleshooting.mdx +++ b/frontend/src/content/en/application/operations-and-troubleshooting.mdx @@ -3,7 +3,7 @@ title: Operations and Troubleshooting description: This page covers day-to-day operational tasks and solutions to common problems when running DeerFlow App. --- -import { Callout, Cards } from "nextra/components"; +import { Callout } from "nextra/components"; # Operations and Troubleshooting diff --git a/frontend/src/content/en/application/quick-start.mdx b/frontend/src/content/en/application/quick-start.mdx index c3baa0764..3e67e5042 100644 --- a/frontend/src/content/en/application/quick-start.mdx +++ b/frontend/src/content/en/application/quick-start.mdx @@ -3,7 +3,7 @@ title: Quick Start description: This guide walks you through starting DeerFlow App on your local machine using the `make dev` workflow. Gateway, Frontend, and nginx start together and are accessible through a single URL. --- -import { Callout, Cards, Steps } from "nextra/components"; +import { Callout, Steps } from "nextra/components"; # Quick Start diff --git a/frontend/src/content/en/application/workspace-usage.mdx b/frontend/src/content/en/application/workspace-usage.mdx index 253519af8..6e815c27b 100644 --- a/frontend/src/content/en/application/workspace-usage.mdx +++ b/frontend/src/content/en/application/workspace-usage.mdx @@ -3,7 +3,7 @@ title: Workspace Usage description: The DeerFlow App workspace is a browser-based interface for having multi-turn conversations with the agent, tracking task progress, viewing artifacts, and managing files. --- -import { Callout, Cards } from "nextra/components"; +import { Callout } from "nextra/components"; # Workspace Usage diff --git a/frontend/src/content/en/harness/configuration.mdx b/frontend/src/content/en/harness/configuration.mdx index 89de12716..8d2e88363 100644 --- a/frontend/src/content/en/harness/configuration.mdx +++ b/frontend/src/content/en/harness/configuration.mdx @@ -3,7 +3,7 @@ title: Configuration description: "DeerFlow's configuration system is designed around one goal: every meaningful behavior should be expressible in a config file, not hardcoded in the application. This makes deployments reproducible, auditable, and easy to customize per environment." --- -import { Callout, Cards } from "nextra/components"; +import { Callout } from "nextra/components"; # Configuration diff --git a/frontend/src/content/en/harness/customization.mdx b/frontend/src/content/en/harness/customization.mdx index 2f538aeb6..7117972af 100644 --- a/frontend/src/content/en/harness/customization.mdx +++ b/frontend/src/content/en/harness/customization.mdx @@ -3,7 +3,7 @@ title: Customization description: DeerFlow's pluggable architecture means most parts of the system can be replaced or extended without forking the core. This page maps the extension points and explains how to use each one. --- -import { Callout, Cards } from "nextra/components"; +import { Callout } from "nextra/components"; # Customization diff --git a/frontend/src/content/en/harness/design-principles.mdx b/frontend/src/content/en/harness/design-principles.mdx index e741f6d74..9b41abfd6 100644 --- a/frontend/src/content/en/harness/design-principles.mdx +++ b/frontend/src/content/en/harness/design-principles.mdx @@ -3,7 +3,7 @@ title: Design Principles description: Understanding the design principles behind DeerFlow Harness helps you use it effectively, extend it confidently, and reason about how your agents will behave in production. --- -import { Callout, Cards } from "nextra/components"; +import { Callout } from "nextra/components"; # Design Principles diff --git a/frontend/src/content/en/harness/index.mdx b/frontend/src/content/en/harness/index.mdx index ea0c098ec..e7369e834 100644 --- a/frontend/src/content/en/harness/index.mdx +++ b/frontend/src/content/en/harness/index.mdx @@ -3,7 +3,7 @@ title: Install DeerFlow Harness description: The DeerFlow Harness is the Python SDK and runtime foundation for building your own Super Agent systems. --- -import { Callout, Cards } from "nextra/components"; +import { Callout } from "nextra/components"; # Install DeerFlow Harness diff --git a/frontend/src/content/en/harness/integration-guide.mdx b/frontend/src/content/en/harness/integration-guide.mdx index 61fffc9af..f5ab0c002 100644 --- a/frontend/src/content/en/harness/integration-guide.mdx +++ b/frontend/src/content/en/harness/integration-guide.mdx @@ -3,7 +3,7 @@ title: Integration Guide description: DeerFlow Harness is not only a standalone application. It is a Python library you can import and use inside your own backend, API server, automation system, or multi-agent orchestrator. --- -import { Callout, Cards } from "nextra/components"; +import { Callout } from "nextra/components"; # Integration Guide diff --git a/frontend/src/content/en/harness/lead-agent.mdx b/frontend/src/content/en/harness/lead-agent.mdx index ee89888c0..0195e69ea 100644 --- a/frontend/src/content/en/harness/lead-agent.mdx +++ b/frontend/src/content/en/harness/lead-agent.mdx @@ -3,7 +3,7 @@ title: Lead Agent description: The Lead Agent is the central executor in a DeerFlow thread. Every conversation, task, and workflow flows through it. Understanding how it works helps you configure it effectively and extend it when needed. --- -import { Callout, Cards, Steps } from "nextra/components"; +import { Callout, Steps } from "nextra/components"; # Lead Agent diff --git a/frontend/src/content/en/harness/mcp.mdx b/frontend/src/content/en/harness/mcp.mdx index 53e5ca274..07e37bbbb 100644 --- a/frontend/src/content/en/harness/mcp.mdx +++ b/frontend/src/content/en/harness/mcp.mdx @@ -3,7 +3,7 @@ title: MCP Integration description: The **Model Context Protocol (MCP)** is an open standard for connecting language models to external tools and data sources. DeerFlow's MCP integration allows you to extend the agent with any tool server that implements the MCP protocol — without modifying the harness itself. --- -import { Callout, Cards, Steps } from "nextra/components"; +import { Callout, Steps } from "nextra/components"; # MCP Integration diff --git a/frontend/src/content/en/harness/memory.mdx b/frontend/src/content/en/harness/memory.mdx index 4904c54bb..cdb15d087 100644 --- a/frontend/src/content/en/harness/memory.mdx +++ b/frontend/src/content/en/harness/memory.mdx @@ -3,7 +3,7 @@ title: Memory description: Memory is a runtime feature of the DeerFlow Harness. It is not a simple conversation log — it is a structured store of facts and context summaries that persist across separate sessions and inform the agent's behavior in future conversations. --- -import { Callout, Cards } from "nextra/components"; +import { Callout } from "nextra/components"; # Memory diff --git a/frontend/src/content/en/harness/quick-start.mdx b/frontend/src/content/en/harness/quick-start.mdx index b253a122c..582049b20 100644 --- a/frontend/src/content/en/harness/quick-start.mdx +++ b/frontend/src/content/en/harness/quick-start.mdx @@ -3,7 +3,7 @@ title: Quick Start description: Learn how to create and run a DeerFlow agent with create_deerflow_agent, from model setup to streaming responses. --- -import { Callout, Cards, Steps } from "nextra/components"; +import { Callout, Steps } from "nextra/components"; # Quick Start diff --git a/frontend/src/content/en/harness/sandbox.mdx b/frontend/src/content/en/harness/sandbox.mdx index b1ba74b13..71cda67c6 100644 --- a/frontend/src/content/en/harness/sandbox.mdx +++ b/frontend/src/content/en/harness/sandbox.mdx @@ -3,7 +3,7 @@ title: Sandbox description: The sandbox gives the Lead Agent a controlled environment where it can read files, write outputs, run shell commands, and produce artifacts. Without a sandbox, the agent can only generate text. With a sandbox, it can write and execute code, process data files, generate charts, and build deliverables. --- -import { Callout, Cards, Tabs } from "nextra/components"; +import { Callout, Tabs } from "nextra/components"; # Sandbox diff --git a/frontend/src/content/en/harness/skills.mdx b/frontend/src/content/en/harness/skills.mdx index 78247c40b..b47ed3540 100644 --- a/frontend/src/content/en/harness/skills.mdx +++ b/frontend/src/content/en/harness/skills.mdx @@ -3,7 +3,7 @@ title: Skills description: A skill is more than a prompt. It is a self-contained capability package that can include structured instructions, step-by-step workflows, domain-specific best practices, supporting resources, and tool configurations. Skills are loaded on demand — they inject their content when a task calls for them and stay out of the context otherwise. --- -import { Callout, Cards, FileTree, Steps } from "nextra/components"; +import { Callout, FileTree, Steps } from "nextra/components"; # Skills diff --git a/frontend/src/content/en/harness/subagents.mdx b/frontend/src/content/en/harness/subagents.mdx index 6da63cf00..b49e7bad8 100644 --- a/frontend/src/content/en/harness/subagents.mdx +++ b/frontend/src/content/en/harness/subagents.mdx @@ -3,7 +3,7 @@ title: Subagents description: When a task is too broad for a single reasoning thread, or when parts of it can be done in parallel, the Lead Agent delegates work to **subagents**. A subagent is a self-contained agent invocation that receives a specific task, executes it, and returns the result. --- -import { Callout, Cards } from "nextra/components"; +import { Callout } from "nextra/components"; # Subagents diff --git a/frontend/src/content/en/harness/tools.mdx b/frontend/src/content/en/harness/tools.mdx index 237c3ac08..0f17bc812 100644 --- a/frontend/src/content/en/harness/tools.mdx +++ b/frontend/src/content/en/harness/tools.mdx @@ -3,7 +3,7 @@ title: Tools description: "The Lead Agent is a tool-calling agent. Tools are how it interacts with the world: searching the web, reading and writing files, running commands, delegating tasks, and presenting outputs to the user." --- -import { Callout, Cards, Tabs } from "nextra/components"; +import { Callout, Tabs } from "nextra/components"; # Tools diff --git a/frontend/src/content/en/introduction/core-concepts.mdx b/frontend/src/content/en/introduction/core-concepts.mdx index f7203ae1e..10dd6895b 100644 --- a/frontend/src/content/en/introduction/core-concepts.mdx +++ b/frontend/src/content/en/introduction/core-concepts.mdx @@ -3,7 +3,7 @@ title: Core Concepts description: Before you go deeper into DeerFlow, it helps to anchor on a few concepts that appear throughout the system. These concepts explain what DeerFlow is optimizing for and why its architecture looks the way it does. --- -import { Callout, Cards } from "nextra/components"; +import { Callout } from "nextra/components"; # Core Concepts diff --git a/frontend/src/content/en/introduction/harness-vs-app.mdx b/frontend/src/content/en/introduction/harness-vs-app.mdx index 9e6b8ece2..2f6f39454 100644 --- a/frontend/src/content/en/introduction/harness-vs-app.mdx +++ b/frontend/src/content/en/introduction/harness-vs-app.mdx @@ -3,7 +3,7 @@ title: Harness vs App description: "DeerFlow has two layers that are closely related but serve different purposes." --- -import { Callout, Cards } from "nextra/components"; +import { Callout } from "nextra/components"; # Harness vs App diff --git a/frontend/src/content/en/introduction/index.mdx b/frontend/src/content/en/introduction/index.mdx index f748a0968..4dc2540e0 100644 --- a/frontend/src/content/en/introduction/index.mdx +++ b/frontend/src/content/en/introduction/index.mdx @@ -3,7 +3,6 @@ title: Introduction description: DeerFlow is a runtime harness for building long-horizon agent systems with skills, memory, tools, and sandboxed execution. --- -import { Cards } from "nextra/components"; # Introduction diff --git a/frontend/src/content/en/introduction/why-deerflow.mdx b/frontend/src/content/en/introduction/why-deerflow.mdx index 66ca91f31..98069eeb5 100644 --- a/frontend/src/content/en/introduction/why-deerflow.mdx +++ b/frontend/src/content/en/introduction/why-deerflow.mdx @@ -3,7 +3,7 @@ title: Why DeerFlow description: DeerFlow exists because modern agent systems need more than a chat loop. A useful agent must plan over long horizons, break work into sub-tasks, use tools, manipulate files, run code safely, and preserve enough context to stay coherent across a complex task. DeerFlow was built to provide that runtime foundation. --- -import { Callout, Cards } from "nextra/components"; +import { Callout } from "nextra/components"; # Why DeerFlow diff --git a/frontend/src/content/zh/application/agents-and-threads.mdx b/frontend/src/content/zh/application/agents-and-threads.mdx index 6ad982fed..9074a9fe4 100644 --- a/frontend/src/content/zh/application/agents-and-threads.mdx +++ b/frontend/src/content/zh/application/agents-and-threads.mdx @@ -3,7 +3,7 @@ title: Agent 与线程 description: 了解 DeerFlow 中 Agent 与线程的关系,以及如何管理自定义 Agent 和对话线程。 --- -import { Callout, Cards, Steps } from "nextra/components"; +import { Callout, Steps } from "nextra/components"; # Agent 与线程 diff --git a/frontend/src/content/zh/application/configuration.mdx b/frontend/src/content/zh/application/configuration.mdx index 94e78120c..2114a8d49 100644 --- a/frontend/src/content/zh/application/configuration.mdx +++ b/frontend/src/content/zh/application/configuration.mdx @@ -3,7 +3,7 @@ title: 配置 description: 本页面涵盖 DeerFlow 应用的所有配置层——`config.yaml`、前端环境变量、`extensions_config.json` 和运行时环境变量。 --- -import { Callout, Cards, Tabs } from "nextra/components"; +import { Callout, Tabs } from "nextra/components"; # 配置 diff --git a/frontend/src/content/zh/application/deployment-guide.mdx b/frontend/src/content/zh/application/deployment-guide.mdx index 635120337..9e3f07e03 100644 --- a/frontend/src/content/zh/application/deployment-guide.mdx +++ b/frontend/src/content/zh/application/deployment-guide.mdx @@ -3,7 +3,7 @@ title: 部署指南 description: 本指南涵盖 DeerFlow 应用所有支持的部署方式:本地开发、Docker Compose 以及使用 Kubernetes 管理沙箱的生产环境。 --- -import { Callout, Cards, Steps, Tabs } from "nextra/components"; +import { Callout, Steps, Tabs } from "nextra/components"; # 部署指南 diff --git a/frontend/src/content/zh/application/index.mdx b/frontend/src/content/zh/application/index.mdx index c12959b42..52456c927 100644 --- a/frontend/src/content/zh/application/index.mdx +++ b/frontend/src/content/zh/application/index.mdx @@ -3,7 +3,7 @@ title: DeerFlow 应用 description: DeerFlow 应用是 DeerFlow 生产体验的参考实现。它将 Harness 运行时、基于 Web 的对话工作区、API Gateway 和反向代理组合成一个可部署的完整系统。 --- -import { Callout, Cards } from "nextra/components"; +import { Callout } from "nextra/components"; # DeerFlow 应用 diff --git a/frontend/src/content/zh/application/operations-and-troubleshooting.mdx b/frontend/src/content/zh/application/operations-and-troubleshooting.mdx index 8dc4c6551..43b8b463f 100644 --- a/frontend/src/content/zh/application/operations-and-troubleshooting.mdx +++ b/frontend/src/content/zh/application/operations-and-troubleshooting.mdx @@ -3,7 +3,7 @@ title: 运维与排障 description: 本页面涵盖运行 DeerFlow 应用的操作信息:日志记录、常见问题和维护任务。 --- -import { Callout, Cards } from "nextra/components"; +import { Callout } from "nextra/components"; # 运维与排障 diff --git a/frontend/src/content/zh/application/quick-start.mdx b/frontend/src/content/zh/application/quick-start.mdx index b5ab052fc..1ed0ac423 100644 --- a/frontend/src/content/zh/application/quick-start.mdx +++ b/frontend/src/content/zh/application/quick-start.mdx @@ -3,7 +3,7 @@ title: 快速上手 description: 本指南引导你使用 `make dev` 工作流在本地机器上启动 DeerFlow 应用。Gateway、前端和 nginx 会一起启动,通过单个 URL 访问。 --- -import { Callout, Cards, Steps } from "nextra/components"; +import { Callout, Steps } from "nextra/components"; # 快速上手 diff --git a/frontend/src/content/zh/application/workspace-usage.mdx b/frontend/src/content/zh/application/workspace-usage.mdx index 35cafcc84..f06604d84 100644 --- a/frontend/src/content/zh/application/workspace-usage.mdx +++ b/frontend/src/content/zh/application/workspace-usage.mdx @@ -3,7 +3,7 @@ title: 工作区使用 description: DeerFlow 工作区是一个基于浏览器的对话界面,你可以在其中向 Agent 发送消息、上传文件、查看中间步骤,以及下载生成的产出物。 --- -import { Callout, Cards } from "nextra/components"; +import { Callout } from "nextra/components"; # 工作区使用 diff --git a/frontend/src/content/zh/harness/configuration.mdx b/frontend/src/content/zh/harness/configuration.mdx index 1b5cf0207..9021b2f0c 100644 --- a/frontend/src/content/zh/harness/configuration.mdx +++ b/frontend/src/content/zh/harness/configuration.mdx @@ -3,7 +3,7 @@ title: 配置 description: DeerFlow 的配置系统围绕一个目标设计:每一个有意义的行为都应该可以在配置文件中表达,而不是硬编码在应用程序中。这使部署可重现、可审计,并且易于按环境定制。 --- -import { Callout, Cards } from "nextra/components"; +import { Callout } from "nextra/components"; # 配置 diff --git a/frontend/src/content/zh/harness/customization.mdx b/frontend/src/content/zh/harness/customization.mdx index 3b77c0394..da9c9ee44 100644 --- a/frontend/src/content/zh/harness/customization.mdx +++ b/frontend/src/content/zh/harness/customization.mdx @@ -3,7 +3,7 @@ title: 自定义与扩展 description: DeerFlow 的可插拔架构意味着系统的大多数部分都可以在不 fork 核心的情况下被替换或扩展。本页面列举了扩展点,并解释如何使用每一个。 --- -import { Callout, Cards } from "nextra/components"; +import { Callout } from "nextra/components"; # 自定义与扩展 diff --git a/frontend/src/content/zh/harness/design-principles.mdx b/frontend/src/content/zh/harness/design-principles.mdx index 97498a91c..a4317d013 100644 --- a/frontend/src/content/zh/harness/design-principles.mdx +++ b/frontend/src/content/zh/harness/design-principles.mdx @@ -3,7 +3,7 @@ title: 设计理念 description: 了解 DeerFlow Harness 背后的设计理念,有助于你有效地使用它、自信地扩展它,并推断 Agent 在生产环境中的行为方式。 --- -import { Callout, Cards } from "nextra/components"; +import { Callout } from "nextra/components"; # 设计理念 diff --git a/frontend/src/content/zh/harness/index.mdx b/frontend/src/content/zh/harness/index.mdx index 6c57cd010..a5d85c1cc 100644 --- a/frontend/src/content/zh/harness/index.mdx +++ b/frontend/src/content/zh/harness/index.mdx @@ -3,7 +3,7 @@ title: 安装 DeerFlow Harness description: DeerFlow Harness 是构建自己 Super Agent 系统的 Python SDK 和运行时基础。 --- -import { Callout, Cards } from "nextra/components"; +import { Callout } from "nextra/components"; # 安装 DeerFlow Harness diff --git a/frontend/src/content/zh/harness/integration-guide.mdx b/frontend/src/content/zh/harness/integration-guide.mdx index ea0a58c3f..3addf1bde 100644 --- a/frontend/src/content/zh/harness/integration-guide.mdx +++ b/frontend/src/content/zh/harness/integration-guide.mdx @@ -3,7 +3,7 @@ title: 集成指南 description: DeerFlow Harness 不仅仅是一个独立应用程序——它是一个可以导入并在你自己的后端、API 服务器、自动化系统或多 Agent 协调器中使用的 Python 库。 --- -import { Callout, Cards } from "nextra/components"; +import { Callout } from "nextra/components"; # 集成指南 diff --git a/frontend/src/content/zh/harness/lead-agent.mdx b/frontend/src/content/zh/harness/lead-agent.mdx index 5e298a809..f284ba4b8 100644 --- a/frontend/src/content/zh/harness/lead-agent.mdx +++ b/frontend/src/content/zh/harness/lead-agent.mdx @@ -3,7 +3,7 @@ title: Lead Agent description: Lead Agent 是 DeerFlow 线程中的核心执行者。每个对话、任务和工作流都通过它进行。理解它的工作方式有助于你有效地配置它,并在需要时扩展它。 --- -import { Callout, Cards, Steps } from "nextra/components"; +import { Callout, Steps } from "nextra/components"; # Lead Agent diff --git a/frontend/src/content/zh/harness/mcp.mdx b/frontend/src/content/zh/harness/mcp.mdx index 0b076aff8..eaa68c954 100644 --- a/frontend/src/content/zh/harness/mcp.mdx +++ b/frontend/src/content/zh/harness/mcp.mdx @@ -3,7 +3,7 @@ title: MCP 集成 description: Model Context Protocol(MCP) 是连接语言模型与外部工具和数据源的开放标准。DeerFlow 的 MCP 集成允许你用任何实现了 MCP 协议的工具服务器扩展 Agent——无需修改 Harness 本身。 --- -import { Callout, Cards, Steps } from "nextra/components"; +import { Callout, Steps } from "nextra/components"; # MCP 集成 diff --git a/frontend/src/content/zh/harness/memory.mdx b/frontend/src/content/zh/harness/memory.mdx index edf2a0e26..e168a7d38 100644 --- a/frontend/src/content/zh/harness/memory.mdx +++ b/frontend/src/content/zh/harness/memory.mdx @@ -3,7 +3,7 @@ title: 记忆系统 description: 记忆是 DeerFlow Harness 的一个运行时功能。它不是简单的对话日志,而是跨多个独立会话持久化、在未来对话中影响 Agent 行为的结构化事实和上下文摘要存储。 --- -import { Callout, Cards } from "nextra/components"; +import { Callout } from "nextra/components"; # 记忆系统 diff --git a/frontend/src/content/zh/harness/quick-start.mdx b/frontend/src/content/zh/harness/quick-start.mdx index 3da8c7b3f..349eef308 100644 --- a/frontend/src/content/zh/harness/quick-start.mdx +++ b/frontend/src/content/zh/harness/quick-start.mdx @@ -3,7 +3,7 @@ title: 快速上手 description: 学习如何使用 create_deerflow_agent 创建并运行 DeerFlow Agent,从模型初始化到流式响应。 --- -import { Callout, Cards, Steps } from "nextra/components"; +import { Callout, Steps } from "nextra/components"; # 快速上手 diff --git a/frontend/src/content/zh/harness/sandbox.mdx b/frontend/src/content/zh/harness/sandbox.mdx index 2b01718d6..f4f3c88d7 100644 --- a/frontend/src/content/zh/harness/sandbox.mdx +++ b/frontend/src/content/zh/harness/sandbox.mdx @@ -3,7 +3,7 @@ title: 沙箱 description: 沙箱为 Lead Agent 提供一个受控环境,在其中可以读取文件、写入输出、运行 Shell 命令并生成产出物。没有沙箱,Agent 只能生成文本;有了沙箱,它可以编写和执行代码、处理数据文件、生成图表并构建交付物。 --- -import { Callout, Cards, Tabs } from "nextra/components"; +import { Callout, Tabs } from "nextra/components"; # 沙箱 diff --git a/frontend/src/content/zh/harness/skills.mdx b/frontend/src/content/zh/harness/skills.mdx index 9b578da01..56d112ee1 100644 --- a/frontend/src/content/zh/harness/skills.mdx +++ b/frontend/src/content/zh/harness/skills.mdx @@ -3,7 +3,7 @@ title: 技能 description: 技能不仅仅是提示词。它是一个自包含的能力包,可以包含结构化指令、分步工作流、领域最佳实践、支撑资源和工具配置。技能按需加载——在任务需要时注入内容,否则不影响上下文。 --- -import { Callout, Cards, FileTree, Steps } from "nextra/components"; +import { Callout, FileTree, Steps } from "nextra/components"; # 技能 diff --git a/frontend/src/content/zh/harness/subagents.mdx b/frontend/src/content/zh/harness/subagents.mdx index 0f99a398a..53ed30de9 100644 --- a/frontend/src/content/zh/harness/subagents.mdx +++ b/frontend/src/content/zh/harness/subagents.mdx @@ -3,7 +3,7 @@ title: 子 Agent description: 当一个任务对单个推理线程来说太宽泛,或者部分任务可以并行完成时,Lead Agent 将工作委派给**子 Agent**。子 Agent 是一个独立的 Agent 调用,接收特定任务、执行并返回结果。 --- -import { Callout, Cards } from "nextra/components"; +import { Callout } from "nextra/components"; # 子 Agent diff --git a/frontend/src/content/zh/harness/tools.mdx b/frontend/src/content/zh/harness/tools.mdx index 60ce3aac4..c3fbc6afb 100644 --- a/frontend/src/content/zh/harness/tools.mdx +++ b/frontend/src/content/zh/harness/tools.mdx @@ -3,7 +3,7 @@ title: 工具 description: Lead Agent 是一个工具调用 Agent。工具是它与世界交互的方式:搜索网络、读写文件、运行命令、委派任务以及向用户呈现输出。 --- -import { Callout, Cards, Tabs } from "nextra/components"; +import { Callout, Tabs } from "nextra/components"; # 工具 diff --git a/frontend/src/content/zh/introduction/core-concepts.mdx b/frontend/src/content/zh/introduction/core-concepts.mdx index df3bfe4ad..6d0d0a307 100644 --- a/frontend/src/content/zh/introduction/core-concepts.mdx +++ b/frontend/src/content/zh/introduction/core-concepts.mdx @@ -3,7 +3,7 @@ title: 核心概念 description: 在深入了解 DeerFlow 之前,先建立一些贯穿整个系统的核心概念。这些概念解释了 DeerFlow 的优化目标以及其架构设计的原因。 --- -import { Callout, Cards } from "nextra/components"; +import { Callout } from "nextra/components"; # 核心概念 diff --git a/frontend/src/content/zh/introduction/harness-vs-app.mdx b/frontend/src/content/zh/introduction/harness-vs-app.mdx index bd31b4bad..b99e689e1 100644 --- a/frontend/src/content/zh/introduction/harness-vs-app.mdx +++ b/frontend/src/content/zh/introduction/harness-vs-app.mdx @@ -3,7 +3,7 @@ title: Harness 与应用 description: DeerFlow 有两个紧密相关但服务于不同目的的层次:. --- -import { Callout, Cards } from "nextra/components"; +import { Callout } from "nextra/components"; # Harness 与应用 diff --git a/frontend/src/content/zh/introduction/index.mdx b/frontend/src/content/zh/introduction/index.mdx index 23392af2e..b57e73259 100644 --- a/frontend/src/content/zh/introduction/index.mdx +++ b/frontend/src/content/zh/introduction/index.mdx @@ -2,7 +2,6 @@ title: 简介 description: DeerFlow 是一个运行时 Harness,用于构建支持技能、记忆、工具和沙箱执行的长时序 Agent 系统。 --- -import { Cards } from "nextra/components"; # 简介 diff --git a/frontend/src/content/zh/introduction/why-deerflow.mdx b/frontend/src/content/zh/introduction/why-deerflow.mdx index 945d844f8..98b98f11e 100644 --- a/frontend/src/content/zh/introduction/why-deerflow.mdx +++ b/frontend/src/content/zh/introduction/why-deerflow.mdx @@ -3,7 +3,7 @@ title: 为什么选择 DeerFlow description: DeerFlow 的诞生是因为现代 Agent 系统需要的不仅仅是一个聊天循环。一个真正有用的 Agent 必须能够进行长时序规划、将任务拆解为子任务、使用工具、操作文件、安全地运行代码,并在复杂任务中保持足够的上下文连贯性。DeerFlow 正是为提供这样的运行时基础而构建的。 --- -import { Callout, Cards } from "nextra/components"; +import { Callout } from "nextra/components"; # 为什么选择 DeerFlow diff --git a/frontend/src/mdx-components.ts b/frontend/src/mdx-components.ts index 71182654c..80e143236 100644 --- a/frontend/src/mdx-components.ts +++ b/frontend/src/mdx-components.ts @@ -1,5 +1,8 @@ import { useMDXComponents as getThemeComponents } from "nextra-theme-docs"; // nextra-theme-blog or your custom theme +import { LocalizedCards } from "@/components/docs/localized-cards"; +import { LocalizedDocsLink } from "@/components/docs/localized-mdx-components"; + // Get the default MDX components const themeComponents = getThemeComponents(); @@ -7,5 +10,7 @@ const themeComponents = getThemeComponents(); export function useMDXComponents() { return { ...themeComponents, + a: LocalizedDocsLink, + Cards: LocalizedCards, }; } diff --git a/frontend/tests/e2e/docs-localized-links.spec.ts b/frontend/tests/e2e/docs-localized-links.spec.ts new file mode 100644 index 000000000..4f1b59dee --- /dev/null +++ b/frontend/tests/e2e/docs-localized-links.spec.ts @@ -0,0 +1,54 @@ +import { expect, test } from "@playwright/test"; + +test.describe("Localized documentation links", () => { + test("keeps English card navigation in the English docs", async ({ + page, + }) => { + await page.goto("/en/docs/introduction/core-concepts"); + + const card = page.locator("a.nextra-card", { hasText: "Why DeerFlow" }); + await expect(card).toHaveAttribute( + "href", + "/en/docs/introduction/why-deerflow", + ); + + await card.click(); + await expect(page).toHaveURL(/\/en\/docs\/introduction\/why-deerflow$/); + await expect(page.locator("main h1")).toContainText("Why DeerFlow"); + }); + + test("keeps Chinese card navigation in the Chinese docs", async ({ + page, + }) => { + await page.goto("/zh/docs/introduction/core-concepts"); + + const card = page.locator("a.nextra-card", { hasText: "Harness 与应用" }); + await expect(card).toHaveAttribute( + "href", + "/zh/docs/introduction/harness-vs-app", + ); + + await card.click(); + await expect(page).toHaveURL(/\/zh\/docs\/introduction\/harness-vs-app$/); + await expect(page.locator("main h1")).toContainText("Harness 与应用"); + }); + + test("localizes regular Markdown links", async ({ page }) => { + await page.goto("/en/docs/application/workspace-usage"); + + const link = page + .locator("main") + .getByRole("link", { name: "Agents and Threads" }) + .first(); + await expect(link).toHaveAttribute( + "href", + "/en/docs/application/agents-and-threads", + ); + + await link.click(); + await expect(page).toHaveURL( + /\/en\/docs\/application\/agents-and-threads$/, + ); + await expect(page.locator("main h1")).toContainText("Agents and Threads"); + }); +}); diff --git a/frontend/tests/unit/components/docs/localized-links.test.ts b/frontend/tests/unit/components/docs/localized-links.test.ts new file mode 100644 index 000000000..b055b665b --- /dev/null +++ b/frontend/tests/unit/components/docs/localized-links.test.ts @@ -0,0 +1,65 @@ +import { readFileSync, readdirSync } from "node:fs"; +import { join, relative } from "node:path"; + +import { describe, expect, it } from "@rstest/core"; + +import { localizeDocsHref } from "@/components/docs/localized-links"; + +const CONTENT_ROOT = join(process.cwd(), "src/content"); + +function findMdxFiles(directory: string): string[] { + return readdirSync(directory, { withFileTypes: true }).flatMap((entry) => { + const path = join(directory, entry.name); + return entry.isDirectory() + ? findMdxFiles(path) + : entry.name.endsWith(".mdx") + ? [path] + : []; + }); +} + +describe("localizeDocsHref", () => { + it.each([ + ["/docs", "en", "/en/docs"], + ["/docs/introduction", "en", "/en/docs/introduction"], + [ + "/docs/introduction?tab=overview#next", + "zh", + "/zh/docs/introduction?tab=overview#next", + ], + ])("localizes %s for %s", (href, lang, expected) => { + expect(localizeDocsHref(href, lang)).toBe(expected); + }); + + it.each([ + ["/en/docs/introduction", "zh"], + ["/zh/docs/introduction", "en"], + ["https://example.com/docs", "en"], + ["#overview", "zh"], + ["mailto:docs@example.com", "en"], + ["/workspace", "zh"], + ["/docs-extra", "en"], + ["/docs/introduction", "fr"], + ["/docs/introduction", undefined], + ])("leaves %s unchanged for language %s", (href, lang) => { + expect(localizeDocsHref(href, lang)).toBe(href); + }); +}); + +describe("documentation Cards imports", () => { + it("does not bypass the locale-aware MDX Cards component", () => { + const violations = findMdxFiles(CONTENT_ROOT) + .filter((path) => { + const source = readFileSync(path, "utf8"); + const nextraImports = source.matchAll( + /import\s*\{([^}]*)\}\s*from\s*["']nextra\/components["']/g, + ); + return [...nextraImports].some((match) => + match[1]?.split(",").some((name) => name.trim() === "Cards"), + ); + }) + .map((path) => relative(CONTENT_ROOT, path)); + + expect(violations).toEqual([]); + }); +});