chore: normalize line endings

This commit is contained in:
Timo Knuth 2026-01-12 14:15:03 +01:00
parent 038c8dddbc
commit e0871e2960
8 changed files with 3697 additions and 3697 deletions

File diff suppressed because it is too large Load Diff

View File

@ -1,72 +1,72 @@
import React from 'react'; import React from 'react';
import type { Metadata } from 'next'; import type { Metadata } from 'next';
import SeoJsonLd from '@/components/SeoJsonLd'; import SeoJsonLd from '@/components/SeoJsonLd';
import { organizationSchema, websiteSchema } from '@/lib/schema'; import { organizationSchema, websiteSchema } from '@/lib/schema';
import HomePageClient from '@/components/marketing/HomePageClient'; import HomePageClient from '@/components/marketing/HomePageClient';
function truncateAtWord(text: string, maxLength: number): string { function truncateAtWord(text: string, maxLength: number): string {
if (text.length <= maxLength) return text; if (text.length <= maxLength) return text;
const truncated = text.slice(0, maxLength); const truncated = text.slice(0, maxLength);
const lastSpace = truncated.lastIndexOf(' '); const lastSpace = truncated.lastIndexOf(' ');
return lastSpace > 0 ? truncated.slice(0, lastSpace) : truncated; return lastSpace > 0 ? truncated.slice(0, lastSpace) : truncated;
} }
export async function generateMetadata(): Promise<Metadata> { export async function generateMetadata(): Promise<Metadata> {
const title = truncateAtWord('QR Master: Dynamic QR Generator', 60); const title = truncateAtWord('QR Master: Dynamic QR Generator', 60);
const description = truncateAtWord( const description = truncateAtWord(
'Dynamic QR, branding, bulk generation & analytics for all campaigns.', 'Dynamic QR, branding, bulk generation & analytics for all campaigns.',
160 160
); );
return { return {
title, title,
description, description,
alternates: { alternates: {
canonical: 'https://www.qrmaster.net/', canonical: 'https://www.qrmaster.net/',
languages: { languages: {
'x-default': 'https://www.qrmaster.net/', 'x-default': 'https://www.qrmaster.net/',
en: 'https://www.qrmaster.net/', en: 'https://www.qrmaster.net/',
de: 'https://www.qrmaster.net/qr-code-erstellen', de: 'https://www.qrmaster.net/qr-code-erstellen',
}, },
}, },
openGraph: { openGraph: {
title, title,
description, description,
url: 'https://www.qrmaster.net/', url: 'https://www.qrmaster.net/',
type: 'website', type: 'website',
}, },
twitter: { twitter: {
title, title,
description, description,
}, },
}; };
} }
export default function HomePage() { export default function HomePage() {
return ( return (
<> <>
<SeoJsonLd data={[organizationSchema(), websiteSchema()]} /> <SeoJsonLd data={[organizationSchema(), websiteSchema()]} />
{/* Server-rendered SEO content for crawlers */} {/* Server-rendered SEO content for crawlers */}
<div className="sr-only" aria-hidden="false"> <div className="sr-only" aria-hidden="false">
<h1>QR Master: Free Dynamic QR Code Generator with Tracking & Analytics</h1> <h1>QR Master: Free Dynamic QR Code Generator with Tracking & Analytics</h1>
<p> <p>
Create professional QR codes for your business with QR Master. Our dynamic QR code generator Create professional QR codes for your business with QR Master. Our dynamic QR code generator
lets you create trackable QR codes, edit destinations anytime, and view detailed analytics. lets you create trackable QR codes, edit destinations anytime, and view detailed analytics.
Perfect for restaurants, retail, events, and marketing campaigns. Perfect for restaurants, retail, events, and marketing campaigns.
</p> </p>
<p> <p>
Features include: Dynamic QR codes with real-time tracking, bulk QR code generation from Excel/CSV, Features include: Dynamic QR codes with real-time tracking, bulk QR code generation from Excel/CSV,
custom branding with colors and logos, advanced scan analytics showing device types and locations, custom branding with colors and logos, advanced scan analytics showing device types and locations,
vCard QR codes for digital business cards, and restaurant menu QR codes. vCard QR codes for digital business cards, and restaurant menu QR codes.
</p> </p>
<p> <p>
Start free with 3 dynamic QR codes and unlimited static codes. Upgrade to Pro for 50 codes Start free with 3 dynamic QR codes and unlimited static codes. Upgrade to Pro for 50 codes
with advanced analytics, or Business for 500 codes with bulk creation and priority support. with advanced analytics, or Business for 500 codes with bulk creation and priority support.
</p> </p>
</div> </div>
<HomePageClient /> <HomePageClient />
</> </>
); );
} }

View File

@ -1,44 +1,44 @@
'use client'; 'use client';
import React from 'react'; import React from 'react';
import AdBanner from '@/components/ads/AdBanner'; import AdBanner from '@/components/ads/AdBanner';
export default function ToolsLayout({ export default function ToolsLayout({
children, children,
}: { }: {
children: React.ReactNode; children: React.ReactNode;
}) { }) {
return ( return (
<div className="flex flex-col min-h-screen"> <div className="flex flex-col min-h-screen">
<div className="flex-grow relative"> <div className="flex-grow relative">
{children} {children}
{/* Desktop Sidebar Ad - High Resolution Only */} {/* Desktop Sidebar Ad - High Resolution Only */}
{/* Positioned absolute to the right, only visible on very wide screens (2xl) */} {/* Positioned absolute to the right, only visible on very wide screens (2xl) */}
<div className="hidden 2xl:block absolute right-4 top-32 w-[160px] z-10"> <div className="hidden 2xl:block absolute right-4 top-32 w-[160px] z-10">
<div className="sticky top-24"> <div className="sticky top-24">
<div className="text-center text-[10px] text-slate-300 mb-1">AD</div> <div className="text-center text-[10px] text-slate-300 mb-1">AD</div>
<AdBanner <AdBanner
dataAdSlot="sidebar-slot-id" dataAdSlot="sidebar-slot-id"
dataAdFormat="vertical" dataAdFormat="vertical"
className="min-h-[600px] w-[160px]" className="min-h-[600px] w-[160px]"
/> />
</div> </div>
</div> </div>
</div> </div>
{/* Footer Ad Placement - Appears on ALL tool pages */} {/* Footer Ad Placement - Appears on ALL tool pages */}
<div className="container mx-auto px-4 sm:px-6 lg:px-8 max-w-7xl pb-8"> <div className="container mx-auto px-4 sm:px-6 lg:px-8 max-w-7xl pb-8">
<div className="mx-auto max-w-4xl text-center text-xs text-slate-400 mb-2"> <div className="mx-auto max-w-4xl text-center text-xs text-slate-400 mb-2">
Sponsored Sponsored
</div> </div>
<AdBanner <AdBanner
dataAdSlot="1234567890" // Placeholder dataAdSlot="1234567890" // Placeholder
dataAdFormat="auto" dataAdFormat="auto"
fullWidthResponsive={true} fullWidthResponsive={true}
className="bg-slate-50 rounded-xl p-4 border border-slate-100 min-h-[100px]" className="bg-slate-50 rounded-xl p-4 border border-slate-100 min-h-[100px]"
/> />
</div> </div>
</div> </div>
); );
} }

View File

