feat(i18n): add internationalization support across multiple components

This commit is contained in:
2025-10-29 16:40:20 +08:00
parent 184c232cc8
commit 9199ed7c29
34 changed files with 1455 additions and 761 deletions

View File

@@ -1,5 +1,6 @@
import React, { useState, useEffect, useRef } from 'react';
import { useParams, useNavigate } from 'react-router-dom';
import { useTranslation } from 'react-i18next';
import {
Box,
Typography,
@@ -38,6 +39,7 @@ import logger from '@/utils/logger';
function KnowledgeBaseDetail() {
const { id } = useParams<{ id: string }>();
const navigate = useNavigate();
const { t } = useTranslation();
// 状态管理
const [error, setError] = useState<string | null>(null);
@@ -114,20 +116,20 @@ function KnowledgeBaseDetail() {
refreshFiles();
fetchKnowledgeDetail();
} catch (err: any) {
setError(err.response?.data?.message || err.message || '删除文件失败');
setError(err.response?.data?.message || err.message || t('knowledgeDetails.deleteFileFailed'));
}
};
// 上传文件处理
const handleUploadFiles = async (uploadFiles: File[]) => {
console.log('上传文件:', uploadFiles);
console.log(t('knowledgeDetails.uploadFiles'), uploadFiles);
const kb_id = knowledgeBase?.id || '';
try {
await uploadDocuments(kb_id, uploadFiles);
refreshFiles();
fetchKnowledgeDetail();
} catch (err: any) {
throw new Error(err.response?.data?.message || err.message || '上传文件失败');
throw new Error(err.response?.data?.message || err.message || t('knowledgeDetails.uploadFileFailed'));
}
};
@@ -138,7 +140,7 @@ function KnowledgeBaseDetail() {
refreshFiles(); // 刷新列表
startPolling(); // 开始轮询
} catch (err: any) {
setError(err.response?.data?.message || err.message || '重新解析失败');
setError(err.response?.data?.message || err.message || t('knowledgeDetails.reparseFailed'));
}
};
@@ -148,7 +150,7 @@ function KnowledgeBaseDetail() {
await renameDocument(fileId, newName);
refreshFiles();
} catch (err: any) {
setError(err.response?.data?.message || err.message || '重命名失败');
setError(err.response?.data?.message || err.message || t('knowledgeDetails.renameFailed'));
}
};
@@ -158,7 +160,7 @@ function KnowledgeBaseDetail() {
await changeDocumentStatus(fileIds, status);
refreshFiles();
} catch (err: any) {
setError(err.response?.data?.message || err.message || '更改状态失败');
setError(err.response?.data?.message || err.message || t('knowledgeDetails.changeStatusFailed'));
}
};
@@ -168,20 +170,20 @@ function KnowledgeBaseDetail() {
await cancelRunDocuments(fileIds);
refreshFiles();
} catch (err: any) {
setError(err.response?.data?.message || err.message || '取消运行失败');
setError(err.response?.data?.message || err.message || t('knowledgeDetails.cancelRunFailed'));
}
};
// 查看详情
const handleViewDetails = (file: IKnowledgeFile) => {
console.log("查看详情:", file);
console.log(t('knowledgeDetails.viewDetails'), file);
navigate(`/chunk/parsed-result?kb_id=${id}&doc_id=${file.id}`);
};
// 查看解析详情
const handleViewProcessDetails = (file: IKnowledgeFile) => {
console.log("查看解析详情:", file);
console.log(t('knowledgeDetails.viewProcessDetails'), file);
setSelectedFileDetails(file);
setProcessDetailsDialogOpen(true);
};
@@ -262,7 +264,7 @@ function KnowledgeBaseDetail() {
return (
<Box sx={{ p: 3 }}>
<LinearProgress />
<Typography sx={{ mt: 2 }}>...</Typography>
<Typography sx={{ mt: 2 }}>{t('common.loading')}</Typography>
</Box>
);
}
@@ -281,11 +283,11 @@ function KnowledgeBaseDetail() {
<KnowledgeBreadcrumbs
kbItems={[
{
label: '知识库',
label: t('knowledgeDetails.knowledgeBase'),
path: '/knowledge'
},
{
label: knowledgeBase?.name || '知识库详情',
label: knowledgeBase?.name || t('knowledgeDetails.knowledgeBaseDetail'),
path: `/knowledge/${id}`
}
]}
@@ -302,8 +304,8 @@ function KnowledgeBaseDetail() {
onChange={(event, newValue) => setCurrentTab(newValue)}
sx={{ borderBottom: 1, borderColor: 'divider' }}
>
<Tab label="Documents" />
<Tab label="Graph" />
<Tab label={t('knowledgeDetails.documents')} />
<Tab label={t('knowledgeDetails.graph')} />
</Tabs>
{/* Document List 标签页内容 */}
@@ -365,7 +367,7 @@ function KnowledgeBaseDetail() {
onSearchChange={setSearchKeyword}
onReparse={(fileIds) => handleReparse(fileIds)}
onDelete={(fileIds) => {
console.log('删除文件:', fileIds);
console.log(t('knowledgeDetails.deleteFiles'), fileIds);
setRowSelectionModel({
type: 'include',
ids: new Set(fileIds)
@@ -379,7 +381,7 @@ function KnowledgeBaseDetail() {
}}
rowSelectionModel={rowSelectionModel}
onRowSelectionModelChange={(newModel) => {
console.log('新的选择模型:', newModel);
console.log(t('knowledgeDetails.newSelectionModel'), newModel);
setRowSelectionModel(newModel);
}}
total={total}
@@ -410,7 +412,7 @@ function KnowledgeBaseDetail() {
open={uploadDialogOpen}
onClose={() => setUploadDialogOpen(false)}
onUpload={handleUploadFiles}
title="上传文件到知识库"
title={t('knowledgeDetails.uploadFilesToKnowledge')}
acceptedFileTypes={['.pdf', '.docx', '.txt', '.md', '.png', '.jpg', '.jpeg', '.mp4', '.wav']}
maxFileSize={100}
maxFiles={10}
@@ -418,15 +420,15 @@ function KnowledgeBaseDetail() {
{/* 删除确认对话框 */}
<Dialog open={deleteDialogOpen} onClose={() => setDeleteDialogOpen(false)}>
<DialogTitle></DialogTitle>
<DialogTitle>{t('knowledgeDetails.confirmDelete')}</DialogTitle>
<DialogContent>
<Typography>
{rowSelectionModel.ids.size}
{t('knowledgeDetails.confirmDeleteMessage', { count: rowSelectionModel.ids.size })}
</Typography>
</DialogContent>
<DialogActions>
<Button onClick={() => setDeleteDialogOpen(false)}></Button>
<Button color="error" onClick={handleDeleteFiles}></Button>
<Button onClick={() => setDeleteDialogOpen(false)}>{t('common.cancel')}</Button>
<Button color="error" onClick={handleDeleteFiles}>{t('common.delete')}</Button>
</DialogActions>
</Dialog>
@@ -437,7 +439,7 @@ function KnowledgeBaseDetail() {
maxWidth="md"
fullWidth
>
<DialogTitle></DialogTitle>
<DialogTitle>{t('knowledgeDetails.documentProcessDetails')}</DialogTitle>
<DialogContent sx={{ p: 3 }}>
{selectedFileDetails && (
<Stack spacing={3}>
@@ -445,12 +447,12 @@ function KnowledgeBaseDetail() {
<Card variant="outlined">
<CardContent>
<Typography variant="h6" gutterBottom color="primary">
{t('knowledgeDetails.basicInfo')}
</Typography>
<Stack spacing={2}>
<Box>
<Typography variant="subtitle2" color="text.secondary" gutterBottom>
{t('knowledgeDetails.fileName')}
</Typography>
<Typography variant="body1" sx={{ fontWeight: 500 }}>
{selectedFileDetails.name}
@@ -459,10 +461,10 @@ function KnowledgeBaseDetail() {
<Divider />
<Box>
<Typography variant="subtitle2" color="text.secondary" gutterBottom>
ID
{t('knowledgeDetails.parserId')}
</Typography>
<Typography variant="body1">
{selectedFileDetails.parser_id || '未指定'}
{selectedFileDetails.parser_id || t('knowledgeDetails.notSpecified')}
</Typography>
</Box>
</Stack>
@@ -473,30 +475,30 @@ function KnowledgeBaseDetail() {
<Card variant="outlined">
<CardContent>
<Typography variant="h6" gutterBottom color="primary">
{t('knowledgeDetails.processStatus')}
</Typography>
<Stack spacing={2}>
<Box>
<Typography variant="subtitle2" color="text.secondary" gutterBottom>
{t('knowledgeDetails.startTime')}
</Typography>
<Typography variant="body1">
{selectedFileDetails.process_begin_at || '未开始'}
{selectedFileDetails.process_begin_at || t('knowledgeDetails.notStarted')}
</Typography>
</Box>
<Divider />
<Box>
<Typography variant="subtitle2" color="text.secondary" gutterBottom>
{t('knowledgeDetails.processingTime')}
</Typography>
<Typography variant="body1">
{selectedFileDetails.process_duration ? `${selectedFileDetails.process_duration}` : '未完成'}
{selectedFileDetails.process_duration ? `${selectedFileDetails.process_duration}${t('knowledgeDetails.seconds')}` : t('knowledgeDetails.notCompleted')}
</Typography>
</Box>
<Divider />
<Box>
<Typography variant="subtitle2" color="text.secondary" gutterBottom>
{t('knowledgeDetails.progress')}
</Typography>
<Box sx={{ display: 'flex', alignItems: 'center', gap: 2 }}>
<Chip
@@ -520,7 +522,7 @@ function KnowledgeBaseDetail() {
<Card variant="outlined">
<CardContent>
<Typography variant="h6" gutterBottom color="primary">
{t('knowledgeDetails.processDetails')}
</Typography>
<Box
sx={{
@@ -556,8 +558,8 @@ function KnowledgeBaseDetail() {
</DialogContent>
<DialogActions sx={{ p: 3, pt: 0 }}>
<Button onClick={() => setProcessDetailsDialogOpen(false)} variant="contained">
</Button>
{t('common.close')}
</Button>
</DialogActions>
</Dialog>
</Box>