Skip to content

Commit df30fe3

Browse files
Seaualclaude
andcommitted
fix: complete i18n translation for Chinese-English language switching
Replace all hardcoded Chinese/English strings across 13 frontend files with proper i18n translation keys. Added missing translation entries for navigation, settings, research agent, upload, cards, and graph views. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 0c5778d commit df30fe3

13 files changed

Lines changed: 248 additions & 98 deletions

frontend/src/components/ConceptGraphInChat.tsx

Lines changed: 7 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import ForceGraph from "force-graph";
77
import { forceManyBody, forceCollide, forceLink, forceCenter } from "d3-force";
88
import { graphApi, foldersApi } from "../lib/api";
99
import { Folder, ChevronDown } from "lucide-react";
10+
import { useTranslation } from "../i18n";
1011

1112
// Types
1213
interface Concept {
@@ -102,6 +103,7 @@ export default function ConceptGraphInChat({
102103
data: _data,
103104
onNodeClick,
104105
}: Props) {
106+
const { t } = useTranslation();
105107
const containerRef = useRef<HTMLDivElement>(null);
106108
const graphRef = useRef<any>(null);
107109
const [error, setError] = useState<string | null>(null);
@@ -160,7 +162,7 @@ export default function ConceptGraphInChat({
160162
setError(null);
161163
} catch (err) {
162164
console.error("Failed to load graph:", err);
163-
setError("加载图谱失败");
165+
setError(t.common.loadGraphFailed);
164166
} finally {
165167
setLoading(false);
166168
}
@@ -335,7 +337,7 @@ export default function ConceptGraphInChat({
335337
return (
336338
<div className="my-3 p-6 rounded-xl bg-gradient-warm">
337339
<div className="text-center mb-4">
338-
<p className="text-sepia font-medium">请选择要显示的文件夹图谱</p>
340+
<p className="text-sepia font-medium">{t.common.selectFolder}</p>
339341
</div>
340342
<div className="flex flex-wrap justify-center gap-2">
341343
{folders.map((folder) => (
@@ -383,7 +385,7 @@ export default function ConceptGraphInChat({
383385
style={{ color: "#666" }}
384386
>
385387
<Folder className="w-3.5 h-3.5" />
386-
{folders.find((f) => f.id === activeFolder)?.name || "全部"}
388+
{folders.find((f) => f.id === activeFolder)?.name || t.common.allFolders}
387389
<ChevronDown className="w-3.5 h-3.5" />
388390
</button>
389391

@@ -417,7 +419,7 @@ export default function ConceptGraphInChat({
417419

418420
{folders.length <= 1 && (
419421
<span className="text-xs" style={{ color: "#666" }}>
420-
{folders.find((f) => f.id === activeFolder)?.name || "全部概念"}
422+
{folders.find((f) => f.id === activeFolder)?.name || t.common.allConcepts}
421423
</span>
422424
)}
423425
</div>
@@ -451,23 +453,7 @@ export default function ConceptGraphInChat({
451453
style={{ background: color }}
452454
/>
453455
<span style={{ color: "#666" }}>
454-
{cat === "field"
455-
? "领域"
456-
: cat === "direction"
457-
? "方向"
458-
: cat === "subdirection"
459-
? "子方向"
460-
: cat === "task"
461-
? "任务"
462-
: cat === "method"
463-
? "方法"
464-
: cat === "technique"
465-
? "技术"
466-
: cat === "dataset"
467-
? "数据集"
468-
: cat === "finding"
469-
? "发现"
470-
: cat}
456+
{(t.concepts.category as Record<string, string>)[cat] || cat}
471457
</span>
472458
</span>
473459
))}

frontend/src/components/ConversationHistory.tsx

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import { useNavigate } from "react-router-dom";
33
import { useConversationStore } from "../stores/conversationStore";
44
import { MessageSquare, Trash2 } from "lucide-react";
5+
import { useTranslation } from "../i18n";
56

67
interface ConversationHistoryProps {
78
onSelect?: () => void;
@@ -11,6 +12,7 @@ export default function ConversationHistory({
1112
onSelect,
1213
}: ConversationHistoryProps) {
1314
const navigate = useNavigate();
15+
const { t } = useTranslation();
1416
const {
1517
conversations,
1618
currentConversationId,
@@ -27,7 +29,7 @@ export default function ConversationHistory({
2729

2830
const handleDelete = async (id: string, e: React.MouseEvent) => {
2931
e.stopPropagation();
30-
if (confirm("确定删除此对话?")) {
32+
if (confirm(t.common.delete)) {
3133
await deleteConversation(id);
3234
}
3335
};
@@ -39,7 +41,7 @@ export default function ConversationHistory({
3941
className="text-xs text-center"
4042
style={{ color: "var(--color-ink-muted)" }}
4143
>
42-
加载中...
44+
{t.common.loading}
4345
</div>
4446
</div>
4547
);
@@ -52,7 +54,7 @@ export default function ConversationHistory({
5254
className="text-xs text-center"
5355
style={{ color: "var(--color-ink-muted)" }}
5456
>
55-
暂无对话历史
57+
{t.common.noConversationHistory}
5658
</div>
5759
</div>
5860
);
@@ -100,14 +102,14 @@ export default function ConversationHistory({
100102
: "var(--color-ink-secondary)",
101103
}}
102104
>
103-
{conv.title || "新对话"}
105+
{conv.title || t.common.newChat}
104106
</span>
105107
</div>
106108
<button
107109
onClick={(e) => handleDelete(conv.id, e)}
108110
className="p-1 rounded hover:bg-overlay transition-colors"
109111
style={{ color: "var(--color-ink-muted)" }}
110-
title="删除"
112+
title={t.common.delete}
111113
aria-label="删除此对话"
112114
type="button"
113115
>

frontend/src/components/DragUploadZone.tsx

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import { useState, useCallback, useRef } from "react";
33
import { Upload, Loader2 } from "lucide-react";
44
import { papersApi } from "../lib/api";
5+
import { useTranslation } from "../i18n";
56

67
interface UploadedPaper {
78
doi: string;
@@ -17,6 +18,7 @@ export default function DragUploadZone({
1718
onUploadSuccess,
1819
onUploadError,
1920
}: DragUploadZoneProps) {
21+
const { t } = useTranslation();
2022
const [isDragging, setIsDragging] = useState(false);
2123
const [isUploading, setIsUploading] = useState(false);
2224
const [uploadProgress, setUploadProgress] = useState(0);
@@ -57,7 +59,7 @@ export default function DragUploadZone({
5759
);
5860

5961
if (files.length === 0) {
60-
onUploadError("请上传 PDF 文件");
62+
onUploadError(t.common.uploadPdfOnly);
6163
return;
6264
}
6365

@@ -89,7 +91,7 @@ export default function DragUploadZone({
8991
if (uploadedPapers.length > 0) {
9092
onUploadSuccess(uploadedPapers);
9193
} else {
92-
onUploadError("上传失败,请重试");
94+
onUploadError(t.common.uploadFailed);
9395
}
9496
},
9597
[onUploadSuccess, onUploadError]
@@ -128,7 +130,7 @@ export default function DragUploadZone({
128130
className="font-body text-sm"
129131
style={{ color: "var(--color-sepia)" }}
130132
>
131-
上传中... {uploadProgress}%
133+
{t.common.uploading} {uploadProgress}%
132134
</p>
133135
</>
134136
) : (
@@ -141,13 +143,13 @@ export default function DragUploadZone({
141143
className="font-display text-lg mb-2"
142144
style={{ color: "var(--color-sepia)" }}
143145
>
144-
拖放 PDF 文件到此处上传
146+
{t.common.dragDropPdf}
145147
</p>
146148
<p
147149
className="font-body text-sm"
148150
style={{ color: "var(--color-muted)" }}
149151
>
150-
支持单个或多个 PDF 文件
152+
{t.common.multiPdfSupport}
151153
</p>
152154
</>
153155
)}

frontend/src/components/ResearchAgentBubble.tsx

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
import { useAgentStore, Message } from "../stores/agentStore";
1212
import { agentApi } from "../lib/api";
1313
import { DeepResearchProgress } from "./DeepResearchProgress";
14+
import { useTranslation } from "../i18n";
1415

1516
// 静默状态 - 右侧垂直窄条
1617
function CollapsedBar({
@@ -103,9 +104,11 @@ function CollapsedBar({
103104
function DialogHeader({
104105
onMouseDown,
105106
onCollapse,
107+
t,
106108
}: {
107109
onMouseDown: (e: React.MouseEvent) => void;
108110
onCollapse: () => void;
111+
t: ReturnType<typeof useTranslation>["t"];
109112
}) {
110113
return (
111114
<div
@@ -147,7 +150,7 @@ function DialogHeader({
147150
e.currentTarget.style.color = "var(--color-muted)";
148151
}}
149152
>
150-
<span className="text-sm">收起</span>
153+
<span className="text-sm">{t.common.collapse}</span>
151154
<ChevronRight className="w-4 h-4" />
152155
</button>
153156
</div>
@@ -158,9 +161,11 @@ function DialogHeader({
158161
function ContextIndicator({
159162
target,
160163
onClear,
164+
t,
161165
}: {
162166
target?: { type: "concept" | "paper"; id: string; name: string };
163167
onClear: () => void;
168+
t: ReturnType<typeof useTranslation>["t"];
164169
}) {
165170
if (!target) return null;
166171

@@ -189,7 +194,7 @@ function ContextIndicator({
189194
color: "var(--color-muted)",
190195
}}
191196
>
192-
{target.type === "paper" ? "论文" : "概念"}
197+
{target.type === "paper" ? t.nav.papers : t.nav.concepts}
193198
</span>
194199
</div>
195200
<button
@@ -235,9 +240,11 @@ function MessageBubble({ msg, isUser }: { msg: Message; isUser: boolean }) {
235240
function MessageList({
236241
messages,
237242
onResearchComplete,
243+
t,
238244
}: {
239245
messages: Message[];
240246
onResearchComplete: (sessionId: string, report: string) => void;
247+
t: ReturnType<typeof useTranslation>["t"];
241248
}) {
242249
const listRef = useRef<HTMLDivElement>(null);
243250

@@ -259,13 +266,13 @@ function MessageList({
259266
className="text-base font-medium"
260267
style={{ color: "var(--color-sepia)" }}
261268
>
262-
研究助手已就绪
269+
{t.researchAgent.ready}
263270
</p>
264271
<div
265272
className="flex flex-col gap-2 text-sm mt-5"
266273
style={{ color: "var(--color-muted)" }}
267274
>
268-
{["分析论文引用关系", "发现概念研究点", "深入研究主题"].map(
275+
{[t.researchAgent.analyzeCitations, t.researchAgent.discoverConcepts, t.researchAgent.deepDive].map(
269276
(item, i) => (
270277
<div
271278
key={i}
@@ -304,9 +311,11 @@ function MessageList({
304311
function ChatInput({
305312
onSend,
306313
isLoading,
314+
t,
307315
}: {
308316
onSend: (message: string) => void;
309317
isLoading: boolean;
318+
t: ReturnType<typeof useTranslation>["t"];
310319
}) {
311320
const [input, setInput] = useState("");
312321

@@ -332,7 +341,7 @@ function ChatInput({
332341
type="text"
333342
value={input}
334343
onChange={(e) => setInput(e.target.value)}
335-
placeholder="输入研究问题..."
344+
placeholder={t.researchAgent.placeholder}
336345
style={{
337346
flex: 1,
338347
padding: "0.75rem 1rem",
@@ -365,6 +374,7 @@ function ChatInput({
365374
// 主组件
366375
export default function ResearchAgentBubble() {
367376
const location = useLocation();
377+
const { t } = useTranslation();
368378

369379
// 在 Chat 页面和 Concepts 页面不显示这个浮框
370380
if (location.pathname === "/chat" || location.pathname === "/concepts") {
@@ -470,7 +480,7 @@ export default function ResearchAgentBubble() {
470480
} catch {
471481
addMessage({
472482
role: "assistant",
473-
content: "处理请求时遇到问题,请重试。",
483+
content: t.researchAgent.errorMsg,
474484
});
475485
} finally {
476486
setLoading(false);
@@ -536,16 +546,19 @@ export default function ResearchAgentBubble() {
536546
<DialogHeader
537547
onMouseDown={handleMouseDown}
538548
onCollapse={() => setIsExpanded(false)}
549+
t={t}
539550
/>
540551
<ContextIndicator
541552
target={contextSummary.currentTarget}
542553
onClear={handleClearContext}
554+
t={t}
543555
/>
544556
<MessageList
545557
messages={messages}
546558
onResearchComplete={handleResearchComplete}
559+
t={t}
547560
/>
548-
<ChatInput onSend={handleSend} isLoading={isLoading} />
561+
<ChatInput onSend={handleSend} isLoading={isLoading} t={t} />
549562
</div>
550563
);
551564
}

frontend/src/components/Sidebar.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ export default function Sidebar() {
116116
}}
117117
>
118118
<MessageSquare className="w-[18px] h-[18px]" />
119-
<span className="font-body text-sm font-medium">新对话</span>
119+
<span className="font-body text-sm font-medium">{t.common.newChat}</span>
120120
</Link>
121121
)}
122122

@@ -130,7 +130,7 @@ export default function Sidebar() {
130130
: item.labelKey === "papers"
131131
? t.nav.papers
132132
: item.labelKey === "settings"
133-
? "设置"
133+
? t.nav.settings
134134
: item.labelKey;
135135

136136
return (
@@ -168,7 +168,7 @@ export default function Sidebar() {
168168
className="text-xs px-3 py-1"
169169
style={{ color: "var(--color-ink-muted)" }}
170170
>
171-
对话历史
171+
{t.common.conversationHistory}
172172
</div>
173173
<ConversationHistory onSelect={() => {}} />
174174
</div>
@@ -185,12 +185,12 @@ export default function Sidebar() {
185185
onClick={toggleLanguage}
186186
className="w-full flex items-center gap-3 px-3 py-2 rounded-lg transition-colors duration-150"
187187
style={{ color: "var(--color-ink-tertiary)" }}
188-
title={language === "zh" ? "Switch to English" : "切换到中文"}
188+
title={language === "zh" ? t.common.english : t.common.chinese}
189189
>
190190
<Globe className="w-[18px] h-[18px]" />
191191
{!isCollapsed && (
192192
<span className="font-body text-sm">
193-
{language === "zh" ? "English" : "中文"}
193+
{language === "zh" ? t.common.english : t.common.chinese}
194194
</span>
195195
)}
196196
</button>
@@ -206,7 +206,7 @@ export default function Sidebar() {
206206
) : (
207207
<>
208208
<ChevronLeft className="w-[18px] h-[18px]" />
209-
<span className="font-body text-sm">收起</span>
209+
<span className="font-body text-sm">{t.common.collapse}</span>
210210
</>
211211
)}
212212
</button>

0 commit comments

Comments
 (0)