@ -1,248 +1,248 @@
'use client'; 'use client';
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import Link from 'next/link'; import Link from 'next/link';
import { usePathname } from 'next/navigation'; import { usePathname } from 'next/navigation';
import { Button } from '@/components/ui/Button'; import { Button } from '@/components/ui/Button';
import { Footer } from '@/components/ui/Footer'; import { Footer } from '@/components/ui/Footer';
import de from '@/i18n/de.json'; import de from '@/i18n/de.json';
import { ChevronDown, Wifi, Contact, MessageCircle, QrCode, Link2, Type, Mail, MessageSquare, Phone, Calendar, MapPin, Facebook, Instagram, Twitter, Youtube, Music, Bitcoin, CreditCard, Video, Users } from 'lucide-react'; import { ChevronDown, Wifi, Contact, MessageCircle, QrCode, Link2, Type, Mail, MessageSquare, Phone, Calendar, MapPin, Facebook, Instagram, Twitter, Youtube, Music, Bitcoin, CreditCard, Video, Users } from 'lucide-react';
import { cn } from '@/lib/utils'; import { cn } from '@/lib/utils';
import { AnimatePresence, motion } from 'framer-motion'; import { AnimatePresence, motion } from 'framer-motion';
export default function MarketingLayout({ export default function MarketingLayout({
children, children,
}: { }: {
children: React.ReactNode; children: React.ReactNode;
}) { }) {
const [mobileMenuOpen, setMobileMenuOpen] = useState(false); const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
const [scrolled, setScrolled] = useState(false); const [scrolled, setScrolled] = useState(false);
const [toolsOpen, setToolsOpen] = useState(false); const [toolsOpen, setToolsOpen] = useState(false);
const [mobileToolsOpen, setMobileToolsOpen] = useState(false); const [mobileToolsOpen, setMobileToolsOpen] = useState(false);
const pathname = usePathname(); const pathname = usePathname();
useEffect(() => { useEffect(() => {
const handleScroll = () => { const handleScroll = () => {
setScrolled(window.scrollY > 20); setScrolled(window.scrollY > 20);
}; };
// Check immediately on mount // Check immediately on mount
handleScroll(); handleScroll();
window.addEventListener('scroll', handleScroll, { passive: true }); window.addEventListener('scroll', handleScroll, { passive: true });
return () => window.removeEventListener('scroll', handleScroll); return () => window.removeEventListener('scroll', handleScroll);
}, []); }, []);
// Close simple menus when path changes // Close simple menus when path changes
useEffect(() => { useEffect(() => {
setMobileMenuOpen(false); setMobileMenuOpen(false);
setToolsOpen(false); setToolsOpen(false);
}, [pathname]); }, [pathname]);
// Always German for this layout // Always German for this layout
const t = de; const t = de;
const tools = [ const tools = [
{ name: 'URL / Link', description: 'Link to any website', href: '/tools/url-qr-code', icon: Link2, color: 'text-blue-500', bgColor: 'bg-blue-50' }, { name: 'URL / Link', description: 'Link to any website', href: '/tools/url-qr-code', icon: Link2, color: 'text-blue-500', bgColor: 'bg-blue-50' },
{ name: 'Text', description: 'Plain text message', href: '/tools/text-qr-code', icon: Type, color: 'text-slate-500', bgColor: 'bg-slate-50' }, { name: 'Text', description: 'Plain text message', href: '/tools/text-qr-code', icon: Type, color: 'text-slate-500', bgColor: 'bg-slate-50' },
{ name: 'WiFi', description: 'Share WiFi credentials', href: '/tools/wifi-qr-code', icon: Wifi, color: 'text-indigo-500', bgColor: 'bg-indigo-50' }, { name: 'WiFi', description: 'Share WiFi credentials', href: '/tools/wifi-qr-code', icon: Wifi, color: 'text-indigo-500', bgColor: 'bg-indigo-50' },
{ name: 'VCard', description: 'Digital business card', href: '/tools/vcard-qr-code', icon: Contact, color: 'text-pink-500', bgColor: 'bg-pink-50' }, { name: 'VCard', description: 'Digital business card', href: '/tools/vcard-qr-code', icon: Contact, color: 'text-pink-500', bgColor: 'bg-pink-50' },
{ name: 'WhatsApp', description: 'Start a chat', href: '/tools/whatsapp-qr-code', icon: MessageCircle, color: 'text-green-500', bgColor: 'bg-green-50' }, { name: 'WhatsApp', description: 'Start a chat', href: '/tools/whatsapp-qr-code', icon: MessageCircle, color: 'text-green-500', bgColor: 'bg-green-50' },
{ name: 'Email', description: 'Compose an email', href: '/tools/email-qr-code', icon: Mail, color: 'text-amber-500', bgColor: 'bg-amber-50' }, { name: 'Email', description: 'Compose an email', href: '/tools/email-qr-code', icon: Mail, color: 'text-amber-500', bgColor: 'bg-amber-50' },
{ name: 'SMS', description: 'Send a text message', href: '/tools/sms-qr-code', icon: MessageSquare, color: 'text-cyan-500', bgColor: 'bg-cyan-50' }, { name: 'SMS', description: 'Send a text message', href: '/tools/sms-qr-code', icon: MessageSquare, color: 'text-cyan-500', bgColor: 'bg-cyan-50' },
{ name: 'Phone', description: 'Start a call', href: '/tools/phone-qr-code', icon: Phone, color: 'text-violet-500', bgColor: 'bg-violet-50' }, { name: 'Phone', description: 'Start a call', href: '/tools/phone-qr-code', icon: Phone, color: 'text-violet-500', bgColor: 'bg-violet-50' },
{ name: 'Event', description: 'Add calendar event', href: '/tools/event-qr-code', icon: Calendar, color: 'text-red-500', bgColor: 'bg-red-50' }, { name: 'Event', description: 'Add calendar event', href: '/tools/event-qr-code', icon: Calendar, color: 'text-red-500', bgColor: 'bg-red-50' },
{ name: 'Location', description: 'Share a place', href: '/tools/geolocation-qr-code', icon: MapPin, color: 'text-emerald-500', bgColor: 'bg-emerald-50' }, { name: 'Location', description: 'Share a place', href: '/tools/geolocation-qr-code', icon: MapPin, color: 'text-emerald-500', bgColor: 'bg-emerald-50' },
{ name: 'Facebook', description: 'Facebook profile/page', href: '/tools/facebook-qr-code', icon: Facebook, color: 'text-blue-600', bgColor: 'bg-blue-50' }, { name: 'Facebook', description: 'Facebook profile/page', href: '/tools/facebook-qr-code', icon: Facebook, color: 'text-blue-600', bgColor: 'bg-blue-50' },
{ name: 'Instagram', description: 'Instagram profile', href: '/tools/instagram-qr-code', icon: Instagram, color: 'text-pink-600', bgColor: 'bg-pink-50' }, { name: 'Instagram', description: 'Instagram profile', href: '/tools/instagram-qr-code', icon: Instagram, color: 'text-pink-600', bgColor: 'bg-pink-50' },
{ name: 'Twitter / X', description: 'Twitter profile', href: '/tools/twitter-qr-code', icon: Twitter, color: 'text-sky-500', bgColor: 'bg-sky-50' }, { name: 'Twitter / X', description: 'Twitter profile', href: '/tools/twitter-qr-code', icon: Twitter, color: 'text-sky-500', bgColor: 'bg-sky-50' },
{ name: 'YouTube', description: 'YouTube video/channel', href: '/tools/youtube-qr-code', icon: Youtube, color: 'text-red-600', bgColor: 'bg-red-50' }, { name: 'YouTube', description: 'YouTube video/channel', href: '/tools/youtube-qr-code', icon: Youtube, color: 'text-red-600', bgColor: 'bg-red-50' },
{ name: 'TikTok', description: 'TikTok profile', href: '/tools/tiktok-qr-code', icon: Music, color: 'text-slate-800', bgColor: 'bg-slate-100' }, { name: 'TikTok', description: 'TikTok profile', href: '/tools/tiktok-qr-code', icon: Music, color: 'text-slate-800', bgColor: 'bg-slate-100' },
{ name: 'Crypto', description: 'Share wallet address', href: '/tools/crypto-qr-code', icon: Bitcoin, color: 'text-orange-500', bgColor: 'bg-orange-50' }, { name: 'Crypto', description: 'Share wallet address', href: '/tools/crypto-qr-code', icon: Bitcoin, color: 'text-orange-500', bgColor: 'bg-orange-50' },
{ name: 'PayPal', description: 'Receive payments', href: '/tools/paypal-qr-code', icon: CreditCard, color: 'text-blue-700', bgColor: 'bg-blue-50' }, { name: 'PayPal', description: 'Receive payments', href: '/tools/paypal-qr-code', icon: CreditCard, color: 'text-blue-700', bgColor: 'bg-blue-50' },
{ name: 'Zoom', description: 'Join Zoom meeting', href: '/tools/zoom-qr-code', icon: Video, color: 'text-sky-500', bgColor: 'bg-sky-50' }, { name: 'Zoom', description: 'Join Zoom meeting', href: '/tools/zoom-qr-code', icon: Video, color: 'text-sky-500', bgColor: 'bg-sky-50' },
{ name: 'Teams', description: 'Join Teams meeting', href: '/tools/teams-qr-code', icon: Users, color: 'text-violet-500', bgColor: 'bg-violet-50' }, { name: 'Teams', description: 'Join Teams meeting', href: '/tools/teams-qr-code', icon: Users, color: 'text-violet-500', bgColor: 'bg-violet-50' },
]; ];
return ( return (
<div className="min-h-screen bg-white"> <div className="min-h-screen bg-white">
{/* Header */} {/* Header */}
<header <header
className="fixed top-0 left-0 right-0 z-50 bg-white/80 backdrop-blur-md border-b border-slate-200 shadow-sm" className="fixed top-0 left-0 right-0 z-50 bg-white/80 backdrop-blur-md border-b border-slate-200 shadow-sm"
> >
<nav className="container mx-auto px-4 sm:px-6 lg:px-8 max-w-7xl h-20 flex items-center justify-between"> <nav className="container mx-auto px-4 sm:px-6 lg:px-8 max-w-7xl h-20 flex items-center justify-between">
{/* Logo */} {/* Logo */}
<Link href="/" className="flex items-center space-x-2.5 group"> <Link href="/" className="flex items-center space-x-2.5 group">
<div className="relative w-9 h-9 flex items-center justify-center bg-indigo-600 rounded-lg shadow-indigo-200 shadow-lg group-hover:scale-105 transition-transform duration-200"> <div className="relative w-9 h-9 flex items-center justify-center bg-indigo-600 rounded-lg shadow-indigo-200 shadow-lg group-hover:scale-105 transition-transform duration-200">
<QrCode className="w-5 h-5 text-white" /> <QrCode className="w-5 h-5 text-white" />
</div> </div>
<span className="text-xl font-bold text-slate-900 tracking-tight group-hover:text-indigo-600 transition-colors">QR Master</span> <span className="text-xl font-bold text-slate-900 tracking-tight group-hover:text-indigo-600 transition-colors">QR Master</span>
</Link> </Link>
{/* Desktop Navigation */} {/* Desktop Navigation */}
<div className="hidden md:flex items-center space-x-1"> <div className="hidden md:flex items-center space-x-1">
{/* Tools Dropdown */} {/* Tools Dropdown */}
<div <div
className="relative group px-3 py-2" className="relative group px-3 py-2"
onMouseEnter={() => setToolsOpen(true)} onMouseEnter={() => setToolsOpen(true)}
onMouseLeave={() => setToolsOpen(false)} onMouseLeave={() => setToolsOpen(false)}
> >
<button className="flex items-center space-x-1 text-sm font-medium text-slate-600 group-hover:text-slate-900 transition-colors"> <button className="flex items-center space-x-1 text-sm font-medium text-slate-600 group-hover:text-slate-900 transition-colors">
<span>{t.nav.tools}</span> <span>{t.nav.tools}</span>
<ChevronDown className={cn("w-4 h-4 transition-transform duration-200", toolsOpen && "rotate-180")} /> <ChevronDown className={cn("w-4 h-4 transition-transform duration-200", toolsOpen && "rotate-180")} />
</button> </button>
<AnimatePresence> <AnimatePresence>
{toolsOpen && ( {toolsOpen && (
<motion.div <motion.div
initial={{ opacity: 0, y: 10 }} initial={{ opacity: 0, y: 10 }}
animate={{ opacity: 1, y: 0 }} animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: 10 }} exit={{ opacity: 0, y: 10 }}
transition={{ duration: 0.15 }} transition={{ duration: 0.15 }}
className="absolute left-1/2 -translate-x-1/2 top-full mt-2 w-[750px] bg-white rounded-2xl shadow-lg border border-slate-100 p-4 overflow-hidden" className="absolute left-1/2 -translate-x-1/2 top-full mt-2 w-[750px] bg-white rounded-2xl shadow-lg border border-slate-100 p-4 overflow-hidden"
> >
<div className="grid grid-cols-3 gap-1"> <div className="grid grid-cols-3 gap-1">
{tools.map((tool) => ( {tools.map((tool) => (
<Link <Link
key={tool.name} key={tool.name}
href={tool.href} href={tool.href}
className="flex items-center space-x-3 p-2.5 rounded-xl transition-colors hover:bg-slate-50" className="flex items-center space-x-3 p-2.5 rounded-xl transition-colors hover:bg-slate-50"
> >
<div className={cn("p-2 rounded-lg shrink-0", tool.bgColor, tool.color)}> <div className={cn("p-2 rounded-lg shrink-0", tool.bgColor, tool.color)}>
<tool.icon className="w-4 h-4" /> <tool.icon className="w-4 h-4" />
</div> </div>
<div> <div>
<div className="text-sm font-semibold text-slate-900">{tool.name}</div> <div className="text-sm font-semibold text-slate-900">{tool.name}</div>
<p className="text-xs text-slate-500 leading-snug">{tool.description}</p> <p className="text-xs text-slate-500 leading-snug">{tool.description}</p>
</div> </div>
</Link> </Link>
))} ))}
</div> </div>
<div className="mt-3 pt-3 border-t border-slate-100 -mx-4 -mb-4 px-4 py-3 text-center bg-slate-50/50"> <div className="mt-3 pt-3 border-t border-slate-100 -mx-4 -mb-4 px-4 py-3 text-center bg-slate-50/50">
<p className="text-xs text-slate-500 font-medium">{t.nav.all_free}</p> <p className="text-xs text-slate-500 font-medium">{t.nav.all_free}</p>
</div> </div>
</motion.div> </motion.div>
)} )}
</AnimatePresence> </AnimatePresence>
</div> </div>
<Link href="/#features" className="px-3 py-2 text-sm font-medium text-slate-600 hover:text-slate-900 transition-colors"> <Link href="/#features" className="px-3 py-2 text-sm font-medium text-slate-600 hover:text-slate-900 transition-colors">
{t.nav.features} {t.nav.features}
</Link> </Link>
<Link href="/#pricing" className="px-3 py-2 text-sm font-medium text-slate-600 hover:text-slate-900 transition-colors"> <Link href="/#pricing" className="px-3 py-2 text-sm font-medium text-slate-600 hover:text-slate-900 transition-colors">
{t.nav.pricing} {t.nav.pricing}
</Link> </Link>
<Link href="/blog" className="px-3 py-2 text-sm font-medium text-slate-600 hover:text-slate-900 transition-colors"> <Link href="/blog" className="px-3 py-2 text-sm font-medium text-slate-600 hover:text-slate-900 transition-colors">
{t.nav.blog} {t.nav.blog}
</Link> </Link>
<Link href="/#faq" className="px-3 py-2 text-sm font-medium text-slate-600 hover:text-slate-900 transition-colors"> <Link href="/#faq" className="px-3 py-2 text-sm font-medium text-slate-600 hover:text-slate-900 transition-colors">
{t.nav.faq} {t.nav.faq}
</Link> </Link>
</div> </div>
<div className="hidden md:flex items-center space-x-4"> <div className="hidden md:flex items-center space-x-4">
<Link href="/login" className="text-sm font-medium text-slate-600 hover:text-slate-900 transition-colors"> <Link href="/login" className="text-sm font-medium text-slate-600 hover:text-slate-900 transition-colors">
{t.nav.login} {t.nav.login}
</Link> </Link>
<Link href="/signup"> <Link href="/signup">
<Button className={cn( <Button className={cn(
"font-semibold shadow-lg shadow-indigo-500/20 transition-all hover:scale-105", "font-semibold shadow-lg shadow-indigo-500/20 transition-all hover:scale-105",
scrolled ? "bg-blue-600 text-white hover:bg-blue-700" : "bg-blue-600 text-white hover:bg-blue-700" scrolled ? "bg-blue-600 text-white hover:bg-blue-700" : "bg-blue-600 text-white hover:bg-blue-700"
)}> )}>
{t.nav.cta || "Get Started Free"} {t.nav.cta || "Get Started Free"}
</Button> </Button>
</Link> </Link>
</div> </div>
{/* Mobile Menu Button - Always dark */} {/* Mobile Menu Button - Always dark */}
<button <button
className="md:hidden p-2 text-slate-900" className="md:hidden p-2 text-slate-900"
onClick={() => setMobileMenuOpen(!mobileMenuOpen)} onClick={() => setMobileMenuOpen(!mobileMenuOpen)}
aria-label="Toggle menu" aria-label="Toggle menu"
> >
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
{mobileMenuOpen ? ( {mobileMenuOpen ? (
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" /> <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
) : ( ) : (
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 6h16M4 12h16M4 18h16" /> <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 6h16M4 12h16M4 18h16" />
)} )}
</svg> </svg>
</button> </button>
</nav> </nav>
{/* Mobile Menu */} {/* Mobile Menu */}
<AnimatePresence> <AnimatePresence>
{mobileMenuOpen && ( {mobileMenuOpen && (
<motion.div <motion.div
initial={{ opacity: 0, height: 0 }} initial={{ opacity: 0, height: 0 }}
animate={{ opacity: 1, height: 'auto' }} animate={{ opacity: 1, height: 'auto' }}
exit={{ opacity: 0, height: 0 }} exit={{ opacity: 0, height: 0 }}
className="md:hidden bg-white border-b border-slate-100 overflow-hidden" className="md:hidden bg-white border-b border-slate-100 overflow-hidden"
> >
<div className="container mx-auto px-4 py-6 space-y-2"> <div className="container mx-auto px-4 py-6 space-y-2">
{/* Free Tools Accordion */} {/* Free Tools Accordion */}
<button <button
onClick={() => setMobileToolsOpen(!mobileToolsOpen)} onClick={() => setMobileToolsOpen(!mobileToolsOpen)}
className="flex items-center justify-between w-full px-4 py-3 rounded-xl hover:bg-slate-50 text-slate-700 font-semibold" className="flex items-center justify-between w-full px-4 py-3 rounded-xl hover:bg-slate-50 text-slate-700 font-semibold"
> >
<span>{t.nav.tools}</span> <span>{t.nav.tools}</span>
<ChevronDown className={cn("w-5 h-5 transition-transform", mobileToolsOpen && "rotate-180")} /> <ChevronDown className={cn("w-5 h-5 transition-transform", mobileToolsOpen && "rotate-180")} />
</button> </button>
<AnimatePresence> <AnimatePresence>
{mobileToolsOpen && ( {mobileToolsOpen && (
<motion.div <motion.div
initial={{ opacity: 0, height: 0 }} initial={{ opacity: 0, height: 0 }}
animate={{ opacity: 1, height: 'auto' }} animate={{ opacity: 1, height: 'auto' }}
exit={{ opacity: 0, height: 0 }} exit={{ opacity: 0, height: 0 }}
className="overflow-hidden" className="overflow-hidden"
> >
<div className="max-h-[50vh] overflow-y-auto pl-4 space-y-1 border-l-2 border-slate-100 ml-4"> <div className="max-h-[50vh] overflow-y-auto pl-4 space-y-1 border-l-2 border-slate-100 ml-4">
{tools.map((tool) => ( {tools.map((tool) => (
<Link <Link
key={tool.name} key={tool.name}
href={tool.href} href={tool.href}
className="flex items-center gap-3 px-4 py-2.5 rounded-lg hover:bg-slate-50 text-slate-600 text-sm" className="flex items-center gap-3 px-4 py-2.5 rounded-lg hover:bg-slate-50 text-slate-600 text-sm"
onClick={() => { setMobileMenuOpen(false); setMobileToolsOpen(false); }} onClick={() => { setMobileMenuOpen(false); setMobileToolsOpen(false); }}
> >
<tool.icon className={cn("w-4 h-4", tool.color)} /> <tool.icon className={cn("w-4 h-4", tool.color)} />
{tool.name} {tool.name}
</Link> </Link>
))} ))}
</div> </div>
</motion.div> </motion.div>
)} )}
</AnimatePresence> </AnimatePresence>
<div className="h-px bg-slate-100 my-2"></div> <div className="h-px bg-slate-100 my-2"></div>
<Link href="/#features" className="block px-4 py-3 text-slate-700 font-medium rounded-xl hover:bg-slate-50" onClick={() => setMobileMenuOpen(false)}>{t.nav.features}</Link> <Link href="/#features" className="block px-4 py-3 text-slate-700 font-medium rounded-xl hover:bg-slate-50" onClick={() => setMobileMenuOpen(false)}>{t.nav.features}</Link>
<Link href="/#pricing" className="block px-4 py-3 text-slate-700 font-medium rounded-xl hover:bg-slate-50" onClick={() => setMobileMenuOpen(false)}>{t.nav.pricing}</Link> <Link href="/#pricing" className="block px-4 py-3 text-slate-700 font-medium rounded-xl hover:bg-slate-50" onClick={() => setMobileMenuOpen(false)}>{t.nav.pricing}</Link>
<Link href="/blog" className="block px-4 py-3 text-slate-700 font-medium rounded-xl hover:bg-slate-50" onClick={() => setMobileMenuOpen(false)}>{t.nav.blog}</Link> <Link href="/blog" className="block px-4 py-3 text-slate-700 font-medium rounded-xl hover:bg-slate-50" onClick={() => setMobileMenuOpen(false)}>{t.nav.blog}</Link>
<Link href="/#faq" className="block px-4 py-3 text-slate-700 font-medium rounded-xl hover:bg-slate-50" onClick={() => setMobileMenuOpen(false)}>{t.nav.faq}</Link> <Link href="/#faq" className="block px-4 py-3 text-slate-700 font-medium rounded-xl hover:bg-slate-50" onClick={() => setMobileMenuOpen(false)}>{t.nav.faq}</Link>
<div className="grid grid-cols-2 gap-4 pt-4"> <div className="grid grid-cols-2 gap-4 pt-4">
<Link href="/login" onClick={() => setMobileMenuOpen(false)}> <Link href="/login" onClick={() => setMobileMenuOpen(false)}>
<Button variant="outline" className="w-full justify-center">{t.nav.login}</Button> <Button variant="outline" className="w-full justify-center">{t.nav.login}</Button>
</Link> </Link>
<Link href="/signup" onClick={() => setMobileMenuOpen(false)}> <Link href="/signup" onClick={() => setMobileMenuOpen(false)}>
<Button className="w-full justify-center bg-indigo-600 hover:bg-indigo-700">{t.nav.cta}</Button> <Button className="w-full justify-center bg-indigo-600 hover:bg-indigo-700">{t.nav.cta}</Button>
</Link> </Link>
</div> </div>
</div> </div>
</motion.div> </motion.div>
)} )}
</AnimatePresence> </AnimatePresence>
</header> </header>
{/* Main Content */} {/* Main Content */}
<main className="pt-20">{children}</main> <main className="pt-20">{children}</main>
{/* Footer */} {/* Footer */}
<Footer t={t} /> <Footer t={t} />
</div > </div >
); );
} }

