Files
homaroma/apps/website/src/app/sitemap.ts
T
2026-07-01 19:32:20 -04:00

93 lines
2.7 KiB
TypeScript

import { MetadataRoute } from 'next';
import { getCategories, getProducts, getArticlesResult } from '../lib/cms';
import { generateProductSlug } from '../lib/slugify';
import { resolveLocalized } from '../lib/localization';
const baseUrl = process.env.NEXT_PUBLIC_SITE_URL || 'http://localhost:3000';
const languages = ['th', 'en', 'ja', 'zh', 'vi', 'ko'];
function createAlternates(path: string) {
const alternates: Record<string, string> = {};
for (const lang of languages) {
alternates[lang] = `${baseUrl}/${lang}${path}`;
}
return alternates;
}
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
const [categories, products, articlesResult] = await Promise.all([
getCategories(),
getProducts('limit=1000'),
getArticlesResult(),
]);
const staticPages = [
'',
'/shop',
'/scent-guide',
'/about',
'/contact',
'/faq',
];
const routes: MetadataRoute.Sitemap = staticPages.map((route) => ({
url: `${baseUrl}/th${route}`,
lastModified: new Date(),
changeFrequency: 'daily',
priority: route === '' ? 1 : 0.8,
alternates: {
languages: createAlternates(route),
},
}));
const categoryRoutes: MetadataRoute.Sitemap = categories.map((category) => ({
url: `${baseUrl}/th/category/${category.id}`,
lastModified: new Date(),
changeFrequency: 'weekly',
priority: 0.7,
alternates: {
languages: createAlternates(`/category/${category.id}`),
},
}));
const productRoutes: MetadataRoute.Sitemap = products.map((product) => {
const alternates: Record<string, string> = {};
let thSlug = '';
for (const lang of languages) {
const localizedName = resolveLocalized(product.name, lang) || (product.brand ? product.brand.name : 'product');
const slug = generateProductSlug(localizedName, product.id);
alternates[lang] = `${baseUrl}/${lang}/products/${slug}`;
if (lang === 'th') thSlug = slug;
}
return {
url: `${baseUrl}/th/products/${thSlug}`,
lastModified: new Date(),
changeFrequency: 'daily',
priority: 0.9,
alternates: {
languages: alternates,
},
};
});
const articleRoutes: MetadataRoute.Sitemap = [];
if (articlesResult.ok && articlesResult.data) {
articlesResult.data.forEach((article) => {
articleRoutes.push({
url: `${baseUrl}/th/article/${article.slug}`,
lastModified: new Date(article.updatedAt || article.createdAt),
changeFrequency: 'monthly',
priority: 0.6,
alternates: {
languages: createAlternates(`/article/${article.slug}`),
},
});
});
}
return [...routes, ...categoryRoutes, ...productRoutes, ...articleRoutes];
}