feat: integrate i18n for multilingual support in Services page

- Added i18n configuration in src/i18n.ts for English and Dutch translations.
- Created locale files for English (en.json) and Dutch (nl.json) with translations for various sections.
- Updated Services component to utilize translation keys for titles, descriptions, and items.
- Refactored process steps in Services component to be dynamically rendered from translation keys.
- Adjusted main.tsx to include i18n initialization.
This commit is contained in:
Dan Dobos
2026-02-23 13:04:13 +01:00
parent 2fed4212c7
commit 8954081593
14 changed files with 1380 additions and 331 deletions
+91 -4
View File
@@ -44,6 +44,7 @@
"cmdk": "1.1.1",
"date-fns": "3.6.0",
"embla-carousel-react": "8.6.0",
"i18next": "^25.8.13",
"input-otp": "1.4.2",
"lucide-react": "0.487.0",
"motion": "12.23.24",
@@ -52,6 +53,7 @@
"react-dnd": "16.0.1",
"react-dnd-html5-backend": "16.0.1",
"react-hook-form": "7.55.0",
"react-i18next": "^16.5.4",
"react-popper": "2.3.0",
"react-resizable-panels": "2.1.7",
"react-responsive-masonry": "2.7.1",
@@ -69,7 +71,7 @@
"@vitejs/plugin-react": "4.7.0",
"gh-pages": "^6.3.0",
"tailwindcss": "4.1.12",
"vite": "6.3.5"
"vite": "^6.4.1"
},
"peerDependencies": {
"react": "18.3.1",
@@ -4357,6 +4359,46 @@
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
"license": "MIT"
},
"node_modules/html-parse-stringify": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz",
"integrity": "sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==",
"license": "MIT",
"dependencies": {
"void-elements": "3.1.0"
}
},
"node_modules/i18next": {
"version": "25.8.13",
"resolved": "https://registry.npmjs.org/i18next/-/i18next-25.8.13.tgz",
"integrity": "sha512-E0vzjBY1yM+nsFrtgkjLhST2NBkirkvOVoQa0MSldhsuZ3jUge7ZNpuwG0Cfc74zwo5ZwRzg3uOgT+McBn32iA==",
"funding": [
{
"type": "individual",
"url": "https://locize.com"
},
{
"type": "individual",
"url": "https://locize.com/i18next.html"
},
{
"type": "individual",
"url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project"
}
],
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.28.4"
},
"peerDependencies": {
"typescript": "^5"
},
"peerDependenciesMeta": {
"typescript": {
"optional": true
}
}
},
"node_modules/ignore": {
"version": "5.3.2",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
@@ -5299,6 +5341,33 @@
"react": "^16.8.0 || ^17 || ^18 || ^19"
}
},
"node_modules/react-i18next": {
"version": "16.5.4",
"resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-16.5.4.tgz",
"integrity": "sha512-6yj+dcfMncEC21QPhOTsW8mOSO+pzFmT6uvU7XXdvM/Cp38zJkmTeMeKmTrmCMD5ToT79FmiE/mRWiYWcJYW4g==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.28.4",
"html-parse-stringify": "^3.0.1",
"use-sync-external-store": "^1.6.0"
},
"peerDependencies": {
"i18next": ">= 25.6.2",
"react": ">= 16.8.0",
"typescript": "^5"
},
"peerDependenciesMeta": {
"react-dom": {
"optional": true
},
"react-native": {
"optional": true
},
"typescript": {
"optional": true
}
}
},
"node_modules/react-is": {
"version": "19.2.4",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.4.tgz",
@@ -5974,6 +6043,15 @@
}
}
},
"node_modules/use-sync-external-store": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz",
"integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==",
"license": "MIT",
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
}
},
"node_modules/vaul": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/vaul/-/vaul-1.1.2.tgz",
@@ -6010,9 +6088,9 @@
}
},
"node_modules/vite": {
"version": "6.3.5",
"resolved": "https://registry.npmjs.org/vite/-/vite-6.3.5.tgz",
"integrity": "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==",
"version": "6.4.1",
"resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz",
"integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -6084,6 +6162,15 @@
}
}
},
"node_modules/void-elements": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz",
"integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/warning": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz",
+3 -1
View File
@@ -48,6 +48,7 @@
"cmdk": "1.1.1",
"date-fns": "3.6.0",
"embla-carousel-react": "8.6.0",
"i18next": "^25.8.13",
"input-otp": "1.4.2",
"lucide-react": "0.487.0",
"motion": "12.23.24",
@@ -56,6 +57,7 @@
"react-dnd": "16.0.1",
"react-dnd-html5-backend": "16.0.1",
"react-hook-form": "7.55.0",
"react-i18next": "^16.5.4",
"react-popper": "2.3.0",
"react-resizable-panels": "2.1.7",
"react-responsive-masonry": "2.7.1",
@@ -73,7 +75,7 @@
"@vitejs/plugin-react": "4.7.0",
"gh-pages": "^6.3.0",
"tailwindcss": "4.1.12",
"vite": "6.3.5"
"vite": "^6.4.1"
},
"peerDependencies": {
"react": "18.3.1",
+36 -23
View File
@@ -1,7 +1,10 @@
import { Link } from "react-router";
import { Phone, Mail, MapPin, Clock, Wrench, Facebook, Instagram, Twitter } from "lucide-react";
import { useTranslation } from "react-i18next";
export function Footer() {
const { t } = useTranslation();
return (
<footer className="bg-gray-900 text-gray-300">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12">
@@ -10,10 +13,12 @@ export function Footer() {
<div>
<div className="flex items-center space-x-2 mb-4">
<Wrench className="h-8 w-8 text-orange-600" />
<span className="font-bold text-xl text-white">Lucris Handyman</span>
<span className="font-bold text-xl text-white">
{t("footer.brand")}
</span>
</div>
<p className="text-sm mb-4">
Professional handyman services for all your home repair and maintenance needs. Quality work, affordable prices.
{t("footer.description")}
</p>
<div className="flex space-x-4">
<a href="#" className="hover:text-orange-600 transition-colors">
@@ -30,31 +35,33 @@ export function Footer() {
{/* Quick Links */}
<div>
<h3 className="text-white font-semibold mb-4">Quick Links</h3>
<h3 className="text-white font-semibold mb-4">
{t("footer.quickLinks")}
</h3>
<ul className="space-y-2">
<li>
<Link to="/" className="hover:text-orange-600 transition-colors">
Home
{t("footer.links.home")}
</Link>
</li>
<li>
<Link to="/services" className="hover:text-orange-600 transition-colors">
Services
{t("footer.links.services")}
</Link>
</li>
<li>
<Link to="/about" className="hover:text-orange-600 transition-colors">
About Us
{t("footer.links.about")}
</Link>
</li>
<li>
<Link to="/gallery" className="hover:text-orange-600 transition-colors">
Gallery
{t("footer.links.gallery")}
</Link>
</li>
<li>
<Link to="/contact" className="hover:text-orange-600 transition-colors">
Contact
{t("footer.links.contact")}
</Link>
</li>
</ul>
@@ -62,47 +69,53 @@ export function Footer() {
{/* Services */}
<div>
<h3 className="text-white font-semibold mb-4">Our Services</h3>
<h3 className="text-white font-semibold mb-4">
{t("footer.ourServices")}
</h3>
<ul className="space-y-2 text-sm">
<li>Plumbing Repairs</li>
<li>Electrical Work</li>
<li>Painting & Drywall</li>
<li>Carpentry</li>
<li>General Repairs</li>
<li>Home Maintenance</li>
<li>{t("footer.services.plumbing")}</li>
<li>{t("footer.services.electrical")}</li>
<li>{t("footer.services.painting")}</li>
<li>{t("footer.services.carpentry")}</li>
<li>{t("footer.services.general")}</li>
<li>{t("footer.services.maintenance")}</li>
</ul>
</div>
{/* Contact Info */}
<div>
<h3 className="text-white font-semibold mb-4">Contact Info</h3>
<h3 className="text-white font-semibold mb-4">
{t("footer.contactInfo")}
</h3>
<ul className="space-y-3">
<li className="flex items-start space-x-3">
<Phone className="h-5 w-5 text-orange-600 flex-shrink-0 mt-0.5" />
<div>
<p className="text-sm">Call Us</p>
<p className="text-sm">{t("footer.callUs")}</p>
<p className="text-white">(555) 123-4567</p>
</div>
</li>
<li className="flex items-start space-x-3">
<Mail className="h-5 w-5 text-orange-600 flex-shrink-0 mt-0.5" />
<div>
<p className="text-sm">Email Us</p>
<p className="text-sm">{t("footer.emailUs")}</p>
<p className="text-white">info@lucris.nl</p>
</div>
</li>
<li className="flex items-start space-x-3">
<MapPin className="h-5 w-5 text-orange-600 flex-shrink-0 mt-0.5" />
<div>
<p className="text-sm">Location</p>
<p className="text-white">123 Main Street<br />New York, NY 10001</p>
<p className="text-sm">{t("footer.location")}</p>
<p className="text-white">
123 Main Street<br />New York, NY 10001
</p>
</div>
</li>
<li className="flex items-start space-x-3">
<Clock className="h-5 w-5 text-orange-600 flex-shrink-0 mt-0.5" />
<div>
<p className="text-sm">Working Hours</p>
<p className="text-white">Mon-Sat: 8AM-6PM</p>
<p className="text-sm">{t("footer.hours")}</p>
<p className="text-white">{t("footer.hoursValue")}</p>
</div>
</li>
</ul>
@@ -110,7 +123,7 @@ export function Footer() {
</div>
<div className="border-t border-gray-800 mt-8 pt-8 text-center text-sm">
<p>&copy; 2026 Lucris Handyman. All rights reserved.</p>
<p>{t("footer.copyright")}</p>
</div>
</div>
</footer>
+18 -9
View File
@@ -1,17 +1,20 @@
import { Link, useLocation } from "react-router";
import { Menu, X, Wrench } from "lucide-react";
import { useState } from "react";
import { useTranslation } from "react-i18next";
import { LanguageSwitcher } from "./LanguageSwitcher";
export function Header() {
const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
const location = useLocation();
const { t } = useTranslation();
const navItems = [
{ name: "Home", path: "/" },
{ name: "Services", path: "/services" },
{ name: "About", path: "/about" },
{ name: "Gallery", path: "/gallery" },
{ name: "Contact", path: "/contact" },
{ name: t("header.nav.home"), path: "/" },
{ name: t("header.nav.services"), path: "/services" },
{ name: t("header.nav.about"), path: "/about" },
{ name: t("header.nav.gallery"), path: "/gallery" },
{ name: t("header.nav.contact"), path: "/contact" },
];
const isActive = (path: string) => location.pathname === path;
@@ -23,11 +26,13 @@ export function Header() {
{/* Logo */}
<Link to="/" className="flex items-center space-x-2">
<Wrench className="h-8 w-8 text-orange-600" />
<span className="font-bold text-xl text-gray-900">Lucris Handyman</span>
<span className="font-bold text-xl text-gray-900">
{t("header.brand")}
</span>
</Link>
{/* Desktop Navigation */}
<nav className="hidden md:flex space-x-8">
<nav className="hidden md:flex items-center space-x-8">
{navItems.map((item) => (
<Link
key={item.path}
@@ -41,6 +46,7 @@ export function Header() {
{item.name}
</Link>
))}
<LanguageSwitcher />
</nav>
{/* CTA Button */}
@@ -48,7 +54,7 @@ export function Header() {
to="/contact"
className="hidden md:block bg-orange-600 text-white px-6 py-2 rounded-md hover:bg-orange-700 transition-colors"
>
Get a Quote
{t("header.cta")}
</Link>
{/* Mobile Menu Button */}
@@ -81,12 +87,15 @@ export function Header() {
{item.name}
</Link>
))}
<div className="mt-4">
<LanguageSwitcher />
</div>
<Link
to="/contact"
onClick={() => setMobileMenuOpen(false)}
className="block mt-4 bg-orange-600 text-white px-6 py-2 rounded-md text-center hover:bg-orange-700 transition-colors"
>
Get a Quote
{t("header.cta")}
</Link>
</nav>
)}
+46
View File
@@ -0,0 +1,46 @@
import { useTranslation } from "react-i18next";
function FlagGB() {
return (
<svg viewBox="0 0 60 30" aria-hidden="true" className="h-4 w-6">
<clipPath id="t"><path d="M0 0h60v30H0z" /></clipPath>
<g clipPath="url(#t)">
<path d="M0 0v30h60V0z" fill="#012169" />
<path d="M0 0l60 30m0-30L0 30" stroke="#fff" strokeWidth="6" />
<path d="M0 0l60 30m0-30L0 30" stroke="#C8102E" strokeWidth="4" />
<path d="M30 0v30M0 15h60" stroke="#fff" strokeWidth="10" />
<path d="M30 0v30M0 15h60" stroke="#C8102E" strokeWidth="6" />
</g>
</svg>
);
}
function FlagNL() {
return (
<svg viewBox="0 0 3 2" aria-hidden="true" className="h-4 w-6">
<rect width="3" height="2" fill="#fff" />
<rect width="3" height="0.6667" y="0" fill="#AE1C28" />
<rect width="3" height="0.6667" y="1.3333" fill="#21468B" />
</svg>
);
}
export function LanguageSwitcher() {
const { i18n, t } = useTranslation();
const current = i18n.language === "nl" ? "nl" : "en";
const other = current === "en" ? "nl" : "en";
const setLang = (lng: "en" | "nl") => i18n.changeLanguage(lng);
return (
<button
type="button"
onClick={() => setLang(other as "en" | "nl")}
aria-label={t("header.language")}
className="flex items-center gap-1 bg-white px-2 py-1 text-sm hover:bg-gray-50"
>
{other === "en" ? <FlagGB /> : <FlagNL />}
</button>
);
}
+70 -51
View File
@@ -1,45 +1,77 @@
import { CheckCircle, Award, Users, Clock } from "lucide-react";
import { ImageWithFallback } from "../components/figma/ImageWithFallback";
import { useTranslation } from "react-i18next";
export function About() {
const { t } = useTranslation();
const stats = [
{ label: "Years in Business", value: "15+" },
{ label: "Happy Clients", value: "5,000+" },
{ label: "Projects Completed", value: "10,000+" },
{ label: "Customer Satisfaction", value: "99%" },
{ label: t("about.stats.years"), value: "15+" },
{ label: t("about.stats.clients"), value: "5,000+" },
{ label: t("about.stats.projects"), value: "10,000+" },
{ label: t("about.stats.satisfaction"), value: "99%" },
];
const values = [
{
icon: CheckCircle,
title: "Quality First",
description: "We never compromise on the quality of our work. Every job is done right the first time.",
title: t("about.values.quality.title"),
description: t("about.values.quality.description"),
},
{
icon: Award,
title: "Professional Excellence",
description: "Our team consists of skilled, licensed professionals with years of experience.",
title: t("about.values.excellence.title"),
description: t("about.values.excellence.description"),
},
{
icon: Users,
title: "Customer Focus",
description: "Your satisfaction is our priority. We listen to your needs and deliver results.",
title: t("about.values.customer.title"),
description: t("about.values.customer.description"),
},
{
icon: Clock,
title: "Reliable Service",
description: "We show up on time, every time. Count on us to be there when you need us.",
title: t("about.values.reliable.title"),
description: t("about.values.reliable.description"),
},
];
const team = [
{
name: t("about.team.members.john.name"),
role: t("about.team.members.john.role"),
description: t("about.team.members.john.description"),
},
{
name: t("about.team.members.david.name"),
role: t("about.team.members.david.role"),
description: t("about.team.members.david.description"),
},
{
name: t("about.team.members.robert.name"),
role: t("about.team.members.robert.role"),
description: t("about.team.members.robert.description"),
},
];
const certifications = [
t("about.certifications.items.0"),
t("about.certifications.items.1"),
t("about.certifications.items.2"),
t("about.certifications.items.3"),
t("about.certifications.items.4"),
t("about.certifications.items.5"),
];
return (
<div>
{/* Hero Section */}
<section className="bg-gradient-to-br from-orange-50 to-orange-100 py-16">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 text-center">
<h1 className="text-4xl md:text-5xl mb-6 text-gray-900">About Lucris Handyman</h1>
<h1 className="text-4xl md:text-5xl mb-6 text-gray-900">
{t("about.hero.title")}
</h1>
<p className="text-xl text-gray-700 max-w-3xl mx-auto">
Your trusted partner for all home repair and maintenance needs since 2011
{t("about.hero.subtitle")}
</p>
</div>
</section>
@@ -49,20 +81,22 @@ export function About() {
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="grid lg:grid-cols-2 gap-12 items-center">
<div>
<h2 className="text-3xl md:text-4xl mb-6 text-gray-900">Our Story</h2>
<h2 className="text-3xl md:text-4xl mb-6 text-gray-900">
{t("about.story.title")}
</h2>
<p className="text-lg text-gray-700 mb-4">
Lucris Handyman was founded in 2011 with a simple mission: to provide reliable, high-quality handyman services at fair prices. What started as a one-person operation has grown into a trusted team of skilled professionals serving the community.
{t("about.story.p1")}
</p>
<p className="text-lg text-gray-700 mb-4">
Over the years, we've completed thousands of projects, from simple repairs to complete home renovations. Our reputation for quality work and excellent customer service has made us the go-to handyman service in the area.
{t("about.story.p2")}
</p>
<p className="text-lg text-gray-700">
Today, we continue to uphold the same values that guided us from the beginning: integrity, quality, and customer satisfaction. Every member of our team is dedicated to exceeding your expectations.
{t("about.story.p3")}
</p>
</div>
<ImageWithFallback
src="https://images.unsplash.com/photo-1768321901750-f7b96d774456?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxob21lJTIwcmVub3ZhdGlvbiUyMHdvcmt8ZW58MXx8fHwxNzcxNTk4Nzk4fDA&ixlib=rb-4.1.0&q=80&w=1080&utm_source=figma&utm_medium=referral"
alt="Home renovation work"
alt={t("about.story.imageAlt")}
className="rounded-lg shadow-lg w-full"
/>
</div>
@@ -75,7 +109,9 @@ export function About() {
<div className="grid grid-cols-2 md:grid-cols-4 gap-8">
{stats.map((stat, index) => (
<div key={index} className="text-center">
<div className="text-4xl md:text-5xl text-white mb-2">{stat.value}</div>
<div className="text-4xl md:text-5xl text-white mb-2">
{stat.value}
</div>
<div className="text-orange-100">{stat.label}</div>
</div>
))}
@@ -87,9 +123,11 @@ export function About() {
<section className="py-16 bg-gray-50">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="text-center mb-12">
<h2 className="text-3xl md:text-4xl mb-4 text-gray-900">Our Values</h2>
<h2 className="text-3xl md:text-4xl mb-4 text-gray-900">
{t("about.values.title")}
</h2>
<p className="text-xl text-gray-600 max-w-2xl mx-auto">
These core principles guide everything we do
{t("about.values.subtitle")}
</p>
</div>
<div className="grid md:grid-cols-2 lg:grid-cols-4 gap-8">
@@ -113,29 +151,15 @@ export function About() {
<section className="py-16 bg-white">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="text-center mb-12">
<h2 className="text-3xl md:text-4xl mb-4 text-gray-900">Meet Our Team</h2>
<h2 className="text-3xl md:text-4xl mb-4 text-gray-900">
{t("about.team.title")}
</h2>
<p className="text-xl text-gray-600 max-w-2xl mx-auto">
Skilled professionals dedicated to your home's care
{t("about.team.subtitle")}
</p>
</div>
<div className="grid md:grid-cols-3 gap-8">
{[
{
name: "John Mitchell",
role: "Founder & Lead Handyman",
description: "15+ years of experience in all aspects of home repair and maintenance.",
},
{
name: "David Chen",
role: "Master Electrician",
description: "Licensed electrician specializing in residential electrical work.",
},
{
name: "Robert Garcia",
role: "Master Plumber",
description: "Expert plumber with extensive experience in repairs and installations.",
},
].map((member, index) => (
{team.map((member, index) => (
<div key={index} className="bg-gray-50 rounded-lg p-6 text-center">
<div className="bg-orange-100 w-24 h-24 rounded-full mx-auto mb-4 flex items-center justify-center">
<Users className="h-12 w-12 text-orange-600" />
@@ -153,20 +177,15 @@ export function About() {
<section className="py-16 bg-gray-50">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="text-center mb-12">
<h2 className="text-3xl md:text-4xl mb-4 text-gray-900">Licensed & Insured</h2>
<h2 className="text-3xl md:text-4xl mb-4 text-gray-900">
{t("about.certifications.title")}
</h2>
<p className="text-xl text-gray-600 max-w-2xl mx-auto">
We maintain all necessary licenses and insurance for your protection and peace of mind
{t("about.certifications.subtitle")}
</p>
</div>
<div className="grid md:grid-cols-3 gap-6 max-w-4xl mx-auto">
{[
"State Licensed Contractor",
"Fully Insured & Bonded",
"BBB Accredited Business",
"Master Electrician License",
"Master Plumber License",
"OSHA Safety Certified",
].map((cert, index) => (
{certifications.map((cert, index) => (
<div key={index} className="flex items-center space-x-3 bg-white p-4 rounded-lg">
<CheckCircle className="h-6 w-6 text-orange-600 flex-shrink-0" />
<span className="text-gray-700">{cert}</span>
+65 -46
View File
@@ -1,7 +1,10 @@
import { useState } from "react";
import { MapPin, Phone, Mail, Clock, Send } from "lucide-react";
import { useTranslation } from "react-i18next";
export function Contact() {
const { t } = useTranslation();
const [formData, setFormData] = useState({
name: "",
email: "",
@@ -12,7 +15,9 @@ export function Contact() {
const [formSubmitted, setFormSubmitted] = useState(false);
const handleChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>) => {
const handleChange = (
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>,
) => {
setFormData({
...formData,
[e.target.name]: e.target.value,
@@ -21,11 +26,9 @@ export function Contact() {
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
// In a real application, this would send the data to a server
console.log("Form submitted:", formData);
setFormSubmitted(true);
// Reset form after 3 seconds
setTimeout(() => {
setFormSubmitted(false);
setFormData({
@@ -39,13 +42,13 @@ export function Contact() {
};
const services = [
"General Repair",
"Plumbing",
"Electrical",
"Painting",
"Carpentry",
"Home Maintenance",
"Other",
t("contact.services.generalRepair"),
t("contact.services.plumbing"),
t("contact.services.electrical"),
t("contact.services.painting"),
t("contact.services.carpentry"),
t("contact.services.homeMaintenance"),
t("contact.services.other"),
];
return (
@@ -53,9 +56,11 @@ export function Contact() {
{/* Hero Section */}
<section className="bg-gradient-to-br from-orange-50 to-orange-100 py-16">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 text-center">
<h1 className="text-4xl md:text-5xl mb-6 text-gray-900">Contact Us</h1>
<h1 className="text-4xl md:text-5xl mb-6 text-gray-900">
{t("contact.hero.title")}
</h1>
<p className="text-xl text-gray-700 max-w-3xl mx-auto">
Get in touch with us for a free quote or to schedule a service
{t("contact.hero.subtitle")}
</p>
</div>
</section>
@@ -67,9 +72,11 @@ export function Contact() {
{/* Contact Information */}
<div className="lg:col-span-2 space-y-8">
<div>
<h2 className="text-3xl mb-6 text-gray-900">Get in Touch</h2>
<h2 className="text-3xl mb-6 text-gray-900">
{t("contact.info.title")}
</h2>
<p className="text-gray-600 mb-8">
Have a question or ready to start your project? We'd love to hear from you. Reach out using any of the methods below.
{t("contact.info.subtitle")}
</p>
</div>
@@ -79,11 +86,13 @@ export function Contact() {
<Phone className="h-6 w-6 text-orange-600" />
</div>
<div>
<h3 className="text-gray-900 mb-1">Phone</h3>
<h3 className="text-gray-900 mb-1">{t("contact.info.phone")}</h3>
<a href="tel:5551234567" className="text-orange-600 hover:text-orange-700">
(555) 123-4567
</a>
<p className="text-gray-600 text-sm mt-1">Mon-Sat: 8AM-6PM</p>
<p className="text-gray-600 text-sm mt-1">
{t("contact.info.phoneHours")}
</p>
</div>
</div>
@@ -92,11 +101,13 @@ export function Contact() {
<Mail className="h-6 w-6 text-orange-600" />
</div>
<div>
<h3 className="text-gray-900 mb-1">Email</h3>
<h3 className="text-gray-900 mb-1">{t("contact.info.email")}</h3>
<a href="mailto:info@lucris.nl" className="text-orange-600 hover:text-orange-700">
info@lucris.nl
</a>
<p className="text-gray-600 text-sm mt-1">We'll respond within 24 hours</p>
<p className="text-gray-600 text-sm mt-1">
{t("contact.info.emailNote")}
</p>
</div>
</div>
@@ -105,10 +116,10 @@ export function Contact() {
<MapPin className="h-6 w-6 text-orange-600" />
</div>
<div>
<h3 className="text-gray-900 mb-1">Address</h3>
<h3 className="text-gray-900 mb-1">{t("contact.info.address")}</h3>
<p className="text-gray-600">
123 Main Street<br />
New York, NY 10001
{t("contact.info.addressLine1")}<br />
{t("contact.info.addressLine2")}
</p>
</div>
</div>
@@ -118,20 +129,20 @@ export function Contact() {
<Clock className="h-6 w-6 text-orange-600" />
</div>
<div>
<h3 className="text-gray-900 mb-1">Business Hours</h3>
<h3 className="text-gray-900 mb-1">{t("contact.info.hours")}</h3>
<p className="text-gray-600">
Monday - Friday: 8:00 AM - 6:00 PM<br />
Saturday: 9:00 AM - 4:00 PM<br />
Sunday: Closed
{t("contact.info.hoursLine1")}<br />
{t("contact.info.hoursLine2")}<br />
{t("contact.info.hoursLine3")}
</p>
</div>
</div>
</div>
<div className="bg-orange-50 p-6 rounded-lg border border-orange-200">
<h3 className="text-gray-900 mb-2">Emergency Services</h3>
<h3 className="text-gray-900 mb-2">{t("contact.emergency.title")}</h3>
<p className="text-gray-600 mb-3">
For urgent repairs outside business hours, call our emergency line:
{t("contact.emergency.subtitle")}
</p>
<a href="tel:5559876543" className="text-xl text-orange-600 hover:text-orange-700">
(555) 987-6543
@@ -141,16 +152,20 @@ export function Contact() {
{/* Contact Form */}
<div className="lg:col-span-3 bg-gray-50 p-8 rounded-lg">
<h2 className="text-2xl mb-6 text-gray-900">Request a Free Quote</h2>
<h2 className="text-2xl mb-6 text-gray-900">
{t("contact.form.title")}
</h2>
{formSubmitted ? (
<div className="bg-green-50 border border-green-200 rounded-lg p-8 text-center">
<div className="bg-green-100 w-16 h-16 rounded-full flex items-center justify-center mx-auto mb-4">
<Send className="h-8 w-8 text-green-600" />
</div>
<h3 className="text-2xl text-green-900 mb-2">Thank You!</h3>
<h3 className="text-2xl text-green-900 mb-2">
{t("contact.form.successTitle")}
</h3>
<p className="text-green-800">
Your message has been received. We'll get back to you within 24 hours.
{t("contact.form.successMessage")}
</p>
</div>
) : (
@@ -158,7 +173,7 @@ export function Contact() {
<div className="grid md:grid-cols-2 gap-6">
<div>
<label htmlFor="name" className="block text-sm text-gray-700 mb-2">
Full Name *
{t("contact.form.fullName")} *
</label>
<input
type="text"
@@ -168,13 +183,13 @@ export function Contact() {
value={formData.name}
onChange={handleChange}
className="w-full px-4 py-3 rounded-lg border border-gray-300 focus:border-orange-600 focus:ring-2 focus:ring-orange-200 outline-none transition-all"
placeholder="John Doe"
placeholder={t("contact.form.fullNamePlaceholder")}
/>
</div>
<div>
<label htmlFor="phone" className="block text-sm text-gray-700 mb-2">
Phone Number *
{t("contact.form.phone")} *
</label>
<input
type="tel"
@@ -184,14 +199,14 @@ export function Contact() {
value={formData.phone}
onChange={handleChange}
className="w-full px-4 py-3 rounded-lg border border-gray-300 focus:border-orange-600 focus:ring-2 focus:ring-orange-200 outline-none transition-all"
placeholder="(555) 123-4567"
placeholder={t("contact.form.phonePlaceholder")}
/>
</div>
</div>
<div>
<label htmlFor="email" className="block text-sm text-gray-700 mb-2">
Email Address *
{t("contact.form.email")} *
</label>
<input
type="email"
@@ -201,13 +216,13 @@ export function Contact() {
value={formData.email}
onChange={handleChange}
className="w-full px-4 py-3 rounded-lg border border-gray-300 focus:border-orange-600 focus:ring-2 focus:ring-orange-200 outline-none transition-all"
placeholder="john@example.com"
placeholder={t("contact.form.emailPlaceholder")}
/>
</div>
<div>
<label htmlFor="service" className="block text-sm text-gray-700 mb-2">
Service Needed *
{t("contact.form.service")} *
</label>
<select
id="service"
@@ -217,7 +232,7 @@ export function Contact() {
onChange={handleChange}
className="w-full px-4 py-3 rounded-lg border border-gray-300 focus:border-orange-600 focus:ring-2 focus:ring-orange-200 outline-none transition-all"
>
<option value="">Select a service</option>
<option value="">{t("contact.form.servicePlaceholder")}</option>
{services.map((service) => (
<option key={service} value={service}>
{service}
@@ -228,7 +243,7 @@ export function Contact() {
<div>
<label htmlFor="message" className="block text-sm text-gray-700 mb-2">
Project Details *
{t("contact.form.details")} *
</label>
<textarea
id="message"
@@ -238,7 +253,7 @@ export function Contact() {
onChange={handleChange}
rows={6}
className="w-full px-4 py-3 rounded-lg border border-gray-300 focus:border-orange-600 focus:ring-2 focus:ring-orange-200 outline-none transition-all resize-none"
placeholder="Please describe your project in detail..."
placeholder={t("contact.form.detailsPlaceholder")}
/>
</div>
@@ -247,11 +262,11 @@ export function Contact() {
className="w-full bg-orange-600 text-white px-8 py-4 rounded-lg hover:bg-orange-700 transition-colors flex items-center justify-center"
>
<Send className="mr-2 h-5 w-5" />
Send Message
{t("contact.form.submit")}
</button>
<p className="text-sm text-gray-600 text-center">
By submitting this form, you agree to our terms and privacy policy.
{t("contact.form.disclaimer")}
</p>
</form>
)}
@@ -263,9 +278,13 @@ export function Contact() {
{/* Map Section */}
<section className="py-16 bg-gray-50">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<h2 className="text-3xl text-center mb-8 text-gray-900">Our Location</h2>
<h2 className="text-3xl text-center mb-8 text-gray-900">
{t("contact.map.title")}
</h2>
<div className="bg-gray-300 rounded-lg overflow-hidden h-96 flex items-center justify-center">
<p className="text-gray-600">Map would be displayed here (e.g., Google Maps integration)</p>
<p className="text-gray-600">
{t("contact.map.placeholder")}
</p>
</div>
</div>
</section>
+60 -55
View File
@@ -1,62 +1,80 @@
import { useState } from "react";
import { ImageWithFallback } from "../components/figma/ImageWithFallback";
import { useTranslation } from "react-i18next";
export function Gallery() {
const [selectedCategory, setSelectedCategory] = useState("All");
const { t } = useTranslation();
const [selectedCategory, setSelectedCategory] = useState("all");
const categories = ["All", "Plumbing", "Electrical", "Painting", "Carpentry", "Renovation"];
const categories = [
{ key: "all", label: t("gallery.categories.all") },
{ key: "plumbing", label: t("gallery.categories.plumbing") },
{ key: "electrical", label: t("gallery.categories.electrical") },
{ key: "painting", label: t("gallery.categories.painting") },
{ key: "carpentry", label: t("gallery.categories.carpentry") },
{ key: "renovation", label: t("gallery.categories.renovation") },
];
const projects = [
{
title: "Kitchen Renovation",
category: "Renovation",
image: "https://images.unsplash.com/photo-1768321901750-f7b96d774456?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxob21lJTIwcmVub3ZhdGlvbiUyMHdvcmt8ZW58MXx8fHwxNzcxNTk4Nzk4fDA&ixlib=rb-4.1.0&q=80&w=1080&utm_source=figma&utm_medium=referral",
description: "Complete kitchen remodel with custom cabinets and new fixtures",
title: t("gallery.projects.kitchen.title"),
category: "renovation",
image:
"https://images.unsplash.com/photo-1768321901750-f7b96d774456?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxob21lJTIwcmVub3ZhdGlvbiUyMHdvcmt8ZW58MXx8fHwxNzcxNTk4Nzk4fDA&ixlib=rb-4.1.0&q=80&w=1080&utm_source=figma&utm_medium=referral",
description: t("gallery.projects.kitchen.description"),
},
{
title: "Plumbing Repair",
category: "Plumbing",
image: "https://images.unsplash.com/photo-1760571327612-8ab776dcd462?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxob21lJTIwcmVwYWlyJTIwcGx1bWJpbmd8ZW58MXx8fHwxNzcxNTE2ODQ2fDA&ixlib=rb-4.1.0&q=80&w=1080&utm_source=figma&utm_medium=referral",
description: "Professional pipe repair and fixture installation",
title: t("gallery.projects.plumbing.title"),
category: "plumbing",
image:
"https://images.unsplash.com/photo-1760571327612-8ab776dcd462?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxob21lJTIwcmVwYWlyJTIwcGx1bWJpbmd8ZW58MXx8fHwxNzcxNTE2ODQ2fDA&ixlib=rb-4.1.0&q=80&w=1080&utm_source=figma&utm_medium=referral",
description: t("gallery.projects.plumbing.description"),
},
{
title: "Electrical Installation",
category: "Electrical",
image: "https://images.unsplash.com/photo-1767514536570-83d70c024247?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxlbGVjdHJpY2FsJTIwd29yayUyMGluc3RhbGxhdGlvbnxlbnwxfHx8fDE3NzE1OTg3OTh8MA&ixlib=rb-4.1.0&q=80&w=1080&utm_source=figma&utm_medium=referral",
description: "Safe and reliable electrical work with proper certification",
title: t("gallery.projects.electrical.title"),
category: "electrical",
image:
"https://images.unsplash.com/photo-1767514536570-83d70c024247?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxlbGVjdHJpY2FsJTIwd29yayUyMGluc3RhbGxhdGlvbnxlbnwxfHx8fDE3NzE1OTg3OTh8MA&ixlib=rb-4.1.0&q=80&w=1080&utm_source=figma&utm_medium=referral",
description: t("gallery.projects.electrical.description"),
},
{
title: "Interior Painting",
category: "Painting",
image: "https://images.unsplash.com/photo-1574359411659-15573a27fd0c?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxob3VzZSUyMHBhaW50aW5nJTIwY29udHJhY3RvcnxlbnwxfHx8fDE3NzE1OTg3OTh8MA&ixlib=rb-4.1.0&q=80&w=1080&utm_source=figma&utm_medium=referral",
description: "Professional interior painting with attention to detail",
title: t("gallery.projects.painting.title"),
category: "painting",
image:
"https://images.unsplash.com/photo-1574359411659-15573a27fd0c?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxob3VzZSUyMHBhaW50aW5nJTIwY29udHJhY3RvcnxlbnwxfHx8fDE3NzE1OTg3OTh8MA&ixlib=rb-4.1.0&q=80&w=1080&utm_source=figma&utm_medium=referral",
description: t("gallery.projects.painting.description"),
},
{
title: "Custom Carpentry",
category: "Carpentry",
image: "https://images.unsplash.com/photo-1581783898377-1c85bf937427?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxoYW5keW1hbiUyMGNhcnBlbnRlciUyMHRvb2xzfGVufDF8fHx8MTc3MTU5ODc5N3ww&ixlib=rb-4.1.0&q=80&w=1080&utm_source=figma&utm_medium=referral",
description: "Custom woodworking and carpentry projects",
title: t("gallery.projects.carpentry.title"),
category: "carpentry",
image:
"https://images.unsplash.com/photo-1581783898377-1c85bf937427?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxoYW5keW1hbiUyMGNhcnBlbnRlciUyMHRvb2xzfGVufDF8fHx8MTc3MTU5ODc5N3ww&ixlib=rb-4.1.0&q=80&w=1080&utm_source=figma&utm_medium=referral",
description: t("gallery.projects.carpentry.description"),
},
{
title: "Home Maintenance",
category: "Renovation",
image: "https://images.unsplash.com/photo-1620838883342-ca19cf8448d6?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxwcm9mZXNzaW9uYWwlMjBoYW5keW1hbiUyMHNlcnZpY2V8ZW58MXx8fHwxNzcxNTk4Nzk4fDA&ixlib=rb-4.1.0&q=80&w=1080&utm_source=figma&utm_medium=referral",
description: "Regular home maintenance and repair services",
title: t("gallery.projects.maintenance.title"),
category: "renovation",
image:
"https://images.unsplash.com/photo-1620838883342-ca19cf8448d6?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxwcm9mZXNzaW9uYWwlMjBoYW5keW1hbiUyMHNlcnZpY2V8ZW58MXx8fHwxNzcxNTk4Nzk4fDA&ixlib=rb-4.1.0&q=80&w=1080&utm_source=figma&utm_medium=referral",
description: t("gallery.projects.maintenance.description"),
},
];
const filteredProjects = selectedCategory === "All"
? projects
: projects.filter(project => project.category === selectedCategory);
const filteredProjects =
selectedCategory === "all"
? projects
: projects.filter((project) => project.category === selectedCategory);
return (
<div>
{/* Hero Section */}
<section className="bg-gradient-to-br from-orange-50 to-orange-100 py-16">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 text-center">
<h1 className="text-4xl md:text-5xl mb-6 text-gray-900">Project Gallery</h1>
<h1 className="text-4xl md:text-5xl mb-6 text-gray-900">
{t("gallery.hero.title")}
</h1>
<p className="text-xl text-gray-700 max-w-3xl mx-auto">
Browse through our portfolio of completed projects and see the quality of our work
{t("gallery.hero.subtitle")}
</p>
</div>
</section>
@@ -67,15 +85,15 @@ export function Gallery() {
<div className="flex flex-wrap gap-3 justify-center">
{categories.map((category) => (
<button
key={category}
onClick={() => setSelectedCategory(category)}
key={category.key}
onClick={() => setSelectedCategory(category.key)}
className={`px-6 py-2 rounded-full transition-colors ${
selectedCategory === category
selectedCategory === category.key
? "bg-orange-600 text-white"
: "bg-gray-100 text-gray-700 hover:bg-gray-200"
}`}
>
{category}
{category.label}
</button>
))}
</div>
@@ -99,7 +117,10 @@ export function Gallery() {
<div className="absolute inset-0 bg-gradient-to-t from-black/80 via-black/40 to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-300">
<div className="absolute bottom-0 left-0 right-0 p-6 text-white">
<div className="inline-block bg-orange-600 px-3 py-1 rounded-full text-sm mb-2">
{project.category}
{
categories.find((c) => c.key === project.category)
?.label
}
</div>
<h3 className="text-xl mb-2">{project.title}</h3>
<p className="text-sm text-gray-200">{project.description}</p>
@@ -111,29 +132,13 @@ export function Gallery() {
{filteredProjects.length === 0 && (
<div className="text-center py-12">
<p className="text-xl text-gray-600">No projects found in this category.</p>
<p className="text-xl text-gray-600">
{t("gallery.empty")}
</p>
</div>
)}
</div>
</section>
{/* CTA Section */}
<section className="py-16 bg-gray-50">
<div className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 text-center">
<h2 className="text-3xl md:text-4xl mb-6 text-gray-900">
Want Your Project Featured Here?
</h2>
<p className="text-xl text-gray-600 mb-8">
Let us help you transform your home with our professional services
</p>
<a
href="/contact"
className="inline-flex items-center bg-orange-600 text-white px-8 py-4 rounded-lg hover:bg-orange-700 transition-colors"
>
Start Your Project
</a>
</div>
</section>
</div>
);
}
+73 -47
View File
@@ -1,49 +1,55 @@
import { Link } from "react-router";
import { CheckCircle, Phone, ArrowRight, Star } from "lucide-react";
import { ImageWithFallback } from "../components/figma/ImageWithFallback";
import { useTranslation } from "react-i18next";
export function Home() {
const { t } = useTranslation();
const services = [
{
title: "Plumbing",
description: "From leaky faucets to pipe repairs, we handle all your plumbing needs.",
image: "https://images.unsplash.com/photo-1760571327612-8ab776dcd462?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxob21lJTIwcmVwYWlyJTIwcGx1bWJpbmd8ZW58MXx8fHwxNzcxNTE2ODQ2fDA&ixlib=rb-4.1.0&q=80&w=1080&utm_source=figma&utm_medium=referral",
title: t("home.services.items.plumbing.title"),
description: t("home.services.items.plumbing.description"),
image:
"https://images.unsplash.com/photo-1760571327612-8ab776dcd462?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxob21lJTIwcmVwYWlyJTIwcGx1bWJpbmd8ZW58MXx8fHwxNzcxNTE2ODQ2fDA&ixlib=rb-4.1.0&q=80&w=1080&utm_source=figma&utm_medium=referral",
},
{
title: "Electrical",
description: "Safe and reliable electrical installations, repairs, and upgrades.",
image: "https://images.unsplash.com/photo-1767514536570-83d70c024247?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxlbGVjdHJpY2FsJTIwd29yayUyMGluc3RhbGxhdGlvbnxlbnwxfHx8fDE3NzE1OTg3OTh8MA&ixlib=rb-4.1.0&q=80&w=1080&utm_source=figma&utm_medium=referral",
title: t("home.services.items.electrical.title"),
description: t("home.services.items.electrical.description"),
image:
"https://images.unsplash.com/photo-1767514536570-83d70c024247?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxlbGVjdHJpY2FsJTIwd29yayUyMGluc3RhbGxhdGlvbnxlbnwxfHx8fDE3NzE1OTg3OTh8MA&ixlib=rb-4.1.0&q=80&w=1080&utm_source=figma&utm_medium=referral",
},
{
title: "Painting",
description: "Professional painting services for interior and exterior projects.",
image: "https://images.unsplash.com/photo-1574359411659-15573a27fd0c?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxob3VzZSUyMHBhaW50aW5nJTIwY29udHJhY3RvcnxlbnwxfHx8fDE3NzE1OTg3OTh8MA&ixlib=rb-4.1.0&q=80&w=1080&utm_source=figma&utm_medium=referral",
title: t("home.services.items.painting.title"),
description: t("home.services.items.painting.description"),
image:
"https://images.unsplash.com/photo-1574359411659-15573a27fd0c?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxob3VzZSUyMHBhaW50aW5nJTIwY29udHJhY3RvcnxlbnwxfHx8fDE3NzE1OTg3OTh8MA&ixlib=rb-4.1.0&q=80&w=1080&utm_source=figma&utm_medium=referral",
},
];
const features = [
"Licensed & Insured",
"Same-Day Service",
"Quality Workmanship",
"Affordable Pricing",
"100% Satisfaction Guarantee",
"Emergency Services Available",
t("home.features.licensed"),
t("home.features.sameDay"),
t("home.features.quality"),
t("home.features.affordable"),
t("home.features.satisfaction"),
t("home.features.emergency"),
];
const testimonials = [
{
name: "Sarah Johnson",
text: "Outstanding service! They fixed our plumbing issue quickly and professionally. Highly recommend!",
name: t("home.testimonials.items.sarah.name"),
text: t("home.testimonials.items.sarah.text"),
rating: 5,
},
{
name: "Mike Thompson",
text: "Lucris is my go-to for all home repairs. Always reliable, fair pricing, and excellent work.",
name: t("home.testimonials.items.mike.name"),
text: t("home.testimonials.items.mike.text"),
rating: 5,
},
{
name: "Emily Davis",
text: "They remodeled our bathroom and the results exceeded our expectations. True professionals!",
name: t("home.testimonials.items.emily.name"),
text: t("home.testimonials.items.emily.text"),
rating: 5,
},
];
@@ -56,17 +62,18 @@ export function Home() {
<div className="grid lg:grid-cols-2 gap-12 items-center">
<div>
<h1 className="text-4xl md:text-5xl lg:text-6xl mb-6 text-gray-900">
Your Trusted <span className="text-orange-600">Handyman</span> Service
{t("home.hero.title")}
<span className="text-orange-600"> {t("home.hero.titleHighlight")}</span>
</h1>
<p className="text-xl text-gray-700 mb-8">
Professional home repair and maintenance services. From small fixes to major renovations, we do it all with quality and care.
{t("home.hero.subtitle")}
</p>
<div className="flex flex-col sm:flex-row gap-4">
<Link
to="/contact"
className="inline-flex items-center justify-center bg-orange-600 text-white px-8 py-4 rounded-lg hover:bg-orange-700 transition-colors"
>
Get Free Quote
{t("home.hero.ctaPrimary")}
<ArrowRight className="ml-2 h-5 w-5" />
</Link>
<a
@@ -74,14 +81,14 @@ export function Home() {
className="inline-flex items-center justify-center bg-white text-orange-600 px-8 py-4 rounded-lg border-2 border-orange-600 hover:bg-orange-50 transition-colors"
>
<Phone className="mr-2 h-5 w-5" />
(555) 123-4567
{t("home.hero.ctaSecondary")}
</a>
</div>
</div>
<div className="relative">
<ImageWithFallback
src="https://images.unsplash.com/photo-1620838883342-ca19cf8448d6?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxwcm9mZXNzaW9uYWwlMjBoYW5keW1hbiUyMHNlcnZpY2V8ZW58MXx8fHwxNzcxNTk4Nzk4fDA&ixlib=rb-4.1.0&q=80&w=1080&utm_source=figma&utm_medium=referral"
alt="Professional handyman at work"
alt={t("home.hero.imageAlt")}
className="rounded-lg shadow-2xl w-full"
/>
</div>
@@ -107,14 +114,19 @@ export function Home() {
<section className="py-16 bg-gray-50">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="text-center mb-12">
<h2 className="text-3xl md:text-4xl mb-4 text-gray-900">Our Services</h2>
<h2 className="text-3xl md:text-4xl mb-4 text-gray-900">
{t("home.services.title")}
</h2>
<p className="text-xl text-gray-600 max-w-2xl mx-auto">
We offer a comprehensive range of handyman services to keep your home in perfect condition.
{t("home.services.subtitle")}
</p>
</div>
<div className="grid md:grid-cols-3 gap-8">
{services.map((service, index) => (
<div key={index} className="bg-white rounded-lg overflow-hidden shadow-lg hover:shadow-xl transition-shadow">
<div
key={index}
className="bg-white rounded-lg overflow-hidden shadow-lg hover:shadow-xl transition-shadow"
>
<ImageWithFallback
src={service.image}
alt={service.title}
@@ -127,7 +139,7 @@ export function Home() {
to="/services"
className="inline-flex items-center text-orange-600 hover:text-orange-700"
>
Learn More
{t("home.services.learnMore")}
<ArrowRight className="ml-2 h-4 w-4" />
</Link>
</div>
@@ -139,7 +151,7 @@ export function Home() {
to="/services"
className="inline-flex items-center bg-orange-600 text-white px-8 py-3 rounded-lg hover:bg-orange-700 transition-colors"
>
View All Services
{t("home.services.viewAll")}
<ArrowRight className="ml-2 h-5 w-5" />
</Link>
</div>
@@ -152,36 +164,48 @@ export function Home() {
<div className="grid lg:grid-cols-2 gap-12 items-center">
<ImageWithFallback
src="https://images.unsplash.com/photo-1581783898377-1c85bf937427?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxoYW5keW1hbiUyMGNhcnBlbnRlciUyMHRvb2xzfGVufDF8fHx8MTc3MTU5ODc5N3ww&ixlib=rb-4.1.0&q=80&w=1080&utm_source=figma&utm_medium=referral"
alt="Handyman tools"
alt={t("home.about.imageAlt")}
className="rounded-lg shadow-lg w-full"
/>
<div>
<h2 className="text-3xl md:text-4xl mb-6 text-gray-900">
Why Choose Lucris Handyman?
{t("home.about.title")}
</h2>
<p className="text-lg text-gray-600 mb-6">
With over 15 years of experience, we've become the most trusted handyman service in the area. Our team of skilled professionals is committed to delivering exceptional quality and customer satisfaction.
{t("home.about.subtitle")}
</p>
<ul className="space-y-4 mb-8">
<li className="flex items-start space-x-3">
<CheckCircle className="h-6 w-6 text-orange-600 flex-shrink-0 mt-0.5" />
<div>
<span className="text-gray-900">Experienced Professionals</span>
<p className="text-gray-600">Skilled craftsmen with years of expertise</p>
<span className="text-gray-900">
{t("home.about.points.experienced.title")}
</span>
<p className="text-gray-600">
{t("home.about.points.experienced.text")}
</p>
</div>
</li>
<li className="flex items-start space-x-3">
<CheckCircle className="h-6 w-6 text-orange-600 flex-shrink-0 mt-0.5" />
<div>
<span className="text-gray-900">Fair & Transparent Pricing</span>
<p className="text-gray-600">No hidden fees, upfront quotes</p>
<span className="text-gray-900">
{t("home.about.points.pricing.title")}
</span>
<p className="text-gray-600">
{t("home.about.points.pricing.text")}
</p>
</div>
</li>
<li className="flex items-start space-x-3">
<CheckCircle className="h-6 w-6 text-orange-600 flex-shrink-0 mt-0.5" />
<div>
<span className="text-gray-900">Quality Guaranteed</span>
<p className="text-gray-600">100% satisfaction or your money back</p>
<span className="text-gray-900">
{t("home.about.points.guarantee.title")}
</span>
<p className="text-gray-600">
{t("home.about.points.guarantee.text")}
</p>
</div>
</li>
</ul>
@@ -189,7 +213,7 @@ export function Home() {
to="/about"
className="inline-flex items-center text-orange-600 hover:text-orange-700 text-lg"
>
Learn More About Us
{t("home.about.learnMore")}
<ArrowRight className="ml-2 h-5 w-5" />
</Link>
</div>
@@ -201,9 +225,11 @@ export function Home() {
<section className="py-16 bg-gray-50">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="text-center mb-12">
<h2 className="text-3xl md:text-4xl mb-4 text-gray-900">What Our Clients Say</h2>
<h2 className="text-3xl md:text-4xl mb-4 text-gray-900">
{t("home.testimonials.title")}
</h2>
<p className="text-xl text-gray-600">
Don't just take our word for it - hear from our satisfied customers
{t("home.testimonials.subtitle")}
</p>
</div>
<div className="grid md:grid-cols-3 gap-8">
@@ -226,17 +252,17 @@ export function Home() {
<section className="py-16 bg-orange-600">
<div className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 text-center">
<h2 className="text-3xl md:text-4xl mb-6 text-white">
Ready to Get Started?
{t("home.cta.title")}
</h2>
<p className="text-xl text-orange-100 mb-8">
Contact us today for a free quote and let us take care of your home repair needs!
{t("home.cta.subtitle")}
</p>
<div className="flex flex-col sm:flex-row gap-4 justify-center">
<Link
to="/contact"
className="inline-flex items-center justify-center bg-white text-orange-600 px-8 py-4 rounded-lg hover:bg-gray-100 transition-colors"
>
Get Free Quote
{t("home.cta.primary")}
<ArrowRight className="ml-2 h-5 w-5" />
</Link>
<a
@@ -244,7 +270,7 @@ export function Home() {
className="inline-flex items-center justify-center bg-orange-700 text-white px-8 py-4 rounded-lg hover:bg-orange-800 transition-colors"
>
<Phone className="mr-2 h-5 w-5" />
Call Now
{t("home.cta.secondary")}
</a>
</div>
</div>
+98 -89
View File
@@ -1,106 +1,134 @@
import { Link } from "react-router";
import {
Wrench,
Droplet,
Zap,
PaintBucket,
Hammer,
Home,
Settings,
import {
Wrench,
Droplet,
Zap,
PaintBucket,
Hammer,
Home,
Settings,
CheckCircle,
ArrowRight
ArrowRight,
} from "lucide-react";
import { useTranslation } from "react-i18next";
export function Services() {
const { t } = useTranslation();
const services = [
{
icon: Droplet,
title: "Plumbing Services",
description: "Expert plumbing repairs and installations for your home.",
title: t("services.list.plumbing.title"),
description: t("services.list.plumbing.description"),
items: [
"Faucet & Fixture Repairs",
"Toilet Repairs & Replacement",
"Pipe Repairs & Leak Detection",
"Drain Cleaning",
"Water Heater Services",
"Garbage Disposal Installation",
t("services.list.plumbing.items.0"),
t("services.list.plumbing.items.1"),
t("services.list.plumbing.items.2"),
t("services.list.plumbing.items.3"),
t("services.list.plumbing.items.4"),
t("services.list.plumbing.items.5"),
],
},
{
icon: Zap,
title: "Electrical Work",
description: "Safe and reliable electrical services by licensed professionals.",
title: t("services.list.electrical.title"),
description: t("services.list.electrical.description"),
items: [
"Light Fixture Installation",
"Outlet & Switch Repair",
"Ceiling Fan Installation",
"Circuit Breaker Services",
"Home Rewiring",
"Electrical Safety Inspections",
t("services.list.electrical.items.0"),
t("services.list.electrical.items.1"),
t("services.list.electrical.items.2"),
t("services.list.electrical.items.3"),
t("services.list.electrical.items.4"),
t("services.list.electrical.items.5"),
],
},
{
icon: PaintBucket,
title: "Painting & Drywall",
description: "Transform your space with professional painting services.",
title: t("services.list.painting.title"),
description: t("services.list.painting.description"),
items: [
"Interior Painting",
"Exterior Painting",
"Drywall Installation",
"Drywall Repair",
"Texture Matching",
"Wallpaper Removal",
t("services.list.painting.items.0"),
t("services.list.painting.items.1"),
t("services.list.painting.items.2"),
t("services.list.painting.items.3"),
t("services.list.painting.items.4"),
t("services.list.painting.items.5"),
],
},
{
icon: Hammer,
title: "Carpentry",
description: "Custom carpentry work for all your woodworking needs.",
title: t("services.list.carpentry.title"),
description: t("services.list.carpentry.description"),
items: [
"Custom Shelving",
"Cabinet Installation",
"Door Installation & Repair",
"Crown Molding",
"Deck Repairs",
"Trim & Baseboards",
t("services.list.carpentry.items.0"),
t("services.list.carpentry.items.1"),
t("services.list.carpentry.items.2"),
t("services.list.carpentry.items.3"),
t("services.list.carpentry.items.4"),
t("services.list.carpentry.items.5"),
],
},
{
icon: Home,
title: "Home Repairs",
description: "General home repairs to keep your property in top shape.",
title: t("services.list.repairs.title"),
description: t("services.list.repairs.description"),
items: [
"Window Repairs",
"Door Repairs",
"Lock Installation",
"Weather Stripping",
"Caulking & Sealing",
"Minor Roof Repairs",
t("services.list.repairs.items.0"),
t("services.list.repairs.items.1"),
t("services.list.repairs.items.2"),
t("services.list.repairs.items.3"),
t("services.list.repairs.items.4"),
t("services.list.repairs.items.5"),
],
},
{
icon: Settings,
title: "Maintenance Services",
description: "Regular maintenance to prevent future problems.",
title: t("services.list.maintenance.title"),
description: t("services.list.maintenance.description"),
items: [
"Seasonal Home Inspections",
"Gutter Cleaning",
"Pressure Washing",
"HVAC Filter Changes",
"Preventive Maintenance",
"Home Safety Checks",
t("services.list.maintenance.items.0"),
t("services.list.maintenance.items.1"),
t("services.list.maintenance.items.2"),
t("services.list.maintenance.items.3"),
t("services.list.maintenance.items.4"),
t("services.list.maintenance.items.5"),
],
},
];
const process = [
{
step: "1",
title: t("services.process.items.0.title"),
description: t("services.process.items.0.description"),
},
{
step: "2",
title: t("services.process.items.1.title"),
description: t("services.process.items.1.description"),
},
{
step: "3",
title: t("services.process.items.2.title"),
description: t("services.process.items.2.description"),
},
{
step: "4",
title: t("services.process.items.3.title"),
description: t("services.process.items.3.description"),
},
];
return (
<div>
{/* Hero Section */}
<section className="bg-gradient-to-br from-orange-50 to-orange-100 py-16">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 text-center">
<h1 className="text-4xl md:text-5xl mb-6 text-gray-900">Our Services</h1>
<h1 className="text-4xl md:text-5xl mb-6 text-gray-900">
{t("services.hero.title")}
</h1>
<p className="text-xl text-gray-700 max-w-3xl mx-auto">
From minor repairs to major renovations, we offer comprehensive handyman services to meet all your home improvement needs.
{t("services.hero.subtitle")}
</p>
</div>
</section>
@@ -140,40 +168,21 @@ export function Services() {
<section className="py-16 bg-gray-50">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="text-center mb-12">
<h2 className="text-3xl md:text-4xl mb-4 text-gray-900">How It Works</h2>
<h2 className="text-3xl md:text-4xl mb-4 text-gray-900">
{t("services.process.title")}
</h2>
<p className="text-xl text-gray-600">
Getting your home repairs done is easy with our simple process
{t("services.process.subtitle")}
</p>
</div>
<div className="grid md:grid-cols-4 gap-8">
{[
{
step: "1",
title: "Contact Us",
description: "Call or fill out our online form to describe your project",
},
{
step: "2",
title: "Get a Quote",
description: "Receive a fair, transparent estimate for the work",
},
{
step: "3",
title: "Schedule Service",
description: "Choose a convenient time that works for you",
},
{
step: "4",
title: "Job Complete",
description: "We complete the work with quality and care",
},
].map((process, index) => (
{process.map((step, index) => (
<div key={index} className="text-center">
<div className="bg-orange-600 text-white w-16 h-16 rounded-full flex items-center justify-center text-2xl mx-auto mb-4">
{process.step}
{step.step}
</div>
<h3 className="text-xl mb-2 text-gray-900">{process.title}</h3>
<p className="text-gray-600">{process.description}</p>
<h3 className="text-xl mb-2 text-gray-900">{step.title}</h3>
<p className="text-gray-600">{step.description}</p>
</div>
))}
</div>
@@ -184,16 +193,16 @@ export function Services() {
<section className="py-16 bg-orange-600">
<div className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 text-center">
<h2 className="text-3xl md:text-4xl mb-6 text-white">
Need a Handyman?
{t("services.cta.title")}
</h2>
<p className="text-xl text-orange-100 mb-8">
Contact us today for a free estimate on any of our services!
{t("services.cta.subtitle")}
</p>
<Link
to="/contact"
className="inline-flex items-center bg-white text-orange-600 px-8 py-4 rounded-lg hover:bg-gray-100 transition-colors"
>
Request a Quote
{t("services.cta.button")}
<ArrowRight className="ml-2 h-5 w-5" />
</Link>
</div>
+17
View File
@@ -0,0 +1,17 @@
import i18n from "i18next";
import { initReactI18next } from "react-i18next";
import en from "./locales/en.json";
import nl from "./locales/nl.json";
i18n.use(initReactI18next).init({
resources: {
en: { translation: en },
nl: { translation: nl },
},
lng: "en",
fallbackLng: "en",
interpolation: { escapeValue: false },
});
export default i18n;
+399
View File
@@ -0,0 +1,399 @@
{
"header": {
"brand": "Lucris Handyman",
"nav": {
"home": "Home",
"services": "Services",
"about": "About Us",
"gallery": "Gallery",
"contact": "Contact"
},
"cta": "Get a Quote",
"language": "Language"
},
"footer": {
"brand": "Lucris Handyman",
"description": "Professional handyman services for all your home repair and maintenance needs. Quality work, affordable prices.",
"quickLinks": "Quick Links",
"links": {
"home": "Home",
"services": "Services",
"about": "About Us",
"gallery": "Gallery",
"contact": "Contact"
},
"ourServices": "Our Services",
"services": {
"plumbing": "Plumbing Repairs",
"electrical": "Electrical Work",
"painting": "Painting & Drywall",
"carpentry": "Carpentry",
"general": "General Repairs",
"maintenance": "Home Maintenance"
},
"contactInfo": "Contact Info",
"callUs": "Call Us",
"emailUs": "Email Us",
"location": "Location",
"hours": "Working Hours",
"hoursValue": "Mon-Sat: 8AM-6PM",
"copyright": "© 2026 Lucris Handyman. All rights reserved."
},
"about": {
"hero": {
"title": "About Lucris Handyman",
"subtitle": "Your trusted partner for all home repair and maintenance needs since 2011"
},
"story": {
"title": "Our Story",
"p1": "Lucris Handyman was founded in 2011 with a simple mission: to provide reliable, high-quality handyman services at fair prices. What started as a one-person operation has grown into a trusted team of skilled professionals serving the community.",
"p2": "Over the years, we've completed thousands of projects, from simple repairs to complete home renovations. Our reputation for quality work and excellent customer service has made us the go-to handyman service in the area.",
"p3": "Today, we continue to uphold the same values that guided us from the beginning: integrity, quality, and customer satisfaction. Every member of our team is dedicated to exceeding your expectations.",
"imageAlt": "Home renovation work"
},
"stats": {
"years": "Years in Business",
"clients": "Happy Clients",
"projects": "Projects Completed",
"satisfaction": "Customer Satisfaction"
},
"values": {
"title": "Our Values",
"subtitle": "These core principles guide everything we do",
"quality": {
"title": "Quality First",
"description": "We never compromise on the quality of our work. Every job is done right the first time."
},
"excellence": {
"title": "Professional Excellence",
"description": "Our team consists of skilled, licensed professionals with years of experience."
},
"customer": {
"title": "Customer Focus",
"description": "Your satisfaction is our priority. We listen to your needs and deliver results."
},
"reliable": {
"title": "Reliable Service",
"description": "We show up on time, every time. Count on us to be there when you need us."
}
},
"team": {
"title": "Meet Our Team",
"subtitle": "Skilled professionals dedicated to your home's care",
"members": {
"john": {
"name": "John Mitchell",
"role": "Founder & Lead Handyman",
"description": "15+ years of experience in all aspects of home repair and maintenance."
},
"david": {
"name": "David Chen",
"role": "Master Electrician",
"description": "Licensed electrician specializing in residential electrical work."
},
"robert": {
"name": "Robert Garcia",
"role": "Master Plumber",
"description": "Expert plumber with extensive experience in repairs and installations."
}
}
},
"certifications": {
"title": "Licensed & Insured",
"subtitle": "We maintain all necessary licenses and insurance for your protection and peace of mind",
"items": [
"State Licensed Contractor",
"Fully Insured & Bonded",
"BBB Accredited Business",
"Master Electrician License",
"Master Plumber License",
"OSHA Safety Certified"
]
}
},
"contact": {
"hero": {
"title": "Contact Us",
"subtitle": "Get in touch with us for a free quote or to schedule a service"
},
"info": {
"title": "Get in Touch",
"subtitle": "Have a question or ready to start your project? We'd love to hear from you. Reach out using any of the methods below.",
"phone": "Phone",
"phoneHours": "Mon-Sat: 8AM-6PM",
"email": "Email",
"emailNote": "We'll respond within 24 hours",
"address": "Address",
"addressLine1": "123 Main Street",
"addressLine2": "New York, NY 10001",
"hours": "Business Hours",
"hoursLine1": "Monday - Friday: 8:00 AM - 6:00 PM",
"hoursLine2": "Saturday: 9:00 AM - 4:00 PM",
"hoursLine3": "Sunday: Closed"
},
"emergency": {
"title": "Emergency Services",
"subtitle": "For urgent repairs outside business hours, call our emergency line:"
},
"form": {
"title": "Request a Free Quote",
"successTitle": "Thank You!",
"successMessage": "Your message has been received. We'll get back to you within 24 hours.",
"fullName": "Full Name",
"fullNamePlaceholder": "John Doe",
"phone": "Phone Number",
"phonePlaceholder": "(555) 123-4567",
"email": "Email Address",
"emailPlaceholder": "john@example.com",
"service": "Service Needed",
"servicePlaceholder": "Select a service",
"details": "Project Details",
"detailsPlaceholder": "Please describe your project in detail...",
"submit": "Send Message",
"disclaimer": "By submitting this form, you agree to our terms and privacy policy."
},
"services": {
"generalRepair": "General Repair",
"plumbing": "Plumbing",
"electrical": "Electrical",
"painting": "Painting",
"carpentry": "Carpentry",
"homeMaintenance": "Home Maintenance",
"other": "Other"
},
"map": {
"title": "Our Location",
"placeholder": "Map would be displayed here (e.g., Google Maps integration)"
}
},
"home": {
"hero": {
"title": "Your Trusted",
"titleHighlight": "Handyman Service",
"subtitle": "Professional home repair and maintenance services. From small fixes to major renovations, we do it all with quality and care.",
"ctaPrimary": "Get Free Quote",
"ctaSecondary": "Call Now",
"imageAlt": "Professional handyman at work"
},
"features": {
"licensed": "Licensed & Insured",
"sameDay": "Same-Day Service",
"quality": "Quality Workmanship",
"affordable": "Affordable Pricing",
"satisfaction": "100% Satisfaction Guarantee",
"emergency": "Emergency Services Available"
},
"services": {
"title": "Our Services",
"subtitle": "We offer a comprehensive range of handyman services to keep your home in perfect condition.",
"learnMore": "Learn More",
"viewAll": "View All Services",
"items": {
"plumbing": {
"title": "Plumbing",
"description": "From leaky faucets to pipe repairs, we handle all your plumbing needs."
},
"electrical": {
"title": "Electrical",
"description": "Safe and reliable electrical installations, repairs, and upgrades."
},
"painting": {
"title": "Painting",
"description": "Professional painting services for interior and exterior projects."
}
}
},
"about": {
"title": "Why Choose Lucris Handyman?",
"subtitle": "With over 15 years of experience, we've become the most trusted handyman service in the area. Our team of skilled professionals is committed to delivering exceptional quality and customer satisfaction.",
"learnMore": "Learn More About Us",
"imageAlt": "Handyman tools",
"points": {
"experienced": {
"title": "Experienced Professionals",
"text": "Skilled craftsmen with years of expertise"
},
"pricing": {
"title": "Fair & Transparent Pricing",
"text": "No hidden fees, upfront quotes"
},
"guarantee": {
"title": "Quality Guaranteed",
"text": "100% satisfaction or your money back"
}
}
},
"testimonials": {
"title": "What Our Clients Say",
"subtitle": "Don't just take our word for it - hear from our satisfied customers",
"items": {
"sarah": {
"name": "Sarah Johnson",
"text": "Outstanding service! They fixed our plumbing issue quickly and professionally. Highly recommend!"
},
"mike": {
"name": "Mike Thompson",
"text": "Lucris is my go-to for all home repairs. Always reliable, fair pricing, and excellent work."
},
"emily": {
"name": "Emily Davis",
"text": "They remodeled our bathroom and the results exceeded our expectations. True professionals!"
}
}
},
"cta": {
"title": "Ready to Get Started?",
"subtitle": "Contact us today for a free quote and let us take care of your home repair needs!",
"primary": "Get Free Quote",
"secondary": "Call Now"
}
},
"services": {
"hero": {
"title": "Our Services",
"subtitle": "From minor repairs to major renovations, we offer comprehensive handyman services to meet all your home improvement needs."
},
"list": {
"plumbing": {
"title": "Plumbing Services",
"description": "Expert plumbing repairs and installations for your home.",
"items": [
"Faucet & Fixture Repairs",
"Toilet Repairs & Replacement",
"Pipe Repairs & Leak Detection",
"Drain Cleaning",
"Water Heater Services",
"Garbage Disposal Installation"
]
},
"electrical": {
"title": "Electrical Work",
"description": "Safe and reliable electrical services by licensed professionals.",
"items": [
"Light Fixture Installation",
"Outlet & Switch Repair",
"Ceiling Fan Installation",
"Circuit Breaker Services",
"Home Rewiring",
"Electrical Safety Inspections"
]
},
"painting": {
"title": "Painting & Drywall",
"description": "Transform your space with professional painting services.",
"items": [
"Interior Painting",
"Exterior Painting",
"Drywall Installation",
"Drywall Repair",
"Texture Matching",
"Wallpaper Removal"
]
},
"carpentry": {
"title": "Carpentry",
"description": "Custom carpentry work for all your woodworking needs.",
"items": [
"Custom Shelving",
"Cabinet Installation",
"Door Installation & Repair",
"Crown Molding",
"Deck Repairs",
"Trim & Baseboards"
]
},
"repairs": {
"title": "Home Repairs",
"description": "General home repairs to keep your property in top shape.",
"items": [
"Window Repairs",
"Door Repairs",
"Lock Installation",
"Weather Stripping",
"Caulking & Sealing",
"Minor Roof Repairs"
]
},
"maintenance": {
"title": "Maintenance Services",
"description": "Regular maintenance to prevent future problems.",
"items": [
"Seasonal Home Inspections",
"Gutter Cleaning",
"Pressure Washing",
"HVAC Filter Changes",
"Preventive Maintenance",
"Home Safety Checks"
]
}
},
"process": {
"title": "How It Works",
"subtitle": "Getting your home repairs done is easy with our simple process",
"items": [
{
"title": "Contact Us",
"description": "Call or fill out our online form to describe your project"
},
{
"title": "Get a Quote",
"description": "Receive a fair, transparent estimate for the work"
},
{
"title": "Schedule Service",
"description": "Choose a convenient time that works for you"
},
{
"title": "Job Complete",
"description": "We complete the work with quality and care"
}
]
},
"cta": {
"title": "Need a Handyman?",
"subtitle": "Contact us today for a free estimate on any of our services!",
"button": "Request a Quote"
}
},
"gallery": {
"hero": {
"title": "Project Gallery",
"subtitle": "Browse through our portfolio of completed projects and see the quality of our work"
},
"categories": {
"all": "All",
"plumbing": "Plumbing",
"electrical": "Electrical",
"painting": "Painting",
"carpentry": "Carpentry",
"renovation": "Renovation"
},
"projects": {
"kitchen": {
"title": "Kitchen Renovation",
"description": "Complete kitchen remodel with custom cabinets and new fixtures"
},
"plumbing": {
"title": "Plumbing Repair",
"description": "Professional pipe repair and fixture installation"
},
"electrical": {
"title": "Electrical Installation",
"description": "Safe and reliable electrical work with proper certification"
},
"painting": {
"title": "Interior Painting",
"description": "Professional interior painting with attention to detail"
},
"carpentry": {
"title": "Custom Carpentry",
"description": "Custom woodworking and carpentry projects"
},
"maintenance": {
"title": "Home Maintenance",
"description": "Regular home maintenance and repair services"
}
},
"empty": "No projects found in this category."
}
}
+399
View File
@@ -0,0 +1,399 @@
{
"header": {
"brand": "Lucris Handyman",
"nav": {
"home": "Home",
"services": "Diensten",
"about": "Over ons",
"gallery": "Galerij",
"contact": "Contact"
},
"cta": "Offerte aanvragen",
"language": "Taal"
},
"footer": {
"brand": "Lucris Handyman",
"description": "Professionele klusdiensten voor al uw reparatie- en onderhoudsbehoeften. Kwaliteit, betaalbare prijzen.",
"quickLinks": "Snelle links",
"links": {
"home": "Home",
"services": "Diensten",
"about": "Over ons",
"gallery": "Galerij",
"contact": "Contact"
},
"ourServices": "Onze diensten",
"services": {
"plumbing": "Loodgieterswerk",
"electrical": "Elektrisch werk",
"painting": "Schilder- & stucwerk",
"carpentry": "Timmerwerk",
"general": "Algemene reparaties",
"maintenance": "Woningonderhoud"
},
"contactInfo": "Contactgegevens",
"callUs": "Bel ons",
"emailUs": "E-mail",
"location": "Locatie",
"hours": "Openingstijden",
"hoursValue": "Ma-Za: 08:00-18:00",
"copyright": "© 2026 Lucris Handyman. Alle rechten voorbehouden."
},
"about": {
"hero": {
"title": "Over Lucris Handyman",
"subtitle": "Uw vertrouwde partner voor al uw woningreparaties en onderhoud sinds 2011"
},
"story": {
"title": "Ons Verhaal",
"p1": "Lucris Handyman is in 2011 opgericht met één eenvoudige missie: betrouwbare, hoogwaardige klusdiensten leveren tegen eerlijke prijzen. Wat begon als een eenmanszaak is uitgegroeid tot een vertrouwd team van vakmensen in de gemeenschap.",
"p2": "In de loop der jaren hebben we duizenden projecten afgerond, van kleine reparaties tot complete renovaties. Onze reputatie voor kwaliteit en uitstekende service heeft ons de vaste klusdienst in de regio gemaakt.",
"p3": "Vandaag houden we vast aan dezelfde waarden als vanaf het begin: integriteit, kwaliteit en klanttevredenheid. Ieder teamlid zet zich in om uw verwachtingen te overtreffen.",
"imageAlt": "Werkzaamheden aan woningrenovatie"
},
"stats": {
"years": "Jaren actief",
"clients": "Tevreden klanten",
"projects": "Projecten afgerond",
"satisfaction": "Klanttevredenheid"
},
"values": {
"title": "Onze waarden",
"subtitle": "Deze kernprincipes sturen alles wat we doen",
"quality": {
"title": "Kwaliteit voorop",
"description": "We doen nooit concessies aan de kwaliteit van ons werk. Elke klus wordt in één keer goed uitgevoerd."
},
"excellence": {
"title": "Professionele excellentie",
"description": "Ons team bestaat uit bekwame, gecertificeerde vakmensen met jaren ervaring."
},
"customer": {
"title": "Klantgericht",
"description": "Uw tevredenheid staat centraal. We luisteren naar uw wensen en leveren resultaat."
},
"reliable": {
"title": "Betrouwbare service",
"description": "We zijn op tijd, altijd. U kunt op ons rekenen wanneer u ons nodig heeft."
}
},
"team": {
"title": "Maak kennis met ons team",
"subtitle": "Vakkundige professionals die zorgen voor uw woning",
"members": {
"john": {
"name": "John Mitchell",
"role": "Oprichter & Lead Handyman",
"description": "Meer dan 15 jaar ervaring in alle aspecten van woningreparatie en onderhoud."
},
"david": {
"name": "David Chen",
"role": "Hoofdelektricien",
"description": "Gediplomeerd elektricien gespecialiseerd in residentiële installaties."
},
"robert": {
"name": "Robert Garcia",
"role": "Hoofdloodgieter",
"description": "Expert-loodgieter met uitgebreide ervaring in reparaties en installaties."
}
}
},
"certifications": {
"title": "Gelicentieerd & verzekerd",
"subtitle": "Wij beschikken over alle benodigde licenties en verzekeringen voor uw bescherming en gemoedsrust",
"items": [
"Gelicentieerde aannemer",
"Volledig verzekerd & gebonden",
"BBB-geaccrediteerd bedrijf",
"Master Electrician-licentie",
"Master Plumber-licentie",
"OSHA-veiligheidscertificering"
]
}
},
"contact": {
"hero": {
"title": "Contact",
"subtitle": "Neem contact op voor een gratis offerte of om een dienst in te plannen"
},
"info": {
"title": "Neem contact op",
"subtitle": "Heb je een vraag of wil je starten met je project? We horen graag van je. Neem contact op via een van onderstaande manieren.",
"phone": "Telefoon",
"phoneHours": "Ma-Za: 08:00-18:00",
"email": "E-mail",
"emailNote": "We reageren binnen 24 uur",
"address": "Adres",
"addressLine1": "123 Main Street",
"addressLine2": "New York, NY 10001",
"hours": "Openingstijden",
"hoursLine1": "Maandag - Vrijdag: 08:00 - 18:00",
"hoursLine2": "Zaterdag: 09:00 - 16:00",
"hoursLine3": "Zondag: Gesloten"
},
"emergency": {
"title": "Spoedservice",
"subtitle": "Voor urgente reparaties buiten openingstijden, bel onze spoedlijn:"
},
"form": {
"title": "Vraag een gratis offerte aan",
"successTitle": "Bedankt!",
"successMessage": "Je bericht is ontvangen. We nemen binnen 24 uur contact met je op.",
"fullName": "Volledige naam",
"fullNamePlaceholder": "Jan Jansen",
"phone": "Telefoonnummer",
"phonePlaceholder": "(555) 123-4567",
"email": "E-mailadres",
"emailPlaceholder": "jan@example.com",
"service": "Benodigde dienst",
"servicePlaceholder": "Selecteer een dienst",
"details": "Projectdetails",
"detailsPlaceholder": "Beschrijf je project in detail...",
"submit": "Bericht verzenden",
"disclaimer": "Door dit formulier te verzenden, ga je akkoord met onze voorwaarden en privacybeleid."
},
"services": {
"generalRepair": "Algemene reparatie",
"plumbing": "Loodgieterswerk",
"electrical": "Elektrisch",
"painting": "Schilderwerk",
"carpentry": "Timmerwerk",
"homeMaintenance": "Woningonderhoud",
"other": "Overig"
},
"map": {
"title": "Onze locatie",
"placeholder": "Hier wordt een kaart weergegeven (bijv. Google Maps-integratie)"
}
},
"home": {
"hero": {
"title": "Uw vertrouwde",
"titleHighlight": "klusservice",
"subtitle": "Professionele diensten voor woningreparatie en onderhoud. Van kleine fixes tot grote renovaties — wij doen het met kwaliteit en zorg.",
"ctaPrimary": "Gratis offerte",
"ctaSecondary": "Bel nu",
"imageAlt": "Professionele klusser aan het werk"
},
"features": {
"licensed": "Gelicentieerd & verzekerd",
"sameDay": "Service op dezelfde dag",
"quality": "Vakmanschap van kwaliteit",
"affordable": "Betaalbare prijzen",
"satisfaction": "100% tevredenheidsgarantie",
"emergency": "Spoedservice beschikbaar"
},
"services": {
"title": "Onze diensten",
"subtitle": "We bieden een complete reeks klusdiensten om uw woning in topconditie te houden.",
"learnMore": "Meer info",
"viewAll": "Bekijk alle diensten",
"items": {
"plumbing": {
"title": "Loodgieterswerk",
"description": "Van lekkende kranen tot leidingreparaties — wij lossen het op."
},
"electrical": {
"title": "Elektrisch",
"description": "Veilige en betrouwbare elektrische installaties, reparaties en upgrades."
},
"painting": {
"title": "Schilderwerk",
"description": "Professioneel schilderwerk voor binnen en buiten."
}
}
},
"about": {
"title": "Waarom Lucris Handyman?",
"subtitle": "Met meer dan 15 jaar ervaring zijn we de meest vertrouwde klusservice in de regio. Ons team levert uitzonderlijke kwaliteit en klanttevredenheid.",
"learnMore": "Meer over ons",
"imageAlt": "Gereedschap van de klusser",
"points": {
"experienced": {
"title": "Ervaren vakmensen",
"text": "Vakkundige professionals met jaren expertise"
},
"pricing": {
"title": "Eerlijke & transparante prijzen",
"text": "Geen verborgen kosten, duidelijke offertes"
},
"guarantee": {
"title": "Kwaliteit gegarandeerd",
"text": "100% tevreden of geld terug"
}
}
},
"testimonials": {
"title": "Wat onze klanten zeggen",
"subtitle": "Geloof ons niet op ons woord — hoor het van onze klanten",
"items": {
"sarah": {
"name": "Sarah Johnson",
"text": "Uitstekende service! Ze hebben ons loodgietersprobleem snel en professioneel opgelost. Aanrader!"
},
"mike": {
"name": "Mike Thompson",
"text": "Lucris is mijn vaste adres voor klussen. Altijd betrouwbaar, eerlijke prijzen en uitstekend werk."
},
"emily": {
"name": "Emily Davis",
"text": "Ze hebben onze badkamer gerenoveerd en het resultaat overtrof onze verwachtingen. Echte professionals!"
}
}
},
"cta": {
"title": "Klaar om te starten?",
"subtitle": "Neem vandaag nog contact op voor een gratis offerte en laat ons uw woningklussen verzorgen!",
"primary": "Gratis offerte",
"secondary": "Bel nu"
}
},
"services": {
"hero": {
"title": "Onze diensten",
"subtitle": "Van kleine reparaties tot grote renovaties: wij bieden uitgebreide klusdiensten voor al uw woningverbetering."
},
"list": {
"plumbing": {
"title": "Loodgieterswerk",
"description": "Vakkundige reparaties en installaties voor uw sanitair.",
"items": [
"Kraan- & armatuurreparaties",
"Toiletreparaties & vervanging",
"Leidingreparaties & lekdetectie",
"Afvoer reinigen",
"Boiler- en warmwaterservices",
"Plaatsing van afvalvermaler"
]
},
"electrical": {
"title": "Elektrisch werk",
"description": "Veilige en betrouwbare elektrische diensten door gecertificeerde professionals.",
"items": [
"Installatie van lichtarmaturen",
"Reparatie van stopcontacten & schakelaars",
"Plafondventilator installatie",
"Groepenkast & zekeringservices",
"Herverdading van de woning",
"Elektrische veiligheidsinspecties"
]
},
"painting": {
"title": "Schilder- & stucwerk",
"description": "Geef uw ruimte een nieuwe look met professioneel schilderwerk.",
"items": [
"Binnen schilderwerk",
"Buiten schilderwerk",
"Gipsplaat installatie",
"Gipsplaat reparatie",
"Structuur bijwerken",
"Behang verwijderen"
]
},
"carpentry": {
"title": "Timmerwerk",
"description": "Maatwerk timmerwerk voor al uw houtwerkprojecten.",
"items": [
"Maatwerk planken",
"Keukenkast installatie",
"Deur installatie & reparatie",
"Sierlijsten",
"Dekreparaties",
"Plinten & afwerking"
]
},
"repairs": {
"title": "Woningreparaties",
"description": "Algemene reparaties om uw woning in topconditie te houden.",
"items": [
"Raamreparaties",
"Deurreparaties",
"Sloten plaatsen",
"Tochtstrips",
"Afdichten & kitten",
"Kleine dakreparaties"
]
},
"maintenance": {
"title": "Onderhoudsdiensten",
"description": "Regelmatig onderhoud om toekomstige problemen te voorkomen.",
"items": [
"Seizoensinspecties",
"Dakgootreiniging",
"Hogedrukreiniging",
"HVAC-filter vervangen",
"Preventief onderhoud",
"Woningveiligheidschecks"
]
}
},
"process": {
"title": "Hoe het werkt",
"subtitle": "Uw klus is zo geregeld met ons eenvoudige proces",
"items": [
{
"title": "Neem contact op",
"description": "Bel of vul ons online formulier in om uw project te beschrijven"
},
{
"title": "Ontvang een offerte",
"description": "Krijg een eerlijke en transparante prijsopgave"
},
{
"title": "Plan de service",
"description": "Kies een moment dat u het beste uitkomt"
},
{
"title": "Klus afgerond",
"description": "We voeren het werk uit met kwaliteit en zorg"
}
]
},
"cta": {
"title": "Een klusser nodig?",
"subtitle": "Neem vandaag nog contact op voor een gratis offerte voor onze diensten!",
"button": "Offerte aanvragen"
}
},
"gallery": {
"hero": {
"title": "Projectgalerij",
"subtitle": "Bekijk ons portfolio van afgeronde projecten en zie de kwaliteit van ons werk"
},
"categories": {
"all": "Alle",
"plumbing": "Loodgieterswerk",
"electrical": "Elektrisch",
"painting": "Schilderwerk",
"carpentry": "Timmerwerk",
"renovation": "Renovatie"
},
"projects": {
"kitchen": {
"title": "Keukenrenovatie",
"description": "Volledige keukenrenovatie met maatwerk kasten en nieuwe armaturen"
},
"plumbing": {
"title": "Loodgietersreparatie",
"description": "Professionele leidingreparatie en installatie van armaturen"
},
"electrical": {
"title": "Elektrische installatie",
"description": "Veilig en betrouwbaar elektrisch werk met juiste certificering"
},
"painting": {
"title": "Binnenschilderwerk",
"description": "Professioneel binnenschilderwerk met oog voor detail"
},
"carpentry": {
"title": "Maatwerk timmerwerk",
"description": "Maatwerk hout- en timmerprojecten"
},
"maintenance": {
"title": "Woningonderhoud",
"description": "Regelmatig woningonderhoud en reparatiediensten"
}
},
"empty": "Geen projecten gevonden in deze categorie."
}
}
+5 -6
View File
@@ -1,7 +1,6 @@
import { createRoot } from "react-dom/client";
import App from "./app/App.tsx";
import "./styles/index.css";
import "./i18n";
import { createRoot } from "react-dom/client";
import App from "./app/App.tsx";
import "./styles/index.css";
createRoot(document.getElementById("root")!).render(<App />);
createRoot(document.getElementById("root")!).render(<App />);