133 lines
3.4 KiB
TypeScript
133 lines
3.4 KiB
TypeScript
import { SITE_URL } from "@/config/pageSeo";
|
||
import { DEFAULT_LANGUAGE, type AppLanguage } from "@/lib/i18n/registry";
|
||
import { formatLocalizedSeoTitle, getSiteSeoMeta } from "@/lib/i18n/seo";
|
||
import { translateCommon } from "@/lib/i18n/translate";
|
||
import { User } from "@/types/types";
|
||
|
||
export function buildProfileSeo(
|
||
user: User | null,
|
||
username: string,
|
||
lang: AppLanguage = DEFAULT_LANGUAGE
|
||
) {
|
||
const path = `/users/${username}`;
|
||
const siteName = getSiteSeoMeta(lang).name;
|
||
|
||
if (!user) {
|
||
const titleCore = translateCommon(lang, "profileSeo.guestTitle", {
|
||
username,
|
||
});
|
||
return {
|
||
title: formatLocalizedSeoTitle(titleCore, lang),
|
||
description: translateCommon(lang, "profileSeo.guestDescription", {
|
||
username,
|
||
siteName,
|
||
}),
|
||
path,
|
||
h1: titleCore,
|
||
index: false,
|
||
};
|
||
}
|
||
|
||
if (user.blocked_you) {
|
||
const unavailableTitle = translateCommon(
|
||
lang,
|
||
"profileSeo.unavailableTitle"
|
||
);
|
||
return {
|
||
title: formatLocalizedSeoTitle(unavailableTitle, lang),
|
||
description: translateCommon(lang, "profileSeo.unavailableDescription"),
|
||
path,
|
||
h1: unavailableTitle,
|
||
index: false,
|
||
};
|
||
}
|
||
|
||
const fullName = `${user.first_name || ""} ${user.last_name || ""}`.trim();
|
||
const city = user.city?.name || "";
|
||
const expertise =
|
||
user.expertise ||
|
||
translateCommon(lang, "profileSeo.defaultExpertise");
|
||
const bio =
|
||
user.bio ||
|
||
translateCommon(lang, "profileSeo.defaultBio", { siteName });
|
||
|
||
const nameSegments = fullName ? [fullName, username] : [username];
|
||
const titleCore = [...nameSegments, expertise, city]
|
||
.filter(Boolean)
|
||
.join(" – ");
|
||
|
||
const description = [fullName, expertise, city, bio]
|
||
.filter(Boolean)
|
||
.join(" – ");
|
||
|
||
const isIndexable = !user.is_private && !user.private_content_locked;
|
||
const citySuffix = city
|
||
? translateCommon(lang, "profileSeo.titleInCity", { city })
|
||
: "";
|
||
|
||
return {
|
||
title: `${titleCore} | ${siteName}`,
|
||
description,
|
||
path,
|
||
h1: fullName
|
||
? `${fullName} – ${expertise}${citySuffix}`
|
||
: `${username} – ${expertise}`,
|
||
index: isIndexable,
|
||
fullName,
|
||
expertise,
|
||
city,
|
||
bio,
|
||
profileUrl: `${SITE_URL}${path}`,
|
||
};
|
||
}
|
||
|
||
export function buildProfileJsonLd(
|
||
user: User,
|
||
username: string,
|
||
profileUrl: string,
|
||
lang: AppLanguage = DEFAULT_LANGUAGE
|
||
) {
|
||
const fullName = `${user.first_name || ""} ${user.last_name || ""}`.trim();
|
||
const siteName = getSiteSeoMeta(lang).name;
|
||
|
||
return {
|
||
"@context": "https://schema.org",
|
||
"@type": "ProfilePage",
|
||
name: fullName || username,
|
||
url: profileUrl,
|
||
mainEntity: {
|
||
"@type": "Person",
|
||
name: fullName || username,
|
||
alternateName: username,
|
||
description: user.bio,
|
||
image: user.profile_image,
|
||
jobTitle: user.expertise,
|
||
address: user.city?.name
|
||
? {
|
||
"@type": "PostalAddress",
|
||
addressLocality: user.city.name,
|
||
addressCountry: "IR",
|
||
}
|
||
: undefined,
|
||
url: profileUrl,
|
||
},
|
||
breadcrumb: {
|
||
"@type": "BreadcrumbList",
|
||
itemListElement: [
|
||
{
|
||
"@type": "ListItem",
|
||
position: 1,
|
||
name: siteName,
|
||
item: SITE_URL,
|
||
},
|
||
{
|
||
"@type": "ListItem",
|
||
position: 2,
|
||
name: fullName || username,
|
||
item: profileUrl,
|
||
},
|
||
],
|
||
},
|
||
};
|
||
}
|