From 92ca0af3c785c7837d7c1dd86e829ccb7a3a273e Mon Sep 17 00:00:00 2001
From: Your Name <119736744+aborayan2022@users.noreply.github.com>
Date: Fri, 3 Apr 2026 02:29:14 +0200
Subject: [PATCH] feat: add comparison page functionality and related routes
- Added a new route for comparison pages in routes.ts.
- Introduced a TOOL_WORKFLOWS object in seoData.ts to define tool usage sequences.
- Updated internal link generation to include workflow slugs.
- Added Arabic, English, and French translations for comparison features and FAQs in respective i18n files.
- Implemented the ComparisonPage component to display feature comparisons, advantages, verdicts, and related tools.
- Enhanced sitemap generation script to include comparison pages.
---
frontend/scripts/generate-seo-assets.mjs | 18 ++
frontend/src/App.tsx | 2 +
frontend/src/components/layout/Footer.tsx | 9 +-
frontend/src/config/comparisonData.ts | 145 +++++++++++
frontend/src/config/routes.ts | 1 +
frontend/src/config/seoData.ts | 29 ++-
frontend/src/i18n/ar.json | 128 ++++++++++
frontend/src/i18n/en.json | 128 ++++++++++
frontend/src/i18n/fr.json | 128 ++++++++++
frontend/src/pages/ComparisonPage.tsx | 278 ++++++++++++++++++++++
scripts/generate_sitemap.py | 21 ++
11 files changed, 885 insertions(+), 2 deletions(-)
create mode 100644 frontend/src/config/comparisonData.ts
create mode 100644 frontend/src/pages/ComparisonPage.tsx
diff --git a/frontend/scripts/generate-seo-assets.mjs b/frontend/scripts/generate-seo-assets.mjs
index 89af579..a1bb2ec 100644
--- a/frontend/scripts/generate-seo-assets.mjs
+++ b/frontend/scripts/generate-seo-assets.mjs
@@ -151,6 +151,22 @@ const toolEntries = dedupeEntries(
})),
).map((entry) => makeUrlTag(entry));
+const comparisonSlugs = [
+ 'compress-pdf-vs-ilovepdf',
+ 'merge-pdf-vs-smallpdf',
+ 'pdf-to-word-vs-adobe-acrobat',
+ 'compress-image-vs-tinypng',
+ 'ocr-vs-adobe-scan',
+];
+
+const comparisonEntries = dedupeEntries(
+ comparisonSlugs.map((slug) => ({
+ loc: `${siteOrigin}/compare/${slug}`,
+ changefreq: 'monthly',
+ priority: '0.7',
+ })),
+).map((entry) => makeUrlTag(entry));
+
const seoEntries = dedupeEntries([
...seoConfig.toolPageSeeds.flatMap((page) => ([
{ loc: `${siteOrigin}/${page.slug}`, changefreq: 'weekly', priority: '0.88' },
@@ -167,6 +183,7 @@ const sitemapIndex = makeSitemapIndex([
{ loc: `${siteOrigin}/sitemaps/blog.xml` },
{ loc: `${siteOrigin}/sitemaps/tools.xml` },
{ loc: `${siteOrigin}/sitemaps/seo.xml` },
+ { loc: `${siteOrigin}/sitemaps/comparisons.xml` },
]);
const robots = [
@@ -192,6 +209,7 @@ await writeFile(path.join(sitemapDir, 'static.xml'), makeSitemapUrlSet(staticEnt
await writeFile(path.join(sitemapDir, 'blog.xml'), makeSitemapUrlSet(blogEntries), 'utf8');
await writeFile(path.join(sitemapDir, 'tools.xml'), makeSitemapUrlSet(toolEntries), 'utf8');
await writeFile(path.join(sitemapDir, 'seo.xml'), makeSitemapUrlSet(seoEntries), 'utf8');
+await writeFile(path.join(sitemapDir, 'comparisons.xml'), makeSitemapUrlSet(comparisonEntries), 'utf8');
await writeFile(path.join(publicDir, 'robots.txt'), robots, 'utf8');
console.log(`Generated SEO assets for ${siteOrigin}`);
diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx
index e43b9a2..5d66e68 100644
--- a/frontend/src/App.tsx
+++ b/frontend/src/App.tsx
@@ -31,6 +31,7 @@ const DevelopersPage = lazy(() => import('@/pages/DevelopersPage'));
const AllToolsPage = lazy(() => import('@/pages/AllToolsPage'));
const InternalAdminPage = lazy(() => import('@/pages/InternalAdminPage'));
const SeoRoutePage = lazy(() => import('@/pages/SeoRoutePage'));
+const ComparisonPage = lazy(() => import('@/pages/ComparisonPage'));
const CookieConsent = lazy(() => import('@/components/layout/CookieConsent'));
const SiteAssistant = lazy(() => import('@/components/layout/SiteAssistant'));
@@ -122,6 +123,7 @@ export default function App() {
} />
} />
} />
+ } />
} />
} />
diff --git a/frontend/src/components/layout/Footer.tsx b/frontend/src/components/layout/Footer.tsx
index f4caf72..6df3c2f 100644
--- a/frontend/src/components/layout/Footer.tsx
+++ b/frontend/src/components/layout/Footer.tsx
@@ -36,6 +36,13 @@ const FOOTER_TOOLS = {
{ slug: 'free-pdf-tools-online', label: 'Free PDF Tools Online', isLanding: true },
{ slug: 'convert-files-online', label: 'Convert Files Online', isLanding: true },
],
+ Comparisons: [
+ { slug: 'compress-pdf-vs-ilovepdf', label: 'Dociva vs iLovePDF', isComparison: true },
+ { slug: 'merge-pdf-vs-smallpdf', label: 'Dociva vs Smallpdf', isComparison: true },
+ { slug: 'pdf-to-word-vs-adobe-acrobat', label: 'Dociva vs Adobe Acrobat', isComparison: true },
+ { slug: 'compress-image-vs-tinypng', label: 'Dociva vs TinyPNG', isComparison: true },
+ { slug: 'ocr-vs-adobe-scan', label: 'Dociva vs Adobe Scan', isComparison: true },
+ ],
};
export default function Footer() {
@@ -55,7 +62,7 @@ export default function Footer() {
{tools.map((tool) => (
{tool.label}
diff --git a/frontend/src/config/comparisonData.ts b/frontend/src/config/comparisonData.ts
new file mode 100644
index 0000000..0035a2c
--- /dev/null
+++ b/frontend/src/config/comparisonData.ts
@@ -0,0 +1,145 @@
+/**
+ * Comparison page data — defines competitor comparisons for SEO landing pages.
+ *
+ * Adding a new comparison:
+ * 1. Append an entry to COMPARISON_PAGES below.
+ * 2. Add matching i18n keys under pages.comparison..* in en/ar/fr.json.
+ * 3. Add the slug to both sitemap generators (generate_sitemap.py + generate-seo-assets.mjs).
+ */
+
+export interface ComparisonFeature {
+ /** i18n key suffix under pages.comparison.features.* */
+ key: string;
+ /** true = has the feature, false = missing, 'partial' = limited */
+ us: boolean | 'partial';
+ competitor: boolean | 'partial';
+}
+
+export interface ComparisonPage {
+ /** URL slug: /compare/ */
+ slug: string;
+ /** i18n key prefix: pages.comparison..* */
+ i18nKey: string;
+ /** Our tool slug (links to /tools/) */
+ ourToolSlug: string;
+ /** Competitor display name */
+ competitorName: string;
+ /** SEO category */
+ category: 'PDF' | 'Image' | 'AI' | 'Convert' | 'Utility';
+ /** Feature comparison rows */
+ features: ComparisonFeature[];
+ /** Related comparison page slugs */
+ relatedComparisonSlugs: string[];
+ /** Tool slugs to show as related */
+ relatedToolSlugs: string[];
+}
+
+export const COMPARISON_PAGES: ComparisonPage[] = [
+ {
+ slug: 'compress-pdf-vs-ilovepdf',
+ i18nKey: 'compressPdfVsIlovepdf',
+ ourToolSlug: 'compress-pdf',
+ competitorName: 'iLovePDF',
+ category: 'PDF',
+ features: [
+ { key: 'freeUnlimited', us: true, competitor: false },
+ { key: 'noSignup', us: true, competitor: false },
+ { key: 'batchProcessing', us: true, competitor: 'partial' },
+ { key: 'compressionLevels', us: true, competitor: true },
+ { key: 'autoDelete', us: true, competitor: true },
+ { key: 'noAds', us: true, competitor: false },
+ { key: 'apiAccess', us: true, competitor: true },
+ { key: 'offlineMode', us: false, competitor: false },
+ ],
+ relatedComparisonSlugs: ['merge-pdf-vs-smallpdf', 'pdf-to-word-vs-adobe-acrobat'],
+ relatedToolSlugs: ['compress-pdf', 'merge-pdf', 'split-pdf', 'compress-image'],
+ },
+ {
+ slug: 'merge-pdf-vs-smallpdf',
+ i18nKey: 'mergePdfVsSmallpdf',
+ ourToolSlug: 'merge-pdf',
+ competitorName: 'Smallpdf',
+ category: 'PDF',
+ features: [
+ { key: 'freeUnlimited', us: true, competitor: false },
+ { key: 'noSignup', us: true, competitor: false },
+ { key: 'batchProcessing', us: true, competitor: true },
+ { key: 'dragReorder', us: true, competitor: true },
+ { key: 'autoDelete', us: true, competitor: true },
+ { key: 'noAds', us: true, competitor: false },
+ { key: 'apiAccess', us: true, competitor: 'partial' },
+ { key: 'offlineMode', us: false, competitor: false },
+ ],
+ relatedComparisonSlugs: ['compress-pdf-vs-ilovepdf', 'pdf-to-word-vs-adobe-acrobat'],
+ relatedToolSlugs: ['merge-pdf', 'split-pdf', 'compress-pdf', 'reorder-pdf'],
+ },
+ {
+ slug: 'pdf-to-word-vs-adobe-acrobat',
+ i18nKey: 'pdfToWordVsAdobeAcrobat',
+ ourToolSlug: 'pdf-to-word',
+ competitorName: 'Adobe Acrobat',
+ category: 'PDF',
+ features: [
+ { key: 'freeUnlimited', us: true, competitor: false },
+ { key: 'noSignup', us: true, competitor: false },
+ { key: 'preserveFormatting', us: true, competitor: true },
+ { key: 'batchProcessing', us: true, competitor: true },
+ { key: 'autoDelete', us: true, competitor: true },
+ { key: 'noAds', us: true, competitor: true },
+ { key: 'noInstall', us: true, competitor: false },
+ { key: 'offlineMode', us: false, competitor: true },
+ ],
+ relatedComparisonSlugs: ['compress-pdf-vs-ilovepdf', 'merge-pdf-vs-smallpdf'],
+ relatedToolSlugs: ['pdf-to-word', 'word-to-pdf', 'pdf-to-excel', 'compress-pdf'],
+ },
+ {
+ slug: 'compress-image-vs-tinypng',
+ i18nKey: 'compressImageVsTinypng',
+ ourToolSlug: 'compress-image',
+ competitorName: 'TinyPNG',
+ category: 'Image',
+ features: [
+ { key: 'freeUnlimited', us: true, competitor: false },
+ { key: 'noSignup', us: true, competitor: true },
+ { key: 'multiFormat', us: true, competitor: 'partial' },
+ { key: 'batchProcessing', us: true, competitor: 'partial' },
+ { key: 'qualityControl', us: true, competitor: false },
+ { key: 'autoDelete', us: true, competitor: true },
+ { key: 'apiAccess', us: true, competitor: true },
+ { key: 'offlineMode', us: false, competitor: false },
+ ],
+ relatedComparisonSlugs: ['compress-pdf-vs-ilovepdf', 'ocr-vs-adobe-scan'],
+ relatedToolSlugs: ['compress-image', 'image-converter', 'image-resize', 'remove-background'],
+ },
+ {
+ slug: 'ocr-vs-adobe-scan',
+ i18nKey: 'ocrVsAdobeScan',
+ ourToolSlug: 'ocr',
+ competitorName: 'Adobe Scan',
+ category: 'AI',
+ features: [
+ { key: 'freeUnlimited', us: true, competitor: false },
+ { key: 'noSignup', us: true, competitor: false },
+ { key: 'noInstall', us: true, competitor: false },
+ { key: 'multiLanguageOcr', us: true, competitor: true },
+ { key: 'batchProcessing', us: true, competitor: false },
+ { key: 'autoDelete', us: true, competitor: true },
+ { key: 'apiAccess', us: true, competitor: false },
+ { key: 'offlineMode', us: false, competitor: true },
+ ],
+ relatedComparisonSlugs: ['pdf-to-word-vs-adobe-acrobat', 'compress-image-vs-tinypng'],
+ relatedToolSlugs: ['ocr', 'chat-pdf', 'summarize-pdf', 'pdf-to-word'],
+ },
+];
+
+export function getComparisonPage(slug: string): ComparisonPage | undefined {
+ return COMPARISON_PAGES.find((p) => p.slug === slug);
+}
+
+export function getAllComparisonSlugs(): string[] {
+ return COMPARISON_PAGES.map((p) => p.slug);
+}
+
+export function getComparisonPagesByTool(toolSlug: string): ComparisonPage[] {
+ return COMPARISON_PAGES.filter((p) => p.ourToolSlug === toolSlug);
+}
diff --git a/frontend/src/config/routes.ts b/frontend/src/config/routes.ts
index d9a30cd..8e33aca 100644
--- a/frontend/src/config/routes.ts
+++ b/frontend/src/config/routes.ts
@@ -27,6 +27,7 @@ const STATIC_PAGE_ROUTES = [
'/tools',
'/internal/admin',
'/pricing-transparency',
+ '/compare/:slug',
] as const;
const SEO_PAGE_ROUTES = getAllSeoLandingPaths();
diff --git a/frontend/src/config/seoData.ts b/frontend/src/config/seoData.ts
index 1a0c415..a07fb1a 100644
--- a/frontend/src/config/seoData.ts
+++ b/frontend/src/config/seoData.ts
@@ -917,6 +917,31 @@ const POPULAR_TOOL_SLUGS = [
'video-to-gif',
] as const;
+/** Workflow chains: tools users are likely to use in sequence */
+const TOOL_WORKFLOWS: Record = {
+ 'compress-pdf': ['merge-pdf', 'split-pdf', 'pdf-to-word'],
+ 'merge-pdf': ['compress-pdf', 'split-pdf', 'rotate-pdf'],
+ 'split-pdf': ['merge-pdf', 'compress-pdf', 'pdf-to-word'],
+ 'pdf-to-word': ['word-to-pdf', 'compress-pdf', 'ocr'],
+ 'word-to-pdf': ['compress-pdf', 'merge-pdf', 'pdf-editor'],
+ 'pdf-to-excel': ['pdf-to-word', 'ocr', 'compress-pdf'],
+ 'pdf-to-pptx': ['pdf-to-word', 'compress-pdf', 'merge-pdf'],
+ 'rotate-pdf': ['merge-pdf', 'split-pdf', 'compress-pdf'],
+ 'pdf-editor': ['compress-pdf', 'merge-pdf', 'watermark-pdf'],
+ 'watermark-pdf': ['compress-pdf', 'pdf-editor', 'merge-pdf'],
+ 'protect-pdf': ['watermark-pdf', 'compress-pdf', 'merge-pdf'],
+ 'unlock-pdf': ['compress-pdf', 'pdf-to-word', 'merge-pdf'],
+ 'ocr': ['pdf-to-word', 'compress-pdf', 'image-converter'],
+ 'compress-image': ['image-resize', 'image-converter', 'image-to-pdf'],
+ 'image-resize': ['compress-image', 'image-converter', 'image-crop'],
+ 'image-converter': ['compress-image', 'image-resize', 'image-to-pdf'],
+ 'image-to-pdf': ['compress-pdf', 'merge-pdf', 'compress-image'],
+ 'image-crop': ['image-resize', 'compress-image', 'image-converter'],
+ 'html-to-pdf': ['compress-pdf', 'merge-pdf', 'pdf-editor'],
+ 'qr-code': ['barcode-generator', 'html-to-pdf'],
+ 'barcode-generator': ['qr-code', 'html-to-pdf'],
+};
+
function dedupeExistingToolSlugs(slugs: string[], excludeSlugs: string[] = []): string[] {
const excluded = new Set(excludeSlugs);
const seen = new Set();
@@ -952,12 +977,14 @@ export function getInternalLinkToolSlugs(currentSlug: string, limit = 8): string
return [];
}
+ const workflowSlugs = TOOL_WORKFLOWS[currentSlug] || [];
+
const sameCategorySlugs = TOOLS_SEO
.filter((tool) => tool.category === currentTool.category && tool.slug !== currentSlug)
.map((tool) => tool.slug);
const internalLinks = dedupeExistingToolSlugs(
- [...currentTool.relatedSlugs, ...sameCategorySlugs, ...POPULAR_TOOL_SLUGS],
+ [...currentTool.relatedSlugs, ...workflowSlugs, ...sameCategorySlugs, ...POPULAR_TOOL_SLUGS],
[currentSlug]
);
diff --git a/frontend/src/i18n/ar.json b/frontend/src/i18n/ar.json
index 8b9b08a..b4dae81 100644
--- a/frontend/src/i18n/ar.json
+++ b/frontend/src/i18n/ar.json
@@ -411,6 +411,134 @@
"pricingCta": "قارن بين Free وPro",
"toolsCta": "استكشف الأدوات"
},
+ "comparison": {
+ "badge": "مقارنة",
+ "featureComparison": "مقارنة المميزات",
+ "feature": "الميزة",
+ "verdictTitle": "الحكم النهائي",
+ "faqTitle": "الأسئلة الشائعة",
+ "relatedComparisons": "مقارنات أخرى",
+ "relatedTools": "أدوات ذات صلة",
+ "ctaSubtext": "مجاني، بدون تسجيل — جرّبه الآن.",
+ "notFound": "المقارنة غير موجودة",
+ "browseTools": "تصفح جميع الأدوات",
+ "features": {
+ "freeUnlimited": "مجاني وبدون حدود",
+ "noSignup": "بدون تسجيل حساب",
+ "batchProcessing": "معالجة دفعات",
+ "compressionLevels": "مستويات ضغط متعددة",
+ "autoDelete": "حذف تلقائي للملفات",
+ "noAds": "بدون إعلانات أو نوافذ منبثقة",
+ "apiAccess": "وصول API",
+ "offlineMode": "وضع سطح المكتب بدون اتصال",
+ "dragReorder": "إعادة ترتيب بالسحب والإفلات",
+ "preserveFormatting": "الحفاظ على التنسيق",
+ "noInstall": "بدون حاجة لتثبيت برامج",
+ "multiFormat": "دعم صيغ متعددة",
+ "qualityControl": "شريط تحكم بالجودة",
+ "multiLanguageOcr": "OCR متعدد اللغات"
+ },
+ "compressPdfVsIlovepdf": {
+ "title": "Dociva مقابل iLovePDF — مقارنة ضغط PDF المجاني",
+ "metaDescription": "قارن بين Dociva وiLovePDF لضغط ملفات PDF. شاهد المميزات والحدود والأسعار جنبًا إلى جنب.",
+ "heading": "Dociva مقابل iLovePDF",
+ "subtitle": "كلتا الأداتين تضغطان ملفات PDF، لكن Dociva تقدم استخدامًا مجانيًا غير محدود بدون تسجيل وبدون إعلانات.",
+ "advantagesTitle": "لماذا تختار Dociva بدلاً من iLovePDF",
+ "advantages": [
+ "بلا حدود حقيقية — لا قيود يومية على الملفات",
+ "بدون حاجة لإنشاء حساب — ابدأ الضغط فورًا",
+ "صفر إعلانات، صفر نوافذ منبثقة، واجهة نظيفة",
+ "الملفات تُحذف تلقائيًا بعد 30 دقيقة",
+ "وصول API متاح في خطة Pro"
+ ],
+ "verdict": "للمستخدمين الذين يحتاجون ضاغط PDF مجاني وموثوق بدون حدود يومية أو جدران تسجيل، Dociva هي الخيار الأوضح.",
+ "faqs": [
+ { "q": "هل Dociva مجاني فعلًا لضغط PDF؟", "a": "نعم. ضاغط PDF في Dociva مجاني بدون حدود يومية وبدون حاجة لحساب." },
+ { "q": "هل يحدّ iLovePDF المستخدمين المجانيين؟", "a": "نعم. الطبقة المجانية في iLovePDF بها حدود يومية للمهام وتعرض إعلانات." },
+ { "q": "أي أداة تضغط أكثر؟", "a": "كلتا الأداتين تقدمان نسب ضغط متقاربة. Dociva توفر ثلاث مستويات ضغط لتوازن الجودة والحجم." }
+ ]
+ },
+ "mergePdfVsSmallpdf": {
+ "title": "Dociva مقابل Smallpdf — مقارنة دمج PDF المجاني",
+ "metaDescription": "قارن بين Dociva وSmallpdf لدمج ملفات PDF. شاهد المميزات والحدود والأسعار جنبًا إلى جنب.",
+ "heading": "Dociva مقابل Smallpdf",
+ "subtitle": "كلتا المنصتين تدمجان ملفات PDF أونلاين، لكن Dociva تقدم دمجًا غير محدود بدون تسجيل.",
+ "advantagesTitle": "لماذا تختار Dociva بدلاً من Smallpdf",
+ "advantages": [
+ "دمج PDF غير محدود — بدون حدود يومية",
+ "بدون حاجة لحساب لدمج الملفات",
+ "واجهة نظيفة بدون إعلانات",
+ "إعادة ترتيب الصفحات بالسحب والإفلات",
+ "الملفات تُحذف تلقائيًا بعد المعالجة"
+ ],
+ "verdict": "Smallpdf أنيقة لكن تقفل معظم المميزات خلف حاجز دفع بعد مهمتين مجانيتين يوميًا. Dociva تقدم نفس وظيفة الدمج الأساسية بلا حدود وبلا تسجيل.",
+ "faqs": [
+ { "q": "هل يمكنني دمج PDF مجانًا مع Dociva؟", "a": "نعم. أداة دمج Dociva مجانية تمامًا بدون حدود يومية." },
+ { "q": "هل يحدّ Smallpdf عمليات الدمج المجانية؟", "a": "نعم. Smallpdf تسمح فقط بمهمتين مجانيتين يوميًا." },
+ { "q": "هل يمكنني إعادة ترتيب الصفحات قبل الدمج؟", "a": "نعم. كلتا الأداتين تدعمان إعادة الترتيب بالسحب والإفلات قبل الدمج النهائي." }
+ ]
+ },
+ "pdfToWordVsAdobeAcrobat": {
+ "title": "Dociva مقابل Adobe Acrobat — مقارنة تحويل PDF إلى Word",
+ "metaDescription": "قارن بين Dociva وAdobe Acrobat لتحويل PDF إلى Word. أداة أونلاين مجانية مقابل برنامج سطح مكتب مدفوع.",
+ "heading": "Dociva مقابل Adobe Acrobat",
+ "subtitle": "Adobe Acrobat هو المعيار الصناعي، لكن Dociva تقدم نفس تحويل PDF إلى Word مجانًا وأونلاين بدون تثبيت.",
+ "advantagesTitle": "لماذا تختار Dociva بدلاً من Adobe Acrobat",
+ "advantages": [
+ "مجاني 100% — بدون رسوم اشتراك",
+ "بدون تحميل أو تثبيت برامج",
+ "يعمل على أي جهاز بمتصفح",
+ "بدون حاجة لمعرف Adobe",
+ "تحويل سريع مع الحفاظ على التنسيق"
+ ],
+ "verdict": "Adobe Acrobat يقدم أقوى مجموعة أدوات PDF، لكن بسعر مرتفع. لتحويل PDF إلى Word المباشر، Dociva تطابق الجودة مجانًا وأونلاين.",
+ "faqs": [
+ { "q": "هل جودة تحويل Dociva بمستوى Adobe؟", "a": "للمستندات العادية، تحافظ Dociva على التنسيق والخطوط والتخطيط بشكل مقارب لمحول Adobe Acrobat." },
+ { "q": "هل يتطلب Adobe Acrobat اشتراكًا؟", "a": "نعم. مميزات التحويل الكاملة تتطلب اشتراك Acrobat Pro." },
+ { "q": "هل يمكنني تحويل ملفات PDF كبيرة؟", "a": "Dociva تدعم ملفات حتى 20 ميجابايت. Adobe Acrobat يدعم ملفات أكبر عبر تطبيق سطح المكتب." }
+ ]
+ },
+ "compressImageVsTinypng": {
+ "title": "Dociva مقابل TinyPNG — مقارنة ضغط الصور المجاني",
+ "metaDescription": "قارن بين Dociva وTinyPNG لضغط الصور. شاهد دعم الصيغ والحدود والجودة.",
+ "heading": "Dociva مقابل TinyPNG",
+ "subtitle": "TinyPNG ضاغط صور شهير، لكن Dociva تدعم صيغ أكثر وبدون حدود على عدد الملفات.",
+ "advantagesTitle": "لماذا تختار Dociva بدلاً من TinyPNG",
+ "advantages": [
+ "ضغط غير محدود — بدون حدود يومية",
+ "تدعم JPEG وPNG وWebP وGIF والمزيد",
+ "شريط تحكم بالجودة لنتائج دقيقة",
+ "رفع ومعالجة صور متعددة دفعة واحدة",
+ "بدون قيود على عدد الملفات في الطبقة المجانية"
+ ],
+ "verdict": "TinyPNG تتفوق في تحسين PNG/JPEG بواجهة بسيطة، لكنها تحدّ المستخدمين المجانيين بـ 20 صورة لكل دفعة. Dociva تزيل هذه الحدود وتضيف مرونة في الصيغ.",
+ "faqs": [
+ { "q": "هل لدى TinyPNG حدود؟", "a": "نعم. أداة TinyPNG المجانية تحدّك بـ 20 صورة لكل دفعة و5 ميجابايت لكل ملف." },
+ { "q": "ما الصيغ التي تدعمها Dociva؟", "a": "Dociva تضغط JPEG وPNG وWebP وGIF وSVG والمزيد." },
+ { "q": "هل يمكنني التحكم بجودة الضغط؟", "a": "نعم. Dociva توفر شريط تحكم بالجودة لتوازن حجم الملف والوضوح البصري." }
+ ]
+ },
+ "ocrVsAdobeScan": {
+ "title": "Dociva OCR مقابل Adobe Scan — مقارنة التعرف على النص",
+ "metaDescription": "قارن بين Dociva OCR وAdobe Scan للتعرف على النص. أداة متصفح مقابل تطبيق جوال.",
+ "heading": "Dociva OCR مقابل Adobe Scan",
+ "subtitle": "Adobe Scan تطبيق مسح ضوئي للجوال، بينما Dociva OCR تعمل مباشرة في متصفحك بدون تثبيت.",
+ "advantagesTitle": "لماذا تختار Dociva OCR بدلاً من Adobe Scan",
+ "advantages": [
+ "تعمل في أي متصفح — بدون تثبيت تطبيق",
+ "معالجة OCR غير محدودة",
+ "بدون حاجة لحساب Adobe",
+ "تدعم معالجة دفعات لملفات متعددة",
+ "تعرف نصي متعدد اللغات (إنجليزي، عربي، فرنسي)"
+ ],
+ "verdict": "Adobe Scan تطبيق مسح ضوئي جوال ممتاز مع دعم العمل بدون اتصال. لكن لـ OCR عبر الويب مع معالجة دفعات وبدون تسجيل، Dociva أسرع وأكثر مرونة.",
+ "faqs": [
+ { "q": "هل يعمل Dociva OCR بدون اتصال؟", "a": "لا. Dociva OCR يتطلب اتصال إنترنت لمعالجة الملفات على خوادم آمنة." },
+ { "q": "هل Adobe Scan مجاني؟", "a": "المميزات الأساسية مجانية، لكن OCR المتقدم والتصدير يتطلبان اشتراك Acrobat." },
+ { "q": "ما اللغات التي يدعمها Dociva OCR؟", "a": "Dociva OCR يدعم التعرف على النص بالإنجليزية والعربية والفرنسية." }
+ ]
+ }
+ },
"developers": {
"metaDescription": "استكشف بوابة مطوري Dociva، وتدفق API غير المتزامن، والنقاط الجاهزة لأتمتة المستندات.",
"badge": "بوابة المطورين",
diff --git a/frontend/src/i18n/en.json b/frontend/src/i18n/en.json
index 9973a19..1e65524 100644
--- a/frontend/src/i18n/en.json
+++ b/frontend/src/i18n/en.json
@@ -411,6 +411,134 @@
"pricingCta": "Compare Free and Pro",
"toolsCta": "Explore tools"
},
+ "comparison": {
+ "badge": "Comparison",
+ "featureComparison": "Feature Comparison",
+ "feature": "Feature",
+ "verdictTitle": "The Verdict",
+ "faqTitle": "Frequently Asked Questions",
+ "relatedComparisons": "More Comparisons",
+ "relatedTools": "Related Tools",
+ "ctaSubtext": "Free, no signup required — try it now.",
+ "notFound": "Comparison not found",
+ "browseTools": "Browse all tools",
+ "features": {
+ "freeUnlimited": "Free & unlimited use",
+ "noSignup": "No signup required",
+ "batchProcessing": "Batch processing",
+ "compressionLevels": "Multiple compression levels",
+ "autoDelete": "Auto-delete files",
+ "noAds": "No ads or popups",
+ "apiAccess": "API access",
+ "offlineMode": "Offline desktop mode",
+ "dragReorder": "Drag-and-drop reorder",
+ "preserveFormatting": "Preserve formatting",
+ "noInstall": "No software install needed",
+ "multiFormat": "Multi-format support",
+ "qualityControl": "Quality control slider",
+ "multiLanguageOcr": "Multi-language OCR"
+ },
+ "compressPdfVsIlovepdf": {
+ "title": "Dociva vs iLovePDF — Free PDF Compression Compared",
+ "metaDescription": "Compare Dociva and iLovePDF for PDF compression. See features, limits, and pricing side by side.",
+ "heading": "Dociva vs iLovePDF",
+ "subtitle": "Both tools compress PDFs, but Dociva offers unlimited free use with no signup and no ads. See how they compare feature by feature.",
+ "advantagesTitle": "Why choose Dociva over iLovePDF",
+ "advantages": [
+ "Truly unlimited — no daily file caps or task limits",
+ "No account required — start compressing immediately",
+ "Zero ads, zero popups, clean interface",
+ "Files automatically deleted after 30 minutes",
+ "API access included on Pro plan"
+ ],
+ "verdict": "For users who need a reliable, free PDF compressor without daily limits or sign-up walls, Dociva is the clear choice. iLovePDF offers a broader desktop suite, but its free tier is restrictive.",
+ "faqs": [
+ { "q": "Is Dociva really free for PDF compression?", "a": "Yes. Dociva's PDF compressor is free with no daily limits, no account required, and no hidden paywalls." },
+ { "q": "Does iLovePDF limit free users?", "a": "Yes. iLovePDF's free tier has daily task limits and shows ads. Premium features require a paid subscription." },
+ { "q": "Which tool compresses PDFs more?", "a": "Both tools offer comparable compression ratios. Dociva provides three compression levels to balance quality and file size." }
+ ]
+ },
+ "mergePdfVsSmallpdf": {
+ "title": "Dociva vs Smallpdf — Free PDF Merge Compared",
+ "metaDescription": "Compare Dociva and Smallpdf for merging PDFs. See features, limits, and pricing side by side.",
+ "heading": "Dociva vs Smallpdf",
+ "subtitle": "Both platforms merge PDFs online, but Dociva offers unlimited merges with no signup. See the differences.",
+ "advantagesTitle": "Why choose Dociva over Smallpdf",
+ "advantages": [
+ "Unlimited PDF merges — no daily caps",
+ "No account required to merge files",
+ "Clean, ad-free interface",
+ "Drag-and-drop page reordering",
+ "Files auto-deleted after processing"
+ ],
+ "verdict": "Smallpdf is polished but locks most features behind a paywall after two free tasks per day. Dociva provides the same core merge functionality with no limits and no signup.",
+ "faqs": [
+ { "q": "Can I merge PDFs for free with Dociva?", "a": "Yes. Dociva's merge tool is completely free with no daily limits." },
+ { "q": "Does Smallpdf limit free merges?", "a": "Yes. Smallpdf allows only two free tasks per day on its free tier." },
+ { "q": "Can I reorder pages before merging?", "a": "Yes. Both tools support drag-and-drop reordering before the final merge." }
+ ]
+ },
+ "pdfToWordVsAdobeAcrobat": {
+ "title": "Dociva vs Adobe Acrobat — Free PDF to Word Compared",
+ "metaDescription": "Compare Dociva and Adobe Acrobat for PDF to Word conversion. Free online tool vs premium desktop software.",
+ "heading": "Dociva vs Adobe Acrobat",
+ "subtitle": "Adobe Acrobat is the industry standard, but Dociva delivers the same PDF-to-Word conversion for free, online, with no install.",
+ "advantagesTitle": "Why choose Dociva over Adobe Acrobat",
+ "advantages": [
+ "100% free — no subscription fees",
+ "No software download or installation",
+ "Works on any device with a browser",
+ "No Adobe ID required",
+ "Fast conversion with formatting preserved"
+ ],
+ "verdict": "Adobe Acrobat offers the most powerful PDF toolkit, but at a high price. For straightforward PDF-to-Word conversion, Dociva matches the quality for free, online, with zero friction.",
+ "faqs": [
+ { "q": "Is Dociva's conversion quality as good as Adobe?", "a": "For standard documents, Dociva preserves formatting, fonts, and layout comparable to Adobe Acrobat's online converter." },
+ { "q": "Does Adobe Acrobat require a subscription?", "a": "Yes. Adobe Acrobat's full conversion features require an Acrobat Pro subscription starting at $19.99/month." },
+ { "q": "Can I convert large PDFs?", "a": "Dociva supports files up to 20MB. Adobe Acrobat supports larger files with its desktop app." }
+ ]
+ },
+ "compressImageVsTinypng": {
+ "title": "Dociva vs TinyPNG — Free Image Compression Compared",
+ "metaDescription": "Compare Dociva and TinyPNG for image compression. See format support, limits, and quality differences.",
+ "heading": "Dociva vs TinyPNG",
+ "subtitle": "TinyPNG is a popular image compressor, but Dociva supports more formats and has no file count limits. Compare them here.",
+ "advantagesTitle": "Why choose Dociva over TinyPNG",
+ "advantages": [
+ "Unlimited compressions — no daily file caps",
+ "Supports JPEG, PNG, WebP, GIF, and more",
+ "Quality control slider for precise results",
+ "Batch upload and process multiple images",
+ "No file count restrictions on free tier"
+ ],
+ "verdict": "TinyPNG excels at PNG/JPEG optimization with a simple interface, but limits free users to 20 images per batch. Dociva removes those limits and adds format flexibility.",
+ "faqs": [
+ { "q": "Does TinyPNG have limits?", "a": "Yes. TinyPNG's free web tool limits you to 20 images per batch and 5MB per file." },
+ { "q": "Which formats does Dociva support?", "a": "Dociva compresses JPEG, PNG, WebP, GIF, SVG, and more image formats." },
+ { "q": "Can I control compression quality?", "a": "Yes. Dociva provides a quality slider so you can balance file size and visual quality." }
+ ]
+ },
+ "ocrVsAdobeScan": {
+ "title": "Dociva OCR vs Adobe Scan — Free Text Recognition Compared",
+ "metaDescription": "Compare Dociva OCR and Adobe Scan for text recognition. Browser-based vs mobile app — see features side by side.",
+ "heading": "Dociva OCR vs Adobe Scan",
+ "subtitle": "Adobe Scan is a mobile scanning app, while Dociva OCR works directly in your browser with no install. See how they compare.",
+ "advantagesTitle": "Why choose Dociva OCR over Adobe Scan",
+ "advantages": [
+ "Works in any browser — no app install",
+ "Unlimited OCR processing",
+ "No Adobe account required",
+ "Supports batch processing of multiple files",
+ "Multi-language text recognition (English, Arabic, French)"
+ ],
+ "verdict": "Adobe Scan is a great mobile scanning app with offline support. But for web-based OCR with batch processing and no login, Dociva is faster and more flexible.",
+ "faqs": [
+ { "q": "Does Dociva OCR work offline?", "a": "No. Dociva OCR requires an internet connection as it processes files on secure servers." },
+ { "q": "Is Adobe Scan free?", "a": "Adobe Scan's basic features are free, but advanced OCR and export features require an Acrobat subscription." },
+ { "q": "Which languages does Dociva OCR support?", "a": "Dociva OCR supports English, Arabic, and French text recognition out of the box." }
+ ]
+ }
+ },
"developers": {
"metaDescription": "Explore the Dociva developer portal, async API flow, and production-ready endpoints for document automation.",
"badge": "Developer Portal",
diff --git a/frontend/src/i18n/fr.json b/frontend/src/i18n/fr.json
index 460b957..ee97e82 100644
--- a/frontend/src/i18n/fr.json
+++ b/frontend/src/i18n/fr.json
@@ -411,6 +411,134 @@
"pricingCta": "Comparer Gratuit et Pro",
"toolsCta": "Explorer les outils"
},
+ "comparison": {
+ "badge": "Comparaison",
+ "featureComparison": "Comparaison des fonctionnalités",
+ "feature": "Fonctionnalité",
+ "verdictTitle": "Le verdict",
+ "faqTitle": "Questions fréquentes",
+ "relatedComparisons": "Autres comparaisons",
+ "relatedTools": "Outils associés",
+ "ctaSubtext": "Gratuit, sans inscription — essayez maintenant.",
+ "notFound": "Comparaison introuvable",
+ "browseTools": "Parcourir tous les outils",
+ "features": {
+ "freeUnlimited": "Gratuit et illimité",
+ "noSignup": "Aucune inscription requise",
+ "batchProcessing": "Traitement par lots",
+ "compressionLevels": "Plusieurs niveaux de compression",
+ "autoDelete": "Suppression automatique des fichiers",
+ "noAds": "Pas de publicités ni de popups",
+ "apiAccess": "Accès API",
+ "offlineMode": "Mode bureau hors ligne",
+ "dragReorder": "Réorganisation par glisser-déposer",
+ "preserveFormatting": "Préservation du formatage",
+ "noInstall": "Aucune installation requise",
+ "multiFormat": "Support multi-format",
+ "qualityControl": "Curseur de contrôle qualité",
+ "multiLanguageOcr": "OCR multilingue"
+ },
+ "compressPdfVsIlovepdf": {
+ "title": "Dociva vs iLovePDF — Compression PDF gratuite comparée",
+ "metaDescription": "Comparez Dociva et iLovePDF pour la compression PDF. Fonctionnalités, limites et prix côte à côte.",
+ "heading": "Dociva vs iLovePDF",
+ "subtitle": "Les deux outils compressent les PDF, mais Dociva offre une utilisation gratuite illimitée sans inscription ni publicité.",
+ "advantagesTitle": "Pourquoi choisir Dociva plutôt qu'iLovePDF",
+ "advantages": [
+ "Vraiment illimité — aucun quota quotidien",
+ "Aucun compte requis — commencez immédiatement",
+ "Zéro publicité, zéro popup, interface épurée",
+ "Fichiers supprimés automatiquement après 30 minutes",
+ "Accès API inclus dans le plan Pro"
+ ],
+ "verdict": "Pour les utilisateurs qui ont besoin d'un compresseur PDF fiable et gratuit sans limites quotidiennes ni mur d'inscription, Dociva est le choix évident.",
+ "faqs": [
+ { "q": "Dociva est-il vraiment gratuit pour la compression PDF ?", "a": "Oui. Le compresseur PDF de Dociva est gratuit sans limites quotidiennes ni compte requis." },
+ { "q": "iLovePDF limite-t-il les utilisateurs gratuits ?", "a": "Oui. Le niveau gratuit d'iLovePDF a des limites quotidiennes et affiche des publicités." },
+ { "q": "Quel outil compresse le plus ?", "a": "Les deux offrent des taux de compression comparables. Dociva propose trois niveaux pour équilibrer qualité et taille." }
+ ]
+ },
+ "mergePdfVsSmallpdf": {
+ "title": "Dociva vs Smallpdf — Fusion PDF gratuite comparée",
+ "metaDescription": "Comparez Dociva et Smallpdf pour la fusion de PDF. Fonctionnalités, limites et prix côte à côte.",
+ "heading": "Dociva vs Smallpdf",
+ "subtitle": "Les deux plateformes fusionnent les PDF en ligne, mais Dociva offre des fusions illimitées sans inscription.",
+ "advantagesTitle": "Pourquoi choisir Dociva plutôt que Smallpdf",
+ "advantages": [
+ "Fusions PDF illimitées — aucun quota quotidien",
+ "Aucun compte requis pour fusionner",
+ "Interface propre sans publicité",
+ "Réorganisation par glisser-déposer",
+ "Fichiers supprimés après traitement"
+ ],
+ "verdict": "Smallpdf est élégant mais verrouille la plupart des fonctionnalités derrière un paywall après deux tâches gratuites par jour. Dociva offre la même fonctionnalité sans limites.",
+ "faqs": [
+ { "q": "Puis-je fusionner des PDF gratuitement avec Dociva ?", "a": "Oui. L'outil de fusion de Dociva est entièrement gratuit sans limites quotidiennes." },
+ { "q": "Smallpdf limite-t-il les fusions gratuites ?", "a": "Oui. Smallpdf ne permet que deux tâches gratuites par jour." },
+ { "q": "Puis-je réorganiser les pages avant la fusion ?", "a": "Oui. Les deux outils supportent la réorganisation par glisser-déposer." }
+ ]
+ },
+ "pdfToWordVsAdobeAcrobat": {
+ "title": "Dociva vs Adobe Acrobat — Conversion PDF vers Word comparée",
+ "metaDescription": "Comparez Dociva et Adobe Acrobat pour la conversion PDF vers Word. Outil gratuit en ligne vs logiciel premium.",
+ "heading": "Dociva vs Adobe Acrobat",
+ "subtitle": "Adobe Acrobat est la référence du secteur, mais Dociva offre la même conversion PDF vers Word gratuitement, en ligne.",
+ "advantagesTitle": "Pourquoi choisir Dociva plutôt qu'Adobe Acrobat",
+ "advantages": [
+ "100% gratuit — aucun abonnement",
+ "Aucun téléchargement ni installation",
+ "Fonctionne sur tout appareil avec un navigateur",
+ "Aucun identifiant Adobe requis",
+ "Conversion rapide avec formatage préservé"
+ ],
+ "verdict": "Adobe Acrobat offre la suite PDF la plus puissante, mais à un prix élevé. Pour une conversion PDF vers Word directe, Dociva égale la qualité gratuitement.",
+ "faqs": [
+ { "q": "La qualité de conversion de Dociva est-elle aussi bonne qu'Adobe ?", "a": "Pour les documents standard, Dociva préserve le formatage de manière comparable au convertisseur en ligne d'Adobe." },
+ { "q": "Adobe Acrobat nécessite-t-il un abonnement ?", "a": "Oui. Les fonctionnalités complètes nécessitent un abonnement Acrobat Pro." },
+ { "q": "Puis-je convertir de gros PDF ?", "a": "Dociva supporte les fichiers jusqu'à 20 Mo. Adobe Acrobat supporte des fichiers plus volumineux via son application." }
+ ]
+ },
+ "compressImageVsTinypng": {
+ "title": "Dociva vs TinyPNG — Compression d'images gratuite comparée",
+ "metaDescription": "Comparez Dociva et TinyPNG pour la compression d'images. Formats, limites et qualité.",
+ "heading": "Dociva vs TinyPNG",
+ "subtitle": "TinyPNG est un compresseur d'images populaire, mais Dociva supporte plus de formats sans limites de fichiers.",
+ "advantagesTitle": "Pourquoi choisir Dociva plutôt que TinyPNG",
+ "advantages": [
+ "Compressions illimitées — aucun quota quotidien",
+ "Supporte JPEG, PNG, WebP, GIF et plus",
+ "Curseur de qualité pour des résultats précis",
+ "Upload et traitement par lots",
+ "Aucune restriction sur le nombre de fichiers"
+ ],
+ "verdict": "TinyPNG excelle dans l'optimisation PNG/JPEG avec une interface simple, mais limite les utilisateurs gratuits à 20 images par lot. Dociva supprime ces limites.",
+ "faqs": [
+ { "q": "TinyPNG a-t-il des limites ?", "a": "Oui. L'outil gratuit de TinyPNG limite à 20 images par lot et 5 Mo par fichier." },
+ { "q": "Quels formats Dociva supporte-t-il ?", "a": "Dociva compresse JPEG, PNG, WebP, GIF, SVG et d'autres formats." },
+ { "q": "Puis-je contrôler la qualité de compression ?", "a": "Oui. Dociva propose un curseur de qualité pour équilibrer taille et qualité visuelle." }
+ ]
+ },
+ "ocrVsAdobeScan": {
+ "title": "Dociva OCR vs Adobe Scan — Reconnaissance de texte comparée",
+ "metaDescription": "Comparez Dociva OCR et Adobe Scan pour la reconnaissance de texte. Navigateur vs application mobile.",
+ "heading": "Dociva OCR vs Adobe Scan",
+ "subtitle": "Adobe Scan est une application mobile de numérisation, tandis que Dociva OCR fonctionne directement dans votre navigateur.",
+ "advantagesTitle": "Pourquoi choisir Dociva OCR plutôt qu'Adobe Scan",
+ "advantages": [
+ "Fonctionne dans tout navigateur — aucune installation",
+ "Traitement OCR illimité",
+ "Aucun compte Adobe requis",
+ "Traitement par lots de plusieurs fichiers",
+ "Reconnaissance multilingue (anglais, arabe, français)"
+ ],
+ "verdict": "Adobe Scan est une excellente application de numérisation mobile avec support hors ligne. Mais pour l'OCR web avec traitement par lots et sans connexion, Dociva est plus rapide et flexible.",
+ "faqs": [
+ { "q": "Dociva OCR fonctionne-t-il hors ligne ?", "a": "Non. Dociva OCR nécessite une connexion Internet pour traiter les fichiers sur des serveurs sécurisés." },
+ { "q": "Adobe Scan est-il gratuit ?", "a": "Les fonctionnalités de base sont gratuites, mais l'OCR avancé nécessite un abonnement Acrobat." },
+ { "q": "Quelles langues Dociva OCR supporte-t-il ?", "a": "Dociva OCR supporte la reconnaissance en anglais, arabe et français." }
+ ]
+ }
+ },
"developers": {
"metaDescription": "Explorez le portail développeur Dociva, le flux API asynchrone et les endpoints prêts pour l'automatisation documentaire.",
"badge": "Portail développeur",
diff --git a/frontend/src/pages/ComparisonPage.tsx b/frontend/src/pages/ComparisonPage.tsx
new file mode 100644
index 0000000..3d7b299
--- /dev/null
+++ b/frontend/src/pages/ComparisonPage.tsx
@@ -0,0 +1,278 @@
+import { useParams, Link } from 'react-router-dom';
+import { useTranslation } from 'react-i18next';
+import { Helmet } from 'react-helmet-async';
+import { CheckCircle, XCircle, MinusCircle, ArrowRight, Swords, Trophy, ExternalLink } from 'lucide-react';
+import { getComparisonPage, getComparisonPagesByTool, type ComparisonFeature } from '@/config/comparisonData';
+import { getToolSEO } from '@/config/seoData';
+import { getSiteOrigin, buildSocialImageUrl, getOgLocale, generateWebPage, generateFAQ } from '@/utils/seo';
+
+function FeatureIcon({ value }: { value: boolean | 'partial' }) {
+ if (value === true) return ;
+ if (value === 'partial') return ;
+ return ;
+}
+
+function FeatureLabel({ value }: { value: boolean | 'partial' }) {
+ if (value === true) return Yes;
+ if (value === 'partial') return Partial;
+ return No;
+}
+
+export default function ComparisonPage() {
+ const { slug } = useParams<{ slug: string }>();
+ const { t, i18n } = useTranslation();
+
+ const comparison = slug ? getComparisonPage(slug) : undefined;
+
+ if (!comparison) {
+ return (
+
+
+ {t('pages.comparison.notFound')}
+
+
+ {t('pages.comparison.browseTools')}
+
+
+ );
+ }
+
+ const ourTool = getToolSEO(comparison.ourToolSlug);
+ const origin = getSiteOrigin(typeof window !== 'undefined' ? window.location.origin : '');
+ const canonicalUrl = `${origin}/compare/${comparison.slug}`;
+ const socialImageUrl = buildSocialImageUrl(origin);
+ const currentOgLocale = getOgLocale(i18n.language);
+ const prefix = `pages.comparison.${comparison.i18nKey}`;
+
+ const title = t(`${prefix}.title`);
+ const metaDescription = t(`${prefix}.metaDescription`);
+
+ const faqItems = t(`${prefix}.faqs`, { returnObjects: true }) as Array<{ q: string; a: string }>;
+ const faqs = Array.isArray(faqItems) ? faqItems : [];
+
+ const webPageSchema = generateWebPage({
+ name: title,
+ description: metaDescription,
+ url: canonicalUrl,
+ });
+
+ const faqSchema = faqs.length > 0
+ ? generateFAQ(faqs.map((f) => ({ question: f.q, answer: f.a })))
+ : null;
+
+ // Related comparisons
+ const relatedComparisons = comparison.relatedComparisonSlugs
+ .map((s) => getComparisonPage(s))
+ .filter(Boolean);
+
+ // Related tools
+ const relatedTools = comparison.relatedToolSlugs
+ .map((s) => getToolSEO(s))
+ .filter(Boolean);
+
+ return (
+ <>
+
+ {title} | {t('common.appName')}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {faqSchema && (
+
+ )}
+
+
+
+ {/* Hero */}
+
+
+
+ {t('pages.comparison.badge')}
+
+
+ {t(`${prefix}.heading`)}
+
+
+ {t(`${prefix}.subtitle`)}
+
+
+
+ {/* Feature Comparison Table */}
+
+
+ {t('pages.comparison.featureComparison')}
+
+
+ {/* Table header */}
+
+
+ {t('pages.comparison.feature')}
+
+
+ {t('common.appName')}
+
+
+ {comparison.competitorName}
+
+
+
+ {/* Feature rows */}
+ {comparison.features.map((feature: ComparisonFeature, idx: number) => (
+
+
+ {t(`pages.comparison.features.${feature.key}`)}
+
+
+
+
+
+
+
+
+
+
+ ))}
+
+
+
+ {/* Our Advantages */}
+
+
+
+ {t(`${prefix}.advantagesTitle`)}
+
+
+ {(() => {
+ const advantages = t(`${prefix}.advantages`, { returnObjects: true }) as string[];
+ return Array.isArray(advantages) ? (
+
+ {advantages.map((adv, idx) => (
+ -
+
+ {adv}
+
+ ))}
+
+ ) : null;
+ })()}
+
+
+
+ {/* Verdict */}
+
+
+ {t('pages.comparison.verdictTitle')}
+
+
+
+ {t(`${prefix}.verdict`)}
+
+
+
+
+ {/* CTA */}
+
+
+ {ourTool ? t(`tools.${ourTool.i18nKey}.title`) : comparison.ourToolSlug}
+
+
+
+ {t('pages.comparison.ctaSubtext')}
+
+
+
+ {/* FAQ */}
+ {faqs.length > 0 && (
+
+
+ {t('pages.comparison.faqTitle')}
+
+
+ {faqs.map((faq, idx) => (
+
+
+ {faq.q}
+
+
+ {faq.a}
+
+
+ ))}
+
+
+ )}
+
+ {/* Related Comparisons */}
+ {relatedComparisons.length > 0 && (
+
+
+ {t('pages.comparison.relatedComparisons')}
+
+
+ {relatedComparisons.map((comp) => (
+
+
+
+ {t(`pages.comparison.${comp!.i18nKey}.heading`)}
+
+
+ ))}
+
+
+ )}
+
+ {/* Related Tools */}
+ {relatedTools.length > 0 && (
+
+
+ {t('pages.comparison.relatedTools')}
+
+
+ {relatedTools.map((tool) => (
+
+
+ {t(`tools.${tool!.i18nKey}.title`)}
+
+
+ {t(`tools.${tool!.i18nKey}.shortDesc`)}
+
+
+ ))}
+
+
+ )}
+
+ >
+ );
+}
diff --git a/scripts/generate_sitemap.py b/scripts/generate_sitemap.py
index 81953cb..df44a0c 100644
--- a/scripts/generate_sitemap.py
+++ b/scripts/generate_sitemap.py
@@ -97,6 +97,15 @@ TOOL_GROUPS = [
('Utility Tools', UTILITY_TOOLS),
]
+# Comparison Pages
+COMPARISON_PAGES = [
+ {'slug': 'compress-pdf-vs-ilovepdf', 'priority': '0.7'},
+ {'slug': 'merge-pdf-vs-smallpdf', 'priority': '0.7'},
+ {'slug': 'pdf-to-word-vs-adobe-acrobat', 'priority': '0.7'},
+ {'slug': 'compress-image-vs-tinypng', 'priority': '0.7'},
+ {'slug': 'ocr-vs-adobe-scan', 'priority': '0.7'},
+]
+
def get_seo_landing_paths() -> tuple[list[str], list[str]]:
repo_root = Path(__file__).resolve().parents[1]
@@ -178,6 +187,17 @@ def generate_sitemap(domain: str) -> str:
0.82
''')
+ # Comparison pages
+ if COMPARISON_PAGES:
+ urls.append('\n ')
+ for page in COMPARISON_PAGES:
+ urls.append(f'''
+ {domain}/compare/{page["slug"]}
+ {today}
+ monthly
+ {page["priority"]}
+ ''')
+
sitemap = f'''
{chr(10).join(urls)}
@@ -209,6 +229,7 @@ def main():
+ sum(len(routes) for _, routes in TOOL_GROUPS)
+ len(seo_tool_pages)
+ len(seo_collection_pages)
+ + len(COMPARISON_PAGES)
)
print(f"Sitemap generated: {args.output}")
print(f"Total URLs: {total}")