From 0018076ed58eb86d7fd4dafacd5d8973a622cf0a Mon Sep 17 00:00:00 2001 From: Benjamin Admin Date: Wed, 29 Apr 2026 16:54:27 +0200 Subject: [PATCH] Unify language system: one setting for all modules - Merge two separate language systems (bp_language + bp_native_language) into one - NativeLanguageContext now reads from LanguageContext (same localStorage key) - Extend i18n.ts to 26 languages with flags (UI falls back to EN/DE) - Replace LanguageSwitcher with LanguageDropdown (flags) in learn + parent layouts - Migration: old bp_native_language value auto-migrates to bp_language - Onboarding page writes to bp_language (unified key) Co-Authored-By: Claude Opus 4.6 (1M context) --- studio-v2/app/learn/layout.tsx | 15 ++++------ studio-v2/app/onboarding/page.tsx | 2 +- studio-v2/app/parent/layout.tsx | 13 ++------- studio-v2/lib/LanguageContext.tsx | 6 ++-- studio-v2/lib/NativeLanguageContext.tsx | 23 ++++++++------- studio-v2/lib/i18n.ts | 39 ++++++++++++++++++++----- 6 files changed, 57 insertions(+), 41 deletions(-) diff --git a/studio-v2/app/learn/layout.tsx b/studio-v2/app/learn/layout.tsx index 1c13f8f..7f0d743 100644 --- a/studio-v2/app/learn/layout.tsx +++ b/studio-v2/app/learn/layout.tsx @@ -2,16 +2,15 @@ import { Sidebar } from '@/components/Sidebar' import { useTheme } from '@/lib/ThemeContext' -import { useNativeLanguage } from '@/lib/useNativeLanguage' -import { LanguageSwitcher } from '@/components/learn/LanguageSwitcher' +import { LanguageDropdown } from '@/components/LanguageDropdown' /** * Shared layout for ALL /learn/* pages. - * Provides: Sidebar + gradient background + language switcher. + * Provides: Sidebar + gradient background + language dropdown (flags). + * Uses the central LanguageContext (same as all other modules). */ export default function LearnLayout({ children }: { children: React.ReactNode }) { const { isDark } = useTheme() - const { nativeLang, setNativeLang, isThirdLanguage } = useNativeLanguage() return (
- {/* Sticky language switcher at top-right */} + {/* Language dropdown at top-right (same as worksheet-editor etc.) */}
- +
{children}
diff --git a/studio-v2/app/onboarding/page.tsx b/studio-v2/app/onboarding/page.tsx index 4e8d186..80bfed0 100644 --- a/studio-v2/app/onboarding/page.tsx +++ b/studio-v2/app/onboarding/page.tsx @@ -15,7 +15,7 @@ interface LangOption { rtl: boolean } -const STORAGE_KEY = 'bp_native_language' +const STORAGE_KEY = 'bp_language' export default function OnboardingPage() { const router = useRouter() diff --git a/studio-v2/app/parent/layout.tsx b/studio-v2/app/parent/layout.tsx index a91fd0c..461b814 100644 --- a/studio-v2/app/parent/layout.tsx +++ b/studio-v2/app/parent/layout.tsx @@ -2,16 +2,14 @@ import { Sidebar } from '@/components/Sidebar' import { useTheme } from '@/lib/ThemeContext' -import { useNativeLanguage } from '@/lib/useNativeLanguage' -import { LanguageSwitcher } from '@/components/learn/LanguageSwitcher' +import { LanguageDropdown } from '@/components/LanguageDropdown' /** * Shared layout for ALL /parent/* pages. - * Same design as learn layout — Sidebar + gradient + language switcher. + * Same design as learn layout — Sidebar + gradient + flag language dropdown. */ export default function ParentLayout({ children }: { children: React.ReactNode }) { const { isDark } = useTheme() - const { nativeLang, setNativeLang } = useNativeLanguage() return (
- {/* Sticky language switcher at top-right */}
- +
{children}
diff --git a/studio-v2/lib/LanguageContext.tsx b/studio-v2/lib/LanguageContext.tsx index 6b9ef91..1754d7a 100644 --- a/studio-v2/lib/LanguageContext.tsx +++ b/studio-v2/lib/LanguageContext.tsx @@ -43,9 +43,9 @@ export function LanguageProvider({ children }: { children: ReactNode }) { } } - // Uebersetzungsfunktion + // Uebersetzungsfunktion (Fallback: en → de → key) const t = (key: string): string => { - return translations[language][key] || translations[defaultLanguage][key] || key + return translations[language]?.[key] || translations['en']?.[key] || translations['de']?.[key] || key } // Waehrend SSR: Default anzeigen @@ -55,7 +55,7 @@ export function LanguageProvider({ children }: { children: ReactNode }) { value={{ language: defaultLanguage, setLanguage: () => {}, - t: (key) => translations[defaultLanguage][key] || key, + t: (key) => translations[defaultLanguage]?.[key] || key, isRTL: false, availableLanguages, }} diff --git a/studio-v2/lib/NativeLanguageContext.tsx b/studio-v2/lib/NativeLanguageContext.tsx index 827ca13..f5f89c9 100644 --- a/studio-v2/lib/NativeLanguageContext.tsx +++ b/studio-v2/lib/NativeLanguageContext.tsx @@ -1,9 +1,15 @@ 'use client' -import React, { createContext, useContext, useState, useEffect, useCallback } from 'react' +import React, { createContext, useContext, useCallback } from 'react' import { exerciseT, type ExerciseKey } from './exerciseTranslations' +import { useLanguage } from './LanguageContext' -const STORAGE_KEY = 'bp_native_language' +/** + * NativeLanguageContext — unified with LanguageContext. + * + * Reads/writes the SAME language as the central LanguageContext (bp_language). + * No separate localStorage key — one language setting for the entire app. + */ interface NativeLanguageState { nativeLang: string @@ -22,17 +28,14 @@ const NativeLanguageContext = createContext({ }) export function NativeLanguageProvider({ children }: { children: React.ReactNode }) { - const [nativeLang, setNativeLangState] = useState('de') + const { language, setLanguage } = useLanguage() - useEffect(() => { - const stored = localStorage.getItem(STORAGE_KEY) - if (stored) setNativeLangState(stored) - }, []) + // Sync: nativeLang = the central language setting + const nativeLang = language const setNativeLang = useCallback((lang: string) => { - setNativeLangState(lang) - localStorage.setItem(STORAGE_KEY, lang) - }, []) + setLanguage(lang) + }, [setLanguage]) const isThirdLanguage = nativeLang !== 'de' && nativeLang !== 'en' diff --git a/studio-v2/lib/i18n.ts b/studio-v2/lib/i18n.ts index 2a2428a..3c1d2dc 100644 --- a/studio-v2/lib/i18n.ts +++ b/studio-v2/lib/i18n.ts @@ -6,9 +6,9 @@ * RTL-Support fuer Arabisch */ -export type Language = 'de' | 'en' | 'tr' | 'ar' | 'ru' | 'uk' | 'pl' +export type Language = string -export const availableLanguages: Record = { +export const availableLanguages: Record = { de: { name: 'Deutsch', flag: '🇩🇪' }, en: { name: 'English', flag: '🇬🇧' }, tr: { name: 'Türkçe', flag: '🇹🇷' }, @@ -16,12 +16,31 @@ export const availableLanguages: Record> = { +// Uebersetzungen fuer Studio v2 UI (7 Sprachen voll, Rest faellt auf EN/DE zurueck) +export const translations: Record> = { de: { // Kopfleiste dashboard: 'Dashboard', @@ -377,7 +396,13 @@ export function getStoredLanguage(): Language { if (typeof window === 'undefined') return defaultLanguage const stored = localStorage.getItem(STORAGE_KEY) if (stored && stored in availableLanguages) { - return stored as Language + return stored + } + // Migration: bp_native_language → bp_language + const native = localStorage.getItem('bp_native_language') + if (native && native in availableLanguages) { + localStorage.setItem(STORAGE_KEY, native) + return native } return defaultLanguage } @@ -388,9 +413,9 @@ export function setStoredLanguage(lang: Language): void { localStorage.setItem(STORAGE_KEY, lang) } -// Uebersetzung abrufen +// Uebersetzung abrufen (Fallback: en → de → key) export function t(key: string, lang: Language): string { - return translations[lang][key] || translations[defaultLanguage][key] || key + return translations[lang]?.[key] || translations['en']?.[key] || translations['de']?.[key] || key } // Ist die Sprache RTL?