Skip to content

Commit 91bf026

Browse files
B2JK-Industryclaude
andcommitted
fix(i18n): PR-P G-31 + G-33 — language audit + /games sunset backdrop
G-31 — language mutation audit pass. Programmatic sweep for cross-locale character leaks across lib/locales/{pl,uk,cs,en}.ts + app/ + components/: - Slovak-only chars (ô ľ ĺ ŕ) in pl/uk/cs/en - Polish-only chars (ą ę ł ń ś ź ż) in uk/cs/en - Cyrillic in pl/cs/en - Strict Latin diacritics in uk Findings: - pl/uk/cs/en dicts: clean. PL chars in non-pl strings are all protected proper nouns (zł, BLIK, Sklepik, Mała elektrownia, Sąsiad, Konto dla Młodych, Bezpieczny Kredyt, huta szkła) — flagged as intentional per the existing "PL termíny chráněny" spec line in cs/uk/en pipeline notes. - 1 real leak fixed: `app/dla-szkol/materialy/page.tsx:219` "Plně auditovateľné" → "Plně auditovatelné" (the curly L `ľ` is Slovak-only; Czech uses `l`). - 1 hardcoded PL surface upgraded: `app/verify/page.tsx` (G-14 expired-token explainer) shipped as PL-only on first cut. Now per-locale COPY × 4 langs (pl/uk/cs/en) so a teacher who receives the verify email under any locale lands on a readable error page when their token expires. - `/rodzic/*` pages remain hardcoded PL by design — `/parent/*` is the multi-lang counterpart (separate audience-routed surfaces). Documented as Pass-11 audit candidate. G-33 — `/games` CityScene sunset backdrop (user-reported drift). After PR-P G-27 added `backdrop="sunset"` to the compact CityScene previews (homepage + dashboard), the FULL-size hero on /games hub still rendered the legacy night palette — so visiting the hub felt like jumping to a different product. Set `backdrop="sunset"` on the /games CityScene call to match the rest of the app. Validation: - pnpm typecheck → 0 errors Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent cdf5843 commit 91bf026

3 files changed

Lines changed: 48 additions & 10 deletions

File tree

app/dla-szkol/materialy/page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ const COPY = {
216216
"UODO: polský dozorový orgán.",
217217
"KNF disclaimery na každé stránce s úvěrem.",
218218
"EU hosting: Upstash Frankfurt + Vercel EU.",
219-
"Plně auditovateľné: ledger každé transakce.",
219+
"Plně auditovatelné: ledger každé transakce.",
220220
],
221221
ctaTitle: "Kontakt",
222222
ctaBody:

app/games/page.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,15 @@ export default async function GamesHubPage() {
9898
})}
9999
</p>
100100
</header>
101-
<CityScene games={cityGames} loggedIn={Boolean(session)} aiGames={cityAiGames} />
101+
{/* G-33 — same sunset backdrop as homepage + dashboard for visual
102+
consistency. PR-P G-27 already added the prop on the compact
103+
previews; the full /games hero needed it explicitly too. */}
104+
<CityScene
105+
games={cityGames}
106+
loggedIn={Boolean(session)}
107+
aiGames={cityAiGames}
108+
backdrop="sunset"
109+
/>
102110
<aside className="card p-5 flex flex-col gap-3 text-sm text-[var(--ink-muted)]">
103111
<h2 className="section-heading text-lg">{t.buildingsMap}</h2>
104112
<ul className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-x-5 gap-y-1.5">

app/verify/page.tsx

Lines changed: 38 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
consumeTeacherVerification,
55
} from "@/lib/teacher-verify";
66
import { markTeacherVerified } from "@/lib/class";
7+
import { getLang } from "@/lib/i18n-server";
78

89
/* G-14 — teacher email verification landing.
910
*
@@ -16,12 +17,43 @@ import { markTeacherVerified } from "@/lib/class";
1617
* - missing token → 308 to /login (link probably mistyped)
1718
* - expired/redeemed token → render an explainer with a "request
1819
* new link" CTA pointing back at signup
20+
*
21+
* G-31 — locale-aware error explainer (was hardcoded PL on first
22+
* ship). Token consume + redirect path is locale-agnostic so it
23+
* doesn't need translation.
1924
*/
2025

2126
type SearchParams = {
2227
token?: string;
2328
};
2429

30+
const COPY = {
31+
pl: {
32+
title: "Link wygasł lub został już użyty",
33+
body: "Linki weryfikacyjne działają 24 godziny i tylko raz. Możesz poprosić o nowy z pulpitu nauczyciela albo zarejestrować się jeszcze raz.",
34+
dashboard: "Pulpit nauczyciela",
35+
signup: "Nowa rejestracja",
36+
},
37+
uk: {
38+
title: "Посилання застаріло або вже було використано",
39+
body: "Посилання для верифікації діють 24 години та лише один раз. Запроси нове з панелі вчителя або зареєструйся знову.",
40+
dashboard: "Панель вчителя",
41+
signup: "Нова реєстрація",
42+
},
43+
cs: {
44+
title: "Odkaz vypršel nebo už byl použit",
45+
body: "Verifikační odkazy fungují 24 hodin a pouze jednou. Vyžádej si nový z panelu učitele nebo se zaregistruj znovu.",
46+
dashboard: "Panel učitele",
47+
signup: "Nová registrace",
48+
},
49+
en: {
50+
title: "Link has expired or was already used",
51+
body: "Verification links work for 24 hours and a single use. Request a new one from the teacher dashboard or sign up again.",
52+
dashboard: "Teacher dashboard",
53+
signup: "New signup",
54+
},
55+
} as const;
56+
2557
export const dynamic = "force-dynamic";
2658

2759
export default async function VerifyPage({
@@ -35,23 +67,21 @@ export default async function VerifyPage({
3567
}
3668
const payload = await consumeTeacherVerification(sp.token);
3769
if (!payload) {
70+
const lang = await getLang();
71+
const t = COPY[lang];
3872
return (
3973
<main className="max-w-xl mx-auto py-12 flex flex-col items-center gap-4 text-center animate-slide-up">
4074
<span aria-hidden className="text-5xl">
4175
4276
</span>
43-
<h1 className="t-h2 text-[var(--accent)]">Link wygasł lub został już użyty</h1>
44-
<p className="text-[var(--ink-muted)] max-w-md">
45-
Linki weryfikacyjne działają 24 godziny i tylko raz. Możesz
46-
poprosić o nowy z pulpitu nauczyciela albo zarejestrować się
47-
jeszcze raz.
48-
</p>
77+
<h1 className="t-h2 text-[var(--accent)]">{t.title}</h1>
78+
<p className="text-[var(--ink-muted)] max-w-md">{t.body}</p>
4979
<div className="flex flex-wrap gap-3">
5080
<Link href="/nauczyciel" className="btn btn-primary">
51-
Pulpit nauczyciela
81+
{t.dashboard}
5282
</Link>
5383
<Link href="/nauczyciel/signup" className="btn btn-secondary">
54-
Nowa rejestracja
84+
{t.signup}
5585
</Link>
5686
</div>
5787
</main>

0 commit comments

Comments
 (0)