refactor: 完成全站国际化改造,统一多语言支持
此提交完成了全项目的国际化适配: 1. 新增多语言翻译文件与基础配置 2. 替换所有硬编码文本为i18n调用 3. 优化语言切换与文档语言同步逻辑 4. 重构部分业务逻辑以支持动态翻译 5. 移除过时代码与硬编码配置
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { AlertTriangleIcon } from "lucide-react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
|
||||
import { Button } from "@/components/ui/button";
|
||||
@@ -28,14 +29,16 @@ type HallBetPreviewDialogProps = {
|
||||
};
|
||||
|
||||
function WarningsBlock({ warnings }: { warnings: TicketPreviewWarning[] }) {
|
||||
const { t } = useTranslation("player");
|
||||
|
||||
if (warnings.length === 0) return null;
|
||||
return (
|
||||
<Alert className="border-amber-500/40 bg-amber-500/5 text-amber-950 dark:text-amber-100">
|
||||
<AlertTriangleIcon />
|
||||
<AlertTitle>赔付池预警</AlertTitle>
|
||||
<AlertTitle>{t("hall.preview.warningsTitle")}</AlertTitle>
|
||||
<AlertDescription className="space-y-1">
|
||||
<p className="text-xs leading-relaxed">
|
||||
产品文档 §6.4:以下号码本期赔付池占用较高,仍允许下注;若实际占用不足将售罄拒单。
|
||||
{t("hall.preview.warningsDescription")}
|
||||
</p>
|
||||
<ul className="list-inside list-disc text-xs">
|
||||
{warnings.map((w, i) => (
|
||||
@@ -61,6 +64,7 @@ export function HallBetPreviewDialog({
|
||||
allowSubmit = true,
|
||||
onConfirmPlace,
|
||||
}: HallBetPreviewDialogProps) {
|
||||
const { t } = useTranslation("player");
|
||||
const summary = data?.summary;
|
||||
const lines = data?.lines ?? [];
|
||||
|
||||
@@ -69,17 +73,17 @@ export function HallBetPreviewDialog({
|
||||
<DialogContent className="max-h-[min(90vh,560px)] gap-0 overflow-hidden p-0 sm:max-w-md">
|
||||
<div className="p-4 pb-2">
|
||||
<DialogHeader>
|
||||
<DialogTitle>确认下注</DialogTitle>
|
||||
<DialogTitle>{t("hall.preview.title")}</DialogTitle>
|
||||
<DialogDescription>
|
||||
请核对号码、玩法与实扣金额;确认后将扣减彩票钱包且不可撤单(产品文档 §6.3)。
|
||||
{t("hall.preview.description")}
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
{!allowSubmit ? (
|
||||
<Alert className="mt-3 border-[#ff4d4f]/35 bg-[#ff4d4f]/8 text-[#ff4d4f] dark:bg-[#ff4d4f]/12">
|
||||
<AlertTriangleIcon />
|
||||
<AlertTitle>已封盘</AlertTitle>
|
||||
<AlertTitle>{t("hall.preview.sealedTitle")}</AlertTitle>
|
||||
<AlertDescription className="text-xs leading-relaxed">
|
||||
当前期已停止接收注单,无法提交。请选择下一期(界面文档 §4.2)。
|
||||
{t("hall.preview.sealedDescription")}
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
) : null}
|
||||
@@ -88,37 +92,38 @@ export function HallBetPreviewDialog({
|
||||
<ScrollArea className="max-h-[min(52vh,360px)] border-y px-4">
|
||||
<div className="space-y-4 py-3 pr-3">
|
||||
{!data ? (
|
||||
<p className="text-sm text-muted-foreground">暂无预览数据</p>
|
||||
<p className="text-sm text-muted-foreground">{t("hall.preview.empty")}</p>
|
||||
) : (
|
||||
<>
|
||||
<div className="rounded-lg border bg-muted/30 p-3 text-xs">
|
||||
<p>
|
||||
期号{" "}
|
||||
<span className="font-mono font-semibold">{data.draw.draw_id}</span> · 状态{" "}
|
||||
{t("hall.preview.draw")}{" "}
|
||||
<span className="font-mono font-semibold">{data.draw.draw_id}</span> ·{" "}
|
||||
{t("hall.preview.status")}{" "}
|
||||
<span className="font-medium">{data.draw.status}</span>
|
||||
</p>
|
||||
{summary ? (
|
||||
<ul className="mt-2 space-y-1 tabular-nums">
|
||||
<li>
|
||||
总下注{" "}
|
||||
{t("hall.preview.totalBet")}{" "}
|
||||
<span className="font-medium">
|
||||
{formatMinorAsCurrency(summary.total_bet_amount, currencyCode)}
|
||||
</span>
|
||||
</li>
|
||||
<li>
|
||||
回水抵扣{" "}
|
||||
{t("hall.preview.rebateDeduct")}{" "}
|
||||
<span className="font-medium">
|
||||
{formatMinorAsCurrency(summary.total_rebate_amount, currencyCode)}
|
||||
</span>
|
||||
</li>
|
||||
<li>
|
||||
实扣金额{" "}
|
||||
{t("hall.preview.actualDeduct")}{" "}
|
||||
<span className="font-semibold text-primary">
|
||||
{formatMinorAsCurrency(summary.total_actual_deduct, currencyCode)}
|
||||
</span>
|
||||
</li>
|
||||
<li>
|
||||
预估最高赔付{" "}
|
||||
{t("hall.preview.estimatedPayout")}{" "}
|
||||
<span className="font-medium">
|
||||
{formatMinorAsCurrency(summary.total_estimated_payout, currencyCode)}
|
||||
</span>
|
||||
@@ -130,7 +135,9 @@ export function HallBetPreviewDialog({
|
||||
<WarningsBlock warnings={data.warnings} />
|
||||
|
||||
<div className="space-y-2">
|
||||
<p className="text-xs font-medium text-muted-foreground">注项明细</p>
|
||||
<p className="text-xs font-medium text-muted-foreground">
|
||||
{t("hall.preview.lines")}
|
||||
</p>
|
||||
<ul className="space-y-2 text-sm">
|
||||
{lines.map((ln) => (
|
||||
<li
|
||||
@@ -146,15 +153,23 @@ export function HallBetPreviewDialog({
|
||||
<p className="mt-1 font-mono text-base">{ln.number}</p>
|
||||
<Separator className="my-2" />
|
||||
<div className="grid grid-cols-2 gap-x-2 gap-y-1 text-xs tabular-nums">
|
||||
<span className="text-muted-foreground">归一号码</span>
|
||||
<span className="text-muted-foreground">
|
||||
{t("hall.preview.normalizedNumber")}
|
||||
</span>
|
||||
<span className="text-right font-mono">{ln.normalized_number}</span>
|
||||
<span className="text-muted-foreground">组合数</span>
|
||||
<span className="text-muted-foreground">
|
||||
{t("hall.preview.combinationCount")}
|
||||
</span>
|
||||
<span className="text-right">{ln.combination_count}</span>
|
||||
<span className="text-muted-foreground">实扣</span>
|
||||
<span className="text-muted-foreground">
|
||||
{t("hall.preview.actual")}
|
||||
</span>
|
||||
<span className="text-right">
|
||||
{formatMinorAsCurrency(ln.actual_deduct_amount, currencyCode)}
|
||||
</span>
|
||||
<span className="text-muted-foreground">预估最高赔</span>
|
||||
<span className="text-muted-foreground">
|
||||
{t("hall.preview.estimatedMax")}
|
||||
</span>
|
||||
<span className="text-right">
|
||||
{formatMinorAsCurrency(ln.estimated_max_payout, currencyCode)}
|
||||
</span>
|
||||
@@ -170,10 +185,14 @@ export function HallBetPreviewDialog({
|
||||
|
||||
<div className="flex flex-col-reverse gap-2 border-t bg-muted/30 p-4 sm:flex-row sm:justify-between">
|
||||
<Button type="button" variant="outline" onClick={() => onOpenChange(false)} disabled={placing}>
|
||||
返回修改
|
||||
{t("hall.preview.backEdit")}
|
||||
</Button>
|
||||
<Button type="button" onClick={onConfirmPlace} disabled={!data || placing || !allowSubmit}>
|
||||
{placing ? "提交中…" : allowSubmit ? "确认提交" : "已封盘"}
|
||||
{placing
|
||||
? t("hall.preview.submitting")
|
||||
: allowSubmit
|
||||
? t("hall.preview.confirmSubmit")
|
||||
: t("hall.preview.sealedTitle")}
|
||||
</Button>
|
||||
</div>
|
||||
</DialogContent>
|
||||
|
||||
Reference in New Issue
Block a user