locale second stage

This commit is contained in:
2026-07-01 11:21:29 -05:00
parent dca3a66206
commit 09020b7aef
12 changed files with 237 additions and 191 deletions

View File

@@ -1,8 +1,9 @@
"use client";
import { useEffect, useState, useCallback } from "react";
import { useEffect, useState, useCallback, useMemo, use } from "react";
import { GroupId, GroupTable, Match, Team, ThirdPlaceRow } from "@/lib/types";
import { ThirdAssignment } from "@/lib/bracket";
import { getDictionary, Locale, Dictionary } from "@/lib/i18n";
import Groups from "./components/Groups";
import ThirdPlace from "./components/ThirdPlace";
import Bracket from "./components/Bracket";
@@ -24,7 +25,9 @@ interface ApiData {
type Tab = "groups" | "groupfixtures" | "kofixtures" | "thirds" | "bracket" | "sim";
export default function Home() {
export default function Home({ params }: { params: Promise<{ locale: string }> }) {
const { locale } = use(params) as { locale: Locale };
const dict = useMemo(() => getDictionary(locale), [locale]);
const [data, setData] = useState<ApiData | null>(null);
const [error, setError] = useState<string | null>(null);
const [tab, setTab] = useState<Tab>("kofixtures");
@@ -33,7 +36,7 @@ export default function Home() {
const load = useCallback(async () => {
try {
const res = await fetch("/api/matches", { cache: "no-store" });
const res = await fetch(`/api/matches?locale=${locale}`, { cache: "no-store" });
if (!res.ok) {
const body = await res.json().catch(() => ({}));
throw new Error(body.detail || `Fehler ${res.status}`);
@@ -43,7 +46,7 @@ export default function Home() {
} catch (e) {
setError(e instanceof Error ? e.message : "Verbindung fehlgeschlagen");
}
}, []);
}, [locale]);
useEffect(() => {
load();
@@ -67,37 +70,37 @@ export default function Home() {
<div className="wrap masthead-inner">
<div className="brand">
<span className="brand-mark">WM <span className="accent">26</span></span>
<span className="brand-sub">USA · Kanada · Mexiko</span>
<span className="brand-sub">{dict.header.hostCountries}</span>
</div>
<span className="status-pill">
<span className={`dot ${anyLive ? "live" : data ? "on" : ""}`} />
{error
? "Feed offline"
? dict.status.feedOffline
: data
? anyLive ? "Live" : `Aktualisiert ${new Date(data.updatedAt).toLocaleTimeString("de-DE")}`
: "Lade Daten…"}
? anyLive ? dict.status.live : dict.status.updated(new Date(data.updatedAt).toLocaleTimeString(locale === "en" ? "en-US" : "de-DE"))
: dict.status.loading}
</span>
<nav className="tabs masthead-tabs">
<button className={`tab ${tab === "kofixtures" ? "active" : ""}`} onClick={() => setTab("kofixtures")}>
K.O.-Spiele
{dict.nav.koFixtures}
</button>
<button className={`tab ${tab === "groups" ? "active" : ""}`} onClick={() => setTab("groups")}>
Gruppen
{dict.nav.groups}
</button>
<button
className={`tab ${tab === "groupfixtures" ? "active" : ""}`}
onClick={() => { if (!fixturesGroup) setFixturesGroup("A"); setTab("groupfixtures"); }}
>
{fixturesGroup ? `Gruppenspiele ${fixturesGroup}` : "Gruppenspiele"}
{fixturesGroup ? dict.nav.groupFixtures(fixturesGroup) : dict.nav.groupFixturesNoGroup}
</button>
<button className={`tab ${tab === "thirds" ? "active" : ""}`} onClick={() => setTab("thirds")}>
Drittplatzierte
{dict.nav.thirdPlace}
</button>
<button className={`tab ${tab === "bracket" ? "active" : ""}`} onClick={() => setTab("bracket")}>
K.o.-Baum
{dict.nav.bracket}
</button>
<button className={`tab ${tab === "sim" ? "active" : ""}`} onClick={() => setTab("sim")}>
Simulation
{dict.nav.simulation}
</button>
</nav>
</div>
@@ -108,9 +111,7 @@ export default function Home() {
<section className="section">
{error && (
<div className="notice err">
Die Live-Feeds sind gerade nicht erreichbar: {error}.
Prüfe den <code>FOOTBALL_DATA_TOKEN</code> und die Netzwerkfreigabe des Servers.
Die Seite versucht es automatisch erneut.
{dict.error.feedUnreachable}
</div>
)}
@@ -121,32 +122,32 @@ export default function Home() {
)}
{data && tab === "kofixtures" && (
<KoFixtures teams={data.teams} matches={data.matches} />
<KoFixtures teams={data.teams} matches={data.matches} dict={dict} locale={locale} />
)}
{data && tab === "groups" && (
<Groups
tables={data.groupTablesLive} teams={data.teams} matches={data.matches}
onOpenGroup={openGroupFixtures}
onOpenGroup={openGroupFixtures} dict={dict} locale={locale}
/>
)}
{data && tab === "groupfixtures" && fixturesGroup && (
<Fixtures
group={fixturesGroup} teams={data.teams} matches={data.matches}
onSelectGroup={setFixturesGroup}
onSelectGroup={setFixturesGroup} dict={dict} locale={locale}
/>
)}
{data && tab === "thirds" && (
<ThirdPlace rows={data.thirdTable} teams={data.teams} secureTeams={data.secureThirdTeams} />
<ThirdPlace rows={data.thirdTable} teams={data.teams} secureTeams={data.secureThirdTeams} dict={dict} />
)}
{data && tab === "bracket" && (
<Bracket
matches={data.matches} teams={data.teams} tables={data.groupTablesLive}
thirds={data.thirdTable} assignment={data.annexAssignment}
annexResolved={data.annexResolved}
annexResolved={data.annexResolved} dict={dict} locale={locale}
/>
)}
{data && tab === "sim" && (
<Simulation teams={data.teams} matches={data.matches} />
<Simulation teams={data.teams} matches={data.matches} dict={dict} locale={locale} />
)}
</section>
</main>
@@ -182,13 +183,13 @@ export default function Home() {
fontFamily: "var(--font-mono)", fontSize: 10,
color: "var(--ink-faint)",
}}>
WM 2026 Dashboard
{dict.footer.dashboard}
</span>
<span style={{
fontFamily: "var(--font-mono)", fontSize: 9,
color: "var(--ink-faint)", opacity: 0.5, marginTop: 8,
}}>
Daten: football-data.org · Polymarket Gamma API · FIFA Annex C
{dict.footer.dataSources}
</span>
</div>
</footer>