diff --git a/app/[lang]/page.tsx b/app/[lang]/page.tsx index 57a96a4..aae8ae6 100644 --- a/app/[lang]/page.tsx +++ b/app/[lang]/page.tsx @@ -1,5 +1,5 @@ import type { Metadata } from "next"; -import { notFound } from "next/navigation"; +import { notFound, permanentRedirect } from "next/navigation"; import { HomePage } from "@/components/home-page"; import { isLanguage, languages, type Language } from "@/data/portfolio"; import { getHomeMetadata } from "@/data/seo"; @@ -21,5 +21,9 @@ export default function LocalizedHomePage({ params }: { params: { lang: string } notFound(); } + if (params.lang === "en") { + permanentRedirect("/"); + } + return ; } diff --git a/app/[lang]/resume/page.tsx b/app/[lang]/resume/page.tsx index 69d8ab1..371b3f9 100644 --- a/app/[lang]/resume/page.tsx +++ b/app/[lang]/resume/page.tsx @@ -1,5 +1,5 @@ import type { Metadata } from "next"; -import { notFound } from "next/navigation"; +import { notFound, permanentRedirect } from "next/navigation"; import { ResumePageContent } from "@/components/resume-page-content"; import { isLanguage, languages, type Language } from "@/data/portfolio"; import { getResumeMetadata } from "@/data/seo"; @@ -21,5 +21,9 @@ export default function LocalizedResumePage({ params }: { params: { lang: string notFound(); } + if (params.lang === "en") { + permanentRedirect("/resume"); + } + return ; } diff --git a/app/page.tsx b/app/page.tsx index 77d15e3..f741494 100644 --- a/app/page.tsx +++ b/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() { - redirect("/en"); + return ; } diff --git a/app/resume/page.tsx b/app/resume/page.tsx index 873bd10..10bbb23 100644 --- a/app/resume/page.tsx +++ b/app/resume/page.tsx @@ -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() { - redirect("/en/resume"); + return ; } diff --git a/app/sitemap.ts b/app/sitemap.ts index a6531c3..cd84fef 100644 --- a/app/sitemap.ts +++ b/app/sitemap.ts @@ -6,7 +6,7 @@ export default function sitemap(): MetadataRoute.Sitemap { return [ { - url: absoluteUrl("/en"), + url: absoluteUrl("/"), lastModified, changeFrequency: "monthly", priority: 1, @@ -18,7 +18,7 @@ export default function sitemap(): MetadataRoute.Sitemap { priority: 1, }, { - url: absoluteUrl("/en/resume"), + url: absoluteUrl("/resume"), lastModified, changeFrequency: "monthly", priority: 0.8, diff --git a/components/home-page.tsx b/components/home-page.tsx index ff41700..5d0b2d2 100644 --- a/components/home-page.tsx +++ b/components/home-page.tsx @@ -7,6 +7,7 @@ import { SiteShell } from "@/components/site-shell"; import { getBasePath, getDirection, + getResumePath, portfolioContent, resumeFile, sharedProfile, @@ -25,6 +26,7 @@ export function HomePage({ language }: { language: Language }) { ? "لوحة بورتفوليو لمجمع إعلامي ومبنى التلفزيون" : "Portfolio board for Media Complex and TV Building"; const basePath = getBasePath(language); + const resumePath = getResumePath(language); const hasResume = resumeFile.available; const contactCards = [ { @@ -91,7 +93,7 @@ export function HomePage({ language }: { language: Language }) { {t.ui.downloadCv} ) : ( - + {t.ui.onlineResume} )} @@ -322,7 +324,7 @@ export function HomePage({ language }: { language: Language }) {
- +

{t.ui.onlineResume}

{t.ui.viewFullResume} diff --git a/components/language-toggle.tsx b/components/language-toggle.tsx index c2bdd91..68ba52a 100644 --- a/components/language-toggle.tsx +++ b/components/language-toggle.tsx @@ -5,18 +5,15 @@ import { usePathname } from "next/navigation"; import { portfolioContent, type Language } from "@/data/portfolio"; export function LanguageToggle({ language }: { language: Language }) { - const pathname = usePathname() ?? `/${language}`; + const pathname = usePathname() ?? (language === "ar" ? "/ar" : "/"); const nextLanguage = language === "en" ? "ar" : "en"; const { languageLabel, languageToggleAriaLabel } = portfolioContent[language].ui; const segments = pathname.split("/").filter(Boolean); - - if (segments[0] === "en" || segments[0] === "ar") { - segments[0] = nextLanguage; - } else { - segments.unshift(nextLanguage); - } - - const nextPath = `/${segments.join("/")}`; + const contentSegments = segments[0] === "en" || segments[0] === "ar" ? segments.slice(1) : segments; + const nextPath = + nextLanguage === "ar" + ? `/ar${contentSegments.length ? `/${contentSegments.join("/")}` : ""}` + : `/${contentSegments.join("/")}` || "/"; return ( {language @@ -41,7 +42,7 @@ export function ResumePageContent({ language }: { language: Language }) { {t.ui.resumeUnavailable}

)} - + {t.ui.backToPortfolio}
diff --git a/data/portfolio.ts b/data/portfolio.ts index 66e8c8c..18c2be2 100644 --- a/data/portfolio.ts +++ b/data/portfolio.ts @@ -2,7 +2,7 @@ export type { Language, Project, AdditionalProject, PortfolioDictionary } from " export { sharedProfile, resumeFile, defaultLanguage } from "./portfolio/shared"; export { englishPortfolioContent } from "./portfolio/en"; 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 { arabicPortfolioContent } from "./portfolio/ar"; diff --git a/data/portfolio/en.ts b/data/portfolio/en.ts index 67f5d1c..f12b3aa 100644 --- a/data/portfolio/en.ts +++ b/data/portfolio/en.ts @@ -2,9 +2,9 @@ import type { AdditionalProject, PortfolioDictionary, Project } from "./types"; export const englishPortfolioContent = { meta: { - title: "Grace Butrus Salmoun | Architectural Engineer Specialized in Architectural Design", + title: "Grace Salmoun | Architectural Engineer and Architecture Portfolio", 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: { navAbout: "About", @@ -71,7 +71,7 @@ export const englishPortfolioContent = { title: "An architectural engineer who turns ideas into clear drawings and readable presentation boards.", 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: [ "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.", @@ -333,7 +333,7 @@ export const englishPortfolioContent = { 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.", 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: "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: @@ -381,5 +381,5 @@ export const englishPortfolioContent = { { value: "3", label: "Languages: Arabic, English, and French" }, ], 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; diff --git a/data/portfolio/helpers.ts b/data/portfolio/helpers.ts index 6b589c2..3b0f18f 100644 --- a/data/portfolio/helpers.ts +++ b/data/portfolio/helpers.ts @@ -13,7 +13,11 @@ export function getDirection(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 { diff --git a/data/portfolio/shared.ts b/data/portfolio/shared.ts index a91e58c..4f4d8a0 100644 --- a/data/portfolio/shared.ts +++ b/data/portfolio/shared.ts @@ -1,9 +1,11 @@ import type { Language } from "./types"; export const sharedProfile = { - brandNameEn: "Grace Butrus Salmoun", + brandNameEn: "Grace Salmoun", brandNameAr: "غريس بطرس سلمون", - founderNameEn: "Grace Butrus Salmoun", + founderNameEn: "Grace Salmoun", + fullNameEn: "Grace Butrus Salmoun", + alternateNamesEn: ["Grace Butrus Salmoun", "Grace Salamoun"], founderNameAr: "غريس بطرس سلمون", phone: "+963 993 292 652", whatsappHref: "https://wa.me/963993292652", diff --git a/data/seo.ts b/data/seo.ts index 0f95624..cdba52f 100644 --- a/data/seo.ts +++ b/data/seo.ts @@ -2,7 +2,15 @@ import type { Metadata } from "next"; import { englishPortfolioContent, getPortfolioContent, sharedProfile, type Language } from "@/data/portfolio"; 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 = [ + "Grace Salmoun", + "Grace Butrus Salmoun", + "Grace Salamoun", "architecture portfolio", "architectural engineer", "architectural design", @@ -26,13 +34,21 @@ function getAlternateLocales(language: Language) { 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) { return { url: absoluteUrl(sharedProfile.heroImage), alt: language === "ar" ? "معاينة بورتفوليو غريس بطرس سلمون" - : "Portfolio preview for Grace Butrus Salmoun", + : "Portfolio preview for Grace Salmoun", }; } @@ -55,16 +71,16 @@ function buildMetadata({ title, description, keywords: [...sharedKeywords, ...localizedKeywords[language]], - authors: [{ name: sharedProfile.founderNameEn }], - creator: sharedProfile.founderNameEn, - publisher: sharedProfile.founderNameEn, + authors: [{ name: primaryEnglishName }], + creator: primaryEnglishName, + publisher: primaryEnglishName, category: "architecture portfolio", alternates: { canonical: canonicalPath, languages: { - en: canonicalPath.includes("/resume") ? "/en/resume" : "/en", + en: canonicalPath.includes("/resume") ? "/resume" : "/", ar: canonicalPath.includes("/resume") ? "/ar/resume" : "/ar", - "x-default": "/en", + "x-default": "/", }, }, robots: { @@ -106,9 +122,9 @@ export function getDefaultSeoMetadata(): Metadata { title, description, applicationName: siteName, - authors: [{ name: sharedProfile.founderNameEn }], - creator: sharedProfile.founderNameEn, - publisher: sharedProfile.founderNameEn, + authors: [{ name: primaryEnglishName }], + creator: primaryEnglishName, + publisher: primaryEnglishName, keywords: [...sharedKeywords, ...localizedKeywords.en], category: "architecture portfolio", referrer: "origin-when-cross-origin", @@ -126,7 +142,7 @@ export function getDefaultSeoMetadata(): Metadata { openGraph: { title, description, - url: absoluteUrl("/en"), + url: absoluteUrl("/"), siteName, locale: "en_US", alternateLocale: ["ar_SY"], @@ -149,7 +165,7 @@ export function getHomeMetadata(language: Language): Metadata { language, title: t.meta.title, description: t.meta.description, - canonicalPath: `/${language}`, + canonicalPath: getHomePath(language), pageType: "website", }); } @@ -162,7 +178,7 @@ export function getResumeMetadata(language: Language): Metadata { language, title, description: t.resume.description, - canonicalPath: `/${language}/resume`, + canonicalPath: getResumePath(language), pageType: "profile", }); } @@ -177,6 +193,7 @@ export function getHomeStructuredData(language: Language) { "@context": "https://schema.org", "@type": "WebSite", name: siteName, + alternateName: [`${fullEnglishName} Portfolio`, "Grace Salamoun Portfolio"], url: absoluteUrl("/"), inLanguage: ["en", "ar"], }, @@ -184,7 +201,11 @@ export function getHomeStructuredData(language: Language) { "@context": "https://schema.org", "@type": "Person", 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), jobTitle: t.ui.architectureEngineer, description: t.meta.description, @@ -203,7 +224,7 @@ export function getHomeStructuredData(language: Language) { "@type": "CollectionPage", name: t.meta.title, description: t.meta.description, - url: absoluteUrl(`/${language}`), + url: absoluteUrl(getHomePath(language)), inLanguage: language, isPartOf: { "@type": "WebSite", @@ -228,7 +249,11 @@ export function getResumeStructuredData(language: Language) { "@context": "https://schema.org", "@type": "Person", 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, telephone: sharedProfile.phone, image: absoluteUrl(sharedProfile.heroImage), @@ -240,7 +265,7 @@ export function getResumeStructuredData(language: Language) { "@type": "ProfilePage", name: title, description: t.resume.description, - url: absoluteUrl(`/${language}/resume`), + url: absoluteUrl(getResumePath(language)), inLanguage: language, isPartOf: { "@type": "WebSite", diff --git a/data/site-config.ts b/data/site-config.ts index 6d7470e..35c2e71 100644 --- a/data/site-config.ts +++ b/data/site-config.ts @@ -1,6 +1,6 @@ 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 function absoluteUrl(path = "/") {