Files
PrivyDrop/frontend/app/sitemap.ts
T
david_bai 89a38936b6 feat(blog-i18n): localize blog UI & SEO; add tag pages to sitemap
- Add Messages.meta.blog and text.blog (BlogTexts) to types/messages
  - Update all locales with blog UI strings and meta.blog
  - Localize blog list, tag pages, and article detail (titles, labels, dates)
  - Pass messages to ArticleListItem; TableOfContents supports localized title
  - Use dictionary-based metadata; alternates cover all supported locales
  - Sitemap: include /[lang]/blog/tag/{tag} and set blog list lastModified to newest post
  - JSON-LD: hardcode site URL in getSiteUrl() for consistency
2025-11-22 10:37:29 +08:00

102 lines
2.9 KiB
TypeScript

import { MetadataRoute } from "next";
import { supportedLocales } from "@/constants/i18n-config";
import { getAllPosts } from "@/lib/blog";
import { slugifyTag } from "@/utils/tagUtils";
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
const baseUrl = "https://www.privydrop.app";
const languages = supportedLocales;
const routes = [
"",
"/features",
"/blog",
"/about",
"/help",
"/faq",
"/terms",
"/privacy",
];
const urls: MetadataRoute.Sitemap = [];
// Add root URL
urls.push({
url: baseUrl,
lastModified: new Date(),
changeFrequency: "daily",
priority: 1,
});
// Add language specific URLs, blog posts and tag pages
for (const lang of languages) {
try {
const posts = await getAllPosts(lang);
// compute latest blog post date for this language
const latestDate = posts.length
? new Date(
Math.max(
...posts.map((p) => new Date(p.frontmatter.date).getTime())
)
)
: new Date();
// Add static routes per language (optimize blog list lastModified)
routes.forEach((route) => {
const isRoot = route === "";
const isBlogList = route === "/blog";
urls.push({
url: `${baseUrl}/${lang}${route}`,
lastModified: isBlogList ? latestDate : new Date(),
changeFrequency: isRoot ? "weekly" : isBlogList ? "weekly" : "weekly",
priority: isRoot ? 1.0 : 0.8,
});
});
// Add blog posts for this language
posts.forEach((post) => {
urls.push({
url: `${baseUrl}/${lang}/blog/${post.slug}`,
lastModified: new Date(post.frontmatter.date),
changeFrequency: "monthly",
priority: 0.7,
});
});
// Add tag pages for this language
const uniqueTags = Array.from(
new Set(posts.flatMap((p) => p.frontmatter.tags))
);
uniqueTags.forEach((tag) => {
const tagSlug = slugifyTag(tag);
const tagLatestDate = posts
.filter((p) => p.frontmatter.tags.includes(tag))
.map((p) => new Date(p.frontmatter.date).getTime());
const lastModified =
tagLatestDate.length > 0
? new Date(Math.max(...tagLatestDate))
: latestDate;
urls.push({
url: `${baseUrl}/${lang}/blog/tag/${tagSlug}`,
lastModified,
changeFrequency: "monthly",
priority: 0.6,
});
});
} catch (error) {
console.warn(`Failed to load blog data for language ${lang}:`, error);
// Fallback: keep at least the static routes
routes.forEach((route) => {
urls.push({
url: `${baseUrl}/${lang}${route}`,
lastModified: new Date(),
changeFrequency: "weekly",
priority: route === "" ? 1.0 : 0.8,
});
});
}
}
return urls;
}