View File

@ -1,108 +1,108 @@
import React from 'react'; import React from 'react';
import type { Metadata } from 'next'; import type { Metadata } from 'next';
import SeoJsonLd from '@/components/SeoJsonLd'; import SeoJsonLd from '@/components/SeoJsonLd';
import { organizationSchema, websiteSchema } from '@/lib/schema'; import { organizationSchema, websiteSchema } from '@/lib/schema';
import { Hero } from '@/components/marketing/Hero'; import { Hero } from '@/components/marketing/Hero';
import { InstantGenerator } from '@/components/marketing/InstantGenerator'; import { InstantGenerator } from '@/components/marketing/InstantGenerator';
import { StaticVsDynamic } from '@/components/marketing/StaticVsDynamic'; import { StaticVsDynamic } from '@/components/marketing/StaticVsDynamic';
import { Features } from '@/components/marketing/Features'; import { Features } from '@/components/marketing/Features';
import { Pricing } from '@/components/marketing/Pricing'; import { Pricing } from '@/components/marketing/Pricing';
import { FAQ } from '@/components/marketing/FAQ'; import { FAQ } from '@/components/marketing/FAQ';
import { ScrollToTop } from '@/components/ui/ScrollToTop'; import { ScrollToTop } from '@/components/ui/ScrollToTop';
import de from '@/i18n/de.json'; import de from '@/i18n/de.json';
function truncateAtWord(text: string, maxLength: number): string { function truncateAtWord(text: string, maxLength: number): string {
if (text.length <= maxLength) return text; if (text.length <= maxLength) return text;
const truncated = text.slice(0, maxLength); const truncated = text.slice(0, maxLength);
const lastSpace = truncated.lastIndexOf(' '); const lastSpace = truncated.lastIndexOf(' ');
return lastSpace > 0 ? truncated.slice(0, lastSpace) : truncated; return lastSpace > 0 ? truncated.slice(0, lastSpace) : truncated;
} }
export async function generateMetadata(): Promise<Metadata> { export async function generateMetadata(): Promise<Metadata> {
const title = truncateAtWord('QR Code Erstellen Kostenlos & Sofort | QR Master', 60); const title = truncateAtWord('QR Code Erstellen Kostenlos & Sofort | QR Master', 60);
const description = truncateAtWord( const description = truncateAtWord(
'Erstellen Sie QR Codes kostenlos in Sekunden. Statische und dynamische QR-Codes mit Tracking, individuellem Branding und Massen-Erstellung. Für immer kostenlos.', 'Erstellen Sie QR Codes kostenlos in Sekunden. Statische und dynamische QR-Codes mit Tracking, individuellem Branding und Massen-Erstellung. Für immer kostenlos.',
160 160
); );
return { return {
title, title,
description, description,
keywords: [ keywords: [
'qr code erstellen', 'qr code erstellen',
'qr code generator', 'qr code generator',
'qr code kostenlos', 'qr code kostenlos',
'qr-code-generatoren', 'qr-code-generatoren',
'qr codes erstellen', 'qr codes erstellen',
'qr code erstellen kostenlos', 'qr code erstellen kostenlos',
'dynamischer qr code', 'dynamischer qr code',
'qr code mit logo' 'qr code mit logo'
], ],
alternates: { alternates: {
canonical: 'https://www.qrmaster.net/qr-code-erstellen', canonical: 'https://www.qrmaster.net/qr-code-erstellen',
languages: { languages: {
'x-default': 'https://www.qrmaster.net/', 'x-default': 'https://www.qrmaster.net/',
en: 'https://www.qrmaster.net/', en: 'https://www.qrmaster.net/',
de: 'https://www.qrmaster.net/qr-code-erstellen', de: 'https://www.qrmaster.net/qr-code-erstellen',
}, },
}, },
openGraph: { openGraph: {
title: 'QR Code Erstellen Kostenlos & Sofort | QR Master', title: 'QR Code Erstellen Kostenlos & Sofort | QR Master',
description: 'Erstellen Sie QR Codes kostenlos in Sekunden. Mit Tracking, Branding und Massen-Erstellung.', description: 'Erstellen Sie QR Codes kostenlos in Sekunden. Mit Tracking, Branding und Massen-Erstellung.',
url: 'https://www.qrmaster.net/qr-code-erstellen', url: 'https://www.qrmaster.net/qr-code-erstellen',
type: 'website', type: 'website',
locale: 'de_DE', locale: 'de_DE',
}, },
twitter: { twitter: {
title: 'QR Code Erstellen Kostenlos | QR Master', title: 'QR Code Erstellen Kostenlos | QR Master',
description: 'QR Codes erstellen in Sekunden. Kostenlos, mit Tracking und individuellem Branding.', description: 'QR Codes erstellen in Sekunden. Kostenlos, mit Tracking und individuellem Branding.',
}, },
}; };
} }
export default function QRCodeErstellenPage() { export default function QRCodeErstellenPage() {
// Use German translations // Use German translations
const t = de; const t = de;
return ( return (
<> <>
<SeoJsonLd data={[organizationSchema(), websiteSchema()]} /> <SeoJsonLd data={[organizationSchema(), websiteSchema()]} />
{/* Server-rendered SEO content for crawlers - GERMAN */} {/* Server-rendered SEO content for crawlers - GERMAN */}
<div className="sr-only" aria-hidden="false"> <div className="sr-only" aria-hidden="false">
<h1>QR Code Erstellen Kostenloser QR Code Generator mit Tracking & Statistiken</h1> <h1>QR Code Erstellen Kostenloser QR Code Generator mit Tracking & Statistiken</h1>
<p> <p>
Erstellen Sie professionelle QR Codes für Ihr Unternehmen mit QR Master. Unser dynamischer QR Code Generator Erstellen Sie professionelle QR Codes für Ihr Unternehmen mit QR Master. Unser dynamischer QR Code Generator
ermöglicht es Ihnen, trackbare QR Codes zu erstellen, Ziel-URLs jederzeit zu ändern und detaillierte Statistiken einzusehen. ermöglicht es Ihnen, trackbare QR Codes zu erstellen, Ziel-URLs jederzeit zu ändern und detaillierte Statistiken einzusehen.
Perfekt für Restaurants, Einzelhandel, Events und Marketing-Kampagnen. Perfekt für Restaurants, Einzelhandel, Events und Marketing-Kampagnen.
</p> </p>
<p> <p>
Funktionen: Dynamische QR Codes mit Echtzeit-Tracking, Massen-QR-Code-Erstellung aus Excel/CSV, Funktionen: Dynamische QR Codes mit Echtzeit-Tracking, Massen-QR-Code-Erstellung aus Excel/CSV,
individuelles Branding mit Farben und Logos, erweiterte Scan-Statistiken mit Gerätetypen und Standorten, individuelles Branding mit Farben und Logos, erweiterte Scan-Statistiken mit Gerätetypen und Standorten,
vCard QR Codes für digitale Visitenkarten und QR Codes für Restaurant-Speisekarten. vCard QR Codes für digitale Visitenkarten und QR Codes für Restaurant-Speisekarten.
</p> </p>
<p> <p>
Starten Sie kostenlos mit 3 dynamischen QR Codes und unbegrenzten statischen Codes. Upgrade auf Pro für 50 Codes Starten Sie kostenlos mit 3 dynamischen QR Codes und unbegrenzten statischen Codes. Upgrade auf Pro für 50 Codes
mit erweiterten Statistiken, oder Business für 500 Codes mit Massen-Erstellung und Prioritäts-Support. mit erweiterten Statistiken, oder Business für 500 Codes mit Massen-Erstellung und Prioritäts-Support.
</p> </p>
</div> </div>
<Hero t={t} /> <Hero t={t} />
{/* Main Interaction: Generator */} {/* Main Interaction: Generator */}
<InstantGenerator t={t} /> <InstantGenerator t={t} />
<StaticVsDynamic t={t} /> <StaticVsDynamic t={t} />
<Features t={t} /> <Features t={t} />
{/* Pricing Section */} {/* Pricing Section */}
<Pricing t={t} /> <Pricing t={t} />
{/* FAQ Section */} {/* FAQ Section */}
<FAQ t={t} /> <FAQ t={t} />
{/* Scroll to Top Button */} {/* Scroll to Top Button */}
<ScrollToTop /> <ScrollToTop />
</> </>
); );
} }

