refactor: 完成全站国际化改造,统一多语言支持
此提交完成了全项目的国际化适配: 1. 新增多语言翻译文件与基础配置 2. 替换所有硬编码文本为i18n调用 3. 优化语言切换与文档语言同步逻辑 4. 重构部分业务逻辑以支持动态翻译 5. 移除过时代码与硬编码配置
This commit is contained in:
@@ -10,10 +10,6 @@ export default async function DrawResultByNoPage(props: PageProps) {
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-4">
|
||||
<div>
|
||||
<h1 className="text-lg font-semibold tracking-tight">开奖结果</h1>
|
||||
<p className="text-xs text-muted-foreground">当期明细 · 23 组分区</p>
|
||||
</div>
|
||||
<DrawResultDetailScreen drawNo={drawNo} />
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -3,13 +3,8 @@ import { DrawResultsListScreen } from "@/features/results/draw-results-list-scre
|
||||
export default function DrawResultsHistoryPage() {
|
||||
return (
|
||||
<div className="flex flex-col gap-4">
|
||||
<div>
|
||||
<h1 className="text-lg font-semibold tracking-tight">开奖结果</h1>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
往期列表与时间以服务器 GMT 为准(界面文档 §4.6)
|
||||
</p>
|
||||
</div>
|
||||
<DrawResultsListScreen />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ import { EntryGate } from "@/features/player/entry-gate";
|
||||
function EntryFallback(): ReactNode {
|
||||
return (
|
||||
<div className="flex min-h-dvh flex-col items-center justify-center bg-gradient-to-b from-red-800 to-red-950 px-4 text-sm text-white/90">
|
||||
<p>加载入口页…</p>
|
||||
<p>Loading...</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -3,8 +3,10 @@
|
||||
import { useEffect } from "react";
|
||||
import Link from "next/link";
|
||||
import { AlertTriangle, Home, RotateCcw } from "lucide-react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import { ERROR_COLORS } from "@/stores/error-store";
|
||||
import "@/i18n";
|
||||
|
||||
/**
|
||||
* Next.js 错误边界组件
|
||||
@@ -18,6 +20,8 @@ export default function ErrorBoundary({
|
||||
error: Error & { digest?: string };
|
||||
reset: () => void;
|
||||
}): React.ReactElement {
|
||||
const { t } = useTranslation("player");
|
||||
|
||||
useEffect(() => {
|
||||
// 记录错误日志
|
||||
console.error("[ErrorBoundary] Application error:", error);
|
||||
@@ -52,26 +56,28 @@ export default function ErrorBoundary({
|
||||
|
||||
{/* 错误标题 */}
|
||||
<h1 className="mb-2 text-2xl font-bold text-foreground">
|
||||
{isServerError ? "服务器暂时不可用" : "应用发生错误"}
|
||||
{isServerError ? t("serverError.unavailable") : t("serverError.appTitle")}
|
||||
</h1>
|
||||
|
||||
{/* 错误消息 */}
|
||||
<p className="mb-2 text-base text-muted-foreground">
|
||||
{isServerError
|
||||
? "服务器暂时不可用,请稍后重试"
|
||||
: "抱歉,应用遇到了问题,请尝试刷新页面"}
|
||||
? t("serverError.serverMessage")
|
||||
: t("serverError.appMessage")}
|
||||
</p>
|
||||
|
||||
{/* 技术详情(开发模式) */}
|
||||
{process.env.NODE_ENV === "development" && (
|
||||
<div className="mb-6 w-full rounded-lg bg-muted p-3 text-left">
|
||||
<p className="mb-1 text-xs font-medium text-muted-foreground">错误详情:</p>
|
||||
<p className="mb-1 text-xs font-medium text-muted-foreground">
|
||||
{t("serverError.details")}
|
||||
</p>
|
||||
<code className="block max-h-32 overflow-auto whitespace-pre-wrap break-words text-xs text-destructive">
|
||||
{error.message}
|
||||
</code>
|
||||
{error.digest && (
|
||||
<p className="mt-2 text-xs text-muted-foreground">
|
||||
错误 ID: {error.digest}
|
||||
{t("serverError.errorId", { id: error.digest })}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
@@ -85,7 +91,7 @@ export default function ErrorBoundary({
|
||||
style={{ borderColor: isServerError ? ERROR_COLORS.error : ERROR_COLORS.warning, color: isServerError ? ERROR_COLORS.error : ERROR_COLORS.warning }}
|
||||
>
|
||||
<RotateCcw className="size-4" />
|
||||
重试
|
||||
{t("actions.retry")}
|
||||
</button>
|
||||
|
||||
<Link
|
||||
@@ -96,7 +102,7 @@ export default function ErrorBoundary({
|
||||
}}
|
||||
>
|
||||
<Home className="size-4" />
|
||||
返回首页
|
||||
{t("serverError.home")}
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
@@ -106,21 +112,21 @@ export default function ErrorBoundary({
|
||||
onClick={() => window.location.reload()}
|
||||
className="hover:text-foreground hover:underline"
|
||||
>
|
||||
刷新页面
|
||||
{t("serverError.refreshPage")}
|
||||
</button>
|
||||
<span>|</span>
|
||||
<Link
|
||||
href="/hall"
|
||||
className="hover:text-foreground hover:underline"
|
||||
>
|
||||
投注大厅
|
||||
{t("serverError.hall")}
|
||||
</Link>
|
||||
<span>|</span>
|
||||
<Link
|
||||
href="/wallet"
|
||||
className="hover:text-foreground hover:underline"
|
||||
>
|
||||
我的钱包
|
||||
{t("serverError.wallet")}
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -2,6 +2,7 @@ import type { Metadata } from "next";
|
||||
import { Geist, Geist_Mono } from "next/font/google";
|
||||
|
||||
import { Providers } from "@/components/providers";
|
||||
import { DEFAULT_LANGUAGE } from "@/i18n";
|
||||
import "./globals.css";
|
||||
|
||||
const geistSans = Geist({
|
||||
@@ -26,7 +27,7 @@ export default function RootLayout({
|
||||
}>) {
|
||||
return (
|
||||
<html
|
||||
lang="en"
|
||||
lang={DEFAULT_LANGUAGE}
|
||||
suppressHydrationWarning
|
||||
className={`${geistSans.variable} ${geistMono.variable} h-full antialiased`}
|
||||
>
|
||||
|
||||
@@ -2,8 +2,10 @@
|
||||
|
||||
import Link from "next/link";
|
||||
import { FileQuestion, Home } from "lucide-react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import { ERROR_COLORS } from "@/stores/error-store";
|
||||
import "@/i18n";
|
||||
|
||||
/**
|
||||
* 全局 404 页面
|
||||
@@ -13,6 +15,8 @@ import { ERROR_COLORS } from "@/stores/error-store";
|
||||
* 使用中性颜色 #d9d9d9 作为背景/插图
|
||||
*/
|
||||
export default function NotFoundPage(): React.ReactElement {
|
||||
const { t } = useTranslation("player");
|
||||
|
||||
return (
|
||||
<div
|
||||
className="flex min-h-screen flex-col items-center justify-center p-4"
|
||||
@@ -42,12 +46,12 @@ export default function NotFoundPage(): React.ReactElement {
|
||||
|
||||
{/* 标题 */}
|
||||
<h1 className="mb-3 text-2xl font-bold text-gray-800">
|
||||
页面不存在
|
||||
{t("notFound.title")}
|
||||
</h1>
|
||||
|
||||
{/* 描述 */}
|
||||
<p className="mb-8 text-base text-gray-500">
|
||||
抱歉,您访问的页面可能已被删除、移动或从未存在过。
|
||||
{t("notFound.description")}
|
||||
</p>
|
||||
|
||||
{/* 返回首页按钮 */}
|
||||
@@ -57,21 +61,21 @@ export default function NotFoundPage(): React.ReactElement {
|
||||
style={{ backgroundColor: "#333" }}
|
||||
>
|
||||
<Home className="size-5" />
|
||||
返回首页
|
||||
{t("notFound.home")}
|
||||
</Link>
|
||||
|
||||
{/* 帮助链接 */}
|
||||
<div className="mt-8 flex gap-4 text-sm text-gray-400">
|
||||
<Link href="/hall" className="hover:text-gray-600 hover:underline">
|
||||
投注大厅
|
||||
{t("notFound.hall")}
|
||||
</Link>
|
||||
<span>|</span>
|
||||
<Link href="/results" className="hover:text-gray-600 hover:underline">
|
||||
开奖结果
|
||||
{t("notFound.results")}
|
||||
</Link>
|
||||
<span>|</span>
|
||||
<Link href="/wallet" className="hover:text-gray-600 hover:underline">
|
||||
我的钱包
|
||||
{t("notFound.wallet")}
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user