feat: improve blog localization and error handling

- Add new localization keys for "all" and "noPostsFound" in English and Chinese
- Update blog components to use localized translations
- Add optional chaining for category properties to prevent rendering errors
- Improve mobile and desktop category list components with translations
This commit is contained in:
javayhu 2025-03-07 01:18:38 +08:00
parent 4657e5b691
commit 2f4b8e23fe
8 changed files with 24 additions and 13 deletions

View File

@ -63,6 +63,8 @@
"subtitle": "Latest news and updates from our team",
"publisher": "Publisher",
"categories": "Categories",
"tableOfContents": "Table of Contents"
"tableOfContents": "Table of Contents",
"all": "All",
"noPostsFound": "No posts found"
}
}

View File

@ -63,6 +63,8 @@
"subtitle": "来自我们的团队最新新闻和更新",
"publisher": "发布者",
"categories": "分类",
"tableOfContents": "目录"
"tableOfContents": "目录",
"all": "全部",
"noPostsFound": "没有找到文章"
}
}

View File

@ -38,10 +38,10 @@ export default function BlogCard({ post }: BlogCardProps) {
<div className="flex flex-wrap gap-1">
{post.categories.map((category, index) => (
<span
key={`${category.slug}-${index}`}
key={`${category?.slug}-${index}`}
className="text-xs font-medium text-white bg-black bg-opacity-50 px-2 py-1 rounded-md"
>
{category.name}
{category?.name}
</span>
))}
</div>

View File

@ -15,7 +15,7 @@ export function BlogCategoryListDesktop({
categoryList,
}: BlogCategoryListDesktopProps) {
const { slug } = useParams() as { slug?: string };
const t = useTranslations("BlogPage.categories");
const t = useTranslations("BlogPage");
return (
<div>
@ -54,6 +54,7 @@ export function BlogCategoryListDesktop({
)}
aria-label={`Toggle blog category of ${category.name}`}
>
{/* TODO: fix as any */}
<Link href={`/blog/category/${category.slug}` as any}>
<h2>{category.name}</h2>
</Link>

View File

@ -6,6 +6,7 @@ import { useParams } from "next/navigation";
import { useState } from "react";
import { Drawer } from "vaul";
import FilterItemMobile from "@/components/shared/filter-item-mobile";
import { useTranslations } from "next-intl";
export type BlogCategoryListMobileProps = {
categoryList: Category[];
@ -14,11 +15,12 @@ export type BlogCategoryListMobileProps = {
export function BlogCategoryListMobile({
categoryList,
}: BlogCategoryListMobileProps) {
const [open, setOpen] = useState(false);
const { slug } = useParams() as { slug?: string };
const selectedCategory = categoryList.find(
(category) => category.slug === slug,
);
const [open, setOpen] = useState(false);
const t = useTranslations("BlogPage");
const closeDrawer = () => {
setOpen(false);
@ -33,10 +35,10 @@ export function BlogCategoryListMobile({
<div className="flex items-center justify-between w-full gap-4">
<div className="flex items-center gap-2">
<LayoutListIcon className="size-5" />
<span className="text-sm">Category</span>
<span className="text-sm">{t("categories")}</span>
</div>
<span className="text-sm">
{selectedCategory?.name ? `${selectedCategory?.name}` : "All"}
{selectedCategory?.name ? `${selectedCategory?.name}` : t("all")}
</span>
</div>
</Drawer.Trigger>
@ -46,14 +48,14 @@ export function BlogCategoryListMobile({
/>
<Drawer.Portal>
<Drawer.Content className="fixed inset-x-0 bottom-0 z-50 mt-24 overflow-hidden rounded-t-[10px] border bg-background">
<Drawer.Title className="sr-only">Category</Drawer.Title>
<Drawer.Title className="sr-only">{t("categories")}</Drawer.Title>
<div className="sticky top-0 z-20 flex w-full items-center justify-center bg-inherit">
<div className="my-3 h-1.5 w-16 rounded-full bg-muted-foreground/20" />
</div>
<ul className="mb-14 w-full p-3 text-muted-foreground">
<FilterItemMobile
title="All"
title={t("all")}
href="/blog"
active={!slug}
clickAction={closeDrawer}

View File

@ -30,7 +30,7 @@ export function BlogPost({ post }: BlogPostProps): React.JSX.Element {
<div className="space-y-8">
<div className="flex flex-row items-center justify-between gap-4 text-base text-muted-foreground">
<span className="flex flex-row items-center gap-2">
{post.categories.map((c) => c.name).join(', ')}
{post.categories.map((c) => c?.name).join(', ')}
</span>
<span className="flex flex-row items-center gap-2">
<time dateTime={post.date}>

View File

@ -36,7 +36,7 @@ export function BlogPosts(): React.JSX.Element {
className="md:duration-2000 flex h-full flex-col space-y-4 text-clip border-dashed py-6 md:rounded-2xl md:px-6 md:shadow md:transition-shadow md:hover:shadow-xl dark:md:bg-accent/40 dark:md:hover:bg-accent"
>
<div className="flex flex-row items-center justify-between text-muted-foreground">
<span className="text-sm">{post.categories.map((c) => c.name).join(', ')}</span>
<span className="text-sm">{post.categories.map((c) => c?.name).join(', ')}</span>
<time
className="text-sm"
dateTime={post.date}

View File

@ -1,8 +1,12 @@
import { useTranslations } from "next-intl";
export default function EmptyGrid() {
const t = useTranslations("BlogPage");
return (
<div>
<div className="my-8 h-32 w-full flex items-center justify-center">
<p className="font-medium text-muted-foreground">Nothing found.</p>
<p className="font-medium text-muted-foreground">{t("noPostsFound")}</p>
</div>
</div>
);