login register comlated
This commit is contained in:
137
src/shared/lib/metadata.ts
Normal file
137
src/shared/lib/metadata.ts
Normal file
@@ -0,0 +1,137 @@
|
||||
import type { Metadata } from 'next';
|
||||
import { SEO_DATA, type SupportedLocale } from '../config/seo.config';
|
||||
|
||||
// ─── Site-wide constants ───────────────────────────────────────────────────────
|
||||
|
||||
const SITE_URL = process.env.NEXT_PUBLIC_SITE_URL ?? 'https://antiplagiat.uz';
|
||||
const OG_IMAGE_URL = `${SITE_URL}/og-image.png`; // 1200×630 px recommended
|
||||
const TWITTER_HANDLE = '@antiplagiatuz'; // update or remove if unused
|
||||
|
||||
// ─── Root layout metadata (called in app/[locale]/layout.tsx) ─────────────────
|
||||
|
||||
export function generateRootMetadata(locale: string): Metadata {
|
||||
const seo = SEO_DATA[locale as SupportedLocale] ?? SEO_DATA.ru;
|
||||
|
||||
// Build alternate-language links for <head>
|
||||
const languages: Record<string, string> = {
|
||||
uz: `${SITE_URL}/uz`,
|
||||
ru: `${SITE_URL}/ru`,
|
||||
en: `${SITE_URL}/en`,
|
||||
'x-default': `${SITE_URL}/ru`,
|
||||
};
|
||||
|
||||
return {
|
||||
// ── Basic ──────────────────────────────────────────────────────────────────
|
||||
metadataBase: new URL(SITE_URL),
|
||||
title: {
|
||||
default: seo.title,
|
||||
template: seo.titleTemplate,
|
||||
},
|
||||
description: seo.description,
|
||||
keywords: seo.keywords,
|
||||
authors: [{ name: seo.siteName, url: SITE_URL }],
|
||||
creator: seo.siteName,
|
||||
publisher: seo.siteName,
|
||||
applicationName: seo.siteName,
|
||||
generator: 'Next.js',
|
||||
|
||||
// ── Canonical & alternates ─────────────────────────────────────────────────
|
||||
alternates: {
|
||||
canonical: `${SITE_URL}/${locale}`,
|
||||
languages,
|
||||
},
|
||||
|
||||
// ── Robots ────────────────────────────────────────────────────────────────
|
||||
robots: {
|
||||
index: true,
|
||||
follow: true,
|
||||
nocache: false,
|
||||
googleBot: {
|
||||
index: true,
|
||||
follow: true,
|
||||
noimageindex: false,
|
||||
'max-video-preview': -1,
|
||||
'max-image-preview': 'large',
|
||||
'max-snippet': -1,
|
||||
},
|
||||
},
|
||||
|
||||
// ── Open Graph ────────────────────────────────────────────────────────────
|
||||
openGraph: {
|
||||
type: 'website',
|
||||
locale: ogLocale(locale),
|
||||
alternateLocale: ogAlternates(locale),
|
||||
url: `${SITE_URL}/${locale}`,
|
||||
siteName: seo.siteName,
|
||||
title: seo.ogTitle,
|
||||
description: seo.ogDescription,
|
||||
images: [
|
||||
{
|
||||
url: OG_IMAGE_URL,
|
||||
width: 1200,
|
||||
height: 630,
|
||||
alt: seo.ogTitle,
|
||||
type: 'image/png',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// ── Twitter / X ───────────────────────────────────────────────────────────
|
||||
twitter: {
|
||||
card: 'summary_large_image',
|
||||
site: TWITTER_HANDLE,
|
||||
creator: TWITTER_HANDLE,
|
||||
title: seo.ogTitle,
|
||||
description: seo.ogDescription,
|
||||
images: [OG_IMAGE_URL],
|
||||
},
|
||||
|
||||
// ── Icons ─────────────────────────────────────────────────────────────────
|
||||
icons: {
|
||||
icon: [
|
||||
{ url: '/favicon.ico' },
|
||||
{ url: '/icons/icon-16.png', sizes: '16x16', type: 'image/png' },
|
||||
{ url: '/icons/icon-32.png', sizes: '32x32', type: 'image/png' },
|
||||
{ url: '/icons/icon-192.png', sizes: '192x192', type: 'image/png' },
|
||||
],
|
||||
apple: [
|
||||
{
|
||||
url: '/icons/apple-touch-icon.png',
|
||||
sizes: '180x180',
|
||||
type: 'image/png',
|
||||
},
|
||||
],
|
||||
shortcut: '/favicon.ico',
|
||||
},
|
||||
|
||||
// ── Web app manifest ──────────────────────────────────────────────────────
|
||||
manifest: '/manifest.webmanifest',
|
||||
|
||||
// ── Verification (add your Search Console token) ──────────────────────────
|
||||
verification: {
|
||||
google: process.env.NEXT_PUBLIC_GOOGLE_SITE_VERIFICATION ?? '',
|
||||
yandex: process.env.NEXT_PUBLIC_YANDEX_VERIFICATION ?? '',
|
||||
},
|
||||
|
||||
// ── Extra meta ────────────────────────────────────────────────────────────
|
||||
category: 'education',
|
||||
};
|
||||
}
|
||||
|
||||
// ─── Helpers ──────────────────────────────────────────────────────────────────
|
||||
|
||||
/** Maps locale code to Open Graph locale string */
|
||||
function ogLocale(locale: string): string {
|
||||
const map: Record<string, string> = {
|
||||
uz: 'uz_UZ',
|
||||
ru: 'ru_RU',
|
||||
en: 'en_US',
|
||||
};
|
||||
return map[locale] ?? 'ru_RU';
|
||||
}
|
||||
|
||||
/** Returns the other two OG locales for alternateLocale */
|
||||
function ogAlternates(currentLocale: string): string[] {
|
||||
const all = ['uz_UZ', 'ru_RU', 'en_US'];
|
||||
return all.filter((l) => l !== ogLocale(currentLocale));
|
||||
}
|
||||
Reference in New Issue
Block a user