feat: implement i18n routing and add localized footer component

This commit is contained in:
Yolando
2026-04-03 18:52:14 +07:00
parent b5a6acc622
commit 43c3bf45d1
5 changed files with 17 additions and 22 deletions

View File

@@ -159,7 +159,10 @@
} }
}, },
"Footer": { "Footer": {
"description": "Building secure, scalable, enterprise-grade systems. Specializing in banking & fintech infrastructure.",
"quickLinksTitle": "Quick Links",
"connectTitle": "Connect",
"backToTop": "Back to top", "backToTop": "Back to top",
"copyright": "Yolando. Built with Next.js & crafted with purpose." "copyright": "Yolando. All Rights Reserved."
} }
} }

View File

@@ -159,7 +159,10 @@
} }
}, },
"Footer": { "Footer": {
"description": "Membangun sistem tingkat enterprise yang aman dan dapat diskalakan. Terspesialisasi dalam infrastruktur perbankan & fintech.",
"quickLinksTitle": "Tautan Cepat",
"connectTitle": "Terhubung",
"backToTop": "Kembali ke atas", "backToTop": "Kembali ke atas",
"copyright": "Yolando. Dibangun dengan Next.js & dibuat dengan penuh tujuan." "copyright": "Yolando. Semua Hak Cipta Dilindungi."
} }
} }

View File

@@ -147,9 +147,6 @@ export function ContactSection() {
{/* Right — Form */} {/* Right — Form */}
<div className="lg:col-span-3 relative p-6 md:p-8 rounded-2xl bg-card border border-border/50 shadow-lg"> <div className="lg:col-span-3 relative p-6 md:p-8 rounded-2xl bg-card border border-border/50 shadow-lg">
{/* Subtle top accent */}
<div className="absolute top-0 inset-x-0 h-0.5 bg-gradient-to-r from-accent to-purple-500 rounded-t-2xl" />
{/* Success overlay */} {/* Success overlay */}
{formState === "success" && ( {formState === "success" && (
<div className="absolute inset-0 flex items-center justify-center bg-card/95 rounded-2xl z-10"> <div className="absolute inset-0 flex items-center justify-center bg-card/95 rounded-2xl z-10">

View File

@@ -4,7 +4,8 @@ import {createNavigation} from 'next-intl/navigation';
export const routing = defineRouting({ export const routing = defineRouting({
locales: ['id', 'en'], locales: ['id', 'en'],
defaultLocale: 'id', defaultLocale: 'id',
localePrefix: 'as-needed' // Don't show /id for the default locale localePrefix: 'as-needed', // Don't show /id for the default locale
localeDetection: false // Force id on first visit regardless of browser lang
}); });
export const {Link, redirect, usePathname, useRouter, getPathname} = createNavigation(routing); export const {Link, redirect, usePathname, useRouter, getPathname} = createNavigation(routing);

View File

@@ -10,6 +10,7 @@ const quickLinks = [
export function Footer() { export function Footer() {
const t = useTranslations("Footer"); const t = useTranslations("Footer");
const tNav = useTranslations("Navigation");
return ( return (
<footer className="relative border-t border-border/50 bg-card/50"> <footer className="relative border-t border-border/50 bg-card/50">
@@ -29,8 +30,7 @@ export function Footer() {
</span> </span>
</div> </div>
<p className="text-sm text-muted-foreground leading-relaxed mb-4 max-w-xs"> <p className="text-sm text-muted-foreground leading-relaxed mb-4 max-w-xs">
Building secure, scalable, enterprise-grade systems. {t("description")}
Specializing in banking & fintech infrastructure.
</p> </p>
<div className="flex items-center gap-1.5 text-xs text-muted-foreground/60"> <div className="flex items-center gap-1.5 text-xs text-muted-foreground/60">
<MapPin size={12} /> <MapPin size={12} />
@@ -41,7 +41,7 @@ export function Footer() {
{/* Quick Links */} {/* Quick Links */}
<div> <div>
<h4 className="text-sm font-bold mb-4 uppercase tracking-wider text-muted-foreground"> <h4 className="text-sm font-bold mb-4 uppercase tracking-wider text-muted-foreground">
Quick Links {t("quickLinksTitle", { fallback: "Quick Links" })}
</h4> </h4>
<div className="space-y-2.5"> <div className="space-y-2.5">
{quickLinks.map((link) => ( {quickLinks.map((link) => (
@@ -50,7 +50,7 @@ export function Footer() {
href={link.href} href={link.href}
className="block text-sm text-muted-foreground hover:text-accent transition-colors" className="block text-sm text-muted-foreground hover:text-accent transition-colors"
> >
{link.label} {tNav(link.label?.toLowerCase() === "tech stack" ? "techStack" : link.label.toLowerCase() as any)}
</a> </a>
))} ))}
</div> </div>
@@ -60,20 +60,11 @@ export function Footer() {
<div className="flex flex-col items-start md:items-end gap-6"> <div className="flex flex-col items-start md:items-end gap-6">
<div> <div>
<h4 className="text-sm font-bold mb-4 uppercase tracking-wider text-muted-foreground md:text-right"> <h4 className="text-sm font-bold mb-4 uppercase tracking-wider text-muted-foreground md:text-right">
Connect {t("connectTitle", { fallback: "Connect" })}
</h4> </h4>
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<a <a
href="https://github.com/yolandoando" href="https://www.linkedin.com/in/yolando-asri-e-g-manullang/"
target="_blank"
rel="noopener noreferrer"
className="p-2.5 rounded-xl bg-muted/50 border border-border/50 hover:bg-accent hover:text-accent-foreground hover:border-accent transition-all duration-300 hover:scale-105 hover:shadow-lg hover:shadow-accent/20"
aria-label="GitHub"
>
<GitFork size={18} />
</a>
<a
href="https://linkedin.com/in/yolandoando"
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
className="p-2.5 rounded-xl bg-muted/50 border border-border/50 hover:bg-accent hover:text-accent-foreground hover:border-accent transition-all duration-300 hover:scale-105 hover:shadow-lg hover:shadow-accent/20" className="p-2.5 rounded-xl bg-muted/50 border border-border/50 hover:bg-accent hover:text-accent-foreground hover:border-accent transition-all duration-300 hover:scale-105 hover:shadow-lg hover:shadow-accent/20"
@@ -82,7 +73,7 @@ export function Footer() {
<Link2 size={18} /> <Link2 size={18} />
</a> </a>
<a <a
href="mailto:yolando@pm.me" href="mailto:yolandomanullang@gmail.com"
className="p-2.5 rounded-xl bg-muted/50 border border-border/50 hover:bg-accent hover:text-accent-foreground hover:border-accent transition-all duration-300 hover:scale-105 hover:shadow-lg hover:shadow-accent/20" className="p-2.5 rounded-xl bg-muted/50 border border-border/50 hover:bg-accent hover:text-accent-foreground hover:border-accent transition-all duration-300 hover:scale-105 hover:shadow-lg hover:shadow-accent/20"
aria-label="Email" aria-label="Email"
> >