Align brand search SEO with Grace Salmoun
هذا الالتزام موجود في:
@@ -1,5 +1,5 @@
|
|||||||
import type { Metadata } from "next";
|
import type { Metadata } from "next";
|
||||||
import { notFound } from "next/navigation";
|
import { notFound, permanentRedirect } from "next/navigation";
|
||||||
import { HomePage } from "@/components/home-page";
|
import { HomePage } from "@/components/home-page";
|
||||||
import { isLanguage, languages, type Language } from "@/data/portfolio";
|
import { isLanguage, languages, type Language } from "@/data/portfolio";
|
||||||
import { getHomeMetadata } from "@/data/seo";
|
import { getHomeMetadata } from "@/data/seo";
|
||||||
@@ -21,5 +21,9 @@ export default function LocalizedHomePage({ params }: { params: { lang: string }
|
|||||||
notFound();
|
notFound();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (params.lang === "en") {
|
||||||
|
permanentRedirect("/");
|
||||||
|
}
|
||||||
|
|
||||||
return <HomePage language={params.lang as Language} />;
|
return <HomePage language={params.lang as Language} />;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import type { Metadata } from "next";
|
import type { Metadata } from "next";
|
||||||
import { notFound } from "next/navigation";
|
import { notFound, permanentRedirect } from "next/navigation";
|
||||||
import { ResumePageContent } from "@/components/resume-page-content";
|
import { ResumePageContent } from "@/components/resume-page-content";
|
||||||
import { isLanguage, languages, type Language } from "@/data/portfolio";
|
import { isLanguage, languages, type Language } from "@/data/portfolio";
|
||||||
import { getResumeMetadata } from "@/data/seo";
|
import { getResumeMetadata } from "@/data/seo";
|
||||||
@@ -21,5 +21,9 @@ export default function LocalizedResumePage({ params }: { params: { lang: string
|
|||||||
notFound();
|
notFound();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (params.lang === "en") {
|
||||||
|
permanentRedirect("/resume");
|
||||||
|
}
|
||||||
|
|
||||||
return <ResumePageContent language={params.lang as Language} />;
|
return <ResumePageContent language={params.lang as Language} />;
|
||||||
}
|
}
|
||||||
|
|||||||
11
app/page.tsx
11
app/page.tsx
@@ -1,5 +1,12 @@
|
|||||||
import { redirect } from "next/navigation";
|
import type { Metadata } from "next";
|
||||||
|
import { HomePage } from "@/components/home-page";
|
||||||
|
import type { Language } from "@/data/portfolio";
|
||||||
|
import { getHomeMetadata } from "@/data/seo";
|
||||||
|
|
||||||
|
const defaultLanguage: Language = "en";
|
||||||
|
|
||||||
|
export const metadata: Metadata = getHomeMetadata(defaultLanguage);
|
||||||
|
|
||||||
export default function RootPage() {
|
export default function RootPage() {
|
||||||
redirect("/en");
|
return <HomePage language={defaultLanguage} />;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,12 @@
|
|||||||
import { redirect } from "next/navigation";
|
import type { Metadata } from "next";
|
||||||
|
import { ResumePageContent } from "@/components/resume-page-content";
|
||||||
|
import type { Language } from "@/data/portfolio";
|
||||||
|
import { getResumeMetadata } from "@/data/seo";
|
||||||
|
|
||||||
|
const defaultLanguage: Language = "en";
|
||||||
|
|
||||||
|
export const metadata: Metadata = getResumeMetadata(defaultLanguage);
|
||||||
|
|
||||||
export default function RootResumePage() {
|
export default function RootResumePage() {
|
||||||
redirect("/en/resume");
|
return <ResumePageContent language={defaultLanguage} />;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ export default function sitemap(): MetadataRoute.Sitemap {
|
|||||||
|
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
url: absoluteUrl("/en"),
|
url: absoluteUrl("/"),
|
||||||
lastModified,
|
lastModified,
|
||||||
changeFrequency: "monthly",
|
changeFrequency: "monthly",
|
||||||
priority: 1,
|
priority: 1,
|
||||||
@@ -18,7 +18,7 @@ export default function sitemap(): MetadataRoute.Sitemap {
|
|||||||
priority: 1,
|
priority: 1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
url: absoluteUrl("/en/resume"),
|
url: absoluteUrl("/resume"),
|
||||||
lastModified,
|
lastModified,
|
||||||
changeFrequency: "monthly",
|
changeFrequency: "monthly",
|
||||||
priority: 0.8,
|
priority: 0.8,
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { SiteShell } from "@/components/site-shell";
|
|||||||
import {
|
import {
|
||||||
getBasePath,
|
getBasePath,
|
||||||
getDirection,
|
getDirection,
|
||||||
|
getResumePath,
|
||||||
portfolioContent,
|
portfolioContent,
|
||||||
resumeFile,
|
resumeFile,
|
||||||
sharedProfile,
|
sharedProfile,
|
||||||
@@ -25,6 +26,7 @@ export function HomePage({ language }: { language: Language }) {
|
|||||||
? "لوحة بورتفوليو لمجمع إعلامي ومبنى التلفزيون"
|
? "لوحة بورتفوليو لمجمع إعلامي ومبنى التلفزيون"
|
||||||
: "Portfolio board for Media Complex and TV Building";
|
: "Portfolio board for Media Complex and TV Building";
|
||||||
const basePath = getBasePath(language);
|
const basePath = getBasePath(language);
|
||||||
|
const resumePath = getResumePath(language);
|
||||||
const hasResume = resumeFile.available;
|
const hasResume = resumeFile.available;
|
||||||
const contactCards = [
|
const contactCards = [
|
||||||
{
|
{
|
||||||
@@ -91,7 +93,7 @@ export function HomePage({ language }: { language: Language }) {
|
|||||||
{t.ui.downloadCv}
|
{t.ui.downloadCv}
|
||||||
</Link>
|
</Link>
|
||||||
) : (
|
) : (
|
||||||
<Link href={`${basePath}/resume`} className="button-secondary hero-action-link">
|
<Link href={resumePath} className="button-secondary hero-action-link">
|
||||||
{t.ui.onlineResume}
|
{t.ui.onlineResume}
|
||||||
</Link>
|
</Link>
|
||||||
)}
|
)}
|
||||||
@@ -322,7 +324,7 @@ export function HomePage({ language }: { language: Language }) {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="grid gap-5 sm:grid-cols-2">
|
<div className="grid gap-5 sm:grid-cols-2">
|
||||||
<Link href={`${basePath}/resume`} className="soft-card content-stack-default block">
|
<Link href={resumePath} className="soft-card content-stack-default block">
|
||||||
<p className="eyebrow-note">{t.ui.onlineResume}</p>
|
<p className="eyebrow-note">{t.ui.onlineResume}</p>
|
||||||
<p className="type-card-title display-face text-[var(--color-ink)]">
|
<p className="type-card-title display-face text-[var(--color-ink)]">
|
||||||
{t.ui.viewFullResume}
|
{t.ui.viewFullResume}
|
||||||
|
|||||||
@@ -5,18 +5,15 @@ import { usePathname } from "next/navigation";
|
|||||||
import { portfolioContent, type Language } from "@/data/portfolio";
|
import { portfolioContent, type Language } from "@/data/portfolio";
|
||||||
|
|
||||||
export function LanguageToggle({ language }: { language: Language }) {
|
export function LanguageToggle({ language }: { language: Language }) {
|
||||||
const pathname = usePathname() ?? `/${language}`;
|
const pathname = usePathname() ?? (language === "ar" ? "/ar" : "/");
|
||||||
const nextLanguage = language === "en" ? "ar" : "en";
|
const nextLanguage = language === "en" ? "ar" : "en";
|
||||||
const { languageLabel, languageToggleAriaLabel } = portfolioContent[language].ui;
|
const { languageLabel, languageToggleAriaLabel } = portfolioContent[language].ui;
|
||||||
const segments = pathname.split("/").filter(Boolean);
|
const segments = pathname.split("/").filter(Boolean);
|
||||||
|
const contentSegments = segments[0] === "en" || segments[0] === "ar" ? segments.slice(1) : segments;
|
||||||
if (segments[0] === "en" || segments[0] === "ar") {
|
const nextPath =
|
||||||
segments[0] = nextLanguage;
|
nextLanguage === "ar"
|
||||||
} else {
|
? `/ar${contentSegments.length ? `/${contentSegments.join("/")}` : ""}`
|
||||||
segments.unshift(nextLanguage);
|
: `/${contentSegments.join("/")}` || "/";
|
||||||
}
|
|
||||||
|
|
||||||
const nextPath = `/${segments.join("/")}`;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Link
|
<Link
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ export function Navbar({ language }: { language: Language }) {
|
|||||||
<div className="logo-shell navbar-logo-shell overflow-hidden rounded-[20px] border p-2">
|
<div className="logo-shell navbar-logo-shell overflow-hidden rounded-[20px] border p-2">
|
||||||
<Image
|
<Image
|
||||||
src={sharedProfile.logoImage}
|
src={sharedProfile.logoImage}
|
||||||
alt={language === "ar" ? "شعار غريس بطرس سلمون" : "Grace Butrus Salmoun logo"}
|
alt={language === "ar" ? "شعار غريس بطرس سلمون" : "Grace Salmoun logo"}
|
||||||
width={60}
|
width={60}
|
||||||
height={60}
|
height={60}
|
||||||
className="navbar-logo-image h-[60px] w-[60px] rounded-[14px] object-contain"
|
className="navbar-logo-image h-[60px] w-[60px] rounded-[14px] object-contain"
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import Link from "next/link";
|
|||||||
import { JsonLd } from "@/components/json-ld";
|
import { JsonLd } from "@/components/json-ld";
|
||||||
import { SectionHeading } from "@/components/section-heading";
|
import { SectionHeading } from "@/components/section-heading";
|
||||||
import { SiteShell } from "@/components/site-shell";
|
import { SiteShell } from "@/components/site-shell";
|
||||||
import { portfolioContent, resumeFile, sharedProfile, type Language } from "@/data/portfolio";
|
import { getBasePath, portfolioContent, resumeFile, sharedProfile, type Language } from "@/data/portfolio";
|
||||||
import { getResumeStructuredData } from "@/data/seo";
|
import { getResumeStructuredData } from "@/data/seo";
|
||||||
|
|
||||||
export function ResumePageContent({ language }: { language: Language }) {
|
export function ResumePageContent({ language }: { language: Language }) {
|
||||||
@@ -11,6 +11,7 @@ export function ResumePageContent({ language }: { language: Language }) {
|
|||||||
const address = language === "ar" ? sharedProfile.addressAr : sharedProfile.address;
|
const address = language === "ar" ? sharedProfile.addressAr : sharedProfile.address;
|
||||||
const hasResume = resumeFile.available;
|
const hasResume = resumeFile.available;
|
||||||
const structuredData = getResumeStructuredData(language);
|
const structuredData = getResumeStructuredData(language);
|
||||||
|
const portfolioPath = getBasePath(language);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SiteShell language={language}>
|
<SiteShell language={language}>
|
||||||
@@ -41,7 +42,7 @@ export function ResumePageContent({ language }: { language: Language }) {
|
|||||||
{t.ui.resumeUnavailable}
|
{t.ui.resumeUnavailable}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
<Link href={`/${language}`} className="button-secondary">
|
<Link href={portfolioPath} className="button-secondary">
|
||||||
{t.ui.backToPortfolio}
|
{t.ui.backToPortfolio}
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ export type { Language, Project, AdditionalProject, PortfolioDictionary } from "
|
|||||||
export { sharedProfile, resumeFile, defaultLanguage } from "./portfolio/shared";
|
export { sharedProfile, resumeFile, defaultLanguage } from "./portfolio/shared";
|
||||||
export { englishPortfolioContent } from "./portfolio/en";
|
export { englishPortfolioContent } from "./portfolio/en";
|
||||||
export { arabicPortfolioContent } from "./portfolio/ar";
|
export { arabicPortfolioContent } from "./portfolio/ar";
|
||||||
export { getBasePath, getDirection, getPortfolioContent, isLanguage, languages } from "./portfolio/helpers";
|
export { getBasePath, getDirection, getPortfolioContent, getResumePath, isLanguage, languages } from "./portfolio/helpers";
|
||||||
|
|
||||||
import { englishPortfolioContent } from "./portfolio/en";
|
import { englishPortfolioContent } from "./portfolio/en";
|
||||||
import { arabicPortfolioContent } from "./portfolio/ar";
|
import { arabicPortfolioContent } from "./portfolio/ar";
|
||||||
|
|||||||
@@ -2,9 +2,9 @@ import type { AdditionalProject, PortfolioDictionary, Project } from "./types";
|
|||||||
|
|
||||||
export const englishPortfolioContent = {
|
export const englishPortfolioContent = {
|
||||||
meta: {
|
meta: {
|
||||||
title: "Grace Butrus Salmoun | Architectural Engineer Specialized in Architectural Design",
|
title: "Grace Salmoun | Architectural Engineer and Architecture Portfolio",
|
||||||
description:
|
description:
|
||||||
"An architecture portfolio for Grace Butrus Salmoun, a Damascus-based architectural engineer specialized in architectural design, featuring work in urban rehabilitation, mixed-use towers, hospitality, landscape, shop drawings, and architectural visualization.",
|
"An architecture portfolio for Grace Salmoun, also known as Grace Butrus Salmoun, a Damascus-based architectural engineer specializing in architectural design, urban rehabilitation, landscape, shop drawings, and architectural visualization.",
|
||||||
},
|
},
|
||||||
ui: {
|
ui: {
|
||||||
navAbout: "About",
|
navAbout: "About",
|
||||||
@@ -71,7 +71,7 @@ export const englishPortfolioContent = {
|
|||||||
title:
|
title:
|
||||||
"An architectural engineer who turns ideas into clear drawings and readable presentation boards.",
|
"An architectural engineer who turns ideas into clear drawings and readable presentation boards.",
|
||||||
description:
|
description:
|
||||||
"Grace Butrus Salmoun is a Syrian architect based in Damascus, holding a Master's degree in Architectural Design from Damascus University, with published academic research in 2025 titled \"A Study of the Factors Influencing the Residential Urban Product: Marota City as a Case Study.\" Her portfolio includes towers, hotels, villas, public squares, landscape studies, and shop drawings.",
|
"Grace Salmoun, also known as Grace Butrus Salmoun, is a Syrian architect based in Damascus, holding a Master's degree in Architectural Design from Damascus University, with published academic research in 2025 titled \"A Study of the Factors Influencing the Residential Urban Product: Marota City as a Case Study.\" Her portfolio includes towers, hotels, villas, public squares, landscape studies, and shop drawings.",
|
||||||
paragraphs: [
|
paragraphs: [
|
||||||
"Her work connects technical production with architectural presentation through plans, sections, elevations, analytical drawings, and 3D visualizations.",
|
"Her work connects technical production with architectural presentation through plans, sections, elevations, analytical drawings, and 3D visualizations.",
|
||||||
"The portfolio includes professional and academic work in Damascus, a first-place project for the rehabilitation of Bab Touma Square, remote collaboration with Regal Pool, and teaching support at Damascus University.",
|
"The portfolio includes professional and academic work in Damascus, a first-place project for the rehabilitation of Bab Touma Square, remote collaboration with Regal Pool, and teaching support at Damascus University.",
|
||||||
@@ -333,7 +333,7 @@ export const englishPortfolioContent = {
|
|||||||
onlineResumeDescription:
|
onlineResumeDescription:
|
||||||
"An architectural engineer with a Master's background in architectural design, published academic research in 2025 on the residential urban product in Marota City, teaching support experience, remote design work, and urban rehabilitation achievements.",
|
"An architectural engineer with a Master's background in architectural design, published academic research in 2025 on the residential urban product in Marota City, teaching support experience, remote design work, and urban rehabilitation achievements.",
|
||||||
resumeIntro:
|
resumeIntro:
|
||||||
"Grace Butrus Salmoun is a Damascus-based architectural engineer specialized in architectural design, working in architectural design, urban rehabilitation, landscape concepts, shop drawings, and visual presentation.",
|
"Grace Salmoun is a Damascus-based architectural engineer specialized in architectural design, working in architectural design, urban rehabilitation, landscape concepts, shop drawings, and visual presentation.",
|
||||||
profileParagraph:
|
profileParagraph:
|
||||||
"She combines organized design thinking, technical drawing ability, 3D modeling, and clear presentation skills, alongside academic research experience connected to her master's thesis and a published study on Marota City, with Arabic as a first language and good proficiency in English and French.",
|
"She combines organized design thinking, technical drawing ability, 3D modeling, and clear presentation skills, alongside academic research experience connected to her master's thesis and a published study on Marota City, with Arabic as a first language and good proficiency in English and French.",
|
||||||
experienceDescription:
|
experienceDescription:
|
||||||
@@ -381,5 +381,5 @@ export const englishPortfolioContent = {
|
|||||||
{ value: "3", label: "Languages: Arabic, English, and French" },
|
{ value: "3", label: "Languages: Arabic, English, and French" },
|
||||||
],
|
],
|
||||||
footer:
|
footer:
|
||||||
"Architectural design, urban rehabilitation, landscape studies, shop drawings, and visual presentation by Grace Butrus Salmoun.",
|
"Architectural design, urban rehabilitation, landscape studies, shop drawings, and visual presentation by Grace Salmoun.",
|
||||||
} satisfies PortfolioDictionary;
|
} satisfies PortfolioDictionary;
|
||||||
|
|||||||
@@ -13,7 +13,11 @@ export function getDirection(language: Language) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function getBasePath(language: Language) {
|
export function getBasePath(language: Language) {
|
||||||
return `/${language}`;
|
return language === "ar" ? "/ar" : "/";
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getResumePath(language: Language) {
|
||||||
|
return language === "ar" ? "/ar/resume" : "/resume";
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getPortfolioContent(language: Language): PortfolioDictionary {
|
export function getPortfolioContent(language: Language): PortfolioDictionary {
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
import type { Language } from "./types";
|
import type { Language } from "./types";
|
||||||
|
|
||||||
export const sharedProfile = {
|
export const sharedProfile = {
|
||||||
brandNameEn: "Grace Butrus Salmoun",
|
brandNameEn: "Grace Salmoun",
|
||||||
brandNameAr: "غريس بطرس سلمون",
|
brandNameAr: "غريس بطرس سلمون",
|
||||||
founderNameEn: "Grace Butrus Salmoun",
|
founderNameEn: "Grace Salmoun",
|
||||||
|
fullNameEn: "Grace Butrus Salmoun",
|
||||||
|
alternateNamesEn: ["Grace Butrus Salmoun", "Grace Salamoun"],
|
||||||
founderNameAr: "غريس بطرس سلمون",
|
founderNameAr: "غريس بطرس سلمون",
|
||||||
phone: "+963 993 292 652",
|
phone: "+963 993 292 652",
|
||||||
whatsappHref: "https://wa.me/963993292652",
|
whatsappHref: "https://wa.me/963993292652",
|
||||||
|
|||||||
57
data/seo.ts
57
data/seo.ts
@@ -2,7 +2,15 @@ import type { Metadata } from "next";
|
|||||||
import { englishPortfolioContent, getPortfolioContent, sharedProfile, type Language } from "@/data/portfolio";
|
import { englishPortfolioContent, getPortfolioContent, sharedProfile, type Language } from "@/data/portfolio";
|
||||||
import { absoluteUrl, siteName } from "@/data/site-config";
|
import { absoluteUrl, siteName } from "@/data/site-config";
|
||||||
|
|
||||||
|
const primaryEnglishName = sharedProfile.founderNameEn;
|
||||||
|
const fullEnglishName = sharedProfile.fullNameEn;
|
||||||
|
const englishAlternateNames = sharedProfile.alternateNamesEn;
|
||||||
|
const arabicName = sharedProfile.founderNameAr;
|
||||||
|
|
||||||
const sharedKeywords = [
|
const sharedKeywords = [
|
||||||
|
"Grace Salmoun",
|
||||||
|
"Grace Butrus Salmoun",
|
||||||
|
"Grace Salamoun",
|
||||||
"architecture portfolio",
|
"architecture portfolio",
|
||||||
"architectural engineer",
|
"architectural engineer",
|
||||||
"architectural design",
|
"architectural design",
|
||||||
@@ -26,13 +34,21 @@ function getAlternateLocales(language: Language) {
|
|||||||
return language === "ar" ? ["en_US"] : ["ar_SY"];
|
return language === "ar" ? ["en_US"] : ["ar_SY"];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getHomePath(language: Language) {
|
||||||
|
return language === "ar" ? "/ar" : "/";
|
||||||
|
}
|
||||||
|
|
||||||
|
function getResumePath(language: Language) {
|
||||||
|
return language === "ar" ? "/ar/resume" : "/resume";
|
||||||
|
}
|
||||||
|
|
||||||
function getOgImage(language: Language) {
|
function getOgImage(language: Language) {
|
||||||
return {
|
return {
|
||||||
url: absoluteUrl(sharedProfile.heroImage),
|
url: absoluteUrl(sharedProfile.heroImage),
|
||||||
alt:
|
alt:
|
||||||
language === "ar"
|
language === "ar"
|
||||||
? "معاينة بورتفوليو غريس بطرس سلمون"
|
? "معاينة بورتفوليو غريس بطرس سلمون"
|
||||||
: "Portfolio preview for Grace Butrus Salmoun",
|
: "Portfolio preview for Grace Salmoun",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,16 +71,16 @@ function buildMetadata({
|
|||||||
title,
|
title,
|
||||||
description,
|
description,
|
||||||
keywords: [...sharedKeywords, ...localizedKeywords[language]],
|
keywords: [...sharedKeywords, ...localizedKeywords[language]],
|
||||||
authors: [{ name: sharedProfile.founderNameEn }],
|
authors: [{ name: primaryEnglishName }],
|
||||||
creator: sharedProfile.founderNameEn,
|
creator: primaryEnglishName,
|
||||||
publisher: sharedProfile.founderNameEn,
|
publisher: primaryEnglishName,
|
||||||
category: "architecture portfolio",
|
category: "architecture portfolio",
|
||||||
alternates: {
|
alternates: {
|
||||||
canonical: canonicalPath,
|
canonical: canonicalPath,
|
||||||
languages: {
|
languages: {
|
||||||
en: canonicalPath.includes("/resume") ? "/en/resume" : "/en",
|
en: canonicalPath.includes("/resume") ? "/resume" : "/",
|
||||||
ar: canonicalPath.includes("/resume") ? "/ar/resume" : "/ar",
|
ar: canonicalPath.includes("/resume") ? "/ar/resume" : "/ar",
|
||||||
"x-default": "/en",
|
"x-default": "/",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
robots: {
|
robots: {
|
||||||
@@ -106,9 +122,9 @@ export function getDefaultSeoMetadata(): Metadata {
|
|||||||
title,
|
title,
|
||||||
description,
|
description,
|
||||||
applicationName: siteName,
|
applicationName: siteName,
|
||||||
authors: [{ name: sharedProfile.founderNameEn }],
|
authors: [{ name: primaryEnglishName }],
|
||||||
creator: sharedProfile.founderNameEn,
|
creator: primaryEnglishName,
|
||||||
publisher: sharedProfile.founderNameEn,
|
publisher: primaryEnglishName,
|
||||||
keywords: [...sharedKeywords, ...localizedKeywords.en],
|
keywords: [...sharedKeywords, ...localizedKeywords.en],
|
||||||
category: "architecture portfolio",
|
category: "architecture portfolio",
|
||||||
referrer: "origin-when-cross-origin",
|
referrer: "origin-when-cross-origin",
|
||||||
@@ -126,7 +142,7 @@ export function getDefaultSeoMetadata(): Metadata {
|
|||||||
openGraph: {
|
openGraph: {
|
||||||
title,
|
title,
|
||||||
description,
|
description,
|
||||||
url: absoluteUrl("/en"),
|
url: absoluteUrl("/"),
|
||||||
siteName,
|
siteName,
|
||||||
locale: "en_US",
|
locale: "en_US",
|
||||||
alternateLocale: ["ar_SY"],
|
alternateLocale: ["ar_SY"],
|
||||||
@@ -149,7 +165,7 @@ export function getHomeMetadata(language: Language): Metadata {
|
|||||||
language,
|
language,
|
||||||
title: t.meta.title,
|
title: t.meta.title,
|
||||||
description: t.meta.description,
|
description: t.meta.description,
|
||||||
canonicalPath: `/${language}`,
|
canonicalPath: getHomePath(language),
|
||||||
pageType: "website",
|
pageType: "website",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -162,7 +178,7 @@ export function getResumeMetadata(language: Language): Metadata {
|
|||||||
language,
|
language,
|
||||||
title,
|
title,
|
||||||
description: t.resume.description,
|
description: t.resume.description,
|
||||||
canonicalPath: `/${language}/resume`,
|
canonicalPath: getResumePath(language),
|
||||||
pageType: "profile",
|
pageType: "profile",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -177,6 +193,7 @@ export function getHomeStructuredData(language: Language) {
|
|||||||
"@context": "https://schema.org",
|
"@context": "https://schema.org",
|
||||||
"@type": "WebSite",
|
"@type": "WebSite",
|
||||||
name: siteName,
|
name: siteName,
|
||||||
|
alternateName: [`${fullEnglishName} Portfolio`, "Grace Salamoun Portfolio"],
|
||||||
url: absoluteUrl("/"),
|
url: absoluteUrl("/"),
|
||||||
inLanguage: ["en", "ar"],
|
inLanguage: ["en", "ar"],
|
||||||
},
|
},
|
||||||
@@ -184,7 +201,11 @@ export function getHomeStructuredData(language: Language) {
|
|||||||
"@context": "https://schema.org",
|
"@context": "https://schema.org",
|
||||||
"@type": "Person",
|
"@type": "Person",
|
||||||
name,
|
name,
|
||||||
url: absoluteUrl(`/${language}`),
|
givenName: "Grace",
|
||||||
|
additionalName: "Butrus",
|
||||||
|
familyName: "Salmoun",
|
||||||
|
alternateName: language === "ar" ? [primaryEnglishName, fullEnglishName, ...englishAlternateNames] : [fullEnglishName, arabicName, ...englishAlternateNames],
|
||||||
|
url: absoluteUrl(getHomePath(language)),
|
||||||
image: absoluteUrl(sharedProfile.heroImage),
|
image: absoluteUrl(sharedProfile.heroImage),
|
||||||
jobTitle: t.ui.architectureEngineer,
|
jobTitle: t.ui.architectureEngineer,
|
||||||
description: t.meta.description,
|
description: t.meta.description,
|
||||||
@@ -203,7 +224,7 @@ export function getHomeStructuredData(language: Language) {
|
|||||||
"@type": "CollectionPage",
|
"@type": "CollectionPage",
|
||||||
name: t.meta.title,
|
name: t.meta.title,
|
||||||
description: t.meta.description,
|
description: t.meta.description,
|
||||||
url: absoluteUrl(`/${language}`),
|
url: absoluteUrl(getHomePath(language)),
|
||||||
inLanguage: language,
|
inLanguage: language,
|
||||||
isPartOf: {
|
isPartOf: {
|
||||||
"@type": "WebSite",
|
"@type": "WebSite",
|
||||||
@@ -228,7 +249,11 @@ export function getResumeStructuredData(language: Language) {
|
|||||||
"@context": "https://schema.org",
|
"@context": "https://schema.org",
|
||||||
"@type": "Person",
|
"@type": "Person",
|
||||||
name,
|
name,
|
||||||
url: absoluteUrl(`/${language}`),
|
givenName: "Grace",
|
||||||
|
additionalName: "Butrus",
|
||||||
|
familyName: "Salmoun",
|
||||||
|
alternateName: language === "ar" ? [primaryEnglishName, fullEnglishName, ...englishAlternateNames] : [fullEnglishName, arabicName, ...englishAlternateNames],
|
||||||
|
url: absoluteUrl(getHomePath(language)),
|
||||||
email: sharedProfile.email,
|
email: sharedProfile.email,
|
||||||
telephone: sharedProfile.phone,
|
telephone: sharedProfile.phone,
|
||||||
image: absoluteUrl(sharedProfile.heroImage),
|
image: absoluteUrl(sharedProfile.heroImage),
|
||||||
@@ -240,7 +265,7 @@ export function getResumeStructuredData(language: Language) {
|
|||||||
"@type": "ProfilePage",
|
"@type": "ProfilePage",
|
||||||
name: title,
|
name: title,
|
||||||
description: t.resume.description,
|
description: t.resume.description,
|
||||||
url: absoluteUrl(`/${language}/resume`),
|
url: absoluteUrl(getResumePath(language)),
|
||||||
inLanguage: language,
|
inLanguage: language,
|
||||||
isPartOf: {
|
isPartOf: {
|
||||||
"@type": "WebSite",
|
"@type": "WebSite",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
const FALLBACK_SITE_URL = "https://grace-salamoun-architect.vercel.app";
|
const FALLBACK_SITE_URL = "https://grace-salamoun-architect.vercel.app";
|
||||||
|
|
||||||
export const siteName = "Grace Butrus Salmoun Portfolio";
|
export const siteName = "Grace Salmoun Portfolio";
|
||||||
export const siteUrl = (process.env.NEXT_PUBLIC_SITE_URL ?? FALLBACK_SITE_URL).replace(/\/+$/, "");
|
export const siteUrl = (process.env.NEXT_PUBLIC_SITE_URL ?? FALLBACK_SITE_URL).replace(/\/+$/, "");
|
||||||
|
|
||||||
export function absoluteUrl(path = "/") {
|
export function absoluteUrl(path = "/") {
|
||||||
|
|||||||
المرجع في مشكلة جديدة
حظر مستخدم