locale second stage
This commit is contained in:
@@ -1,18 +1,19 @@
|
||||
"use client";
|
||||
|
||||
import { useMemo, useState, useCallback } from "react";
|
||||
import { GroupTable, Match, Team, ThirdPlaceRow } from "@/lib/types";
|
||||
import { GroupTable, Match, Team, ThirdPlaceRow, teamName } from "@/lib/types";
|
||||
import { ThirdAssignment, orderedRound } from "@/lib/bracket";
|
||||
import { resolveBracket, ResolvedSide, ResolvedTie } from "@/lib/resolve-bracket";
|
||||
import { Dictionary } from "@/lib/i18n";
|
||||
import { STADIUMS, MATCH_STADIUMS, MATCH_DATES } from "@/lib/stadiums";
|
||||
import Flag from "./Flag";
|
||||
|
||||
interface TipState { x: number; y: number; text: string }
|
||||
|
||||
function Side({
|
||||
s, prob, teams, onShowTip, onHideTip,
|
||||
s, prob, teams, locale, dict, onShowTip, onHideTip,
|
||||
}: {
|
||||
s: ResolvedSide; prob?: number | null; teams: Team[];
|
||||
s: ResolvedSide; prob?: number | null; teams: Team[]; locale: string; dict: Dictionary;
|
||||
onShowTip: (text: string, x: number, y: number) => void;
|
||||
onHideTip: () => void;
|
||||
}) {
|
||||
@@ -33,8 +34,8 @@ function Side({
|
||||
{s.teamId ? (
|
||||
<>
|
||||
<Flag team={team} size={18} />
|
||||
<span className="tn">{s.label}</span>
|
||||
{s.provisional && <span className="prov-mark" title="vorläufig – Gruppe/Zuordnung noch nicht fix">≈</span>}
|
||||
<span className="tn">{teamName(team, locale)}</span>
|
||||
{s.provisional && <span className="prov-mark" title={dict.bracket.provisionalTooltip}>≈</span>}
|
||||
</>
|
||||
) : (
|
||||
<span className="lbl">{s.label}</span>
|
||||
@@ -48,11 +49,12 @@ function Side({
|
||||
);
|
||||
}
|
||||
|
||||
function fmtMatchInfo(utcDate?: string, stadiumId?: string): string {
|
||||
function fmtMatchInfo(utcDate?: string, stadiumId?: string, locale: string = "de"): string {
|
||||
if (!utcDate) return "";
|
||||
const intlLocale = locale === "en" ? "en-US" : "de-DE";
|
||||
const d = new Date(utcDate);
|
||||
const dateStr = d.toLocaleDateString("de-DE", { day: "numeric", month: "numeric" });
|
||||
const timeStr = d.toLocaleTimeString("de-DE", { hour: "2-digit", minute: "2-digit" });
|
||||
const dateStr = d.toLocaleDateString(intlLocale, { day: "numeric", month: "numeric" });
|
||||
const timeStr = d.toLocaleTimeString(intlLocale, { hour: "2-digit", minute: "2-digit" });
|
||||
const city = stadiumId ? STADIUMS[stadiumId]?.city : "";
|
||||
const parts = [`${dateStr}`, `${timeStr}`];
|
||||
if (city) parts.push(city);
|
||||
@@ -60,10 +62,11 @@ function fmtMatchInfo(utcDate?: string, stadiumId?: string): string {
|
||||
}
|
||||
|
||||
function Tie({
|
||||
tie, teams, isFinal, matchInfo, onShowTip, onHideTip,
|
||||
tie, teams, isFinal, matchInfo, locale, dict, onShowTip, onHideTip,
|
||||
}: {
|
||||
tie: ResolvedTie; teams: Team[]; isFinal?: boolean;
|
||||
matchInfo?: string;
|
||||
locale: string; dict: Dictionary;
|
||||
onShowTip: (text: string, x: number, y: number) => void;
|
||||
onHideTip: () => void;
|
||||
}) {
|
||||
@@ -71,13 +74,13 @@ function Tie({
|
||||
<div className={`tie ${isFinal ? "final-tie" : ""}`}>
|
||||
<div className="match-badge">{tie.matchNumber}</div>
|
||||
<div className="tie-meta">
|
||||
{matchInfo || `Spiel ${tie.matchNumber}`}
|
||||
{matchInfo || dict.bracket.match(tie.matchNumber)}
|
||||
</div>
|
||||
<Side s={tie.home} prob={tie.prob?.home} teams={teams} onShowTip={onShowTip} onHideTip={onHideTip} />
|
||||
<Side s={tie.away} prob={tie.prob?.away} teams={teams} onShowTip={onShowTip} onHideTip={onHideTip} />
|
||||
<Side s={tie.home} prob={tie.prob?.home} teams={teams} locale={locale} dict={dict} onShowTip={onShowTip} onHideTip={onHideTip} />
|
||||
<Side s={tie.away} prob={tie.prob?.away} teams={teams} locale={locale} dict={dict} onShowTip={onShowTip} onHideTip={onHideTip} />
|
||||
{tie.homePenalty != null && tie.awayPenalty != null && (
|
||||
<div className="tie-meta" style={{ padding: "2px 10px 4px", textAlign: "center" }}>
|
||||
({tie.homePenalty}:{tie.awayPenalty} i.E.)
|
||||
({tie.homePenalty}:{tie.awayPenalty} {dict.bracket.penaltyShootout})
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
@@ -86,14 +89,15 @@ function Tie({
|
||||
|
||||
export default function Bracket({
|
||||
matches, teams, tables, thirds, assignment, annexResolved,
|
||||
preResolved,
|
||||
preResolved, dict, locale,
|
||||
}: {
|
||||
matches: Match[]; teams: Team[]; tables: GroupTable[];
|
||||
thirds: ThirdPlaceRow[]; assignment: ThirdAssignment | null; annexResolved: boolean;
|
||||
preResolved?: { r32: ResolvedTie[]; later: Record<number, ResolvedTie> };
|
||||
dict: Dictionary; locale: string;
|
||||
}) {
|
||||
const { r32: r32Array, later } = preResolved ?? resolveBracket(
|
||||
matches, teams, tables, thirds, assignment, annexResolved,
|
||||
matches, teams, tables, thirds, assignment, annexResolved, undefined, dict,
|
||||
);
|
||||
|
||||
const r32ByNum = new Map(r32Array.map((t) => [t.matchNumber, t]));
|
||||
@@ -104,11 +108,11 @@ export default function Bracket({
|
||||
for (let n = 73; n <= 104; n++) {
|
||||
const utcDate = MATCH_DATES[n];
|
||||
const stadiumId = MATCH_STADIUMS[n];
|
||||
const info = fmtMatchInfo(utcDate, stadiumId);
|
||||
const info = fmtMatchInfo(utcDate, stadiumId, locale);
|
||||
if (info) meta.set(n, info);
|
||||
}
|
||||
return meta;
|
||||
}, []);
|
||||
}, [locale]);
|
||||
|
||||
const sfOrder = orderedRound([104]);
|
||||
const qfOrder = orderedRound(sfOrder);
|
||||
@@ -129,48 +133,48 @@ export default function Bracket({
|
||||
return (
|
||||
<div>
|
||||
<div className="bracket-banner">
|
||||
<span className="k">Annex-C-Zuordnung der Drittplatzierten:</span>
|
||||
<span className="k">{dict.bracket.annexHeader}</span>
|
||||
<span className="v">
|
||||
{annexResolved
|
||||
? "aufgelöst — die acht Dritten sind den Gruppensiegern fest zugeteilt"
|
||||
: "noch offen — sobald die 8 besten Dritten feststehen, verbindet sich der Baum automatisch"}
|
||||
? dict.bracket.annexResolved
|
||||
: dict.bracket.annexPending}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className="bracket-scroll">
|
||||
<div className="bracket">
|
||||
<div className="round">
|
||||
<div className="round-label">Letzte 32</div>
|
||||
<div className="round-label">{dict.round.r32}</div>
|
||||
<div className="round-matches">
|
||||
{r32.map((t) => <Tie key={t.matchNumber} tie={t} teams={teams} matchInfo={matchMeta.get(t.matchNumber)} onShowTip={showTip} onHideTip={hideTip} />)}
|
||||
{r32.map((t) => <Tie key={t.matchNumber} tie={t} teams={teams} locale={locale} dict={dict} matchInfo={matchMeta.get(t.matchNumber)} onShowTip={showTip} onHideTip={hideTip} />)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="round">
|
||||
<div className="round-label">Achtelfinale</div>
|
||||
<div className="round-label">{dict.round.r16}</div>
|
||||
<div className="round-matches">
|
||||
{r16.map((t) => <Tie key={t.matchNumber} tie={t} teams={teams} matchInfo={matchMeta.get(t.matchNumber)} onShowTip={showTip} onHideTip={hideTip} />)}
|
||||
{r16.map((t) => <Tie key={t.matchNumber} tie={t} teams={teams} locale={locale} dict={dict} matchInfo={matchMeta.get(t.matchNumber)} onShowTip={showTip} onHideTip={hideTip} />)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="round">
|
||||
<div className="round-label">Viertelfinale</div>
|
||||
<div className="round-label">{dict.round.qf}</div>
|
||||
<div className="round-matches">
|
||||
{qf.map((t) => <Tie key={t.matchNumber} tie={t} teams={teams} matchInfo={matchMeta.get(t.matchNumber)} onShowTip={showTip} onHideTip={hideTip} />)}
|
||||
{qf.map((t) => <Tie key={t.matchNumber} tie={t} teams={teams} locale={locale} dict={dict} matchInfo={matchMeta.get(t.matchNumber)} onShowTip={showTip} onHideTip={hideTip} />)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="round">
|
||||
<div className="round-label">Halbfinale</div>
|
||||
<div className="round-label">{dict.round.sf}</div>
|
||||
<div className="round-matches">
|
||||
{sf.map((t) => <Tie key={t.matchNumber} tie={t} teams={teams} matchInfo={matchMeta.get(t.matchNumber)} onShowTip={showTip} onHideTip={hideTip} />)}
|
||||
{sf.map((t) => <Tie key={t.matchNumber} tie={t} teams={teams} locale={locale} dict={dict} matchInfo={matchMeta.get(t.matchNumber)} onShowTip={showTip} onHideTip={hideTip} />)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="round">
|
||||
<div className="round-label">Finale</div>
|
||||
<div className="round-label">{dict.round.final}</div>
|
||||
<div className="round-matches">
|
||||
{fin && <Tie tie={fin} teams={teams} isFinal matchInfo={matchMeta.get(fin.matchNumber)} onShowTip={showTip} onHideTip={hideTip} />}
|
||||
{fin && <Tie tie={fin} teams={teams} isFinal locale={locale} dict={dict} matchInfo={matchMeta.get(fin.matchNumber)} onShowTip={showTip} onHideTip={hideTip} />}
|
||||
{third && (
|
||||
<div style={{ marginTop: 20 }}>
|
||||
<div className="round-label" style={{ marginBottom: 8 }}>Spiel um Platz 3</div>
|
||||
<Tie tie={third} teams={teams} matchInfo={matchMeta.get(third.matchNumber)} onShowTip={showTip} onHideTip={hideTip} />
|
||||
<div className="round-label" style={{ marginBottom: 8 }}>{dict.round.thirdPlace}</div>
|
||||
<Tie tie={third} teams={teams} locale={locale} dict={dict} matchInfo={matchMeta.get(third.matchNumber)} onShowTip={showTip} onHideTip={hideTip} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
@@ -179,12 +183,12 @@ export default function Bracket({
|
||||
</div>
|
||||
|
||||
<div className="legend">
|
||||
<span><i style={{ background: "var(--turf)" }} />Sieger / weiter</span>
|
||||
<span><i style={{ background: "var(--gold)" }} />Finale</span>
|
||||
<span><i className="leg-fix" />fix qualifiziert</span>
|
||||
<span><i className="leg-prov" />vorläufig (≈, nach aktueller Tabelle)</span>
|
||||
<span><i style={{ background: "var(--ink-faint)" }} />Platzhalter offen</span>
|
||||
<span>%-Werte: Polymarket-Wahrscheinlichkeit (falls verfügbar)</span>
|
||||
<span><i style={{ background: "var(--turf)" }} />{dict.legend.winner}</span>
|
||||
<span><i style={{ background: "var(--gold)" }} />{dict.legend.final}</span>
|
||||
<span><i className="leg-fix" />{dict.legend.fixed}</span>
|
||||
<span><i className="leg-prov" />{dict.legend.provisional}</span>
|
||||
<span><i style={{ background: "var(--ink-faint)" }} />{dict.legend.placeholder}</span>
|
||||
<span>{dict.legend.probExplanation}</span>
|
||||
</div>
|
||||
|
||||
{tip && (
|
||||
|
||||
Reference in New Issue
Block a user