Skip to content

Commit

Permalink
Add a localization file
Browse files Browse the repository at this point in the history
  • Loading branch information
instantfred committed Aug 20, 2024
1 parent 8ed14f4 commit 03e0297
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 125 deletions.
158 changes: 54 additions & 104 deletions src/SounddittoGame.js
Original file line number Diff line number Diff line change
@@ -1,34 +1,37 @@
import React, { useState, useEffect } from "react";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardHeader } from "@/components/ui/card";
import { Switch } from "@/components/ui/switch";
import { Info } from "lucide-react";
import englishWords from "./lib/englishWords";
import spanishWords from "./lib/spanishWords";
import Footer from "./components/ui/Footer";
import InstructionsModal from "./components/modals/InstructionsModal";
import React, { useState, useEffect } from 'react';
import { Button } from "@/components/ui/button"
import { Card, CardContent, CardHeader } from "@/components/ui/card"
import { Switch } from "@/components/ui/switch"
import { Info } from "lucide-react"
import englishWords from './lib/englishWords';
import spanishWords from './lib/spanishWords';
import localization from './lib/localization';
import Footer from './components/ui/Footer';
import InstructionsModal from './components/modals/InstructionsModal';

const GAME_DURATION = 60; // Game duration in seconds
const SKIP_PENALTY = 5; // Time penalty for skipping in seconds

