diff --git a/studio-v2/app/learn/page.tsx b/studio-v2/app/learn/page.tsx index 6601a33..90e80b5 100644 --- a/studio-v2/app/learn/page.tsx +++ b/studio-v2/app/learn/page.tsx @@ -3,6 +3,7 @@ import React, { useState, useEffect } from 'react' import { useTheme } from '@/lib/ThemeContext' import { UnitCard } from '@/components/learn/UnitCard' +import { useNativeLanguage } from '@/lib/useNativeLanguage' interface LearningUnit { id: string @@ -16,12 +17,87 @@ interface LearningUnit { created_at: string } -function getApiBase() { - return '' // Same-origin proxy via /api/learning-units/... +// Parent guide translations +const guide: Record> = { + welcome: { + de: 'Willkommen bei den Lernmodulen!', + en: 'Welcome to the learning modules!', + tr: 'Ogrenme modullerine hos geldiniz!', + ar: '\u0645\u0631\u062d\u0628\u0627 \u0628\u0643 \u0641\u064a \u0648\u062d\u062f\u0627\u062a \u0627\u0644\u062a\u0639\u0644\u0645!', + uk: '\u041b\u0430\u0441\u043a\u0430\u0432\u043e \u043f\u0440\u043e\u0441\u0438\u043c\u043e \u0434\u043e \u043d\u0430\u0432\u0447\u0430\u043b\u044c\u043d\u0438\u0445 \u043c\u043e\u0434\u0443\u043b\u0456\u0432!', + ru: '\u0414\u043e\u0431\u0440\u043e \u043f\u043e\u0436\u0430\u043b\u043e\u0432\u0430\u0442\u044c \u0432 \u0443\u0447\u0435\u0431\u043d\u044b\u0435 \u043c\u043e\u0434\u0443\u043b\u0438!', + pl: 'Witamy w modulach do nauki!', + }, + what_is_this: { + de: 'Was ist das?', + en: 'What is this?', + tr: 'Bu nedir?', + ar: '\u0645\u0627 \u0647\u0630\u0627\u061f', + uk: '\u0429\u043e \u0446\u0435?', + ru: '\u0427\u0442\u043e \u044d\u0442\u043e?', + pl: 'Co to jest?', + }, + explanation: { + de: 'Der Lehrer Ihres Kindes hat Vokabeln zusammengestellt, die Ihr Kind lernen muss. Hier koennen Sie Ihrem Kind beim Ueben helfen — auch wenn Sie selbst kein Deutsch oder Englisch sprechen. Jedes Wort wird in Ihrer Sprache angezeigt.', + en: 'Your child\'s teacher has prepared vocabulary that your child needs to learn. Here you can help your child practice — even if you don\'t speak German or English. Every word is shown in your language.', + tr: 'Cocugunuzun ogretmeni, cocugunuzun ogrenmesi gereken kelimeleri hazirladi. Burada cocugunuzun pratik yapmasina yardimci olabilirsiniz — Almanca veya Ingilizce bilmeseniz bile. Her kelime sizin dilinizde gosterilir.', + ar: '\u0623\u0639\u062f \u0645\u0639\u0644\u0645 \u0637\u0641\u0644\u0643 \u0645\u0641\u0631\u062f\u0627\u062a \u064a\u062d\u062a\u0627\u062c \u0637\u0641\u0644\u0643 \u0644\u062a\u0639\u0644\u0645\u0647\u0627. \u0647\u0646\u0627 \u064a\u0645\u0643\u0646\u0643 \u0645\u0633\u0627\u0639\u062f\u0629 \u0637\u0641\u0644\u0643 \u0639\u0644\u0649 \u0627\u0644\u062a\u062f\u0631\u064a\u0628 \u2014 \u062d\u062a\u0649 \u0644\u043e \u0644\u0645 \u062a\u062a\u062d\u062f\u062b \u0627\u0644\u0623\u0644\u0645\u0627\u0646\u064a\u0629 \u0623\u043e \u0627\u0644\u0625\u0646\u062c\u0644\u064a\u0632\u064a\u0629. \u0643\u0644 \u0643\u0644\u0645\u0629 \u062a\u0638\u0647\u0631 \u0628\u0644\u063a\u062a\u0643.', + uk: '\u0412\u0447\u0438\u0442\u0435\u043b\u044c \u0432\u0430\u0448\u043e\u0457 \u0434\u0438\u0442\u0438\u043d\u0438 \u043f\u0456\u0434\u0433\u043e\u0442\u0443\u0432\u0430\u0432 \u0441\u043b\u043e\u0432\u0430, \u044f\u043a\u0456 \u0434\u0438\u0442\u0438\u043d\u0430 \u043f\u043e\u0432\u0438\u043d\u043d\u0430 \u0432\u0438\u0432\u0447\u0438\u0442\u0438. \u0422\u0443\u0442 \u0432\u0438 \u043c\u043e\u0436\u0435\u0442\u0435 \u0434\u043e\u043f\u043e\u043c\u043e\u0433\u0442\u0438 \u0434\u0438\u0442\u0438\u043d\u0456 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0443\u0432\u0430\u0442\u0438 \u2014 \u043d\u0430\u0432\u0456\u0442\u044c \u044f\u043a\u0449\u043e \u0432\u0438 \u043d\u0435 \u0440\u043e\u0437\u043c\u043e\u0432\u043b\u044f\u0454\u0442\u0435 \u043d\u0456\u043c\u0435\u0446\u044c\u043a\u043e\u044e \u0447\u0438 \u0430\u043d\u0433\u043b\u0456\u0439\u0441\u044c\u043a\u043e\u044e. \u041a\u043e\u0436\u043d\u0435 \u0441\u043b\u043e\u0432\u043e \u043f\u043e\u043a\u0430\u0437\u0430\u043d\u043e \u0432\u0430\u0448\u043e\u044e \u043c\u043e\u0432\u043e\u044e.', + ru: '\u0423\u0447\u0438\u0442\u0435\u043b\u044c \u0432\u0430\u0448\u0435\u0433\u043e \u0440\u0435\u0431\u0435\u043d\u043a\u0430 \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u0438\u043b \u0441\u043b\u043e\u0432\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0440\u0435\u0431\u0435\u043d\u043e\u043a \u0434\u043e\u043b\u0436\u0435\u043d \u0432\u044b\u0443\u0447\u0438\u0442\u044c. \u0417\u0434\u0435\u0441\u044c \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043f\u043e\u043c\u043e\u0447\u044c \u0440\u0435\u0431\u0435\u043d\u043a\u0443 \u0442\u0440\u0435\u043d\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u2014 \u0434\u0430\u0436\u0435 \u0435\u0441\u043b\u0438 \u0432\u044b \u043d\u0435 \u0433\u043e\u0432\u043e\u0440\u0438\u0442\u0435 \u043f\u043e-\u043d\u0435\u043c\u0435\u0446\u043a\u0438 \u0438\u043b\u0438 \u043f\u043e-\u0430\u043d\u0433\u043b\u0438\u0439\u0441\u043a\u0438. \u041a\u0430\u0436\u0434\u043e\u0435 \u0441\u043b\u043e\u0432\u043e \u043f\u043e\u043a\u0430\u0437\u0430\u043d\u043e \u043d\u0430 \u0432\u0430\u0448\u0435\u043c \u044f\u0437\u044b\u043a\u0435.', + pl: 'Nauczyciel Twojego dziecka przygotowal slowka, ktorych dziecko musi sie nauczyc. Tutaj mozesz pomoc dziecku cwczyc — nawet jesli nie mowisz po niemiecku ani angielsku. Kazde slowo jest pokazane w Twoim jezyku.', + }, + exercises_explained: { + de: 'Waehlen Sie eine Uebung:', + en: 'Choose an exercise:', + tr: 'Bir alistirma secin:', + ar: '\u0627\u062e\u062a\u0631 \u062a\u0645\u0631\u064a\u0646\u0627:', + uk: '\u0412\u0438\u0431\u0435\u0440\u0456\u0442\u044c \u0432\u043f\u0440\u0430\u0432\u0443:', + ru: '\u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u0443\u043f\u0440\u0430\u0436\u043d\u0435\u043d\u0438\u0435:', + pl: 'Wybierz cwiczenie:', + }, + exercise_cards: { + de: 'Karteikarten — Wort umdrehen und pruefen', + tr: 'Kartlar — Kelimeyi cevir ve kontrol et', + ar: '\u0628\u0637\u0627\u0642\u0627\u062a \u2014 \u0627\u0642\u0644\u0628 \u0627\u0644\u0643\u0644\u0645\u0629 \u0648\u062a\u062d\u0642\u0642', + uk: '\u041a\u0430\u0440\u0442\u043a\u0438 \u2014 \u041f\u0435\u0440\u0435\u0432\u0435\u0440\u043d\u0456\u0442\u044c \u0441\u043b\u043e\u0432\u043e \u0456 \u043f\u0435\u0440\u0435\u0432\u0456\u0440\u0442\u0435', + ru: '\u041a\u0430\u0440\u0442\u043e\u0447\u043a\u0438 \u2014 \u041f\u0435\u0440\u0435\u0432\u0435\u0440\u043d\u0438\u0442\u0435 \u0441\u043b\u043e\u0432\u043e \u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u044c\u0442\u0435', + pl: 'Fiszki — Odwroc slowo i sprawdz', + en: 'Flashcards — Flip the word and check', + }, + exercise_quiz: { + de: 'Quiz — Richtige Uebersetzung aus 4 Optionen waehlen', + tr: 'Quiz — 4 secenekten dogru ceviriyi sec', + ar: '\u0627\u062e\u062a\u0628\u0627\u0631 \u2014 \u0627\u062e\u062a\u0631 \u0627\u0644\u062a\u0631\u062c\u0645\u0629 \u0627\u0644\u0635\u062d\u064a\u062d\u0629 \u0645\u0646 4 \u062e\u064a\u0627\u0631\u0627\u062a', + uk: '\u0422\u0435\u0441\u0442 \u2014 \u0412\u0438\u0431\u0435\u0440\u0456\u0442\u044c \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u0438\u0439 \u043f\u0435\u0440\u0435\u043a\u043b\u0430\u0434 \u0437 4 \u0432\u0430\u0440\u0456\u0430\u043d\u0442\u0456\u0432', + ru: '\u0422\u0435\u0441\u0442 \u2014 \u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u044b\u0439 \u043f\u0435\u0440\u0435\u0432\u043e\u0434 \u0438\u0437 4 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043e\u0432', + pl: 'Quiz — Wybierz poprawne tlumaczenie z 4 opcji', + en: 'Quiz — Choose correct translation from 4 options', + }, + exercise_listen: { + de: 'Hoeren — Wort hoeren und Uebersetzung waehlen', + tr: 'Dinleme — Kelimeyi dinle ve ceviriyi sec', + ar: '\u0627\u0633\u062a\u0645\u0627\u0639 \u2014 \u0627\u0633\u062a\u0645\u0639 \u0644\u0644\u0643\u0644\u0645\u0629 \u0648\u0627\u062e\u062a\u0631 \u0627\u0644\u062a\u0631\u062c\u0645\u0629', + uk: '\u0421\u043b\u0443\u0445\u0430\u043d\u043d\u044f \u2014 \u041f\u043e\u0441\u043b\u0443\u0445\u0430\u0439 \u0441\u043b\u043e\u0432\u043e \u0456 \u0432\u0438\u0431\u0435\u0440\u0438 \u043f\u0435\u0440\u0435\u043a\u043b\u0430\u0434', + ru: '\u0421\u043b\u0443\u0448\u0430\u043d\u0438\u0435 \u2014 \u041f\u043e\u0441\u043b\u0443\u0448\u0430\u0439\u0442\u0435 \u0441\u043b\u043e\u0432\u043e \u0438 \u0432\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u043f\u0435\u0440\u0435\u0432\u043e\u0434', + pl: 'Sluchanie — Posluchaj slowa i wybierz tlumaczenie', + en: 'Listening — Hear the word and choose the translation', + }, + exercise_speak: { + de: 'Sprechen — Wort hoeren und nachsprechen', + tr: 'Konusma — Kelimeyi dinle ve tekrar et', + ar: '\u062a\u062d\u062f\u062b \u2014 \u0627\u0633\u062a\u0645\u0639 \u0644\u0644\u0643\u0644\u0645\u0629 \u0648\u0643\u0631\u0631\u0647\u0627', + uk: '\u0413\u043e\u0432\u043e\u0440\u0456\u043d\u043d\u044f \u2014 \u041f\u043e\u0441\u043b\u0443\u0445\u0430\u0439 \u0441\u043b\u043e\u0432\u043e \u0456 \u043f\u043e\u0432\u0442\u043e\u0440\u0438', + ru: '\u0413\u043e\u0432\u043e\u0440\u0435\u043d\u0438\u0435 \u2014 \u041f\u043e\u0441\u043b\u0443\u0448\u0430\u0439\u0442\u0435 \u0441\u043b\u043e\u0432\u043e \u0438 \u043f\u043e\u0432\u0442\u043e\u0440\u0438\u0442\u0435', + pl: 'Mowienie — Posluchaj slowa i powtorz', + en: 'Speaking — Hear the word and repeat it', + }, } +function getApiBase() { return '' } + export default function LearnPage() { const { isDark } = useTheme() + const { t, nativeLang, isThirdLanguage } = useNativeLanguage() const [units, setUnits] = useState([]) const [isLoading, setIsLoading] = useState(true) const [error, setError] = useState(null) @@ -30,17 +106,16 @@ export default function LearnPage() { ? 'bg-white/10 backdrop-blur-xl border border-white/10' : 'bg-white/80 backdrop-blur-xl border border-black/5' - useEffect(() => { - loadUnits() - }, []) + const g = (key: string) => guide[key]?.[nativeLang] || guide[key]?.['de'] || key + + useEffect(() => { loadUnits() }, []) const loadUnits = async () => { setIsLoading(true) try { const resp = await fetch(`${getApiBase()}/api/learning-units/`) if (!resp.ok) throw new Error(`HTTP ${resp.status}`) - const data = await resp.json() - setUnits(data) + setUnits(await resp.json()) } catch (err: any) { setError(err.message) } finally { @@ -51,88 +126,97 @@ export default function LearnPage() { const handleDelete = async (unitId: string) => { try { const resp = await fetch(`${getApiBase()}/api/learning-units/${unitId}`, { method: 'DELETE' }) - if (resp.ok) { - setUnits((prev) => prev.filter((u) => u.id !== unitId)) - } - } catch (err) { - console.error('Delete failed:', err) - } + if (resp.ok) setUnits(prev => prev.filter(u => u.id !== unitId)) + } catch {} } return ( <> - {/* Header */} -
-
-
-
- - - -
-
-

- Meine Lernmodule -

-

- Karteikarten, Quiz und Lueckentexte aus deinen Vokabeln -

-
+ {/* Header */} +
+
+
+
+ + + +
+
+

+ {isThirdLanguage ? g('welcome') : 'Meine Lernmodule'} +

+

+ {isThirdLanguage + ? g('exercises_explained') + : 'Karteikarten, Quiz und Lueckentexte aus deinen Vokabeln'} +

+
- {/* Content */} -
- {isLoading && ( -
-
-
- )} +
+ {/* Parent Guide Panel — only for non-DE/EN users */} + {isThirdLanguage && ( +
+

+ {g('what_is_this')} +

+

+ {g('explanation')} +

- {error && ( -
-

Fehler: {error}

- -
- )} - - {!isLoading && !error && units.length === 0 && ( -
-
- - - -
-

- Noch keine Lernmodule -

-

- Scanne eine Schulbuchseite im Vokabel-Arbeitsblatt Generator und klicke "Lernmodule generieren". +

+

+ {g('exercises_explained')}

- - Zum Vokabel-Scanner - +

🃏 {g('exercise_cards')}

+

❓ {g('exercise_quiz')}

+

🔊 {g('exercise_listen')}

+

🎤 {g('exercise_speak')}

- )} +
+ )} - {!isLoading && units.length > 0 && ( -
- {units.map((unit) => ( - - ))} + {isLoading && ( +
+
+
+ )} + + {error && ( +
+

Fehler: {error}

+ +
+ )} + + {!isLoading && !error && units.length === 0 && ( +
+
+ + +
- )} -
+

+ {isThirdLanguage ? g('welcome') : 'Noch keine Lernmodule'} +

+ + {isThirdLanguage ? g('exercises_explained') : 'Zum Woerterbuch'} + +
+ )} + + {!isLoading && units.length > 0 && ( +
+ {units.map(unit => ( + + ))} +
+ )} +
) }