feat: 增加管理端多语言与多模块界面国际化支持

This commit is contained in:
2026-05-19 09:11:55 +08:00
parent 49a4caf01e
commit 1b1dfc92ab
110 changed files with 4053 additions and 1308 deletions

View File

@@ -1,6 +1,7 @@
"use client";
import { useCallback, useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import { toast } from "sonner";
import {
@@ -42,6 +43,7 @@ interface Draft {
}
export function WalletConfigDocScreen() {
const { t } = useTranslation(["config", "adminUsers"]);
const [draft, setDraft] = useState<Draft>({
inMin: "",
inMax: "",
@@ -71,11 +73,11 @@ export function WalletConfigDocScreen() {
setSaved(d);
setDirty(false);
} catch {
toast.error("加载失败");
toast.error(t("wallet.loadFailed", { ns: "config" }));
} finally {
setLoading(false);
}
}, []);
}, [t]);
useEffect(() => {
queueMicrotask(() => {
@@ -95,11 +97,13 @@ export function WalletConfigDocScreen() {
await updateAdminSetting(KEYS.IN_MAX, displayToMinorUnits(draft.inMax));
await updateAdminSetting(KEYS.OUT_MIN, displayToMinorUnits(draft.outMin));
await updateAdminSetting(KEYS.OUT_MAX, displayToMinorUnits(draft.outMax));
toast.success("保存成功");
toast.success(t("wallet.saveSuccess", { ns: "config" }));
setSaved(draft);
setDirty(false);
} catch (error) {
toast.error(error instanceof LotteryApiBizError ? error.message : "保存失败");
toast.error(
error instanceof LotteryApiBizError ? error.message : t("wallet.saveFailed", { ns: "config" }),
);
} finally {
setSaving(false);
}
@@ -108,81 +112,81 @@ export function WalletConfigDocScreen() {
return (
<Card>
<CardHeader>
<CardTitle></CardTitle>
<CardTitle>{t("wallet.title", { ns: "config" })}</CardTitle>
</CardHeader>
<CardContent className="space-y-6">
<p className="text-sm text-muted-foreground">
NPR 100 = 1.00 NPR 1
{t("wallet.description", { ns: "config" })}
</p>
<div className="grid gap-6 sm:grid-cols-2">
<div className="space-y-2">
<Label htmlFor="in-min"></Label>
<Label htmlFor="in-min">{t("wallet.fields.inMin", { ns: "config" })}</Label>
<Input
id="in-min"
type="number"
min="0"
step="0.01"
placeholder="例如 1.00"
placeholder={t("wallet.placeholders.min", { ns: "config" })}
value={draft.inMin}
onChange={(e) => handleChange("inMin", e.target.value)}
disabled={loading || saving}
/>
<p className="text-xs text-muted-foreground">
{t("wallet.hints.inMin", { ns: "config" })}
</p>
</div>
<div className="space-y-2">
<Label htmlFor="in-max"></Label>
<Label htmlFor="in-max">{t("wallet.fields.inMax", { ns: "config" })}</Label>
<Input
id="in-max"
type="number"
min="0"
step="0.01"
placeholder="例如 10000.00"
placeholder={t("wallet.placeholders.max", { ns: "config" })}
value={draft.inMax}
onChange={(e) => handleChange("inMax", e.target.value)}
disabled={loading || saving}
/>
<p className="text-xs text-muted-foreground">
{t("wallet.hints.inMax", { ns: "config" })}
</p>
</div>
<div className="space-y-2">
<Label htmlFor="out-min"></Label>
<Label htmlFor="out-min">{t("wallet.fields.outMin", { ns: "config" })}</Label>
<Input
id="out-min"
type="number"
min="0"
step="0.01"
placeholder="例如 1.00"
placeholder={t("wallet.placeholders.min", { ns: "config" })}
value={draft.outMin}
onChange={(e) => handleChange("outMin", e.target.value)}
disabled={loading || saving}
/>
<p className="text-xs text-muted-foreground">
{t("wallet.hints.outMin", { ns: "config" })}
</p>
</div>
<div className="space-y-2">
<Label htmlFor="out-max"></Label>
<Label htmlFor="out-max">{t("wallet.fields.outMax", { ns: "config" })}</Label>
<Input
id="out-max"
type="number"
min="0"
step="0.01"
placeholder="例如 10000.00"
placeholder={t("wallet.placeholders.max", { ns: "config" })}
value={draft.outMax}
onChange={(e) => handleChange("outMax", e.target.value)}
disabled={loading || saving}
/>
<p className="text-xs text-muted-foreground">
{t("wallet.hints.outMax", { ns: "config" })}
</p>
</div>
</div>
<div className="flex items-center gap-4">
<Button onClick={() => void handleSave()} disabled={!dirty || loading || saving}>
{saving ? "保存中…" : "保存"}
{saving ? t("saving", { ns: "adminUsers" }) : t("actions.save", { ns: "adminUsers" })}
</Button>
{dirty && (
<Button
@@ -192,7 +196,7 @@ export function WalletConfigDocScreen() {
setDirty(false);
}}
>
{t("wallet.discard", { ns: "config" })}
</Button>
)}
</div>