x
This commit is contained in:
1 parent
3c4bb06003
commit
f7aa4d099f
36 files changed
+528
-180
No files matched your search
@@ -7,11 +7,13 @@ import i18n from '../lib/i18n';
|
||||
|
||||
export default function ClientProviders({ children }: { children: ReactNode }) {
|
||||
useEffect(() => {
|
||||
const savedLang = localStorage.getItem('homaroma_lang')
|
||||
|
||||
// Hydrate from the user's persisted language only after the first client render.
|
||||
if (savedLang && savedLang !== i18n.language) {
|
||||
void i18n.changeLanguage(savedLang)
|
||||
// With Locale Routing, the URL is the source of truth for language.
|
||||
// Sync i18n to match the current URL if needed.
|
||||
const pathLang = window.location.pathname.split('/')[1];
|
||||
const targetLang = pathLang && ['th', 'en', 'ja', 'zh', 'vi', 'ko'].includes(pathLang) ? pathLang : 'th';
|
||||
|
||||
if (targetLang !== i18n.language) {
|
||||
void i18n.changeLanguage(targetLang);
|
||||
}
|
||||
}, [])
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { useState, useEffect } from 'react'
|
||||
import Link from 'next/link'
|
||||
import Link from './LocalizedLink'
|
||||
import type { Category, MenuItem, StoreSettings } from '@homaroma/types'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { resolveLocalized } from '../lib/localization'
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
'use client';
|
||||
|
||||
import Link, { LinkProps } from 'next/link';
|
||||
import { usePathname } from 'next/navigation';
|
||||
import { useMemo } from 'react';
|
||||
import { getPathWithLocale, SUPPORTED_LOCALES } from '../lib/locales';
|
||||
|
||||
interface LocalizedLinkProps extends Omit<React.AnchorHTMLAttributes<HTMLAnchorElement>, keyof LinkProps>, LinkProps {
|
||||
children: React.ReactNode;
|
||||
activeClassName?: string;
|
||||
exact?: boolean;
|
||||
}
|
||||
|
||||
export default function LocalizedLink({
|
||||
href,
|
||||
children,
|
||||
className = '',
|
||||
activeClassName = '',
|
||||
exact = false,
|
||||
...props
|
||||
}: LocalizedLinkProps) {
|
||||
const pathname = usePathname();
|
||||
|
||||
// Extract current locale from pathname
|
||||
const currentLocale = useMemo(() => {
|
||||
const segments = pathname.split('/').filter(Boolean);
|
||||
if (segments.length > 0 && SUPPORTED_LOCALES.includes(segments[0] as any)) {
|
||||
return segments[0];
|
||||
}
|
||||
return 'th'; // Fallback
|
||||
}, [pathname]);
|
||||
|
||||
// Resolve the localized href
|
||||
const localizedHref = useMemo(() => {
|
||||
if (typeof href === 'string') {
|
||||
return getPathWithLocale(href, currentLocale);
|
||||
}
|
||||
if (typeof href === 'object' && href.pathname) {
|
||||
return {
|
||||
...href,
|
||||
pathname: getPathWithLocale(href.pathname, currentLocale)
|
||||
};
|
||||
}
|
||||
return href;
|
||||
}, [href, currentLocale]);
|
||||
|
||||
// Check if link is active
|
||||
const isActive = useMemo(() => {
|
||||
const targetPath = typeof localizedHref === 'string' ? localizedHref : localizedHref.pathname || '';
|
||||
if (exact) {
|
||||
return pathname === targetPath;
|
||||
}
|
||||
return pathname.startsWith(targetPath) && targetPath !== `/${currentLocale}`;
|
||||
}, [pathname, localizedHref, exact, currentLocale]);
|
||||
|
||||
const combinedClassName = `${className} ${isActive ? activeClassName : ''}`.trim();
|
||||
|
||||
return (
|
||||
<Link href={localizedHref} className={combinedClassName} {...props}>
|
||||
{children}
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
"use client"
|
||||
|
||||
import Link from 'next/link'
|
||||
import Link from './LocalizedLink'
|
||||
import { getPathWithoutLocale, getPathWithLocale } from '../lib/locales'
|
||||
import { useRouter, usePathname } from 'next/navigation'
|
||||
import { useState, useEffect, useMemo, useRef } from 'react'
|
||||
import type { Category } from '@homaroma/types'
|
||||
@@ -89,7 +90,13 @@ export default function Navbar({ categories = [], initialMenu = [], settings = n
|
||||
const changeLanguage = (code: string) => {
|
||||
i18n.changeLanguage(code)
|
||||
localStorage.setItem('homaroma_lang', code)
|
||||
document.cookie = `homaroma_lang=${code}; path=/; max-age=31536000`
|
||||
|
||||
const currentPathWithoutLang = getPathWithoutLocale(pathname)
|
||||
const newPath = getPathWithLocale(currentPathWithoutLang, code)
|
||||
|
||||
setLangSheetOpen(false)
|
||||
router.push(newPath)
|
||||
}
|
||||
|
||||
const loginWithLine = () => {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"use client"
|
||||
|
||||
import Link from 'next/link'
|
||||
import Link from '../LocalizedLink'
|
||||
import { useState, useRef } from 'react'
|
||||
import type { MegaMenuPayload } from './menuTypes'
|
||||
import { getLocalizedMenuText } from './menuTypes'
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"use client"
|
||||
|
||||
import { useEffect, useState } from 'react'
|
||||
import Link from 'next/link'
|
||||
import Link from '../LocalizedLink'
|
||||
import { ChevronLeft, ChevronRight, Globe, X } from 'lucide-react'
|
||||
import type { MegaMenuPayload, MenuColumn, MenuLink } from './menuTypes'
|
||||
import { getLocalizedMenuText } from './menuTypes'
|
||||
|
||||
Reference in new issue
Block a user