View File

@ -1,136 +1,136 @@
import type { Metadata } from 'next'; import type { Metadata } from 'next';
import { Suspense } from 'react'; import { Suspense } from 'react';
import '@/styles/globals.css'; import '@/styles/globals.css';
import { ToastContainer } from '@/components/ui/Toast'; import { ToastContainer } from '@/components/ui/Toast';
import AuthProvider from '@/components/SessionProvider'; import AuthProvider from '@/components/SessionProvider';
import { PostHogProvider } from '@/components/PostHogProvider'; import { PostHogProvider } from '@/components/PostHogProvider';
import CookieBanner from '@/components/CookieBanner'; import CookieBanner from '@/components/CookieBanner';
const isIndexable = process.env.NEXT_PUBLIC_INDEXABLE === 'true'; const isIndexable = process.env.NEXT_PUBLIC_INDEXABLE === 'true';
// Organization Schema for all pages // Organization Schema for all pages
const organizationSchema = { const organizationSchema = {
'@context': 'https://schema.org', '@context': 'https://schema.org',
'@type': 'Organization', '@type': 'Organization',
'@id': 'https://www.qrmaster.net/#organization', '@id': 'https://www.qrmaster.net/#organization',
name: 'QR Master', name: 'QR Master',
alternateName: 'QRMaster', alternateName: 'QRMaster',
url: 'https://www.qrmaster.net', url: 'https://www.qrmaster.net',
logo: { logo: {
'@type': 'ImageObject', '@type': 'ImageObject',
url: 'https://www.qrmaster.net/static/og-image.png', url: 'https://www.qrmaster.net/static/og-image.png',
width: 1200, width: 1200,
height: 630, height: 630,
}, },
image: 'https://www.qrmaster.net/static/og-image.png', image: 'https://www.qrmaster.net/static/og-image.png',
sameAs: ['https://twitter.com/qrmaster'], sameAs: ['https://twitter.com/qrmaster'],
contactPoint: { contactPoint: {
'@type': 'ContactPoint', '@type': 'ContactPoint',
contactType: 'Customer Support', contactType: 'Customer Support',
email: 'support@qrmaster.net', email: 'support@qrmaster.net',
availableLanguage: ['English', 'German'], availableLanguage: ['English', 'German'],
}, },
description: 'B2B SaaS platform for dynamic QR code generation with analytics, branding, and bulk generation for enterprise marketing campaigns.', description: 'B2B SaaS platform for dynamic QR code generation with analytics, branding, and bulk generation for enterprise marketing campaigns.',
slogan: 'Dynamic QR codes that work smarter', slogan: 'Dynamic QR codes that work smarter',
foundingDate: '2025', foundingDate: '2025',
areaServed: 'Worldwide', areaServed: 'Worldwide',
serviceType: 'Software as a Service', serviceType: 'Software as a Service',
priceRange: '$0 - $29', priceRange: '$0 - $29',
}; };
// Website Schema for all pages // Website Schema for all pages
const websiteSchema = { const websiteSchema = {
'@context': 'https://schema.org', '@context': 'https://schema.org',
'@type': 'WebSite', '@type': 'WebSite',
'@id': 'https://www.qrmaster.net/#website', '@id': 'https://www.qrmaster.net/#website',
name: 'QR Master', name: 'QR Master',
url: 'https://www.qrmaster.net', url: 'https://www.qrmaster.net',
inLanguage: 'en', inLanguage: 'en',
publisher: { '@id': 'https://www.qrmaster.net/#organization' }, publisher: { '@id': 'https://www.qrmaster.net/#organization' },
potentialAction: { potentialAction: {
'@type': 'SearchAction', '@type': 'SearchAction',
target: { target: {
'@type': 'EntryPoint', '@type': 'EntryPoint',
urlTemplate: 'https://www.qrmaster.net/blog?q={search_term_string}', urlTemplate: 'https://www.qrmaster.net/blog?q={search_term_string}',
}, },
'query-input': 'required name=search_term_string', 'query-input': 'required name=search_term_string',
}, },
}; };
export const metadata: Metadata = { export const metadata: Metadata = {
metadataBase: new URL('https://www.qrmaster.net'), metadataBase: new URL('https://www.qrmaster.net'),
title: { title: {
default: 'QR Master Smart QR Generator & Analytics', default: 'QR Master Smart QR Generator & Analytics',
template: '%s | QR Master', template: '%s | QR Master',
}, },
description: 'Create dynamic QR codes, track scans, and scale campaigns with secure analytics.', description: 'Create dynamic QR codes, track scans, and scale campaigns with secure analytics.',
keywords: 'QR code, QR generator, dynamic QR, QR tracking, QR analytics, branded QR, bulk QR generator', keywords: 'QR code, QR generator, dynamic QR, QR tracking, QR analytics, branded QR, bulk QR generator',
robots: isIndexable robots: isIndexable
? { index: true, follow: true } ? { index: true, follow: true }
: { index: false, follow: false }, : { index: false, follow: false },
icons: { icons: {
icon: [ icon: [
{ url: '/favicon.svg', type: 'image/svg+xml' }, { url: '/favicon.svg', type: 'image/svg+xml' },
{ url: '/logo.svg', type: 'image/svg+xml' }, { url: '/logo.svg', type: 'image/svg+xml' },
], ],
apple: '/logo.svg', apple: '/logo.svg',
}, },
twitter: { twitter: {
card: 'summary_large_image', card: 'summary_large_image',
site: '@qrmaster', site: '@qrmaster',
images: ['https://www.qrmaster.net/static/og-image.png'], images: ['https://www.qrmaster.net/static/og-image.png'],
}, },
openGraph: { openGraph: {
type: 'website', type: 'website',
siteName: 'QR Master', siteName: 'QR Master',
title: 'QR Master Smart QR Generator & Analytics', title: 'QR Master Smart QR Generator & Analytics',
description: 'Create dynamic QR codes, track scans, and scale campaigns with secure analytics.', description: 'Create dynamic QR codes, track scans, and scale campaigns with secure analytics.',
url: 'https://www.qrmaster.net', url: 'https://www.qrmaster.net',
images: [ images: [
{ {
url: 'https://www.qrmaster.net/static/og-image.png', url: 'https://www.qrmaster.net/static/og-image.png',
width: 1200, width: 1200,
height: 630, height: 630,
alt: 'QR Master - Dynamic QR Code Generator and Analytics Platform', alt: 'QR Master - Dynamic QR Code Generator and Analytics Platform',
}, },
], ],
locale: 'en_US', locale: 'en_US',
}, },
}; };
export default function RootLayout({ export default function RootLayout({
children, children,
}: { }: {
children: React.ReactNode; children: React.ReactNode;
}) { }) {
return ( return (
<html lang="en"> <html lang="en">
<head> <head>
<script <script
type="application/ld+json" type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(organizationSchema) }} dangerouslySetInnerHTML={{ __html: JSON.stringify(organizationSchema) }}
/> />
<script <script
type="application/ld+json" type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(websiteSchema) }} dangerouslySetInnerHTML={{ __html: JSON.stringify(websiteSchema) }}
/> />
<script <script
async async
src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-2782770414424875" src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-2782770414424875"
crossOrigin="anonymous" crossOrigin="anonymous"
/> />
</head> </head>
<body className="font-sans"> <body className="font-sans">
<Suspense fallback={null}> <Suspense fallback={null}>
<PostHogProvider> <PostHogProvider>
<AuthProvider> <AuthProvider>
{children} {children}
</AuthProvider> </AuthProvider>
<CookieBanner /> <CookieBanner />
<ToastContainer /> <ToastContainer />
</PostHogProvider> </PostHogProvider>
</Suspense> </Suspense>
</body> </body>
</html> </html>
); );
} }

