Fix: Language switch takes effect immediately (React Context)
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) <noreply@anthropic.com>
This commit is contained in:
@@ -6,6 +6,7 @@ import { AlertsProvider } from '@/lib/AlertsContext'
|
|||||||
import { AlertsB2BProvider } from '@/lib/AlertsB2BContext'
|
import { AlertsB2BProvider } from '@/lib/AlertsB2BContext'
|
||||||
import { MessagesProvider } from '@/lib/MessagesContext'
|
import { MessagesProvider } from '@/lib/MessagesContext'
|
||||||
import { ActivityProvider } from '@/lib/ActivityContext'
|
import { ActivityProvider } from '@/lib/ActivityContext'
|
||||||
|
import { NativeLanguageProvider } from '@/lib/NativeLanguageContext'
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: 'BreakPilot Studio v2',
|
title: 'BreakPilot Studio v2',
|
||||||
@@ -26,7 +27,9 @@ export default function RootLayout({
|
|||||||
<AlertsB2BProvider>
|
<AlertsB2BProvider>
|
||||||
<MessagesProvider>
|
<MessagesProvider>
|
||||||
<ActivityProvider>
|
<ActivityProvider>
|
||||||
|
<NativeLanguageProvider>
|
||||||
{children}
|
{children}
|
||||||
|
</NativeLanguageProvider>
|
||||||
</ActivityProvider>
|
</ActivityProvider>
|
||||||
</MessagesProvider>
|
</MessagesProvider>
|
||||||
</AlertsB2BProvider>
|
</AlertsB2BProvider>
|
||||||
|
|||||||
61
studio-v2/lib/NativeLanguageContext.tsx
Normal file
61
studio-v2/lib/NativeLanguageContext.tsx
Normal file
@@ -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, any>) => string
|
||||||
|
}
|
||||||
|
|
||||||
|
const NativeLanguageContext = createContext<NativeLanguageState>({
|
||||||
|
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<string, string>)[nativeLang] || entry.de || key
|
||||||
|
}, [nativeLang])
|
||||||
|
|
||||||
|
const wordInNative = useCallback((translations?: Record<string, any>): string => {
|
||||||
|
if (!translations || !isThirdLanguage) return ''
|
||||||
|
const entry = translations[nativeLang]
|
||||||
|
if (!entry) return ''
|
||||||
|
return typeof entry === 'string' ? entry : entry.text || ''
|
||||||
|
}, [nativeLang, isThirdLanguage])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<NativeLanguageContext.Provider value={{ nativeLang, setNativeLang, isThirdLanguage, t, wordInNative }}>
|
||||||
|
{children}
|
||||||
|
</NativeLanguageContext.Provider>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useNativeLanguage() {
|
||||||
|
return useContext(NativeLanguageContext)
|
||||||
|
}
|
||||||
@@ -1,44 +1,4 @@
|
|||||||
'use client'
|
'use client'
|
||||||
|
|
||||||
import { useState, useEffect, useCallback } from 'react'
|
// Re-export from Context so all existing imports keep working
|
||||||
import { exerciseT, type ExerciseKey } from './exerciseTranslations'
|
export { useNativeLanguage } from './NativeLanguageContext'
|
||||||
|
|
||||||
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<string, string>)[nativeLang] || entry.de || key
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get native translation of a vocab word from translations JSONB */
|
|
||||||
const wordInNative = (translations?: Record<string, any>): 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 }
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user