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}")