feat: implement internationalization and routing for locale-based pages
- Added RootLayout component to handle locale and message loading. - Created Home page with header, about info, products, and story sections. - Developed ProductPage for displaying product categories and products. - Implemented ProductsPage to list product categories with banners. - Added Projects page with a grid layout for project display. - Configured server settings for port and host. - Established navigation and routing for internationalization. - Set up request handling for locale and message retrieval. - Defined routing structure for supported locales. - Created middleware for locale-based routing. - Defined layout parameters for locale handling.
This commit is contained in:
@@ -0,0 +1,30 @@
|
||||
import images from '@/assets/images/images';
|
||||
import InnerPageBanner from '@/components/layout/innerPages/banner';
|
||||
import AboutTopInfo from '@/components/pages/about/TopInfo';
|
||||
import { ILayoutLocaleParams } from '@/models/layout';
|
||||
import { useTranslations } from 'next-intl';
|
||||
import { setRequestLocale } from 'next-intl/server';
|
||||
import { getTranslations } from 'next-intl/server';
|
||||
|
||||
export default async function AboutUs({
|
||||
params,
|
||||
}: Readonly<{
|
||||
params: ILayoutLocaleParams;
|
||||
}>) {
|
||||
const { locale } = await params;
|
||||
|
||||
// Enable static rendering
|
||||
setRequestLocale(locale);
|
||||
|
||||
const t = await getTranslations({ locale });
|
||||
|
||||
return (
|
||||
<main className="flex flex-col items-center justify-between">
|
||||
<InnerPageBanner
|
||||
title={t('pages_about_title')}
|
||||
imageSrc={images.aboutBanner.src}
|
||||
/>
|
||||
<AboutTopInfo />
|
||||
</main>
|
||||
);
|
||||
}
|
||||
@@ -1,20 +1,20 @@
|
||||
import images from '@/assets/images/images';
|
||||
import InnerPageBanner from '@/components/layout/innerPages/banner';
|
||||
import PostsGrid from '@/components/pages/blog/PostsGrid';
|
||||
import { t } from '@/locales/translates';
|
||||
import { ILayoutLocaleParams } from '@/models/layout';
|
||||
import { getTranslations } from 'next-intl/server';
|
||||
|
||||
async function getData() {
|
||||
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||||
return { message: 'This data was fetched on the server!' };
|
||||
}
|
||||
|
||||
export default async function Blog() {
|
||||
const data = await getData();
|
||||
export default async function Blog({
|
||||
params,
|
||||
}: {
|
||||
params: ILayoutLocaleParams;
|
||||
}) {
|
||||
const t = await getTranslations({ locale: params.locale });
|
||||
|
||||
return (
|
||||
<main className="flex flex-col items-center justify-between">
|
||||
<InnerPageBanner
|
||||
title={t('pages_blog_title') as string}
|
||||
title={t('pages_blog_title')}
|
||||
imageSrc={images.blogBanner.src}
|
||||
/>
|
||||
|
||||
@@ -3,21 +3,21 @@ import InnerPageBanner from '@/components/layout/innerPages/banner';
|
||||
import ContactMap from '@/components/layout/map';
|
||||
import ContactForm from '@/components/pages/contact/ContactMeForm';
|
||||
import TouchUs from '@/components/pages/contact/TouchUs';
|
||||
import { t } from '@/locales/translates';
|
||||
import Image from 'next/image';
|
||||
import { getTranslations } from 'next-intl/server';
|
||||
import { ILayoutLocaleParams } from '@/models/layout';
|
||||
|
||||
async function getData() {
|
||||
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||||
return { message: 'This data was fetched on the server!' };
|
||||
}
|
||||
|
||||
export default async function Contact() {
|
||||
const data = await getData();
|
||||
export default async function Contact({
|
||||
params,
|
||||
}: {
|
||||
params: ILayoutLocaleParams;
|
||||
}) {
|
||||
const t = await getTranslations({ locale: params.locale });
|
||||
|
||||
return (
|
||||
<main className="flex flex-col items-center justify-between">
|
||||
<InnerPageBanner
|
||||
title={t('pages_contact_title') as string}
|
||||
title={t('pages_contact_title')}
|
||||
imageSrc={images.blogBanner.src}
|
||||
/>
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 25 KiB |
@@ -0,0 +1,43 @@
|
||||
import Footer from '@/components/layout/footer/Footer';
|
||||
import '@/app/globals.css';
|
||||
import 'leaflet/dist/leaflet.css';
|
||||
import { notFound } from 'next/navigation';
|
||||
import { NextIntlClientProvider } from 'next-intl';
|
||||
import type { ILayoutLocaleParams } from '@/models/layout.d';
|
||||
|
||||
// export const metadata: Metadata = {
|
||||
// title: 'Create Next App',
|
||||
// description: 'Generated by create next app',
|
||||
// };
|
||||
|
||||
export default async function RootLayout({
|
||||
children,
|
||||
params,
|
||||
}: Readonly<{
|
||||
children: React.ReactNode;
|
||||
params: ILayoutLocaleParams;
|
||||
}>) {
|
||||
const locale = params.locale;
|
||||
console.log(locale);
|
||||
|
||||
let messages;
|
||||
try {
|
||||
console.log(await import(`../../../messages/en.json`));
|
||||
messages = (await import(`../../../messages/en.json`)).default;
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
|
||||
notFound();
|
||||
}
|
||||
|
||||
return (
|
||||
<html lang={locale} dir={locale === 'fa' ? 'rtl' : 'ltr'}>
|
||||
<body className="min-h-svh w-full overflow-x-hidden">
|
||||
<NextIntlClientProvider locale={locale} messages={messages}>
|
||||
{children}
|
||||
<Footer />
|
||||
</NextIntlClientProvider>
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
@@ -2,20 +2,23 @@ import Header from '@/components/layout/header';
|
||||
import AboutTopInfo from '@/components/pages/about/TopInfo';
|
||||
import HomeStorySection from '@/components/pages/home/HomeStorySection';
|
||||
import HomePageProducts from '@/components/pages/home/Products';
|
||||
import { ILayoutLocaleParams } from '@/models/layout';
|
||||
import { getTranslations } from 'next-intl/server';
|
||||
|
||||
async function getData() {
|
||||
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||||
return { message: 'This data was fetched on the server!' };
|
||||
interface IPageParams {
|
||||
params: ILayoutLocaleParams;
|
||||
}
|
||||
|
||||
export default async function Home() {
|
||||
const data = await getData();
|
||||
export default async function Home({ params }: IPageParams) {
|
||||
const { locale } = await params;
|
||||
|
||||
const t = await getTranslations({ locale });
|
||||
|
||||
return (
|
||||
<main className="flex flex-col items-center justify-between">
|
||||
<Header />
|
||||
<AboutTopInfo />
|
||||
<HomePageProducts />
|
||||
<HomePageProducts locale={locale} />
|
||||
<HomeStorySection className="my-24" />
|
||||
</main>
|
||||
);
|
||||
+8
-4
@@ -5,9 +5,11 @@ import { IBreadcrumbItem } from '@/components/layout/breadcrumb/breadcrumb';
|
||||
import InnerPageBanner from '@/components/layout/innerPages/banner';
|
||||
import ProductCategoryCardInProducts from '@/components/pages/productCategories/ProductCategoryCardInProducts';
|
||||
import ProductCard from '@/components/pages/products/ProductCard';
|
||||
import { ILayoutLocaleParams } from '@/models/layout';
|
||||
import { getProductCategoryById, getProducts } from '@/services/products';
|
||||
import { getTranslations } from 'next-intl/server';
|
||||
|
||||
interface IParams {
|
||||
interface IParams extends ILayoutLocaleParams {
|
||||
product_category_id: string;
|
||||
}
|
||||
|
||||
@@ -16,15 +18,17 @@ export default async function ProductPage({
|
||||
}: {
|
||||
params: Promise<IParams>;
|
||||
}) {
|
||||
const { product_category_id: productCategoryId } = await params;
|
||||
const { product_category_id: productCategoryId, locale } = await params;
|
||||
const t = await getTranslations({ locale });
|
||||
const routes = routeFactory(t, locale);
|
||||
|
||||
const productCategory = await getProductCategoryById(productCategoryId);
|
||||
const products = await getProducts(productCategoryId);
|
||||
|
||||
const breadcrumbItems = [
|
||||
{
|
||||
...routeFactory.productCategories,
|
||||
href: routeFactory.productCategories.route(),
|
||||
...routes.productCategories,
|
||||
href: routes.productCategories.route(),
|
||||
},
|
||||
{ title: productCategory.title },
|
||||
] as IBreadcrumbItem[];
|
||||
@@ -2,17 +2,24 @@ import images from '@/assets/images/images';
|
||||
import InnerPageBanner from '@/components/layout/innerPages/banner';
|
||||
import ProductsCategoryCard from '@/components/pages/productCategories/ProductCategoryCard';
|
||||
import type { IProductCategoryCardProps } from '@/components/pages/productCategories/productCategoryCard.d';
|
||||
import { t } from '@/locales/translates';
|
||||
import { ILayoutLocaleParams } from '@/models/layout';
|
||||
import { getProductCategories } from '@/services/products';
|
||||
import { getTranslations } from 'next-intl/server';
|
||||
|
||||
export default async function ProductsPage() {
|
||||
export default async function ProductsPage({
|
||||
params,
|
||||
}: {
|
||||
params: ILayoutLocaleParams;
|
||||
}) {
|
||||
const awaitedParams = await params;
|
||||
const t = await getTranslations({ locale: awaitedParams.locale });
|
||||
const productCategories: IProductCategoryCardProps[] =
|
||||
await getProductCategories();
|
||||
|
||||
return (
|
||||
<main>
|
||||
<InnerPageBanner
|
||||
title={t('pages_product_categories_title') as string}
|
||||
title={t('pages_product_categories_title')}
|
||||
imageSrc={images.aboutBanner.src}
|
||||
/>
|
||||
<div className="container-fluid mx-auto my-24">
|
||||
@@ -23,10 +30,10 @@ export default async function ProductsPage() {
|
||||
</div>
|
||||
<div className="mt-20">
|
||||
<h2 className="mb-4 text-2xl font-semibold text-gray-500">
|
||||
{t('pages_products_content_title') as string}
|
||||
{t('pages_products_content_title')}
|
||||
</h2>
|
||||
<p className="text-base font-light text-gray-400">
|
||||
{t('pages_products_content_description') as string}
|
||||
{t('pages_products_content_description')}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,20 +1,20 @@
|
||||
import images from '@/assets/images/images';
|
||||
import InnerPageBanner from '@/components/layout/innerPages/banner';
|
||||
import ProjectsGrid from '@/components/pages/project/ProjectGrid';
|
||||
import { t } from '@/locales/translates';
|
||||
import { ILayoutLocaleParams } from '@/models/layout';
|
||||
import { getTranslations } from 'next-intl/server';
|
||||
|
||||
async function getData() {
|
||||
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||||
return { message: 'This data was fetched on the server!' };
|
||||
}
|
||||
|
||||
export default async function Projects() {
|
||||
const data = await getData();
|
||||
export default async function Projects({
|
||||
params,
|
||||
}: {
|
||||
params: ILayoutLocaleParams;
|
||||
}) {
|
||||
const t = await getTranslations({ locale: params.locale });
|
||||
|
||||
return (
|
||||
<main className="flex flex-col items-center justify-between">
|
||||
<InnerPageBanner
|
||||
title={t('pages_projects_title') as string}
|
||||
title={t('pages_projects_title')}
|
||||
imageSrc={images.blogBanner.src}
|
||||
/>
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
import images from '@/assets/images/images';
|
||||
import Header from '@/components/layout/header';
|
||||
import InnerPageBanner from '@/components/layout/innerPages/banner';
|
||||
import SectionTitle from '@/components/layout/sectionTitle';
|
||||
import AboutTopInfo from '@/components/pages/about/TopInfo';
|
||||
import { t } from '@/locales/translates';
|
||||
|
||||
async function getData() {
|
||||
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||||
return { message: 'This data was fetched on the server!' };
|
||||
}
|
||||
|
||||
export default async function AboutUs() {
|
||||
const data = await getData();
|
||||
|
||||
return (
|
||||
<main className="flex flex-col items-center justify-between">
|
||||
<InnerPageBanner
|
||||
title={t('pages_about_title') as string}
|
||||
imageSrc={images.aboutBanner.src}
|
||||
/>
|
||||
<AboutTopInfo />
|
||||
</main>
|
||||
);
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
import Footer from '@/components/layout/footer/Footer';
|
||||
import './globals.css';
|
||||
import { cookies } from 'next/headers';
|
||||
import 'leaflet/dist/leaflet.css';
|
||||
|
||||
// export const metadata: Metadata = {
|
||||
// title: 'Create Next App',
|
||||
// description: 'Generated by create next app',
|
||||
// };
|
||||
|
||||
export default async function RootLayout({
|
||||
children,
|
||||
}: Readonly<{
|
||||
children: React.ReactNode;
|
||||
}>) {
|
||||
const cookieStore = await cookies();
|
||||
const locale = cookieStore.get('lang')?.value || 'en';
|
||||
|
||||
return (
|
||||
<html lang={locale} dir={locale === 'fa' ? 'rtl' : 'ltr'}>
|
||||
<body className="min-h-svh w-full overflow-x-hidden">
|
||||
{children}
|
||||
<Footer />
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user