2026-06-25 12:53:49 +02:00
|
|
|
import React from 'react';
|
feat: wybór języka przez URL (/en) — reaktywny hook, przełącznik, hreflang
Język wynikał z navigator.language liczonego przy każdym renderze, więc nie
dało się go wybrać ani zalinkować. Teraz nośnikiem języka jest ścieżka.
- src/router.ts: usePathname() na useSyncExternalStore + navigate(). pushState
nie emituje zdarzenia, więc bez tego React nie widzi zmiany URL-a.
- i18n: useLang(), localizePath(), stripLangPrefix(), setLang(). useT() czyta
język ze ścieżki i jest reaktywne na nawigację.
- Detekcja przeglądarki tylko przy pierwszym wejściu na "/" i tylko gdy w
localStorage nic nie ma; wynik zapisujemy od razu, więc przekierowanie na
/en zadziała najwyżej raz i nie nadpisze późniejszego wyboru użytkownika.
Deep linki honorujemy bez ruszania.
- App.tsx: jedna tablica tras dla obu języków (/en/privacy -> '/privacy').
Ustawia też document.documentElement.lang, bo index.html ma na sztywno "pl".
- Header: przełącznik PL/EN (desktop + mobile), <button>, nie <a> — link
przeładowałby dokument.
- Hrefy w Header/Footer/PrivacyPolicyPage/PlatformPage przez localizePath,
inaczej /en jest pułapką jednokierunkową: każdy klik wraca na PL.
- index.html: hreflang pl/en/x-default; og:url z gethumanai.com na .pl
(wskazywał na cudzą domenę).
Bez nowych tłumaczeń treści — to osobny krok.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-31 15:54:49 +02:00
|
|
|
import { localizePath, useLang, useT } from '../i18n';
|
2026-06-25 12:53:49 +02:00
|
|
|
import Footer from './Footer';
|
2026-07-31 16:22:50 +02:00
|
|
|
import LangSwitcher from './LangSwitcher';
|
2026-06-25 12:53:49 +02:00
|
|
|
|
|
|
|
|
const PrivacyPolicyPage = () => {
|
|
|
|
|
const t = useT();
|
feat: wybór języka przez URL (/en) — reaktywny hook, przełącznik, hreflang
Język wynikał z navigator.language liczonego przy każdym renderze, więc nie
dało się go wybrać ani zalinkować. Teraz nośnikiem języka jest ścieżka.
- src/router.ts: usePathname() na useSyncExternalStore + navigate(). pushState
nie emituje zdarzenia, więc bez tego React nie widzi zmiany URL-a.
- i18n: useLang(), localizePath(), stripLangPrefix(), setLang(). useT() czyta
język ze ścieżki i jest reaktywne na nawigację.
- Detekcja przeglądarki tylko przy pierwszym wejściu na "/" i tylko gdy w
localStorage nic nie ma; wynik zapisujemy od razu, więc przekierowanie na
/en zadziała najwyżej raz i nie nadpisze późniejszego wyboru użytkownika.
Deep linki honorujemy bez ruszania.
- App.tsx: jedna tablica tras dla obu języków (/en/privacy -> '/privacy').
Ustawia też document.documentElement.lang, bo index.html ma na sztywno "pl".
- Header: przełącznik PL/EN (desktop + mobile), <button>, nie <a> — link
przeładowałby dokument.
- Hrefy w Header/Footer/PrivacyPolicyPage/PlatformPage przez localizePath,
inaczej /en jest pułapką jednokierunkową: każdy klik wraca na PL.
- index.html: hreflang pl/en/x-default; og:url z gethumanai.com na .pl
(wskazywał na cudzą domenę).
Bez nowych tłumaczeń treści — to osobny krok.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-31 15:54:49 +02:00
|
|
|
const lang = useLang();
|
|
|
|
|
const home = localizePath('/', lang);
|
2026-06-25 12:53:49 +02:00
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div className="min-h-screen bg-background selection:bg-primary selection:text-background">
|
|
|
|
|
<header className="bg-background/80 backdrop-blur-lg border-b border-white/5">
|
|
|
|
|
<div className="container mx-auto px-6 py-4 flex items-center justify-between">
|
feat: wybór języka przez URL (/en) — reaktywny hook, przełącznik, hreflang
Język wynikał z navigator.language liczonego przy każdym renderze, więc nie
dało się go wybrać ani zalinkować. Teraz nośnikiem języka jest ścieżka.
- src/router.ts: usePathname() na useSyncExternalStore + navigate(). pushState
nie emituje zdarzenia, więc bez tego React nie widzi zmiany URL-a.
- i18n: useLang(), localizePath(), stripLangPrefix(), setLang(). useT() czyta
język ze ścieżki i jest reaktywne na nawigację.
- Detekcja przeglądarki tylko przy pierwszym wejściu na "/" i tylko gdy w
localStorage nic nie ma; wynik zapisujemy od razu, więc przekierowanie na
/en zadziała najwyżej raz i nie nadpisze późniejszego wyboru użytkownika.
Deep linki honorujemy bez ruszania.
- App.tsx: jedna tablica tras dla obu języków (/en/privacy -> '/privacy').
Ustawia też document.documentElement.lang, bo index.html ma na sztywno "pl".
- Header: przełącznik PL/EN (desktop + mobile), <button>, nie <a> — link
przeładowałby dokument.
- Hrefy w Header/Footer/PrivacyPolicyPage/PlatformPage przez localizePath,
inaczej /en jest pułapką jednokierunkową: każdy klik wraca na PL.
- index.html: hreflang pl/en/x-default; og:url z gethumanai.com na .pl
(wskazywał na cudzą domenę).
Bez nowych tłumaczeń treści — to osobny krok.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-31 15:54:49 +02:00
|
|
|
<a href={home} className="text-2xl font-bold tracking-tight hover:opacity-80 transition-opacity">
|
2026-06-25 12:53:49 +02:00
|
|
|
human<span className="text-primary">AI</span>
|
|
|
|
|
</a>
|
2026-07-31 16:22:50 +02:00
|
|
|
<div className="flex items-center gap-6">
|
|
|
|
|
<a href={home} className="text-sm text-muted hover:text-foreground transition-colors">
|
2026-07-31 16:46:46 +02:00
|
|
|
{t.common.backToHome}
|
2026-07-31 16:22:50 +02:00
|
|
|
</a>
|
|
|
|
|
<LangSwitcher />
|
|
|
|
|
</div>
|
2026-06-25 12:53:49 +02:00
|
|
|
</div>
|
|
|
|
|
</header>
|
|
|
|
|
|
|
|
|
|
<main className="container mx-auto px-6 py-16 max-w-3xl">
|
|
|
|
|
<h1 className="text-4xl font-bold mb-2">{t.privacy.title}</h1>
|
|
|
|
|
<p className="text-muted text-sm mb-8">{t.privacy.lastUpdated}</p>
|
|
|
|
|
<p className="text-foreground/80 mb-12 leading-relaxed">{t.privacy.intro}</p>
|
|
|
|
|
|
|
|
|
|
<div className="space-y-10">
|
|
|
|
|
{t.privacy.sections.map((section, i) => (
|
|
|
|
|
<section key={section.title} id={['controller', 'contact', 'analytics', 'cookies', 'rights', 'changes'][i]}>
|
|
|
|
|
<h2 className="text-xl font-bold mb-4">{section.title}</h2>
|
|
|
|
|
{section.body.split('\n\n').map((paragraph, i) => (
|
|
|
|
|
<p key={i} className="text-foreground/80 leading-relaxed mb-3">
|
|
|
|
|
{paragraph}
|
|
|
|
|
</p>
|
|
|
|
|
))}
|
|
|
|
|
</section>
|
|
|
|
|
))}
|
|
|
|
|
</div>
|
|
|
|
|
</main>
|
|
|
|
|
|
|
|
|
|
<Footer />
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export default PrivacyPolicyPage;
|