const SounddittoGame = () => {
const [gameState, setGameState] = useState("waiting");
const [currentWords, setCurrentWords] = useState({ easy: "", hard: "" });
const [gameState, setGameState] = useState('waiting');
const [currentWords, setCurrentWords] = useState({ easy: '', hard: '' });
const [score, setScore] = useState(0);
const [timeLeft, setTimeLeft] = useState(GAME_DURATION);
const [language, setLanguage] = useState("english");
const [language, setLanguage] = useState('en');
const [availableWords, setAvailableWords] = useState([]);
const [isInstructionsOpen, setIsInstructionsOpen] = useState(false);
const [isTimerEnabled, setIsTimerEnabled] = useState(true);

const t = (key) => localization[language][key];

useEffect(() => {
let timer;
if (gameState === "playing" && isTimerEnabled) {
if (gameState === 'playing' && isTimerEnabled) {
timer = setInterval(() => {
setTimeLeft((prevTime) => {
if (prevTime <= 1) {
clearInterval(timer);
setGameState("finished");
setGameState('finished');
return 0;
}
return prevTime - 1;
Expand All @@ -39,10 +42,9 @@ const SounddittoGame = () => {
}, [gameState, isTimerEnabled]);

const startGame = () => {
const words =
language === "english" ? [...englishWords] : [...spanishWords];
const words = language === 'en' ? [...englishWords] : [...spanishWords];
setAvailableWords(words);
setGameState("playing");
setGameState('playing');
setScore(0);
if (isTimerEnabled) {
setTimeLeft(GAME_DURATION);
Expand All @@ -51,12 +53,12 @@ const SounddittoGame = () => {
};

const endGame = () => {
setGameState("finished");
setGameState('finished');
};

const nextWord = (words = availableWords) => {
if (words.length <= 1) {
setGameState("finished");
setGameState('finished');
return;
}
const randomIndex = Math.floor(Math.random() * words.length);
Expand All @@ -72,48 +74,38 @@ const SounddittoGame = () => {
};

const handleGotIt = (difficulty) => {
setScore((prevScore) => prevScore + (difficulty === "easy" ? 1 : 2));
setScore((prevScore) => prevScore + (difficulty === 'easy' ? 1 : 2));
nextWord();
};

const toggleLanguage = () => {
setLanguage((prevLang) => (prevLang === "english" ? "spanish" : "english"));
setLanguage(prevLang => prevLang === 'en' ? 'es' : 'en');
};

const toggleTimer = () => {
setIsTimerEnabled((prevState) => !prevState);
setIsTimerEnabled(prevState => !prevState);
};

const renderLanguageToggle = () => (
<div className="flex items-center justify-center mt-4 space-x-2">
<span
className={`font-semibold ${language === "english" ? "text-pink-500" : "text-gray-400"}`}
>
EN
</span>
<span className={`font-semibold ${language === 'en' ? 'text-pink-500' : 'text-gray-400'}`}>EN</span>
<Switch
checked={language === "spanish"}
checked={language === 'es'}
onCheckedChange={toggleLanguage}
disabled={gameState !== "waiting"}
disabled={gameState !== 'waiting'}
className="bg-white border-2 border-gray-300 data-[state=checked]:bg-white data-[state=unchecked]:bg-white"
/>
<span
className={`font-semibold ${language === "spanish" ? "text-yellow-500" : "text-gray-400"}`}
>
ES
</span>
<span className={`font-semibold ${language === 'es' ? 'text-yellow-500' : 'text-gray-400'}`}>ES</span>
</div>
);

const renderTimerToggle = () => (
<div className="flex items-center justify-center mt-4 space-x-2">
<span className="font-semibold text-gray-600">
{language === "english" ? "Timer" : "Temporizador"}
</span>
<span className="font-semibold text-gray-600">{t('timer')}</span>
<Switch
checked={isTimerEnabled}
onCheckedChange={toggleTimer}
disabled={gameState !== "waiting"}
disabled={gameState !== 'waiting'}
className="bg-white border-2 border-gray-300 data-[state=checked]:bg-white data-[state=unchecked]:bg-white"
/>
</div>
Expand All @@ -139,121 +131,79 @@ const SounddittoGame = () => {
<Info className="h-6 w-6" />
</Button>
</div>
{gameState === "waiting" && (
{gameState === 'waiting' && (
<>
{renderLanguageToggle()}
{renderTimerToggle()}
</>
)}
</CardHeader>
<CardContent className="p-6">
{gameState === "waiting" && (
<Button
onClick={startGame}
className="w-full bg-gradient-to-r from-green-400 to-blue-500 hover:from-green-500 hover:to-blue-600 text-white font-bold py-3 rounded-full shadow-lg hover:scale-105 transition-all duration-300 animate-pulse"
>
{language === "english" ? "Start Game" : "Iniciar Juego"}
{gameState === 'waiting' && (
<Button onClick={startGame} className="w-full bg-gradient-to-r from-green-400 to-blue-500 hover:from-green-500 hover:to-blue-600 text-white font-bold py-3 rounded-full shadow-lg hover:scale-105 transition-all duration-300 animate-pulse">
{t('startGame')}
</Button>
)}
{gameState === "playing" && (
{gameState === 'playing' && (
<div className="space-y-6">
<div className="text-center">
<p className="text-xl font-semibold text-gray-600">
{language === "english"
? "Choose a word:"
: "Elige una palabra:"}
{t('chooseWord')}
</p>
<div className="flex justify-between mt-4 space-x-4">
<Button
onClick={() => handleGotIt("easy")}
className="flex-1 bg-green-500 hover:bg-green-600 text-white font-bold py-6 rounded-full shadow-lg hover:scale-105 transition-all duration-300"
>
<Button onClick={() => handleGotIt('easy')} className="flex-1 bg-green-500 hover:bg-green-600 text-white font-bold py-6 rounded-full shadow-lg hover:scale-105 transition-all duration-300">
<span className="block">
<span className="text-xs">
{language === "english"
? "Easy (1pt)"
: "Fácil (1pt)"}
</span>
<span className="block text-lg font-bold">
{currentWords.easy}
</span>
<span className="text-xs">{t('easy')} (1pt)</span>
<span className="block text-lg font-bold">{currentWords.easy}</span>
</span>
</Button>
<Button
onClick={() => handleGotIt("hard")}
className="flex-1 bg-yellow-500 hover:bg-yellow-600 text-white font-bold py-6 rounded-full shadow-lg hover:scale-105 transition-all duration-300"
>
<Button onClick={() => handleGotIt('hard')} className="flex-1 bg-yellow-500 hover:bg-yellow-600 text-white font-bold py-6 rounded-full shadow-lg hover:scale-105 transition-all duration-300">
<span className="block">
<span className="text-xs">
{language === "english"
? "Hard (2pts)"
: "Difícil (2pts)"}
</span>
<span className="block text-lg font-bold">
{currentWords.hard}
</span>
<span className="text-xs">{t('hard')} (2pts)</span>
<span className="block text-lg font-bold">{currentWords.hard}</span>
</span>
</Button>
</div>
</div>
<Button
onClick={handleSkip}
className="w-full bg-red-500 hover:bg-red-600 text-white font-bold py-3 rounded-full shadow-lg hover:scale-105 transition-all duration-300"
>
{language === "english" ? "Skip" : "Saltar"}
<Button onClick={handleSkip} className="w-full bg-red-500 hover:bg-red-600 text-white font-bold py-3 rounded-full shadow-lg hover:scale-105 transition-all duration-300">
{t('skip')}
</Button>
<div className="flex justify-between items-center bg-gray-100 p-4 rounded-lg">
<p className="text-lg font-semibold text-indigo-600">
{language === "english" ? "Score:" : "Puntos:"}
<span className="ml-2 text-2xl">{score}</span>
{t('score')} <span className="ml-2 text-2xl">{score}</span>
</p>
{isTimerEnabled ? (
<p className="text-lg font-semibold text-pink-600">
{language === "english" ? "Time:" : "Tiempo:"}
<span className="ml-2 text-2xl">{timeLeft}s</span>
{t('time')} <span className="ml-2 text-2xl">{timeLeft}s</span>
</p>
) : (
<Button
onClick={endGame}
className="bg-blue-500 hover:bg-blue-600 text-white font-bold py-2 px-4 rounded-full shadow-lg hover:scale-105 transition-all duration-300"
>
{language === "english" ? "End Game" : "Terminar Juego"}
<Button onClick={endGame} className="bg-blue-500 hover:bg-blue-600 text-white font-bold py-2 px-4 rounded-full shadow-lg hover:scale-105 transition-all duration-300">
{t('endGame')}
</Button>
)}
</div>
</div>
)}
{gameState === "finished" && (
{gameState === 'finished' && (
<div className="text-center space-y-6">
<p className="text-2xl font-bold text-indigo-600">
{language === "english" ? "Game Over!" : "¡Juego Terminado!"}
{t('gameOver')}
</p>
<p className="text-4xl font-extrabold bg-gradient-to-r from-purple-500 to-pink-500 bg-clip-text text-transparent">
{language === "english"
? "Final Score:"
: "Puntuación Final:"}{" "}
{score}
{t('finalScore')} {score}
</p>
<Button
onClick={startGame}
className="w-full bg-gradient-to-r from-green-400 to-blue-500 hover:from-green-500 hover:to-blue-600 text-white font-bold py-3 rounded-full shadow-lg hover:scale-105 transition-all duration-300"
>
{language === "english" ? "Play Again" : "Jugar de Nuevo"}
<Button onClick={startGame} className="w-full bg-gradient-to-r from-green-400 to-blue-500 hover:from-green-500 hover:to-blue-600 text-white font-bold py-3 rounded-full shadow-lg hover:scale-105 transition-all duration-300">
{t('playAgain')}
</Button>
</div>
)}
</CardContent>
</Card>
</div>
<Footer />
<InstructionsModal
isOpen={isInstructionsOpen}
onClose={closeInstructions}
language={language}
/>
<InstructionsModal isOpen={isInstructionsOpen} onClose={closeInstructions} language={language} />
</div>
);
};

export default SounddittoGame;

44 changes: 23 additions & 21 deletions src/components/modals/InstructionsModal.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,29 @@ import React from 'react';
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription } from "@/components/ui/dialog"
import { Button } from "@/components/ui/button"

const instructions = {
en: [
"Choose a word from either the 'Easy' or 'Hard' category.",
"Make the sound of the chosen word without using actual words.",
"Your team must guess the word based on your sound.",
"Score 1 point for easy words, 2 points for hard words.",
"Skip difficult words, but beware of the time penalty!",
"Race against the clock or play until you've gone through all words.",
"Have fun and get creative with your sounds!"
],
es: [
"Elige una palabra de la categoría 'Fácil' o 'Difícil'.",
"Haz el sonido de la palabra elegida sin usar palabras reales.",
"Tu equipo debe adivinar la palabra basándose en tu sonido.",
"Gana 1 punto por palabras fáciles, 2 puntos por palabras difíciles.",
"Salta las palabras difíciles, ¡pero cuidado con la penalización de tiempo!",
"Compite contra el reloj o juega hasta que hayas pasado por todas las palabras.",
"¡Diviértete y sé creativo con tus sonidos!"
]
};

const InstructionsModal = ({ isOpen, onClose, language }) => {
const instructions = {
english: [
"Choose between an easy (1 point) or hard (2 points) word.",
"Make the sound of the chosen word without using words or gestures.",
"Sitting on your hands is recommended to avoid gestures.",
"Your teammates guess the word.",
"Click on the word if they guess correctly, or 'Skip' to move to the next word.",
"Skipping penalizes you 5 seconds.",
"Score as many points as possible in 60 seconds!"
],
spanish: [
"Elige entre una palabra fácil (1 punto) o difícil (2 puntos).",
"Haz el sonido de la palabra elegida, sin usar palabras o señas.",
"Se recomienda sentarse sobre las manos para evitar señas.",
"Tus compañeros de equipo adivinan la palabra.",
"Haz clic en la palabra si adivinan correctamente, o 'Saltar' para pasar a la siguiente palabra.",
"Saltar te penaliza con 5 segundos.",
"¡Consigue tantos puntos como sea posible en 60 segundos!"
]
};
const currentInstructions = instructions[language] || instructions.en;

return (
<Dialog open={isOpen} onOpenChange={onClose}>
Expand All @@ -34,7 +36,7 @@ const InstructionsModal = ({ isOpen, onClose, language }) => {
</DialogHeader>
<DialogDescription>
<ul className="list-disc pl-5 space-y-2 text-gray-700">
{instructions[language].map((instruction, index) => (
{currentInstructions.map((instruction, index) => (
<li key={index}>{instruction}</li>
))}
</ul>
Expand Down
32 changes: 32 additions & 0 deletions src/lib/localization.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
const localization = {
en: {
startGame: "Start Game",
chooseWord: "Choose a word:",
easy: "Easy",
hard: "Hard",
skip: "Skip",
score: "Score:",
time: "Time:",
endGame: "End Game",
gameOver: "Game Over!",
finalScore: "Final Score:",
playAgain: "Play Again",
timer: "Timer",
},
es: {
startGame: "Iniciar Juego",
chooseWord: "Elige una palabra:",
easy: "Fácil",
hard: "Difícil",
skip: "Saltar",
score: "Puntos:",
time: "Tiempo:",
endGame: "Finalizar Juego",
gameOver: "¡Juego Terminado!",
finalScore: "Puntuación Final:",
playAgain: "Jugar de Nuevo",
timer: "Temporizador",
}
};

export default localization;

0 comments on commit 03e0297

Please sign in to comment.