View File

@ -1,59 +1,59 @@
'use client'; 'use client';
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import { useSession } from 'next-auth/react'; import { useSession } from 'next-auth/react';
interface AdBannerProps { interface AdBannerProps {
dataAdSlot: string; dataAdSlot: string;
dataAdFormat?: string; dataAdFormat?: string;
fullWidthResponsive?: boolean; fullWidthResponsive?: boolean;
className?: string; className?: string;
} }
export default function AdBanner({ export default function AdBanner({
dataAdSlot, dataAdSlot,
dataAdFormat = 'auto', dataAdFormat = 'auto',
fullWidthResponsive = true, fullWidthResponsive = true,
className = '', className = '',
}: AdBannerProps) { }: AdBannerProps) {
const { data: session, status } = useSession(); const { data: session, status } = useSession();
// Check if user has a paid plan // Check if user has a paid plan
// Adjust 'pro' or 'premium' based on your actual plan values // Adjust 'pro' or 'premium' based on your actual plan values
const isPaidUser = session?.user && ( const isPaidUser = session?.user && (
session.user.plan === 'PRO' || session.user.plan === 'PRO' ||
session.user.plan === 'PREMIUM' || session.user.plan === 'PREMIUM' ||
session.user.plan === 'LIFETIME' session.user.plan === 'LIFETIME'
); );
const [adLoaded, setAdLoaded] = useState(false); const [adLoaded, setAdLoaded] = useState(false);
useEffect(() => { useEffect(() => {
// Don't load if loading session or if user is paid // Don't load if loading session or if user is paid
if (status === 'loading' || isPaidUser) return; if (status === 'loading' || isPaidUser) return;
try { try {
// @ts-ignore // @ts-ignore
(window.adsbygoogle = window.adsbygoogle || []).push({}); (window.adsbygoogle = window.adsbygoogle || []).push({});
setAdLoaded(true); setAdLoaded(true);
} catch (err) { } catch (err) {
console.error('AdSense error:', err); console.error('AdSense error:', err);
} }
}, [isPaidUser, status]); }, [isPaidUser, status]);
// Don't render anything if paid user // Don't render anything if paid user
if (status === 'authenticated' && isPaidUser) return null; if (status === 'authenticated' && isPaidUser) return null;
return ( return (
<div className={`ad-container my-8 flex justify-center items-center overflow-hidden ${className}`} aria-hidden={true}> <div className={`ad-container my-8 flex justify-center items-center overflow-hidden ${className}`} aria-hidden={true}>
<ins <ins
className="adsbygoogle" className="adsbygoogle"
style={{ display: 'block', minWidth: '300px', minHeight: '50px', width: '100%' }} style={{ display: 'block', minWidth: '300px', minHeight: '50px', width: '100%' }}
data-ad-client="ca-pub-2782770414424875" data-ad-client="ca-pub-2782770414424875"
data-ad-slot={dataAdSlot} data-ad-slot={dataAdSlot}
data-ad-format={dataAdFormat} data-ad-format={dataAdFormat}
data-full-width-responsive={fullWidthResponsive} data-full-width-responsive={fullWidthResponsive}
/> />
</div> </div>
); );
} }

View File

