From bde0d57b5a16db3c7828814ab2ce88463eaadafa Mon Sep 17 00:00:00 2001 From: Benjamin Admin Date: Wed, 29 Apr 2026 17:49:58 +0200 Subject: [PATCH] Add Schulsprache (school language) as second language setting - LanguageContext: new schoolLanguage + setSchoolLanguage - LanguageDropdown: two tabs (Muttersprache / Schulsprache) with flag selection - UnitBuilder: defaults target language to schoolLanguage - Stored in bp_school_language localStorage (default: de) - Shows school flag badge next to main language when different Co-Authored-By: Claude Opus 4.6 (1M context) --- .../app/vocabulary/components/UnitBuilder.tsx | 7 +- studio-v2/app/vocabulary/page.tsx | 3 + studio-v2/components/LanguageDropdown.tsx | 89 ++++++++++++------- studio-v2/lib/LanguageContext.tsx | 22 +++-- studio-v2/lib/i18n.ts | 16 +++- 5 files changed, 97 insertions(+), 40 deletions(-) diff --git a/studio-v2/app/vocabulary/components/UnitBuilder.tsx b/studio-v2/app/vocabulary/components/UnitBuilder.tsx index 379340c..cfaf581 100644 --- a/studio-v2/app/vocabulary/components/UnitBuilder.tsx +++ b/studio-v2/app/vocabulary/components/UnitBuilder.tsx @@ -43,16 +43,19 @@ interface Props { isCreating: boolean noSearchResults?: boolean searchQuery?: string + defaultSourceLang?: string + defaultTargetLang?: string } export default function UnitBuilder({ isDark, glassCard, glassInput, selectedWords, onWordsChange, onCreateUnit, isCreating, noSearchResults, searchQuery, + defaultSourceLang = 'en', defaultTargetLang = 'de', }: Props) { const [unitTitle, setUnitTitle] = useState('') - const [sourceLang, setSourceLang] = useState('de') - const [targetLang, setTargetLang] = useState('en') + const [sourceLang, setSourceLang] = useState(defaultSourceLang) + const [targetLang, setTargetLang] = useState(defaultTargetLang) const [showManualEntry, setShowManualEntry] = useState(false) const [manualSource, setManualSource] = useState('') const [manualTarget, setManualTarget] = useState('') diff --git a/studio-v2/app/vocabulary/page.tsx b/studio-v2/app/vocabulary/page.tsx index b8de604..ae3eb8b 100644 --- a/studio-v2/app/vocabulary/page.tsx +++ b/studio-v2/app/vocabulary/page.tsx @@ -3,6 +3,7 @@ import React, { useState, useEffect, useCallback } from 'react' import { useRouter } from 'next/navigation' import { useTheme } from '@/lib/ThemeContext' +import { useLanguage } from '@/lib/LanguageContext' import { Sidebar } from '@/components/Sidebar' import { AudioButton } from '@/components/learn/AudioButton' import UnitBuilder, { type UnitWord } from './components/UnitBuilder' @@ -39,6 +40,7 @@ function vocabToUnit(w: VocabWord, searchLang: string): UnitWord { export default function VocabularyPage() { const { isDark } = useTheme() + const { schoolLanguage } = useLanguage() const router = useRouter() const [query, setQuery] = useState('') @@ -340,6 +342,7 @@ export default function VocabularyPage() { isCreating={isCreating} noSearchResults={noSearchResults} searchQuery={query} + defaultTargetLang={schoolLanguage} /> diff --git a/studio-v2/components/LanguageDropdown.tsx b/studio-v2/components/LanguageDropdown.tsx index 44481b2..a5f777f 100644 --- a/studio-v2/components/LanguageDropdown.tsx +++ b/studio-v2/components/LanguageDropdown.tsx @@ -10,12 +10,12 @@ interface LanguageDropdownProps { } export function LanguageDropdown({ className = '' }: LanguageDropdownProps) { - const { language, setLanguage, availableLanguages } = useLanguage() + const { language, setLanguage, schoolLanguage, setSchoolLanguage, availableLanguages } = useLanguage() const { isDark } = useTheme() const [isOpen, setIsOpen] = useState(false) + const [mode, setMode] = useState<'native' | 'school'>('native') const dropdownRef = useRef(null) - // Schliessen bei Klick ausserhalb useEffect(() => { function handleClickOutside(event: MouseEvent) { if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) { @@ -26,7 +26,6 @@ export function LanguageDropdown({ className = '' }: LanguageDropdownProps) { return () => document.removeEventListener('mousedown', handleClickOutside) }, []) - // Schliessen bei Escape useEffect(() => { function handleEscape(event: KeyboardEvent) { if (event.key === 'Escape') setIsOpen(false) @@ -35,11 +34,22 @@ export function LanguageDropdown({ className = '' }: LanguageDropdownProps) { return () => document.removeEventListener('keydown', handleEscape) }, []) - const currentLang = availableLanguages[language] + const nativeLang = availableLanguages[language] + const schoolLang = availableLanguages[schoolLanguage] + const activeLang = mode === 'native' ? language : schoolLanguage + + const handleSelect = (lang: Language) => { + if (mode === 'native') { + setLanguage(lang) + } else { + setSchoolLanguage(lang) + } + setIsOpen(false) + } return (
- {/* Trigger Button */} + {/* Trigger: shows both native + school language */} - {/* Dropdown Menu */} + {/* Dropdown */} {isOpen && ( -
-
    + {/* Tab switcher: Muttersprache / Schulsprache */} +
    + + +
    + + {/* Language list */} +
      {(Object.keys(availableLanguages) as Language[]).map((lang) => { const langInfo = availableLanguages[lang] - const isSelected = lang === language + const isSelected = lang === activeLang return (