修复缺失的汉化
Some checks are pending
Build Test / Build Test (${{ matrix.platform.name }}) (map[name:Linux os:ubuntu-latest rust-target:x86_64-unknown-linux-gnu]) (push) Waiting to run
Build Test / Build Test (${{ matrix.platform.name }}) (map[name:Windows os:windows-latest rust-target:x86_64-pc-windows-msvc]) (push) Waiting to run
Build Test / Build Test (${{ matrix.platform.name }}) (map[name:macOS os:macos-latest rust-target:x86_64-apple-darwin]) (push) Waiting to run
Build Test / Build Test Summary (push) Blocked by required conditions

This commit is contained in:
2025-07-04 12:23:19 +08:00
parent 98cbca759f
commit 8958a91dec
7 changed files with 110 additions and 89 deletions

View File

@@ -7,6 +7,7 @@ import { Badge } from "@/components/ui/badge";
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"; import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
import { Loader2, Terminal, Package, Check } from "lucide-react"; import { Loader2, Terminal, Package, Check } from "lucide-react";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
import { useTranslation } from "react-i18next";
interface ClaudeVersionSelectorProps { interface ClaudeVersionSelectorProps {
/** /**
@@ -52,6 +53,7 @@ export const ClaudeVersionSelector: React.FC<ClaudeVersionSelectorProps> = ({
onSave, onSave,
isSaving = false, isSaving = false,
}) => { }) => {
const { t } = useTranslation();
const [installations, setInstallations] = useState<ClaudeInstallation[]>([]); const [installations, setInstallations] = useState<ClaudeInstallation[]>([]);
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null); const [error, setError] = useState<string | null>(null);
@@ -91,7 +93,7 @@ export const ClaudeVersionSelector: React.FC<ClaudeVersionSelectorProps> = ({
} }
} catch (err) { } catch (err) {
console.error("Failed to load Claude installations:", err); console.error("Failed to load Claude installations:", err);
setError(err instanceof Error ? err.message : "Failed to load Claude installations"); setError(err instanceof Error ? err.message : t('settings.claudeInstallationLoadFailed'));
} finally { } finally {
setLoading(false); setLoading(false);
} }
@@ -140,7 +142,7 @@ export const ClaudeVersionSelector: React.FC<ClaudeVersionSelectorProps> = ({
return ( return (
<Card className={cn("p-4", className)}> <Card className={cn("p-4", className)}>
<div className="text-sm text-muted-foreground"> <div className="text-sm text-muted-foreground">
No Claude Code installations found on your system. {t('settings.noClaudeInstallations')}
</div> </div>
</Card> </Card>
); );
@@ -148,65 +150,60 @@ export const ClaudeVersionSelector: React.FC<ClaudeVersionSelectorProps> = ({
return ( return (
<div className={cn("space-y-4", className)}> <div className={cn("space-y-4", className)}>
<div> <RadioGroup
<Label className="text-sm font-medium mb-3 block"> value={selectedInstallation?.path}
Select Claude Code Installation onValueChange={(value: string) => {
</Label> const installation = installations.find(i => i.path === value);
<RadioGroup if (installation) {
value={selectedInstallation?.path} handleSelect(installation);
onValueChange={(value: string) => { }
const installation = installations.find(i => i.path === value); }}
if (installation) { >
handleSelect(installation); <div className="space-y-2">
} {installations.map((installation) => (
}} <Card
> key={installation.path}
<div className="space-y-2"> className={cn(
{installations.map((installation) => ( "relative cursor-pointer transition-colors",
<Card selectedInstallation?.path === installation.path
key={installation.path} ? "border-primary"
className={cn( : "hover:border-muted-foreground/50"
"relative cursor-pointer transition-colors", )}
selectedInstallation?.path === installation.path onClick={() => handleSelect(installation)}
? "border-primary" >
: "hover:border-muted-foreground/50" <div className="flex items-start p-4">
)} <RadioGroupItem
onClick={() => handleSelect(installation)} value={installation.path}
> id={installation.path}
<div className="flex items-start p-4"> className="mt-1"
<RadioGroupItem />
value={installation.path} <div className="ml-3 flex-1">
id={installation.path} <div className="flex items-center gap-2 mb-1">
className="mt-1" {getSourceIcon(installation.source)}
/> <span className="font-medium text-sm">
<div className="ml-3 flex-1"> {getSourceLabel(installation.source)}
<div className="flex items-center gap-2 mb-1"> </span>
{getSourceIcon(installation.source)} {installation.version && (
<span className="font-medium text-sm"> <Badge variant="secondary" className="text-xs">
{getSourceLabel(installation.source)} v{installation.version}
</span> </Badge>
{installation.version && ( )}
<Badge variant="secondary" className="text-xs"> {selectedPath === installation.path && (
v{installation.version} <Badge variant="default" className="text-xs">
</Badge> <Check className="w-3 h-3 mr-1" />
)} {t('settings.current')}
{selectedPath === installation.path && ( </Badge>
<Badge variant="default" className="text-xs"> )}
<Check className="w-3 h-3 mr-1" />
Current
</Badge>
)}
</div>
<p className="text-xs text-muted-foreground font-mono break-all">
{installation.path}
</p>
</div> </div>
<p className="text-xs text-muted-foreground font-mono break-all">
{installation.path}
</p>
</div> </div>
</Card> </div>
))} </Card>
</div> ))}
</RadioGroup> </div>
</div> </RadioGroup>
{showSaveButton && onSave && ( {showSaveButton && onSave && (
<div className="flex justify-end"> <div className="flex justify-end">
@@ -218,14 +215,14 @@ export const ClaudeVersionSelector: React.FC<ClaudeVersionSelectorProps> = ({
{isSaving ? ( {isSaving ? (
<> <>
<Loader2 className="w-4 h-4 mr-2 animate-spin" /> <Loader2 className="w-4 h-4 mr-2 animate-spin" />
Saving... {t('common.saving')}
</> </>
) : ( ) : (
"Save Selection" t('settings.saveSelection')
)} )}
</Button> </Button>
</div> </div>
)} )}
</div> </div>
); );
}; };

View File

@@ -266,14 +266,14 @@ export const MCPAddServer: React.FC<MCPAddServerProps> = ({
</div> </div>
<Tabs value={transport} onValueChange={(v) => setTransport(v as "stdio" | "sse")}> <Tabs value={transport} onValueChange={(v) => setTransport(v as "stdio" | "sse")}>
<TabsList className="grid w-full grid-cols-2 max-w-sm mb-6"> <TabsList className="grid w-full grid-cols-2 max-w-xs mb-6">
<TabsTrigger value="stdio" className="gap-2"> <TabsTrigger value="stdio" className="gap-2 min-w-0 flex-1">
<Terminal className="h-4 w-4 text-amber-500" /> <Terminal className="h-4 w-4 text-amber-500 flex-shrink-0" />
Stdio <span className="truncate">Stdio</span>
</TabsTrigger> </TabsTrigger>
<TabsTrigger value="sse" className="gap-2"> <TabsTrigger value="sse" className="gap-2 min-w-0 flex-1">
<Globe className="h-4 w-4 text-emerald-500" /> <Globe className="h-4 w-4 text-emerald-500 flex-shrink-0" />
SSE <span className="truncate">SSE</span>
</TabsTrigger> </TabsTrigger>
</TabsList> </TabsList>

View File

@@ -151,18 +151,18 @@ export const MCPManager: React.FC<MCPManagerProps> = ({
) : ( ) : (
<div className="flex-1 overflow-y-auto p-4"> <div className="flex-1 overflow-y-auto p-4">
<Tabs value={activeTab} onValueChange={setActiveTab} className="space-y-6"> <Tabs value={activeTab} onValueChange={setActiveTab} className="space-y-6">
<TabsList className="grid w-full max-w-md grid-cols-3"> <TabsList className="grid w-full max-w-lg grid-cols-3">
<TabsTrigger value="servers" className="gap-2"> <TabsTrigger value="servers" className="gap-2 min-w-0 flex-1">
<Network className="h-4 w-4 text-blue-500" /> <Network className="h-4 w-4 text-blue-500 flex-shrink-0" />
{t('mcp.servers')} <span className="truncate">{t('mcp.servers')}</span>
</TabsTrigger> </TabsTrigger>
<TabsTrigger value="add" className="gap-2"> <TabsTrigger value="add" className="gap-2 min-w-0 flex-1">
<Plus className="h-4 w-4 text-green-500" /> <Plus className="h-4 w-4 text-green-500 flex-shrink-0" />
{t('mcp.addServer')} <span className="truncate">{t('mcp.addServer')}</span>
</TabsTrigger> </TabsTrigger>
<TabsTrigger value="import" className="gap-2"> <TabsTrigger value="import" className="gap-2 min-w-0 flex-1">
<Download className="h-4 w-4 text-purple-500" /> <Download className="h-4 w-4 text-purple-500 flex-shrink-0" />
{t('mcp.importExport')} <span className="truncate">{t('mcp.importExport')}</span>
</TabsTrigger> </TabsTrigger>
</TabsList> </TabsList>

View File

@@ -6,6 +6,7 @@ import { Button } from "@/components/ui/button";
import { Toast, ToastContainer } from "@/components/ui/toast"; import { Toast, ToastContainer } from "@/components/ui/toast";
import { api } from "@/lib/api"; import { api } from "@/lib/api";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
import { useTranslation } from "react-i18next";
interface MarkdownEditorProps { interface MarkdownEditorProps {
/** /**
@@ -28,6 +29,7 @@ export const MarkdownEditor: React.FC<MarkdownEditorProps> = ({
onBack, onBack,
className, className,
}) => { }) => {
const { t } = useTranslation();
const [content, setContent] = useState<string>(""); const [content, setContent] = useState<string>("");
const [originalContent, setOriginalContent] = useState<string>(""); const [originalContent, setOriginalContent] = useState<string>("");
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
@@ -51,7 +53,7 @@ export const MarkdownEditor: React.FC<MarkdownEditorProps> = ({
setOriginalContent(prompt); setOriginalContent(prompt);
} catch (err) { } catch (err) {
console.error("Failed to load system prompt:", err); console.error("Failed to load system prompt:", err);
setError("Failed to load CLAUDE.md file"); setError(t('markdownEditor.loadFailed'));
} finally { } finally {
setLoading(false); setLoading(false);
} }
@@ -64,11 +66,11 @@ export const MarkdownEditor: React.FC<MarkdownEditorProps> = ({
setToast(null); setToast(null);
await api.saveSystemPrompt(content); await api.saveSystemPrompt(content);
setOriginalContent(content); setOriginalContent(content);
setToast({ message: "CLAUDE.md saved successfully", type: "success" }); setToast({ message: t('markdownEditor.saveSuccess'), type: "success" });
} catch (err) { } catch (err) {
console.error("Failed to save system prompt:", err); console.error("Failed to save system prompt:", err);
setError("Failed to save CLAUDE.md file"); setError(t('markdownEditor.saveFailed'));
setToast({ message: "Failed to save CLAUDE.md", type: "error" }); setToast({ message: t('markdownEditor.saveFailed'), type: "error" });
} finally { } finally {
setSaving(false); setSaving(false);
} }
@@ -77,7 +79,7 @@ export const MarkdownEditor: React.FC<MarkdownEditorProps> = ({
const handleBack = () => { const handleBack = () => {
if (hasChanges) { if (hasChanges) {
const confirmLeave = window.confirm( const confirmLeave = window.confirm(
"You have unsaved changes. Are you sure you want to leave?" t('markdownEditor.unsavedChanges')
); );
if (!confirmLeave) return; if (!confirmLeave) return;
} }
@@ -106,7 +108,7 @@ export const MarkdownEditor: React.FC<MarkdownEditorProps> = ({
<div> <div>
<h2 className="text-lg font-semibold">CLAUDE.md</h2> <h2 className="text-lg font-semibold">CLAUDE.md</h2>
<p className="text-xs text-muted-foreground"> <p className="text-xs text-muted-foreground">
Edit your Claude Code system prompt {t('markdownEditor.description')}
</p> </p>
</div> </div>
</div> </div>
@@ -121,7 +123,7 @@ export const MarkdownEditor: React.FC<MarkdownEditorProps> = ({
) : ( ) : (
<Save className="mr-2 h-4 w-4" /> <Save className="mr-2 h-4 w-4" />
)} )}
{saving ? "Saving..." : "Save"} {saving ? t('common.saving') : t('common.save')}
</Button> </Button>
</motion.div> </motion.div>

View File

@@ -432,7 +432,7 @@ export const Settings: React.FC<SettingsProps> = ({
{/* Claude Binary Path Selector */} {/* Claude Binary Path Selector */}
<div className="space-y-4"> <div className="space-y-4">
<div> <div>
<Label className="text-sm font-medium mb-2 block">{t('settings.claudeInstallation')}</Label> <Label className="text-sm font-medium mb-2 block">{t('settings.selectClaudeInstallation')}</Label>
<p className="text-xs text-muted-foreground mb-4"> <p className="text-xs text-muted-foreground mb-4">
{t('settings.claudeInstallationDesc')} {t('settings.claudeInstallationDesc')}
</p> </p>

View File

@@ -210,7 +210,12 @@
"chatRetention": "Chat Transcript Retention (days)", "chatRetention": "Chat Transcript Retention (days)",
"chatRetentionDesc": "How long to retain chat transcripts locally (default: 30 days)", "chatRetentionDesc": "How long to retain chat transcripts locally (default: 30 days)",
"claudeInstallation": "Claude Code Installation", "claudeInstallation": "Claude Code Installation",
"selectClaudeInstallation": "Select Claude Code Installation",
"claudeInstallationDesc": "Select which Claude Code installation to use", "claudeInstallationDesc": "Select which Claude Code installation to use",
"current": "Current",
"noClaudeInstallations": "No Claude Code installations found on your system",
"claudeInstallationLoadFailed": "Failed to load Claude installations",
"saveSelection": "Save Selection",
"permissionRules": "Permission Rules", "permissionRules": "Permission Rules",
"permissionRulesDesc": "Control which tools Claude Code can use without manual approval", "permissionRulesDesc": "Control which tools Claude Code can use without manual approval",
"allowRules": "Allow Rules", "allowRules": "Allow Rules",
@@ -379,6 +384,13 @@
"auto": "Auto", "auto": "Auto",
"fullscreen": "Fullscreen" "fullscreen": "Fullscreen"
}, },
"markdownEditor": {
"description": "Edit your Claude Code system prompt",
"loadFailed": "Failed to load CLAUDE.md file",
"saveSuccess": "CLAUDE.md saved successfully",
"saveFailed": "Failed to save CLAUDE.md",
"unsavedChanges": "You have unsaved changes. Are you sure you want to leave?"
},
"errors": { "errors": {
"loadProjectsFailed": "Failed to load projects. Please ensure ~/.claude directory exists.", "loadProjectsFailed": "Failed to load projects. Please ensure ~/.claude directory exists.",
"loadSessionsFailed": "Failed to load sessions for this project." "loadSessionsFailed": "Failed to load sessions for this project."

View File

@@ -162,7 +162,6 @@
"outputCopiedAsJsonl": "输出已复制为 JSONL", "outputCopiedAsJsonl": "输出已复制为 JSONL",
"outputRefreshed": "输出已刷新", "outputRefreshed": "输出已刷新",
"agentExecutionCompleted": "智能体执行完成", "agentExecutionCompleted": "智能体执行完成",
"queuedPrompts": "排队提示({{count}}",
"scrollToTop": "滚动到顶部", "scrollToTop": "滚动到顶部",
"scrollToBottom": "滚动到底部", "scrollToBottom": "滚动到底部",
"tokens": "标记", "tokens": "标记",
@@ -231,7 +230,12 @@
"chatRetention": "聊天记录保留期(天)", "chatRetention": "聊天记录保留期(天)",
"chatRetentionDesc": "本地保留聊天记录的时长默认30天", "chatRetentionDesc": "本地保留聊天记录的时长默认30天",
"claudeInstallation": "Claude Code 安装", "claudeInstallation": "Claude Code 安装",
"selectClaudeInstallation": "选择 Claude Code 安装",
"claudeInstallationDesc": "选择要使用的 Claude Code 安装", "claudeInstallationDesc": "选择要使用的 Claude Code 安装",
"current": "当前",
"noClaudeInstallations": "在您的系统上未找到 Claude Code 安装",
"claudeInstallationLoadFailed": "加载 Claude 安装失败",
"saveSelection": "保存选择",
"permissionRules": "权限规则", "permissionRules": "权限规则",
"permissionRulesDesc": "控制 Claude Code 无需手动批准即可使用的工具", "permissionRulesDesc": "控制 Claude Code 无需手动批准即可使用的工具",
"allowRules": "允许规则", "allowRules": "允许规则",
@@ -268,11 +272,17 @@
"modelNameDesc": "自定义模型名称", "modelNameDesc": "自定义模型名称",
"costWarningsDesc": "禁用成本警告 (1)" "costWarningsDesc": "禁用成本警告 (1)"
}, },
"markdownEditor": {
"description": "编辑您的 Claude Code 系统提示",
"loadFailed": "加载 CLAUDE.md 文件失败",
"saveSuccess": "CLAUDE.md 保存成功",
"saveFailed": "保存 CLAUDE.md 失败",
"unsavedChanges": "您有未保存的更改。确定要离开吗?"
},
"mcp": { "mcp": {
"title": "MCP 服务器", "title": "MCP 服务器",
"description": "管理 Model Context Protocol 服务器", "description": "管理 Model Context Protocol 服务器",
"servers": "服务器", "servers": "服务器",
"addServer": "添加服务器",
"importExport": "导入/导出", "importExport": "导入/导出",
"configuredServers": "已配置的服务器", "configuredServers": "已配置的服务器",
"running": "运行中", "running": "运行中",