refactor: 完成全站国际化改造,统一多语言支持

此提交完成了全项目的国际化适配:
1. 新增多语言翻译文件与基础配置
2. 替换所有硬编码文本为i18n调用
3. 优化语言切换与文档语言同步逻辑
4. 重构部分业务逻辑以支持动态翻译
5. 移除过时代码与硬编码配置
This commit is contained in:
2026-05-15 10:41:14 +08:00
parent ac612cb32c
commit f2c7f5e4f1
53 changed files with 2179 additions and 767 deletions

View File

@@ -1,26 +1,19 @@
"use client";
import Link from "next/link";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { useTranslation } from "react-i18next";
import { getWalletLogs } from "@/api/wallet";
import { Button, buttonVariants } from "@/components/ui/button";
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { PlayerPanel } from "@/components/layout/player-panel";
import { WalletLogsBlock } from "@/features/wallet/wallet-logs-block";
import { formatWalletClientError } from "@/lib/wallet-api-error";
import { cn } from "@/lib/utils";
import { usePlayerSessionStore } from "@/stores/player-session-store";
import type { WalletLogsData } from "@/types/api/wallet-logs";
/** 独立路由 `/wallet/logs` */
export function WalletLogsScreen() {
const profile = usePlayerSessionStore((s) => s.profile);
const { t } = useTranslation("player");
const [logs, setLogs] = useState<WalletLogsData | null>(null);
const [filter, setFilter] = useState("");
const [loading, setLoading] = useState(true);
@@ -50,12 +43,12 @@ export function WalletLogsScreen() {
});
setLogs(L);
} catch (e) {
setError(formatWalletClientError(e));
setError(formatWalletClientError(e, t));
} finally {
setLoading(false);
setLogsLoading(false);
}
}, [filter]);
}, [filter, t]);
useEffect(() => {
queueMicrotask(() => {
@@ -64,39 +57,36 @@ export function WalletLogsScreen() {
}, [load]);
return (
<div className="flex flex-col gap-6">
<div className="flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between">
<h1 className="text-lg font-semibold tracking-tight"></h1>
<Link
href="/wallet"
className={cn(buttonVariants({ variant: "outline", size: "sm" }))}
>
</Link>
</div>
{error ? (
<Card className="border-destructive/40">
<CardHeader>
<CardTitle className="text-destructive"></CardTitle>
<CardDescription>{error}</CardDescription>
</CardHeader>
<CardContent>
<Button type="button" onClick={() => void load()}>
<PlayerPanel
title={t("wallet.logsTitle")}
subtitle={t("wallet.logsSubtitle")}
eyebrow={t("brand.name")}
backHref="/wallet"
backLabel={t("wallet.title")}
>
<div className="space-y-4">
{error ? (
<div className="rounded-xl border border-red-200 bg-red-50 px-4 py-4 text-sm text-red-700">
<p>{error}</p>
<Button
type="button"
className="mt-3 bg-[#e5002c] text-white hover:bg-[#d10028]"
onClick={() => void load()}
>
{t("actions.retry")}
</Button>
</CardContent>
</Card>
) : null}
</div>
) : null}
<WalletLogsBlock
logs={logs}
logsLoading={loading || logsLoading}
filter={filter}
onFilterChange={setFilter}
currency={currency}
title="类型筛选"
/>
</div>
<WalletLogsBlock
logs={logs}
logsLoading={loading || logsLoading}
filter={filter}
onFilterChange={setFilter}
currency={currency}
title={t("wallet.typeFilter")}
/>
</div>
</PlayerPanel>
);
}