From 3549dbf871c59e16358fc8452e695cab7b74c74a Mon Sep 17 00:00:00 2001 From: Ryker_Feng <90562015+18062706139fcz@users.noreply.github.com> Date: Mon, 27 Jul 2026 22:52:36 +0800 Subject: [PATCH] fix(frontend): localize conversation export failures (#4493) --- .../components/workspace/export-trigger.tsx | 27 +++++++++---------- .../components/workspace/recent-chat-list.tsx | 15 +++-------- frontend/src/core/i18n/locales/en-US.ts | 1 + frontend/src/core/i18n/locales/types.ts | 1 + frontend/src/core/i18n/locales/zh-CN.ts | 1 + frontend/src/core/threads/export.ts | 14 ++++++++++ 6 files changed, 33 insertions(+), 26 deletions(-) diff --git a/frontend/src/components/workspace/export-trigger.tsx b/frontend/src/components/workspace/export-trigger.tsx index a42784a54..66bed29a0 100644 --- a/frontend/src/components/workspace/export-trigger.tsx +++ b/frontend/src/components/workspace/export-trigger.tsx @@ -12,10 +12,7 @@ import { DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; import { useI18n } from "@/core/i18n/hooks"; -import { - exportThreadAsJSON, - exportThreadAsMarkdown, -} from "@/core/threads/export"; +import { exportThread, type ThreadExportFormat } from "@/core/threads/export"; import type { AgentThread } from "@/core/threads/types"; import { useThread } from "./messages/context"; @@ -28,23 +25,23 @@ export function ExportTrigger({ threadId }: { threadId: string }) { const messages = thread.messages; const handleExport = useCallback( - (format: "markdown" | "json") => { + (format: ThreadExportFormat) => { if (messages.length === 0) { toast.error(t.conversation.noMessages); return; } - const agentThread = { - thread_id: threadId, - updated_at: new Date().toISOString(), - values: thread.values, - } as AgentThread; + try { + const agentThread = { + thread_id: threadId, + updated_at: new Date().toISOString(), + values: thread.values, + } as AgentThread; - if (format === "markdown") { - exportThreadAsMarkdown(agentThread, messages); - } else { - exportThreadAsJSON(agentThread, messages); + exportThread(agentThread, messages, format); + toast.success(t.common.exportSuccess); + } catch { + toast.error(t.common.exportFailed); } - toast.success(t.common.exportSuccess); }, [messages, thread.values, threadId, t], ); diff --git a/frontend/src/components/workspace/recent-chat-list.tsx b/frontend/src/components/workspace/recent-chat-list.tsx index c7fd24cb7..d990d327f 100644 --- a/frontend/src/components/workspace/recent-chat-list.tsx +++ b/frontend/src/components/workspace/recent-chat-list.tsx @@ -48,10 +48,7 @@ import { resetThreadChatAfterDelete } from "@/components/workspace/chats/use-thr import { getAPIClient } from "@/core/api"; import { writeTextToClipboard } from "@/core/clipboard"; import { useI18n } from "@/core/i18n/hooks"; -import { - exportThreadAsJSON, - exportThreadAsMarkdown, -} from "@/core/threads/export"; +import { exportThread, type ThreadExportFormat } from "@/core/threads/export"; import { useDeleteThread, useInfiniteThreads, @@ -239,7 +236,7 @@ export function RecentChatList() { ); const handleExport = useCallback( - async (thread: AgentThread, format: "markdown" | "json") => { + async (thread: AgentThread, format: ThreadExportFormat) => { try { const apiClient = getAPIClient(); const state = await apiClient.threads.getState( @@ -250,14 +247,10 @@ export function RecentChatList() { toast.error(t.conversation.noMessages); return; } - if (format === "markdown") { - exportThreadAsMarkdown(thread, messages); - } else { - exportThreadAsJSON(thread, messages); - } + exportThread(thread, messages, format); toast.success(t.common.exportSuccess); } catch { - toast.error("Failed to export conversation"); + toast.error(t.common.exportFailed); } }, [t], diff --git a/frontend/src/core/i18n/locales/en-US.ts b/frontend/src/core/i18n/locales/en-US.ts index 3bc7b022c..d3371d8ec 100644 --- a/frontend/src/core/i18n/locales/en-US.ts +++ b/frontend/src/core/i18n/locales/en-US.ts @@ -51,6 +51,7 @@ export const enUS: Translations = { exportAsMarkdown: "Export as Markdown", exportAsJSON: "Export as JSON", exportSuccess: "Conversation exported", + exportFailed: "Failed to export conversation.", regenerate: "Regenerate", editAndRerun: "Edit and rerun", updateAndRerun: "Update and rerun", diff --git a/frontend/src/core/i18n/locales/types.ts b/frontend/src/core/i18n/locales/types.ts index 47cbcb260..1a9927627 100644 --- a/frontend/src/core/i18n/locales/types.ts +++ b/frontend/src/core/i18n/locales/types.ts @@ -40,6 +40,7 @@ export interface Translations { exportAsMarkdown: string; exportAsJSON: string; exportSuccess: string; + exportFailed: string; regenerate: string; editAndRerun: string; updateAndRerun: string; diff --git a/frontend/src/core/i18n/locales/zh-CN.ts b/frontend/src/core/i18n/locales/zh-CN.ts index 0aa82f9ec..7cffa37c1 100644 --- a/frontend/src/core/i18n/locales/zh-CN.ts +++ b/frontend/src/core/i18n/locales/zh-CN.ts @@ -51,6 +51,7 @@ export const zhCN: Translations = { exportAsMarkdown: "导出为 Markdown", exportAsJSON: "导出为 JSON", exportSuccess: "对话已导出", + exportFailed: "导出对话失败。", regenerate: "重新生成", editAndRerun: "编辑并重新运行", updateAndRerun: "更新并重新运行", diff --git a/frontend/src/core/threads/export.ts b/frontend/src/core/threads/export.ts index 02eeeb910..ce86ec9a0 100644 --- a/frontend/src/core/threads/export.ts +++ b/frontend/src/core/threads/export.ts @@ -30,6 +30,8 @@ export interface ExportOptions { includeHidden?: boolean; } +export type ThreadExportFormat = "markdown" | "json"; + function visibleMessages( messages: Message[], options: ExportOptions, @@ -222,3 +224,15 @@ export function exportThreadAsJSON(thread: AgentThread, messages: Message[]) { const filename = `${sanitizeFilename(titleOfThread(thread))}.json`; downloadAsFile(json, filename, "application/json;charset=utf-8"); } + +export function exportThread( + thread: AgentThread, + messages: Message[], + format: ThreadExportFormat, +) { + if (format === "markdown") { + exportThreadAsMarkdown(thread, messages); + } else { + exportThreadAsJSON(thread, messages); + } +}