diff --git a/messages/en.json b/messages/en.json index 9f9ecaf..bb17bd3 100644 --- a/messages/en.json +++ b/messages/en.json @@ -72,7 +72,7 @@ "hero-subtitle": "Make smarter bets with our advanced AI prediction engine. Analyze matches, discover value bets, and build winning coupons.", "get-started": "Get Started", "learn-more": "Learn More", - "features-title": "Why Choose Suggest Bet?", + "features-title": "Why Choose Iddaai?", "feature-ai": "AI Predictions", "feature-ai-desc": "Powered by V20 ensemble model with 95%+ data quality scoring.", "feature-value": "Value Bets", diff --git a/messages/tr.json b/messages/tr.json index e395099..5beb69b 100644 --- a/messages/tr.json +++ b/messages/tr.json @@ -5,8 +5,8 @@ "intelligent-transportation-systems": "Akıllı Ulaşım Sistemleri", "artificial-intelligence": "Yapay Zeka", "error": { - "not-found": "Aradığınız sayfa bulunamadı.", "404": "404", + "not-found": "Aradığınız sayfa bulunamadı.", "back-to-home": "Ana sayfaya dön", "generic": "Beklenmeyen bir hata oluştu.", "network": "Ağ hatası. Lütfen bağlantınızı kontrol edin.", @@ -45,7 +45,6 @@ "low": "Düşük", "medium": "Orta", "high": "Yüksek", - "nav": { "home": "Anasayfa", "dashboard": "Kontrol Paneli", @@ -66,13 +65,12 @@ "coupons": "Kuponlar", "tools": "Araçlar" }, - "landing": { "hero-title": "Yapay Zeka Destekli Bahis Tahminleri", "hero-subtitle": "Gelişmiş yapay zeka tahmin motorumuz ile daha akıllı bahisler yapın. Maçları analiz edin, değerli bahisleri keşfedin ve kazanan kuponlar oluşturun.", "get-started": "Başla", "learn-more": "Daha Fazla", - "features-title": "Neden Suggest Bet?", + "features-title": "Neden Iddaai?", "feature-ai": "Yapay Zeka Tahminleri", "feature-ai-desc": "%95+ veri kalitesi puanlama ile V20 ensemble modeli tarafından desteklenmektedir.", "feature-value": "Değerli Bahisler", @@ -86,7 +84,6 @@ "stats-users": "Aktif Kullanıcı", "stats-matches": "Analiz Edilen Maç" }, - "dashboard": { "title": "Kontrol Paneli", "welcome": "Tekrar hoş geldiniz", @@ -99,7 +96,6 @@ "no-matches": "Bugün maç bulunmuyor.", "no-predictions": "Tahmin bulunmuyor." }, - "matches": { "title": "Maçlar", "filter-sport": "Spor", @@ -123,7 +119,6 @@ "away-team": "Deplasman", "vs": "vs" }, - "predictions": { "title": "Tahminler", "upcoming": "Yaklaşan", @@ -251,7 +246,6 @@ "recommended-stake-inline": "Önerilen miktar" } }, - "coupons": { "title": "Kupon Oluşturucu", "builder-title": "Kupon Oluşturucu", @@ -388,15 +382,14 @@ "win-rate": "Kazanma Oranı", "total-profit": "Toplam Kâr" }, - "leagues": { "title": "Ligler & Takımlar", "countries": "Ülkeler", "leagues": "Ligler", "countries-leagues": "Ülkeler & Ligler", - "search-at-least-2": "Takım aramak için en az 2 karakter yazın." + "search-at-least-2": "Takım aramak için en az 2 karakter yazın.", + "all": "Tümü" }, - "h2h": { "title": "Karşılıklı Karşılaşma", "team-1": "Takım 1", @@ -406,7 +399,6 @@ "draws": "Beraberlikler", "no-matches-found": "Bu takımlar arasında karşılıklı maç bulunamadı." }, - "analysis": { "title": "Çoklu Maç Analizi", "select-matches": "Maç Seç", @@ -418,7 +410,6 @@ "matches-analyzed": "maç analiz edildi", "no-history": "Henüz analiz geçmişi yok." }, - "spor-toto": { "title": "Spor Toto", "sync-bulletins": "Bültenleri Senkronize Et", @@ -446,7 +437,6 @@ "rollover-stats": "Devir İstatistikleri", "prediction-generated": "Tahmin başarıyla oluşturuldu!" }, - "admin": { "title": "Yönetim Paneli", "subtitle": "Kullanıcıları yönetin, tahminleri takip edin ve sistemi izleyin.", @@ -476,7 +466,6 @@ "user-status": "Durum", "no-users": "Kullanıcı bulunamadı." }, - "common": { "loading": "Yükleniyor...", "save": "Kaydet", @@ -505,5 +494,76 @@ "items-per-page": "Sayfa başına öğe", "showing": "Gösterilen", "results": "sonuç" + }, + "seo": { + "global": { + "title": "iddaai.com | Yapay Zeka İddaa Tahminleri", + "description": "iddaai.com yapay zeka destekli iddaa tahminleri, detaylı maç analizleri ve veriye dayalı kupon oluşturma hizmeti sunar.", + "keywords": "iddaa, iddaa tahminleri, yapay zeka iddaa, maç analizi, banko kuponlar, futbol istatistikleri" + }, + "home": { + "title": "Ana Sayfa", + "description": "Yapay zeka destekli iddaa tahminleri. Maçları analiz edin, değerli bahisleri keşfedin ve kazandıran kuponlar oluşturun." + }, + "h2h": { + "title": "Takım Karşılaştırma (H2H)", + "description": "Futbol takımlarını birebir karşılaştırın. Derinlemesine istatistikler, geçmiş maçlar ve tahminler." + }, + "analysis": { + "title": "Çoklu Maç Analizi", + "description": "Aynı anda birden fazla maçı analiz edin. Detaylı istatistikler ve yapay zeka ile stratejiler geliştirin." + }, + "leagues": { + "title": "Ligler ve Takımlar", + "description": "Dünya çapındaki futbol ve basketbol liglerini, ülkeleri ve takım istatistiklerini inceleyin." + }, + "admin": { + "title": "Yönetici Paneli", + "description": "Kullanıcıları ve sistem ayarlarını yönetmek için yönetici paneli." + }, + "matches": { + "title": "Maçlar ve Fikstür", + "description": "Yaklaşan maçları, canlı skorları ve yapay zeka tahminleriyle geçmiş fikstürleri görüntüleyin." + }, + "about": { + "title": "Hakkımızda", + "description": "iddaai.com, yapay zeka teknolojimiz ve bahis öngörülerini nasıl sağladığımız hakkında daha fazla bilgi edinin." + }, + "dashboard": { + "title": "Kullanıcı Paneli", + "description": "Bahis istatistikleri, tahminler ve hesaba genel bakış için kişiselleştirilmiş paneliniz." + }, + "profile": { + "title": "Profilim", + "description": "Kullanıcı profilinizi, aboneliğinizi ve hesap ayarlarınızı yönetin." + }, + "spor-toto": { + "title": "Spor Toto Tahminleri", + "description": "Yapay zeka destekli Spor Toto tahminleri. Muhafazakar, dengeli veya agresif stratejilerle kuponlar oluşturun." + }, + "coupon-builder": { + "title": "Yapay Zeka Kupon Oluşturucu", + "description": "Gelişmiş yapay zeka ve istatistiksel modelleri kullanarak otomatik olarak optimize edilmiş bahis kuponları oluşturun." + }, + "teams": { + "title": "Takım İstatistikleri", + "description": "Futbol takımları için detaylı istatistikler, form durumları ve tahmine dayalı modeller." + }, + "coupon-history": { + "title": "Kupon Geçmişi", + "description": "Geçmişte oluşturduğunuz bahis kuponlarınızı ve performansınızı inceleyin." + }, + "predictions": { + "title": "İddaa Tahminleri", + "description": "Günlük yapay zeka iddaa tahminleri, değerli oranlar ve yüksek güvenilirlikli maç tüyoları." + }, + "signup": { + "title": "Kayıt Ol", + "description": "Yapay zeka tahminlerine erişmek için iddaai.com hesabınızı oluşturun." + }, + "signin": { + "title": "Giriş Yap", + "description": "Yapay zeka tahminlerine ve araçlarına erişmek için iddaai.com hesabınıza giriş yapın." + } } } diff --git a/public/apple-icon.png b/public/apple-icon.png new file mode 100644 index 0000000..b26a6b4 Binary files /dev/null and b/public/apple-icon.png differ diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 0000000..eb3d2bf Binary files /dev/null and b/public/favicon.ico differ diff --git a/public/favicon/favicon.ico b/public/favicon/favicon.ico deleted file mode 100644 index df65926..0000000 Binary files a/public/favicon/favicon.ico and /dev/null differ diff --git a/public/logo.png b/public/logo.png new file mode 100644 index 0000000..36abb01 Binary files /dev/null and b/public/logo.png differ diff --git a/src/app/[locale]/(auth)/signin/page.tsx b/src/app/[locale]/(auth)/signin/page.tsx index 38d35dd..ccf3b27 100644 --- a/src/app/[locale]/(auth)/signin/page.tsx +++ b/src/app/[locale]/(auth)/signin/page.tsx @@ -27,6 +27,32 @@ import { signIn } from "next-auth/react"; import { toaster } from "@/components/ui/feedback/toaster"; import { useState } from "react"; +import { Metadata } from "next"; + +export async function generateMetadata(props: { params: Promise<{ locale: string }> }): Promise { + const params = await props.params; + const { locale } = params; + const t = await getTranslations({ locale, namespace: "seo" }); + const siteUrl = process.env.NEXT_PUBLIC_APP_URL || "https://iddaai.com"; + + // Next.js parses route variables automatically, but for canonical we'll just use a clean relative base if available, + // or let next.js construct it implicitly from metadataBase if not explicitly specified. + // We'll set alternates just for languages based on current path segment as a best effort + const pathSegment = "signin"; + + return { + title: t("signin.title"), + description: t("signin.description"), + alternates: { + canonical: `${siteUrl}/${locale}/${pathSegment}`, + languages: { + en: `${siteUrl}/en/${pathSegment}`, + tr: `${siteUrl}/tr/${pathSegment}`, + }, + }, + }; +} + const schema = yup.object({ email: yup.string().email().required(), password: yup.string().required(), diff --git a/src/app/[locale]/(auth)/signup/page.tsx b/src/app/[locale]/(auth)/signup/page.tsx index efeeab6..354b912 100644 --- a/src/app/[locale]/(auth)/signup/page.tsx +++ b/src/app/[locale]/(auth)/signup/page.tsx @@ -27,6 +27,32 @@ import { useState } from "react"; import { signIn } from "next-auth/react"; import { toaster } from "@/components/ui/feedback/toaster"; +import { Metadata } from "next"; + +export async function generateMetadata(props: { params: Promise<{ locale: string }> }): Promise { + const params = await props.params; + const { locale } = params; + const t = await getTranslations({ locale, namespace: "seo" }); + const siteUrl = process.env.NEXT_PUBLIC_APP_URL || "https://iddaai.com"; + + // Next.js parses route variables automatically, but for canonical we'll just use a clean relative base if available, + // or let next.js construct it implicitly from metadataBase if not explicitly specified. + // We'll set alternates just for languages based on current path segment as a best effort + const pathSegment = "signup"; + + return { + title: t("signup.title"), + description: t("signup.description"), + alternates: { + canonical: `${siteUrl}/${locale}/${pathSegment}`, + languages: { + en: `${siteUrl}/en/${pathSegment}`, + tr: `${siteUrl}/tr/${pathSegment}`, + }, + }, + }; +} + const schema = yup.object({ name: yup.string().required(), email: yup.string().email().required(), diff --git a/src/app/[locale]/(site)/about/page.tsx b/src/app/[locale]/(site)/about/page.tsx index 539f1a0..8c61549 100644 --- a/src/app/[locale]/(site)/about/page.tsx +++ b/src/app/[locale]/(site)/about/page.tsx @@ -1,5 +1,31 @@ import React from 'react'; +import { Metadata } from "next"; + +export async function generateMetadata(props: { params: Promise<{ locale: string }> }): Promise { + const params = await props.params; + const { locale } = params; + const t = await getTranslations({ locale, namespace: "seo" }); + const siteUrl = process.env.NEXT_PUBLIC_APP_URL || "https://iddaai.com"; + + // Next.js parses route variables automatically, but for canonical we'll just use a clean relative base if available, + // or let next.js construct it implicitly from metadataBase if not explicitly specified. + // We'll set alternates just for languages based on current path segment as a best effort + const pathSegment = "about"; + + return { + title: t("about.title"), + description: t("about.description"), + alternates: { + canonical: `${siteUrl}/${locale}/${pathSegment}`, + languages: { + en: `${siteUrl}/en/${pathSegment}`, + tr: `${siteUrl}/tr/${pathSegment}`, + }, + }, + }; +} + function AboutPage() { return
AboutPage
; } diff --git a/src/app/[locale]/(site)/admin/page.tsx b/src/app/[locale]/(site)/admin/page.tsx index 081c69d..d057ca5 100644 --- a/src/app/[locale]/(site)/admin/page.tsx +++ b/src/app/[locale]/(site)/admin/page.tsx @@ -5,12 +5,29 @@ import { isAdminRole } from "@/lib/auth/roles"; import { getServerSession } from "next-auth"; import { notFound } from "next/navigation"; -export async function generateMetadata() { - const t = await getTranslations(); +import { Metadata } from "next"; + +export async function generateMetadata(props: { params: Promise<{ locale: string }> }): Promise { + const params = await props.params; + const { locale } = params; + const t = await getTranslations({ locale, namespace: "seo" }); + const siteUrl = process.env.NEXT_PUBLIC_APP_URL || "https://iddaai.com"; + + // Next.js parses route variables automatically, but for canonical we'll just use a clean relative base if available, + // or let next.js construct it implicitly from metadataBase if not explicitly specified. + // We'll set alternates just for languages based on current path segment as a best effort + const pathSegment = "admin"; + return { - title: `${t("admin.title")} | Suggest Bet`, - description: - "Admin panel for managing users, monitoring predictions, and system overview.", + title: t("admin.title"), + description: t("admin.description"), + alternates: { + canonical: `${siteUrl}/${locale}/${pathSegment}`, + languages: { + en: `${siteUrl}/en/${pathSegment}`, + tr: `${siteUrl}/tr/${pathSegment}`, + }, + }, }; } diff --git a/src/app/[locale]/(site)/analysis/page.tsx b/src/app/[locale]/(site)/analysis/page.tsx index 5dd5ebb..1c8b563 100644 --- a/src/app/[locale]/(site)/analysis/page.tsx +++ b/src/app/[locale]/(site)/analysis/page.tsx @@ -1,11 +1,29 @@ import { getTranslations } from "next-intl/server"; import AnalysisContent from "@/components/analysis/analysis-content"; -export async function generateMetadata() { - const t = await getTranslations(); +import { Metadata } from "next"; + +export async function generateMetadata(props: { params: Promise<{ locale: string }> }): Promise { + const params = await props.params; + const { locale } = params; + const t = await getTranslations({ locale, namespace: "seo" }); + const siteUrl = process.env.NEXT_PUBLIC_APP_URL || "https://iddaai.com"; + + // Next.js parses route variables automatically, but for canonical we'll just use a clean relative base if available, + // or let next.js construct it implicitly from metadataBase if not explicitly specified. + // We'll set alternates just for languages based on current path segment as a best effort + const pathSegment = "analysis"; + return { - title: `${t("analysis.title")} | Suggest Bet`, - description: "AI-powered multi-match analysis for coupon generation.", + title: t("analysis.title"), + description: t("analysis.description"), + alternates: { + canonical: `${siteUrl}/${locale}/${pathSegment}`, + languages: { + en: `${siteUrl}/en/${pathSegment}`, + tr: `${siteUrl}/tr/${pathSegment}`, + }, + }, }; } diff --git a/src/app/[locale]/(site)/coupon-builder/page.tsx b/src/app/[locale]/(site)/coupon-builder/page.tsx index b01cd3b..400f36b 100644 --- a/src/app/[locale]/(site)/coupon-builder/page.tsx +++ b/src/app/[locale]/(site)/coupon-builder/page.tsx @@ -1,12 +1,29 @@ import { getTranslations } from "next-intl/server"; import CouponBuilderContent from "@/components/coupons/coupon-builder-content"; -export async function generateMetadata() { - const t = await getTranslations(); +import { Metadata } from "next"; + +export async function generateMetadata(props: { params: Promise<{ locale: string }> }): Promise { + const params = await props.params; + const { locale } = params; + const t = await getTranslations({ locale, namespace: "seo" }); + const siteUrl = process.env.NEXT_PUBLIC_APP_URL || "https://iddaai.com"; + + // Next.js parses route variables automatically, but for canonical we'll just use a clean relative base if available, + // or let next.js construct it implicitly from metadataBase if not explicitly specified. + // We'll set alternates just for languages based on current path segment as a best effort + const pathSegment = "coupon-builder"; + return { - title: `${t("coupons.builder-title")} | Suggest Bet`, - description: - "Build your coupon with AI-powered suggestions. Choose your strategy and let AI optimize your bets.", + title: t("coupon-builder.title"), + description: t("coupon-builder.description"), + alternates: { + canonical: `${siteUrl}/${locale}/${pathSegment}`, + languages: { + en: `${siteUrl}/en/${pathSegment}`, + tr: `${siteUrl}/tr/${pathSegment}`, + }, + }, }; } diff --git a/src/app/[locale]/(site)/coupon-history/page.tsx b/src/app/[locale]/(site)/coupon-history/page.tsx index 855feec..93761ff 100644 --- a/src/app/[locale]/(site)/coupon-history/page.tsx +++ b/src/app/[locale]/(site)/coupon-history/page.tsx @@ -1,12 +1,29 @@ import { getTranslations } from "next-intl/server"; import CouponHistoryContent from "@/components/coupons/coupon-history-content"; -export async function generateMetadata() { - const t = await getTranslations(); +import { Metadata } from "next"; + +export async function generateMetadata(props: { params: Promise<{ locale: string }> }): Promise { + const params = await props.params; + const { locale } = params; + const t = await getTranslations({ locale, namespace: "seo" }); + const siteUrl = process.env.NEXT_PUBLIC_APP_URL || "https://iddaai.com"; + + // Next.js parses route variables automatically, but for canonical we'll just use a clean relative base if available, + // or let next.js construct it implicitly from metadataBase if not explicitly specified. + // We'll set alternates just for languages based on current path segment as a best effort + const pathSegment = "coupon-history"; + return { - title: `${t("coupons.history-title")} | Suggest Bet`, - description: - "View your coupon history, track wins and losses, and analyze your betting performance.", + title: t("coupon-history.title"), + description: t("coupon-history.description"), + alternates: { + canonical: `${siteUrl}/${locale}/${pathSegment}`, + languages: { + en: `${siteUrl}/en/${pathSegment}`, + tr: `${siteUrl}/tr/${pathSegment}`, + }, + }, }; } diff --git a/src/app/[locale]/(site)/dashboard/page.tsx b/src/app/[locale]/(site)/dashboard/page.tsx index da3d2ae..5a2bd6a 100644 --- a/src/app/[locale]/(site)/dashboard/page.tsx +++ b/src/app/[locale]/(site)/dashboard/page.tsx @@ -1,13 +1,29 @@ import { getTranslations } from "next-intl/server"; import DashboardContent from "@/components/dashboard/dashboard-content"; -export async function generateMetadata() { - const t = await getTranslations(); +import { Metadata } from "next"; + +export async function generateMetadata(props: { params: Promise<{ locale: string }> }): Promise { + const params = await props.params; + const { locale } = params; + const t = await getTranslations({ locale, namespace: "seo" }); + const siteUrl = process.env.NEXT_PUBLIC_APP_URL || "https://iddaai.com"; + + // Next.js parses route variables automatically, but for canonical we'll just use a clean relative base if available, + // or let next.js construct it implicitly from metadataBase if not explicitly specified. + // We'll set alternates just for languages based on current path segment as a best effort + const pathSegment = "dashboard"; return { - title: `${t("dashboard.title")} | Suggest Bet`, - description: - "Your personalized betting dashboard with predictions, value bets, and match insights.", + title: t("dashboard.title"), + description: t("dashboard.description"), + alternates: { + canonical: `${siteUrl}/${locale}/${pathSegment}`, + languages: { + en: `${siteUrl}/en/${pathSegment}`, + tr: `${siteUrl}/tr/${pathSegment}`, + }, + }, }; } diff --git a/src/app/[locale]/(site)/h2h/page.tsx b/src/app/[locale]/(site)/h2h/page.tsx index 1499087..2dace5a 100644 --- a/src/app/[locale]/(site)/h2h/page.tsx +++ b/src/app/[locale]/(site)/h2h/page.tsx @@ -1,11 +1,29 @@ import { getTranslations } from "next-intl/server"; import H2HContent from "@/components/h2h/h2h-content"; -export async function generateMetadata() { - const t = await getTranslations(); +import { Metadata } from "next"; + +export async function generateMetadata(props: { params: Promise<{ locale: string }> }): Promise { + const params = await props.params; + const { locale } = params; + const t = await getTranslations({ locale, namespace: "seo" }); + const siteUrl = process.env.NEXT_PUBLIC_APP_URL || "https://iddaai.com"; + + // Next.js parses route variables automatically, but for canonical we'll just use a clean relative base if available, + // or let next.js construct it implicitly from metadataBase if not explicitly specified. + // We'll set alternates just for languages based on current path segment as a best effort + const pathSegment = "h2h"; + return { - title: `${t("matches.head-to-head")} | Suggest Bet`, - description: "Compare two teams and view their head-to-head match history.", + title: t("h2h.title"), + description: t("h2h.description"), + alternates: { + canonical: `${siteUrl}/${locale}/${pathSegment}`, + languages: { + en: `${siteUrl}/en/${pathSegment}`, + tr: `${siteUrl}/tr/${pathSegment}`, + }, + }, }; } diff --git a/src/app/[locale]/(site)/home/page.tsx b/src/app/[locale]/(site)/home/page.tsx index 98b6569..ca4d415 100644 --- a/src/app/[locale]/(site)/home/page.tsx +++ b/src/app/[locale]/(site)/home/page.tsx @@ -1,13 +1,29 @@ import { getTranslations } from "next-intl/server"; import HomeContent from "@/components/home/home-content"; -export async function generateMetadata() { - const t = await getTranslations(); +import { Metadata } from "next"; + +export async function generateMetadata(props: { params: Promise<{ locale: string }> }): Promise { + const params = await props.params; + const { locale } = params; + const t = await getTranslations({ locale, namespace: "seo" }); + const siteUrl = process.env.NEXT_PUBLIC_APP_URL || "https://iddaai.com"; + + // Next.js parses route variables automatically, but for canonical we'll just use a clean relative base if available, + // or let next.js construct it implicitly from metadataBase if not explicitly specified. + // We'll set alternates just for languages based on current path segment as a best effort + const pathSegment = "home"; return { - title: `${t("home")} | Suggest Bet`, - description: - "AI-powered betting predictions. Analyze matches, discover value bets, and build winning coupons.", + title: t("home.title"), + description: t("home.description"), + alternates: { + canonical: `${siteUrl}/${locale}/${pathSegment}`, + languages: { + en: `${siteUrl}/en/${pathSegment}`, + tr: `${siteUrl}/tr/${pathSegment}`, + }, + }, }; } diff --git a/src/app/[locale]/(site)/leagues/[id]/page.tsx b/src/app/[locale]/(site)/leagues/[id]/page.tsx new file mode 100644 index 0000000..b29b9d7 --- /dev/null +++ b/src/app/[locale]/(site)/leagues/[id]/page.tsx @@ -0,0 +1,30 @@ +import { getTranslations } from "next-intl/server"; +import LeagueDetailContent from "@/components/leagues/league-detail-content"; + +import { Metadata } from "next"; + +export async function generateMetadata(props: { params: Promise<{ locale: string; id: string }> }): Promise { + const params = await props.params; + const { locale, id } = params; + const t = await getTranslations({ locale, namespace: "seo" }); + const siteUrl = process.env.NEXT_PUBLIC_APP_URL || "https://iddaai.com"; + + const pathSegment = `leagues/${id}`; + + return { + title: `${t("leagues.title")} - Detay`, + description: t("leagues.description"), + alternates: { + canonical: `${siteUrl}/${locale}/${pathSegment}`, + languages: { + en: `${siteUrl}/en/${pathSegment}`, + tr: `${siteUrl}/tr/${pathSegment}`, + }, + }, + }; +} + +export default async function LeagueDetailPage(props: { params: Promise<{ id: string }> }) { + const { id } = await props.params; + return ; +} diff --git a/src/app/[locale]/(site)/leagues/page.tsx b/src/app/[locale]/(site)/leagues/page.tsx index cf0ef55..38c3407 100644 --- a/src/app/[locale]/(site)/leagues/page.tsx +++ b/src/app/[locale]/(site)/leagues/page.tsx @@ -1,11 +1,29 @@ import { getTranslations } from "next-intl/server"; import LeaguesContent from "@/components/leagues/leagues-content"; -export async function generateMetadata() { - const t = await getTranslations(); +import { Metadata } from "next"; + +export async function generateMetadata(props: { params: Promise<{ locale: string }> }): Promise { + const params = await props.params; + const { locale } = params; + const t = await getTranslations({ locale, namespace: "seo" }); + const siteUrl = process.env.NEXT_PUBLIC_APP_URL || "https://iddaai.com"; + + // Next.js parses route variables automatically, but for canonical we'll just use a clean relative base if available, + // or let next.js construct it implicitly from metadataBase if not explicitly specified. + // We'll set alternates just for languages based on current path segment as a best effort + const pathSegment = "leagues"; + return { - title: `${t("leagues.title")} | Suggest Bet`, - description: "Browse football and basketball leagues, countries, and teams.", + title: t("leagues.title"), + description: t("leagues.description"), + alternates: { + canonical: `${siteUrl}/${locale}/${pathSegment}`, + languages: { + en: `${siteUrl}/en/${pathSegment}`, + tr: `${siteUrl}/tr/${pathSegment}`, + }, + }, }; } diff --git a/src/app/[locale]/(site)/matches/[id]/page.tsx b/src/app/[locale]/(site)/matches/[id]/page.tsx index 3666bfe..d4ad3be 100644 --- a/src/app/[locale]/(site)/matches/[id]/page.tsx +++ b/src/app/[locale]/(site)/matches/[id]/page.tsx @@ -1,11 +1,29 @@ import { getTranslations } from "next-intl/server"; import MatchDetailContent from "@/components/matches/match-detail-content"; -export async function generateMetadata() { - const t = await getTranslations(); +import { Metadata } from "next"; + +export async function generateMetadata(props: { params: Promise<{ locale: string }> }): Promise { + const params = await props.params; + const { locale } = params; + const t = await getTranslations({ locale, namespace: "seo" }); + const siteUrl = process.env.NEXT_PUBLIC_APP_URL || "https://iddaai.com"; + + // Next.js parses route variables automatically, but for canonical we'll just use a clean relative base if available, + // or let next.js construct it implicitly from metadataBase if not explicitly specified. + // We'll set alternates just for languages based on current path segment as a best effort + const pathSegment = "matches/[id]"; return { - title: `${t("matches.match-details")} | Suggest Bet`, + title: t("matches.title"), + description: t("matches.description"), + alternates: { + canonical: `${siteUrl}/${locale}/${pathSegment}`, + languages: { + en: `${siteUrl}/en/${pathSegment}`, + tr: `${siteUrl}/tr/${pathSegment}`, + }, + }, }; } diff --git a/src/app/[locale]/(site)/matches/page.tsx b/src/app/[locale]/(site)/matches/page.tsx index 930d3e8..4854888 100644 --- a/src/app/[locale]/(site)/matches/page.tsx +++ b/src/app/[locale]/(site)/matches/page.tsx @@ -1,13 +1,29 @@ import { getTranslations } from "next-intl/server"; import MatchesContent from "@/components/matches/matches-content"; -export async function generateMetadata() { - const t = await getTranslations(); +import { Metadata } from "next"; + +export async function generateMetadata(props: { params: Promise<{ locale: string }> }): Promise { + const params = await props.params; + const { locale } = params; + const t = await getTranslations({ locale, namespace: "seo" }); + const siteUrl = process.env.NEXT_PUBLIC_APP_URL || "https://iddaai.com"; + + // Next.js parses route variables automatically, but for canonical we'll just use a clean relative base if available, + // or let next.js construct it implicitly from metadataBase if not explicitly specified. + // We'll set alternates just for languages based on current path segment as a best effort + const pathSegment = "matches"; return { - title: `${t("matches.title")} | Suggest Bet`, - description: - "Browse and analyze upcoming football and basketball matches with AI predictions.", + title: t("matches.title"), + description: t("matches.description"), + alternates: { + canonical: `${siteUrl}/${locale}/${pathSegment}`, + languages: { + en: `${siteUrl}/en/${pathSegment}`, + tr: `${siteUrl}/tr/${pathSegment}`, + }, + }, }; } diff --git a/src/app/[locale]/(site)/predictions/page.tsx b/src/app/[locale]/(site)/predictions/page.tsx index 040a7c5..7f0e512 100644 --- a/src/app/[locale]/(site)/predictions/page.tsx +++ b/src/app/[locale]/(site)/predictions/page.tsx @@ -1,12 +1,29 @@ import { getTranslations } from "next-intl/server"; import PredictionsContent from "@/components/predictions/predictions-content"; -export async function generateMetadata() { - const t = await getTranslations(); +import { Metadata } from "next"; + +export async function generateMetadata(props: { params: Promise<{ locale: string }> }): Promise { + const params = await props.params; + const { locale } = params; + const t = await getTranslations({ locale, namespace: "seo" }); + const siteUrl = process.env.NEXT_PUBLIC_APP_URL || "https://iddaai.com"; + + // Next.js parses route variables automatically, but for canonical we'll just use a clean relative base if available, + // or let next.js construct it implicitly from metadataBase if not explicitly specified. + // We'll set alternates just for languages based on current path segment as a best effort + const pathSegment = "predictions"; + return { - title: `${t("predictions.title")} | Suggest Bet`, - description: - "AI-powered match predictions with confidence scores, value bets, and prediction history.", + title: t("predictions.title"), + description: t("predictions.description"), + alternates: { + canonical: `${siteUrl}/${locale}/${pathSegment}`, + languages: { + en: `${siteUrl}/en/${pathSegment}`, + tr: `${siteUrl}/tr/${pathSegment}`, + }, + }, }; } diff --git a/src/app/[locale]/(site)/profile/page.tsx b/src/app/[locale]/(site)/profile/page.tsx index 0a014c4..1b1c99d 100644 --- a/src/app/[locale]/(site)/profile/page.tsx +++ b/src/app/[locale]/(site)/profile/page.tsx @@ -1,12 +1,29 @@ import { getTranslations } from "next-intl/server"; import ProfileContent from "@/components/profile/profile-content"; -export async function generateMetadata() { - const t = await getTranslations(); +import { Metadata } from "next"; + +export async function generateMetadata(props: { params: Promise<{ locale: string }> }): Promise { + const params = await props.params; + const { locale } = params; + const t = await getTranslations({ locale, namespace: "seo" }); + const siteUrl = process.env.NEXT_PUBLIC_APP_URL || "https://iddaai.com"; + + // Next.js parses route variables automatically, but for canonical we'll just use a clean relative base if available, + // or let next.js construct it implicitly from metadataBase if not explicitly specified. + // We'll set alternates just for languages based on current path segment as a best effort + const pathSegment = "profile"; + return { - title: `${t("profile.title")} | Suggest Bet`, - description: - "Manage your profile, view account info, and track your betting statistics.", + title: t("profile.title"), + description: t("profile.description"), + alternates: { + canonical: `${siteUrl}/${locale}/${pathSegment}`, + languages: { + en: `${siteUrl}/en/${pathSegment}`, + tr: `${siteUrl}/tr/${pathSegment}`, + }, + }, }; } diff --git a/src/app/[locale]/(site)/spor-toto/page.tsx b/src/app/[locale]/(site)/spor-toto/page.tsx index c3f78ad..2789593 100644 --- a/src/app/[locale]/(site)/spor-toto/page.tsx +++ b/src/app/[locale]/(site)/spor-toto/page.tsx @@ -1,12 +1,29 @@ import { getTranslations } from "next-intl/server"; import SporTotoContent from "@/components/spor-toto/spor-toto-content"; -export async function generateMetadata() { - const t = await getTranslations(); +import { Metadata } from "next"; + +export async function generateMetadata(props: { params: Promise<{ locale: string }> }): Promise { + const params = await props.params; + const { locale } = params; + const t = await getTranslations({ locale, namespace: "seo" }); + const siteUrl = process.env.NEXT_PUBLIC_APP_URL || "https://iddaai.com"; + + // Next.js parses route variables automatically, but for canonical we'll just use a clean relative base if available, + // or let next.js construct it implicitly from metadataBase if not explicitly specified. + // We'll set alternates just for languages based on current path segment as a best effort + const pathSegment = "spor-toto"; + return { - title: `${t("spor-toto.title")} | Suggest Bet`, - description: - "Spor Toto predictions with AI-powered analysis. Generate optimized system coupons with contrarian parimutuel strategy.", + title: t("spor-toto.title"), + description: t("spor-toto.description"), + alternates: { + canonical: `${siteUrl}/${locale}/${pathSegment}`, + languages: { + en: `${siteUrl}/en/${pathSegment}`, + tr: `${siteUrl}/tr/${pathSegment}`, + }, + }, }; } diff --git a/src/app/[locale]/(site)/teams/[id]/page.tsx b/src/app/[locale]/(site)/teams/[id]/page.tsx index 85b0aae..2ca3546 100644 --- a/src/app/[locale]/(site)/teams/[id]/page.tsx +++ b/src/app/[locale]/(site)/teams/[id]/page.tsx @@ -1,10 +1,29 @@ import { getTranslations } from "next-intl/server"; import TeamDetailContent from "@/components/teams/team-detail-content"; -export async function generateMetadata() { - const t = await getTranslations(); +import { Metadata } from "next"; + +export async function generateMetadata(props: { params: Promise<{ locale: string }> }): Promise { + const params = await props.params; + const { locale } = params; + const t = await getTranslations({ locale, namespace: "seo" }); + const siteUrl = process.env.NEXT_PUBLIC_APP_URL || "https://iddaai.com"; + + // Next.js parses route variables automatically, but for canonical we'll just use a clean relative base if available, + // or let next.js construct it implicitly from metadataBase if not explicitly specified. + // We'll set alternates just for languages based on current path segment as a best effort + const pathSegment = "teams/[id]"; + return { - title: `${t("nav.teams")} | Suggest Bet`, + title: t("teams.title"), + description: t("teams.description"), + alternates: { + canonical: `${siteUrl}/${locale}/${pathSegment}`, + languages: { + en: `${siteUrl}/en/${pathSegment}`, + tr: `${siteUrl}/tr/${pathSegment}`, + }, + }, }; } diff --git a/src/app/[locale]/(site)/teams/page.tsx b/src/app/[locale]/(site)/teams/page.tsx index 96a339b..a911bdf 100644 --- a/src/app/[locale]/(site)/teams/page.tsx +++ b/src/app/[locale]/(site)/teams/page.tsx @@ -1,11 +1,29 @@ import { getTranslations } from "next-intl/server"; import TeamsContent from "@/components/teams/teams-content"; -export async function generateMetadata() { - const t = await getTranslations(); +import { Metadata } from "next"; + +export async function generateMetadata(props: { params: Promise<{ locale: string }> }): Promise { + const params = await props.params; + const { locale } = params; + const t = await getTranslations({ locale, namespace: "seo" }); + const siteUrl = process.env.NEXT_PUBLIC_APP_URL || "https://iddaai.com"; + + // Next.js parses route variables automatically, but for canonical we'll just use a clean relative base if available, + // or let next.js construct it implicitly from metadataBase if not explicitly specified. + // We'll set alternates just for languages based on current path segment as a best effort + const pathSegment = "teams"; + return { - title: `${t("nav.teams")} | Suggest Bet`, - description: "Search and explore football teams, view match history and stats.", + title: t("teams.title"), + description: t("teams.description"), + alternates: { + canonical: `${siteUrl}/${locale}/${pathSegment}`, + languages: { + en: `${siteUrl}/en/${pathSegment}`, + tr: `${siteUrl}/tr/${pathSegment}`, + }, + }, }; } diff --git a/src/app/[locale]/layout.tsx b/src/app/[locale]/layout.tsx index 31b6222..699bf02 100644 --- a/src/app/[locale]/layout.tsx +++ b/src/app/[locale]/layout.tsx @@ -4,8 +4,38 @@ import { hasLocale, NextIntlClientProvider } from "next-intl"; import { notFound } from "next/navigation"; import { routing } from "@/i18n/routing"; import { dir } from "i18next"; +import { Metadata } from "next"; +import { getTranslations } from "next-intl/server"; import "./global.css"; +export async function generateMetadata({ params }: { params: Promise<{ locale: string }> }): Promise { + const { locale } = await params; + const t = await getTranslations({ locale, namespace: "seo" }); + const siteUrl = process.env.NEXT_PUBLIC_APP_URL || "https://iddaai.com"; + + return { + metadataBase: new URL(siteUrl), + title: { + template: `%s | ${t("global.title").split(" | ")[0]}`, + default: t("global.title"), + }, + description: t("global.description"), + keywords: t("global.keywords"), + openGraph: { + title: t("global.title"), + description: t("global.description"), + siteName: t("global.title").split(" | ")[0], + locale: locale, + type: "website", + }, + twitter: { + card: "summary_large_image", + title: t("global.title"), + description: t("global.description"), + }, + }; +} + const bricolage = Bricolage_Grotesque({ variable: "--font-bricolage", subsets: ["latin"], @@ -23,6 +53,27 @@ export default async function RootLayout({ notFound(); } + const siteUrl = process.env.NEXT_PUBLIC_APP_URL || "https://iddaai.com"; + const jsonLd = { + "@context": "https://schema.org", + "@type": "WebSite", + "name": "iddaai.com", + "url": siteUrl, + "potentialAction": { + "@type": "SearchAction", + "target": `${siteUrl}/search?q={search_term_string}`, + "query-input": "required name=search_term_string" + } + }; + + const orgJsonLd = { + "@context": "https://schema.org", + "@type": "Organization", + "name": "iddaai.com", + "url": siteUrl, + "logo": `${siteUrl}/favicon/android-chrome-512x512.png`, + }; + return ( */} +