diff --git a/src/app/[locale]/layout.tsx b/src/app/[locale]/layout.tsx index e6b0a8a..31f42ee 100644 --- a/src/app/[locale]/layout.tsx +++ b/src/app/[locale]/layout.tsx @@ -1,11 +1,36 @@ +import { Metadata } from "next"; import { NextIntlClientProvider } from "next-intl"; import { getMessages, setRequestLocale } from "next-intl/server"; import { routing } from "@/i18n/routing"; +const baseUrl = process.env.NEXT_PUBLIC_SITE_URL || "https://dev.manoonoils.com"; + export function generateStaticParams() { return routing.locales.map((locale) => ({ locale })); } +export async function generateMetadata({ + params, +}: { + params: Promise<{ locale: string }>; +}): Promise { + const { locale } = await params; + const localePrefix = locale === "sr" ? "" : `/${locale}`; + + const languages: Record = {}; + for (const loc of routing.locales) { + const prefix = loc === "sr" ? "" : `/${loc}`; + languages[loc] = `${baseUrl}${prefix}`; + } + + return { + alternates: { + canonical: `${baseUrl}${localePrefix}`, + languages, + }, + }; +} + export default async function LocaleLayout({ children, params, @@ -22,4 +47,4 @@ export default async function LocaleLayout({ {children} ); -} \ No newline at end of file +} diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 64be938..606dc94 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -2,6 +2,8 @@ import "./globals.css"; import type { Metadata, Viewport } from "next"; import ErrorBoundary from "@/components/providers/ErrorBoundary"; +const baseUrl = process.env.NEXT_PUBLIC_SITE_URL || "https://dev.manoonoils.com"; + export const metadata: Metadata = { title: { default: "ManoonOils - Premium Natural Oils for Hair & Skin", @@ -9,6 +11,15 @@ export const metadata: Metadata = { }, description: "Discover our premium collection of natural oils for hair and skin care.", robots: "index, follow", + alternates: { + canonical: baseUrl, + languages: { + sr: baseUrl, + en: `${baseUrl}/en`, + de: `${baseUrl}/de`, + fr: `${baseUrl}/fr`, + }, + }, openGraph: { title: "ManoonOils - Premium Natural Oils for Hair & Skin", description: "Discover our premium collection of natural oils for hair and skin care.", diff --git a/src/app/sitemap.ts b/src/app/sitemap.ts index a58ecd2..f58c6ec 100644 --- a/src/app/sitemap.ts +++ b/src/app/sitemap.ts @@ -1,48 +1,121 @@ import { MetadataRoute } from "next"; import { getProducts } from "@/lib/saleor"; -export default async function sitemap(): Promise { - const baseUrl = process.env.NEXT_PUBLIC_SITE_URL || "https://dev.manoonoils.com"; - +const LOCALES = ["sr", "en", "de", "fr"] as const; +const baseUrl = process.env.NEXT_PUBLIC_SITE_URL || "https://dev.manoonoils.com"; + +interface SitemapEntry { + url: string; + lastModified: Date; + changeFrequency: "always" | "hourly" | "daily" | "weekly" | "monthly" | "yearly" | "never"; + priority: number; + alternates?: { + languages?: Record; + }; +} + +export default async function sitemap(): Promise { let products: any[] = []; try { products = await getProducts("SR", 100); } catch (e) { - console.log('Failed to fetch products for sitemap during build'); + console.log("Failed to fetch products for sitemap during build"); } - - const productUrls = products.map((product) => ({ - url: `${baseUrl}/products/${product.slug}`, - lastModified: new Date(), - changeFrequency: "weekly" as const, - priority: 0.8, - })); - return [ + const staticPages: SitemapEntry[] = [ { url: baseUrl, lastModified: new Date(), changeFrequency: "daily", priority: 1, + alternates: { + languages: { + sr: `${baseUrl}`, + en: `${baseUrl}/en`, + de: `${baseUrl}/de`, + fr: `${baseUrl}/fr`, + }, + }, }, { url: `${baseUrl}/products`, lastModified: new Date(), changeFrequency: "daily", priority: 0.9, + alternates: { + languages: { + sr: `${baseUrl}/products`, + en: `${baseUrl}/en/products`, + de: `${baseUrl}/de/products`, + fr: `${baseUrl}/fr/products`, + }, + }, }, { url: `${baseUrl}/about`, lastModified: new Date(), changeFrequency: "monthly", priority: 0.6, + alternates: { + languages: { + sr: `${baseUrl}/about`, + en: `${baseUrl}/en/about`, + de: `${baseUrl}/de/about`, + fr: `${baseUrl}/fr/about`, + }, + }, }, { url: `${baseUrl}/contact`, lastModified: new Date(), changeFrequency: "monthly", priority: 0.6, + alternates: { + languages: { + sr: `${baseUrl}/contact`, + en: `${baseUrl}/en/contact`, + de: `${baseUrl}/de/contact`, + fr: `${baseUrl}/fr/contact`, + }, + }, + }, + { + url: `${baseUrl}/checkout`, + lastModified: new Date(), + changeFrequency: "monthly", + priority: 0.5, + alternates: { + languages: { + sr: `${baseUrl}/checkout`, + en: `${baseUrl}/en/checkout`, + de: `${baseUrl}/de/checkout`, + fr: `${baseUrl}/fr/checkout`, + }, + }, }, - ...productUrls, ]; + + const productUrls: SitemapEntry[] = []; + + for (const product of products) { + for (const locale of LOCALES) { + const localePrefix = locale === "sr" ? "" : `/${locale}`; + productUrls.push({ + url: `${baseUrl}${localePrefix}/products/${product.slug}`, + lastModified: new Date(), + changeFrequency: "weekly", + priority: 0.8, + alternates: { + languages: { + sr: `${baseUrl}/products/${product.slug}`, + en: `${baseUrl}/en/products/${product.slug}`, + de: `${baseUrl}/de/products/${product.slug}`, + fr: `${baseUrl}/fr/products/${product.slug}`, + }, + }, + }); + } + } + + return [...staticPages, ...productUrls]; }