diff --git a/app/[locale]/blog/[slug]/page.tsx b/app/[locale]/blog/[slug]/page.tsx index 8acc79f..bed89ad 100644 --- a/app/[locale]/blog/[slug]/page.tsx +++ b/app/[locale]/blog/[slug]/page.tsx @@ -7,14 +7,14 @@ import { getBlogDetailBySlug } from "@/data/blog-detail"; const SITE_URL = process.env.NEXT_PUBLIC_SITE_URL || "https://poyrazavsever.com"; type BlogDetailPageProps = { - params: Promise<{ slug: string }>; + params: Promise<{ locale: string; slug: string }>; }; export async function generateMetadata({ params }: BlogDetailPageProps): Promise { - const { slug } = await params; + const { locale, slug } = await params; const post = await getBlogDetailBySlug(slug); - if (!post) { + if (!post || post.lang !== locale) { return { title: "Yazı Bulunamadı", }; @@ -51,10 +51,10 @@ export async function generateMetadata({ params }: BlogDetailPageProps): Promise } export default async function BlogDetailPage({ params }: BlogDetailPageProps) { - const { slug } = await params; + const { locale, slug } = await params; const post = await getBlogDetailBySlug(slug); - if (!post) { + if (!post || post.lang !== locale) { notFound(); } diff --git a/app/[locale]/blog/page.tsx b/app/[locale]/blog/page.tsx index 6728d80..ded6ba5 100644 --- a/app/[locale]/blog/page.tsx +++ b/app/[locale]/blog/page.tsx @@ -2,10 +2,12 @@ import { BlogContent } from "@/components/blog-content"; import { getBlogPageData } from "@/data/blog"; type BlogPageProps = { + params: Promise<{ locale: string }>; searchParams?: Promise<{ page?: string | string[]; category?: string | string[]; search?: string | string[] }>; }; -export default async function BlogPage({ searchParams }: BlogPageProps) { +export default async function BlogPage({ params, searchParams }: BlogPageProps) { + const { locale } = await params; const resolved = searchParams ? await searchParams : undefined; const pageParam = Array.isArray(resolved?.page) ? resolved?.page[0] : resolved?.page; const categoryParam = Array.isArray(resolved?.category) @@ -14,7 +16,7 @@ export default async function BlogPage({ searchParams }: BlogPageProps) { const searchParam = Array.isArray(resolved?.search) ? resolved?.search[0] : resolved?.search; const page = Number(pageParam ?? "1"); const currentPage = Number.isFinite(page) && page > 0 ? Math.floor(page) : 1; - const data = await getBlogPageData(currentPage, 12, categoryParam, searchParam); + const data = await getBlogPageData(locale, currentPage, 12, categoryParam, searchParam); return ; } diff --git a/app/[locale]/page.tsx b/app/[locale]/page.tsx index 30bab0a..254c06f 100644 --- a/app/[locale]/page.tsx +++ b/app/[locale]/page.tsx @@ -4,8 +4,13 @@ import { ReferencesSection } from "@/components/references-section"; import { SponsorsSection } from "@/components/sponsors-section"; import { getHomeBlogNews } from "@/data/blog"; -export default async function Home() { - const homeNews = await getHomeBlogNews(3); +export default async function Home({ + params, +}: { + params: Promise<{ locale: string }>; +}) { + const { locale } = await params; + const homeNews = await getHomeBlogNews(locale, 3); return (
diff --git a/components/blog-content.tsx b/components/blog-content.tsx index cf5de22..c8661e4 100644 --- a/components/blog-content.tsx +++ b/components/blog-content.tsx @@ -1,9 +1,9 @@ "use client"; import { useState, useCallback } from "react"; -import Link from "next/link"; -import { useRouter } from "next/navigation"; +import { Link, useRouter } from "@/i18n/routing"; import { Icon } from "@iconify/react"; +import { useTranslations } from "next-intl"; import { Badge, Card, Typography } from "poyraz-ui/atoms"; import { ArticleCard, @@ -34,6 +34,7 @@ function buildHref(params: { page?: number; category?: string; search?: string } export function BlogContent({ data }: BlogContentProps) { const router = useRouter(); + const t = useTranslations("Blog"); const [searchInput, setSearchInput] = useState(data.searchQuery); const pageNumbers = Array.from({ length: data.totalPages }, (_, i) => i + 1); const hasArticles = data.articles.length > 0; @@ -59,7 +60,7 @@ export function BlogContent({ data }: BlogContentProps) { {/* Kategoriler */}
- Kategori: + {t("categories")}: {data.categories.map((category) => ( { if (e.key === "Enter") submitSearch(searchInput); }} - placeholder="Başlık veya içerikte ara..." + placeholder={t("searchPlaceholder")} className="w-full rounded-sm border border-border bg-background py-2 pr-10 pl-9 text-sm text-foreground placeholder:text-muted-foreground focus:border-red-600 focus:ring-1 focus:ring-red-600/30 focus:outline-none" /> {searchInput && ( @@ -115,7 +116,7 @@ export function BlogContent({ data }: BlogContentProps) { {(data.searchQuery || data.selectedCategory !== "All") && (
- {data.articles.length} sonuç + {data.articles.length} {t("results")} {data.searchQuery ? ` · "${data.searchQuery}"` : ""} {data.selectedCategory !== "All" ? ` · ${data.selectedCategory}` : ""} @@ -125,7 +126,7 @@ export function BlogContent({ data }: BlogContentProps) { className="inline-flex cursor-pointer items-center gap-1 rounded-sm border border-border px-2 py-0.5 text-xs text-muted-foreground transition-colors hover:text-foreground" > - Temizle + {t("clear")}
)} @@ -160,10 +161,10 @@ export function BlogContent({ data }: BlogContentProps) { /> {data.searchQuery - ? `"${data.searchQuery}" aramasına uygun sonuç bulunamadı.` + ? t("noSearch", { search: data.searchQuery }) : data.selectedCategory === "All" - ? "Henüz blog yazısı bulunmuyor." - : `"${data.selectedCategory}" kategorisinde henüz blog yazısı bulunmuyor.`} + ? t("empty") + : t("emptyCategory", { category: data.selectedCategory })} {(data.searchQuery || data.selectedCategory !== "All") && ( )} diff --git a/components/blog-detail-content.tsx b/components/blog-detail-content.tsx index 0ee0c63..e0d73a8 100644 --- a/components/blog-detail-content.tsx +++ b/components/blog-detail-content.tsx @@ -1,7 +1,8 @@ "use client"; import Image from "next/image"; -import Link from "next/link"; +import { Link } from "@/i18n/routing"; +import { useTranslations } from "next-intl"; import ReactMarkdown from "react-markdown"; import remarkGfm from "remark-gfm"; import { Prism as SyntaxHighlighter } from "react-syntax-highlighter"; @@ -94,6 +95,7 @@ function extractText(children: React.ReactNode): string { } function MermaidBlock({ chart }: { chart: string }) { + const t = useTranslations("Blog"); const [svg, setSvg] = useState(""); const [error, setError] = useState(""); const idRef = useRef(`mermaid-${Math.random().toString(36).slice(2)}`); @@ -117,7 +119,7 @@ function MermaidBlock({ chart }: { chart: string }) { } } catch { if (mounted) { - setError("Mermaid diyagramı oluşturulamadı."); + setError(t("diagramError")); } } }; @@ -126,7 +128,7 @@ function MermaidBlock({ chart }: { chart: string }) { return () => { mounted = false; }; - }, [chart]); + }, [chart, t]); if (error) { return ( @@ -142,7 +144,7 @@ function MermaidBlock({ chart }: { chart: string }) { return ( - Diyagram hazırlanıyor... + {t("diagramLoading")} ); @@ -162,6 +164,7 @@ const GISCUS_CATEGORY = const GISCUS_CATEGORY_ID = process.env.NEXT_PUBLIC_GISCUS_CATEGORY_ID || ""; export function BlogDetailContent({ post }: BlogDetailContentProps) { + const t = useTranslations("Blog"); const progressBarRef = useRef(null); const [tocOpen, setTocOpen] = useState(false); @@ -199,7 +202,7 @@ export function BlogDetailContent({ post }: BlogDetailContentProps) { href="/blog" className="inline-flex items-center rounded-sm border border-border px-3 py-1.5 text-sm text-muted-foreground transition-colors hover:text-foreground" > - {"<- Blog'a dön"} + {t("backToBlog")}
@@ -270,7 +273,7 @@ export function BlogDetailContent({ post }: BlogDetailContentProps) { }, p: ({ node, children, ...props }) => { const hasImg = node?.children?.some( - (c: any) => c.tagName === "img", + (c: unknown) => (c as { tagName?: string }).tagName === "img", ); if (hasImg) { return ( @@ -405,7 +408,7 @@ export function BlogDetailContent({ post }: BlogDetailContentProps) { {showGiscus && (
- Yorumlar + {t("comments")} setTocOpen(true)} className="fixed right-4 bottom-6 z-40 flex h-11 w-11 cursor-pointer items-center justify-center rounded-full border border-border bg-background shadow-lg transition-transform hover:scale-105 active:scale-95 lg:hidden" - aria-label="İçindekiler" + aria-label={t("toc")} > e.stopPropagation()} >
- İçindekiler + {t("toc")}