chore(messages): update settings keys for multiple languages

This commit is contained in:
Fatih Kadir Akın
2026-01-14 12:40:10 +03:00
parent a9cdc7863d
commit a366b74a0a
21 changed files with 206 additions and 298 deletions
+1 -1
View File
@@ -1445,6 +1445,6 @@
"stepByStep": { "title": "فكر خطوة بخطوة", "problem": "المشكلة:", "withoutMagic": "بدون الكلمات السحرية:", "addMagicWords": "أضف الكلمات السحرية!", "magicWordsActive": "تمت إضافة الكلمات السحرية!", "nextStep": "اكشف الخطوة التالية", "withMagic": "مع التفكير خطوة بخطوة:", "retry": "حاول مرة أخرى" },
"promptLab": { "title": "مختبر الأوامر", "progress": "التحسينات", "yourPrompt": "أمرك:", "aiSays": "رد الذكاء الاصطناعي:", "addDetails": "أضف تحسينات:", "success": "أمرك الآن محدد جداً!", "retry": "ابدأ من جديد" },
"wordPredictor": { "title": "كيف يفكر الذكاء الاصطناعي", "instruction": "الذكاء الاصطناعي يخمن الكلمة التالية الأكثر احتمالاً. هل يمكنك التفكير مثله؟", "aiThinks": "الذكاء الاصطناعي يقرأ:", "thinkingDefault": "همم، أي كلمة ستكون منطقية هنا؟", "check": "تحقق من تخميني!", "correct": "أنت تفكر مثل الذكاء الاصطناعي!", "tryAgain": "ليس تماماً! الذكاء الاصطناعي يختار الكلمة الأكثر احتمالاً.", "retry": "حاول مرة أخرى" },
"settings": { "title": "الإعدادات", "language": "اللغة", "progress": "تقدمك", "stars": "النجوم", "completed": "المكتمل", "resetTitle": "إعادة تعيين التقدم", "resetButton": "إعادة تعيين كل التقدم", "resetWarning": "سيحذف هذا كل نجومك وتقدمك. هل أنت متأكد؟", "resetConfirm": "نعم، أعد تعيين كل شيء", "resetComplete": "تم إعادة التعيين! جارٍ إعادة التحميل...", "cancel": "إلغاء" }
"settings": { "title": "الإعدادات", "music": "الموسيقى", "language": "اللغة", "progress": "تقدمك", "stars": "النجوم", "completed": "المكتمل", "resetTitle": "إعادة تعيين التقدم", "resetButton": "إعادة تعيين كل التقدم", "resetWarning": "سيحذف هذا كل نجومك وتقدمك. هل أنت متأكد؟", "resetConfirm": "نعم، أعد تعيين كل شيء", "resetComplete": "تم إعادة التعيين! جارٍ إعادة التحميل...", "cancel": "إلغاء" }
}
}
+1 -1
View File
@@ -1445,6 +1445,6 @@
"stepByStep": { "title": "Addım-addım Düşün", "problem": "Problem:", "withoutMagic": "Sehrli sözlər olmadan:", "addMagicWords": "Sehrli Sözləri Əlavə Et!", "magicWordsActive": "Sehrli sözlər əlavə edildi!", "nextStep": "Növbəti Addımı Göstər", "withMagic": "Addım-addım düşünmə ilə:", "retry": "Yenidən cəhd et" },
"promptLab": { "title": "Prompt Laboratoriyası", "progress": "Təkmilləşdirmələr", "yourPrompt": "Sənin Promptun:", "aiSays": "AI Cavabı:", "addDetails": "Təkmilləşdirmə əlavə et:", "success": "Promptun indi çox spesifikdir!", "retry": "Yenidən başla" },
"wordPredictor": { "title": "AI Necə Düşünür", "instruction": "AI ən çox ehtimal olunan növbəti sözü təxmin edir. AI kimi düşünə bilərsən?", "aiThinks": "AI oxuyur:", "thinkingDefault": "Hmm, burada hansı söz ən məntiqli olardı?", "check": "Cavabımı yoxla!", "correct": "AI kimi düşünürsən!", "tryAgain": "Tam deyil! AI ən çox ehtimal olunan sözü seçir.", "retry": "Yenidən cəhd et" },
"settings": { "title": "Parametrlər", "language": "Dil", "progress": "Tərəqqin", "stars": "Ulduzlar", "completed": "Tamamlandı", "resetTitle": "Tərəqqini Sıfırla", "resetButton": "Hamısını Sıfırla", "resetWarning": "Bu bütün ulduzları və tərəqqini siləcək. Əminsən?", "resetConfirm": "Bəli, Hamısını Sıfırla", "resetComplete": "Tərəqqi sıfırlandı! Yenidən yüklənir...", "cancel": "Ləğv et" }
"settings": { "title": "Tənzimləmələr", "music": "Musiqi", "language": "Dil", "progress": "Tərəqqin", "stars": "Ulduzlar", "completed": "Tamamlandı", "resetTitle": "Tərəqqini Sıfırla", "resetButton": "Hamısını Sıfırla", "resetWarning": "Bu bütün ulduzları və tərəqqini siləcək. Əminsən?", "resetConfirm": "Bəli, Hamısını Sıfırla", "resetComplete": "Tərəqqi sıfırlandı! Yenidən yüklənir...", "cancel": "Ləğv et" }
}
}
+1 -1
View File
@@ -1445,6 +1445,6 @@
"stepByStep": { "title": "Schritt für Schritt denken", "problem": "Das Problem:", "withoutMagic": "Ohne Zauberwörter:", "addMagicWords": "Füge Zauberwörter hinzu!", "magicWordsActive": "Zauberwörter hinzugefügt!", "nextStep": "Nächsten Schritt zeigen", "withMagic": "Mit Schritt-für-Schritt-Denken:", "retry": "Nochmal versuchen" },
"promptLab": { "title": "Prompt-Labor", "progress": "Verbesserungen", "yourPrompt": "Dein Prompt:", "aiSays": "KI-Antwort:", "addDetails": "Verbesserungen hinzufügen:", "success": "Dein Prompt ist jetzt super spezifisch!", "retry": "Von vorn" },
"wordPredictor": { "title": "Wie KI denkt", "instruction": "KI errät das wahrscheinlichste nächste Wort. Kannst du wie KI denken?", "aiThinks": "KI liest:", "thinkingDefault": "Hmm, welches Wort würde hier Sinn machen?", "check": "Meine Antwort prüfen!", "correct": "Du denkst wie KI!", "tryAgain": "Nicht ganz! KI wählt das wahrscheinlichste Wort.", "retry": "Nochmal versuchen" },
"settings": { "title": "Einstellungen", "language": "Sprache", "progress": "Dein Fortschritt", "stars": "Sterne", "completed": "Abgeschlossen", "resetTitle": "Fortschritt zurücksetzen", "resetButton": "Alles zurücksetzen", "resetWarning": "Dies löscht alle Sterne und Fortschritt. Bist du sicher?", "resetConfirm": "Ja, alles zurücksetzen", "resetComplete": "Fortschritt zurückgesetzt! Wird neu geladen...", "cancel": "Abbrechen" }
"settings": { "title": "Einstellungen", "music": "Musik", "language": "Sprache", "progress": "Dein Fortschritt", "stars": "Sterne", "completed": "Abgeschlossen", "resetTitle": "Fortschritt zurücksetzen", "resetButton": "Alles zurücksetzen", "resetWarning": "Dies löscht alle Sterne und Fortschritt. Bist du sicher?", "resetConfirm": "Ja, alles zurücksetzen", "resetComplete": "Fortschritt zurückgesetzt! Wird neu geladen...", "cancel": "Abbrechen" }
}
}
+1 -1
View File
@@ -1445,6 +1445,6 @@
"stepByStep": { "title": "Σκέψου Βήμα-Βήμα", "problem": "Το Πρόβλημα:", "withoutMagic": "Χωρίς μαγικές λέξεις:", "addMagicWords": "Πρόσθεσε Μαγικές Λέξεις!", "magicWordsActive": "Μαγικές λέξεις προστέθηκαν!", "nextStep": "Αποκάλυψη Επόμενου Βήματος", "withMagic": "Με σκέψη βήμα-βήμα:", "retry": "Προσπάθησε ξανά" },
"promptLab": { "title": "Εργαστήριο Prompts", "progress": "Βελτιώσεις", "yourPrompt": "Το Prompt σου:", "aiSays": "Απάντηση AI:", "addDetails": "Πρόσθεσε βελτιώσεις:", "success": "Το prompt σου είναι τώρα πολύ συγκεκριμένο!", "retry": "Από την αρχή" },
"wordPredictor": { "title": "Πώς Σκέφτεται η AI", "instruction": "Η AI μαντεύει την πιο πιθανή επόμενη λέξη. Μπορείς να σκεφτείς σαν AI;", "aiThinks": "Η AI διαβάζει:", "thinkingDefault": "Χμμ, ποια λέξη θα είχε νόημα εδώ;", "check": "Έλεγξε την απάντησή μου!", "correct": "Σκέφτεσαι σαν AI!", "tryAgain": "Όχι ακριβώς! Η AI διαλέγει την πιο πιθανή λέξη.", "retry": "Προσπάθησε ξανά" },
"settings": { "title": "Ρυθμίσεις", "language": "Γλώσσα", "progress": "Η Πρόοδός σου", "stars": "Αστέρια", "completed": "Ολοκληρώθηκε", "resetTitle": "Επαναφορά Προόδου", "resetButton": "Επαναφορά Όλων", "resetWarning": "Αυτό θα διαγράψει όλα τα αστέρια και την πρόοδο. Είσαι σίγουρος;", "resetConfirm": "Ναι, Επαναφορά Όλων", "resetComplete": "Η πρόοδος επαναφέρθηκε! Επαναφόρτωση...", "cancel": "Ακύρωση" }
"settings": { "title": "Ρυθμίσεις", "music": "Μουσική", "language": "Γλώσσα", "progress": "Η Πρόοδός σου", "stars": "Αστέρια", "completed": "Ολοκληρώθηκε", "resetTitle": "Επαναφορά Προόδου", "resetButton": "Επαναφορά Όλων", "resetWarning": "Αυτό θα διαγράψει όλα τα αστέρια και την πρόοδο. Είσαι σίγουρος;", "resetConfirm": "Ναι, Επαναφορά Όλων", "resetComplete": "Η πρόοδος επαναφέρθηκε! Επαναφόρτωση...", "cancel": "Ακύρωση" }
}
}
+1
View File
@@ -1633,6 +1633,7 @@
},
"settings": {
"title": "Settings",
"music": "Music",
"language": "Language",
"progress": "Your Progress",
"stars": "Stars",
+1 -1
View File
@@ -1445,6 +1445,6 @@
"stepByStep": { "title": "Piensa Paso a Paso", "problem": "El Problema:", "withoutMagic": "Sin palabras mágicas:", "addMagicWords": "¡Añade las Palabras Mágicas!", "magicWordsActive": "¡Palabras mágicas añadidas!", "nextStep": "Revelar Siguiente Paso", "withMagic": "Con pensamiento paso a paso:", "retry": "Intentar de nuevo" },
"promptLab": { "title": "Laboratorio de Prompts", "progress": "Mejoras", "yourPrompt": "Tu Prompt:", "aiSays": "Respuesta de IA:", "addDetails": "Añadir mejoras:", "success": "¡Tu prompt ahora es súper específico!", "retry": "Empezar de nuevo" },
"wordPredictor": { "title": "Cómo Piensa la IA", "instruction": "La IA adivina la palabra más probable. ¿Puedes pensar como IA?", "aiThinks": "La IA está leyendo:", "thinkingDefault": "Hmm, ¿qué palabra tendría más sentido aquí?", "check": "¡Comprobar mi respuesta!", "correct": "¡Piensas como IA!", "tryAgain": "¡No del todo! La IA elige la palabra más probable.", "retry": "Intentar de nuevo" },
"settings": { "title": "Configuración", "language": "Idioma", "progress": "Tu Progreso", "stars": "Estrellas", "completed": "Completados", "resetTitle": "Restablecer Progreso", "resetButton": "Restablecer Todo", "resetWarning": "Esto eliminará todas tus estrellas y progreso. ¿Estás seguro?", "resetConfirm": "Sí, Restablecer Todo", "resetComplete": "¡Progreso restablecido! Recargando...", "cancel": "Cancelar" }
"settings": { "title": "Configuración", "music": "Música", "language": "Idioma", "progress": "Tu Progreso", "stars": "Estrellas", "completed": "Completados", "resetTitle": "Restablecer Progreso", "resetButton": "Restablecer Todo", "resetWarning": "Esto eliminará todas tus estrellas y progreso. ¿Estás seguro?", "resetConfirm": "Sí, Restablecer Todo", "resetComplete": "¡Progreso restablecido! Recargando...", "cancel": "Cancelar" }
}
}
+1 -1
View File
@@ -1445,6 +1445,6 @@
"stepByStep": { "title": "قدم به قدم فکر کن", "problem": "مسئله:", "withoutMagic": "بدون کلمات جادویی:", "addMagicWords": "کلمات جادویی اضافه کن!", "magicWordsActive": "کلمات جادویی اضافه شد!", "nextStep": "قدم بعدی نشان بده", "withMagic": "با فکر قدم به قدم:", "retry": "دوباره تلاش کن" },
"promptLab": { "title": "آزمایشگاه پرامپت", "progress": "بهبودها", "yourPrompt": "پرامپت تو:", "aiSays": "پاسخ هوش مصنوعی:", "addDetails": "بهبود اضافه کن:", "success": "پرامپتت الان خیلی مشخصه!", "retry": "از اول" },
"wordPredictor": { "title": "هوش مصنوعی چطور فکر می‌کند", "instruction": "هوش مصنوعی محتمل‌ترین کلمه بعدی حدس می‌زند. می‌تونی مثل هوش مصنوعی فکر کنی?", "aiThinks": "هوش مصنوعی می‌خواند:", "thinkingDefault": "هوم، کدام کلمه اینجا منطقی‌تره؟", "check": "جوابم بررسی کن!", "correct": "مثل هوش مصنوعی فکر می‌کنی!", "tryAgain": "دقیقاً نه! هوش مصنوعی محتمل‌ترین کلمه انتخاب می‌کند.", "retry": "دوباره تلاش کن" },
"settings": { "title": "تنظیمات", "language": "زبان", "progress": "پیشرفت تو", "stars": "ستاره‌ها", "completed": "تکمیل شده", "resetTitle": "بازنشانی پیشرفت", "resetButton": "همه بازنشانی", "resetWarning": "این همه ستاره‌ها و پیشرفت پاک می‌کند. مطمئنی؟", "resetConfirm": "بله، همه بازنشانی", "resetComplete": "پیشرفت بازنشانی شد! بارگذاری مجدد...", "cancel": "لغو" }
"settings": { "title": "تنظیمات", "music": "موسیقی", "language": "زبان", "progress": "پیشرفت تو", "stars": "ستاره‌ها", "completed": "تکمیل شده", "resetTitle": "بازنشانی پیشرفت", "resetButton": "همه بازنشانی", "resetWarning": "این همه ستاره‌ها و پیشرفت پاک می‌کند. مطمئنی؟", "resetConfirm": "بله، همه بازنشانی", "resetComplete": "پیشرفت بازنشانی شد! بارگذاری مجدد...", "cancel": "لغو" }
}
}
+1 -1
View File
@@ -1445,6 +1445,6 @@
"stepByStep": { "title": "Penser Étape par Étape", "problem": "Le Problème :", "withoutMagic": "Sans mots magiques :", "addMagicWords": "Ajoute les Mots Magiques !", "magicWordsActive": "Mots magiques ajoutés !", "nextStep": "Révéler l'Étape Suivante", "withMagic": "Avec la pensée étape par étape :", "retry": "Réessayer" },
"promptLab": { "title": "Labo de Prompts", "progress": "Améliorations", "yourPrompt": "Ton Prompt :", "aiSays": "Réponse de l'IA :", "addDetails": "Ajouter des améliorations :", "success": "Ton prompt est maintenant super spécifique !", "retry": "Recommencer" },
"wordPredictor": { "title": "Comment l'IA Pense", "instruction": "L'IA devine le mot suivant le plus probable. Peux-tu penser comme l'IA ?", "aiThinks": "L'IA lit :", "thinkingDefault": "Hmm, quel mot aurait le plus de sens ici ?", "check": "Vérifier ma réponse !", "correct": "Tu penses comme l'IA !", "tryAgain": "Pas tout à fait ! L'IA choisit le mot le plus probable.", "retry": "Réessayer" },
"settings": { "title": "Paramètres", "language": "Langue", "progress": "Ta Progression", "stars": "Étoiles", "completed": "Complétés", "resetTitle": "Réinitialiser la Progression", "resetButton": "Tout Réinitialiser", "resetWarning": "Cela supprimera toutes tes étoiles et ta progression. Es-tu sûr ?", "resetConfirm": "Oui, Tout Réinitialiser", "resetComplete": "Progression réinitialisée ! Rechargement...", "cancel": "Annuler" }
"settings": { "title": "Paramètres", "music": "Musique", "language": "Langue", "progress": "Ta Progression", "stars": "Étoiles", "completed": "Complétés", "resetTitle": "Réinitialiser la Progression", "resetButton": "Tout Réinitialiser", "resetWarning": "Cela supprimera toutes tes étoiles et ta progression. Es-tu sûr ?", "resetConfirm": "Oui, Tout Réinitialiser", "resetComplete": "Progression réinitialisée ! Rechargement...", "cancel": "Annuler" }
}
}
+1 -1
View File
@@ -1445,6 +1445,6 @@
"stepByStep": { "title": "חשוב צעד אחר צעד", "problem": "הבעיה:", "withoutMagic": "בלי מילות קסם:", "addMagicWords": "הוסף את מילות הקסם!", "magicWordsActive": "מילות הקסם נוספו!", "nextStep": "גלה את הצעד הבא", "withMagic": "עם חשיבה צעד אחר צעד:", "retry": "נסה שוב" },
"promptLab": { "title": "מעבדת פרומפטים", "progress": "שיפורים", "yourPrompt": "הפרומפט שלך:", "aiSays": "תשובת AI:", "addDetails": "הוסף שיפורים:", "success": "הפרומפט שלך עכשיו ספציפי מאוד!", "retry": "התחל מחדש" },
"wordPredictor": { "title": "איך AI חושב", "instruction": "AI מנחש את המילה הסבירה ביותר. אתה יכול לחשוב כמו AI?", "aiThinks": "AI קורא:", "thinkingDefault": "הממ, איזו מילה תהיה הגיונית כאן?", "check": "בדוק את התשובה שלי!", "correct": "אתה חושב כמו AI!", "tryAgain": "לא בדיוק! AI בוחר את המילה הסבירה ביותר.", "retry": "נסה שוב" },
"settings": { "title": "הגדרות", "language": "שפה", "progress": "ההתקדמות שלך", "stars": "כוכבים", "completed": "הושלם", "resetTitle": "אפס התקדמות", "resetButton": "אפס הכל", "resetWarning": "זה ימחק את כל הכוכבים וההתקדמות. בטוח?", "resetConfirm": "כן, אפס הכל", "resetComplete": "התקדמות אופסה! טוען מחדש...", "cancel": "ביטול" }
"settings": { "title": "הגדרות", "music": "מוזיקה", "language": "שפה", "progress": "ההתקדמות שלך", "stars": "כוכבים", "completed": "הושלם", "resetTitle": "אפס התקדמות", "resetButton": "אפס הכל", "resetWarning": "זה ימחק את כל הכוכבים וההתקדמות. בטוח?", "resetConfirm": "כן, אפס הכל", "resetComplete": "התקדמות אופסה! טוען מחדש...", "cancel": "ביטול" }
}
}
+1 -1
View File
@@ -1445,6 +1445,6 @@
"stepByStep": { "title": "Pensa Passo dopo Passo", "problem": "Il Problema:", "withoutMagic": "Senza parole magiche:", "addMagicWords": "Aggiungi le Parole Magiche!", "magicWordsActive": "Parole magiche aggiunte!", "nextStep": "Rivela Passo Successivo", "withMagic": "Con il pensiero passo dopo passo:", "retry": "Riprova" },
"promptLab": { "title": "Laboratorio Prompt", "progress": "Miglioramenti", "yourPrompt": "Il Tuo Prompt:", "aiSays": "Risposta IA:", "addDetails": "Aggiungi miglioramenti:", "success": "Il tuo prompt ora è super specifico!", "retry": "Ricomincia" },
"wordPredictor": { "title": "Come Pensa l'IA", "instruction": "L'IA indovina la parola più probabile. Puoi pensare come l'IA?", "aiThinks": "L'IA sta leggendo:", "thinkingDefault": "Hmm, quale parola avrebbe più senso qui?", "check": "Verifica la mia risposta!", "correct": "Pensi come l'IA!", "tryAgain": "Non proprio! L'IA sceglie la parola più probabile.", "retry": "Riprova" },
"settings": { "title": "Impostazioni", "language": "Lingua", "progress": "I Tuoi Progressi", "stars": "Stelle", "completed": "Completati", "resetTitle": "Reimposta Progressi", "resetButton": "Reimposta Tutto", "resetWarning": "Questo cancellerà tutte le stelle e i progressi. Sei sicuro?", "resetConfirm": "Sì, Reimposta Tutto", "resetComplete": "Progressi reimpostati! Ricaricamento...", "cancel": "Annulla" }
"settings": { "title": "Impostazioni", "music": "Musica", "language": "Lingua", "progress": "I Tuoi Progressi", "stars": "Stelle", "completed": "Completati", "resetTitle": "Reimposta Progressi", "resetButton": "Reimposta Tutto", "resetWarning": "Questo cancellerà tutte le stelle e i progressi. Sei sicuro?", "resetConfirm": "Sì, Reimposta Tutto", "resetComplete": "Progressi reimpostati! Ricaricamento...", "cancel": "Annulla" }
}
}
+1 -1
View File
@@ -1445,6 +1445,6 @@
"stepByStep": { "title": "ステップバイステップで考えよう", "problem": "問題:", "withoutMagic": "魔法の言葉なし:", "addMagicWords": "魔法の言葉を追加!", "magicWordsActive": "魔法の言葉を追加した!", "nextStep": "次のステップを見る", "withMagic": "ステップバイステップ思考で:", "retry": "もう一度" },
"promptLab": { "title": "プロンプトラボ", "progress": "改善", "yourPrompt": "あなたのプロンプト:", "aiSays": "AIの応答:", "addDetails": "改善を追加:", "success": "プロンプトがとても具体的になった!", "retry": "最初から" },
"wordPredictor": { "title": "AIの考え方", "instruction": "AIは最も可能性の高い次の単語を推測する。AIのように考えられる?", "aiThinks": "AIが読んでいる:", "thinkingDefault": "うーん、ここでどの単語が一番意味がある?", "check": "答えをチェック!", "correct": "AIのように考えてる!", "tryAgain": "違う!AIは最も可能性の高い単語を選ぶ。", "retry": "もう一度" },
"settings": { "title": "設定", "language": "言語", "progress": "あなたの進捗", "stars": "スター", "completed": "完了", "resetTitle": "進捗をリセット", "resetButton": "すべてリセット", "resetWarning": "すべてのスターと進捗が削除されます。よろしいですか?", "resetConfirm": "はい、すべてリセット", "resetComplete": "進捗をリセットしました!再読み込み中...", "cancel": "キャンセル" }
"settings": { "title": "設定", "music": "音楽", "language": "言語", "progress": "あなたの進捗", "stars": "スター", "completed": "完了", "resetTitle": "進捗をリセット", "resetButton": "すべてリセット", "resetWarning": "すべてのスターと進捗が削除されます。よろしいですか?", "resetConfirm": "はい、すべてリセット", "resetComplete": "進捗をリセットしました!再読み込み中...", "cancel": "キャンセル" }
}
}
+1 -1
View File
@@ -1445,6 +1445,6 @@
"stepByStep": { "title": "단계별로 생각하기", "problem": "문제:", "withoutMagic": "마법의 단어 없이:", "addMagicWords": "마법의 단어를 추가하세요!", "magicWordsActive": "마법의 단어가 추가됐어요!", "nextStep": "다음 단계 보기", "withMagic": "단계별 사고로:", "retry": "다시 시도" },
"promptLab": { "title": "프롬프트 연구소", "progress": "개선", "yourPrompt": "당신의 프롬프트:", "aiSays": "AI 응답:", "addDetails": "개선 추가:", "success": "프롬프트가 아주 구체적이 됐어요!", "retry": "처음부터" },
"wordPredictor": { "title": "AI가 생각하는 방법", "instruction": "AI는 가장 가능성 높은 다음 단어를 추측해요. AI처럼 생각할 수 있나요?", "aiThinks": "AI가 읽고 있어요:", "thinkingDefault": "음, 어떤 단어가 여기에 가장 맞을까?", "check": "내 답 확인!", "correct": "AI처럼 생각하고 있어요!", "tryAgain": "아니에요! AI는 가장 가능성 높은 단어를 선택해요.", "retry": "다시 시도" },
"settings": { "title": "설정", "language": "언어", "progress": "진행 상황", "stars": "별", "completed": "완료", "resetTitle": "진행 상황 초기화", "resetButton": "모두 초기화", "resetWarning": "모든 별과 진행 상황이 삭제됩니다. 확실한가요?", "resetConfirm": "네, 모두 초기화", "resetComplete": "진행 상황 초기화됨! 새로고침 중...", "cancel": "취소" }
"settings": { "title": "설정", "music": "음악", "language": "언어", "progress": "진행 상황", "stars": "별", "completed": "완료", "resetTitle": "진행 상황 초기화", "resetButton": "모두 초기화", "resetWarning": "모든 별과 진행 상황이 삭제됩니다. 확실한가요?", "resetConfirm": "네, 모두 초기화", "resetComplete": "진행 상황 초기화됨! 새로고침 중...", "cancel": "취소" }
}
}
+1
View File
@@ -1633,6 +1633,7 @@
},
"settings": {
"title": "Instellingen",
"music": "Muziek",
"language": "Taal",
"progress": "Jouw voortgang",
"stars": "Sterren",
+1 -1
View File
@@ -1445,6 +1445,6 @@
"stepByStep": { "title": "Pense Passo a Passo", "problem": "O Problema:", "withoutMagic": "Sem palavras mágicas:", "addMagicWords": "Adicione as Palavras Mágicas!", "magicWordsActive": "Palavras mágicas adicionadas!", "nextStep": "Revelar Próximo Passo", "withMagic": "Com pensamento passo a passo:", "retry": "Tentar de novo" },
"promptLab": { "title": "Laboratório de Prompts", "progress": "Melhorias", "yourPrompt": "Seu Prompt:", "aiSays": "Resposta da IA:", "addDetails": "Adicionar melhorias:", "success": "Seu prompt agora é super específico!", "retry": "Recomeçar" },
"wordPredictor": { "title": "Como a IA Pensa", "instruction": "A IA adivinha a palavra mais provável. Você consegue pensar como IA?", "aiThinks": "A IA está lendo:", "thinkingDefault": "Hmm, qual palavra faria mais sentido aqui?", "check": "Verificar minha resposta!", "correct": "Você pensa como IA!", "tryAgain": "Não exatamente! A IA escolhe a palavra mais provável.", "retry": "Tentar de novo" },
"settings": { "title": "Configurações", "language": "Idioma", "progress": "Seu Progresso", "stars": "Estrelas", "completed": "Completados", "resetTitle": "Redefinir Progresso", "resetButton": "Redefinir Tudo", "resetWarning": "Isso apagará todas as estrelas e progresso. Tem certeza?", "resetConfirm": "Sim, Redefinir Tudo", "resetComplete": "Progresso redefinido! Recarregando...", "cancel": "Cancelar" }
"settings": { "title": "Configurações", "music": "Música", "language": "Idioma", "progress": "Seu Progresso", "stars": "Estrelas", "completed": "Completados", "resetTitle": "Redefinir Progresso", "resetButton": "Redefinir Tudo", "resetWarning": "Isso apagará todas as estrelas e progresso. Tem certeza?", "resetConfirm": "Sim, Redefinir Tudo", "resetComplete": "Progresso redefinido! Recarregando...", "cancel": "Cancelar" }
}
}
+1 -1
View File
@@ -1445,6 +1445,6 @@
"stepByStep": { "title": "Думай пошагово", "problem": "Проблема:", "withoutMagic": "Без волшебных слов:", "addMagicWords": "Добавь волшебные слова!", "magicWordsActive": "Волшебные слова добавлены!", "nextStep": "Показать следующий шаг", "withMagic": "С пошаговым мышлением:", "retry": "Попробуй снова" },
"promptLab": { "title": "Лаборатория промптов", "progress": "Улучшения", "yourPrompt": "Твой промпт:", "aiSays": "Ответ ИИ:", "addDetails": "Добавь улучшения:", "success": "Твой промпт теперь очень конкретный!", "retry": "Сначала" },
"wordPredictor": { "title": "Как думает ИИ", "instruction": "ИИ угадывает наиболее вероятное следующее слово. Можешь думать как ИИ?", "aiThinks": "ИИ читает:", "thinkingDefault": "Хмм, какое слово имело бы смысл здесь?", "check": "Проверь мой ответ!", "correct": "Ты думаешь как ИИ!", "tryAgain": "Не совсем! ИИ выбирает наиболее вероятное слово.", "retry": "Попробуй снова" },
"settings": { "title": "Настройки", "language": "Язык", "progress": "Твой прогресс", "stars": "Звёзды", "completed": "Завершено", "resetTitle": "Сбросить прогресс", "resetButton": "Сбросить всё", "resetWarning": "Это удалит все звёзды и прогресс. Уверен?", "resetConfirm": "Да, сбросить всё", "resetComplete": "Прогресс сброшен! Перезагрузка...", "cancel": "Отмена" }
"settings": { "title": "Настройки", "music": "Музыка", "language": "Язык", "progress": "Твой прогресс", "stars": "Звёзды", "completed": "Завершено", "resetTitle": "Сбросить прогресс", "resetButton": "Сбросить всё", "resetWarning": "Это удалит все звёзды и прогресс. Уверен?", "resetConfirm": "Да, сбросить всё", "resetComplete": "Прогресс сброшен! Перезагрузка...", "cancel": "Отмена" }
}
}
+1
View File
@@ -1566,6 +1566,7 @@
},
"settings": {
"title": "Ayarlar",
"music": "Müzik",
"language": "Dil",
"progress": "İlerlemeniz",
"stars": "Yıldız",
+1 -1
View File
@@ -1445,6 +1445,6 @@
"stepByStep": { "title": "逐步思考", "problem": "问题:", "withoutMagic": "没有魔法词语:", "addMagicWords": "添加魔法词语!", "magicWordsActive": "魔法词语已添加!", "nextStep": "显示下一步", "withMagic": "逐步思考:", "retry": "再试一次" },
"promptLab": { "title": "提示词实验室", "progress": "改进", "yourPrompt": "你的提示词:", "aiSays": "AI回应:", "addDetails": "添加改进:", "success": "你的提示词现在非常具体!", "retry": "重新开始" },
"wordPredictor": { "title": "AI如何思考", "instruction": "AI猜测最可能的下一个词。你能像AI一样思考吗?", "aiThinks": "AI正在阅读:", "thinkingDefault": "嗯,哪个词在这里最有意义?", "check": "检查我的答案!", "correct": "你像AI一样思考!", "tryAgain": "不太对!AI选择最可能的词。", "retry": "再试一次" },
"settings": { "title": "设置", "language": "语言", "progress": "你的进度", "stars": "星星", "completed": "已完成", "resetTitle": "重置进度", "resetButton": "重置全部", "resetWarning": "这将删除所有星星和进度。确定吗?", "resetConfirm": "是的,重置全部", "resetComplete": "进度已重置!正在重新加载...", "cancel": "取消" }
"settings": { "title": "设置", "music": "音乐", "language": "语言", "progress": "你的进度", "stars": "星星", "completed": "已完成", "resetTitle": "重置进度", "resetButton": "重置全部", "resetWarning": "这将删除所有星星和进度。确定吗?", "resetConfirm": "是的,重置全部", "resetComplete": "进度已重置!正在重新加载...", "cancel": "取消" }
}
}
Binary file not shown.
+3 -2
View File
@@ -1,7 +1,7 @@
import { Schoolbell } from "next/font/google";
import { getLocale } from "next-intl/server";
import { KidsHeader } from "@/components/kids/layout/kids-header";
import { BackgroundMusic } from "@/components/kids/layout/background-music";
import { MusicProvider } from "@/components/kids/layout/background-music";
import { LevelProvider } from "@/components/kids/providers/level-context";
const RTL_LOCALES = ["ar", "he", "fa"];
@@ -40,6 +40,7 @@ export default async function KidsLayout({
return (
<LevelProvider>
<MusicProvider>
<div
className={`fixed inset-0 flex flex-col text-xl light ${kidsFont.className}`}
data-theme="light"
@@ -86,8 +87,8 @@ export default async function KidsLayout({
<main className="flex-1 min-h-0 overflow-hidden">
{children}
</main>
<BackgroundMusic />
</div>
</MusicProvider>
</LevelProvider>
);
}
+154 -280
View File
@@ -1,6 +1,24 @@
"use client";
import { useState, useRef, useCallback } from "react";
import { useState, useEffect, useRef, useCallback, createContext, useContext } from "react";
const MUSIC_ENABLED_KEY = "kids-music-enabled";
const MUSIC_VOLUME_KEY = "kids-music-volume";
// Shared audio instance and context for cross-component communication
interface MusicContextType {
isPlaying: boolean;
volume: number;
setIsPlaying: (playing: boolean) => void;
setVolume: (volume: number) => void;
audioRef: React.RefObject<HTMLAudioElement | null>;
}
const MusicContext = createContext<MusicContextType | null>(null);
export function useMusicContext() {
return useContext(MusicContext);
}
// Pixel art speaker icons
function PixelSpeakerOn() {
@@ -30,304 +48,125 @@ function PixelSpeakerOff() {
);
}
// 8-bit chiptune music generator using Web Audio API
class ChiptunePlayer {
private audioContext: AudioContext | null = null;
private masterGain: GainNode | null = null;
private isPlaying = false;
private intervalId: number | null = null;
private step = 0;
// Provider component that manages the audio element
export function MusicProvider({ children }: { children: React.ReactNode }) {
const audioRef = useRef<HTMLAudioElement | null>(null);
const [isPlaying, setIsPlaying] = useState(false);
const [volume, setVolume] = useState(0.3);
const [hasInteracted, setHasInteracted] = useState(false);
// Fun bouncy 8-bit melody - playful and catchy!
private melody = [
// Part 1: Bouncy intro
523.25, 0, 659.25, 0, 783.99, 0, 659.25, 0, // C5 - E5 - G5 - E5 (bouncy)
698.46, 0, 783.99, 0, 880.00, 783.99, 659.25, 0, // F5 - G5 - A5 G5 E5 (climb up!)
// Part 2: Silly descending
783.99, 698.46, 659.25, 587.33, 523.25, 0, 392.00, 0, // G5 F5 E5 D5 C5 - G4 (slide down)
440.00, 493.88, 523.25, 0, 659.25, 0, 523.25, 0, // A4 B4 C5 - E5 - C5 (pop back up)
// Part 3: Playful jumps
392.00, 523.25, 392.00, 523.25, 659.25, 783.99, 659.25, 0, // G4 C5 G4 C5 E5 G5 E5 (jumping!)
880.00, 0, 783.99, 0, 659.25, 523.25, 587.33, 659.25, // A5 - G5 - E5 C5 D5 E5
// Part 4: Fun ending
783.99, 0, 659.25, 0, 523.25, 587.33, 659.25, 783.99, // G5 - E5 - C5 D5 E5 G5
880.00, 783.99, 659.25, 523.25, 392.00, 0, 523.25, 0, // A5 G5 E5 C5 G4 - C5 (finish!)
];
// Funky bass line - groovy!
private bass = [
// Part 1
130.81, 0, 130.81, 164.81, 196.00, 0, 164.81, 0, // C3 - C3 E3 G3 - E3
174.61, 0, 196.00, 0, 220.00, 196.00, 164.81, 0, // F3 - G3 - A3 G3 E3
// Part 2
196.00, 174.61, 164.81, 146.83, 130.81, 0, 98.00, 0, // G3 F3 E3 D3 C3 - G2
110.00, 123.47, 130.81, 0, 164.81, 0, 130.81, 0, // A2 B2 C3 - E3 - C3
// Part 3
98.00, 130.81, 98.00, 130.81, 164.81, 196.00, 164.81, 0, // G2 C3 G2 C3 E3 G3 E3
220.00, 0, 196.00, 0, 164.81, 130.81, 146.83, 164.81, // A3 - G3 - E3 C3 D3 E3
// Part 4
196.00, 0, 164.81, 0, 130.81, 146.83, 164.81, 196.00, // G3 - E3 - C3 D3 E3 G3
220.00, 196.00, 164.81, 130.81, 98.00, 0, 130.81, 0, // A3 G3 E3 C3 G2 - C3
];
async start() {
if (this.isPlaying) return;
// Load saved preferences
useEffect(() => {
const savedEnabled = localStorage.getItem(MUSIC_ENABLED_KEY);
const savedVolume = localStorage.getItem(MUSIC_VOLUME_KEY);
try {
this.audioContext = new (window.AudioContext || (window as unknown as { webkitAudioContext: typeof AudioContext }).webkitAudioContext)();
// Resume audio context if suspended (required by browsers)
if (this.audioContext.state === "suspended") {
await this.audioContext.resume();
if (savedVolume) {
setVolume(parseFloat(savedVolume));
}
// Default to enabled if not set
if (savedEnabled === null || savedEnabled === "true") {
setIsPlaying(true);
}
}, []);
// Create and manage audio element
useEffect(() => {
if (!audioRef.current) {
const audio = new Audio("/kids-music.mp3");
audio.loop = true;
audio.volume = volume;
audioRef.current = audio;
}
return () => {
if (audioRef.current) {
audioRef.current.pause();
audioRef.current = null;
}
this.masterGain = this.audioContext.createGain();
this.masterGain.gain.value = 0.2;
this.masterGain.connect(this.audioContext.destination);
this.isPlaying = true;
this.step = 0;
};
}, []);
// Play notes at upbeat tempo
this.intervalId = window.setInterval(() => this.playStep(), 150);
} catch (error) {
console.error("Failed to start audio:", error);
// Update volume when it changes
useEffect(() => {
if (audioRef.current) {
audioRef.current.volume = volume;
}
}
localStorage.setItem(MUSIC_VOLUME_KEY, volume.toString());
}, [volume]);
private playStep() {
if (!this.audioContext || !this.masterGain) return;
const now = this.audioContext.currentTime;
const noteIndex = this.step % this.melody.length;
// Play melody (square wave for 8-bit sound) - skip if 0 (rest)
if (this.melody[noteIndex] > 0) {
this.playNote(this.melody[noteIndex], now, 0.12, "square", 0.12);
}
// Handle play/pause
useEffect(() => {
localStorage.setItem(MUSIC_ENABLED_KEY, isPlaying.toString());
// Play bass (triangle wave) - louder and deeper, skip if 0
if (this.bass[noteIndex] > 0) {
this.playNote(this.bass[noteIndex], now, 0.14, "triangle", 0.15);
// Add sub-bass for extra punch
this.playNote(this.bass[noteIndex] / 2, now, 0.14, "sine", 0.08);
}
// Aggressive dubstep-style percussion
if (this.step % 8 === 0) {
this.playDrum(now, "kick");
this.playDrum(now + 0.15, "kick"); // Double kick
} else if (this.step % 8 === 4) {
this.playDrum(now, "snare");
} else if (this.step % 2 === 1) {
this.playDrum(now, "hihat");
}
if (!audioRef.current) return;
// Wobble bass on every other beat for dubstep feel
if (this.step % 4 === 2) {
this.playWobble(now);
}
this.step++;
}
private playNote(freq: number, time: number, duration: number, type: OscillatorType, volume: number) {
if (!this.audioContext || !this.masterGain) return;
const osc = this.audioContext.createOscillator();
const gain = this.audioContext.createGain();
osc.type = type;
osc.frequency.value = freq;
gain.gain.setValueAtTime(volume, time);
gain.gain.exponentialRampToValueAtTime(0.001, time + duration);
osc.connect(gain);
gain.connect(this.masterGain);
osc.start(time);
osc.stop(time + duration);
}
private playDrum(time: number, type: "kick" | "hihat" | "snare" = "hihat") {
if (!this.audioContext || !this.masterGain) return;
if (type === "kick") {
// Heavy dubstep kick - deep and punchy
const osc = this.audioContext.createOscillator();
const gain = this.audioContext.createGain();
osc.type = "sine";
osc.frequency.setValueAtTime(180, time);
osc.frequency.exponentialRampToValueAtTime(30, time + 0.12);
gain.gain.setValueAtTime(0.5, time);
gain.gain.exponentialRampToValueAtTime(0.001, time + 0.2);
osc.connect(gain);
gain.connect(this.masterGain);
osc.start(time);
osc.stop(time + 0.2);
// Add click for attack
const click = this.audioContext.createOscillator();
const clickGain = this.audioContext.createGain();
click.type = "square";
click.frequency.value = 800;
clickGain.gain.setValueAtTime(0.15, time);
clickGain.gain.exponentialRampToValueAtTime(0.001, time + 0.02);
click.connect(clickGain);
clickGain.connect(this.masterGain);
click.start(time);
click.stop(time + 0.02);
} else if (type === "snare") {
// Aggressive dubstep snare - noise + tone
const bufferSize = this.audioContext.sampleRate * 0.15;
const buffer = this.audioContext.createBuffer(1, bufferSize, this.audioContext.sampleRate);
const data = buffer.getChannelData(0);
for (let i = 0; i < bufferSize; i++) {
data[i] = Math.random() * 2 - 1;
}
const noise = this.audioContext.createBufferSource();
noise.buffer = buffer;
const noiseGain = this.audioContext.createGain();
noiseGain.gain.setValueAtTime(0.3, time);
noiseGain.gain.exponentialRampToValueAtTime(0.001, time + 0.15);
const filter = this.audioContext.createBiquadFilter();
filter.type = "bandpass";
filter.frequency.value = 3000;
filter.Q.value = 1;
noise.connect(filter);
filter.connect(noiseGain);
noiseGain.connect(this.masterGain);
noise.start(time);
noise.stop(time + 0.15);
// Add tone body
const tone = this.audioContext.createOscillator();
const toneGain = this.audioContext.createGain();
tone.type = "triangle";
tone.frequency.setValueAtTime(200, time);
tone.frequency.exponentialRampToValueAtTime(100, time + 0.05);
toneGain.gain.setValueAtTime(0.2, time);
toneGain.gain.exponentialRampToValueAtTime(0.001, time + 0.08);
tone.connect(toneGain);
toneGain.connect(this.masterGain);
tone.start(time);
tone.stop(time + 0.08);
if (isPlaying && hasInteracted) {
audioRef.current.play().catch(() => {
// Autoplay blocked, will retry on user interaction
});
} else {
// Hi-hat - crispy noise
const bufferSize = this.audioContext.sampleRate * 0.04;
const buffer = this.audioContext.createBuffer(1, bufferSize, this.audioContext.sampleRate);
const data = buffer.getChannelData(0);
for (let i = 0; i < bufferSize; i++) {
data[i] = Math.random() * 2 - 1;
audioRef.current.pause();
}
}, [isPlaying, hasInteracted]);
// Listen for first user interaction to enable autoplay
useEffect(() => {
const handleInteraction = () => {
setHasInteracted(true);
if (isPlaying && audioRef.current) {
audioRef.current.play().catch(() => {});
}
const noise = this.audioContext.createBufferSource();
noise.buffer = buffer;
const gain = this.audioContext.createGain();
gain.gain.setValueAtTime(0.08, time);
gain.gain.exponentialRampToValueAtTime(0.001, time + 0.04);
const filter = this.audioContext.createBiquadFilter();
filter.type = "highpass";
filter.frequency.value = 9000;
noise.connect(filter);
filter.connect(gain);
gain.connect(this.masterGain);
noise.start(time);
noise.stop(time + 0.04);
}
}
};
private playWobble(time: number) {
if (!this.audioContext || !this.masterGain) return;
document.addEventListener("click", handleInteraction, { once: true });
document.addEventListener("keydown", handleInteraction, { once: true });
document.addEventListener("touchstart", handleInteraction, { once: true });
// Classic dubstep wobble bass
const osc = this.audioContext.createOscillator();
const gain = this.audioContext.createGain();
const lfo = this.audioContext.createOscillator();
const lfoGain = this.audioContext.createGain();
osc.type = "sawtooth";
osc.frequency.value = 55; // Low A
// LFO for wobble effect
lfo.type = "sine";
lfo.frequency.value = 8; // Wobble speed
lfoGain.gain.value = 400;
lfo.connect(lfoGain);
// Create filter for wobble
const filter = this.audioContext.createBiquadFilter();
filter.type = "lowpass";
filter.frequency.value = 400;
filter.Q.value = 8;
lfoGain.connect(filter.frequency);
gain.gain.setValueAtTime(0.2, time);
gain.gain.exponentialRampToValueAtTime(0.001, time + 0.3);
osc.connect(filter);
filter.connect(gain);
gain.connect(this.masterGain);
lfo.start(time);
osc.start(time);
lfo.stop(time + 0.3);
osc.stop(time + 0.3);
}
return () => {
document.removeEventListener("click", handleInteraction);
document.removeEventListener("keydown", handleInteraction);
document.removeEventListener("touchstart", handleInteraction);
};
}, [isPlaying]);
stop() {
if (this.intervalId) {
clearInterval(this.intervalId);
this.intervalId = null;
}
if (this.audioContext) {
this.audioContext.close();
this.audioContext = null;
}
this.isPlaying = false;
}
getIsPlaying() {
return this.isPlaying;
}
return (
<MusicContext.Provider value={{ isPlaying, volume, setIsPlaying, setVolume, audioRef }}>
{children}
</MusicContext.Provider>
);
}
export function MusicButton() {
const [isPlaying, setIsPlaying] = useState(false);
const playerRef = useRef<ChiptunePlayer | null>(null);
const context = useMusicContext();
// Fallback for when not wrapped in provider
const [localPlaying, setLocalPlaying] = useState(false);
const localAudioRef = useRef<HTMLAudioElement | null>(null);
const isPlaying = context?.isPlaying ?? localPlaying;
const setIsPlaying = context?.setIsPlaying ?? setLocalPlaying;
const toggleMusic = useCallback(async () => {
if (!playerRef.current) {
playerRef.current = new ChiptunePlayer();
}
if (isPlaying) {
playerRef.current.stop();
setIsPlaying(false);
const toggleMusic = useCallback(() => {
if (context) {
context.setIsPlaying(!context.isPlaying);
} else {
await playerRef.current.start();
setIsPlaying(true);
// Fallback behavior
if (!localAudioRef.current) {
localAudioRef.current = new Audio("/kids-music.mp3");
localAudioRef.current.loop = true;
localAudioRef.current.volume = 0.3;
}
if (localPlaying) {
localAudioRef.current.pause();
setLocalPlaying(false);
} else {
localAudioRef.current.play().catch(() => {});
setLocalPlaying(true);
}
}
}, [isPlaying]);
}, [context, localPlaying]);
return (
<button
@@ -341,6 +180,41 @@ export function MusicButton() {
);
}
// Volume slider component for settings
export function MusicVolumeSlider() {
const context = useMusicContext();
if (!context) return null;
const { volume, setVolume, isPlaying, setIsPlaying } = context;
return (
<div className="space-y-2">
<div className="flex items-center justify-between">
<button
onClick={() => setIsPlaying(!isPlaying)}
className={`px-3 py-1.5 rounded-lg font-medium text-sm transition-colors ${
isPlaying
? "bg-[#22C55E] text-white"
: "bg-gray-200 text-gray-600"
}`}
>
{isPlaying ? "🔊 On" : "🔇 Off"}
</button>
<span className="text-sm text-[#5D4037]">{Math.round(volume * 100)}%</span>
</div>
<input
type="range"
min="0"
max="100"
value={volume * 100}
onChange={(e) => setVolume(parseInt(e.target.value) / 100)}
className="w-full h-2 bg-[#D4A574] rounded-lg appearance-none cursor-pointer accent-[#8B4513]"
/>
</div>
);
}
// Legacy export for backwards compatibility
export function BackgroundMusic() {
return null;
+32 -2
View File
@@ -6,7 +6,8 @@ import { cn } from "@/lib/utils";
import { clearAllProgress, getTotalStars, getCompletedLevelsCount } from "@/lib/kids/progress";
import { setLocale } from "@/lib/i18n/client";
import { analyticsKids } from "@/lib/analytics";
import { Settings, X, Globe, Trash2, Check } from "lucide-react";
import { Settings, X, Globe, Trash2, Check, Volume2 } from "lucide-react";
import { MusicVolumeSlider } from "./background-music";
const SUPPORTED_LOCALES = [
{ code: "en", label: "English", flag: "🇺🇸" },
@@ -91,7 +92,7 @@ function SettingsModal({ onClose }: { onClose: () => void }) {
/>
{/* Modal */}
<div className="relative bg-[#FEF3C7] border-4 border-[#8B4513] rounded-xl p-6 w-full max-w-md animate-in zoom-in-95 fade-in duration-200">
<div className="relative bg-[#FEF3C7] border-4 border-[#8B4513] rounded-xl p-6 w-full max-w-md max-h-[90vh] overflow-y-auto animate-in zoom-in-95 fade-in duration-200">
{/* Close button */}
<button
onClick={onClose}
@@ -106,6 +107,35 @@ function SettingsModal({ onClose }: { onClose: () => void }) {
{t("title")}
</h2>
{/* Music Section */}
<div className="mb-6">
<h3 className="text-lg font-bold text-[#5D4037] mb-3 flex items-center gap-2">
<Volume2 className="w-5 h-5" />
{t("music")}
</h3>
<MusicVolumeSlider />
<p className="mt-3 text-xs text-[#8B7355]">
Music by{" "}
<a
href="https://pixabay.com/users/djartmusic-46653586/?utm_source=link-attribution&utm_medium=referral&utm_campaign=music&utm_content=301272"
target="_blank"
rel="noopener noreferrer"
className="underline hover:text-[#8B4513]"
>
Krzysztof Szymanski
</a>{" "}
from{" "}
<a
href="https://pixabay.com/?utm_source=link-attribution&utm_medium=referral&utm_campaign=music&utm_content=301272"
target="_blank"
rel="noopener noreferrer"
className="underline hover:text-[#8B4513]"
>
Pixabay
</a>
</p>
</div>
{/* Language Section */}
<div className="mb-6">
<h3 className="text-lg font-bold text-[#5D4037] mb-3 flex items-center gap-2">