"use client"; import Link from "next/link"; import { usePathname } from "next/navigation"; import { useEffect, useMemo, useState } from "react"; import { motion, AnimatePresence } from "framer-motion"; import { ArrowRight, Menu, X, Sparkles } from "lucide-react"; import { Button } from "@/components/ui/button"; import { LanguageSwitcher } from "./LanguageSwitcher"; import { useTranslation, getServerTranslations } from "@/lib/i18n"; import { cn } from "@/lib/utils"; export function Header() { const pathname = usePathname(); const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false); const [mounted, setMounted] = useState(false); const { t, locale, setLocale } = useTranslation(); useEffect(() => { setMounted(true); // Auto detect language on first mount if not manually set const stored = localStorage.getItem("locale-storage"); if (!stored) { const lang = navigator.language.toLowerCase(); if (lang.includes("zh")) setLocale("zh"); } }, [setLocale]); useEffect(() => { if (!mounted) return; document.documentElement.lang = locale; }, [locale, mounted]); // Prevent hydration mismatch by rendering a stable version initially const displayT = (key: string, params?: Record) => { if (!mounted) return getServerTranslations("en").t(key, params); return t(key, params); }; const navItems = useMemo( () => [ { name: displayT("sidebar.videoToFrames"), href: "/tools/video-frames" }, { name: displayT("sidebar.imageCompression"), href: "/tools/image-compress" }, { name: displayT("sidebar.audioCompression"), href: "/tools/audio-compress" }, { name: displayT("sidebar.textureAtlas"), href: "/tools/texture-atlas" }, ], // eslint-disable-next-line react-hooks/exhaustive-deps [mounted, locale] ); return (
{isMobileMenuOpen && (
{navItems.map((item) => ( setIsMobileMenuOpen(false)} className={cn( "rounded-xl px-3 py-2 text-sm font-medium transition-colors", pathname === item.href ? "bg-white/8 text-foreground" : "text-muted-foreground hover:bg-white/5 hover:text-foreground" )} > {item.name} ))}
{mounted && }
)}
); }