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

View File

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

View File

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

View File

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

View File

@@ -432,7 +432,7 @@ export const Settings: React.FC<SettingsProps> = ({
{/* Claude Binary Path Selector */}
<div className="space-y-4">
<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">
{t('settings.claudeInstallationDesc')}
</p>

View File

@@ -210,7 +210,12 @@
"chatRetention": "Chat Transcript Retention (days)",
"chatRetentionDesc": "How long to retain chat transcripts locally (default: 30 days)",
"claudeInstallation": "Claude Code Installation",
"selectClaudeInstallation": "Select Claude Code Installation",
"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",
"permissionRulesDesc": "Control which tools Claude Code can use without manual approval",
"allowRules": "Allow Rules",
@@ -379,6 +384,13 @@
"auto": "Auto",
"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": {
"loadProjectsFailed": "Failed to load projects. Please ensure ~/.claude directory exists.",
"loadSessionsFailed": "Failed to load sessions for this project."

View File

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