Translate pages

This commit is contained in:
Andras Schmelczer 2026-04-04 09:47:18 +01:00
parent a7aaf5effa
commit 96402228e3
49 changed files with 1458 additions and 926 deletions

View file

@ -1,4 +1,5 @@
import { useState, useCallback, useEffect } from 'react';
import { useTranslation } from 'react-i18next';
import type { AuthUser } from '../../hooks/useAuth';
import { shortenUrl, prewarmScreenshot } from '../../lib/api';
import { copyToClipboard } from '../../lib/clipboard';
@ -13,6 +14,7 @@ import { MoonIcon } from './icons/MoonIcon';
import { SpinnerIcon } from './icons/SpinnerIcon';
import UserMenu from './UserMenu';
import MobileMenu from './MobileMenu';
import LanguageDropdown from './LanguageDropdown';
export type Page =
| 'home'
@ -64,6 +66,7 @@ export default function Header({
onLogout: () => void;
isMobile: boolean;
}) {
const { t } = useTranslation();
const [copied, setCopied] = useState(false);
const [sharing, setSharing] = useState(false);
const [menuOpen, setMenuOpen] = useState(false);
@ -131,7 +134,7 @@ export default function Header({
onClick={(e) => navLink('home', e)}
>
<LogoIcon className="w-5 h-5 text-teal-400" />
<span className="font-semibold text-lg">Perfect Postcode</span>
<span className="font-semibold text-lg">{t('header.appName')}</span>
</a>
{/* Desktop nav */}
@ -142,7 +145,7 @@ export default function Header({
className={tabClass('dashboard')}
onClick={(e) => navLink('dashboard', e)}
>
Dashboard
{t('header.dashboard')}
</a>
{user && (
<a
@ -150,7 +153,7 @@ export default function Header({
className={tabClass('invites')}
onClick={(e) => navLink('invites', e)}
>
Invite Friends
{t('header.inviteFriends')}
</a>
)}
<a
@ -158,7 +161,7 @@ export default function Header({
className={tabClass('learn')}
onClick={(e) => navLink('learn', e)}
>
Learn
{t('header.learn')}
</a>
{user?.subscription !== 'licensed' && !user?.isAdmin && (
<a
@ -166,7 +169,7 @@ export default function Header({
className={tabClass('pricing')}
onClick={(e) => navLink('pricing', e)}
>
Pricing
{t('header.pricing')}
</a>
)}
</nav>
@ -186,17 +189,17 @@ export default function Header({
{sharing ? (
<>
<SpinnerIcon className="w-4 h-4 animate-spin" />
Sharing...
{t('header.sharing')}
</>
) : copied ? (
<>
<CheckIcon className="w-4 h-4" />
Copied!
{t('common.copied')}
</>
) : (
<>
<ClipboardIcon className="w-4 h-4" />
Share
{t('common.share')}
</>
)}
</button>
@ -204,10 +207,10 @@ export default function Header({
onClick={onExport ?? undefined}
disabled={!onExport || exporting}
className="flex items-center gap-1.5 px-3 py-1.5 rounded bg-navy-800 hover:bg-navy-700 transition-colors text-sm disabled:opacity-50 disabled:cursor-wait"
title="Export to Excel"
title={t('header.exportToExcel')}
>
<DownloadIcon className="w-4 h-4" />
{exporting ? 'Exporting...' : 'Export'}
{exporting ? t('header.exporting') : t('header.exportLabel')}
</button>
{onSaveSearch && (
<button
@ -220,7 +223,7 @@ export default function Header({
) : (
<BookmarkIcon className="w-4 h-4" />
)}
Save
{t('common.save')}
</button>
)}
</>
@ -231,7 +234,7 @@ export default function Header({
className={tabClass('saved')}
onClick={(e) => navLink('saved', e)}
>
Saved
{t('header.saved')}
</a>
)}
@ -252,13 +255,13 @@ export default function Header({
onClick={onLoginClick}
className="px-3 py-1.5 rounded bg-navy-800 hover:bg-navy-700 transition-colors text-sm"
>
Log in
{t('header.logIn')}
</button>
<button
onClick={onRegisterClick}
className="px-3 py-1.5 rounded bg-teal-600 hover:bg-teal-700 transition-colors text-sm font-medium"
>
Create account
{t('header.createAccount')}
</button>
</>
)}
@ -271,16 +274,19 @@ export default function Header({
onClick={onRegisterClick}
className="px-4 py-1.5 rounded bg-teal-600 hover:bg-teal-700 transition-colors text-sm font-semibold"
>
Create account
{t('header.createAccount')}
</button>
)}
{/* Language selector (desktop) */}
{!isMobile && <LanguageDropdown />}
{/* Theme toggle (desktop, logged-out only — logged-in users use UserMenu) */}
{!isMobile && !user && (
<button
onClick={onToggleTheme}
className="flex items-center justify-center w-8 h-8 rounded bg-navy-800 hover:bg-navy-700 transition-colors"
title={`Theme: ${theme}`}
title={theme === 'light' ? t('userMenu.themeLight') : t('userMenu.themeDark')}
>
{theme === 'light' ? <SunIcon className="w-4 h-4" /> : <MoonIcon className="w-4 h-4" />}
</button>
@ -291,7 +297,7 @@ export default function Header({
<button
onClick={() => setMenuOpen(true)}
className="flex items-center justify-center w-10 h-10 -mr-2 rounded hover:bg-navy-800 transition-colors"
aria-label="Open menu"
aria-label={t('header.openMenu')}
>
<MenuIcon className="w-6 h-6" />
</button>
@ -322,7 +328,7 @@ export default function Header({
{isMobile && copied && (
<div className="fixed top-14 left-1/2 -translate-x-1/2 z-[60] flex items-center gap-2 px-4 py-2 rounded-lg bg-navy-900 text-white text-sm shadow-lg animate-fade-in">
<CheckIcon className="w-4 h-4 text-teal-400" />
Copied to clipboard
{t('common.copiedToClipboard')}
</div>
)}
</header>