From d99c0e2429a167e6423d0751cd94cdf3b8ed9e8a Mon Sep 17 00:00:00 2001 From: Sascha Bach Date: Wed, 26 Nov 2025 12:21:04 +0100 Subject: [PATCH] zweisprachigkeit implementiert --- src/app/PortfolioApp.tsx | 7 +- src/components/LanguageToggle.tsx | 43 ++++++++++++ src/components/ThemeToggle.tsx | 4 +- src/components/layout/Footer.tsx | 4 +- src/components/layout/Navigation.tsx | 6 +- src/components/sections/AboutSection.tsx | 7 +- .../sections/CertificationsSection.tsx | 7 +- src/components/sections/ContactSection.tsx | 5 +- src/components/sections/HeroSection.tsx | 7 +- src/components/sections/ProjectsSection.tsx | 7 +- src/components/sections/ServicesSection.tsx | 7 +- src/components/sections/SkillsSection.tsx | 7 +- src/config/locales/en/index.ts | 16 ++--- src/config/projects-config.ts | 1 - src/contexts/LanguageContext.tsx | 66 +++++++++++++++++++ src/pages/ImprintPage.tsx | 3 +- src/pages/PrivacyPolicy.tsx | 5 +- src/scss/language-toggle.scss | 48 ++++++++++++++ src/scss/layout/topbar.scss | 4 ++ 19 files changed, 215 insertions(+), 39 deletions(-) create mode 100644 src/components/LanguageToggle.tsx create mode 100644 src/contexts/LanguageContext.tsx create mode 100644 src/scss/language-toggle.scss diff --git a/src/app/PortfolioApp.tsx b/src/app/PortfolioApp.tsx index af94419..667908b 100644 --- a/src/app/PortfolioApp.tsx +++ b/src/app/PortfolioApp.tsx @@ -1,7 +1,12 @@ +import { LanguageProvider } from '../contexts/LanguageContext'; import AppRouter from './AppRouter'; function PortfolioApp() { - return ; + return ( + + + + ); } export default PortfolioApp; diff --git a/src/components/LanguageToggle.tsx b/src/components/LanguageToggle.tsx new file mode 100644 index 0000000..9114e31 --- /dev/null +++ b/src/components/LanguageToggle.tsx @@ -0,0 +1,43 @@ +import { useLanguage } from '../contexts/LanguageContext'; +import '../scss/language-toggle.scss'; + +export default function LanguageToggle() { + const { language, setLanguage } = useLanguage(); + + const handleLanguageChange = (newLang: 'en' | 'de') => { + if (newLang !== language) { + setLanguage(newLang); + // Announce language change to screen readers + const announcement = document.createElement('div'); + announcement.setAttribute('role', 'status'); + announcement.setAttribute('aria-live', 'polite'); + announcement.setAttribute('class', 'sr-only'); + announcement.textContent = `Language changed to ${newLang === 'en' ? 'English' : 'Deutsch'}`; + document.body.appendChild(announcement); + setTimeout(() => announcement.remove(), 1000); + } + }; + + return ( +
+ + +
+ ); +} diff --git a/src/components/ThemeToggle.tsx b/src/components/ThemeToggle.tsx index 70d698d..cd1a0d8 100644 --- a/src/components/ThemeToggle.tsx +++ b/src/components/ThemeToggle.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { getTexts } from '../config/texts'; +import { useLanguage } from '../contexts/LanguageContext'; type Props = Readonly<{ theme: 'light' | 'dark'; @@ -10,7 +10,7 @@ export default function ThemeToggle({ theme, setTheme }: Props) { - const texts = getTexts(); + const { texts } = useLanguage(); const toggleTheme = () => { setTheme(theme === 'light' ? 'dark' : 'light'); diff --git a/src/components/layout/Footer.tsx b/src/components/layout/Footer.tsx index 46d12f2..3c1f06d 100644 --- a/src/components/layout/Footer.tsx +++ b/src/components/layout/Footer.tsx @@ -1,10 +1,10 @@ import { Github, Linkedin, Mail } from 'lucide-react'; import { Link } from 'react-router-dom'; import { personalConfig, createEmailLink } from '../../config/personal'; -import { getTexts } from '../../config/texts'; +import { useLanguage } from '../../contexts/LanguageContext'; export default function Footer() { - const texts = getTexts(); + const { texts } = useLanguage(); // Email obfuscation function using config const handleEmailClick = (e: React.MouseEvent) => { e.preventDefault(); diff --git a/src/components/layout/Navigation.tsx b/src/components/layout/Navigation.tsx index d212ed7..3467635 100644 --- a/src/components/layout/Navigation.tsx +++ b/src/components/layout/Navigation.tsx @@ -1,9 +1,10 @@ import { useState } from 'react'; import { Link, useLocation, useNavigate } from 'react-router-dom'; import ThemeToggle from '../ThemeToggle'; +import LanguageToggle from '../LanguageToggle'; import MobileMenu from './MobileMenu'; import { personalConfig } from '../../config/personal'; -import { getTexts } from '../../config/texts'; +import { useLanguage } from '../../contexts/LanguageContext'; import { scrollToSection } from '../../utils/scrollUtils'; type Props = { @@ -18,7 +19,7 @@ export default function Navbar({ const [menuOpen, setMenuOpen] = useState(false); const location = useLocation(); const navigate = useNavigate(); - const texts = getTexts(); + const { texts } = useLanguage(); const menuItems = texts.navigation.menuItems; @@ -43,6 +44,7 @@ export default function Navbar({ {item} ))} + {/* Burger Button für Mobile */}