修复缺失的汉化
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
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:
@@ -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>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@@ -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>
|
||||||
|
|
||||||
|
@@ -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>
|
||||||
|
|
||||||
|
@@ -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>
|
||||||
|
|
||||||
|
@@ -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>
|
||||||
|
@@ -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."
|
||||||
|
@@ -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": "运行中",
|
||||||
|
Reference in New Issue
Block a user