feat(i18n): translate Claude session components to Chinese

Translate English interface text to Chinese in Claude Code session components:

- ClaudeCodeSession.tsx: Session management UI, settings, timeline, and execution states
- SessionOutputViewer.tsx: Output viewer, status messages, and copy operations

Key translations:
- Session management terms (会话, 恢复会话, 分叉会话)
- Status indicators (运行中, 实时, 完成, 取消)
- UI actions (复制输出, 刷新, 设置, 时间线)
- Error and loading messages
- Project directory selection interface

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-07-03 12:42:06 +08:00
parent f1377833b3
commit ee565ac80f
2 changed files with 60 additions and 60 deletions

View File

@@ -275,7 +275,7 @@ export const ClaudeCodeSession: React.FC<ClaudeCodeSessionProps> = ({
setIsFirstPrompt(false);
} catch (err) {
console.error("Failed to load session history:", err);
setError("Failed to load session history");
setError("加载会话历史失败");
} finally {
setIsLoading(false);
}
@@ -377,7 +377,7 @@ export const ClaudeCodeSession: React.FC<ClaudeCodeSessionProps> = ({
const selected = await open({
directory: true,
multiple: false,
title: "Select Project Directory"
title: "选择项目目录"
});
if (selected) {
@@ -387,7 +387,7 @@ export const ClaudeCodeSession: React.FC<ClaudeCodeSessionProps> = ({
} catch (err) {
console.error("Failed to select directory:", err);
const errorMessage = err instanceof Error ? err.message : String(err);
setError(`Failed to select directory: ${errorMessage}`);
setError(`选择目录失败: ${errorMessage}`);
}
};
@@ -395,7 +395,7 @@ export const ClaudeCodeSession: React.FC<ClaudeCodeSessionProps> = ({
console.log('[ClaudeCodeSession] handleSendPrompt called with:', { prompt, model, projectPath, claudeSessionId, effectiveSession });
if (!projectPath) {
setError("Please select a project directory first");
setError("请先选择项目目录");
return;
}
@@ -597,7 +597,7 @@ export const ClaudeCodeSession: React.FC<ClaudeCodeSessionProps> = ({
}
} catch (err) {
console.error("Failed to send prompt:", err);
setError("Failed to send prompt");
setError("发送提示失败");
setIsLoading(false);
hasActiveSessionRef.current = false;
}
@@ -711,7 +711,7 @@ export const ClaudeCodeSession: React.FC<ClaudeCodeSessionProps> = ({
const cancelMessage: ClaudeStreamMessage = {
type: "system",
subtype: "info",
result: "Session cancelled by user",
result: "会话已被用户取消",
timestamp: new Date().toISOString()
};
setMessages(prev => [...prev, cancelMessage]);
@@ -723,7 +723,7 @@ export const ClaudeCodeSession: React.FC<ClaudeCodeSessionProps> = ({
const errorMessage: ClaudeStreamMessage = {
type: "system",
subtype: "error",
result: `Failed to cancel execution: ${err instanceof Error ? err.message : 'Unknown error'}. The process may still be running in the background.`,
result: `取消执行失败: ${err instanceof Error ? err.message : '未知错误'}. 该进程可能仍在后台运行。`,
timestamp: new Date().toISOString()
};
setMessages(prev => [...prev, errorMessage]);
@@ -772,7 +772,7 @@ export const ClaudeCodeSession: React.FC<ClaudeCodeSessionProps> = ({
setForkSessionName("");
} catch (err) {
console.error("Failed to fork checkpoint:", err);
setError("Failed to fork checkpoint");
setError("分叉检查点失败");
} finally {
setIsLoading(false);
}
@@ -904,7 +904,7 @@ export const ClaudeCodeSession: React.FC<ClaudeCodeSessionProps> = ({
className="p-4 border-b border-border flex-shrink-0"
>
<Label htmlFor="project-path" className="text-sm font-medium">
Project Directory
</Label>
<div className="flex items-center gap-2 mt-1">
<Input
@@ -973,9 +973,9 @@ export const ClaudeCodeSession: React.FC<ClaudeCodeSessionProps> = ({
<div className="flex items-center gap-2">
<Terminal className="h-5 w-5" />
<div>
<h2 className="text-lg font-semibold">Claude Code Session</h2>
<h2 className="text-lg font-semibold">Claude Code </h2>
<p className="text-xs text-muted-foreground">
{session ? `Resuming session ${session.id.slice(0, 8)}...` : 'Interactive session'}
{session ? `恢复会话 ${session.id.slice(0, 8)}...` : '交互式会话'}
</p>
</div>
</div>
@@ -991,7 +991,7 @@ export const ClaudeCodeSession: React.FC<ClaudeCodeSessionProps> = ({
className="flex items-center gap-2"
>
<Settings className="h-4 w-4" />
Settings
</Button>
<Button
variant="outline"
@@ -1000,7 +1000,7 @@ export const ClaudeCodeSession: React.FC<ClaudeCodeSessionProps> = ({
className="flex items-center gap-2"
>
<GitBranch className="h-4 w-4" />
Timeline
线
</Button>
</>
)}
@@ -1023,13 +1023,13 @@ export const ClaudeCodeSession: React.FC<ClaudeCodeSessionProps> = ({
className="flex items-center gap-2"
>
<Globe className="h-4 w-4" />
{showPreview ? "Close Preview" : "Preview"}
{showPreview ? "关闭预览" : "预览"}
</Button>
</TooltipTrigger>
<TooltipContent>
{showPreview
? "Close the preview pane"
: "Open a browser preview to test your web applications"
? "关闭预览面板"
: "打开浏览器预览以测试您的Web应用程序"
}
</TooltipContent>
</Tooltip>
@@ -1044,7 +1044,7 @@ export const ClaudeCodeSession: React.FC<ClaudeCodeSessionProps> = ({
className="flex items-center gap-2"
>
<Copy className="h-4 w-4" />
Copy Output
<ChevronDown className="h-3 w-3" />
</Button>
}
@@ -1056,7 +1056,7 @@ export const ClaudeCodeSession: React.FC<ClaudeCodeSessionProps> = ({
onClick={handleCopyAsMarkdown}
className="w-full justify-start"
>
Copy as Markdown
Markdown
</Button>
<Button
variant="ghost"
@@ -1064,7 +1064,7 @@ export const ClaudeCodeSession: React.FC<ClaudeCodeSessionProps> = ({
onClick={handleCopyAsJsonl}
className="w-full justify-start"
>
Copy as JSONL
JSONL
</Button>
</div>
}
@@ -1115,7 +1115,7 @@ export const ClaudeCodeSession: React.FC<ClaudeCodeSessionProps> = ({
<div className="flex items-center gap-3">
<div className="rotating-symbol text-primary text-2xl" />
<span className="text-sm text-muted-foreground">
{session ? "Loading session history..." : "Initializing Claude Code..."}
{session ? "正在加载会话历史..." : "正在初始化Claude Code..."}
</span>
</div>
</div>
@@ -1138,7 +1138,7 @@ export const ClaudeCodeSession: React.FC<ClaudeCodeSessionProps> = ({
<div className="bg-background/95 backdrop-blur-md border rounded-lg shadow-lg p-3 space-y-2">
<div className="flex items-center justify-between">
<div className="text-xs font-medium text-muted-foreground mb-1">
Queued Prompts ({queuedPrompts.length})
({queuedPrompts.length})
</div>
<Button variant="ghost" size="icon" onClick={() => setQueuedPromptsCollapsed(prev => !prev)}>
{queuedPromptsCollapsed ? <ChevronUp className="h-3 w-3" /> : <ChevronDown className="h-3 w-3" />}
@@ -1214,7 +1214,7 @@ export const ClaudeCodeSession: React.FC<ClaudeCodeSessionProps> = ({
}
}}
className="px-3 py-2 hover:bg-accent rounded-none"
title="Scroll to top"
title="滚动到顶部"
>
<ChevronUp className="h-4 w-4" />
</Button>
@@ -1236,7 +1236,7 @@ export const ClaudeCodeSession: React.FC<ClaudeCodeSessionProps> = ({
}
}}
className="px-3 py-2 hover:bg-accent rounded-none"
title="Scroll to bottom"
title="滚动到底部"
>
<ChevronDown className="h-4 w-4" />
</Button>
@@ -1272,7 +1272,7 @@ export const ClaudeCodeSession: React.FC<ClaudeCodeSessionProps> = ({
<div className="flex items-center gap-1.5 text-xs">
<Hash className="h-3 w-3 text-muted-foreground" />
<span className="font-mono">{totalTokens.toLocaleString()}</span>
<span className="text-muted-foreground">tokens</span>
<span className="text-muted-foreground"></span>
</div>
</motion.div>
</div>
@@ -1294,7 +1294,7 @@ export const ClaudeCodeSession: React.FC<ClaudeCodeSessionProps> = ({
<div className="h-full flex flex-col">
{/* Timeline Header */}
<div className="flex items-center justify-between p-4 border-b border-border">
<h3 className="text-lg font-semibold">Session Timeline</h3>
<h3 className="text-lg font-semibold">线</h3>
<Button
variant="ghost"
size="icon"
@@ -1327,18 +1327,18 @@ export const ClaudeCodeSession: React.FC<ClaudeCodeSessionProps> = ({
<Dialog open={showForkDialog} onOpenChange={setShowForkDialog}>
<DialogContent>
<DialogHeader>
<DialogTitle>Fork Session</DialogTitle>
<DialogTitle></DialogTitle>
<DialogDescription>
Create a new session branch from the selected checkpoint.
</DialogDescription>
</DialogHeader>
<div className="space-y-4 py-4">
<div className="space-y-2">
<Label htmlFor="fork-name">New Session Name</Label>
<Label htmlFor="fork-name"></Label>
<Input
id="fork-name"
placeholder="e.g., Alternative approach"
placeholder="例如:备用方案"
value={forkSessionName}
onChange={(e) => setForkSessionName(e.target.value)}
onKeyPress={(e) => {
@@ -1356,13 +1356,13 @@ export const ClaudeCodeSession: React.FC<ClaudeCodeSessionProps> = ({
onClick={() => setShowForkDialog(false)}
disabled={isLoading}
>
Cancel
</Button>
<Button
onClick={handleConfirmFork}
disabled={isLoading || !forkSessionName.trim()}
>
Create Fork
</Button>
</DialogFooter>
</DialogContent>

View File

@@ -146,7 +146,7 @@ export function SessionOutputViewer({ session, onClose, className }: SessionOutp
}
} catch (error) {
console.error('Failed to load session output:', error);
setToast({ message: 'Failed to load session output', type: 'error' });
setToast({ message: '加载会话输出失败', type: 'error' });
} finally {
setLoading(false);
}
@@ -180,12 +180,12 @@ export function SessionOutputViewer({ session, onClose, className }: SessionOutp
});
const completeUnlisten = await listen<boolean>(`agent-complete:${session.id}`, () => {
setToast({ message: 'Agent execution completed', type: 'success' });
setToast({ message: '智能体执行完成', type: 'success' });
// Don't set status here as the parent component should handle it
});
const cancelUnlisten = await listen<boolean>(`agent-cancelled:${session.id}`, () => {
setToast({ message: 'Agent execution was cancelled', type: 'error' });
setToast({ message: '智能体执行已取消', type: 'error' });
});
unlistenRefs.current = [outputUnlisten, errorUnlisten, completeUnlisten, cancelUnlisten];
@@ -199,7 +199,7 @@ export function SessionOutputViewer({ session, onClose, className }: SessionOutp
const jsonl = rawJsonlOutput.join('\n');
await navigator.clipboard.writeText(jsonl);
setCopyPopoverOpen(false);
setToast({ message: 'Output copied as JSONL', type: 'success' });
setToast({ message: '输出已复制为JSONL', type: 'success' });
};
const handleCopyAsMarkdown = async () => {
@@ -254,7 +254,7 @@ export function SessionOutputViewer({ session, onClose, className }: SessionOutp
await navigator.clipboard.writeText(markdown);
setCopyPopoverOpen(false);
setToast({ message: 'Output copied as Markdown', type: 'success' });
setToast({ message: '输出已复制为Markdown', type: 'success' });
};
@@ -262,10 +262,10 @@ export function SessionOutputViewer({ session, onClose, className }: SessionOutp
setRefreshing(true);
try {
await loadOutput(true); // Skip cache when manually refreshing
setToast({ message: 'Output refreshed', type: 'success' });
setToast({ message: '输出已刷新', type: 'success' });
} catch (error) {
console.error('Failed to refresh output:', error);
setToast({ message: 'Failed to refresh output', type: 'error' });
setToast({ message: '刷新输出失败', type: 'error' });
} finally {
setRefreshing(false);
}
@@ -345,7 +345,7 @@ export function SessionOutputViewer({ session, onClose, className }: SessionOutp
<div className="flex items-center space-x-3">
<div className="text-2xl">{session.agent_icon}</div>
<div>
<CardTitle className="text-base">{session.agent_name} - Output</CardTitle>
<CardTitle className="text-base">{session.agent_name} - </CardTitle>
<div className="flex items-center space-x-2 mt-1">
<Badge variant={session.status === 'running' ? 'default' : 'secondary'}>
{session.status}
@@ -353,11 +353,11 @@ export function SessionOutputViewer({ session, onClose, className }: SessionOutp
{session.status === 'running' && (
<Badge variant="outline" className="text-xs bg-green-50 text-green-700 border-green-200">
<div className="w-1.5 h-1.5 bg-green-500 rounded-full animate-pulse mr-1"></div>
Live
</Badge>
)}
<span className="text-xs text-muted-foreground">
{messages.length} messages
{messages.length}
</span>
</div>
</div>
@@ -369,7 +369,7 @@ export function SessionOutputViewer({ session, onClose, className }: SessionOutp
variant="outline"
size="sm"
onClick={() => setIsFullscreen(!isFullscreen)}
title="Fullscreen"
title="全屏"
>
{isFullscreen ? <Minimize2 className="h-4 w-4" /> : <Maximize2 className="h-4 w-4" />}
</Button>
@@ -381,7 +381,7 @@ export function SessionOutputViewer({ session, onClose, className }: SessionOutp
className="flex items-center gap-2"
>
<Copy className="h-4 w-4" />
Copy Output
<ChevronDown className="h-3 w-3" />
</Button>
}
@@ -393,7 +393,7 @@ export function SessionOutputViewer({ session, onClose, className }: SessionOutp
className="w-full justify-start"
onClick={handleCopyAsJsonl}
>
Copy as JSONL
JSONL
</Button>
<Button
variant="ghost"
@@ -401,7 +401,7 @@ export function SessionOutputViewer({ session, onClose, className }: SessionOutp
className="w-full justify-start"
onClick={handleCopyAsMarkdown}
>
Copy as Markdown
Markdown
</Button>
</div>
}
@@ -416,7 +416,7 @@ export function SessionOutputViewer({ session, onClose, className }: SessionOutp
size="sm"
onClick={refreshOutput}
disabled={refreshing}
title="Refresh output"
title="刷新输出"
>
<RotateCcw className={`h-4 w-4 ${refreshing ? 'animate-spin' : ''}`} />
</Button>
@@ -431,7 +431,7 @@ export function SessionOutputViewer({ session, onClose, className }: SessionOutp
<div className="flex items-center justify-center h-full">
<div className="flex items-center space-x-2">
<RefreshCw className="h-4 w-4 animate-spin" />
<span>Loading output...</span>
<span>...</span>
</div>
</div>
) : (
@@ -455,14 +455,14 @@ export function SessionOutputViewer({ session, onClose, className }: SessionOutp
{session.status === 'running' ? (
<>
<RefreshCw className="h-8 w-8 animate-spin text-muted-foreground mb-2" />
<p className="text-muted-foreground">Waiting for output...</p>
<p className="text-muted-foreground">...</p>
<p className="text-xs text-muted-foreground mt-1">
Agent is running but no output received yet
</p>
</>
) : (
<>
<p className="text-muted-foreground">No output available</p>
<p className="text-muted-foreground"></p>
<Button
variant="outline"
size="sm"
@@ -471,7 +471,7 @@ export function SessionOutputViewer({ session, onClose, className }: SessionOutp
disabled={refreshing}
>
{refreshing ? <RefreshCw className="h-4 w-4 animate-spin mr-2" /> : <RotateCcw className="h-4 w-4 mr-2" />}
Refresh
</Button>
</>
)}
@@ -508,11 +508,11 @@ export function SessionOutputViewer({ session, onClose, className }: SessionOutp
<div className="flex items-center justify-between p-4 border-b border-border">
<div className="flex items-center gap-2">
<div className="text-2xl">{session.agent_icon}</div>
<h2 className="text-lg font-semibold">{session.agent_name} - Output</h2>
<h2 className="text-lg font-semibold">{session.agent_name} - </h2>
{session.status === 'running' && (
<div className="flex items-center gap-1">
<div className="w-2 h-2 bg-green-500 rounded-full animate-pulse"></div>
<span className="text-xs text-green-600 font-medium">Running</span>
<span className="text-xs text-green-600 font-medium"></span>
</div>
)}
</div>
@@ -526,7 +526,7 @@ export function SessionOutputViewer({ session, onClose, className }: SessionOutp
className="flex items-center gap-2"
>
<Copy className="h-4 w-4" />
Copy Output
<ChevronDown className="h-3 w-3" />
</Button>
}
@@ -538,7 +538,7 @@ export function SessionOutputViewer({ session, onClose, className }: SessionOutp
className="w-full justify-start"
onClick={handleCopyAsJsonl}
>
Copy as JSONL
JSONL
</Button>
<Button
variant="ghost"
@@ -546,7 +546,7 @@ export function SessionOutputViewer({ session, onClose, className }: SessionOutp
className="w-full justify-start"
onClick={handleCopyAsMarkdown}
>
Copy as Markdown
Markdown
</Button>
</div>
}
@@ -562,7 +562,7 @@ export function SessionOutputViewer({ session, onClose, className }: SessionOutp
className="flex items-center gap-2"
>
<X className="h-4 w-4" />
Close
</Button>
</div>
</div>
@@ -589,14 +589,14 @@ export function SessionOutputViewer({ session, onClose, className }: SessionOutp
{session.status === 'running' ? (
<>
<RefreshCw className="h-8 w-8 animate-spin text-muted-foreground mb-2" />
<p className="text-muted-foreground">Waiting for output...</p>
<p className="text-muted-foreground">...</p>
<p className="text-xs text-muted-foreground mt-1">
Agent is running but no output received yet
</p>
</>
) : (
<>
<p className="text-muted-foreground">No output available</p>
<p className="text-muted-foreground"></p>
</>
)}
</div>