nerdware/apps/web/src/i18n/en.ts
AyoubBenziza 1e5ef2be90 feat(web): i18n (FR/EN) — homemade typed dictionary
- lightweight, dependency-free i18n: typed fr/en dictionaries (fr is the source
  of truth, en must match its shape → compile error on drift), I18nProvider +
  useI18n hook, browser detection + localStorage persistence
- FR/EN language switcher (home + room header)
- translated the whole player-facing flow: home, join, pseudo, room shell,
  lobby (incl. settings, categories, bots, track submission, history),
  quiz, blindtest, player-cards, round transitions, end screen (podium, awards,
  tracks, rounds recap), and server-error messages (mapped by code)
- history dates localized to the active language

Content (questions/categories) intentionally left as-is. Back-office (admin)
not translated yet — internal, token-gated tool.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-11 19:03:28 +02:00

180 lines
5.2 KiB
TypeScript

// Dictionnaire EN. Doit respecter la forme de `fr` (Dict) — sinon erreur TS.
import type { Dict } from "./context"
export const en: Dict = {
common: {
you: "(you)",
back: "Back to home",
backShort: "Back",
loading: "Loading…",
error: "Error",
},
home: {
tagline: "Geek culture party game",
create: "Create a room",
orJoin: "or join",
codePlaceholder: "CODE",
join: "Join",
connecting: "Connecting to server…",
},
pseudo: {
room: (code: string) => `Room ${code}`,
choose: "Choose your nickname",
placeholder: "Your nickname",
enter: "Enter the room",
},
joinPage: {
connecting: (code: string) => `Joining room ${code}`,
notFound: "Room not found.",
},
room: {
notFound: "Room not found or session lost.",
connected: "Connected",
disconnected: "Disconnected",
leave: "Leave",
},
roomCode: {
label: "Room code",
copyCode: "Copy code",
copyLink: "Copy invite link",
link: "Link",
copied: "Copied",
},
lobby: {
players: (n: number) => `Players (${n})`,
host: "Host",
bot: "🤖 Bot",
offline: "offline",
bots: "Bots",
settings: "Game settings",
gameMode: "Game mode",
blindtestLockHint: "3 players incl. 2 real ones (a bot can't DJ)",
blindtestUnlock:
"Blindtest unlocks at 3 players incl. 2 real ones (a bot can't DJ).",
subModes: "Included sub-modes",
quizCount: "Quiz questions",
imageCount: "Images to guess",
imageHint: "Requires “Image” questions created in the back-office.",
categories: "Categories",
allCategories: "All",
botLevel: "🤖 Bot difficulty",
blindtestMode: "Blindtest mode",
tracksPerPlayer: "Tracks per player",
launch: (n: number) => `Start (${n} rounds)`,
launching: "Starting…",
waitTracks: (n: number) =>
`Waiting for everyone to submit their ${n} track(s).`,
waitHost: "Waiting for the host to start…",
tracksSubmitted: (n: number) => ` (${n} tracks submitted)`,
prevGames: (n: number) => `Previous games (${n})`,
myTracks: (count: number, max: number) => `Your tracks (${count}/${max})`,
youtubePlaceholder: "YouTube link",
add: "Add",
openYoutube: "Open on YouTube",
remove: "Remove",
rejected: "Rejected",
},
gameTypes: {
mixed: "Mixed",
quiz: "Quiz",
image: "Images",
blindtest: "Blindtest",
},
mixModes: {
quiz: "Quiz",
image: "Images",
blindtest: "Blindtest",
},
blindtestModes: {
title_artist: "Title & artist",
who_added: "Who added it?",
mixed: "Mixed",
},
botDifficulty: {
easy: "Easy",
normal: "Normal",
hard: "Hard",
},
game: {
question: (i: number, n: number) => `Question ${i} / ${n}`,
blindtest: (i: number, n: number) => `Blindtest ${i} / ${n}`,
answerSent: "Answer sent — waiting for the others",
answeredCount: (count: number, total: number) => `${count}/${total} answered`,
answer: "Answer:",
correct: "Correct! 🎉",
noAnswer: "No answer 😴",
wrong: "Wrong 💥",
yourAnswer: "Your answer",
validate: "Submit",
},
blindtest: {
djHint: "You're the DJ 🎧 — control playback (and vote like everyone)",
play: "Play",
pause: "Pause",
restart: "Start",
yourTrack: "It's your track!",
yourTrackTitleArtist: "You don't vote. Enjoy while the others search.",
yourTrackWhoAdded:
"You don't vote — your goal: nobody guesses you added it. +50 per fooled player.",
titlePlaceholder: "Title",
artistPlaceholder: "Artist",
whoAdded: "Who added it?",
vote: "Vote",
pickPlayer: "Pick a player",
revealTitle: "Title",
revealArtist: "Artist",
revealAddedBy: "Added by",
points: (n: number) => `+${n} points 🎉`,
submit: "Submit my answer",
},
playerCards: {
ready: "Ready",
waiting: "waiting",
},
transition: {
kind: {
quiz: "Question",
image: "Image",
blindtest: "Track",
},
ready: "READY ?!",
},
end: {
over: "Game over",
winner: (name: string) => `🏆 ${name} wins!`,
copy: "Copy results",
copied: "Copied!",
replay: "Play again",
waitHostReplay: "Waiting for the host to start a new game…",
leave: "Leave",
resultsTitle: "NerdWare — Results",
ranking: "🏆 Ranking",
rounds: "Rounds",
tracksTitle: "Tracks from the game",
playlist: "Playlist",
addedBy: (name: string) => `added by ${name}`,
searchSpotify: "Search on Spotify",
openYoutube: "Open on YouTube",
awards: "Awards",
awardPerfect: "Flawless",
awardBrain: "The brain",
awardFastest: "The fastest",
awardDecoy: "Master of deception",
awardBoulet: "The dud",
recapTitle: (n: number) => `Rounds recap (${n})`,
noAnswer: "No answer",
you: " (you)",
},
errors: {
ROOM_NOT_FOUND: "This room doesn't exist.",
ROOM_IN_PROGRESS: "The game has already started.",
ALREADY_STARTED: "Game already started.",
NO_ROUNDS: "No round configured.",
NEED_THREE: "Blindtest needs at least 3 players incl. 2 real ones.",
TRACKS_PENDING: "Not all players have submitted their tracks yet.",
CODE_EXHAUSTED: "Couldn't generate a room code.",
REJOIN_FAILED: "Reconnection failed.",
UNKNOWN_MODE: "Round unavailable.",
},
}