From 9f21bd070ab6c7f13a040d9385bf20bbdcba5393 Mon Sep 17 00:00:00 2001 From: Benjamin Admin Date: Mon, 27 Apr 2026 14:45:53 +0200 Subject: [PATCH] Fix: Language switch takes effect immediately (React Context) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replaced localStorage-only hook with React Context Provider. Layout and page components now share the same state — switching language in the dropdown instantly updates all text on screen without requiring a page reload. NativeLanguageProvider added to root layout.tsx. useNativeLanguage() re-exported from Context for backward compat. Co-Authored-By: Claude Opus 4.6 (1M context) --- studio-v2/app/layout.tsx | 5 +- studio-v2/lib/NativeLanguageContext.tsx | 61 +++++++++++++++++++++++++ studio-v2/lib/useNativeLanguage.ts | 44 +----------------- 3 files changed, 67 insertions(+), 43 deletions(-) create mode 100644 studio-v2/lib/NativeLanguageContext.tsx diff --git a/studio-v2/app/layout.tsx b/studio-v2/app/layout.tsx index 2f5509e..15bc901 100644 --- a/studio-v2/app/layout.tsx +++ b/studio-v2/app/layout.tsx @@ -6,6 +6,7 @@ import { AlertsProvider } from '@/lib/AlertsContext' import { AlertsB2BProvider } from '@/lib/AlertsB2BContext' import { MessagesProvider } from '@/lib/MessagesContext' import { ActivityProvider } from '@/lib/ActivityContext' +import { NativeLanguageProvider } from '@/lib/NativeLanguageContext' export const metadata: Metadata = { title: 'BreakPilot Studio v2', @@ -26,7 +27,9 @@ export default function RootLayout({ - {children} + + {children} + diff --git a/studio-v2/lib/NativeLanguageContext.tsx b/studio-v2/lib/NativeLanguageContext.tsx new file mode 100644 index 0000000..77aa9c0 --- /dev/null +++ b/studio-v2/lib/NativeLanguageContext.tsx @@ -0,0 +1,61 @@ +'use client' + +import React, { createContext, useContext, useState, useEffect, useCallback } from 'react' +import { exerciseT, type ExerciseKey } from './exerciseTranslations' + +const STORAGE_KEY = 'bp_native_language' + +interface NativeLanguageState { + nativeLang: string + setNativeLang: (lang: string) => void + isThirdLanguage: boolean + t: (key: ExerciseKey) => string + wordInNative: (translations?: Record) => string +} + +const NativeLanguageContext = createContext({ + nativeLang: 'de', + setNativeLang: () => {}, + isThirdLanguage: false, + t: (key) => key, + wordInNative: () => '', +}) + +export function NativeLanguageProvider({ children }: { children: React.ReactNode }) { + const [nativeLang, setNativeLangState] = useState('de') + + useEffect(() => { + const stored = localStorage.getItem(STORAGE_KEY) + if (stored) setNativeLangState(stored) + }, []) + + const setNativeLang = useCallback((lang: string) => { + setNativeLangState(lang) + localStorage.setItem(STORAGE_KEY, lang) + }, []) + + const isThirdLanguage = nativeLang !== 'de' && nativeLang !== 'en' + + const t = useCallback((key: ExerciseKey): string => { + const entry = exerciseT[key] + if (!entry) return key + return (entry as Record)[nativeLang] || entry.de || key + }, [nativeLang]) + + const wordInNative = useCallback((translations?: Record): string => { + if (!translations || !isThirdLanguage) return '' + const entry = translations[nativeLang] + if (!entry) return '' + return typeof entry === 'string' ? entry : entry.text || '' + }, [nativeLang, isThirdLanguage]) + + return ( + + {children} + + ) +} + +export function useNativeLanguage() { + return useContext(NativeLanguageContext) +} diff --git a/studio-v2/lib/useNativeLanguage.ts b/studio-v2/lib/useNativeLanguage.ts index 233dcfb..93b5ac5 100644 --- a/studio-v2/lib/useNativeLanguage.ts +++ b/studio-v2/lib/useNativeLanguage.ts @@ -1,44 +1,4 @@ 'use client' -import { useState, useEffect, useCallback } from 'react' -import { exerciseT, type ExerciseKey } from './exerciseTranslations' - -const STORAGE_KEY = 'bp_native_language' - -/** - * Hook for native language state + translations. - * Persists to localStorage. Can be changed at any time (e.g. parent switches language). - */ -export function useNativeLanguage() { - const [nativeLang, setNativeLangState] = useState('de') - - useEffect(() => { - const stored = localStorage.getItem(STORAGE_KEY) - if (stored) setNativeLangState(stored) - }, []) - - /** Change native language (persists to localStorage) */ - const setNativeLang = useCallback((lang: string) => { - setNativeLangState(lang) - localStorage.setItem(STORAGE_KEY, lang) - }, []) - - const isThirdLanguage = nativeLang !== 'de' && nativeLang !== 'en' - - /** Get translated exercise UI text */ - const t = (key: ExerciseKey): string => { - const entry = exerciseT[key] - if (!entry) return key - return (entry as Record)[nativeLang] || entry.de || key - } - - /** Get native translation of a vocab word from translations JSONB */ - const wordInNative = (translations?: Record): string => { - if (!translations || !isThirdLanguage) return '' - const entry = translations[nativeLang] - if (!entry) return '' - return typeof entry === 'string' ? entry : entry.text || '' - } - - return { nativeLang, setNativeLang, isThirdLanguage, t, wordInNative } -} +// Re-export from Context so all existing imports keep working +export { useNativeLanguage } from './NativeLanguageContext'