@ -1,400 +1,400 @@
{ {
"nav": { "nav": {
"features": "Funktionen", "features": "Funktionen",
"pricing": "Preise", "pricing": "Preise",
"faq": "FAQ", "faq": "FAQ",
"blog": "Blog", "blog": "Blog",
"login": "Anmelden", "login": "Anmelden",
"dashboard": "Dashboard", "dashboard": "Dashboard",
"create_qr": "QR erstellen", "create_qr": "QR erstellen",
"bulk_creation": "Massen-Erstellung", "bulk_creation": "Massen-Erstellung",
"analytics": "Analytik", "analytics": "Analytik",
"settings": "Einstellungen", "settings": "Einstellungen",
"cta": "Kostenlos loslegen", "cta": "Kostenlos loslegen",
"tools": "Kostenlose Tools", "tools": "Kostenlose Tools",
"all_free": "Alle Generatoren sind 100% kostenlos" "all_free": "Alle Generatoren sind 100% kostenlos"
}, },
"hero": { "hero": {
"badge": "Kostenloser QR-Code-Generator", "badge": "Kostenloser QR-Code-Generator",
"title": "Erstellen Sie QR-Codes, die überall funktionieren", "title": "Erstellen Sie QR-Codes, die überall funktionieren",
"subtitle": "Generieren Sie statische und dynamische QR-Codes mit Tracking, individuellem Branding und Massen-Erstellung. Kostenlos für immer.", "subtitle": "Generieren Sie statische und dynamische QR-Codes mit Tracking, individuellem Branding und Massen-Erstellung. Kostenlos für immer.",
"features": [ "features": [
"Keine Kreditkarte zum Starten erforderlich", "Keine Kreditkarte zum Starten erforderlich",
"QR-Codes für immer kostenlos erstellen", "QR-Codes für immer kostenlos erstellen",
"Erweiterte Verfolgung und Analytik", "Erweiterte Verfolgung und Analytik",
"Individuelle Farben und Stile" "Individuelle Farben und Stile"
], ],
"cta_primary": "QR-Code kostenlos erstellen", "cta_primary": "QR-Code kostenlos erstellen",
"cta_secondary": "Preise ansehen", "cta_secondary": "Preise ansehen",
"engagement_badge": "Kostenlos für immer", "engagement_badge": "Kostenlos für immer",
"get_started": "Loslegen", "get_started": "Loslegen",
"view_full_pricing": "Alle Preisdetails ansehen →" "view_full_pricing": "Alle Preisdetails ansehen →"
}, },
"trust": { "trust": {
"users": "10.000+ Aktive Nutzer", "users": "10.000+ Aktive Nutzer",
"codes": "500.000+ QR-Codes erstellt", "codes": "500.000+ QR-Codes erstellt",
"scans": "50M+ Scans verfolgt", "scans": "50M+ Scans verfolgt",
"countries": "120+ Länder" "countries": "120+ Länder"
}, },
"industries": { "industries": {
"restaurant": "Restaurant-Kette", "restaurant": "Restaurant-Kette",
"tech": "Tech-Startup", "tech": "Tech-Startup",
"realestate": "Immobilien", "realestate": "Immobilien",
"events": "Event-Agentur", "events": "Event-Agentur",
"retail": "Einzelhandel", "retail": "Einzelhandel",
"healthcare": "Gesundheitswesen" "healthcare": "Gesundheitswesen"
}, },
"templates": { "templates": {
"title": "Mit einer Vorlage beginnen", "title": "Mit einer Vorlage beginnen",
"restaurant": "Restaurant-Menü", "restaurant": "Restaurant-Menü",
"business": "Visitenkarte", "business": "Visitenkarte",
"vcard": "Kontaktkarte", "vcard": "Kontaktkarte",
"event": "Event-Ticket", "event": "Event-Ticket",
"use_template": "Vorlage verwenden →" "use_template": "Vorlage verwenden →"
}, },
"generator": { "generator": {
"title": "Sofortiger QR-Code-Generator", "title": "Sofortiger QR-Code-Generator",
"url_placeholder": "Geben Sie hier Ihre URL ein...", "url_placeholder": "Geben Sie hier Ihre URL ein...",
"foreground": "Vordergrund", "foreground": "Vordergrund",
"background": "Hintergrund", "background": "Hintergrund",
"corners": "Ecken", "corners": "Ecken",
"size": "Größe", "size": "Größe",
"contrast_good": "Guter Kontrast", "contrast_good": "Guter Kontrast",
"download_svg": "SVG herunterladen", "download_svg": "SVG herunterladen",
"download_png": "PNG herunterladen", "download_png": "PNG herunterladen",
"save_track": "Speichern & Verfolgen", "save_track": "Speichern & Verfolgen",
"live_preview": "Live-Vorschau", "live_preview": "Live-Vorschau",
"demo_note": "Dies ist ein Demo-QR-Code" "demo_note": "Dies ist ein Demo-QR-Code"
}, },
"static_vs_dynamic": { "static_vs_dynamic": {
"title": "Warum dynamische QR-Codes Geld sparen", "title": "Warum dynamische QR-Codes Geld sparen",
"description": "Hören Sie auf, Materialien neu zu drucken. Ändern Sie Zielorte sofort und verfolgen Sie jeden Scan.", "description": "Hören Sie auf, Materialien neu zu drucken. Ändern Sie Zielorte sofort und verfolgen Sie jeden Scan.",
"static": { "static": {
"title": "Statische QR-Codes", "title": "Statische QR-Codes",
"subtitle": "Immer kostenlos", "subtitle": "Immer kostenlos",
"description": "Perfekt für permanente Inhalte, die sich nie ändern", "description": "Perfekt für permanente Inhalte, die sich nie ändern",
"features": [ "features": [
"Inhalt kann nicht bearbeitet werden", "Inhalt kann nicht bearbeitet werden",
"Keine Scan-Verfolgung", "Keine Scan-Verfolgung",
"Funktioniert für immer", "Funktioniert für immer",
"Kein Konto erforderlich" "Kein Konto erforderlich"
] ]
}, },
"dynamic": { "dynamic": {
"title": "Dynamische QR-Codes", "title": "Dynamische QR-Codes",
"subtitle": "Empfohlen", "subtitle": "Empfohlen",
"description": "Volle Kontrolle mit Tracking- und Bearbeitungsfunktionen", "description": "Volle Kontrolle mit Tracking- und Bearbeitungsfunktionen",
"features": [ "features": [
"Inhalt jederzeit bearbeiten", "Inhalt jederzeit bearbeiten",
"Erweiterte Analytik", "Erweiterte Analytik",
"Individuelles Branding", "Individuelles Branding",
"Bulk-Operationen" "Bulk-Operationen"
] ]
} }
}, },
"features": { "features": {
"title": "Alles was Sie brauchen, um professionelle QR-Codes zu erstellen", "title": "Alles was Sie brauchen, um professionelle QR-Codes zu erstellen",
"analytics": { "analytics": {
"title": "Erweiterte Analytik", "title": "Erweiterte Analytik",
"description": "Verfolgen Sie Scans, Standorte, Geräte und Nutzerverhalten mit detaillierten Einblicken." "description": "Verfolgen Sie Scans, Standorte, Geräte und Nutzerverhalten mit detaillierten Einblicken."
}, },
"customization": { "customization": {
"title": "Vollständige Anpassung", "title": "Vollständige Anpassung",
"description": "Branden Sie Ihre QR-Codes mit individuellen Farben, Logos und Styling-Optionen." "description": "Branden Sie Ihre QR-Codes mit individuellen Farben, Logos und Styling-Optionen."
}, },
"unlimited": { "unlimited": {
"title": "Unbegrenzte statische QR-Codes", "title": "Unbegrenzte statische QR-Codes",
"description": "Erstellen Sie so viele statische QR-Codes wie Sie möchten. Für immer kostenlos, ohne Limits." "description": "Erstellen Sie so viele statische QR-Codes wie Sie möchten. Für immer kostenlos, ohne Limits."
}, },
"bulk": { "bulk": {
"title": "Bulk-Operationen", "title": "Bulk-Operationen",
"description": "Erstellen Sie hunderte von QR-Codes auf einmal mit CSV-Import und Batch-Verarbeitung." "description": "Erstellen Sie hunderte von QR-Codes auf einmal mit CSV-Import und Batch-Verarbeitung."
}, },
"integrations": { "integrations": {
"title": "Integrationen", "title": "Integrationen",
"description": "Verbinden Sie sich mit Zapier, Airtable, Google Sheets und weiteren beliebten Tools." "description": "Verbinden Sie sich mit Zapier, Airtable, Google Sheets und weiteren beliebten Tools."
}, },
"api": { "api": {
"title": "Entwickler-API", "title": "Entwickler-API",
"description": "Integrieren Sie QR-Code-Generierung in Ihre Anwendungen mit unserer REST-API." "description": "Integrieren Sie QR-Code-Generierung in Ihre Anwendungen mit unserer REST-API."
}, },
"support": { "support": {
"title": "24/7 Support", "title": "24/7 Support",
"description": "Erhalten Sie Hilfe, wenn Sie sie brauchen, mit unserem dedizierten Kundensupport-Team." "description": "Erhalten Sie Hilfe, wenn Sie sie brauchen, mit unserem dedizierten Kundensupport-Team."
} }
}, },
"pricing": { "pricing": {
"title": "Wählen Sie Ihren Plan", "title": "Wählen Sie Ihren Plan",
"subtitle": "Wählen Sie den perfekten Plan für Ihre QR-Code-Bedürfnisse", "subtitle": "Wählen Sie den perfekten Plan für Ihre QR-Code-Bedürfnisse",
"choose_plan": "Wählen Sie Ihren Plan", "choose_plan": "Wählen Sie Ihren Plan",
"select_plan": "Wählen Sie den perfekten Plan für Ihre QR-Code-Bedürfnisse", "select_plan": "Wählen Sie den perfekten Plan für Ihre QR-Code-Bedürfnisse",
"current_plan": "Aktueller Plan", "current_plan": "Aktueller Plan",
"upgrade_to": "Upgrade auf", "upgrade_to": "Upgrade auf",
"downgrade_to_free": "Zu Kostenlos zurückstufen", "downgrade_to_free": "Zu Kostenlos zurückstufen",
"most_popular": "Beliebteste", "most_popular": "Beliebteste",
"all_plans_note": "Alle Pläne beinhalten unbegrenzte statische QR-Codes und Basis-Anpassung.", "all_plans_note": "Alle Pläne beinhalten unbegrenzte statische QR-Codes und Basis-Anpassung.",
"free": { "free": {
"title": "Kostenlos", "title": "Kostenlos",
"name": "Free", "name": "Free",
"price": "€0", "price": "€0",
"period": "für immer", "period": "für immer",
"features": [ "features": [
"3 dynamische QR-Codes", "3 dynamische QR-Codes",
"Unbegrenzte statische QR-Codes", "Unbegrenzte statische QR-Codes",
"Basis-Scan-Tracking", "Basis-Scan-Tracking",
"Standard QR-Design-Vorlagen" "Standard QR-Design-Vorlagen"
] ]
}, },
"pro": { "pro": {
"title": "Pro", "title": "Pro",
"name": "Pro", "name": "Pro",
"price": "€9", "price": "€9",
"period": "pro Monat", "period": "pro Monat",
"badge": "Beliebteste", "badge": "Beliebteste",
"features": [ "features": [
"50 dynamische QR-Codes", "50 dynamische QR-Codes",
"Unbegrenzte statische QR-Codes", "Unbegrenzte statische QR-Codes",
"Erweiterte Analytik (Scans, Geräte, Standorte)", "Erweiterte Analytik (Scans, Geräte, Standorte)",
"Individuelles Branding (Farben)", "Individuelles Branding (Farben)",
"Download als SVG/PNG" "Download als SVG/PNG"
] ]
}, },
"business": { "business": {
"title": "Business", "title": "Business",
"name": "Business", "name": "Business",
"price": "€29", "price": "€29",
"period": "pro Monat", "period": "pro Monat",
"features": [ "features": [
"500 dynamische QR-Codes", "500 dynamische QR-Codes",
"Unbegrenzte statische QR-Codes", "Unbegrenzte statische QR-Codes",
"Alles aus Pro", "Alles aus Pro",
"Massen-QR-Erstellung (bis zu 1.000)", "Massen-QR-Erstellung (bis zu 1.000)",
"Prioritäts-E-Mail-Support", "Prioritäts-E-Mail-Support",
"Erweiterte Tracking & Insights" "Erweiterte Tracking & Insights"
] ]
} }
}, },
"faq": { "faq": {
"title": "Häufig gestellte Fragen", "title": "Häufig gestellte Fragen",
"questions": { "questions": {
"account": { "account": {
"question": "Benötige ich ein Konto, um QR-Codes zu erstellen?", "question": "Benötige ich ein Konto, um QR-Codes zu erstellen?",
"answer": "Für statische QR-Codes ist kein Konto erforderlich. Dynamische QR-Codes mit Tracking- und Bearbeitungsfunktionen erfordern jedoch ein kostenloses Konto." "answer": "Für statische QR-Codes ist kein Konto erforderlich. Dynamische QR-Codes mit Tracking- und Bearbeitungsfunktionen erfordern jedoch ein kostenloses Konto."
}, },
"static_vs_dynamic": { "static_vs_dynamic": {
"question": "Was ist der Unterschied zwischen statischen und dynamischen QR-Codes?", "question": "Was ist der Unterschied zwischen statischen und dynamischen QR-Codes?",
"answer": "Statische QR-Codes enthalten feste Inhalte, die nicht geändert werden können. Dynamische QR-Codes können jederzeit bearbeitet werden und bieten detaillierte Analytik." "answer": "Statische QR-Codes enthalten feste Inhalte, die nicht geändert werden können. Dynamische QR-Codes können jederzeit bearbeitet werden und bieten detaillierte Analytik."
}, },
"forever": { "forever": {
"question": "Funktionieren meine QR-Codes für immer?", "question": "Funktionieren meine QR-Codes für immer?",
"answer": "Statische QR-Codes funktionieren für immer, da der Inhalt direkt eingebettet ist. Dynamische QR-Codes funktionieren, solange Ihr Konto aktiv ist." "answer": "Statische QR-Codes funktionieren für immer, da der Inhalt direkt eingebettet ist. Dynamische QR-Codes funktionieren, solange Ihr Konto aktiv ist."
}, },
"file_type": { "file_type": {
"question": "Welchen Dateityp sollte ich zum Drucken verwenden?", "question": "Welchen Dateityp sollte ich zum Drucken verwenden?",
"answer": "Für Druckmaterialien empfehlen wir das SVG-Format für Skalierbarkeit oder hochauflösendes PNG (300+ DPI) für beste Qualität." "answer": "Für Druckmaterialien empfehlen wir das SVG-Format für Skalierbarkeit oder hochauflösendes PNG (300+ DPI) für beste Qualität."
}, },
"password": { "password": {
"question": "Kann ich einen QR-Code mit einem Passwort schützen?", "question": "Kann ich einen QR-Code mit einem Passwort schützen?",
"answer": "Ja, Pro- und Business-Pläne beinhalten Passwortschutz und Zugriffskontrollfunktionen für Ihre QR-Codes." "answer": "Ja, Pro- und Business-Pläne beinhalten Passwortschutz und Zugriffskontrollfunktionen für Ihre QR-Codes."
}, },
"analytics": { "analytics": {
"question": "Wie funktioniert die Analytik?", "question": "Wie funktioniert die Analytik?",
"answer": "Wir verfolgen Scans, Standorte, Geräte und Referrer unter Beachtung der Privatsphäre der Nutzer. Keine persönlichen Daten werden gespeichert." "answer": "Wir verfolgen Scans, Standorte, Geräte und Referrer unter Beachtung der Privatsphäre der Nutzer. Keine persönlichen Daten werden gespeichert."
}, },
"privacy": { "privacy": {
"question": "Verfolgen Sie persönliche Daten?", "question": "Verfolgen Sie persönliche Daten?",
"answer": "Wir respektieren die Privatsphäre und sammeln nur anonyme Nutzungsdaten. IP-Adressen werden gehasht und wir respektieren Do-Not-Track-Header." "answer": "Wir respektieren die Privatsphäre und sammeln nur anonyme Nutzungsdaten. IP-Adressen werden gehasht und wir respektieren Do-Not-Track-Header."
}, },
"bulk": { "bulk": {
"question": "Kann ich Codes in großen Mengen mit meinen eigenen Daten erstellen?", "question": "Kann ich Codes in großen Mengen mit meinen eigenen Daten erstellen?",
"answer": "Ja, Sie können CSV- oder Excel-Dateien hochladen, um mehrere QR-Codes auf einmal mit individueller Datenzuordnung zu erstellen." "answer": "Ja, Sie können CSV- oder Excel-Dateien hochladen, um mehrere QR-Codes auf einmal mit individueller Datenzuordnung zu erstellen."
} }
} }
}, },
"dashboard": { "dashboard": {
"title": "Dashboard", "title": "Dashboard",
"subtitle": "Verwalten Sie Ihre QR-Codes und verfolgen Sie Ihre Performance", "subtitle": "Verwalten Sie Ihre QR-Codes und verfolgen Sie Ihre Performance",
"stats": { "stats": {
"total_scans": "Gesamte Scans", "total_scans": "Gesamte Scans",
"active_codes": "Aktive QR-Codes", "active_codes": "Aktive QR-Codes",
"conversion_rate": "Konversionsrate" "conversion_rate": "Konversionsrate"
}, },
"recent_codes": "Aktuelle QR-Codes", "recent_codes": "Aktuelle QR-Codes",
"blog_resources": "Blog & Ressourcen", "blog_resources": "Blog & Ressourcen",
"menu": { "menu": {
"edit": "Bearbeiten", "edit": "Bearbeiten",
"duplicate": "Duplizieren", "duplicate": "Duplizieren",
"pause": "Pausieren", "pause": "Pausieren",
"delete": "Löschen" "delete": "Löschen"
} }
}, },
"create": { "create": {
"title": "QR-Code erstellen", "title": "QR-Code erstellen",
"subtitle": "Generieren Sie dynamische und statische QR-Codes mit individuellem Branding", "subtitle": "Generieren Sie dynamische und statische QR-Codes mit individuellem Branding",
"content": "Inhalt", "content": "Inhalt",
"type": "QR-Code-Typ", "type": "QR-Code-Typ",
"style": "Stil & Branding", "style": "Stil & Branding",
"preview": "Live-Vorschau", "preview": "Live-Vorschau",
"title_label": "Titel", "title_label": "Titel",
"title_placeholder": "Mein QR-Code", "title_placeholder": "Mein QR-Code",
"content_type": "Inhaltstyp", "content_type": "Inhaltstyp",
"url_label": "URL", "url_label": "URL",
"url_placeholder": "https://beispiel.de", "url_placeholder": "https://beispiel.de",
"tags_label": "Tags (durch Komma getrennt)", "tags_label": "Tags (durch Komma getrennt)",
"tags_placeholder": "marketing, kampagne, 2025", "tags_placeholder": "marketing, kampagne, 2025",
"qr_code_type": "QR-Code-Typ", "qr_code_type": "QR-Code-Typ",
"dynamic": "Dynamisch", "dynamic": "Dynamisch",
"static": "Statisch", "static": "Statisch",
"recommended": "Empfohlen", "recommended": "Empfohlen",
"dynamic_description": "Dynamisch: Scans verfolgen, URL später bearbeiten, Analytik ansehen. QR enthält Tracking-Link.", "dynamic_description": "Dynamisch: Scans verfolgen, URL später bearbeiten, Analytik ansehen. QR enthält Tracking-Link.",
"static_description": "Statisch: Direkt zum Inhalt, kein Tracking, nicht bearbeitbar. QR enthält tatsächlichen Inhalt.", "static_description": "Statisch: Direkt zum Inhalt, kein Tracking, nicht bearbeitbar. QR enthält tatsächlichen Inhalt.",
"foreground_color": "Vordergrundfarbe", "foreground_color": "Vordergrundfarbe",
"background_color": "Hintergrundfarbe", "background_color": "Hintergrundfarbe",
"corner_style": "Eckenstil", "corner_style": "Eckenstil",
"size": "Größe", "size": "Größe",
"good_contrast": "Guter Kontrast", "good_contrast": "Guter Kontrast",
"contrast_ratio": "Kontrastverhältnis", "contrast_ratio": "Kontrastverhältnis",
"download_svg": "SVG herunterladen", "download_svg": "SVG herunterladen",
"download_png": "PNG herunterladen", "download_png": "PNG herunterladen",
"save_qr_code": "QR-Code speichern" "save_qr_code": "QR-Code speichern"
}, },
"analytics": { "analytics": {
"title": "Analytik", "title": "Analytik",
"subtitle": "Verfolgen und analysieren Sie die Performance Ihrer QR-Codes", "subtitle": "Verfolgen und analysieren Sie die Performance Ihrer QR-Codes",
"export_report": "Bericht exportieren", "export_report": "Bericht exportieren",
"from_last_period": "vom letzten Zeitraum", "from_last_period": "vom letzten Zeitraum",
"no_mobile_scans": "Keine mobilen Scans", "no_mobile_scans": "Keine mobilen Scans",
"of_total": "der Gesamtmenge", "of_total": "der Gesamtmenge",
"ranges": { "ranges": {
"7d": "7 Tage", "7d": "7 Tage",
"30d": "30 Tage", "30d": "30 Tage",
"90d": "90 Tage" "90d": "90 Tage"
}, },
"kpis": { "kpis": {
"total_scans": "Gesamte Scans", "total_scans": "Gesamte Scans",
"avg_scans": "Ø Scans/QR", "avg_scans": "Ø Scans/QR",
"mobile_usage": "Mobile Nutzung", "mobile_usage": "Mobile Nutzung",
"top_country": "Top Land" "top_country": "Top Land"
}, },
"charts": { "charts": {
"scans_over_time": "Scans über Zeit", "scans_over_time": "Scans über Zeit",
"device_types": "Gerätetypen", "device_types": "Gerätetypen",
"top_countries": "Top Länder" "top_countries": "Top Länder"
}, },
"table": { "table": {
"qr_code": "QR-Code", "qr_code": "QR-Code",
"type": "Typ", "type": "Typ",
"total_scans": "Gesamte Scans", "total_scans": "Gesamte Scans",
"unique_scans": "Einzigartige Scans", "unique_scans": "Einzigartige Scans",
"conversion": "Konversion", "conversion": "Konversion",
"trend": "Trend", "trend": "Trend",
"scans": "Scans", "scans": "Scans",
"percentage": "Prozent", "percentage": "Prozent",
"country": "Land", "country": "Land",
"performance": "Performance", "performance": "Performance",
"created": "Erstellt", "created": "Erstellt",
"status": "Status" "status": "Status"
}, },
"performance_title": "QR-Code-Performance" "performance_title": "QR-Code-Performance"
}, },
"bulk": { "bulk": {
"title": "Massen-Erstellung", "title": "Massen-Erstellung",
"subtitle": "Erstellen Sie mehrere QR-Codes gleichzeitig aus CSV- oder Excel-Dateien", "subtitle": "Erstellen Sie mehrere QR-Codes gleichzeitig aus CSV- oder Excel-Dateien",
"template_warning_title": "Bitte folgen Sie dem Vorlagenformat", "template_warning_title": "Bitte folgen Sie dem Vorlagenformat",
"template_warning_text": "Laden Sie die Vorlage unten herunter und folgen Sie dem Format genau. Ihre CSV muss Spalten für Titel und Inhalt (URL) enthalten.", "template_warning_text": "Laden Sie die Vorlage unten herunter und folgen Sie dem Format genau. Ihre CSV muss Spalten für Titel und Inhalt (URL) enthalten.",
"static_only_title": "Nur statische QR-Codes", "static_only_title": "Nur statische QR-Codes",
"static_only_text": "Massen-Erstellung generiert statische QR-Codes, die nach der Erstellung nicht bearbeitet werden können. Diese QR-Codes beinhalten kein Tracking oder Analytik. Perfekt für Druckmaterialien und Offline-Nutzung.", "static_only_text": "Massen-Erstellung generiert statische QR-Codes, die nach der Erstellung nicht bearbeitet werden können. Diese QR-Codes beinhalten kein Tracking oder Analytik. Perfekt für Druckmaterialien und Offline-Nutzung.",
"download_template": "Vorlage herunterladen", "download_template": "Vorlage herunterladen",
"no_file_selected": "Keine ausgewählt", "no_file_selected": "Keine ausgewählt",
"simple_format": "Einfaches Format", "simple_format": "Einfaches Format",
"just_title_url": "Nur Titel & URL", "just_title_url": "Nur Titel & URL",
"static_qr_codes": "Statische QR-Codes", "static_qr_codes": "Statische QR-Codes",
"no_tracking": "Kein Tracking enthalten", "no_tracking": "Kein Tracking enthalten",
"instant_download": "Sofortiger Download", "instant_download": "Sofortiger Download",
"get_zip": "ZIP mit allen SVGs erhalten", "get_zip": "ZIP mit allen SVGs erhalten",
"max_rows": "max 1.000 Zeilen", "max_rows": "max 1.000 Zeilen",
"steps": { "steps": {
"upload": "Datei hochladen", "upload": "Datei hochladen",
"preview": "Vorschau & Zuordnung", "preview": "Vorschau & Zuordnung",
"download": "Herunterladen" "download": "Herunterladen"
}, },
"drag_drop": "Datei hier hinziehen", "drag_drop": "Datei hier hinziehen",
"or_click": "oder klicken zum Durchsuchen", "or_click": "oder klicken zum Durchsuchen",
"supported_formats": "Unterstützt CSV, XLS, XLSX (max 1.000 Zeilen)" "supported_formats": "Unterstützt CSV, XLS, XLSX (max 1.000 Zeilen)"
}, },
"integrations": { "integrations": {
"title": "Integrationen", "title": "Integrationen",
"metrics": { "metrics": {
"total_codes": "QR-Codes Gesamt", "total_codes": "QR-Codes Gesamt",
"active_integrations": "Aktive Integrationen", "active_integrations": "Aktive Integrationen",
"sync_status": "Sync-Status", "sync_status": "Sync-Status",
"available_services": "Verfügbare Services" "available_services": "Verfügbare Services"
}, },
"zapier": { "zapier": {
"title": "Zapier", "title": "Zapier",
"description": "Automatisieren Sie QR-Code-Erstellung mit 5000+ Apps", "description": "Automatisieren Sie QR-Code-Erstellung mit 5000+ Apps",
"features": [ "features": [
"Trigger bei neuen QR-Codes", "Trigger bei neuen QR-Codes",
"Codes aus anderen Apps erstellen", "Codes aus anderen Apps erstellen",
"Scan-Daten synchronisieren" "Scan-Daten synchronisieren"
] ]
}, },
"airtable": { "airtable": {
"title": "Airtable", "title": "Airtable",
"description": "Synchronisieren Sie QR-Codes mit Ihren Airtable-Basen", "description": "Synchronisieren Sie QR-Codes mit Ihren Airtable-Basen",
"features": [ "features": [
"Bidirektionale Synchronisation", "Bidirektionale Synchronisation",
"Individuelle Feldzuordnung", "Individuelle Feldzuordnung",
"Echtzeit-Updates" "Echtzeit-Updates"
] ]
}, },
"sheets": { "sheets": {
"title": "Google Sheets", "title": "Google Sheets",
"description": "Exportieren Sie Daten automatisch zu Google Sheets", "description": "Exportieren Sie Daten automatisch zu Google Sheets",
"features": [ "features": [
"Automatisierte Exporte", "Automatisierte Exporte",
"Individuelle Vorlagen", "Individuelle Vorlagen",
"Geplante Updates" "Geplante Updates"
] ]
}, },
"activate": "Aktivieren & Konfigurieren" "activate": "Aktivieren & Konfigurieren"
}, },
"settings": { "settings": {
"title": "Einstellungen", "title": "Einstellungen",
"subtitle": "Verwalten Sie Ihre Kontoeinstellungen und Präferenzen", "subtitle": "Verwalten Sie Ihre Kontoeinstellungen und Präferenzen",
"tabs": { "tabs": {
"profile": "Profil", "profile": "Profil",
"billing": "Abrechnung", "billing": "Abrechnung",
"team": "Team & Rollen", "team": "Team & Rollen",
"api": "API-Schlüssel", "api": "API-Schlüssel",
"workspace": "Arbeitsbereich" "workspace": "Arbeitsbereich"
} }
}, },
"common": { "common": {
"save": "Speichern", "save": "Speichern",
"cancel": "Abbrechen", "cancel": "Abbrechen",
"delete": "Löschen", "delete": "Löschen",
"edit": "Bearbeiten", "edit": "Bearbeiten",
"create": "Erstellen", "create": "Erstellen",
"loading": "Lädt...", "loading": "Lädt...",
"error": "Ein Fehler ist aufgetreten", "error": "Ein Fehler ist aufgetreten",
"success": "Erfolgreich!" "success": "Erfolgreich!"
}, },
"footer": { "footer": {
"product": "Produkt", "product": "Produkt",
"features": "Funktionen", "features": "Funktionen",
"pricing": "Preise", "pricing": "Preise",
"faq": "FAQ", "faq": "FAQ",
"blog": "Blog", "blog": "Blog",
"resources": "Ressourcen", "resources": "Ressourcen",
"full_pricing": "Alle Preise", "full_pricing": "Alle Preise",
"all_questions": "Alle Fragen", "all_questions": "Alle Fragen",
"all_articles": "Alle Artikel", "all_articles": "Alle Artikel",
"get_started": "Loslegen", "get_started": "Loslegen",
"legal": "Rechtliches", "legal": "Rechtliches",
"privacy_policy": "Datenschutzerklärung", "privacy_policy": "Datenschutzerklärung",
"tagline": "Erstellen Sie individuelle QR-Codes in Sekunden mit erweitertem Tracking und Analytik.", "tagline": "Erstellen Sie individuelle QR-Codes in Sekunden mit erweitertem Tracking und Analytik.",
"newsletter": "Newsletter Anmeldung", "newsletter": "Newsletter Anmeldung",
"rights_reserved": "QR Master. Alle Rechte vorbehalten." "rights_reserved": "QR Master. Alle Rechte vorbehalten."
} }
} }