From 912c70332e37fa3000248094232090df8d7d2139 Mon Sep 17 00:00:00 2001 From: gbanyan Date: Wed, 19 Nov 2025 23:20:04 +0800 Subject: [PATCH] Fix tag URL encoding for non-ASCII characters MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixed tag matching issue where tags with spaces and non-ASCII characters (like "Medicine - 醫學") were not working correctly on Vercel. Changes: 1. Updated getTagSlug() to normalize tags without encoding - Next.js handles URL encoding automatically 2. Added decodeURIComponent() in tag page to decode incoming URL parameters 3. This ensures proper matching between generated slugs and URL parameters The fix resolves: - Tag archive pages showing wrong characters - Articles not being collected under correct tags - URL display issues with encoded characters 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- app/tags/[tag]/page.tsx | 10 +++++++--- lib/posts.ts | 10 +++++----- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/app/tags/[tag]/page.tsx b/app/tags/[tag]/page.tsx index 953deea..1b7c4e5 100644 --- a/app/tags/[tag]/page.tsx +++ b/app/tags/[tag]/page.tsx @@ -27,10 +27,12 @@ interface Props { export async function generateMetadata({ params }: Props): Promise { const { tag: slug } = await params; + // Decode the slug since Next.js encodes non-ASCII characters in URLs + const decodedSlug = decodeURIComponent(slug); // Find original tag label by slug const tag = allPosts .flatMap((post) => post.tags ?? []) - .find((t) => getTagSlug(t) === slug); + .find((t) => getTagSlug(t) === decodedSlug); return { title: tag ? `標籤:${tag}` : '標籤' @@ -39,13 +41,15 @@ export async function generateMetadata({ params }: Props): Promise { export default async function TagPage({ params }: Props) { const { tag: slug } = await params; + // Decode the slug since Next.js encodes non-ASCII characters in URLs + const decodedSlug = decodeURIComponent(slug); const posts = allPosts.filter( - (post) => post.tags && post.tags.some((t) => getTagSlug(t) === slug) + (post) => post.tags && post.tags.some((t) => getTagSlug(t) === decodedSlug) ); const tagLabel = - posts[0]?.tags?.find((t) => getTagSlug(t) === slug) ?? slug; + posts[0]?.tags?.find((t) => getTagSlug(t) === decodedSlug) ?? decodedSlug; return ( diff --git a/lib/posts.ts b/lib/posts.ts index 9828894..58a0b02 100644 --- a/lib/posts.ts +++ b/lib/posts.ts @@ -27,14 +27,14 @@ export function getPageBySlug(slug: string): Page | undefined { } export function getTagSlug(tag: string): string { - // Normalize spaces and convert to lowercase first + // Normalize spaces and convert to lowercase // Replace multiple spaces/dashes with single dash - const normalized = tag + // Next.js will handle URL encoding automatically, so we don't encode here + return tag .toLowerCase() .replace(/\s+/g, '-') - .replace(/-+/g, '-'); - // Encode URI components to handle non-ASCII characters properly - return encodeURIComponent(normalized); + .replace(/-+/g, '-') + .trim(); } export function getAllTagsWithCount(): { tag: string; slug: string; count: number }[] {