refactor: współdzielony LangSwitcher także w nagłówkach podstron

Przełącznik siedział w Header.tsx, który renderuje się tylko na landingu —
PrivacyPolicyPage i PlatformPage mają własne <header>. Z /en/privacy i
/en/platforma nie dało się wrócić na PL inaczej niż przez stronę główną
albo ręczną edycję URL-a.

Wyciągnięty do src/components/LangSwitcher.tsx i wstawiony w oba nagłówki
obok linku powrotnego.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
oskar 2026-07-31 16:22:50 +02:00
parent 3e452191de
commit 13ffb8754b
4 changed files with 60 additions and 39 deletions

View file

@ -1,39 +1,8 @@
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import { Menu, X } from 'lucide-react'; import { Menu, X } from 'lucide-react';
import { motion, AnimatePresence } from 'framer-motion'; import { motion, AnimatePresence } from 'framer-motion';
import { localizePath, setLang, useLang, type Lang } from '../i18n'; import { localizePath, useLang } from '../i18n';
import LangSwitcher from './LangSwitcher';
const LANGS: Lang[] = ['pl', 'en'];
// PL / EN toggle. Buttons rather than links: switching is a client-side
// navigation (setLang), so a real href would reload the whole document.
const LangSwitcher = ({ onSwitch }: { onSwitch?: () => void }) => {
const lang = useLang();
return (
<div className="flex items-center gap-2 text-sm font-medium" role="group" aria-label="Język / Language">
{LANGS.map((code, i) => (
<React.Fragment key={code}>
{i > 0 && <span aria-hidden="true" className="text-muted/40">/</span>}
<button
type="button"
lang={code}
aria-current={code === lang ? 'true' : undefined}
onClick={() => {
setLang(code);
onSwitch?.();
}}
className={`uppercase tracking-wide transition-colors ${
code === lang ? 'text-foreground' : 'text-muted hover:text-foreground'
}`}
>
{code}
</button>
</React.Fragment>
))}
</div>
);
};
const Header = () => { const Header = () => {
const lang = useLang(); const lang = useLang();

View file

@ -0,0 +1,44 @@
import React from 'react';
import { setLang, useLang, type Lang } from '../i18n';
const LANGS: Lang[] = ['pl', 'en'];
/**
* PL / EN toggle. Buttons rather than links: switching is a client-side
* navigation (setLang), so a real href would reload the whole document.
*
* Shared by the landing Header and the standalone pages' own headers without
* it on those pages, /en/privacy and /en/platforma have no way back to Polish
* short of editing the URL.
*
* @param onSwitch runs after the language changes used to close the mobile menu.
*/
const LangSwitcher = ({ onSwitch }: { onSwitch?: () => void }) => {
const lang = useLang();
return (
<div className="flex items-center gap-2 text-sm font-medium" role="group" aria-label="Język / Language">
{LANGS.map((code, i) => (
<React.Fragment key={code}>
{i > 0 && <span aria-hidden="true" className="text-muted/40">/</span>}
<button
type="button"
lang={code}
aria-current={code === lang ? 'true' : undefined}
onClick={() => {
setLang(code);
onSwitch?.();
}}
className={`uppercase tracking-wide transition-colors ${
code === lang ? 'text-foreground' : 'text-muted hover:text-foreground'
}`}
>
{code}
</button>
</React.Fragment>
))}
</div>
);
};
export default LangSwitcher;

View file

@ -2,6 +2,7 @@ import React from 'react';
import { ArrowRight, Building2, CheckCircle2, ChevronRight, Home } from 'lucide-react'; import { ArrowRight, Building2, CheckCircle2, ChevronRight, Home } from 'lucide-react';
import Footer from './Footer'; import Footer from './Footer';
import { localizePath, useLang } from '../i18n'; import { localizePath, useLang } from '../i18n';
import LangSwitcher from './LangSwitcher';
// Standalone product page at /platforma (and /en/platforma). The copy is not // Standalone product page at /platforma (and /en/platforma). The copy is not
// localized yet — the site only translates contact.* and privacy.* — but the // localized yet — the site only translates contact.* and privacy.* — but the
@ -16,9 +17,12 @@ const PlatformPage = () => {
<a href={localizePath('/', lang)} className="text-2xl font-bold tracking-tight hover:opacity-80 transition-opacity"> <a href={localizePath('/', lang)} className="text-2xl font-bold tracking-tight hover:opacity-80 transition-opacity">
human<span className="text-primary">AI</span> human<span className="text-primary">AI</span>
</a> </a>
<a href={localizePath('/', lang)} className="text-sm text-muted hover:text-foreground transition-colors"> <div className="flex items-center gap-6">
Wróć na stronę główną <a href={localizePath('/', lang)} className="text-sm text-muted hover:text-foreground transition-colors">
</a> Wróć na stronę główną
</a>
<LangSwitcher />
</div>
</div> </div>
</header> </header>

View file

@ -1,6 +1,7 @@
import React from 'react'; import React from 'react';
import { localizePath, useLang, useT } from '../i18n'; import { localizePath, useLang, useT } from '../i18n';
import Footer from './Footer'; import Footer from './Footer';
import LangSwitcher from './LangSwitcher';
const PrivacyPolicyPage = () => { const PrivacyPolicyPage = () => {
const t = useT(); const t = useT();
@ -14,9 +15,12 @@ const PrivacyPolicyPage = () => {
<a href={home} className="text-2xl font-bold tracking-tight hover:opacity-80 transition-opacity"> <a href={home} className="text-2xl font-bold tracking-tight hover:opacity-80 transition-opacity">
human<span className="text-primary">AI</span> human<span className="text-primary">AI</span>
</a> </a>
<a href={home} className="text-sm text-muted hover:text-foreground transition-colors"> <div className="flex items-center gap-6">
{t.privacy.backToHome} <a href={home} className="text-sm text-muted hover:text-foreground transition-colors">
</a> {t.privacy.backToHome}
</a>
<LangSwitcher />
</div>
</div> </div>
</header> </header>