@@ -11,6 +11,87 @@ import {
1111 getLearningOutcomes ,
1212} from '../../utils/seo' ;
1313
14+ const OG_LOCALE_MAP = {
15+ en : 'en_US' ,
16+ es : 'es_ES' ,
17+ hi : 'hi_IN' ,
18+ fr : 'fr_FR' ,
19+ de : 'de_DE' ,
20+ zh : 'zh_CN' ,
21+ bn : 'bn_BD' ,
22+ ja : 'ja_JP' ,
23+ } ;
24+
25+ const HREFLANG_REGION_ALIASES = {
26+ en : [ 'en-US' , 'en-GB' , 'en-IN' ] ,
27+ es : [ 'es-ES' , 'es-MX' , 'es-AR' ] ,
28+ hi : [ 'hi-IN' ] ,
29+ fr : [ 'fr-FR' , 'fr-CA' ] ,
30+ de : [ 'de-DE' , 'de-AT' ] ,
31+ zh : [ 'zh-CN' , 'zh-TW' , 'zh-HK' ] ,
32+ bn : [ 'bn-BD' , 'bn-IN' ] ,
33+ ja : [ 'ja-JP' ] ,
34+ } ;
35+
36+ const ensureMinimumDescriptionLength = (
37+ description ,
38+ language ,
39+ contextLabel = 'page'
40+ ) => {
41+ if ( ! description ) return description ;
42+ const MIN_LENGTH = 150 ;
43+ const MAX_LENGTH = 165 ;
44+ if ( description . length >= MIN_LENGTH ) {
45+ return description . length > MAX_LENGTH
46+ ? `${ description . slice ( 0 , MAX_LENGTH - 1 ) . trimEnd ( ) } …`
47+ : description ;
48+ }
49+
50+ const EXPANSION_BY_LANGUAGE = {
51+ en :
52+ contextLabel === 'homepage'
53+ ? ' Explore sorting animations, compare runtime behavior, and strengthen DSA interview preparation.'
54+ : ` Explore this ${ contextLabel } with interactive visuals and interview-focused DSA guidance.` ,
55+ es :
56+ contextLabel === 'homepage'
57+ ? ' Explora animaciones de ordenamiento, compara rendimiento y fortalece tu preparación para entrevistas DSA.'
58+ : ' Explora esta página con visualización interactiva y guía práctica para entrevistas DSA.' ,
59+ hi :
60+ contextLabel === 'homepage'
61+ ? ' सॉर्टिंग एनीमेशन देखें, प्रदर्शन की तुलना करें और DSA इंटरव्यू तैयारी मजबूत करें।'
62+ : ' इस पेज को इंटरएक्टिव विजुअल्स और इंटरव्यू-केंद्रित DSA मार्गदर्शन के साथ समझें।' ,
63+ fr :
64+ contextLabel === 'homepage'
65+ ? ' Explorez les animations de tri, comparez les performances et renforcez votre préparation DSA.'
66+ : ' Explorez cette page avec des visuels interactifs et des conseils DSA orientés entretien.' ,
67+ de :
68+ contextLabel === 'homepage'
69+ ? ' Entdecke Sortieranimationen, vergleiche Laufzeiten und verbessere deine DSA-Interviewvorbereitung.'
70+ : ' Entdecke diese Seite mit interaktiven Visualisierungen und DSA-Interviewhilfe.' ,
71+ zh :
72+ contextLabel === 'homepage'
73+ ? ' 通过交互式排序动画对比性能表现,系统提升你的 DSA 面试准备效率。'
74+ : ' 通过交互式可视化学习本页面内容,并获得面试导向的 DSA 学习指引。' ,
75+ bn :
76+ contextLabel === 'homepage'
77+ ? ' ইন্টারঅ্যাকটিভ সোর্টিং অ্যানিমেশন দেখে পারফরম্যান্স তুলনা করুন এবং DSA ইন্টারভিউ প্রস্তুতি বাড়ান।'
78+ : ' ইন্টারঅ্যাকটিভ ভিজুয়াল ও ইন্টারভিউ-কেন্দ্রিক DSA গাইডসহ এই পেজটি অন্বেষণ করুন।' ,
79+ ja :
80+ contextLabel === 'homepage'
81+ ? ' ソートのアニメーションで挙動と性能を比較し、DSA面接対策を効果的に進められます。'
82+ : ' このページをインタラクティブ表示で学び、面接向けDSA理解を深められます。' ,
83+ } ;
84+
85+ const expansion = EXPANSION_BY_LANGUAGE [ language ] || EXPANSION_BY_LANGUAGE . en ;
86+ const needed = MIN_LENGTH - description . length ;
87+ const safeAppend = expansion . slice ( 0 , Math . max ( needed + 8 , 0 ) ) ;
88+ const merged = `${ description } ${ safeAppend } ` . trim ( ) ;
89+
90+ return merged . length > MAX_LENGTH
91+ ? `${ merged . slice ( 0 , MAX_LENGTH - 1 ) . trimEnd ( ) } …`
92+ : merged ;
93+ } ;
94+
1495// Generate metadata dynamically based on the route
1596export async function generateMetadata ( { params, searchParams } ) {
1697 // Await params as they are now a Promise in Next.js 16
@@ -74,6 +155,12 @@ export async function generateMetadata({ params, searchParams }) {
74155 add ( lang , lang ) ;
75156 } ) ;
76157
158+ // Add regional aliases that map to the same language URL.
159+ supportedLanguages . forEach ( lang => {
160+ const aliases = HREFLANG_REGION_ALIASES [ lang ] || [ ] ;
161+ aliases . forEach ( alias => add ( alias , lang ) ) ;
162+ } ) ;
163+
77164 // Add x-default pointing to English (canonical)
78165 alternates [ 'x-default' ] = `https://www.sortvision.com${ basePath } ` ;
79166
@@ -85,6 +172,23 @@ export async function generateMetadata({ params, searchParams }) {
85172 const algorithm = slug [ 2 ] ;
86173 const tab = slug [ 1 ] || 'config' ;
87174 const metaTags = getAlgorithmMetaTags ( algorithm , language ) ;
175+ const tabTitleMap = {
176+ config : 'Configuration' ,
177+ details : 'Step-by-step Details' ,
178+ metrics : 'Performance Metrics' ,
179+ } ;
180+ const tabTitleSuffix = tabTitleMap [ tab ] || 'Algorithm View' ;
181+ const tabDescriptionMap = {
182+ config :
183+ 'Configure inputs, speed, and array size to explore algorithm behavior interactively.' ,
184+ details :
185+ 'Follow each comparison and swap with step-by-step algorithm execution insights.' ,
186+ metrics :
187+ 'Analyze time complexity, operation counts, and runtime performance characteristics.' ,
188+ } ;
189+ const tabDescriptionSuffix =
190+ tabDescriptionMap [ tab ] ||
191+ 'Explore this algorithm view with interactive educational controls.' ;
88192
89193 const basePath = `/algorithms/${ tab } /${ algorithm } ` ;
90194 const currentUrl = language === 'en' ? basePath : `/${ language } ${ basePath } ` ;
@@ -99,12 +203,16 @@ export async function generateMetadata({ params, searchParams }) {
99203 : `/${ language } ${ canonicalBasePath } ` ;
100204
101205 return {
102- title : metaTags . title ,
103- description : metaTags . description ,
206+ title : `${ metaTags . title } | ${ tabTitleSuffix } ` ,
207+ description : ensureMinimumDescriptionLength (
208+ `${ metaTags . description } ${ tabDescriptionSuffix } ` ,
209+ language ,
210+ `${ algorithm } algorithm`
211+ ) ,
104212 keywords : metaTags . keywords ,
105213 authors : [ { name : 'Prabal Patra' } ] ,
106214 robots :
107- 'index, follow, noarchive, max-image-preview:large, max-snippet:-1, max-video-preview:-1' ,
215+ 'index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1' ,
108216 openGraph : {
109217 type : 'website' ,
110218 url : `https://www.sortvision.com${ currentUrl } ` ,
@@ -119,18 +227,7 @@ export async function generateMetadata({ params, searchParams }) {
119227 } ,
120228 ] ,
121229 siteName : 'SortVision' ,
122- locale :
123- language === 'es'
124- ? 'es_ES'
125- : language === 'hi'
126- ? 'hi_IN'
127- : language === 'fr'
128- ? 'fr_FR'
129- : language === 'de'
130- ? 'de_DE'
131- : language === 'zh'
132- ? 'zh_CN'
133- : 'en_US' ,
230+ locale : OG_LOCALE_MAP [ language ] || 'en_US' ,
134231 } ,
135232 twitter : {
136233 card : 'summary_large_image' ,
@@ -231,19 +328,45 @@ export async function generateMetadata({ params, searchParams }) {
231328 } else {
232329 metaTags = getContributionsMetaTags ( language ) ;
233330 }
331+ const sectionTitleMap = {
332+ overview : 'Overview' ,
333+ guide : 'Guide' ,
334+ ssoc : 'Leaderboard' ,
335+ } ;
336+ const sectionTitleSuffix = sectionTitleMap [ section ] || 'Contributions' ;
337+ const languageTitleSuffix =
338+ language === 'en' ? '' : ` (${ language . toUpperCase ( ) } )` ;
339+ const sectionDescriptionMap = {
340+ overview :
341+ 'Browse contributor profiles, pull requests, issues, and overall community impact.' ,
342+ guide :
343+ 'Learn contribution workflow, setup steps, standards, and PR process for SortVision.' ,
344+ ssoc : 'Track SSOC leaderboard standings, points, and contributor activity across the program.' ,
345+ } ;
346+ const sectionDescriptionSuffix =
347+ sectionDescriptionMap [ section ] ||
348+ 'Explore this contribution section for project and community insights.' ;
349+ const languageDescriptionSuffix =
350+ language === 'en'
351+ ? ''
352+ : ` Localized for ${ language . toUpperCase ( ) } users.` ;
234353
235354 const basePath = contributorId
236355 ? `/contributions/${ section } /${ contributorId } `
237356 : `/contributions/${ section } ` ;
238357 const currentUrl = language === 'en' ? basePath : `/${ language } ${ basePath } ` ;
239358
240359 return {
241- title : metaTags . title ,
242- description : metaTags . description ,
360+ title : `${ metaTags . title } | ${ sectionTitleSuffix } ${ languageTitleSuffix } ` ,
361+ description : ensureMinimumDescriptionLength (
362+ `${ metaTags . description } ${ sectionDescriptionSuffix } ${ languageDescriptionSuffix } ` ,
363+ language ,
364+ `${ section } contributions`
365+ ) ,
243366 keywords : metaTags . keywords ,
244367 authors : [ { name : 'Prabal Patra' } ] ,
245368 robots :
246- 'index, follow, noarchive, max-image-preview:large, max-snippet:-1, max-video-preview:-1' ,
369+ 'index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1' ,
247370 openGraph : {
248371 type : 'website' ,
249372 url : `https://www.sortvision.com${ currentUrl } ` ,
@@ -258,18 +381,7 @@ export async function generateMetadata({ params, searchParams }) {
258381 } ,
259382 ] ,
260383 siteName : 'SortVision' ,
261- locale :
262- language === 'es'
263- ? 'es_ES'
264- : language === 'hi'
265- ? 'hi_IN'
266- : language === 'fr'
267- ? 'fr_FR'
268- : language === 'de'
269- ? 'de_DE'
270- : language === 'zh'
271- ? 'zh_CN'
272- : 'en_US' ,
384+ locale : OG_LOCALE_MAP [ language ] || 'en_US' ,
273385 } ,
274386 twitter : {
275387 card : 'summary_large_image' ,
@@ -314,11 +426,15 @@ export async function generateMetadata({ params, searchParams }) {
314426
315427 return {
316428 title : metaTags . title ,
317- description : metaTags . description ,
429+ description : ensureMinimumDescriptionLength (
430+ metaTags . description ,
431+ language ,
432+ 'homepage'
433+ ) ,
318434 keywords : metaTags . keywords ,
319435 authors : [ { name : 'Prabal Patra' } ] ,
320436 robots :
321- 'index, follow, noarchive, max-image-preview:large, max-snippet:-1, max-video-preview:-1' ,
437+ 'index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1' ,
322438 openGraph : {
323439 type : 'website' ,
324440 url : `https://www.sortvision.com${ currentUrl } ` ,
@@ -333,18 +449,7 @@ export async function generateMetadata({ params, searchParams }) {
333449 } ,
334450 ] ,
335451 siteName : 'SortVision' ,
336- locale :
337- language === 'es'
338- ? 'es_ES'
339- : language === 'hi'
340- ? 'hi_IN'
341- : language === 'fr'
342- ? 'fr_FR'
343- : language === 'de'
344- ? 'de_DE'
345- : language === 'zh'
346- ? 'zh_CN'
347- : 'en_US' ,
452+ locale : OG_LOCALE_MAP [ language ] || 'en_US' ,
348453 } ,
349454 twitter : {
350455 card : 'summary_large_image' ,
0 commit comments