File tree Expand file tree Collapse file tree 6 files changed +106
-3
lines changed
Expand file tree Collapse file tree 6 files changed +106
-3
lines changed Original file line number Diff line number Diff line change @@ -6,6 +6,7 @@ import { Projects } from '@/components/sections/projects';
66import { Navbar } from '@/components/sections/navbar' ;
77import { getDictionary , type Locale } from '@/lib/i18n' ;
88import { notFound } from 'next/navigation' ;
9+ import { LangRedirect } from '@/components/lang-redirect' ;
910
1011type Params = { lang : Locale } ;
1112
@@ -20,7 +21,8 @@ export default function LangPage({ params }: { params: Params }) {
2021 const dict = getDictionary ( params . lang ) ;
2122 return (
2223 < main className = "min-h-screen" >
23- < Navbar content = { dict . nav } />
24+ < LangRedirect currentLocale = { params . lang } />
25+ < Navbar content = { dict . nav } currentLocale = { params . lang } />
2426 < div className = "bg-page-gradient" >
2527 < Hero content = { dict . hero } />
2628 < About content = { dict . about } />
Original file line number Diff line number Diff line change @@ -5,12 +5,14 @@ import { Hero } from '@/components/sections/hero';
55import { Projects } from '@/components/sections/projects' ;
66import { Navbar } from '@/components/sections/navbar' ;
77import { getDictionary } from '@/lib/i18n' ;
8+ import { LangRedirect } from '@/components/lang-redirect' ;
89
910export default function HomePage ( ) {
1011 const dict = getDictionary ( 'es' ) ;
1112 return (
1213 < main className = "min-h-screen" >
13- < Navbar content = { dict . nav } />
14+ < LangRedirect currentLocale = "es" />
15+ < Navbar content = { dict . nav } currentLocale = "es" />
1416 < div className = "bg-page-gradient" >
1517 < Hero content = { dict . hero } />
1618 < About content = { dict . about } />
Original file line number Diff line number Diff line change 1+ 'use client' ;
2+
3+ import { normalizeLocale , type Locale } from '@/lib/i18n' ;
4+ import { useEffect } from 'react' ;
5+
6+ const STORAGE_KEY = 'preferred-lang' ;
7+
8+ function pathForLocale ( locale : Locale ) : string {
9+ return locale === 'es' ? '/' : `/${ locale } ` ;
10+ }
11+
12+ export function LangRedirect ( { currentLocale } : { currentLocale : Locale } ) {
13+ useEffect ( ( ) => {
14+ const stored = localStorage . getItem ( STORAGE_KEY ) ;
15+ if ( stored === 'en' || stored === 'es' ) {
16+ if ( stored !== currentLocale ) {
17+ window . location . assign ( pathForLocale ( stored ) ) ;
18+ }
19+ return ;
20+ }
21+
22+ const navigatorLang =
23+ typeof navigator !== 'undefined' ? navigator . language || navigator . languages ?. [ 0 ] : undefined ;
24+ const detected = normalizeLocale ( navigatorLang ) ;
25+
26+ if ( detected !== currentLocale ) {
27+ localStorage . setItem ( STORAGE_KEY , detected ) ;
28+ window . location . assign ( pathForLocale ( detected ) ) ;
29+ }
30+ } , [ currentLocale ] ) ;
31+
32+ return null ;
33+ }
Original file line number Diff line number Diff line change 1+ 'use client' ;
2+
3+ import type { Locale } from '@/lib/i18n' ;
4+ import { cn } from '@/lib/utils' ;
5+ import { useEffect , useState } from 'react' ;
6+ import { useRouter } from 'next/navigation' ;
7+
8+ const STORAGE_KEY = 'preferred-lang' ;
9+
10+ function pathForLocale ( locale : Locale ) : string {
11+ return locale === 'es' ? '/' : `/${ locale } ` ;
12+ }
13+
14+ type Props = {
15+ current : Locale ;
16+ className ?: string ;
17+ } ;
18+
19+ export function LangSwitcher ( { current, className } : Props ) {
20+ const router = useRouter ( ) ;
21+ const [ active , setActive ] = useState < Locale > ( current ) ;
22+
23+ useEffect ( ( ) => {
24+ setActive ( current ) ;
25+ } , [ current ] ) ;
26+
27+ function handleChange ( locale : Locale ) {
28+ if ( locale === active ) return ;
29+ setActive ( locale ) ;
30+ localStorage . setItem ( STORAGE_KEY , locale ) ;
31+ router . push ( pathForLocale ( locale ) ) ;
32+ }
33+
34+ return (
35+ < div className = { cn ( 'flex items-center gap-1 rounded-full border border-white/10 bg-white/5 px-1 py-0.5' , className ) } >
36+ { ( [ 'es' , 'en' ] as Locale [ ] ) . map ( ( locale ) => (
37+ < button
38+ key = { locale }
39+ type = "button"
40+ onClick = { ( ) => handleChange ( locale ) }
41+ className = { cn (
42+ 'px-2 py-1 text-xs rounded-full transition-colors' ,
43+ active === locale
44+ ? 'bg-accent-mint/20 text-accent-mint'
45+ : 'text-base-muted hover:text-base-text'
46+ ) }
47+ aria-pressed = { active === locale }
48+ >
49+ { locale . toUpperCase ( ) }
50+ </ button >
51+ ) ) }
52+ </ div >
53+ ) ;
54+ }
Original file line number Diff line number Diff line change 11import Link from 'next/link' ;
22import type { NavContent } from '@/lib/i18n' ;
3+ import { LangSwitcher } from '@/components/lang-switcher' ;
4+ import type { Locale } from '@/lib/i18n' ;
35
46type Props = {
57 content : NavContent ;
8+ currentLocale : Locale ;
69} ;
710
8- export function Navbar ( { content } : Props ) {
11+ export function Navbar ( { content, currentLocale } : Props ) {
912 return (
1013 < header className = "sticky top-0 z-20 bg-base-bg/70 backdrop-blur-md border-b border-white/10" >
1114 < div className = "max-w-6xl mx-auto px-4 h-14 flex items-center justify-between" >
@@ -18,6 +21,7 @@ export function Navbar({ content }: Props) {
1821 { link . label }
1922 </ Link >
2023 ) ) }
24+ < LangSwitcher current = { currentLocale } />
2125 </ nav >
2226 </ div >
2327 </ header >
Original file line number Diff line number Diff line change 11export type Locale = 'es' | 'en' ;
22
3+ export function normalizeLocale ( input ?: string ) : Locale {
4+ if ( ! input ) return 'es' ;
5+ const lower = input . toLowerCase ( ) ;
6+ if ( lower . startsWith ( 'en' ) ) return 'en' ;
7+ if ( lower . startsWith ( 'es' ) ) return 'es' ;
8+ return 'es' ;
9+ }
10+
311export type NavContent = {
412 brand : string ;
513 links : { href : string ; label : string } [ ] ;
You can’t perform that action at this time.
0 commit comments