From e004dfedaf88cee1f9fa515b316c5224e4ce0877 Mon Sep 17 00:00:00 2001 From: simoleo89 Date: Sun, 28 Jun 2026 20:40:06 +0200 Subject: [PATCH] i18n: translate all public page bodies (EN + IT) Internationalised the ~44 public pages with next-intl (the shell was already translated). Each page now pulls its copy from a "pages." namespace via getTranslations (server) / useTranslations (client); the EN + IT catalogs were authored by parallel agents and merged centrally, with natural Italian (ICU plurals) and it backfilled from en for any gap. request.ts gained getMessageFallback/onError so a missing key degrades to the English value, never a raw key. Behaviour unchanged (only display text moved to t() calls; queries, actions, fields, ContentCard structure preserved). Verified on the prod server: with NEXT_LOCALE=it, home/community/staff/news/shop/rankings all render Italian copy, no raw-key leakage; English unchanged. The nav language switcher toggles EN/IT live. tsc 0, vitest 49/49, next build 0. Admin pages intentionally left in English (staff tooling). --- src/app/apply/staff/page.tsx | 34 +- src/app/apply/team/page.tsx | 22 +- src/app/badges/page.tsx | 9 +- src/app/banned/page.tsx | 16 +- src/app/community/page.tsx | 31 +- src/app/forgot/page.tsx | 14 +- src/app/friends/page.tsx | 12 +- src/app/guilds/[id]/forum/new/page.tsx | 20 +- src/app/guilds/[id]/forum/page.tsx | 42 +- src/app/guilds/[id]/page.tsx | 26 +- src/app/guilds/page.tsx | 12 +- src/app/help/[category]/page.tsx | 10 +- src/app/help/page.tsx | 23 +- src/app/help/tickets/page.tsx | 49 ++- src/app/leaderboard/page.tsx | 24 +- src/app/login/page.tsx | 32 +- src/app/maintenance/page.tsx | 8 +- src/app/marketplace/page.tsx | 46 +- src/app/messages/page.tsx | 30 +- src/app/news/[slug]/page.tsx | 41 +- src/app/news/page.tsx | 9 +- src/app/page.tsx | 20 +- src/app/photos/page.tsx | 13 +- src/app/radio/apply/page.tsx | 41 +- src/app/radio/contests/page.tsx | 13 +- src/app/radio/giveaways/page.tsx | 13 +- src/app/radio/leaderboard/page.tsx | 17 +- src/app/radio/page.tsx | 57 +-- src/app/radio/schedule/page.tsx | 19 +- src/app/radio/shouts/page.tsx | 23 +- src/app/rankings/page.tsx | 6 +- src/app/rares/[category]/page.tsx | 28 +- src/app/rares/page.tsx | 12 +- src/app/redeem/page.tsx | 20 +- src/app/register/page.tsx | 16 +- src/app/reset/page.tsx | 12 +- src/app/settings/2fa/page.tsx | 36 +- src/app/settings/connections/page.tsx | 28 +- src/app/settings/page.tsx | 30 +- src/app/shop/page.tsx | 18 +- src/app/shop/topup/page.tsx | 37 +- src/app/staff/page.tsx | 20 +- src/app/u/[username]/page.tsx | 32 +- src/app/verify/page.tsx | 25 +- src/i18n/request.ts | 23 +- src/messages/en.json | 571 +++++++++++++++++++++++++ src/messages/it.json | 571 +++++++++++++++++++++++++ 47 files changed, 1740 insertions(+), 471 deletions(-) diff --git a/src/app/apply/staff/page.tsx b/src/app/apply/staff/page.tsx index f1efe8f6..045bc884 100644 --- a/src/app/apply/staff/page.tsx +++ b/src/app/apply/staff/page.tsx @@ -1,3 +1,4 @@ +import { getTranslations } from "next-intl/server"; import { redirect } from "next/navigation"; import { applyStaff } from "@/actions/applications"; import { ContentCard, EmptyState } from "@/components/public/ui"; @@ -10,18 +11,20 @@ export const dynamic = "force-dynamic"; // Canonical Habbo badge image CDN (same base used by the profile page). const BADGE_IMG_BASE = "https://images.habbo.com/c_images/album1584"; -function formatDeadline(d: Date | null | undefined): string { - if (!d) return "No deadline set"; - return d.toISOString().slice(0, 16).replace("T", " "); -} - export default async function ApplyStaffPage() { const session = await auth(); if (!session?.user?.id) redirect("/login"); + const t = await getTranslations("pages.applyStaff"); + const userId = Number(session.user.id); const hotelName = (await siteSettings.get("hotel_name", "Atom")) ?? "Atom"; + function formatDeadline(d: Date | null | undefined): string { + if (!d) return t("noDeadline"); + return d.toISOString().slice(0, 16).replace("T", " "); + } + // ── Open positions ────────────────────────────────────────── // Each query is isolated so a DB hiccup degrades that section to empty // rather than 500-ing the whole page. @@ -52,16 +55,13 @@ export default async function ApplyStaffPage() {
{positions.length === 0 ? ( - - - There are currently no positions open. Please come back at a later time to check if we - have any openings by then. Thank you for your interest. - + + {t("noPositionsBody")} ) : (
@@ -98,7 +98,7 @@ export default async function ApplyStaffPage() {

{position.description}

- Application deadline: {formatDeadline(position.applyTo)} + {t("deadline", { date: formatDeadline(position.applyTo) })}

{alreadyApplied ? ( @@ -108,7 +108,7 @@ export default async function ApplyStaffPage() { disabled style={{ width: "100%" }} > - You have already applied for {rankName} + {t("alreadyApplied", { rank: rankName })} ) : (
@@ -116,7 +116,7 @@ export default async function ApplyStaffPage() { re-read from the session inside the action. */}