fix(blog url bug): fix blog url bug

Fixed the bug of redundant language suffix in blog URLs, added lang to the blog homepage link to prevent language switching issues.
This commit is contained in:
david_bai
2025-08-02 23:27:02 +08:00
parent 3dfee10cee
commit 245c4efcd0
6 changed files with 51 additions and 46 deletions
+1 -1
View File
@@ -8,7 +8,7 @@ export async function generateMetadata({
}: {
params: { slug: string; lang: string };
}): Promise<Metadata> {
const post = await getPostBySlug(params.slug);
const post = await getPostBySlug(params.slug, params.lang);
if (!post) {
//blog not found
+2 -2
View File
@@ -12,9 +12,9 @@ export { generateMetadata };
export default async function BlogPost({
params,
}: {
params: { slug: string };
params: { slug: string; lang: string };
}) {
const post = await getPostBySlug(params.slug);
const post = await getPostBySlug(params.slug, params.lang);
if (!post) {
return <div>Post not found</div>;
+2 -2
View File
@@ -26,7 +26,7 @@ export default async function BlogPage({
{/* Articles List */}
<div className="space-y-12">
{posts.map((post) => (
<ArticleListItem key={post.slug} post={post} />
<ArticleListItem key={post.slug} post={post} lang={lang} />
))}
</div>
</main>
@@ -41,7 +41,7 @@ export default async function BlogPage({
{posts.slice(0, 5).map((post) => (
<Link
key={post.slug}
href={`/en/blog/${post.slug}`}
href={`/${lang}/blog/${post.slug}`}
className="block hover:text-blue-600 text-base font-medium"
>
{post.frontmatter.title}
+1 -1
View File
@@ -59,7 +59,7 @@ export default async function TagPage({
<div className="space-y-12">
{posts.length > 0 ? (
posts.map((post) => (
<ArticleListItem key={post.slug} post={post} />
<ArticleListItem key={post.slug} post={post} lang={lang} />
))
) : (
<p>No articles found for this decodedTag.</p>
+4 -3
View File
@@ -4,9 +4,10 @@ import { type BlogPost } from "@/lib/blog";
interface ArticleListItemProps {
post: BlogPost;
lang: string;
}
export function ArticleListItem({ post }: ArticleListItemProps) {
export function ArticleListItem({ post, lang }: ArticleListItemProps) {
return (
<article className="bg-white rounded-xl shadow-lg hover:shadow-xl transition-shadow overflow-hidden">
<div className="relative h-80 w-full">
@@ -37,7 +38,7 @@ export function ArticleListItem({ post }: ArticleListItemProps) {
))}
</div>
</div>
<Link href={`/blog/${post.slug}`}>
<Link href={`/${lang}/blog/${post.slug}`}>
<h2 className="text-3xl font-bold mb-4 hover:text-blue-600 transition-colors leading-tight">
{post.frontmatter.title}
</h2>
@@ -49,7 +50,7 @@ export function ArticleListItem({ post }: ArticleListItemProps) {
<div className="flex items-center justify-between pt-4 border-t border-gray-100">
<Link
href={`/blog/${post.slug}`}
href={`/${lang}/blog/${post.slug}`}
className="text-blue-600 hover:text-blue-800 font-medium inline-flex items-center text-lg"
>
Read more
+41 -37
View File
@@ -22,45 +22,45 @@ export interface BlogPost {
export async function getAllPosts(lang: string): Promise<BlogPost[]> {
const files = fs.readdirSync(POSTS_PATH);
const posts = await Promise.all(
files
.filter((file) => /\.mdx?$/.test(file))
.map(async (file) => {
const filePath = path.join(POSTS_PATH, file);
const source = fs.readFileSync(filePath, "utf8");
const { data, content } = matter(source);
const postsWithLang = files
.filter((file) => /\.mdx?$/.test(file))
.map((file) => {
const langFromFile = file.match(/-([a-z]{2})\.mdx?$/)?.[1];
return { file, langFromFile };
});
// Validate and transform frontmatter data
const frontmatter = {
title: data.title ?? "",
description: data.description ?? "",
date: data.date ?? new Date().toISOString(),
author: data.author ?? "",
cover: data.cover ?? "",
tags: Array.isArray(data.tags) ? data.tags : [], // Use the tags array directly
status: data.status ?? "draft",
};
return {
slug: file.replace(/\.mdx?$/, ""),
frontmatter,
content,
} as BlogPost;
})
const lang_dst = lang === "zh" ? "zh" : "en";
const filteredFiles = postsWithLang.filter(
({ langFromFile }) => langFromFile === lang_dst
);
// Filter out draft status blogs
return posts
.filter((post) => post.frontmatter.status === "published") // Only keep published status
.filter((post) => {
// Split slug into an array by '-'
const parts = post.slug.split("-");
// Get the last part
const lastPart = parts[parts.length - 1];
// Check if the last part equals the target language && if the target language is Chinese, return Chinese blogs, otherwise return English blogs
const lang_dst = lang === "zh" ? "zh" : "en";
return lastPart === lang_dst;
const posts = await Promise.all(
filteredFiles.map(async ({ file }) => {
const filePath = path.join(POSTS_PATH, file);
const source = fs.readFileSync(filePath, "utf8");
const { data, content } = matter(source);
// Validate and transform frontmatter data
const frontmatter = {
title: data.title ?? "",
description: data.description ?? "",
date: data.date ?? new Date().toISOString(),
author: data.author ?? "",
cover: data.cover ?? "",
tags: Array.isArray(data.tags) ? data.tags : [],
status: data.status ?? "draft",
};
return {
slug: file.replace(/-[a-z]{2}\.mdx?$/, "").replace(/\.mdx?$/, ""),
frontmatter,
content,
} as BlogPost;
})
);
return posts
.filter((post) => post.frontmatter.status === "published")
.sort(
(a, b) =>
new Date(b.frontmatter.date).getTime() -
@@ -68,9 +68,13 @@ export async function getAllPosts(lang: string): Promise<BlogPost[]> {
);
}
export async function getPostBySlug(slug: string): Promise<BlogPost | null> {
export async function getPostBySlug(
slug: string,
lang: string
): Promise<BlogPost | null> {
try {
const filePath = path.join(POSTS_PATH, `${slug}.mdx`);
const lang_dst = lang === "zh" ? "zh" : "en";
const filePath = path.join(POSTS_PATH, `${slug}-${lang_dst}.mdx`);
const source = fs.readFileSync(filePath, "utf8");
const { data, content } = matter(source);