Add canonical URLs, hreflang alternates and article metadata

Set metadataBase so relative metadata URLs resolve to the real domain,
link the Norwegian and English versions of each page, and mark blog
posts as articles with their publish date and author.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
leanderandClaude Opus 5.5 committed 2026-10-30 22:59:56 +01:00
1 parent 115afd4275
commit 2e54e32ea6
5 files changed
+38 -6

No files matched your search

+2
View File
@@ -64,10 +64,12 @@ export async function generateMetadata({
return generateSeoMetadata({
locale,
path: `/blog/${slug}`,
title: data.title,
description: data.excerpt,
imageURL: data.mainImage?.asset?.url,
author: data.author?.name,
publishedTime: data._createdAt,
})
}
+1
View File
@@ -36,6 +36,7 @@ export async function generateMetadata({
return generateSeoMetadata({
locale,
path: `/event/${slug}`,
title: data.title,
description: [
`${t("time")}: ${formatEventDate(data.date, locale)}`,
+3 -1
View File
@@ -6,7 +6,7 @@ import { getMessages } from "next-intl/server"
import { notFound } from "next/navigation"
import LanguageSelector from "@/components/ui/languageSelector"
import { THEME_COLOR } from "@/components/seo"
import { SITE_URL, THEME_COLOR } from "@/components/seo"
import UmamiAnalytics from "@/components/umamiAnalytics"
import { routing } from "@/i18n/routing"
@@ -16,6 +16,8 @@ import { routing } from "@/i18n/routing"
const CLIENT_NAMESPACES = ["about", "buttons", "common", "office"]
export const metadata: Metadata = {
// Resolves relative URLs in metadata, like Open Graph images and alternates
metadataBase: new URL(SITE_URL),
title: "UiO Gaming",
description:
"En hobbyforening som ønsker skape et sosialt miljø rundt gaming og e-sport på UiO!",
+1 -1
View File
@@ -23,7 +23,7 @@ export async function generateMetadata({
}: HomePageParams): Promise<Metadata> {
const { locale } = await params
return generateSeoMetadata({ locale })
return generateSeoMetadata({ locale, path: "/" })
}
export default function Home() {
+31 -4
View File
@@ -2,38 +2,65 @@ import { Metadata } from "next"
import type { Locale } from "next-intl"
import { getTranslations } from "next-intl/server"
import { routing } from "@/i18n/routing"
export const SITE_URL = "https://uiogaming.no"
export const THEME_COLOR = "#7d36e7"
type SeoProps = {
locale: Locale
/** Path without the locale prefix, e.g. "/" or "/event/some-slug" */
path: string
title?: string
description?: string
imageURL?: string
author?: string
/** Marks the page as an article, e.g. a blog post */
publishedTime?: string
}
export async function generateSeoMetadata({
locale,
path,
title,
description,
imageURL,
author,
publishedTime,
}: SeoProps): Promise<Metadata> {
const t = await getTranslations({ locale, namespace: "metaTags" })
const defaultTitle = "UiO Gaming"
const metaDescription = description || t("description")
const siteUrl = "https://uiogaming.no"
const localizedPath = (pageLocale: Locale) =>
path === "/" ? `/${pageLocale}` : `/${pageLocale}${path}`
return {
title: title ? `${title} | ${defaultTitle}` : defaultTitle,
description: metaDescription,
authors: author ? [{ name: author }] : [{ name: "UiO Gaming" }],
// Tells search engines that the Norwegian and English versions are the
// same page. The unprefixed path redirects based on the browser language
alternates: {
canonical: localizedPath(locale),
languages: {
...Object.fromEntries(
routing.locales.map(pageLocale => [
pageLocale,
localizedPath(pageLocale),
])
),
"x-default": path,
},
},
openGraph: {
title: title || defaultTitle,
description: metaDescription,
type: "website",
...(publishedTime
? { type: "article", publishedTime, authors: author && [author] }
: { type: "website" }),
locale: locale,
url: localizedPath(locale),
siteName: defaultTitle,
images: imageURL
? [
@@ -46,7 +73,7 @@ export async function generateSeoMetadata({
]
: [
{
url: `${siteUrl}/logo_2024_neon_trans.png`,
url: "/logo_2024_neon_trans.png",
alt: defaultTitle,
},
],
@@ -55,7 +82,7 @@ export async function generateSeoMetadata({
card: imageURL ? "summary_large_image" : "summary",
title: title || defaultTitle,
description: metaDescription,
images: imageURL ? [imageURL] : [`${siteUrl}/logo_2024_neon_trans.png`],
images: imageURL ? [imageURL] : ["/logo_2024_neon_trans.png"],
},
other: {
"msapplication-TileColor": THEME_COLOR,