diff --git a/src/app/learning/openings/[openingId]/page.tsx b/src/app/learning/openings/[openingId]/page.tsx index d8a37b8..f699c7f 100644 --- a/src/app/learning/openings/[openingId]/page.tsx +++ b/src/app/learning/openings/[openingId]/page.tsx @@ -78,7 +78,7 @@ export default function OpeningTrainingPage() {
-

Loading opening training session...

+

{t.learning.openingTrainer.loadingSession}

@@ -95,16 +95,16 @@ export default function OpeningTrainingPage() {

- Opening Not Found + {t.learning.openingTrainer.openingNotFound}

- The requested opening could not be found. + {t.learning.openingTrainer.openingNotFoundDescription}

@@ -125,7 +125,7 @@ export default function OpeningTrainingPage() { className="p-2 md:px-4 md:py-2 bg-gray-200 dark:bg-gray-700 rounded-lg hover:bg-gray-300 dark:hover:bg-gray-600 text-sm font-medium transition-colors flex items-center gap-2" > - Back to Opening Selection + {t.learning.openingTrainer.backToOpeningSelection} diff --git a/src/components/Header.tsx b/src/components/Header.tsx index 70e04d1..dd18d65 100644 --- a/src/components/Header.tsx +++ b/src/components/Header.tsx @@ -1,4 +1,5 @@ import React from 'react'; +import Link from 'next/link'; import { useTranslation } from '@/lib/i18n/useTranslation'; import { SupportedLanguage } from '@/lib/i18n/translations'; @@ -14,7 +15,7 @@ export default function Header({ language }: HeaderProps) {
{/* App Title/Branding */} -
+

Chess Tutor @@ -22,7 +23,7 @@ export default function Header({ language }: HeaderProps) { {t.header.tagline} -

+ {/* Action Buttons */}
diff --git a/src/components/OpeningTrainer/DeviationDialog.tsx b/src/components/OpeningTrainer/DeviationDialog.tsx index 87ad588..93f32ba 100644 --- a/src/components/OpeningTrainer/DeviationDialog.tsx +++ b/src/components/OpeningTrainer/DeviationDialog.tsx @@ -1,11 +1,15 @@ 'use client'; +import { useTranslation } from '@/lib/i18n/useTranslation'; +import { SupportedLanguage } from '@/lib/i18n/translations'; + interface DeviationDialogProps { openingName: string; movesCompleted: number; onUndo: () => void; onStartGame: () => void; onContinueExploring?: () => void; + language: SupportedLanguage; } export default function DeviationDialog({ @@ -14,18 +18,20 @@ export default function DeviationDialog({ onUndo, onStartGame, onContinueExploring, + language, }: DeviationDialogProps) { + const t = useTranslation(language); return (
🤔

- You've Left the Opening! + {t.learning.openingTrainer.deviationTitle}

- You've studied {movesCompleted} move - {movesCompleted !== 1 ? 's' : ''} of the{' '} + {t.learning.openingTrainer.deviationMessage} {movesCompleted}{' '} + {movesCompleted !== 1 ? t.learning.openingTrainer.moves : t.learning.openingTrainer.move} of the{' '} {openingName}.

@@ -40,7 +46,7 @@ export default function DeviationDialog({ className="w-full px-6 py-3 bg-blue-600 text-white rounded-lg hover:bg-blue-700 font-medium transition-colors flex items-center justify-center gap-2" > ♟️ - Continue Playing (Start Game) + {t.learning.openingTrainer.continuePlayingButton} {/* Secondary action: Undo */} @@ -49,7 +55,7 @@ export default function DeviationDialog({ className="w-full px-6 py-3 bg-gray-200 dark:bg-gray-700 text-gray-700 dark:text-gray-300 rounded-lg hover:bg-gray-300 dark:hover:bg-gray-600 font-medium transition-colors flex items-center justify-center gap-2" > ↩️ - Undo & Return to Opening + {t.learning.openingTrainer.undoReturnButton} {/* Optional: Continue exploring */} @@ -59,13 +65,13 @@ export default function DeviationDialog({ className="w-full px-6 py-3 bg-gray-100 dark:bg-gray-800 text-gray-600 dark:text-gray-400 rounded-lg hover:bg-gray-200 dark:hover:bg-gray-700 font-medium transition-colors border border-gray-300 dark:border-gray-600 flex items-center justify-center gap-2" > 🔍 - Explore This Variation + {t.learning.openingTrainer.exploreVariationButton} )}

- Tip: You can always navigate back using the move history + {t.learning.openingTrainer.deviationTip}

diff --git a/src/components/OpeningTrainer/OpeningTrainer.tsx b/src/components/OpeningTrainer/OpeningTrainer.tsx index 7e063c5..38f3fd0 100644 --- a/src/components/OpeningTrainer/OpeningTrainer.tsx +++ b/src/components/OpeningTrainer/OpeningTrainer.tsx @@ -559,6 +559,7 @@ export default function OpeningTrainer({ opening, personality, apiKey, language {/* Session info */} @@ -589,6 +590,7 @@ export default function OpeningTrainer({ opening, personality, apiKey, language onUndo={handleUndoDeviation} onStartGame={handleStartGameFromPosition} onContinueExploring={handleContinueExploring} + language={language} /> )}
diff --git a/src/components/OpeningTrainer/WikipediaSummary.tsx b/src/components/OpeningTrainer/WikipediaSummary.tsx index 385443c..07751f9 100644 --- a/src/components/OpeningTrainer/WikipediaSummary.tsx +++ b/src/components/OpeningTrainer/WikipediaSummary.tsx @@ -3,16 +3,20 @@ import { useState, useEffect } from 'react'; import { WikipediaSummary as WikipediaSummaryType } from '@/types/openingTraining'; import { getWikipediaSummary } from '@/lib/openingTrainer/wikipediaService'; +import { useTranslation } from '@/lib/i18n/useTranslation'; +import { SupportedLanguage } from '@/lib/i18n/translations'; interface WikipediaSummaryProps { openingName: string; wikipediaSlug?: string; // Preferred: direct slug from database + language: SupportedLanguage; } -export default function WikipediaSummary({ openingName, wikipediaSlug }: WikipediaSummaryProps) { +export default function WikipediaSummary({ openingName, wikipediaSlug, language }: WikipediaSummaryProps) { const [summary, setSummary] = useState(null); const [isLoading, setIsLoading] = useState(true); const [error, setError] = useState(null); + const t = useTranslation(language); useEffect(() => { fetchSummary(); @@ -46,7 +50,7 @@ export default function WikipediaSummary({ openingName, wikipediaSlug }: Wikiped
-

Loading opening background...

+

{t.learning.openingTrainer.loadingBackground}

); @@ -56,7 +60,7 @@ export default function WikipediaSummary({ openingName, wikipediaSlug }: Wikiped return (

- No background information available for this opening. + {t.learning.openingTrainer.noBackgroundInfo}

); @@ -77,7 +81,7 @@ export default function WikipediaSummary({ openingName, wikipediaSlug }: Wikiped

{summary.extract}

- Source: Wikipedia (cached {new Date(summary.fetchedAt).toLocaleDateString()}) + {t.learning.openingTrainer.wikipediaSource} {new Date(summary.fetchedAt).toLocaleDateString()})

); diff --git a/src/lib/i18n/translations.ts b/src/lib/i18n/translations.ts index 8b1b759..ffb013e 100644 --- a/src/lib/i18n/translations.ts +++ b/src/lib/i18n/translations.ts @@ -215,6 +215,23 @@ export interface Translations { backToLearning: string; findTheMove: string; }; + openingTrainer: { + loadingSession: string; + openingNotFound: string; + openingNotFoundDescription: string; + backToOpeningSelection: string; + loadingBackground: string; + noBackgroundInfo: string; + wikipediaSource: string; + deviationTitle: string; + deviationMessage: string; + deviationTip: string; + continuePlayingButton: string; + undoReturnButton: string; + exploreVariationButton: string; + move: string; + moves: string; + }; }; } @@ -419,6 +436,23 @@ const en: Translations = { backToLearning: 'Back to Learning Area', findTheMove: 'Find the move that creates a', }, + openingTrainer: { + loadingSession: 'Loading opening training session...', + openingNotFound: 'Opening Not Found', + openingNotFoundDescription: 'The requested opening could not be found.', + backToOpeningSelection: 'Back to Opening Selection', + loadingBackground: 'Loading opening background...', + noBackgroundInfo: 'No background information available for this opening.', + wikipediaSource: 'Source: Wikipedia (cached', + deviationTitle: "You've Left the Opening!", + deviationMessage: "You've studied", + deviationTip: 'Tip: You can always navigate back using the move history', + continuePlayingButton: 'Continue Playing (Start Game)', + undoReturnButton: 'Undo & Return to Opening', + exploreVariationButton: 'Explore This Variation', + move: 'move', + moves: 'moves', + }, }, }; @@ -623,6 +657,23 @@ const de: Translations = { backToLearning: 'Zurück zum Lernbereich', findTheMove: 'Finde den Zug, der eine', }, + openingTrainer: { + loadingSession: 'Lade Eröffnungstraining...', + openingNotFound: 'Eröffnung nicht gefunden', + openingNotFoundDescription: 'Die angeforderte Eröffnung konnte nicht gefunden werden.', + backToOpeningSelection: 'Zurück zur Eröffnungsauswahl', + loadingBackground: 'Lade Eröffnungshintergrund...', + noBackgroundInfo: 'Keine Hintergrundinformationen für diese Eröffnung verfügbar.', + wikipediaSource: 'Quelle: Wikipedia (zwischengespeichert', + deviationTitle: 'Du hast die Eröffnung verlassen!', + deviationMessage: 'Du hast', + deviationTip: 'Tipp: Du kannst jederzeit über die Zughistorie zurücknavigieren', + continuePlayingButton: 'Weiterspielen (Spiel starten)', + undoReturnButton: 'Rückgängig & zur Eröffnung zurück', + exploreVariationButton: 'Diese Variante erkunden', + move: 'Zug', + moves: 'Züge', + }, }, }; @@ -827,6 +878,23 @@ const fr: Translations = { backToLearning: 'Retour à la zone d\'apprentissage', findTheMove: 'Trouvez le coup qui crée un', }, + openingTrainer: { + loadingSession: 'Chargement de la session d\'entraînement...', + openingNotFound: 'Ouverture non trouvée', + openingNotFoundDescription: 'L\'ouverture demandée n\'a pas pu être trouvée.', + backToOpeningSelection: 'Retour à la sélection d\'ouverture', + loadingBackground: 'Chargement des informations sur l\'ouverture...', + noBackgroundInfo: 'Aucune information disponible pour cette ouverture.', + wikipediaSource: 'Source : Wikipédia (en cache', + deviationTitle: 'Vous avez quitté l\'ouverture !', + deviationMessage: 'Vous avez étudié', + deviationTip: 'Astuce : Vous pouvez toujours revenir en arrière en utilisant l\'historique des coups', + continuePlayingButton: 'Continuer à jouer (Démarrer la partie)', + undoReturnButton: 'Annuler et retourner à l\'ouverture', + exploreVariationButton: 'Explorer cette variante', + move: 'coup', + moves: 'coups', + }, }, }; @@ -1031,6 +1099,23 @@ const it: Translations = { backToLearning: 'Torna all\'area di apprendimento', findTheMove: 'Trova la mossa che crea un', }, + openingTrainer: { + loadingSession: 'Caricamento sessione di allenamento...', + openingNotFound: 'Apertura non trovata', + openingNotFoundDescription: 'L\'apertura richiesta non è stata trovata.', + backToOpeningSelection: 'Torna alla selezione delle aperture', + loadingBackground: 'Caricamento informazioni sull\'apertura...', + noBackgroundInfo: 'Nessuna informazione disponibile per questa apertura.', + wikipediaSource: 'Fonte: Wikipedia (in cache', + deviationTitle: 'Hai lasciato l\'apertura!', + deviationMessage: 'Hai studiato', + deviationTip: 'Suggerimento: Puoi sempre tornare indietro usando la cronologia delle mosse', + continuePlayingButton: 'Continua a giocare (Inizia partita)', + undoReturnButton: 'Annulla e torna all\'apertura', + exploreVariationButton: 'Esplora questa variante', + move: 'mossa', + moves: 'mosse', + }, }, }; @@ -1235,6 +1320,23 @@ const pl: Translations = { backToLearning: 'Powrót do strefy nauki', findTheMove: 'Znajdź ruch, który tworzy', }, + openingTrainer: { + loadingSession: 'Ładowanie sesji treningowej...', + openingNotFound: 'Nie znaleziono otwarcia', + openingNotFoundDescription: 'Żądane otwarcie nie zostało znalezione.', + backToOpeningSelection: 'Powrót do wyboru otwarcia', + loadingBackground: 'Ładowanie informacji o otwarciu...', + noBackgroundInfo: 'Brak informacji o tym otwarciu.', + wikipediaSource: 'Źródło: Wikipedia (w pamięci podręcznej', + deviationTitle: 'Opuściłeś otwarcie!', + deviationMessage: 'Przestudiowałeś', + deviationTip: 'Wskazówka: Zawsze możesz wrócić używając historii ruchów', + continuePlayingButton: 'Kontynuuj grę (Rozpocznij partię)', + undoReturnButton: 'Cofnij i wróć do otwarcia', + exploreVariationButton: 'Zbadaj tę wariant', + move: 'ruch', + moves: 'ruchy', + }, }, };