From 32c6e4d0df395432252d92cc944e72acbba31732 Mon Sep 17 00:00:00 2001 From: hanlinyu1030 Date: Wed, 5 Aug 2026 15:56:35 +0800 Subject: [PATCH 1/2] fix(workspace): ensure default session on name collision and reject case-duplicate folder --- .../NewProjectDialog/NewProjectDialog.tsx | 17 ++++++++++++++++- .../src/flow_chat/services/FlowChatManager.ts | 10 ++++++---- src/web-ui/src/locales/en-US/common.json | 3 ++- src/web-ui/src/locales/zh-CN/common.json | 3 ++- src/web-ui/src/locales/zh-TW/common.json | 3 ++- 5 files changed, 28 insertions(+), 8 deletions(-) diff --git a/src/web-ui/src/app/components/NewProjectDialog/NewProjectDialog.tsx b/src/web-ui/src/app/components/NewProjectDialog/NewProjectDialog.tsx index 4ce9a43429..1f42c8fbc5 100644 --- a/src/web-ui/src/app/components/NewProjectDialog/NewProjectDialog.tsx +++ b/src/web-ui/src/app/components/NewProjectDialog/NewProjectDialog.tsx @@ -16,7 +16,7 @@ import { useTranslation } from 'react-i18next'; import { createLogger } from '@/shared/utils/logger'; import { Modal, Button, Input, Tooltip } from '@/component-library'; import './NewProjectDialog.scss'; -import {workspaceAPI} from "@/infrastructure"; +import {workspaceAPI, systemAPI} from "@/infrastructure"; import { notificationService } from '@/shared/notification-system'; const log = createLogger('NewProjectDialog'); @@ -82,6 +82,21 @@ export const NewProjectDialog: React.FC = ({ return; } + // Pre-creation existence / case-collision check. On Windows/macOS the + // filesystem is case-insensitive, so "MyProject" and "myproject" resolve to + // the same folder; createDirectory is idempotent and would silently succeed + // without creating a new folder. Surface a clear error before attempting. + const trimmedName = projectName.trim(); + const fullPath = `${parentPath.replace(/\\/g, '/')}/${trimmedName}`; + try { + if (await systemAPI.checkPathExists(fullPath)) { + setError(t('newProject.errorAlreadyExists')); + return; + } + } catch (error) { + log.error('Failed to check path existence', error); + } + setIsCreating(true); setError(''); diff --git a/src/web-ui/src/flow_chat/services/FlowChatManager.ts b/src/web-ui/src/flow_chat/services/FlowChatManager.ts index 6ceff7faa9..5a2b61fbba 100644 --- a/src/web-ui/src/flow_chat/services/FlowChatManager.ts +++ b/src/web-ui/src/flow_chat/services/FlowChatManager.ts @@ -255,10 +255,12 @@ export class FlowChatManager { nextCursor = nextPage.nextCursor; } } - const hasHistoricalSessions = - workspaceSessions.length > 0 || - initialMetadataPage.totalTopLevelCount > 0 || - initialMetadataPage.sessions.length > 0; + // Count only sessions that belong to THIS workspace (already path-filtered + // above). Counting all sessions in the storage dir (totalTopLevelCount / + // initialMetadataPage.sessions.length) incorrectly reports "has history" + // when another workspace shares the slug-collided sessions/ dir, which + // suppresses default-session creation for a newly opened workspace. + const hasHistoricalSessions = workspaceSessions.length > 0; const isCurrentInitializationRequest = () => this.latestInitializationRequestKey === requestKey; const activeSession = state.activeSessionId diff --git a/src/web-ui/src/locales/en-US/common.json b/src/web-ui/src/locales/en-US/common.json index 9235a0a53e..18df5d8aa4 100644 --- a/src/web-ui/src/locales/en-US/common.json +++ b/src/web-ui/src/locales/en-US/common.json @@ -637,7 +637,8 @@ "errorSelectParent": "Please select a parent directory", "errorEnterName": "Please enter a project name", "errorCreateFailed": "Failed to create project", - "errorInvalidName": "Project name cannot contain these characters: / \\ : * ? \" < > |" + "errorInvalidName": "Project name cannot contain these characters: / \\ : * ? \" < > |", + "errorAlreadyExists": "A workspace with this name already exists at the selected location" }, "peerDirectoryPicker": { "loading": "Loading remote directories…", diff --git a/src/web-ui/src/locales/zh-CN/common.json b/src/web-ui/src/locales/zh-CN/common.json index eed43eb601..25baa45db2 100644 --- a/src/web-ui/src/locales/zh-CN/common.json +++ b/src/web-ui/src/locales/zh-CN/common.json @@ -637,7 +637,8 @@ "errorSelectParent": "请选择父目录", "errorEnterName": "请输入工作区名称", "errorCreateFailed": "创建工作区失败", - "errorInvalidName": "工作区名称不能包含以下字符:/ \\ : * ? \" < > |" + "errorInvalidName": "工作区名称不能包含以下字符:/ \\ : * ? \" < > |", + "errorAlreadyExists": "所选位置已存在同名工作区" }, "peerDirectoryPicker": { "loading": "正在加载远程目录…", diff --git a/src/web-ui/src/locales/zh-TW/common.json b/src/web-ui/src/locales/zh-TW/common.json index 05f72415ae..28b5e892e0 100644 --- a/src/web-ui/src/locales/zh-TW/common.json +++ b/src/web-ui/src/locales/zh-TW/common.json @@ -637,7 +637,8 @@ "errorSelectParent": "請選擇父目錄", "errorEnterName": "請輸入工作區名稱", "errorCreateFailed": "建立工作區失敗", - "errorInvalidName": "工作區名稱不能包含以下字符:/ \\ : * ? \" < > |" + "errorInvalidName": "工作區名稱不能包含以下字符:/ \\ : * ? \" < > |", + "errorAlreadyExists": "所選位置已存在同名工作區" }, "peerDirectoryPicker": { "loading": "正在載入遠端目錄…", From 3ed4dc43f0da5bacb13e92ab11725f5e278cd366 Mon Sep 17 00:00:00 2001 From: hanlinyu1030 Date: Wed, 5 Aug 2026 17:53:41 +0800 Subject: [PATCH 2/2] fix(workspace): localize create/open errors and persist default session title key --- .../NewProjectDialog/NewProjectDialog.tsx | 14 ++++++++++++- .../review-platform/ReviewPlatformPanel.tsx | 7 ++++++- .../src/flow_chat/components/ChatInput.tsx | 14 +++++++++---- .../components/btw/BtwSessionPanel.tsx | 9 ++++++-- .../components/modern/ExportImageButton.tsx | 7 ++++++- .../flow-chat-manager/MessageModule.ts | 21 ++++++++++++------- .../flow-chat-manager/SessionModule.ts | 8 ++++++- .../api/errors/TauriCommandError.ts | 8 ++++--- .../services/business/workspaceManager.ts | 8 ++++++- src/web-ui/src/locales/en-US/common.json | 5 ++++- src/web-ui/src/locales/en-US/flow-chat.json | 4 +++- src/web-ui/src/locales/zh-CN/common.json | 5 ++++- src/web-ui/src/locales/zh-CN/flow-chat.json | 4 +++- src/web-ui/src/locales/zh-TW/common.json | 5 ++++- src/web-ui/src/locales/zh-TW/flow-chat.json | 4 +++- 15 files changed, 96 insertions(+), 27 deletions(-) diff --git a/src/web-ui/src/app/components/NewProjectDialog/NewProjectDialog.tsx b/src/web-ui/src/app/components/NewProjectDialog/NewProjectDialog.tsx index 1f42c8fbc5..4c261b7381 100644 --- a/src/web-ui/src/app/components/NewProjectDialog/NewProjectDialog.tsx +++ b/src/web-ui/src/app/components/NewProjectDialog/NewProjectDialog.tsx @@ -17,6 +17,7 @@ import { createLogger } from '@/shared/utils/logger'; import { Modal, Button, Input, Tooltip } from '@/component-library'; import './NewProjectDialog.scss'; import {workspaceAPI, systemAPI} from "@/infrastructure"; +import { isTauriCommandError } from '@/infrastructure/api/errors/TauriCommandError'; import { notificationService } from '@/shared/notification-system'; const log = createLogger('NewProjectDialog'); @@ -81,6 +82,10 @@ export const NewProjectDialog: React.FC = ({ notificationService.warning(t('newProject.errorInvalidName'), { duration: 4500 }); return; } + if (projectName.trim().length > 255) { + setError(t('newProject.errorNameTooLong')); + return; + } // Pre-creation existence / case-collision check. On Windows/macOS the // filesystem is case-insensitive, so "MyProject" and "myproject" resolve to @@ -107,7 +112,14 @@ export const NewProjectDialog: React.FC = ({ onClose(); } catch (error) { log.error('Failed to create project', error); - const message = error instanceof Error && error.message ? error.message : t('newProject.errorCreateFailed'); + let message: string; + if (isTauriCommandError(error) && error.isPermissionError()) { + message = t('newProject.errorParentNoAccess'); + } else if (error instanceof Error && /does not exist|not a directory/i.test(error.message)) { + message = t('newProject.errorPathNotFound'); + } else { + message = t('newProject.errorCreateFailed'); + } setError(message); notificationService.error(message, { duration: 4500 }); } finally { diff --git a/src/web-ui/src/app/components/panels/review-platform/ReviewPlatformPanel.tsx b/src/web-ui/src/app/components/panels/review-platform/ReviewPlatformPanel.tsx index 7ca1fb5d53..4509dd7414 100644 --- a/src/web-ui/src/app/components/panels/review-platform/ReviewPlatformPanel.tsx +++ b/src/web-ui/src/app/components/panels/review-platform/ReviewPlatformPanel.tsx @@ -436,6 +436,9 @@ function reviewSessionLifecycle(session: Session): LinkedReviewSession['lifecycl } function getSessionTitle(session?: Session, fallback = 'Review session'): string { + if (session?.titleSource === 'i18n' && session.titleI18nKey) { + return i18nService.t(session.titleI18nKey, session.titleI18nParams ?? {}) || fallback; + } return session?.title?.trim() || fallback; } @@ -1852,7 +1855,9 @@ export const ReviewPlatformPanel: React.FC = ({ workspacePath: linked.childSession.workspacePath, expand: true, sessionKind: linked.kind, - sessionTitle: linked.title, + sessionTitle: linked.childSession.titleSource === 'i18n' && linked.childSession.titleI18nKey + ? (i18nService.t(linked.childSession.titleI18nKey, linked.childSession.titleI18nParams ?? {}) || linked.title) + : linked.title, agentType: linked.childSession.config.agentType ?? (linked.kind === 'deep_review' ? 'DeepReview' : 'CodeReview'), }); }; diff --git a/src/web-ui/src/flow_chat/components/ChatInput.tsx b/src/web-ui/src/flow_chat/components/ChatInput.tsx index 8a48880835..5f2cc541fe 100644 --- a/src/web-ui/src/flow_chat/components/ChatInput.tsx +++ b/src/web-ui/src/flow_chat/components/ChatInput.tsx @@ -9,6 +9,8 @@ import { useTranslation } from 'react-i18next'; import { ArrowUp, BotMessageSquare, Image, RotateCcw, Plus, X, Sparkles, Loader2, ChevronRight, Files, MessageSquarePlus, Star } from 'lucide-react'; import { ContextDropZone, useContextStore } from '../../shared/context-system'; import { useActiveSessionState } from '@/flow_chat/hooks'; +import { i18nService } from '@/infrastructure/i18n'; +import { resolveSessionTitle } from '../utils/sessionTitle'; import { RichTextInput, type InlineTriggerState, @@ -476,7 +478,12 @@ export const ChatInput: React.FC = ({ const threadGoalController = useThreadGoalController(effectiveTargetSession, { isBtwSession, }); - const currentSessionTitle = currentSession?.title?.trim() || t('session.untitled'); + // Resolve via the i18n key (re-localizes on locale switch) instead of the + // persisted localized session.title string, so this tab stays in sync with + // the sidebar/header/toolbar instead of showing a stale old-locale name. + const currentSessionTitle = currentSession + ? resolveSessionTitle(currentSession, (key, options) => i18nService.t(key, options)) + : t('session.untitled'); const activeBtwSession = activeBtwSessionId ? flowChatState.sessions.get(activeBtwSessionId) : undefined; @@ -492,10 +499,9 @@ export const ChatInput: React.FC = ({ const activeBtwTargetLabel = t(`childSession.kinds.${activeBtwKind}.short`, { defaultValue: t('chatInput.targetBtw'), }); + const activeBtwFallbackKey = `childSession.kinds.${activeBtwKind}.title`; const activeBtwSessionTitle = activeBtwSession - ? activeBtwSession.title?.trim() || t(`childSession.kinds.${activeBtwKind}.title`, { - defaultValue: t('btw.threadLabel'), - }) + ? resolveSessionTitle(activeBtwSession, (key, options) => i18nService.t(key, options), activeBtwFallbackKey) || t('btw.threadLabel') : ''; const deferChatStripPassiveGitRefresh = diff --git a/src/web-ui/src/flow_chat/components/btw/BtwSessionPanel.tsx b/src/web-ui/src/flow_chat/components/btw/BtwSessionPanel.tsx index 002b53e132..c68e9568fc 100644 --- a/src/web-ui/src/flow_chat/components/btw/BtwSessionPanel.tsx +++ b/src/web-ui/src/flow_chat/components/btw/BtwSessionPanel.tsx @@ -1,5 +1,6 @@ import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react'; import {useTranslation} from 'react-i18next'; +import { i18nService } from '@/infrastructure/i18n'; import path from 'path-browserify'; import {CornerUpLeft, Link2, Square, Sparkles} from 'lucide-react'; import {FlowChatContext} from '../modern/FlowChatContext'; @@ -83,8 +84,12 @@ const PANEL_CONFIG: FlowChatConfig = { theme: 'dark', }; -const resolveSessionTitle = (session?: Session | null, fallback = 'Side thread') => - session?.title?.trim() || fallback; +const resolveSessionTitle = (session?: Session | null, fallback = 'Side thread') => { + if (session?.titleSource === 'i18n' && session.titleI18nKey) { + return i18nService.t(session.titleI18nKey, session.titleI18nParams ?? {}) || fallback; + } + return session?.title?.trim() || fallback; +}; const log = createLogger('BtwSessionPanel'); const REVIEW_ACTION_BOTTOM_BLANK_SPACE_PX = 96; const EMPTY_ACTION_ID_SET = new Set(); diff --git a/src/web-ui/src/flow_chat/components/modern/ExportImageButton.tsx b/src/web-ui/src/flow_chat/components/modern/ExportImageButton.tsx index 46ae59c835..6d62acc154 100644 --- a/src/web-ui/src/flow_chat/components/modern/ExportImageButton.tsx +++ b/src/web-ui/src/flow_chat/components/modern/ExportImageButton.tsx @@ -182,7 +182,12 @@ export const ExportImageButton: React.FC = ({ for (const [, session] of state.sessions) { const turn = session.dialogTurns.find((t: DialogTurn) => t.id === turnId); - if (turn) return { turn, sessionTitle: session.title?.trim() || '' }; + if (turn) { + const sessionTitle = session.titleSource === 'i18n' && session.titleI18nKey + ? (i18nService.t(session.titleI18nKey, session.titleI18nParams ?? {}) || '') + : (session.title?.trim() || ''); + return { turn, sessionTitle }; + } } return null; }, [turnId]); diff --git a/src/web-ui/src/flow_chat/services/flow-chat-manager/MessageModule.ts b/src/web-ui/src/flow_chat/services/flow-chat-manager/MessageModule.ts index 659ca4ae62..ed684d2b25 100644 --- a/src/web-ui/src/flow_chat/services/flow-chat-manager/MessageModule.ts +++ b/src/web-ui/src/flow_chat/services/flow-chat-manager/MessageModule.ts @@ -8,6 +8,7 @@ import { ACPClientAPI } from '@/infrastructure/api/service-api/ACPClientAPI'; import { configManager } from '@/infrastructure/config/services/ConfigManager'; import type { AIModelConfig, AgentModelDefaultsConfig, DefaultModelsConfig } from '@/infrastructure/config/types'; import { notificationService } from '../../../shared/notification-system'; +import { i18nService } from '@/infrastructure/i18n'; import { stateMachineManager } from '../../state-machine'; import { SessionExecutionEvent, SessionExecutionState } from '../../state-machine/types'; import { generateTempTitle } from '../../utils/titleUtils'; @@ -358,9 +359,15 @@ export async function sendMessage( } catch (error) { log.error('Failed to send message', { sessionId: sessionId, error }); - - const errorMessage = error instanceof Error ? error.message : 'Failed to send message'; - + + // Map the "workspace folder deleted/moved" backend error to a localized + // message; other errors pass through verbatim for diagnostics. The + // "Thinking process error" notification title was also hardcoded English. + const rawErrorMessage = error instanceof Error ? error.message : ''; + const errorMessage = /does not resolve to a local workspace/i.test(rawErrorMessage) + ? i18nService.t('flow-chat:errors.workspaceNotResolvable') + : (rawErrorMessage || i18nService.t('flow-chat:errors.sendFailed')); + const currentState = stateMachineManager.getCurrentState(sessionId); if (currentState === SessionExecutionState.PROCESSING) { await stateMachineManager.transition(sessionId, SessionExecutionEvent.ERROR_OCCURRED, { @@ -368,20 +375,20 @@ export async function sendMessage( }); await stateMachineManager.transition(sessionId, SessionExecutionEvent.RESET); } - + const state = context.flowChatStore.getState(); const currentSession = state.sessions.get(sessionId); if (createdLocalTurnId && currentSession && !options?.preserveTurnOnStartError) { context.flowChatStore.deleteDialogTurn(sessionId, createdLocalTurnId); } - + if (!options?.preserveTurnOnStartError) { notificationService.error(errorMessage, { - title: 'Thinking process error', + title: i18nService.t('flow-chat:errors.thinkingProcessError'), duration: 5000 }); } - + throw error; } } diff --git a/src/web-ui/src/flow_chat/services/flow-chat-manager/SessionModule.ts b/src/web-ui/src/flow_chat/services/flow-chat-manager/SessionModule.ts index fe600480ed..f26cd5bc75 100644 --- a/src/web-ui/src/flow_chat/services/flow-chat-manager/SessionModule.ts +++ b/src/web-ui/src/flow_chat/services/flow-chat-manager/SessionModule.ts @@ -18,7 +18,7 @@ import { WorkspaceKind, type WorkspaceInfo } from '@/shared/types'; import type { AIModelConfig, AgentModelDefaultsConfig, DefaultModelsConfig } from '@/infrastructure/config/types'; import type { FlowChatContext, SessionConfig } from './types'; import type { Session } from '../../types/flow-chat'; -import { touchSessionActivity, cleanupSaveState } from './PersistenceModule'; +import { touchSessionActivity, cleanupSaveState, updateSessionMetadata } from './PersistenceModule'; import { cleanupSessionBuffers } from './TextChunkModule'; import { createTextSessionTitleDescriptor, @@ -643,6 +643,12 @@ export async function createChatSession( titleDescriptor, ); + // Persist the title metadata (incl. the i18n title key/params) at creation + // so an empty session can re-localize its default name on a later reload + + // locale switch. createSession only stored the localized sessionName string; + // without this, empty sessions have no title key on disk and can't re-localize. + await updateSessionMetadata(context, response.sessionId); + return response.sessionId; }); diff --git a/src/web-ui/src/infrastructure/api/errors/TauriCommandError.ts b/src/web-ui/src/infrastructure/api/errors/TauriCommandError.ts index 6e48e9c0a7..5db7668cf2 100644 --- a/src/web-ui/src/infrastructure/api/errors/TauriCommandError.ts +++ b/src/web-ui/src/infrastructure/api/errors/TauriCommandError.ts @@ -58,10 +58,12 @@ export class TauriCommandError extends Error { public isPermissionError(): boolean { const message = this.message.toLowerCase(); - return message.includes('permission') || - message.includes('access') || + return message.includes('permission') || + message.includes('permitted') || + message.includes('access') || message.includes('unauthorized') || - message.includes('forbidden'); + message.includes('forbidden') || + message.includes('eperm'); } diff --git a/src/web-ui/src/infrastructure/services/business/workspaceManager.ts b/src/web-ui/src/infrastructure/services/business/workspaceManager.ts index 5ea7ca2f6f..39dd8ee49c 100644 --- a/src/web-ui/src/infrastructure/services/business/workspaceManager.ts +++ b/src/web-ui/src/infrastructure/services/business/workspaceManager.ts @@ -14,6 +14,7 @@ import { createLogger } from '@/shared/utils/logger'; import { startupTrace } from '@/shared/utils/startupTrace'; import { elapsedMs, nowMs } from '@/shared/utils/timing'; import { listen } from '@tauri-apps/api/event'; +import { i18nService } from '@/infrastructure/i18n'; const log = createLogger('WorkspaceManager'); @@ -625,7 +626,12 @@ class WorkspaceManager { return workspace; } catch (error) { log.error('Failed to open workspace', { path, error }); - const errorMessage = error instanceof Error ? error.message : String(error); + const rawMessage = error instanceof Error ? error.message : String(error); + // Map the common "folder moved/deleted" backend error to a localized + // message; other errors pass through verbatim (callers log the raw error). + const errorMessage = /does not exist|not a directory/i.test(rawMessage) + ? i18nService.t('common:newProject.errorPathNotFound') + : rawMessage; this.updateState({ loading: false, error: errorMessage }, { type: 'workspace:error', error: errorMessage }); throw error; } diff --git a/src/web-ui/src/locales/en-US/common.json b/src/web-ui/src/locales/en-US/common.json index 18df5d8aa4..562a2079fb 100644 --- a/src/web-ui/src/locales/en-US/common.json +++ b/src/web-ui/src/locales/en-US/common.json @@ -638,7 +638,10 @@ "errorEnterName": "Please enter a project name", "errorCreateFailed": "Failed to create project", "errorInvalidName": "Project name cannot contain these characters: / \\ : * ? \" < > |", - "errorAlreadyExists": "A workspace with this name already exists at the selected location" + "errorAlreadyExists": "A workspace with this name already exists at the selected location", + "errorParentNoAccess": "No access permission for the selected parent directory", + "errorNameTooLong": "Project name is too long (max 255 characters)", + "errorPathNotFound": "The workspace folder does not exist or has been moved" }, "peerDirectoryPicker": { "loading": "Loading remote directories…", diff --git a/src/web-ui/src/locales/en-US/flow-chat.json b/src/web-ui/src/locales/en-US/flow-chat.json index 9f21591832..04abd08f68 100644 --- a/src/web-ui/src/locales/en-US/flow-chat.json +++ b/src/web-ui/src/locales/en-US/flow-chat.json @@ -2356,7 +2356,9 @@ } }, "errors": { - "sendFailed": "Failed to send message" + "sendFailed": "Failed to send message", + "thinkingProcessError": "Thinking process error", + "workspaceNotResolvable": "The workspace folder does not exist or has been moved" }, "actions": { "send": "Send" diff --git a/src/web-ui/src/locales/zh-CN/common.json b/src/web-ui/src/locales/zh-CN/common.json index 25baa45db2..6e40971ad7 100644 --- a/src/web-ui/src/locales/zh-CN/common.json +++ b/src/web-ui/src/locales/zh-CN/common.json @@ -638,7 +638,10 @@ "errorEnterName": "请输入工作区名称", "errorCreateFailed": "创建工作区失败", "errorInvalidName": "工作区名称不能包含以下字符:/ \\ : * ? \" < > |", - "errorAlreadyExists": "所选位置已存在同名工作区" + "errorAlreadyExists": "所选位置已存在同名工作区", + "errorParentNoAccess": "没有所选父目录的访问权限", + "errorNameTooLong": "工作区名称过长(最多 255 个字符)", + "errorPathNotFound": "工作区文件夹不存在或已被移动" }, "peerDirectoryPicker": { "loading": "正在加载远程目录…", diff --git a/src/web-ui/src/locales/zh-CN/flow-chat.json b/src/web-ui/src/locales/zh-CN/flow-chat.json index b3bdf8a786..2e073185f8 100644 --- a/src/web-ui/src/locales/zh-CN/flow-chat.json +++ b/src/web-ui/src/locales/zh-CN/flow-chat.json @@ -2356,7 +2356,9 @@ } }, "errors": { - "sendFailed": "发送消息失败" + "sendFailed": "发送消息失败", + "thinkingProcessError": "思考过程错误", + "workspaceNotResolvable": "工作区文件夹不存在或已被移动" }, "actions": { "send": "发送" diff --git a/src/web-ui/src/locales/zh-TW/common.json b/src/web-ui/src/locales/zh-TW/common.json index 28b5e892e0..35ea66de0f 100644 --- a/src/web-ui/src/locales/zh-TW/common.json +++ b/src/web-ui/src/locales/zh-TW/common.json @@ -638,7 +638,10 @@ "errorEnterName": "請輸入工作區名稱", "errorCreateFailed": "建立工作區失敗", "errorInvalidName": "工作區名稱不能包含以下字符:/ \\ : * ? \" < > |", - "errorAlreadyExists": "所選位置已存在同名工作區" + "errorAlreadyExists": "所選位置已存在同名工作區", + "errorParentNoAccess": "沒有所選父目錄的存取權限", + "errorNameTooLong": "工作區名稱過長(最多 255 個字元)", + "errorPathNotFound": "工作區資料夾不存在或已被移動" }, "peerDirectoryPicker": { "loading": "正在載入遠端目錄…", diff --git a/src/web-ui/src/locales/zh-TW/flow-chat.json b/src/web-ui/src/locales/zh-TW/flow-chat.json index 215dd931e1..7cdfeebc42 100644 --- a/src/web-ui/src/locales/zh-TW/flow-chat.json +++ b/src/web-ui/src/locales/zh-TW/flow-chat.json @@ -2356,7 +2356,9 @@ } }, "errors": { - "sendFailed": "傳送訊息失敗" + "sendFailed": "傳送訊息失敗", + "thinkingProcessError": "思考過程錯誤", + "workspaceNotResolvable": "工作區資料夾不存在或已被移動" }, "actions": { "send": "傳送"