feat: add n18n

This commit is contained in:
qixinbo
2026-03-21 21:26:57 +08:00
parent 40f84fc98e
commit 5ab9884bf6
22 changed files with 823 additions and 273 deletions
+17 -15
View File
@@ -2,6 +2,7 @@ import { useState, useRef } from "react";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Loader2, Check, AlertTriangle, Upload } from "lucide-react";
import { useTranslation } from "react-i18next";
import { api } from "@/lib/api";
export interface DataSourceConfig {
@@ -19,6 +20,7 @@ interface DataSourceFormProps {
}
export function DataSourceForm({ initialData, onSubmit, onTest, onCancel }: DataSourceFormProps) {
const { t } = useTranslation();
const [name, setName] = useState(initialData?.name || "");
const [type, setType] = useState(initialData?.type || "postgres");
const [config, setConfig] = useState<Record<string, any>>(initialData?.config || {});
@@ -52,7 +54,7 @@ export function DataSourceForm({ initialData, onSubmit, onTest, onCancel }: Data
}
} catch (error) {
console.error("Upload failed", error);
alert("上传失败");
alert(t('uploadFailed'));
} finally {
setIsUploading(false);
// Clear input value so same file can be selected again
@@ -69,12 +71,12 @@ export function DataSourceForm({ initialData, onSubmit, onTest, onCancel }: Data
const success = await onTest(type, config);
setTestResult({
success,
message: success ? "连接成功" : "连接失败",
message: success ? t('connectionSuccess') : t('connectionFailed'),
});
} catch (e: any) {
setTestResult({
success: false,
message: e.message || "连接失败",
message: e.message || t('connectionFailed'),
});
} finally {
setIsTesting(false);
@@ -141,7 +143,7 @@ export function DataSourceForm({ initialData, onSubmit, onTest, onCancel }: Data
/>
</div>
<div className="text-xs text-zinc-500 pt-2">
使 Supabase Connection String (URI):
{t('orUseSupabaseConnectionString')}
</div>
<div className="space-y-2">
<label className="text-sm font-medium">Connection String</label>
@@ -206,7 +208,7 @@ export function DataSourceForm({ initialData, onSubmit, onTest, onCancel }: Data
/>
</div>
<div className="text-xs text-zinc-500 pt-2">
使 ():
{t('orUseConnectionString')}
</div>
<div className="space-y-2">
<label className="text-sm font-medium">Connection String</label>
@@ -273,7 +275,7 @@ export function DataSourceForm({ initialData, onSubmit, onTest, onCancel }: Data
return (
<div className="space-y-4">
<div className="space-y-2">
<label className="text-sm font-medium"></label>
<label className="text-sm font-medium">{t('fileUpload')}</label>
<div className="flex gap-2">
<Input
value={config.file_path || ""}
@@ -292,7 +294,7 @@ export function DataSourceForm({ initialData, onSubmit, onTest, onCancel }: Data
onChange={handleFileUpload}
/>
</div>
<p className="text-xs text-zinc-500"></p>
<p className="text-xs text-zinc-500">{t('uploadFileOrEnterPath')}</p>
</div>
</div>
);
@@ -300,9 +302,9 @@ export function DataSourceForm({ initialData, onSubmit, onTest, onCancel }: Data
return (
<div className="flex flex-col items-center justify-center py-8 text-center">
<AlertTriangle className="h-10 w-10 text-amber-500 mb-3" />
<h3 className="font-medium text-zinc-900"></h3>
<h3 className="font-medium text-zinc-900">{t('unsupportedDataSourceType')}</h3>
<p className="text-sm text-zinc-500 mt-1 max-w-[300px]">
使 PostgreSQL, ClickHouse
{t('dataSourceConnectorInDevelopment')}
</p>
</div>
);
@@ -312,18 +314,18 @@ export function DataSourceForm({ initialData, onSubmit, onTest, onCancel }: Data
return (
<form onSubmit={handleSubmit} className="space-y-6">
<div className="space-y-2">
<label className="text-sm font-medium"></label>
<label className="text-sm font-medium">{t('name')}</label>
<Input
value={name}
onChange={e => setName(e.target.value)}
placeholder="我的数据源"
placeholder={t('myDataSource')}
required
/>
</div>
{!initialData?.type && (
<div className="space-y-2">
<label className="text-sm font-medium"></label>
<label className="text-sm font-medium">{t('type')}</label>
<select
className="w-full h-10 px-3 rounded-md border border-zinc-200 bg-white text-sm focus:outline-none focus:ring-2 focus:ring-zinc-950 focus:border-transparent"
value={type}
@@ -353,7 +355,7 @@ export function DataSourceForm({ initialData, onSubmit, onTest, onCancel }: Data
<div className="flex justify-end gap-3 pt-4">
<Button type="button" variant="outline" onClick={onCancel}>
{t('cancel')}
</Button>
<Button
type="button"
@@ -362,11 +364,11 @@ export function DataSourceForm({ initialData, onSubmit, onTest, onCancel }: Data
disabled={isTesting}
>
{isTesting && <Loader2 className="mr-2 h-4 w-4 animate-spin" />}
{t('testConnection')}
</Button>
<Button type="submit" disabled={isSaving}>
{isSaving && <Loader2 className="mr-2 h-4 w-4 animate-spin" />}
{t('save')}
</Button>
</div>
</form>