mirror of
https://github.com/alam00000/bentopdf.git
synced 2026-11-12 01:33:36 +01:00
Merge pull request #664 from Skillkiller/translation
Localize status messages and UI elements across various tools
This commit is contained in:
41 files changed
+1309
-312
No files matched your search
@@ -674,7 +674,7 @@
|
|||||||
"pageTitle": "توقيع رقمي لـ PDF - إضافة توقيع تشفيري | BentoPDF",
|
"pageTitle": "توقيع رقمي لـ PDF - إضافة توقيع تشفيري | BentoPDF",
|
||||||
"subtitle": "إضافة توقيع رقمي تشفيري إلى PDF باستخدام شهادات X.509. يدعم تنسيقات PKCS#12 (.pfx، .p12) وPEM. مفتاحك الخاص لا يغادر متصفحك أبدًا.",
|
"subtitle": "إضافة توقيع رقمي تشفيري إلى PDF باستخدام شهادات X.509. يدعم تنسيقات PKCS#12 (.pfx، .p12) وPEM. مفتاحك الخاص لا يغادر متصفحك أبدًا.",
|
||||||
"certificateSection": "الشهادة",
|
"certificateSection": "الشهادة",
|
||||||
"uploadCert": "رفع شهادة (.pfx، .p12)",
|
"uploadCert": "رفع شهادة (.pfx, .p12, .pem)",
|
||||||
"certPassword": "كلمة مرور الشهادة",
|
"certPassword": "كلمة مرور الشهادة",
|
||||||
"certPasswordPlaceholder": "أدخل كلمة مرور الشهادة",
|
"certPasswordPlaceholder": "أدخل كلمة مرور الشهادة",
|
||||||
"certInfo": "معلومات الشهادة",
|
"certInfo": "معلومات الشهادة",
|
||||||
|
|||||||
@@ -732,7 +732,7 @@
|
|||||||
"pageTitle": "Лічбавы подпіс PDF - Дадаць крыптаграфічны подпіс | BentoPDF",
|
"pageTitle": "Лічбавы подпіс PDF - Дадаць крыптаграфічны подпіс | BentoPDF",
|
||||||
"subtitle": "Дадаць крыптаграфічны лічбавы подпіс да PDF з выкарыстаннем сертыфікатаў X.509. Падтрымлівае фарматы PKCS#12 (.pfx, .p12) і PEM. Ваш прыватны ключ ніколі не пакідае ваш браўзер.",
|
"subtitle": "Дадаць крыптаграфічны лічбавы подпіс да PDF з выкарыстаннем сертыфікатаў X.509. Падтрымлівае фарматы PKCS#12 (.pfx, .p12) і PEM. Ваш прыватны ключ ніколі не пакідае ваш браўзер.",
|
||||||
"certificateSection": "Сертыфікат",
|
"certificateSection": "Сертыфікат",
|
||||||
"uploadCert": "Запампаваць сертыфікат (.pfx, .p12)",
|
"uploadCert": "Запампаваць сертыфікат (.pfx, .p12, .pem)",
|
||||||
"certPassword": "Пароль сертыфіката",
|
"certPassword": "Пароль сертыфіката",
|
||||||
"certPasswordPlaceholder": "Увядзіце пароль сертыфіката",
|
"certPasswordPlaceholder": "Увядзіце пароль сертыфіката",
|
||||||
"certInfo": "Інфармацыя пра сертыфікат",
|
"certInfo": "Інфармацыя пра сертыфікат",
|
||||||
|
|||||||
@@ -674,7 +674,7 @@
|
|||||||
"pageTitle": "Digital signatur PDF - Tilføj kryptografisk signatur | BentoPDF",
|
"pageTitle": "Digital signatur PDF - Tilføj kryptografisk signatur | BentoPDF",
|
||||||
"subtitle": "Tilføj en digital signatur til din PDF med X.509-certifikater. Understøtter PKCS#12 (.pfx, .p12) og PEM. Din private nøgle forlader aldrig browseren.",
|
"subtitle": "Tilføj en digital signatur til din PDF med X.509-certifikater. Understøtter PKCS#12 (.pfx, .p12) og PEM. Din private nøgle forlader aldrig browseren.",
|
||||||
"certificateSection": "Certifikat",
|
"certificateSection": "Certifikat",
|
||||||
"uploadCert": "Upload certifikat (.pfx, .p12)",
|
"uploadCert": "Upload certifikat (.pfx, .p12, .pem)",
|
||||||
"certPassword": "Certifikatkodeord",
|
"certPassword": "Certifikatkodeord",
|
||||||
"certPasswordPlaceholder": "Indtast kodeord til certifikat",
|
"certPasswordPlaceholder": "Indtast kodeord til certifikat",
|
||||||
"certInfo": "Certifikatinformation",
|
"certInfo": "Certifikatinformation",
|
||||||
|
|||||||
@@ -261,7 +261,8 @@
|
|||||||
"file": "Datei",
|
"file": "Datei",
|
||||||
"files": "Dateien",
|
"files": "Dateien",
|
||||||
"close": "Schließen",
|
"close": "Schließen",
|
||||||
"convert": "Konvertieren"
|
"convert": "Konvertieren",
|
||||||
|
"unknownError": "Unbekannter Fehler"
|
||||||
},
|
},
|
||||||
"about": {
|
"about": {
|
||||||
"hero": {
|
"hero": {
|
||||||
@@ -357,8 +358,11 @@
|
|||||||
},
|
},
|
||||||
"howItWorks": {
|
"howItWorks": {
|
||||||
"title": "So funktioniert's",
|
"title": "So funktioniert's",
|
||||||
|
"step1Title": "Datei hochladen",
|
||||||
"step1": "Klicken oder Datei hierher ziehen",
|
"step1": "Klicken oder Datei hierher ziehen",
|
||||||
|
"step2Title": "Verarbeiten",
|
||||||
"step2": "Klicken Sie auf die Verarbeitungsschaltfläche",
|
"step2": "Klicken Sie auf die Verarbeitungsschaltfläche",
|
||||||
|
"step3Title": "Herunterladen",
|
||||||
"step3": "Speichern Sie Ihre verarbeitete Datei sofort"
|
"step3": "Speichern Sie Ihre verarbeitete Datei sofort"
|
||||||
},
|
},
|
||||||
"relatedTools": {
|
"relatedTools": {
|
||||||
|
|||||||
+233
-13
@@ -10,6 +10,7 @@
|
|||||||
"input": "Eingabe",
|
"input": "Eingabe",
|
||||||
"output": "Ausgabe"
|
"output": "Ausgabe"
|
||||||
},
|
},
|
||||||
|
"convertToPdf": "In PDF konvertieren",
|
||||||
"pdfMultiTool": {
|
"pdfMultiTool": {
|
||||||
"name": "PDF Multi-Werkzeug",
|
"name": "PDF Multi-Werkzeug",
|
||||||
"subtitle": "Zusammenführen, Teilen, Organisieren, Löschen, Drehen, Leere Seiten hinzufügen, Extrahieren und Duplizieren in einer einheitlichen Oberfläche."
|
"subtitle": "Zusammenführen, Teilen, Organisieren, Löschen, Drehen, Leere Seiten hinzufügen, Extrahieren und Duplizieren in einer einheitlichen Oberfläche."
|
||||||
@@ -72,7 +73,8 @@
|
|||||||
},
|
},
|
||||||
"duplicateOrganize": {
|
"duplicateOrganize": {
|
||||||
"name": "Duplizieren & Organisieren",
|
"name": "Duplizieren & Organisieren",
|
||||||
"subtitle": "Seiten duplizieren, neu anordnen und löschen."
|
"subtitle": "Seiten duplizieren, neu anordnen und löschen.",
|
||||||
|
"saveChanges": "Änderungen speichern"
|
||||||
},
|
},
|
||||||
"deletePages": {
|
"deletePages": {
|
||||||
"name": "Seiten löschen",
|
"name": "Seiten löschen",
|
||||||
@@ -80,11 +82,30 @@
|
|||||||
},
|
},
|
||||||
"editBookmarks": {
|
"editBookmarks": {
|
||||||
"name": "Lesezeichen bearbeiten",
|
"name": "Lesezeichen bearbeiten",
|
||||||
"subtitle": "PDF-Lesezeichen hinzufügen, bearbeiten, importieren, löschen und extrahieren."
|
"subtitle": "PDF-Lesezeichen hinzufügen, bearbeiten, importieren, löschen und extrahieren.",
|
||||||
|
"autoExtractExisting": "Vorhandene Lesezeichen automatisch extrahieren",
|
||||||
|
"importSectionTitle": "Oder Lesezeichen importieren",
|
||||||
|
"csvFormat": "CSV-Format: Titel,Seite,Ebene",
|
||||||
|
"jsonFormat": "JSON-Format",
|
||||||
|
"uploadCsvAction": "Klicken, um CSV hochzuladen",
|
||||||
|
"uploadJsonAction": "Klicken, um JSON hochzuladen",
|
||||||
|
"orDragHere": "oder hierher ziehen"
|
||||||
},
|
},
|
||||||
"tableOfContents": {
|
"tableOfContents": {
|
||||||
"name": "Inhaltsverzeichnis",
|
"name": "Inhaltsverzeichnis",
|
||||||
"subtitle": "Ein Inhaltsverzeichnis aus PDF-Lesezeichen generieren."
|
"subtitle": "Ein Inhaltsverzeichnis aus PDF-Lesezeichen generieren.",
|
||||||
|
"titleLabel": "Inhaltsverzeichnis-Titel",
|
||||||
|
"fontSize": "Schriftgröße",
|
||||||
|
"fontFamily": "Schriftfamilie",
|
||||||
|
"addBookmark": "Lesezeichen für Inhaltsverzeichnis-Seite hinzufügen",
|
||||||
|
"generateButton": "Inhaltsverzeichnis generieren",
|
||||||
|
"selectPdfFirst": "Bitte wählen Sie zuerst eine PDF-Datei aus.",
|
||||||
|
"statusReadingFileMainThread": "Datei wird gelesen (Haupt-Thread)...",
|
||||||
|
"statusGenerating": "Inhaltsverzeichnis wird generiert...",
|
||||||
|
"errorReadingFileWithMessage": "Fehler beim Lesen der Datei: {{message}}",
|
||||||
|
"successGeneratedDownloadStarted": "Inhaltsverzeichnis erfolgreich generiert! Download gestartet.",
|
||||||
|
"workerErrorWithMessage": "Fehler: {{message}}",
|
||||||
|
"workerErrorOccurred": "Worker-Fehler aufgetreten. Details in der Konsole."
|
||||||
},
|
},
|
||||||
"pageNumbers": {
|
"pageNumbers": {
|
||||||
"name": "Seitenzahlen",
|
"name": "Seitenzahlen",
|
||||||
@@ -210,7 +231,8 @@
|
|||||||
"subtitle": "Bildstempel zu Ihrer PDF über die Annotations-Symbolleiste hinzufügen.",
|
"subtitle": "Bildstempel zu Ihrer PDF über die Annotations-Symbolleiste hinzufügen.",
|
||||||
"usernameLabel": "Stempel-Benutzername",
|
"usernameLabel": "Stempel-Benutzername",
|
||||||
"usernamePlaceholder": "Geben Sie Ihren Namen ein (für Stempel)",
|
"usernamePlaceholder": "Geben Sie Ihren Namen ein (für Stempel)",
|
||||||
"usernameHint": "Dieser Name erscheint auf von Ihnen erstellten Stempeln."
|
"usernameHint": "Dieser Name erscheint auf von Ihnen erstellten Stempeln.",
|
||||||
|
"saveButton": "Gestempelte PDF speichern"
|
||||||
},
|
},
|
||||||
"removeAnnotations": {
|
"removeAnnotations": {
|
||||||
"name": "Annotationen entfernen",
|
"name": "Annotationen entfernen",
|
||||||
@@ -218,11 +240,16 @@
|
|||||||
},
|
},
|
||||||
"pdfFormFiller": {
|
"pdfFormFiller": {
|
||||||
"name": "PDF-Formular ausfüllen",
|
"name": "PDF-Formular ausfüllen",
|
||||||
"subtitle": "Formulare direkt im Browser ausfüllen. Unterstützt auch XFA-Formulare."
|
"subtitle": "Formulare direkt im Browser ausfüllen. Unterstützt auch XFA-Formulare.",
|
||||||
|
"uploadHint": "Laden Sie eine PDF mit Formularfeldern hoch. Füllen Sie sie direkt im untenstehenden Viewer aus und klicken Sie dann auf die Schaltfläche, um das ausgefüllte Formular zu speichern und herunterzuladen. Unterstützt auch XFA-Formulare.",
|
||||||
|
"xfaNoteTitle": "Hinweis zu XFA-Formularen:",
|
||||||
|
"xfaNoteDescription": "XFA (XML Forms Architecture) ist ein älteres Format, das nur von bestimmten PDF-Viewern wie BentoPDF und Firefox unterstützt wird. Wenn Sie eine XFA-PDF in anderer Software öffnen und leere Seiten oder keine Formularfelder sehen, bedeutet das, dass dieser Viewer XFA nicht unterstützt. Um XFA-Formulare korrekt anzuzeigen und auszufüllen, verwenden Sie Firefox oder den Formular-Ausfüller von BentoPDF."
|
||||||
},
|
},
|
||||||
"createPdfForm": {
|
"createPdfForm": {
|
||||||
"name": "PDF-Formular erstellen",
|
"name": "PDF-Formular erstellen",
|
||||||
"subtitle": "Ausfüllbare PDF-Formulare mit Drag-and-Drop-Textfeldern erstellen."
|
"subtitle": "Ausfüllbare PDF-Formulare mit Drag-and-Drop-Textfeldern erstellen.",
|
||||||
|
"orSeparator": "ODER",
|
||||||
|
"createBlankPdf": "Leere PDF erstellen"
|
||||||
},
|
},
|
||||||
"removeBlankPages": {
|
"removeBlankPages": {
|
||||||
"name": "Leere Seiten entfernen",
|
"name": "Leere Seiten entfernen",
|
||||||
@@ -259,11 +286,35 @@
|
|||||||
},
|
},
|
||||||
"textToPdf": {
|
"textToPdf": {
|
||||||
"name": "Text zu PDF",
|
"name": "Text zu PDF",
|
||||||
"subtitle": "Eine Textdatei in eine PDF konvertieren."
|
"subtitle": "Eine Textdatei in eine PDF konvertieren.",
|
||||||
|
"uploadFiles": "Dateien hochladen",
|
||||||
|
"typeText": "Text eingeben",
|
||||||
|
"acceptedFormats": "Textdateien (.txt)",
|
||||||
|
"fontFamily": "Schriftfamilie",
|
||||||
|
"fontSize": "Schriftgröße",
|
||||||
|
"textColor": "Textfarbe",
|
||||||
|
"pageSize": "Seitengröße",
|
||||||
|
"rtlAutoDetectNote": "RTL-Sprachen (Arabisch, Urdu, Persisch usw.) werden automatisch erkannt und die Textrichtung wird entsprechend angepasst.",
|
||||||
|
"createButton": "PDF erstellen"
|
||||||
},
|
},
|
||||||
"jsonToPdf": {
|
"jsonToPdf": {
|
||||||
"name": "JSON zu PDF",
|
"name": "JSON zu PDF",
|
||||||
"subtitle": "JSON-Dateien in PDF-Format konvertieren."
|
"subtitle": "JSON-Dateien in PDF-Format konvertieren.",
|
||||||
|
"noteLabel": "Hinweis:",
|
||||||
|
"noteText": "Es werden nur JSON-Dateien unterstützt, die mit dem PDF-zu-JSON-Konverter erstellt wurden. Normale JSON-Dateien aus anderen Tools funktionieren nicht.",
|
||||||
|
"acceptedFormats": "Mehrere JSON-Dateien",
|
||||||
|
"status": {
|
||||||
|
"selectAtLeastOne": "Bitte wählen Sie mindestens 1 JSON-Datei aus",
|
||||||
|
"selectedReady": "{{count}} Datei(en) ausgewählt. Bereit zur Konvertierung!",
|
||||||
|
"readingFiles": "Dateien werden gelesen (Haupt-Thread)...",
|
||||||
|
"converting": "JSON-Dateien werden in PDFs konvertiert...",
|
||||||
|
"readError": "Fehler beim Lesen der Dateien: {{message}}",
|
||||||
|
"creatingZip": "ZIP-Datei wird erstellt...",
|
||||||
|
"success": "JSON-Dateien erfolgreich in PDF konvertiert! ZIP-Download wurde gestartet.",
|
||||||
|
"zipError": "Fehler beim Erstellen der ZIP-Datei: {{message}}",
|
||||||
|
"workerError": "Worker-Fehler: {{message}}",
|
||||||
|
"getStarted": "Wählen Sie JSON-Dateien aus, um zu starten"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"pdfToJpg": {
|
"pdfToJpg": {
|
||||||
"name": "PDF zu JPG",
|
"name": "PDF zu JPG",
|
||||||
@@ -379,11 +430,75 @@
|
|||||||
},
|
},
|
||||||
"pdfToJson": {
|
"pdfToJson": {
|
||||||
"name": "PDF zu JSON",
|
"name": "PDF zu JSON",
|
||||||
"subtitle": "PDF-Dateien in JSON-Format konvertieren."
|
"subtitle": "PDF-Dateien in JSON-Format konvertieren.",
|
||||||
|
"convertButton": "In JSON konvertieren",
|
||||||
|
"status": {
|
||||||
|
"selectAtLeastOne": "Bitte wählen Sie mindestens 1 PDF-Datei aus",
|
||||||
|
"selectedReady": "{{count}} Datei(en) ausgewählt. Bereit zur Konvertierung!",
|
||||||
|
"checkingEncrypted": "Es wird auf verschlüsselte PDFs geprüft...",
|
||||||
|
"readingFiles": "Dateien werden gelesen (Haupt-Thread)...",
|
||||||
|
"converting": "PDFs werden in JSON konvertiert...",
|
||||||
|
"readError": "Fehler beim Lesen der Dateien: {{message}}",
|
||||||
|
"creatingZip": "ZIP-Datei wird erstellt...",
|
||||||
|
"success": "PDFs erfolgreich in JSON konvertiert! ZIP-Download wurde gestartet.",
|
||||||
|
"zipError": "Fehler beim Erstellen der ZIP-Datei: {{message}}",
|
||||||
|
"workerError": "Worker-Fehler: {{message}}",
|
||||||
|
"getStarted": "Wählen Sie PDF-Dateien aus, um zu starten"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"ocrPdf": {
|
"ocrPdf": {
|
||||||
"name": "OCR PDF",
|
"name": "OCR PDF",
|
||||||
"subtitle": "Eine PDF durchsuchbar und kopierbar machen."
|
"subtitle": "Eine PDF durchsuchbar und kopierbar machen.",
|
||||||
|
"languagesInDocument": "Sprachen im Dokument",
|
||||||
|
"searchLanguagesPlaceholder": "Nach Sprachen suchen...",
|
||||||
|
"selectedLabel": "Ausgewählt:",
|
||||||
|
"none": "Keine",
|
||||||
|
"advancedSettingsSummary": "Erweiterte Einstellungen (empfohlen zur Verbesserung der Genauigkeit)",
|
||||||
|
"resolutionLabel": "Auflösung",
|
||||||
|
"resolutionStandard": "Standard (192 DPI)",
|
||||||
|
"resolutionHigh": "Hoch (288 DPI)",
|
||||||
|
"resolutionUltra": "Ultra (384 DPI)",
|
||||||
|
"binarizeLabel": "In Schwarz-Weiß umwandeln (Kontrast für saubere Scans verbessern)",
|
||||||
|
"embedFullFontsLabel": "Vollständige Schriftarten einbetten (größere Datei, bessere Kompatibilität)",
|
||||||
|
"whitelistPresetLabel": "Zeichen-Whitelist-Voreinstellung",
|
||||||
|
"whitelistNone": "Keine (alle Zeichen)",
|
||||||
|
"whitelistAlphanumeric": "Alphanumerisch + grundlegende Satzzeichen",
|
||||||
|
"whitelistNumbersCurrency": "Zahlen + Währungssymbole",
|
||||||
|
"whitelistLettersOnly": "Nur Buchstaben (A-Z, a-z)",
|
||||||
|
"whitelistNumbersOnly": "Nur Zahlen (0-9)",
|
||||||
|
"whitelistInvoice": "Rechnung/Beleg (Zahlen, $, ., -, /)",
|
||||||
|
"whitelistForms": "Formulare (alphanumerisch + gängige Symbole)",
|
||||||
|
"whitelistCustom": "Benutzerdefiniert...",
|
||||||
|
"whitelistHelp": "Nur diese Zeichen werden erkannt. Für alle Zeichen leer lassen.",
|
||||||
|
"whitelistInputLabel": "Zeichen-Whitelist (optional)",
|
||||||
|
"whitelistInputPlaceholder": "z. B. abcdefghijklmnopqrstuvwxyz0123456789$.,",
|
||||||
|
"startButton": "OCR starten",
|
||||||
|
"progressInitializing": "Wird initialisiert...",
|
||||||
|
"resultsTitle": "OCR abgeschlossen",
|
||||||
|
"resultsDescription": "Ihre durchsuchbare PDF ist bereit. Sie können den extrahierten Text unten auch kopieren oder herunterladen.",
|
||||||
|
"copyToClipboard": "In Zwischenablage kopieren",
|
||||||
|
"downloadTxt": "Als .txt herunterladen",
|
||||||
|
"downloadSearchablePdf": "Durchsuchbare PDF herunterladen",
|
||||||
|
"statusPrefix": "Status: {{status}}",
|
||||||
|
"availabilityInvalidConfig": "Diese Bereitstellung stellt keine gültigen OCR-Sprachen bereit. Erstellen Sie sie mit VITE_TESSERACT_AVAILABLE_LANGUAGES neu und setzen Sie gültige Tesseract-Codes.",
|
||||||
|
"availabilityBundles": "Diese Bereitstellung enthält OCR für: {{languages}}.",
|
||||||
|
"noLanguagesAvailable": "In dieser Bereitstellung sind keine OCR-Sprachen verfügbar.",
|
||||||
|
"noLanguagesTitle": "Keine Sprachen ausgewählt",
|
||||||
|
"noLanguagesMessage": "Bitte wählen Sie mindestens eine Sprache für OCR aus.",
|
||||||
|
"noFileTitle": "Keine Datei",
|
||||||
|
"noFileMessage": "Bitte laden Sie zuerst eine PDF-Datei hoch.",
|
||||||
|
"languageUnavailableTitle": "OCR-Sprache nicht verfügbar",
|
||||||
|
"ocrErrorTitle": "OCR-Fehler",
|
||||||
|
"ocrErrorMessage": "Während des OCR-Prozesses ist ein Fehler aufgetreten. Der Worker konnte möglicherweise nicht geladen werden. Bitte versuchen Sie es erneut.",
|
||||||
|
"howItWorksTitle": "So funktioniert es:",
|
||||||
|
"extractTextLabel": "Text extrahieren:",
|
||||||
|
"extractTextDescription": "Verwendet Tesseract OCR, um Text aus gescannten Bildern oder PDFs zu erkennen.",
|
||||||
|
"searchableOutputLabel": "Durchsuchbare Ausgabe:",
|
||||||
|
"searchableOutputDescription": "Erstellt eine neue PDF mit einer unsichtbaren Textebene, sodass Ihr Dokument vollständig durchsuchbar wird, während das ursprüngliche Erscheinungsbild erhalten bleibt.",
|
||||||
|
"characterFilteringLabel": "Zeichenfilterung:",
|
||||||
|
"characterFilteringDescription": "Verwenden Sie Whitelists, um unerwünschte Zeichen herauszufiltern und die Genauigkeit für bestimmte Dokumenttypen zu verbessern (Rechnungen, Formulare usw.).",
|
||||||
|
"multiLanguageSupportLabel": "Mehrsprachige Unterstützung:",
|
||||||
|
"multiLanguageSupportDescription": "Wählen Sie mehrere Sprachen für Dokumente mit gemischten Sprachinhalten aus."
|
||||||
},
|
},
|
||||||
"alternateMerge": {
|
"alternateMerge": {
|
||||||
"name": "Seiten abwechselnd mischen",
|
"name": "Seiten abwechselnd mischen",
|
||||||
@@ -716,7 +831,8 @@
|
|||||||
"pdfToText": {
|
"pdfToText": {
|
||||||
"name": "PDF zu Text",
|
"name": "PDF zu Text",
|
||||||
"subtitle": "Text aus PDF-Dateien extrahieren und als Textdatei (.txt) speichern. Unterstützt mehrere Dateien.",
|
"subtitle": "Text aus PDF-Dateien extrahieren und als Textdatei (.txt) speichern. Unterstützt mehrere Dateien.",
|
||||||
"note": "Dieses Tool funktioniert NUR mit digital erstellten PDFs. Für gescannte Dokumente oder bildbasierte PDFs verwenden Sie stattdessen unser OCR PDF-Tool.",
|
"noteLabel": "Hinweis:",
|
||||||
|
"noteText": "Dieses Tool funktioniert NUR mit digital erstellten PDFs. Für gescannte Dokumente oder bildbasierte PDFs verwenden Sie stattdessen unser OCR PDF-Tool.",
|
||||||
"convertButton": "Text extrahieren"
|
"convertButton": "Text extrahieren"
|
||||||
},
|
},
|
||||||
"digitalSignPdf": {
|
"digitalSignPdf": {
|
||||||
@@ -724,8 +840,9 @@
|
|||||||
"pageTitle": "Digitale PDF-Signatur - Kryptografische Signatur hinzufügen | BentoPDF",
|
"pageTitle": "Digitale PDF-Signatur - Kryptografische Signatur hinzufügen | BentoPDF",
|
||||||
"subtitle": "Fügen Sie eine kryptografische digitale Signatur mit X.509-Zertifikaten zu Ihrer PDF hinzu. Unterstützt PKCS#12 (.pfx, .p12) und PEM-Formate. Ihr privater Schlüssel verlässt niemals Ihren Browser.",
|
"subtitle": "Fügen Sie eine kryptografische digitale Signatur mit X.509-Zertifikaten zu Ihrer PDF hinzu. Unterstützt PKCS#12 (.pfx, .p12) und PEM-Formate. Ihr privater Schlüssel verlässt niemals Ihren Browser.",
|
||||||
"certificateSection": "Zertifikat",
|
"certificateSection": "Zertifikat",
|
||||||
"uploadCert": "Zertifikat hochladen (.pfx, .p12)",
|
"uploadCert": "Zertifikat hochladen (.pfx, .p12, .pem)",
|
||||||
"certPassword": "Zertifikat-Passwort",
|
"certPassword": "Zertifikat-Passwort",
|
||||||
|
"privateKeyPassword": "Passwort für privaten Schlüssel",
|
||||||
"certPasswordPlaceholder": "Zertifikat-Passwort eingeben",
|
"certPasswordPlaceholder": "Zertifikat-Passwort eingeben",
|
||||||
"certInfo": "Zertifikat-Informationen",
|
"certInfo": "Zertifikat-Informationen",
|
||||||
"certSubject": "Betreff",
|
"certSubject": "Betreff",
|
||||||
@@ -738,8 +855,71 @@
|
|||||||
"locationPlaceholder": "z.B. Berlin, Deutschland",
|
"locationPlaceholder": "z.B. Berlin, Deutschland",
|
||||||
"contactInfo": "Kontaktdaten",
|
"contactInfo": "Kontaktdaten",
|
||||||
"contactPlaceholder": "z.B. email@beispiel.de",
|
"contactPlaceholder": "z.B. email@beispiel.de",
|
||||||
|
"visibleSignature": "Sichtbare Signatur",
|
||||||
|
"visibleSignatureDescription": "Wenn aktiviert, erscheint ein sichtbares Signaturfeld in der PDF. Sie können ein Bild/Logo hochladen oder Text hinzufügen. Falls keines von beidem angegeben ist, wird automatisch der Name des Unterzeichners aus dem Zertifikat angezeigt.",
|
||||||
|
"signatureImage": "Signaturbild/Logo (optional)",
|
||||||
|
"uploadSignatureImage": "Bild hochladen (PNG, JPG, WebP)",
|
||||||
|
"signaturePreviewAlt": "Signaturvorschau",
|
||||||
|
"remove": "Entfernen",
|
||||||
|
"page": "Seite",
|
||||||
|
"firstPage": "Erste Seite",
|
||||||
|
"lastPage": "Letzte Seite",
|
||||||
|
"allPages": "Alle Seiten",
|
||||||
|
"customPage": "Benutzerdefinierte Seite #",
|
||||||
|
"pageNumber": "Seite #",
|
||||||
|
"xPosition": "X-Position (links)",
|
||||||
|
"yPosition": "Y-Position (oben)",
|
||||||
|
"width": "Breite",
|
||||||
|
"height": "Höhe",
|
||||||
|
"addTextOverlay": "Textüberlagerung hinzufügen",
|
||||||
|
"text": "Text",
|
||||||
|
"textPlaceholder": "z.B. Digital signiert von Max Mustermann",
|
||||||
|
"textColor": "Textfarbe",
|
||||||
|
"fontSize": "Schriftgröße",
|
||||||
|
"invalidImageTitle": "Ungültiges Bild",
|
||||||
|
"invalidImageMessage": "Bitte wählen Sie ein PNG-, JPG- oder WebP-Bild.",
|
||||||
|
"invalidFileTitle": "Ungültige Datei",
|
||||||
|
"invalidFileMessage": "Bitte wählen Sie eine PDF-Datei aus.",
|
||||||
|
"invalidCertificateTitle": "Ungültiges Zertifikat",
|
||||||
|
"invalidCertificateMessage": "Bitte wählen Sie eine Zertifikatsdatei im Format .pfx, .p12 oder .pem aus.",
|
||||||
|
"certificateLoaded": "Zertifikat geladen",
|
||||||
|
"certificateUnlocked": "Zertifikat entsperrt",
|
||||||
|
"failedParsePem": "PEM-Datei konnte nicht geparst werden",
|
||||||
|
"enterPasswordToUnlock": "Passwort zum Entsperren eingeben",
|
||||||
|
"invalidPasswordOrCertificate": "Ungültiges Passwort oder Zertifikat",
|
||||||
|
"incorrectPassword": "Falsches Passwort",
|
||||||
|
"failedParseCertificate": "Zertifikat konnte nicht geparst werden",
|
||||||
|
"missingDataTitle": "Fehlende Daten",
|
||||||
|
"missingDataMessage": "Bitte laden Sie sowohl eine PDF als auch ein gültiges Zertifikat hoch.",
|
||||||
|
"applyingSignature": "Digitale Signatur wird angewendet...",
|
||||||
|
"signingFailedTitle": "Signieren fehlgeschlagen",
|
||||||
|
"chainFetchFailed": "Die Zertifikatskette konnte nicht abgerufen werden. Dies kann an Netzwerkproblemen oder einem nicht verfügbaren Zertifikats-Proxy liegen. Bitte prüfen Sie Ihre Internetverbindung und versuchen Sie es erneut. Wenn das Problem weiterhin besteht, kontaktieren Sie den Support.",
|
||||||
|
"failedToSignPdf": "PDF konnte nicht signiert werden: {{message}}",
|
||||||
|
"defaultSignatureText": "Digital signiert von {{signer}}\n{{date}}",
|
||||||
|
"pageCount": "{{count}} Seiten",
|
||||||
|
"howToStep1Title": "PDF hochladen",
|
||||||
|
"howToStep1Text": "Wählen Sie das PDF-Dokument aus, das Sie signieren möchten",
|
||||||
|
"howToStep2Title": "Zertifikat hochladen",
|
||||||
|
"howToStep2Text": "Stellen Sie Ihre .pfx- oder .p12-Zertifikatsdatei und das Passwort bereit",
|
||||||
|
"howToStep3Title": "Signieren & herunterladen",
|
||||||
|
"howToStep3Text": "Wenden Sie die digitale Signatur an und laden Sie Ihr signiertes PDF herunter",
|
||||||
|
"relatedEncryptDesc": "PDF mit Passwort schützen",
|
||||||
|
"relatedDecryptDesc": "PDF-Passwort entfernen",
|
||||||
|
"relatedFlattenDesc": "Anmerkungen dauerhaft machen",
|
||||||
|
"relatedSanitizeDesc": "Versteckte Daten entfernen",
|
||||||
|
"relatedPermissionsDesc": "PDF-Berechtigungen festlegen",
|
||||||
|
"faqWhatIsQuestion": "Was ist eine digitale Signatur?",
|
||||||
|
"faqWhatIsAnswer": "Eine digitale Signatur ist ein kryptografischer Mechanismus, der die Authentizität und Integrität eines Dokuments verifiziert. Anders als eine gezeichnete Signatur verwendet sie Public-Key-Kryptografie (X.509-Zertifikate), um die Identität des Unterzeichners nachzuweisen.",
|
||||||
|
"faqFormatsQuestion": "Welche Zertifikatsformate werden unterstützt?",
|
||||||
|
"faqFormatsAnswer": "Wir unterstützen Zertifikate im PKCS#12-Format (.pfx, .p12), die sowohl Ihr Zertifikat als auch den privaten Schlüssel in einer einzigen verschlüsselten Datei enthalten. Diese werden häufig von Zertifizierungsstellen ausgegeben.",
|
||||||
|
"faqPrivateKeyQuestion": "Ist mein privater Schlüssel sicher?",
|
||||||
|
"faqPrivateKeyAnswer": "Ja! Die gesamte Verarbeitung erfolgt vollständig in Ihrem Browser. Ihr Zertifikat, privater Schlüssel und Ihre PDF-Dateien verlassen Ihr Gerät niemals und werden auf keinen Server hochgeladen.",
|
||||||
|
"faqValidReadersQuestion": "Ist die Signatur in PDF-Readern gültig?",
|
||||||
|
"faqValidReadersAnswer": "Ja, das Tool erstellt standardmäßige PKCS#7-Detached-Signaturen, die von allen großen PDF-Viewern erkannt werden. Für eine vollständige Validierung verwenden Sie ein Zertifikat einer vertrauenswürdigen Zertifizierungsstelle.",
|
||||||
"applySignature": "Digitale Signatur anwenden",
|
"applySignature": "Digitale Signatur anwenden",
|
||||||
"successMessage": "PDF erfolgreich signiert! Die Signatur kann in jedem PDF-Reader überprüft werden."
|
"successMessage": "PDF erfolgreich signiert! Die Signatur kann in jedem PDF-Reader überprüft werden.",
|
||||||
|
"internetRequiredTitle": "Internetverbindung erforderlich",
|
||||||
|
"internetRequiredDescription": "Beim Signieren müssen möglicherweise Informationen zur Zertifikatskette vom Server Ihres Zertifikatsausstellers abgerufen werden, um die Signatur zu validieren."
|
||||||
},
|
},
|
||||||
"validateSignaturePdf": {
|
"validateSignaturePdf": {
|
||||||
"name": "PDF-Signatur überprüfen",
|
"name": "PDF-Signatur überprüfen",
|
||||||
@@ -896,6 +1076,46 @@
|
|||||||
"failedToImport": "Workflow konnte nicht importiert werden: {{message}}"
|
"failedToImport": "Workflow konnte nicht importiert werden: {{message}}"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"wasmSettings": {
|
||||||
|
"title": "Erweiterte Feature-Einstellungen",
|
||||||
|
"description": "Konfigurieren Sie externe Verarbeitungsmodule, um erweiterte PDF-Funktionen zu aktivieren. Diese Module sind optional und separat lizenziert.",
|
||||||
|
"status": {
|
||||||
|
"testing": "Wird getestet...",
|
||||||
|
"customOverride": "Benutzerdefinierte Überschreibung",
|
||||||
|
"preConfigured": "Vorkonfiguriert",
|
||||||
|
"notConfigured": "Nicht konfiguriert"
|
||||||
|
},
|
||||||
|
"preconfiguredTitle": "Vorkonfiguriert und einsatzbereit.",
|
||||||
|
"preconfiguredDescription": "Erweiterte Verarbeitungsmodule werden automatisch über ein CDN geladen. Sie können die untenstehenden URLs überschreiben, wenn Sie eine benutzerdefinierte Quelle verwenden möchten (z. B. für Air-Gap- oder Self-Hosting-Bereitstellungen).",
|
||||||
|
"usingDefault": "Standard wird verwendet: {{url}}",
|
||||||
|
"pymupdfSubtitle": "Dokumentenverarbeitungs-Engine",
|
||||||
|
"pymupdfFeatures": "Aktiviert: PDF zu Text, Markdown, SVG, DOCX, Excel • Bilder/Tabellen extrahieren • Formatkonvertierung",
|
||||||
|
"testButton": "Testen",
|
||||||
|
"recommendedLabel": "Empfohlen:",
|
||||||
|
"copyTitle": "In Zwischenablage kopieren",
|
||||||
|
"ghostscriptSubtitle": "PDF/A-Konvertierungs-Engine",
|
||||||
|
"ghostscriptFeatures": "Aktiviert: PDF/A-1b-, PDF/A-2b-, PDF/A-3b-Konvertierung • Schriftarten in Pfade umwandeln",
|
||||||
|
"cpdfSubtitle": "Lesezeichen- & Metadaten-Engine",
|
||||||
|
"cpdfFeatures": "Aktiviert: Nach Lesezeichen aufteilen • Lesezeichen bearbeiten • PDF-Metadaten",
|
||||||
|
"saveConfiguration": "Konfiguration speichern",
|
||||||
|
"savingConfiguration": "Konfiguration wird gespeichert...",
|
||||||
|
"savedTitle": "Gespeichert",
|
||||||
|
"savedMessage": "Konfiguration erfolgreich gespeichert!",
|
||||||
|
"errorTitle": "Fehler",
|
||||||
|
"failedSave": "Konfiguration konnte nicht gespeichert werden: {{message}}",
|
||||||
|
"emptyUrlTitle": "Leere URL",
|
||||||
|
"emptyUrlMessage": "Bitte geben Sie eine URL zum Testen ein.",
|
||||||
|
"testSuccessTitle": "Erfolg",
|
||||||
|
"connectionSuccess": "Verbindung zu {{package}} erfolgreich!",
|
||||||
|
"connectionFailedTitle": "Verbindung fehlgeschlagen",
|
||||||
|
"connectionFailedMessage": "Verbindung zur URL konnte nicht hergestellt werden.",
|
||||||
|
"resetDefaults": "Auf Standard zurücksetzen",
|
||||||
|
"resetTitle": "Zurückgesetzt",
|
||||||
|
"resetWithDefaults": "Benutzerdefinierte Überschreibungen wurden entfernt. Vorkonfigurierte Standardwerte sind aktiv.",
|
||||||
|
"resetNoDefaults": "Alle Konfigurationen und zwischengespeicherten Module wurden gelöscht.",
|
||||||
|
"licenseTitle": "Lizenzhinweis:",
|
||||||
|
"licenseDescription": "Die externen Module (PyMuPDF, Ghostscript, CoherentPDF) sind unter AGPL-3.0 oder ähnlichen Copyleft-Lizenzen lizenziert. Durch das Konfigurieren und Verwenden dieser Module stimmen Sie den jeweiligen Lizenzbedingungen zu. BentoPDF ist mit jeder Ghostscript-WASM- und PyMuPDF-WASM-Implementierung kompatibel, die der erwarteten Schnittstelle folgt."
|
||||||
|
},
|
||||||
"pdfOverlay": {
|
"pdfOverlay": {
|
||||||
"name": "PDF-Überlagerung",
|
"name": "PDF-Überlagerung",
|
||||||
"subtitle": "Seiten eines PDFs über oder unter die Seiten eines anderen PDFs legen.",
|
"subtitle": "Seiten eines PDFs über oder unter die Seiten eines anderen PDFs legen.",
|
||||||
|
|||||||
@@ -100,8 +100,11 @@
|
|||||||
},
|
},
|
||||||
"howItWorks": {
|
"howItWorks": {
|
||||||
"title": "How It Works",
|
"title": "How It Works",
|
||||||
|
"step1Title": "Upload File",
|
||||||
"step1": "Click or drag and drop your file to begin",
|
"step1": "Click or drag and drop your file to begin",
|
||||||
|
"step2Title": "Process",
|
||||||
"step2": "Click the process button to start",
|
"step2": "Click the process button to start",
|
||||||
|
"step3Title": "Download",
|
||||||
"step3": "Save your processed file instantly"
|
"step3": "Save your processed file instantly"
|
||||||
},
|
},
|
||||||
"relatedTools": {
|
"relatedTools": {
|
||||||
@@ -273,7 +276,8 @@
|
|||||||
"file": "File",
|
"file": "File",
|
||||||
"files": "Files",
|
"files": "Files",
|
||||||
"close": "Close",
|
"close": "Close",
|
||||||
"convert": "Convert"
|
"convert": "Convert",
|
||||||
|
"unknownError": "Unknown error"
|
||||||
},
|
},
|
||||||
"about": {
|
"about": {
|
||||||
"hero": {
|
"hero": {
|
||||||
|
|||||||
+233
-13
@@ -10,6 +10,7 @@
|
|||||||
"input": "Input",
|
"input": "Input",
|
||||||
"output": "Output"
|
"output": "Output"
|
||||||
},
|
},
|
||||||
|
"convertToPdf": "Convert to PDF",
|
||||||
"pdfMultiTool": {
|
"pdfMultiTool": {
|
||||||
"name": "PDF Multi Tool",
|
"name": "PDF Multi Tool",
|
||||||
"subtitle": "Merge, Split, Organize, Delete, Rotate, Add Blank Pages, Extract and Duplicate in an unified interface."
|
"subtitle": "Merge, Split, Organize, Delete, Rotate, Add Blank Pages, Extract and Duplicate in an unified interface."
|
||||||
@@ -72,7 +73,8 @@
|
|||||||
},
|
},
|
||||||
"duplicateOrganize": {
|
"duplicateOrganize": {
|
||||||
"name": "Duplicate & Organize",
|
"name": "Duplicate & Organize",
|
||||||
"subtitle": "Duplicate, reorder, and delete pages."
|
"subtitle": "Duplicate, reorder, and delete pages.",
|
||||||
|
"saveChanges": "Save Changes"
|
||||||
},
|
},
|
||||||
"deletePages": {
|
"deletePages": {
|
||||||
"name": "Delete Pages",
|
"name": "Delete Pages",
|
||||||
@@ -80,11 +82,30 @@
|
|||||||
},
|
},
|
||||||
"editBookmarks": {
|
"editBookmarks": {
|
||||||
"name": "Edit Bookmarks",
|
"name": "Edit Bookmarks",
|
||||||
"subtitle": "Add, edit, import, delete and extract PDF bookmarks."
|
"subtitle": "Add, edit, import, delete and extract PDF bookmarks.",
|
||||||
|
"autoExtractExisting": "Auto-extract existing bookmarks",
|
||||||
|
"importSectionTitle": "Or Import Bookmarks",
|
||||||
|
"csvFormat": "CSV format: title,page,level",
|
||||||
|
"jsonFormat": "JSON format",
|
||||||
|
"uploadCsvAction": "Click to upload CSV",
|
||||||
|
"uploadJsonAction": "Click to upload JSON",
|
||||||
|
"orDragHere": "or drag here"
|
||||||
},
|
},
|
||||||
"tableOfContents": {
|
"tableOfContents": {
|
||||||
"name": "Table of Contents",
|
"name": "Table of Contents",
|
||||||
"subtitle": "Generate a table of contents page from PDF bookmarks."
|
"subtitle": "Generate a table of contents page from PDF bookmarks.",
|
||||||
|
"titleLabel": "TOC Title",
|
||||||
|
"fontSize": "Font Size",
|
||||||
|
"fontFamily": "Font Family",
|
||||||
|
"addBookmark": "Add bookmark for TOC page",
|
||||||
|
"generateButton": "Generate Table of Contents",
|
||||||
|
"selectPdfFirst": "Please select a PDF file first.",
|
||||||
|
"statusReadingFileMainThread": "Reading file (Main Thread)...",
|
||||||
|
"statusGenerating": "Generating table of contents...",
|
||||||
|
"errorReadingFileWithMessage": "Error reading file: {{message}}",
|
||||||
|
"successGeneratedDownloadStarted": "Table of contents generated successfully! Download started.",
|
||||||
|
"workerErrorWithMessage": "Error: {{message}}",
|
||||||
|
"workerErrorOccurred": "Worker error occurred. Check console for details."
|
||||||
},
|
},
|
||||||
"pageNumbers": {
|
"pageNumbers": {
|
||||||
"name": "Page Numbers",
|
"name": "Page Numbers",
|
||||||
@@ -210,7 +231,8 @@
|
|||||||
"subtitle": "Add image stamps to your PDF using the annotation toolbar.",
|
"subtitle": "Add image stamps to your PDF using the annotation toolbar.",
|
||||||
"usernameLabel": "Stamp Username",
|
"usernameLabel": "Stamp Username",
|
||||||
"usernamePlaceholder": "Enter your name (for stamps)",
|
"usernamePlaceholder": "Enter your name (for stamps)",
|
||||||
"usernameHint": "This name will appear on stamps you create."
|
"usernameHint": "This name will appear on stamps you create.",
|
||||||
|
"saveButton": "Save Stamped PDF"
|
||||||
},
|
},
|
||||||
"removeAnnotations": {
|
"removeAnnotations": {
|
||||||
"name": "Remove Annotations",
|
"name": "Remove Annotations",
|
||||||
@@ -218,11 +240,16 @@
|
|||||||
},
|
},
|
||||||
"pdfFormFiller": {
|
"pdfFormFiller": {
|
||||||
"name": "PDF Form Filler",
|
"name": "PDF Form Filler",
|
||||||
"subtitle": "Fill in forms directly in the browser. Also supports XFA forms."
|
"subtitle": "Fill in forms directly in the browser. Also supports XFA forms.",
|
||||||
|
"uploadHint": "Upload a PDF with form fields. Fill them directly in the viewer below, then click the button to save and download the filled form. Also supports XFA forms.",
|
||||||
|
"xfaNoteTitle": "Note on XFA Forms:",
|
||||||
|
"xfaNoteDescription": "XFA (XML Forms Architecture) is a legacy format that's only supported by certain PDF viewers like BentoPDF and Firefox. If you open an XFA PDF in other software and see blank pages or no form fields, it means that viewer doesn't support XFA. To view and fill XFA forms properly, use Firefox or BentoPDF's Form Filler."
|
||||||
},
|
},
|
||||||
"createPdfForm": {
|
"createPdfForm": {
|
||||||
"name": "Create PDF Form",
|
"name": "Create PDF Form",
|
||||||
"subtitle": "Create fillable PDF forms with drag-and-drop text fields."
|
"subtitle": "Create fillable PDF forms with drag-and-drop text fields.",
|
||||||
|
"orSeparator": "OR",
|
||||||
|
"createBlankPdf": "Create Blank PDF"
|
||||||
},
|
},
|
||||||
"removeBlankPages": {
|
"removeBlankPages": {
|
||||||
"name": "Remove Blank Pages",
|
"name": "Remove Blank Pages",
|
||||||
@@ -259,11 +286,35 @@
|
|||||||
},
|
},
|
||||||
"textToPdf": {
|
"textToPdf": {
|
||||||
"name": "Text to PDF",
|
"name": "Text to PDF",
|
||||||
"subtitle": "Convert a plain text file into a PDF."
|
"subtitle": "Convert a plain text file into a PDF.",
|
||||||
|
"uploadFiles": "Upload Files",
|
||||||
|
"typeText": "Type Text",
|
||||||
|
"acceptedFormats": "Text files (.txt)",
|
||||||
|
"fontFamily": "Font Family",
|
||||||
|
"fontSize": "Font Size",
|
||||||
|
"textColor": "Text Color",
|
||||||
|
"pageSize": "Page Size",
|
||||||
|
"rtlAutoDetectNote": "RTL languages (Arabic, Urdu, Persian, etc.) are automatically detected and text direction is adjusted.",
|
||||||
|
"createButton": "Create PDF"
|
||||||
},
|
},
|
||||||
"jsonToPdf": {
|
"jsonToPdf": {
|
||||||
"name": "JSON to PDF",
|
"name": "JSON to PDF",
|
||||||
"subtitle": "Convert JSON files to PDF format."
|
"subtitle": "Convert JSON files to PDF format.",
|
||||||
|
"noteLabel": "Note:",
|
||||||
|
"noteText": "Only JSON files created by the PDF-to-JSON converter tool are supported. Standard JSON files from other tools will not work.",
|
||||||
|
"acceptedFormats": "Multiple JSON files",
|
||||||
|
"status": {
|
||||||
|
"selectAtLeastOne": "Please select at least 1 JSON file",
|
||||||
|
"selectedReady": "{{count}} file(s) selected. Ready to convert!",
|
||||||
|
"readingFiles": "Reading files (Main Thread)...",
|
||||||
|
"converting": "Converting JSON files to PDFs...",
|
||||||
|
"readError": "Error reading files: {{message}}",
|
||||||
|
"creatingZip": "Creating ZIP file...",
|
||||||
|
"success": "JSON files converted to PDF successfully! ZIP download started.",
|
||||||
|
"zipError": "Error creating ZIP: {{message}}",
|
||||||
|
"workerError": "Worker Error: {{message}}",
|
||||||
|
"getStarted": "Select JSON files to get started"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"pdfToJpg": {
|
"pdfToJpg": {
|
||||||
"name": "PDF to JPG",
|
"name": "PDF to JPG",
|
||||||
@@ -387,11 +438,75 @@
|
|||||||
},
|
},
|
||||||
"pdfToJson": {
|
"pdfToJson": {
|
||||||
"name": "PDF to JSON",
|
"name": "PDF to JSON",
|
||||||
"subtitle": "Convert PDF files to JSON format."
|
"subtitle": "Convert PDF files to JSON format.",
|
||||||
|
"convertButton": "Convert to JSON",
|
||||||
|
"status": {
|
||||||
|
"selectAtLeastOne": "Please select at least 1 PDF file",
|
||||||
|
"selectedReady": "{{count}} file(s) selected. Ready to convert!",
|
||||||
|
"checkingEncrypted": "Checking for encrypted PDFs...",
|
||||||
|
"readingFiles": "Reading files (Main Thread)...",
|
||||||
|
"converting": "Converting PDFs to JSON...",
|
||||||
|
"readError": "Error reading files: {{message}}",
|
||||||
|
"creatingZip": "Creating ZIP file...",
|
||||||
|
"success": "PDFs converted to JSON successfully! ZIP download started.",
|
||||||
|
"zipError": "Error creating ZIP: {{message}}",
|
||||||
|
"workerError": "Worker Error: {{message}}",
|
||||||
|
"getStarted": "Select PDF files to get started"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"ocrPdf": {
|
"ocrPdf": {
|
||||||
"name": "OCR PDF",
|
"name": "OCR PDF",
|
||||||
"subtitle": "Make a PDF searchable and copyable."
|
"subtitle": "Make a PDF searchable and copyable.",
|
||||||
|
"languagesInDocument": "Languages in Document",
|
||||||
|
"searchLanguagesPlaceholder": "Search for languages...",
|
||||||
|
"selectedLabel": "Selected:",
|
||||||
|
"none": "None",
|
||||||
|
"advancedSettingsSummary": "Advanced Settings (Recommended to improve accuracy)",
|
||||||
|
"resolutionLabel": "Resolution",
|
||||||
|
"resolutionStandard": "Standard (192 DPI)",
|
||||||
|
"resolutionHigh": "High (288 DPI)",
|
||||||
|
"resolutionUltra": "Ultra (384 DPI)",
|
||||||
|
"binarizeLabel": "Binarize Image (Enhance Contrast for Clean Scans)",
|
||||||
|
"embedFullFontsLabel": "Embed Full Fonts (Larger file, better compatibility)",
|
||||||
|
"whitelistPresetLabel": "Character Whitelist Preset",
|
||||||
|
"whitelistNone": "None (All characters)",
|
||||||
|
"whitelistAlphanumeric": "Alphanumeric + Basic Punctuation",
|
||||||
|
"whitelistNumbersCurrency": "Numbers + Currency Symbols",
|
||||||
|
"whitelistLettersOnly": "Letters Only (A-Z, a-z)",
|
||||||
|
"whitelistNumbersOnly": "Numbers Only (0-9)",
|
||||||
|
"whitelistInvoice": "Invoice/Receipt (Numbers, $, ., -, /)",
|
||||||
|
"whitelistForms": "Forms (Alphanumeric + Common Symbols)",
|
||||||
|
"whitelistCustom": "Custom...",
|
||||||
|
"whitelistHelp": "Only these characters will be recognized. Leave empty for all characters.",
|
||||||
|
"whitelistInputLabel": "Character Whitelist (Optional)",
|
||||||
|
"whitelistInputPlaceholder": "e.g., abcdefghijklmnopqrstuvwxyz0123456789$.,",
|
||||||
|
"startButton": "Start OCR",
|
||||||
|
"progressInitializing": "Initializing...",
|
||||||
|
"resultsTitle": "OCR Complete",
|
||||||
|
"resultsDescription": "Your searchable PDF is ready. You can also copy or download the extracted text below.",
|
||||||
|
"copyToClipboard": "Copy to Clipboard",
|
||||||
|
"downloadTxt": "Download as .txt",
|
||||||
|
"downloadSearchablePdf": "Download Searchable PDF",
|
||||||
|
"statusPrefix": "Status: {{status}}",
|
||||||
|
"availabilityInvalidConfig": "This deployment does not expose any valid OCR languages. Rebuild it with VITE_TESSERACT_AVAILABLE_LANGUAGES set to valid Tesseract codes.",
|
||||||
|
"availabilityBundles": "This deployment bundles OCR for: {{languages}}.",
|
||||||
|
"noLanguagesAvailable": "No OCR languages are available in this deployment.",
|
||||||
|
"noLanguagesTitle": "No Languages Selected",
|
||||||
|
"noLanguagesMessage": "Please select at least one language for OCR.",
|
||||||
|
"noFileTitle": "No File",
|
||||||
|
"noFileMessage": "Please upload a PDF file first.",
|
||||||
|
"languageUnavailableTitle": "OCR Language Not Available",
|
||||||
|
"ocrErrorTitle": "OCR Error",
|
||||||
|
"ocrErrorMessage": "An error occurred during the OCR process. The worker may have failed to load. Please try again.",
|
||||||
|
"howItWorksTitle": "How it works:",
|
||||||
|
"extractTextLabel": "Extract Text:",
|
||||||
|
"extractTextDescription": "Uses Tesseract OCR to recognize text from scanned images or PDFs.",
|
||||||
|
"searchableOutputLabel": "Searchable Output:",
|
||||||
|
"searchableOutputDescription": "Creates a new PDF with an invisible text layer, making your document fully searchable while preserving the original appearance.",
|
||||||
|
"characterFilteringLabel": "Character Filtering:",
|
||||||
|
"characterFilteringDescription": "Use whitelists to filter out unwanted characters and improve accuracy for specific document types (invoices, forms, etc.).",
|
||||||
|
"multiLanguageSupportLabel": "Multi-language Support:",
|
||||||
|
"multiLanguageSupportDescription": "Select multiple languages for documents containing mixed language content."
|
||||||
},
|
},
|
||||||
"alternateMerge": {
|
"alternateMerge": {
|
||||||
"name": "Alternate & Mix Pages",
|
"name": "Alternate & Mix Pages",
|
||||||
@@ -724,7 +839,8 @@
|
|||||||
"pdfToText": {
|
"pdfToText": {
|
||||||
"name": "PDF to Text",
|
"name": "PDF to Text",
|
||||||
"subtitle": "Extract text from PDF files and save as plain text (.txt). Supports multiple files.",
|
"subtitle": "Extract text from PDF files and save as plain text (.txt). Supports multiple files.",
|
||||||
"note": "This tool works ONLY with digitally created PDFs. For scanned documents or image-based PDFs, use our OCR PDF tool instead.",
|
"noteLabel": "Note:",
|
||||||
|
"noteText": "This tool works ONLY with digitally created PDFs. For scanned documents or image-based PDFs, use our OCR PDF tool instead.",
|
||||||
"convertButton": "Extract Text"
|
"convertButton": "Extract Text"
|
||||||
},
|
},
|
||||||
"digitalSignPdf": {
|
"digitalSignPdf": {
|
||||||
@@ -732,8 +848,9 @@
|
|||||||
"pageTitle": "Digital Signature PDF - Add Cryptographic Signature | BentoPDF",
|
"pageTitle": "Digital Signature PDF - Add Cryptographic Signature | BentoPDF",
|
||||||
"subtitle": "Add a cryptographic digital signature to your PDF using X.509 certificates. Supports PKCS#12 (.pfx, .p12) and PEM formats. Your private key never leaves your browser.",
|
"subtitle": "Add a cryptographic digital signature to your PDF using X.509 certificates. Supports PKCS#12 (.pfx, .p12) and PEM formats. Your private key never leaves your browser.",
|
||||||
"certificateSection": "Certificate",
|
"certificateSection": "Certificate",
|
||||||
"uploadCert": "Upload certificate (.pfx, .p12)",
|
"uploadCert": "Upload certificate (.pfx, .p12, .pem)",
|
||||||
"certPassword": "Certificate Password",
|
"certPassword": "Certificate Password",
|
||||||
|
"privateKeyPassword": "Private Key Password",
|
||||||
"certPasswordPlaceholder": "Enter certificate password",
|
"certPasswordPlaceholder": "Enter certificate password",
|
||||||
"certInfo": "Certificate Information",
|
"certInfo": "Certificate Information",
|
||||||
"certSubject": "Subject",
|
"certSubject": "Subject",
|
||||||
@@ -746,8 +863,71 @@
|
|||||||
"locationPlaceholder": "e.g., New York, USA",
|
"locationPlaceholder": "e.g., New York, USA",
|
||||||
"contactInfo": "Contact Info",
|
"contactInfo": "Contact Info",
|
||||||
"contactPlaceholder": "e.g., email@example.com",
|
"contactPlaceholder": "e.g., email@example.com",
|
||||||
|
"visibleSignature": "Visible Signature",
|
||||||
|
"visibleSignatureDescription": "When enabled, a visible signature box appears on the PDF. You can upload an image/logo or add text. If neither is provided, the signer's name from the certificate will be shown automatically.",
|
||||||
|
"signatureImage": "Signature Image/Logo (Optional)",
|
||||||
|
"uploadSignatureImage": "Upload image (PNG, JPG, WebP)",
|
||||||
|
"signaturePreviewAlt": "Signature preview",
|
||||||
|
"remove": "Remove",
|
||||||
|
"page": "Page",
|
||||||
|
"firstPage": "First page",
|
||||||
|
"lastPage": "Last page",
|
||||||
|
"allPages": "All pages",
|
||||||
|
"customPage": "Custom page #",
|
||||||
|
"pageNumber": "Page #",
|
||||||
|
"xPosition": "X Position (left)",
|
||||||
|
"yPosition": "Y Position (top)",
|
||||||
|
"width": "Width",
|
||||||
|
"height": "Height",
|
||||||
|
"addTextOverlay": "Add text overlay",
|
||||||
|
"text": "Text",
|
||||||
|
"textPlaceholder": "e.g., Digitally signed by John Doe",
|
||||||
|
"textColor": "Text Color",
|
||||||
|
"fontSize": "Font Size",
|
||||||
|
"invalidImageTitle": "Invalid Image",
|
||||||
|
"invalidImageMessage": "Please select a PNG, JPG, or WebP image.",
|
||||||
|
"invalidFileTitle": "Invalid File",
|
||||||
|
"invalidFileMessage": "Please select a PDF file.",
|
||||||
|
"invalidCertificateTitle": "Invalid Certificate",
|
||||||
|
"invalidCertificateMessage": "Please select a .pfx, .p12, or .pem certificate file.",
|
||||||
|
"certificateLoaded": "Certificate loaded",
|
||||||
|
"certificateUnlocked": "Certificate unlocked",
|
||||||
|
"failedParsePem": "Failed to parse PEM file",
|
||||||
|
"enterPasswordToUnlock": "Enter password to unlock",
|
||||||
|
"invalidPasswordOrCertificate": "Invalid password or certificate",
|
||||||
|
"incorrectPassword": "Incorrect password",
|
||||||
|
"failedParseCertificate": "Failed to parse certificate",
|
||||||
|
"missingDataTitle": "Missing Data",
|
||||||
|
"missingDataMessage": "Please upload both a PDF and a valid certificate.",
|
||||||
|
"applyingSignature": "Applying digital signature...",
|
||||||
|
"signingFailedTitle": "Signing Failed",
|
||||||
|
"chainFetchFailed": "Failed to fetch certificate chain. This may be due to network issues or the certificate proxy being unavailable. Please check your internet connection and try again. If the issue persists, contact support.",
|
||||||
|
"failedToSignPdf": "Failed to sign PDF: {{message}}",
|
||||||
|
"defaultSignatureText": "Digitally signed by {{signer}}\n{{date}}",
|
||||||
|
"pageCount": "{{count}} pages",
|
||||||
|
"howToStep1Title": "Upload PDF",
|
||||||
|
"howToStep1Text": "Select the PDF document you want to sign",
|
||||||
|
"howToStep2Title": "Upload Certificate",
|
||||||
|
"howToStep2Text": "Provide your .pfx or .p12 certificate file and password",
|
||||||
|
"howToStep3Title": "Sign & Download",
|
||||||
|
"howToStep3Text": "Apply the digital signature and download your signed PDF",
|
||||||
|
"relatedEncryptDesc": "Password protect your PDF",
|
||||||
|
"relatedDecryptDesc": "Remove PDF password",
|
||||||
|
"relatedFlattenDesc": "Make annotations permanent",
|
||||||
|
"relatedSanitizeDesc": "Remove hidden data",
|
||||||
|
"relatedPermissionsDesc": "Set PDF permissions",
|
||||||
|
"faqWhatIsQuestion": "What is a digital signature?",
|
||||||
|
"faqWhatIsAnswer": "A digital signature is a cryptographic mechanism that verifies the authenticity and integrity of a document. Unlike a drawn signature, it uses public key cryptography (X.509 certificates) to prove the signer's identity.",
|
||||||
|
"faqFormatsQuestion": "What certificate formats are supported?",
|
||||||
|
"faqFormatsAnswer": "We support PKCS#12 format certificates (.pfx, .p12) which contain both your certificate and private key in a single encrypted file. These are commonly issued by certificate authorities.",
|
||||||
|
"faqPrivateKeyQuestion": "Is my private key safe?",
|
||||||
|
"faqPrivateKeyAnswer": "Yes! All processing happens entirely in your browser. Your certificate, private key, and PDF files never leave your device or get uploaded to any server.",
|
||||||
|
"faqValidReadersQuestion": "Will the signature be valid in PDF readers?",
|
||||||
|
"faqValidReadersAnswer": "Yes, the tool creates standard PKCS#7 detached signatures that are recognized by all major PDF viewers. For full validation, use a certificate from a trusted Certificate Authority.",
|
||||||
"applySignature": "Apply Digital Signature",
|
"applySignature": "Apply Digital Signature",
|
||||||
"successMessage": "PDF signed successfully! The signature can be verified in any PDF reader."
|
"successMessage": "PDF signed successfully! The signature can be verified in any PDF reader.",
|
||||||
|
"internetRequiredTitle": "Internet connection required",
|
||||||
|
"internetRequiredDescription": "Signing may need to fetch certificate chain information from your certificate issuer's server to validate the signature."
|
||||||
},
|
},
|
||||||
"validateSignaturePdf": {
|
"validateSignaturePdf": {
|
||||||
"name": "Validate PDF Signature",
|
"name": "Validate PDF Signature",
|
||||||
@@ -904,6 +1084,46 @@
|
|||||||
"failedToImport": "Failed to import workflow: {{message}}"
|
"failedToImport": "Failed to import workflow: {{message}}"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"wasmSettings": {
|
||||||
|
"title": "Advanced Features Settings",
|
||||||
|
"description": "Configure external processing modules to enable advanced PDF features. These modules are optional and licensed separately.",
|
||||||
|
"status": {
|
||||||
|
"testing": "Testing...",
|
||||||
|
"customOverride": "Custom Override",
|
||||||
|
"preConfigured": "Pre-configured",
|
||||||
|
"notConfigured": "Not Configured"
|
||||||
|
},
|
||||||
|
"preconfiguredTitle": "Pre-configured and ready to use.",
|
||||||
|
"preconfiguredDescription": "Advanced processing modules are loaded automatically from CDN. You can override the URLs below if you need to use a custom source (e.g., for air-gapped or self-hosted deployments).",
|
||||||
|
"usingDefault": "Using default: {{url}}",
|
||||||
|
"pymupdfSubtitle": "Document Processing Engine",
|
||||||
|
"pymupdfFeatures": "Enables: PDF to Text, Markdown, SVG, DOCX, Excel • Extract Images/Tables • Format Conversion",
|
||||||
|
"testButton": "Test",
|
||||||
|
"recommendedLabel": "Recommended:",
|
||||||
|
"copyTitle": "Copy to clipboard",
|
||||||
|
"ghostscriptSubtitle": "PDF/A Conversion Engine",
|
||||||
|
"ghostscriptFeatures": "Enables: PDF/A-1b, PDF/A-2b, PDF/A-3b Conversion • Font to Outline",
|
||||||
|
"cpdfSubtitle": "Bookmarks & Metadata Engine",
|
||||||
|
"cpdfFeatures": "Enables: Split by Bookmarks • Edit Bookmarks • PDF Metadata",
|
||||||
|
"saveConfiguration": "Save Configuration",
|
||||||
|
"savingConfiguration": "Saving configuration...",
|
||||||
|
"savedTitle": "Saved",
|
||||||
|
"savedMessage": "Configuration saved successfully!",
|
||||||
|
"errorTitle": "Error",
|
||||||
|
"failedSave": "Failed to save configuration: {{message}}",
|
||||||
|
"emptyUrlTitle": "Empty URL",
|
||||||
|
"emptyUrlMessage": "Please enter a URL to test.",
|
||||||
|
"testSuccessTitle": "Success",
|
||||||
|
"connectionSuccess": "Connection to {{package}} successful!",
|
||||||
|
"connectionFailedTitle": "Connection Failed",
|
||||||
|
"connectionFailedMessage": "Could not connect to the URL.",
|
||||||
|
"resetDefaults": "Reset to Defaults",
|
||||||
|
"resetTitle": "Reset",
|
||||||
|
"resetWithDefaults": "Custom overrides cleared. Pre-configured defaults are active.",
|
||||||
|
"resetNoDefaults": "All configurations and cached modules have been cleared.",
|
||||||
|
"licenseTitle": "License Notice:",
|
||||||
|
"licenseDescription": "The external modules (PyMuPDF, Ghostscript, CoherentPDF) are licensed under AGPL-3.0 or similar copyleft licenses. By configuring and using these modules, you agree to their respective license terms. BentoPDF is compatible with any Ghostscript WASM and PyMuPDF WASM implementation that follows the expected interface."
|
||||||
|
},
|
||||||
"pdfOverlay": {
|
"pdfOverlay": {
|
||||||
"name": "PDF Overlay",
|
"name": "PDF Overlay",
|
||||||
"subtitle": "Overlay or underlay pages from one PDF onto another.",
|
"subtitle": "Overlay or underlay pages from one PDF onto another.",
|
||||||
|
|||||||
@@ -674,7 +674,7 @@
|
|||||||
"pageTitle": "Firma Digital PDF - Agregar Firma Criptográfica | BentoPDF",
|
"pageTitle": "Firma Digital PDF - Agregar Firma Criptográfica | BentoPDF",
|
||||||
"subtitle": "Agrega una firma digital criptográfica a tu PDF usando certificados X.509. Soporta formatos PKCS#12 (.pfx, .p12) y PEM. Tu clave privada nunca sale de tu navegador.",
|
"subtitle": "Agrega una firma digital criptográfica a tu PDF usando certificados X.509. Soporta formatos PKCS#12 (.pfx, .p12) y PEM. Tu clave privada nunca sale de tu navegador.",
|
||||||
"certificateSection": "Certificado",
|
"certificateSection": "Certificado",
|
||||||
"uploadCert": "Cargar certificado (.pfx, .p12)",
|
"uploadCert": "Cargar certificado (.pfx, .p12, .pem)",
|
||||||
"certPassword": "Contraseña del Certificado",
|
"certPassword": "Contraseña del Certificado",
|
||||||
"certPasswordPlaceholder": "Ingresa la contraseña del certificado",
|
"certPasswordPlaceholder": "Ingresa la contraseña del certificado",
|
||||||
"certInfo": "Información del Certificado",
|
"certInfo": "Información del Certificado",
|
||||||
|
|||||||
@@ -674,7 +674,7 @@
|
|||||||
"pageTitle": "Signature numérique PDF - Ajouter une signature cryptographique | BentoPDF",
|
"pageTitle": "Signature numérique PDF - Ajouter une signature cryptographique | BentoPDF",
|
||||||
"subtitle": "Ajouter une signature numérique cryptographique à votre PDF à l’aide de certificats X.509. Prend en charge les formats PKCS#12 (.pfx, .p12) et PEM. Votre clé privée ne quitte jamais votre navigateur.",
|
"subtitle": "Ajouter une signature numérique cryptographique à votre PDF à l’aide de certificats X.509. Prend en charge les formats PKCS#12 (.pfx, .p12) et PEM. Votre clé privée ne quitte jamais votre navigateur.",
|
||||||
"certificateSection": "Certificat",
|
"certificateSection": "Certificat",
|
||||||
"uploadCert": "Téléverser un certificat (.pfx, .p12)",
|
"uploadCert": "Téléverser un certificat (.pfx, .p12, .pem)",
|
||||||
"certPassword": "Mot de passe du certificat",
|
"certPassword": "Mot de passe du certificat",
|
||||||
"certPasswordPlaceholder": "Saisissez le mot de passe du certificat",
|
"certPasswordPlaceholder": "Saisissez le mot de passe du certificat",
|
||||||
"certInfo": "Informations du certificat",
|
"certInfo": "Informations du certificat",
|
||||||
|
|||||||
@@ -674,7 +674,7 @@
|
|||||||
"pageTitle": "Tanda Tangan Digital PDF - Tambah Tanda Tangan Kriptografi | BentoPDF",
|
"pageTitle": "Tanda Tangan Digital PDF - Tambah Tanda Tangan Kriptografi | BentoPDF",
|
||||||
"subtitle": "Tambah tanda tangan digital kriptografi ke PDF Anda menggunakan sertifikat X.509. Mendukung format PKCS#12 (.pfx, .p12) dan PEM. Kunci pribadi Anda tidak pernah meninggalkan browser Anda.",
|
"subtitle": "Tambah tanda tangan digital kriptografi ke PDF Anda menggunakan sertifikat X.509. Mendukung format PKCS#12 (.pfx, .p12) dan PEM. Kunci pribadi Anda tidak pernah meninggalkan browser Anda.",
|
||||||
"certificateSection": "Sertifikat",
|
"certificateSection": "Sertifikat",
|
||||||
"uploadCert": "Unggah sertifikat (.pfx, .p12)",
|
"uploadCert": "Unggah sertifikat (.pfx, .p12, .pem)",
|
||||||
"certPassword": "Kata Sandi Sertifikat",
|
"certPassword": "Kata Sandi Sertifikat",
|
||||||
"certPasswordPlaceholder": "Masukkan kata sandi sertifikat",
|
"certPasswordPlaceholder": "Masukkan kata sandi sertifikat",
|
||||||
"certInfo": "Informasi Sertifikat",
|
"certInfo": "Informasi Sertifikat",
|
||||||
|
|||||||
@@ -674,7 +674,7 @@
|
|||||||
"pageTitle": "Firma digitale PDF - Aggiungi firma crittografica | BentoPDF",
|
"pageTitle": "Firma digitale PDF - Aggiungi firma crittografica | BentoPDF",
|
||||||
"subtitle": "Aggiungi una firma digitale crittografica al tuo PDF usando certificati X.509. Supporta i formati PKCS#12 (.pfx, .p12) e PEM. La tua chiave privata non lascia mai il browser.",
|
"subtitle": "Aggiungi una firma digitale crittografica al tuo PDF usando certificati X.509. Supporta i formati PKCS#12 (.pfx, .p12) e PEM. La tua chiave privata non lascia mai il browser.",
|
||||||
"certificateSection": "Certificato",
|
"certificateSection": "Certificato",
|
||||||
"uploadCert": "Carica certificato (.pfx, .p12)",
|
"uploadCert": "Carica certificato (.pfx, .p12, .pem)",
|
||||||
"certPassword": "Password del certificato",
|
"certPassword": "Password del certificato",
|
||||||
"certPasswordPlaceholder": "Inserisci la password del certificato",
|
"certPasswordPlaceholder": "Inserisci la password del certificato",
|
||||||
"certInfo": "Informazioni sul certificato",
|
"certInfo": "Informazioni sul certificato",
|
||||||
|
|||||||
@@ -674,7 +674,7 @@
|
|||||||
"pageTitle": "PDF 디지털 서명 - 암호화 서명 추가 | BentoPDF",
|
"pageTitle": "PDF 디지털 서명 - 암호화 서명 추가 | BentoPDF",
|
||||||
"subtitle": "X.509 인증서를 사용하여 PDF에 암호화 디지털 서명을 추가합니다. PKCS#12(.pfx, .p12) 및 PEM 형식을 지원합니다. 개인키는 브라우저 밖으로 나가지 않습니다.",
|
"subtitle": "X.509 인증서를 사용하여 PDF에 암호화 디지털 서명을 추가합니다. PKCS#12(.pfx, .p12) 및 PEM 형식을 지원합니다. 개인키는 브라우저 밖으로 나가지 않습니다.",
|
||||||
"certificateSection": "인증서",
|
"certificateSection": "인증서",
|
||||||
"uploadCert": "인증서 업로드 (.pfx, .p12)",
|
"uploadCert": "인증서 업로드 (.pfx, .p12, .pem)",
|
||||||
"certPassword": "인증서 비밀번호",
|
"certPassword": "인증서 비밀번호",
|
||||||
"certPasswordPlaceholder": "인증서 비밀번호 입력",
|
"certPasswordPlaceholder": "인증서 비밀번호 입력",
|
||||||
"certInfo": "인증서 정보",
|
"certInfo": "인증서 정보",
|
||||||
|
|||||||
@@ -732,7 +732,7 @@
|
|||||||
"pageTitle": "Digitale handtekening - Cryptografische handtekening toevoegen | BentoPDF",
|
"pageTitle": "Digitale handtekening - Cryptografische handtekening toevoegen | BentoPDF",
|
||||||
"subtitle": "Een cryptografische digitale handtekening toevoegen aan een PDF met behulp van X.509-certificaten. Ondersteunt PKCS#12 (.pfx, .p12) en PEM-formaten. Jouw privésleutel blijft op jouw browser.",
|
"subtitle": "Een cryptografische digitale handtekening toevoegen aan een PDF met behulp van X.509-certificaten. Ondersteunt PKCS#12 (.pfx, .p12) en PEM-formaten. Jouw privésleutel blijft op jouw browser.",
|
||||||
"certificateSection": "Certificaat",
|
"certificateSection": "Certificaat",
|
||||||
"uploadCert": "Certificaat laden (.pfx, .p12)",
|
"uploadCert": "Certificaat laden (.pfx, .p12, .pem)",
|
||||||
"certPassword": "Certificaatwachtwoord",
|
"certPassword": "Certificaatwachtwoord",
|
||||||
"certPasswordPlaceholder": "Voer het wachtwoord van het certificaat in",
|
"certPasswordPlaceholder": "Voer het wachtwoord van het certificaat in",
|
||||||
"certInfo": "Certificaatinformatie",
|
"certInfo": "Certificaatinformatie",
|
||||||
|
|||||||
@@ -688,7 +688,7 @@
|
|||||||
"pageTitle": "Assinatura Digital PDF - Adicionar Assinatura Criptográfica | BentoPDF",
|
"pageTitle": "Assinatura Digital PDF - Adicionar Assinatura Criptográfica | BentoPDF",
|
||||||
"subtitle": "Adicione uma assinatura digital criptográfica ao seu PDF usando certificados X.509. Suporta formatos PKCS#12 (.pfx, .p12) e PEM. Sua chave privada nunca sai do seu navegador.",
|
"subtitle": "Adicione uma assinatura digital criptográfica ao seu PDF usando certificados X.509. Suporta formatos PKCS#12 (.pfx, .p12) e PEM. Sua chave privada nunca sai do seu navegador.",
|
||||||
"certificateSection": "Certificado",
|
"certificateSection": "Certificado",
|
||||||
"uploadCert": "Carregar certificado (.pfx, .p12)",
|
"uploadCert": "Carregar certificado (.pfx, .p12, .pem)",
|
||||||
"certPassword": "Senha do Certificado",
|
"certPassword": "Senha do Certificado",
|
||||||
"certPasswordPlaceholder": "Digite a senha",
|
"certPasswordPlaceholder": "Digite a senha",
|
||||||
"certInfo": "Informações do Certificado",
|
"certInfo": "Informações do Certificado",
|
||||||
|
|||||||
@@ -628,7 +628,7 @@
|
|||||||
"pageTitle": "Цифровая подпись PDF - Добавить криптографическую подпись | BentoPDF",
|
"pageTitle": "Цифровая подпись PDF - Добавить криптографическую подпись | BentoPDF",
|
||||||
"subtitle": "Добавить криптографическую цифровую подпись в PDF-файл, используя сертификаты X.509. Поддерживает форматы PKCS#12 (.pfx, .p12) и PEM. Ваш приватный ключ не покидает браузер.",
|
"subtitle": "Добавить криптографическую цифровую подпись в PDF-файл, используя сертификаты X.509. Поддерживает форматы PKCS#12 (.pfx, .p12) и PEM. Ваш приватный ключ не покидает браузер.",
|
||||||
"certificateSection": "Сертификат",
|
"certificateSection": "Сертификат",
|
||||||
"uploadCert": "Загрузить сертификат (.pfx, .p12)",
|
"uploadCert": "Загрузить сертификат (.pfx, .p12, .pem)",
|
||||||
"certPassword": "Пароль от сертификата",
|
"certPassword": "Пароль от сертификата",
|
||||||
"certPasswordPlaceholder": "Введите Пароль от сертификата",
|
"certPasswordPlaceholder": "Введите Пароль от сертификата",
|
||||||
"certInfo": "Сведения о сертификате",
|
"certInfo": "Сведения о сертификате",
|
||||||
|
|||||||
@@ -674,7 +674,7 @@
|
|||||||
"pageTitle": "Digital signatur PDF - Lägg till kryptografisk signatur | BentoPDF",
|
"pageTitle": "Digital signatur PDF - Lägg till kryptografisk signatur | BentoPDF",
|
||||||
"subtitle": "Lägg till en kryptografisk digital signatur på din PDF med X.509-certifikat. Stöder PKCS#12 (.pfx, .p12) och PEM-format. Din privata nyckel lämnar aldrig din webbläsare.",
|
"subtitle": "Lägg till en kryptografisk digital signatur på din PDF med X.509-certifikat. Stöder PKCS#12 (.pfx, .p12) och PEM-format. Din privata nyckel lämnar aldrig din webbläsare.",
|
||||||
"certificateSection": "Certifikat",
|
"certificateSection": "Certifikat",
|
||||||
"uploadCert": "Ladda upp certifikat (.pfx, .p12)",
|
"uploadCert": "Ladda upp certifikat (.pfx, .p12, .pem)",
|
||||||
"certPassword": "Certifikatlösenord",
|
"certPassword": "Certifikatlösenord",
|
||||||
"certPasswordPlaceholder": "Ange certifikatlösenord",
|
"certPasswordPlaceholder": "Ange certifikatlösenord",
|
||||||
"certInfo": "Certifikatinformation",
|
"certInfo": "Certifikatinformation",
|
||||||
|
|||||||
@@ -688,7 +688,7 @@
|
|||||||
"pageTitle": "Digital Signature PDF - Add Cryptographic Signature | BentoPDF",
|
"pageTitle": "Digital Signature PDF - Add Cryptographic Signature | BentoPDF",
|
||||||
"subtitle": "Add a cryptographic digital signature to your PDF using X.509 certificates. Supports PKCS#12 (.pfx, .p12) and PEM formats. Your private key never leaves your browser.",
|
"subtitle": "Add a cryptographic digital signature to your PDF using X.509 certificates. Supports PKCS#12 (.pfx, .p12) and PEM formats. Your private key never leaves your browser.",
|
||||||
"certificateSection": "Certificate",
|
"certificateSection": "Certificate",
|
||||||
"uploadCert": "Upload certificate (.pfx, .p12)",
|
"uploadCert": "Upload certificate (.pfx, .p12, .pem)",
|
||||||
"certPassword": "Certificate Password",
|
"certPassword": "Certificate Password",
|
||||||
"certPasswordPlaceholder": "Enter certificate password",
|
"certPasswordPlaceholder": "Enter certificate password",
|
||||||
"certInfo": "Certificate Information",
|
"certInfo": "Certificate Information",
|
||||||
|
|||||||
@@ -674,7 +674,7 @@
|
|||||||
"pageTitle": "Chữ ký số PDF - Thêm chữ ký mật mã | BentoPDF",
|
"pageTitle": "Chữ ký số PDF - Thêm chữ ký mật mã | BentoPDF",
|
||||||
"subtitle": "Thêm chữ ký số mật mã vào PDF của bạn bằng chứng chỉ X.509. Hỗ trợ định dạng PKCS#12 (.pfx, .p12) và PEM. Khóa riêng của bạn không bao giờ rời khỏi trình duyệt.",
|
"subtitle": "Thêm chữ ký số mật mã vào PDF của bạn bằng chứng chỉ X.509. Hỗ trợ định dạng PKCS#12 (.pfx, .p12) và PEM. Khóa riêng của bạn không bao giờ rời khỏi trình duyệt.",
|
||||||
"certificateSection": "Chứng chỉ",
|
"certificateSection": "Chứng chỉ",
|
||||||
"uploadCert": "Tải lên chứng chỉ (.pfx, .p12)",
|
"uploadCert": "Tải lên chứng chỉ (.pfx, .p12, .pem)",
|
||||||
"certPassword": "Mật khẩu chứng chỉ",
|
"certPassword": "Mật khẩu chứng chỉ",
|
||||||
"certPasswordPlaceholder": "Nhập mật khẩu chứng chỉ",
|
"certPasswordPlaceholder": "Nhập mật khẩu chứng chỉ",
|
||||||
"certInfo": "Thông tin chứng chỉ",
|
"certInfo": "Thông tin chứng chỉ",
|
||||||
|
|||||||
@@ -688,7 +688,7 @@
|
|||||||
"pageTitle": "Digital Signature PDF - Add Cryptographic Signature | BentoPDF",
|
"pageTitle": "Digital Signature PDF - Add Cryptographic Signature | BentoPDF",
|
||||||
"subtitle": "Add a cryptographic digital signature to your PDF using X.509 certificates. Supports PKCS#12 (.pfx, .p12) and PEM formats. Your private key never leaves your browser.",
|
"subtitle": "Add a cryptographic digital signature to your PDF using X.509 certificates. Supports PKCS#12 (.pfx, .p12) and PEM formats. Your private key never leaves your browser.",
|
||||||
"certificateSection": "Certificate",
|
"certificateSection": "Certificate",
|
||||||
"uploadCert": "Upload certificate (.pfx, .p12)",
|
"uploadCert": "Upload certificate (.pfx, .p12, .pem)",
|
||||||
"certPassword": "Certificate Password",
|
"certPassword": "Certificate Password",
|
||||||
"certPasswordPlaceholder": "Enter certificate password",
|
"certPasswordPlaceholder": "Enter certificate password",
|
||||||
"certInfo": "Certificate Information",
|
"certInfo": "Certificate Information",
|
||||||
|
|||||||
@@ -674,7 +674,7 @@
|
|||||||
"pageTitle": "PDF 数字签名 - 添加加密签名 | BentoPDF",
|
"pageTitle": "PDF 数字签名 - 添加加密签名 | BentoPDF",
|
||||||
"subtitle": "使用 X.509 证书为您的 PDF 添加加密数字签名。支持 PKCS#12 (.pfx, .p12) 和 PEM 格式。您的私钥永远不会离开您的浏览器。",
|
"subtitle": "使用 X.509 证书为您的 PDF 添加加密数字签名。支持 PKCS#12 (.pfx, .p12) 和 PEM 格式。您的私钥永远不会离开您的浏览器。",
|
||||||
"certificateSection": "证书",
|
"certificateSection": "证书",
|
||||||
"uploadCert": "上传证书 (.pfx, .p12)",
|
"uploadCert": "上传证书 (.pfx, .p12, .pem)",
|
||||||
"certPassword": "证书密码",
|
"certPassword": "证书密码",
|
||||||
"certPasswordPlaceholder": "输入证书密码",
|
"certPasswordPlaceholder": "输入证书密码",
|
||||||
"certInfo": "证书信息",
|
"certInfo": "证书信息",
|
||||||
|
|||||||
@@ -190,8 +190,8 @@ function initializePage(): void {
|
|||||||
const validTypes = ['image/png', 'image/jpeg', 'image/webp'];
|
const validTypes = ['image/png', 'image/jpeg', 'image/webp'];
|
||||||
if (!validTypes.includes(file.type)) {
|
if (!validTypes.includes(file.type)) {
|
||||||
showAlert(
|
showAlert(
|
||||||
'Invalid Image',
|
t('tools:digitalSignPdf.invalidImageTitle'),
|
||||||
'Please select a PNG, JPG, or WebP image.'
|
t('tools:digitalSignPdf.invalidImageMessage')
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -249,7 +249,10 @@ async function handlePdfFile(file: File): Promise<void> {
|
|||||||
file.type !== 'application/pdf' &&
|
file.type !== 'application/pdf' &&
|
||||||
!file.name.toLowerCase().endsWith('.pdf')
|
!file.name.toLowerCase().endsWith('.pdf')
|
||||||
) {
|
) {
|
||||||
showAlert('Invalid File', 'Please select a PDF file.');
|
showAlert(
|
||||||
|
t('tools:digitalSignPdf.invalidFileTitle'),
|
||||||
|
t('tools:digitalSignPdf.invalidFileMessage')
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -314,7 +317,7 @@ async function updatePdfDisplay(): Promise<void> {
|
|||||||
state.pdfFile = result.file;
|
state.pdfFile = result.file;
|
||||||
state.pdfBytes = new Uint8Array(result.bytes);
|
state.pdfBytes = new Uint8Array(result.bytes);
|
||||||
nameSpan.textContent = result.file.name;
|
nameSpan.textContent = result.file.name;
|
||||||
metaSpan.textContent = `${formatBytes(result.file.size)} • ${result.pdf.numPages} pages`;
|
metaSpan.textContent = `${formatBytes(result.file.size)} • ${t('tools:digitalSignPdf.pageCount', { count: result.pdf.numPages })}`;
|
||||||
result.pdf.destroy();
|
result.pdf.destroy();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -373,8 +376,8 @@ async function handleCertFile(file: File): Promise<void> {
|
|||||||
|
|
||||||
if (!hasValidExtension) {
|
if (!hasValidExtension) {
|
||||||
showAlert(
|
showAlert(
|
||||||
'Invalid Certificate',
|
t('tools:digitalSignPdf.invalidCertificateTitle'),
|
||||||
'Please select a .pfx, .p12, or .pem certificate file.'
|
t('tools:digitalSignPdf.invalidCertificateMessage')
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -393,7 +396,7 @@ async function handleCertFile(file: File): Promise<void> {
|
|||||||
|
|
||||||
if (isEncrypted) {
|
if (isEncrypted) {
|
||||||
showPasswordSection();
|
showPasswordSection();
|
||||||
updatePasswordLabel('Private Key Password');
|
updatePasswordLabel(t('tools:digitalSignPdf.privateKeyPassword'));
|
||||||
} else {
|
} else {
|
||||||
state.certData = parseCombinedPem(pemContent);
|
state.certData = parseCombinedPem(pemContent);
|
||||||
updateCertInfo();
|
updateCertInfo();
|
||||||
@@ -401,8 +404,7 @@ async function handleCertFile(file: File): Promise<void> {
|
|||||||
|
|
||||||
const certStatus = getElement<HTMLDivElement>('cert-status');
|
const certStatus = getElement<HTMLDivElement>('cert-status');
|
||||||
if (certStatus) {
|
if (certStatus) {
|
||||||
certStatus.innerHTML =
|
certStatus.innerHTML = `${t('tools:digitalSignPdf.certificateLoaded')} <i data-lucide="check" class="inline w-4 h-4"></i>`;
|
||||||
'Certificate loaded <i data-lucide="check" class="inline w-4 h-4"></i>';
|
|
||||||
createIcons({ icons });
|
createIcons({ icons });
|
||||||
certStatus.className = 'text-xs text-green-400';
|
certStatus.className = 'text-xs text-green-400';
|
||||||
}
|
}
|
||||||
@@ -410,13 +412,13 @@ async function handleCertFile(file: File): Promise<void> {
|
|||||||
} catch {
|
} catch {
|
||||||
const certStatus = getElement<HTMLDivElement>('cert-status');
|
const certStatus = getElement<HTMLDivElement>('cert-status');
|
||||||
if (certStatus) {
|
if (certStatus) {
|
||||||
certStatus.textContent = 'Failed to parse PEM file';
|
certStatus.textContent = t('tools:digitalSignPdf.failedParsePem');
|
||||||
certStatus.className = 'text-xs text-red-400';
|
certStatus.className = 'text-xs text-red-400';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
showPasswordSection();
|
showPasswordSection();
|
||||||
updatePasswordLabel('Certificate Password');
|
updatePasswordLabel(t('tools:digitalSignPdf.certPassword'));
|
||||||
}
|
}
|
||||||
|
|
||||||
hideSignatureOptions();
|
hideSignatureOptions();
|
||||||
@@ -444,7 +446,7 @@ function updateCertDisplay(): void {
|
|||||||
const metaSpan = document.createElement('div');
|
const metaSpan = document.createElement('div');
|
||||||
metaSpan.className = 'text-xs text-gray-400';
|
metaSpan.className = 'text-xs text-gray-400';
|
||||||
metaSpan.id = 'cert-status';
|
metaSpan.id = 'cert-status';
|
||||||
metaSpan.textContent = 'Enter password to unlock';
|
metaSpan.textContent = t('tools:digitalSignPdf.enterPasswordToUnlock');
|
||||||
|
|
||||||
infoContainer.append(nameSpan, metaSpan);
|
infoContainer.append(nameSpan, metaSpan);
|
||||||
|
|
||||||
@@ -557,8 +559,7 @@ async function handlePasswordInput(): Promise<void> {
|
|||||||
|
|
||||||
const certStatus = getElement<HTMLDivElement>('cert-status');
|
const certStatus = getElement<HTMLDivElement>('cert-status');
|
||||||
if (certStatus) {
|
if (certStatus) {
|
||||||
certStatus.innerHTML =
|
certStatus.innerHTML = `${t('tools:digitalSignPdf.certificateUnlocked')} <i data-lucide="check-circle" class="inline w-4 h-4"></i>`;
|
||||||
'Certificate unlocked <i data-lucide="check-circle" class="inline w-4 h-4"></i>';
|
|
||||||
createIcons({ icons });
|
createIcons({ icons });
|
||||||
certStatus.className = 'text-xs text-green-400';
|
certStatus.className = 'text-xs text-green-400';
|
||||||
}
|
}
|
||||||
@@ -572,10 +573,10 @@ async function handlePasswordInput(): Promise<void> {
|
|||||||
const errorMessage =
|
const errorMessage =
|
||||||
error instanceof Error
|
error instanceof Error
|
||||||
? error.message
|
? error.message
|
||||||
: 'Invalid password or certificate';
|
: t('tools:digitalSignPdf.invalidPasswordOrCertificate');
|
||||||
certStatus.textContent = errorMessage.includes('password')
|
certStatus.textContent = errorMessage.includes('password')
|
||||||
? 'Incorrect password'
|
? t('tools:digitalSignPdf.incorrectPassword')
|
||||||
: 'Failed to parse certificate';
|
: t('tools:digitalSignPdf.failedParseCertificate');
|
||||||
certStatus.className = 'text-xs text-red-400';
|
certStatus.className = 'text-xs text-red-400';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -623,8 +624,8 @@ function updateProcessButton(): void {
|
|||||||
async function processSignature(): Promise<void> {
|
async function processSignature(): Promise<void> {
|
||||||
if (!state.pdfBytes || !state.certData) {
|
if (!state.pdfBytes || !state.certData) {
|
||||||
showAlert(
|
showAlert(
|
||||||
'Missing Data',
|
t('tools:digitalSignPdf.missingDataTitle'),
|
||||||
'Please upload both a PDF and a valid certificate.'
|
t('tools:digitalSignPdf.missingDataMessage')
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -706,7 +707,10 @@ async function processSignature(): Promise<void> {
|
|||||||
if (!state.sigImageData && !sigText && state.certData) {
|
if (!state.sigImageData && !sigText && state.certData) {
|
||||||
const certInfo = getCertificateInfo(state.certData.certificate);
|
const certInfo = getCertificateInfo(state.certData.certificate);
|
||||||
const date = new Date().toLocaleDateString();
|
const date = new Date().toLocaleDateString();
|
||||||
sigText = `Digitally signed by ${certInfo.subject}\n${date}`;
|
sigText = t('tools:digitalSignPdf.defaultSignatureText', {
|
||||||
|
signer: certInfo.subject,
|
||||||
|
date,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let finalHeight = sigHeight;
|
let finalHeight = sigHeight;
|
||||||
@@ -735,7 +739,7 @@ async function processSignature(): Promise<void> {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
showLoader('Applying digital signature...');
|
showLoader(t('tools:digitalSignPdf.applyingSignature'));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const signedPdfBytes = await signPdf(state.pdfBytes, state.certData, {
|
const signedPdfBytes = await signPdf(state.pdfBytes, state.certData, {
|
||||||
@@ -750,8 +754,8 @@ async function processSignature(): Promise<void> {
|
|||||||
|
|
||||||
hideLoader();
|
hideLoader();
|
||||||
showAlert(
|
showAlert(
|
||||||
'Success',
|
t('common.success'),
|
||||||
'PDF signed successfully! The signature can be verified in any PDF reader.',
|
t('tools:digitalSignPdf.successMessage'),
|
||||||
'success',
|
'success',
|
||||||
() => {
|
() => {
|
||||||
resetState();
|
resetState();
|
||||||
@@ -761,7 +765,7 @@ async function processSignature(): Promise<void> {
|
|||||||
hideLoader();
|
hideLoader();
|
||||||
console.error('Signing error:', error);
|
console.error('Signing error:', error);
|
||||||
const errorMessage =
|
const errorMessage =
|
||||||
error instanceof Error ? error.message : 'Unknown error occurred';
|
error instanceof Error ? error.message : t('common.unknownError');
|
||||||
|
|
||||||
// Check if this is a CORS/network error from certificate chain fetching
|
// Check if this is a CORS/network error from certificate chain fetching
|
||||||
if (
|
if (
|
||||||
@@ -770,11 +774,14 @@ async function processSignature(): Promise<void> {
|
|||||||
errorMessage.includes('NetworkError')
|
errorMessage.includes('NetworkError')
|
||||||
) {
|
) {
|
||||||
showAlert(
|
showAlert(
|
||||||
'Signing Failed',
|
t('tools:digitalSignPdf.signingFailedTitle'),
|
||||||
'Failed to fetch certificate chain. This may be due to network issues or the certificate proxy being unavailable. Please check your internet connection and try again. If the issue persists, contact support.'
|
t('tools:digitalSignPdf.chainFetchFailed')
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
showAlert('Signing Failed', `Failed to sign PDF: ${errorMessage}`);
|
showAlert(
|
||||||
|
t('tools:digitalSignPdf.signingFailedTitle'),
|
||||||
|
t('tools:digitalSignPdf.failedToSignPdf', { message: errorMessage })
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+52
-36
@@ -10,6 +10,7 @@ import {
|
|||||||
showWasmRequiredDialog,
|
showWasmRequiredDialog,
|
||||||
WasmProvider,
|
WasmProvider,
|
||||||
} from '../utils/wasm-provider.js';
|
} from '../utils/wasm-provider.js';
|
||||||
|
import { initI18n, t } from '../i18n/i18n';
|
||||||
|
|
||||||
const worker = new Worker(
|
const worker = new Worker(
|
||||||
import.meta.env.BASE_URL + 'workers/json-to-pdf.worker.js'
|
import.meta.env.BASE_URL + 'workers/json-to-pdf.worker.js'
|
||||||
@@ -17,8 +18,8 @@ const worker = new Worker(
|
|||||||
|
|
||||||
let selectedFiles: File[] = [];
|
let selectedFiles: File[] = [];
|
||||||
|
|
||||||
const jsonFilesInput = document.getElementById('jsonFiles') as HTMLInputElement;
|
let jsonFilesInput!: HTMLInputElement;
|
||||||
const convertBtn = document.getElementById('convertBtn') as HTMLButtonElement;
|
let convertBtn!: HTMLButtonElement;
|
||||||
const statusMessage = document.getElementById(
|
const statusMessage = document.getElementById(
|
||||||
'status-message'
|
'status-message'
|
||||||
) as HTMLDivElement;
|
) as HTMLDivElement;
|
||||||
@@ -72,27 +73,9 @@ function updateFileList() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
jsonFilesInput.addEventListener('change', (e) => {
|
|
||||||
const target = e.target as HTMLInputElement;
|
|
||||||
if (target.files && target.files.length > 0) {
|
|
||||||
selectedFiles = Array.from(target.files);
|
|
||||||
convertBtn.disabled = selectedFiles.length === 0;
|
|
||||||
updateFileList();
|
|
||||||
|
|
||||||
if (selectedFiles.length === 0) {
|
|
||||||
showStatus('Please select at least 1 JSON file', 'info');
|
|
||||||
} else {
|
|
||||||
showStatus(
|
|
||||||
`${selectedFiles.length} file(s) selected. Ready to convert!`,
|
|
||||||
'info'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
async function convertJSONsToPDF() {
|
async function convertJSONsToPDF() {
|
||||||
if (selectedFiles.length === 0) {
|
if (selectedFiles.length === 0) {
|
||||||
showStatus('Please select at least 1 JSON file', 'error');
|
showStatus(t('tools:jsonToPdf.status.selectAtLeastOne'), 'error');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,13 +87,13 @@ async function convertJSONsToPDF() {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
convertBtn.disabled = true;
|
convertBtn.disabled = true;
|
||||||
showStatus('Reading files (Main Thread)...', 'info');
|
showStatus(t('tools:jsonToPdf.status.readingFiles'), 'info');
|
||||||
|
|
||||||
const fileBuffers = await Promise.all(
|
const fileBuffers = await Promise.all(
|
||||||
selectedFiles.map((file) => readFileAsArrayBuffer(file))
|
selectedFiles.map((file) => readFileAsArrayBuffer(file))
|
||||||
);
|
);
|
||||||
|
|
||||||
showStatus('Converting JSONs to PDFs...', 'info');
|
showStatus(t('tools:jsonToPdf.status.converting'), 'info');
|
||||||
|
|
||||||
worker.postMessage(
|
worker.postMessage(
|
||||||
{
|
{
|
||||||
@@ -124,7 +107,10 @@ async function convertJSONsToPDF() {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error reading files:', error);
|
console.error('Error reading files:', error);
|
||||||
showStatus(
|
showStatus(
|
||||||
`❌ Error reading files: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
t('tools:jsonToPdf.status.readError', {
|
||||||
|
message:
|
||||||
|
error instanceof Error ? error.message : t('common.unknownError'),
|
||||||
|
}),
|
||||||
'error'
|
'error'
|
||||||
);
|
);
|
||||||
convertBtn.disabled = false;
|
convertBtn.disabled = false;
|
||||||
@@ -141,7 +127,7 @@ worker.onmessage = async (e: MessageEvent) => {
|
|||||||
}>;
|
}>;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
showStatus('Creating ZIP file...', 'info');
|
showStatus(t('tools:jsonToPdf.status.creatingZip'), 'info');
|
||||||
|
|
||||||
const zip = new JSZip();
|
const zip = new JSZip();
|
||||||
pdfFiles.forEach(({ name, data }) => {
|
pdfFiles.forEach(({ name, data }) => {
|
||||||
@@ -157,10 +143,7 @@ worker.onmessage = async (e: MessageEvent) => {
|
|||||||
a.download = 'jsons-to-pdf.zip';
|
a.download = 'jsons-to-pdf.zip';
|
||||||
downloadFile(zipBlob, 'jsons-to-pdf.zip');
|
downloadFile(zipBlob, 'jsons-to-pdf.zip');
|
||||||
|
|
||||||
showStatus(
|
showStatus(t('tools:jsonToPdf.status.success'), 'success');
|
||||||
'✅ JSONs converted to PDF successfully! ZIP download started.',
|
|
||||||
'success'
|
|
||||||
);
|
|
||||||
|
|
||||||
selectedFiles = [];
|
selectedFiles = [];
|
||||||
jsonFilesInput.value = '';
|
jsonFilesInput.value = '';
|
||||||
@@ -174,14 +157,20 @@ worker.onmessage = async (e: MessageEvent) => {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error creating ZIP:', error);
|
console.error('Error creating ZIP:', error);
|
||||||
showStatus(
|
showStatus(
|
||||||
`❌ Error creating ZIP: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
t('tools:jsonToPdf.status.zipError', {
|
||||||
|
message:
|
||||||
|
error instanceof Error ? error.message : t('common.unknownError'),
|
||||||
|
}),
|
||||||
'error'
|
'error'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else if (e.data.status === 'error') {
|
} else if (e.data.status === 'error') {
|
||||||
const errorMessage = e.data.message || 'Unknown error occurred in worker.';
|
const errorMessage = e.data.message || t('common.unknownError');
|
||||||
console.error('Worker Error:', errorMessage);
|
console.error('Worker Error:', errorMessage);
|
||||||
showStatus(`❌ Worker Error: ${errorMessage}`, 'error');
|
showStatus(
|
||||||
|
t('tools:jsonToPdf.status.workerError', { message: errorMessage }),
|
||||||
|
'error'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -191,8 +180,35 @@ if (backToToolsBtn) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
convertBtn.addEventListener('click', convertJSONsToPDF);
|
// Initialize after i18n is ready so the default status is translated.
|
||||||
|
void (async () => {
|
||||||
|
await initI18n();
|
||||||
|
|
||||||
// Initialize
|
jsonFilesInput = document.getElementById('jsonFiles') as HTMLInputElement;
|
||||||
showStatus('Select JSON files to get started', 'info');
|
convertBtn = document.getElementById('convertBtn') as HTMLButtonElement;
|
||||||
initializeGlobalShortcuts();
|
|
||||||
|
jsonFilesInput.addEventListener('change', (e) => {
|
||||||
|
const target = e.target as HTMLInputElement;
|
||||||
|
if (target.files && target.files.length > 0) {
|
||||||
|
selectedFiles = Array.from(target.files);
|
||||||
|
convertBtn.disabled = selectedFiles.length === 0;
|
||||||
|
updateFileList();
|
||||||
|
|
||||||
|
if (selectedFiles.length === 0) {
|
||||||
|
showStatus(t('tools:jsonToPdf.status.selectAtLeastOne'), 'info');
|
||||||
|
} else {
|
||||||
|
showStatus(
|
||||||
|
t('tools:jsonToPdf.status.selectedReady', {
|
||||||
|
count: selectedFiles.length,
|
||||||
|
}),
|
||||||
|
'info'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
convertBtn.addEventListener('click', convertJSONsToPDF);
|
||||||
|
|
||||||
|
showStatus(t('tools:jsonToPdf.status.getStarted'), 'info');
|
||||||
|
initializeGlobalShortcuts();
|
||||||
|
})();
|
||||||
@@ -10,6 +10,7 @@ import {
|
|||||||
resolveConfiguredTesseractAvailableLanguages,
|
resolveConfiguredTesseractAvailableLanguages,
|
||||||
UnsupportedOcrLanguageError,
|
UnsupportedOcrLanguageError,
|
||||||
} from '../utils/tesseract-language-availability.js';
|
} from '../utils/tesseract-language-availability.js';
|
||||||
|
import { initI18n, t } from '../i18n/index.js';
|
||||||
|
|
||||||
const pageState: OcrState = {
|
const pageState: OcrState = {
|
||||||
file: null,
|
file: null,
|
||||||
@@ -37,7 +38,7 @@ function updateProgress(status: string, progress: number) {
|
|||||||
progressStatus.textContent = status;
|
progressStatus.textContent = status;
|
||||||
progressBar.style.width = `${Math.min(100, progress * 100)}%`;
|
progressBar.style.width = `${Math.min(100, progress * 100)}%`;
|
||||||
|
|
||||||
const logMessage = `Status: ${status}`;
|
const logMessage = t('tools:ocrPdf.statusPrefix', { status });
|
||||||
progressLog.textContent += logMessage + '\n';
|
progressLog.textContent += logMessage + '\n';
|
||||||
progressLog.scrollTop = progressLog.scrollHeight;
|
progressLog.scrollTop = progressLog.scrollHeight;
|
||||||
}
|
}
|
||||||
@@ -78,7 +79,9 @@ function resetState() {
|
|||||||
const selectedLangsDisplay = document.getElementById(
|
const selectedLangsDisplay = document.getElementById(
|
||||||
'selected-langs-display'
|
'selected-langs-display'
|
||||||
);
|
);
|
||||||
if (selectedLangsDisplay) selectedLangsDisplay.textContent = 'None';
|
if (selectedLangsDisplay) {
|
||||||
|
selectedLangsDisplay.textContent = t('tools:ocrPdf.none');
|
||||||
|
}
|
||||||
|
|
||||||
const processBtn = document.getElementById(
|
const processBtn = document.getElementById(
|
||||||
'process-btn'
|
'process-btn'
|
||||||
@@ -100,14 +103,15 @@ function updateLanguageAvailabilityNotice() {
|
|||||||
const availableEntries = getAvailableTesseractLanguageEntries();
|
const availableEntries = getAvailableTesseractLanguageEntries();
|
||||||
if (availableEntries.length === 0) {
|
if (availableEntries.length === 0) {
|
||||||
notice.classList.remove('hidden');
|
notice.classList.remove('hidden');
|
||||||
notice.textContent =
|
notice.textContent = t('tools:ocrPdf.availabilityInvalidConfig');
|
||||||
'This deployment does not expose any valid OCR languages. Rebuild it with VITE_TESSERACT_AVAILABLE_LANGUAGES set to valid Tesseract codes.';
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const availableNames = availableEntries.map(([, name]) => name).join(', ');
|
const availableNames = availableEntries.map(([, name]) => name).join(', ');
|
||||||
notice.classList.remove('hidden');
|
notice.classList.remove('hidden');
|
||||||
notice.textContent = `This deployment bundles OCR for: ${availableNames}.`;
|
notice.textContent = t('tools:ocrPdf.availabilityBundles', {
|
||||||
|
languages: availableNames,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function runOCR() {
|
async function runOCR() {
|
||||||
@@ -131,14 +135,14 @@ async function runOCR() {
|
|||||||
|
|
||||||
if (selectedLangs.length === 0) {
|
if (selectedLangs.length === 0) {
|
||||||
showAlert(
|
showAlert(
|
||||||
'No Languages Selected',
|
t('tools:ocrPdf.noLanguagesTitle'),
|
||||||
'Please select at least one language for OCR.'
|
t('tools:ocrPdf.noLanguagesMessage')
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!pageState.file) {
|
if (!pageState.file) {
|
||||||
showAlert('No File', 'Please upload a PDF file first.');
|
showAlert(t('tools:ocrPdf.noFileTitle'), t('tools:ocrPdf.noFileMessage'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -177,11 +181,11 @@ async function runOCR() {
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
if (e instanceof UnsupportedOcrLanguageError) {
|
if (e instanceof UnsupportedOcrLanguageError) {
|
||||||
showAlert('OCR Language Not Available', e.message);
|
showAlert(t('tools:ocrPdf.languageUnavailableTitle'), e.message);
|
||||||
} else {
|
} else {
|
||||||
showAlert(
|
showAlert(
|
||||||
'OCR Error',
|
t('tools:ocrPdf.ocrErrorTitle'),
|
||||||
'An error occurred during the OCR process. The worker may have failed to load. Please try again.'
|
t('tools:ocrPdf.ocrErrorMessage')
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (toolOptions) toolOptions.classList.remove('hidden');
|
if (toolOptions) toolOptions.classList.remove('hidden');
|
||||||
@@ -258,8 +262,7 @@ function populateLanguageList() {
|
|||||||
if (availableEntries.length === 0) {
|
if (availableEntries.length === 0) {
|
||||||
const emptyState = document.createElement('p');
|
const emptyState = document.createElement('p');
|
||||||
emptyState.className = 'text-sm text-yellow-300 p-2';
|
emptyState.className = 'text-sm text-yellow-300 p-2';
|
||||||
emptyState.textContent =
|
emptyState.textContent = t('tools:ocrPdf.noLanguagesAvailable');
|
||||||
'No OCR languages are available in this deployment.';
|
|
||||||
langList.appendChild(emptyState);
|
langList.appendChild(emptyState);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -282,7 +285,7 @@ function populateLanguageList() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', function () {
|
document.addEventListener('DOMContentLoaded', async function () {
|
||||||
const fileInput = document.getElementById('file-input') as HTMLInputElement;
|
const fileInput = document.getElementById('file-input') as HTMLInputElement;
|
||||||
const dropZone = document.getElementById('drop-zone');
|
const dropZone = document.getElementById('drop-zone');
|
||||||
const processBtn = document.getElementById(
|
const processBtn = document.getElementById(
|
||||||
@@ -304,6 +307,7 @@ document.addEventListener('DOMContentLoaded', function () {
|
|||||||
const downloadTxtBtn = document.getElementById('download-txt-btn');
|
const downloadTxtBtn = document.getElementById('download-txt-btn');
|
||||||
const downloadPdfBtn = document.getElementById('download-searchable-pdf');
|
const downloadPdfBtn = document.getElementById('download-searchable-pdf');
|
||||||
|
|
||||||
|
await initI18n();
|
||||||
populateLanguageList();
|
populateLanguageList();
|
||||||
updateLanguageAvailabilityNotice();
|
updateLanguageAvailabilityNotice();
|
||||||
|
|
||||||
@@ -376,7 +380,7 @@ document.addEventListener('DOMContentLoaded', function () {
|
|||||||
|
|
||||||
if (selectedLangsDisplay) {
|
if (selectedLangsDisplay) {
|
||||||
selectedLangsDisplay.textContent =
|
selectedLangsDisplay.textContent =
|
||||||
selected.length > 0 ? selected.join(', ') : 'None';
|
selected.length > 0 ? selected.join(', ') : t('tools:ocrPdf.none');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (processBtn) {
|
if (processBtn) {
|
||||||
|
|||||||
+29
-17
@@ -12,6 +12,7 @@ import {
|
|||||||
WasmProvider,
|
WasmProvider,
|
||||||
} from '../utils/wasm-provider.js';
|
} from '../utils/wasm-provider.js';
|
||||||
import { batchDecryptIfNeeded } from '../utils/password-prompt.js';
|
import { batchDecryptIfNeeded } from '../utils/password-prompt.js';
|
||||||
|
import { initI18n, t } from '../i18n/i18n';
|
||||||
|
|
||||||
const worker = new Worker(
|
const worker = new Worker(
|
||||||
import.meta.env.BASE_URL + 'workers/pdf-to-json.worker.js'
|
import.meta.env.BASE_URL + 'workers/pdf-to-json.worker.js'
|
||||||
@@ -82,10 +83,12 @@ pdfFilesInput.addEventListener('change', (e) => {
|
|||||||
updateFileList();
|
updateFileList();
|
||||||
|
|
||||||
if (selectedFiles.length === 0) {
|
if (selectedFiles.length === 0) {
|
||||||
showStatus('Please select at least 1 PDF file', 'info');
|
showStatus(t('tools:pdfToJson.status.selectAtLeastOne'), 'info');
|
||||||
} else {
|
} else {
|
||||||
showStatus(
|
showStatus(
|
||||||
`${selectedFiles.length} file(s) selected. Ready to convert!`,
|
t('tools:pdfToJson.status.selectedReady', {
|
||||||
|
count: selectedFiles.length,
|
||||||
|
}),
|
||||||
'info'
|
'info'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -94,7 +97,7 @@ pdfFilesInput.addEventListener('change', (e) => {
|
|||||||
|
|
||||||
async function convertPDFsToJSON() {
|
async function convertPDFsToJSON() {
|
||||||
if (selectedFiles.length === 0) {
|
if (selectedFiles.length === 0) {
|
||||||
showStatus('Please select at least 1 PDF file', 'error');
|
showStatus(t('tools:pdfToJson.status.selectAtLeastOne'), 'error');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,17 +109,17 @@ async function convertPDFsToJSON() {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
convertBtn.disabled = true;
|
convertBtn.disabled = true;
|
||||||
showStatus('Checking for encrypted PDFs...', 'info');
|
showStatus(t('tools:pdfToJson.status.checkingEncrypted'), 'info');
|
||||||
|
|
||||||
selectedFiles = await batchDecryptIfNeeded(selectedFiles);
|
selectedFiles = await batchDecryptIfNeeded(selectedFiles);
|
||||||
|
|
||||||
showStatus('Reading files (Main Thread)...', 'info');
|
showStatus(t('tools:pdfToJson.status.readingFiles'), 'info');
|
||||||
|
|
||||||
const fileBuffers = await Promise.all(
|
const fileBuffers = await Promise.all(
|
||||||
selectedFiles.map((file) => readFileAsArrayBuffer(file))
|
selectedFiles.map((file) => readFileAsArrayBuffer(file))
|
||||||
);
|
);
|
||||||
|
|
||||||
showStatus('Converting PDFs to JSON..', 'info');
|
showStatus(t('tools:pdfToJson.status.converting'), 'info');
|
||||||
|
|
||||||
worker.postMessage(
|
worker.postMessage(
|
||||||
{
|
{
|
||||||
@@ -130,7 +133,10 @@ async function convertPDFsToJSON() {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error reading files:', error);
|
console.error('Error reading files:', error);
|
||||||
showStatus(
|
showStatus(
|
||||||
`❌ Error reading files: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
t('tools:pdfToJson.status.readError', {
|
||||||
|
message:
|
||||||
|
error instanceof Error ? error.message : t('common.unknownError'),
|
||||||
|
}),
|
||||||
'error'
|
'error'
|
||||||
);
|
);
|
||||||
convertBtn.disabled = false;
|
convertBtn.disabled = false;
|
||||||
@@ -147,7 +153,7 @@ worker.onmessage = async (e: MessageEvent) => {
|
|||||||
}>;
|
}>;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
showStatus('Creating ZIP file...', 'info');
|
showStatus(t('tools:pdfToJson.status.creatingZip'), 'info');
|
||||||
|
|
||||||
const zip = new JSZip();
|
const zip = new JSZip();
|
||||||
const usedNames = new Set<string>();
|
const usedNames = new Set<string>();
|
||||||
@@ -161,10 +167,7 @@ worker.onmessage = async (e: MessageEvent) => {
|
|||||||
const zipBlob = await zip.generateAsync({ type: 'blob' });
|
const zipBlob = await zip.generateAsync({ type: 'blob' });
|
||||||
downloadFile(zipBlob, 'pdfs-to-json.zip');
|
downloadFile(zipBlob, 'pdfs-to-json.zip');
|
||||||
|
|
||||||
showStatus(
|
showStatus(t('tools:pdfToJson.status.success'), 'success');
|
||||||
'✅ PDFs converted to JSON successfully! ZIP download started.',
|
|
||||||
'success'
|
|
||||||
);
|
|
||||||
|
|
||||||
selectedFiles = [];
|
selectedFiles = [];
|
||||||
pdfFilesInput.value = '';
|
pdfFilesInput.value = '';
|
||||||
@@ -178,14 +181,20 @@ worker.onmessage = async (e: MessageEvent) => {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error creating ZIP:', error);
|
console.error('Error creating ZIP:', error);
|
||||||
showStatus(
|
showStatus(
|
||||||
`❌ Error creating ZIP: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
t('tools:pdfToJson.status.zipError', {
|
||||||
|
message:
|
||||||
|
error instanceof Error ? error.message : t('common.unknownError'),
|
||||||
|
}),
|
||||||
'error'
|
'error'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else if (e.data.status === 'error') {
|
} else if (e.data.status === 'error') {
|
||||||
const errorMessage = e.data.message || 'Unknown error occurred in worker.';
|
const errorMessage = e.data.message || t('common.unknownError');
|
||||||
console.error('Worker Error:', errorMessage);
|
console.error('Worker Error:', errorMessage);
|
||||||
showStatus(`❌ Worker Error: ${errorMessage}`, 'error');
|
showStatus(
|
||||||
|
t('tools:pdfToJson.status.workerError', { message: errorMessage }),
|
||||||
|
'error'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -197,5 +206,8 @@ if (backToToolsBtn) {
|
|||||||
|
|
||||||
convertBtn.addEventListener('click', convertPDFsToJSON);
|
convertBtn.addEventListener('click', convertPDFsToJSON);
|
||||||
|
|
||||||
showStatus('Select PDF files to get started', 'info');
|
void (async () => {
|
||||||
initializeGlobalShortcuts();
|
await initI18n();
|
||||||
|
showStatus(t('tools:pdfToJson.status.getStarted'), 'info');
|
||||||
|
initializeGlobalShortcuts();
|
||||||
|
})();
|
||||||
@@ -6,6 +6,7 @@ import {
|
|||||||
WasmProvider,
|
WasmProvider,
|
||||||
} from '../utils/wasm-provider.js';
|
} from '../utils/wasm-provider.js';
|
||||||
import { loadPdfWithPasswordPrompt } from '../utils/password-prompt.js';
|
import { loadPdfWithPasswordPrompt } from '../utils/password-prompt.js';
|
||||||
|
import { t } from '../i18n/index.js';
|
||||||
|
|
||||||
const worker = new Worker(
|
const worker = new Worker(
|
||||||
import.meta.env.BASE_URL + 'workers/table-of-contents.worker.js'
|
import.meta.env.BASE_URL + 'workers/table-of-contents.worker.js'
|
||||||
@@ -128,7 +129,7 @@ fileInput.addEventListener('change', (e) => {
|
|||||||
|
|
||||||
async function generateTableOfContents() {
|
async function generateTableOfContents() {
|
||||||
if (!pdfFile) {
|
if (!pdfFile) {
|
||||||
showStatus('Please select a PDF file first.', 'error');
|
showStatus(t('tools:tableOfContents.selectPdfFirst'), 'error');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -140,13 +141,13 @@ async function generateTableOfContents() {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
generateBtn.disabled = true;
|
generateBtn.disabled = true;
|
||||||
showStatus('Reading file (Main Thread)...', 'info');
|
showStatus(t('tools:tableOfContents.statusReadingFileMainThread'), 'info');
|
||||||
|
|
||||||
const arrayBuffer = await pdfFile.arrayBuffer();
|
const arrayBuffer = await pdfFile.arrayBuffer();
|
||||||
|
|
||||||
showStatus('Generating table of contents...', 'info');
|
showStatus(t('tools:tableOfContents.statusGenerating'), 'info');
|
||||||
|
|
||||||
const title = tocTitleInput.value || 'Table of Contents';
|
const title = tocTitleInput.value || t('tools:tableOfContents.name');
|
||||||
const fontSize = parseInt(fontSizeSelect.value, 10);
|
const fontSize = parseInt(fontSizeSelect.value, 10);
|
||||||
const fontFamily = parseInt(fontFamilySelect.value, 10);
|
const fontFamily = parseInt(fontFamilySelect.value, 10);
|
||||||
const addBookmark = addBookmarkCheckbox.checked;
|
const addBookmark = addBookmarkCheckbox.checked;
|
||||||
@@ -165,7 +166,10 @@ async function generateTableOfContents() {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error reading file:', error);
|
console.error('Error reading file:', error);
|
||||||
showStatus(
|
showStatus(
|
||||||
`Error reading file: ${error instanceof Error ? error.message : 'Unknown error occurred'}`,
|
t('tools:tableOfContents.errorReadingFileWithMessage', {
|
||||||
|
message:
|
||||||
|
error instanceof Error ? error.message : t('common.unknownError'),
|
||||||
|
}),
|
||||||
'error'
|
'error'
|
||||||
);
|
);
|
||||||
generateBtn.disabled = false;
|
generateBtn.disabled = false;
|
||||||
@@ -183,7 +187,7 @@ worker.onmessage = (e: MessageEvent<TOCWorkerResponse>) => {
|
|||||||
downloadFile(blob, pdfFile?.name || 'document.pdf');
|
downloadFile(blob, pdfFile?.name || 'document.pdf');
|
||||||
|
|
||||||
showStatus(
|
showStatus(
|
||||||
'Table of contents generated successfully! Download started.',
|
t('tools:tableOfContents.successGeneratedDownloadStarted'),
|
||||||
'success'
|
'success'
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -194,15 +198,20 @@ worker.onmessage = (e: MessageEvent<TOCWorkerResponse>) => {
|
|||||||
fileDisplayArea.classList.add('hidden');
|
fileDisplayArea.classList.add('hidden');
|
||||||
generateBtn.disabled = true;
|
generateBtn.disabled = true;
|
||||||
} else if (e.data.status === 'error') {
|
} else if (e.data.status === 'error') {
|
||||||
const errorMessage = e.data.message || 'Unknown error occurred in worker.';
|
const errorMessage = e.data.message || t('common.unknownError');
|
||||||
console.error('Worker Error:', errorMessage);
|
console.error('Worker Error:', errorMessage);
|
||||||
showStatus(`Error: ${errorMessage}`, 'error');
|
showStatus(
|
||||||
|
t('tools:tableOfContents.workerErrorWithMessage', {
|
||||||
|
message: errorMessage,
|
||||||
|
}),
|
||||||
|
'error'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
worker.onerror = (error) => {
|
worker.onerror = (error) => {
|
||||||
console.error('Worker error:', error);
|
console.error('Worker error:', error);
|
||||||
showStatus('Worker error occurred. Check console for details.', 'error');
|
showStatus(t('tools:tableOfContents.workerErrorOccurred'), 'error');
|
||||||
generateBtn.disabled = false;
|
generateBtn.disabled = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { showAlert, showLoader, hideLoader } from '../ui.js';
|
|||||||
import { WasmProvider, type WasmPackage } from '../utils/wasm-provider.js';
|
import { WasmProvider, type WasmPackage } from '../utils/wasm-provider.js';
|
||||||
import { clearPyMuPDFCache } from '../utils/pymupdf-loader.js';
|
import { clearPyMuPDFCache } from '../utils/pymupdf-loader.js';
|
||||||
import { clearGhostscriptCache } from '../utils/ghostscript-dynamic-loader.js';
|
import { clearGhostscriptCache } from '../utils/ghostscript-dynamic-loader.js';
|
||||||
|
import { initI18n, t } from '../i18n/index.js';
|
||||||
|
|
||||||
if (document.readyState === 'loading') {
|
if (document.readyState === 'loading') {
|
||||||
document.addEventListener('DOMContentLoaded', initializePage);
|
document.addEventListener('DOMContentLoaded', initializePage);
|
||||||
@@ -10,9 +11,15 @@ if (document.readyState === 'loading') {
|
|||||||
initializePage();
|
initializePage();
|
||||||
}
|
}
|
||||||
|
|
||||||
function initializePage() {
|
async function initializePage() {
|
||||||
createIcons({ icons });
|
createIcons({ icons });
|
||||||
|
|
||||||
|
try {
|
||||||
|
await initI18n();
|
||||||
|
} catch (error) {
|
||||||
|
console.warn('WASM settings i18n initialization failed:', error);
|
||||||
|
}
|
||||||
|
|
||||||
document.querySelectorAll('.copy-btn').forEach((btn) => {
|
document.querySelectorAll('.copy-btn').forEach((btn) => {
|
||||||
btn.addEventListener('click', async () => {
|
btn.addEventListener('click', async () => {
|
||||||
const url = btn.getAttribute('data-copy');
|
const url = btn.getAttribute('data-copy');
|
||||||
@@ -90,7 +97,7 @@ function initializePage() {
|
|||||||
input.value = url;
|
input.value = url;
|
||||||
} else {
|
} else {
|
||||||
input.value = '';
|
input.value = '';
|
||||||
input.placeholder = `Using default: ${url}`;
|
input.placeholder = t('tools:wasmSettings.usingDefault', { url });
|
||||||
}
|
}
|
||||||
updateStatus(name, true);
|
updateStatus(name, true);
|
||||||
}
|
}
|
||||||
@@ -111,19 +118,19 @@ function initializePage() {
|
|||||||
if (!statusEl) return;
|
if (!statusEl) return;
|
||||||
|
|
||||||
if (testing) {
|
if (testing) {
|
||||||
statusEl.textContent = 'Testing...';
|
statusEl.textContent = t('tools:wasmSettings.status.testing');
|
||||||
statusEl.className =
|
statusEl.className =
|
||||||
'text-xs px-2 py-1 rounded-full bg-yellow-600/30 text-yellow-300';
|
'text-xs px-2 py-1 rounded-full bg-yellow-600/30 text-yellow-300';
|
||||||
} else if (configured && WasmProvider.isUserConfigured(packageName)) {
|
} else if (configured && WasmProvider.isUserConfigured(packageName)) {
|
||||||
statusEl.textContent = 'Custom Override';
|
statusEl.textContent = t('tools:wasmSettings.status.customOverride');
|
||||||
statusEl.className =
|
statusEl.className =
|
||||||
'text-xs px-2 py-1 rounded-full bg-blue-600/30 text-blue-300';
|
'text-xs px-2 py-1 rounded-full bg-blue-600/30 text-blue-300';
|
||||||
} else if (configured || WasmProvider.hasEnvDefault(packageName)) {
|
} else if (configured || WasmProvider.hasEnvDefault(packageName)) {
|
||||||
statusEl.textContent = 'Pre-configured';
|
statusEl.textContent = t('tools:wasmSettings.status.preConfigured');
|
||||||
statusEl.className =
|
statusEl.className =
|
||||||
'text-xs px-2 py-1 rounded-full bg-green-600/30 text-green-300';
|
'text-xs px-2 py-1 rounded-full bg-green-600/30 text-green-300';
|
||||||
} else {
|
} else {
|
||||||
statusEl.textContent = 'Not Configured';
|
statusEl.textContent = t('tools:wasmSettings.status.notConfigured');
|
||||||
statusEl.className =
|
statusEl.className =
|
||||||
'text-xs px-2 py-1 rounded-full bg-gray-600 text-gray-300';
|
'text-xs px-2 py-1 rounded-full bg-gray-600 text-gray-300';
|
||||||
}
|
}
|
||||||
@@ -131,7 +138,10 @@ function initializePage() {
|
|||||||
|
|
||||||
async function testConnection(packageName: WasmPackage, url: string) {
|
async function testConnection(packageName: WasmPackage, url: string) {
|
||||||
if (!url.trim()) {
|
if (!url.trim()) {
|
||||||
showAlert('Empty URL', 'Please enter a URL to test.');
|
showAlert(
|
||||||
|
t('tools:wasmSettings.emptyUrlTitle'),
|
||||||
|
t('tools:wasmSettings.emptyUrlMessage')
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -142,15 +152,17 @@ function initializePage() {
|
|||||||
if (result.valid) {
|
if (result.valid) {
|
||||||
updateStatus(packageName, true);
|
updateStatus(packageName, true);
|
||||||
showAlert(
|
showAlert(
|
||||||
'Success',
|
t('tools:wasmSettings.testSuccessTitle'),
|
||||||
`Connection to ${WasmProvider.getPackageDisplayName(packageName)} successful!`,
|
t('tools:wasmSettings.connectionSuccess', {
|
||||||
|
package: WasmProvider.getPackageDisplayName(packageName),
|
||||||
|
}),
|
||||||
'success'
|
'success'
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
updateStatus(packageName, false);
|
updateStatus(packageName, false);
|
||||||
showAlert(
|
showAlert(
|
||||||
'Connection Failed',
|
t('tools:wasmSettings.connectionFailedTitle'),
|
||||||
result.error || 'Could not connect to the URL.'
|
result.error || t('tools:wasmSettings.connectionFailedMessage')
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -168,7 +180,7 @@ function initializePage() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
saveBtn?.addEventListener('click', async () => {
|
saveBtn?.addEventListener('click', async () => {
|
||||||
showLoader('Saving configuration...');
|
showLoader(t('tools:wasmSettings.savingConfiguration'));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (pymupdfUrl.value.trim()) {
|
if (pymupdfUrl.value.trim()) {
|
||||||
@@ -196,11 +208,19 @@ function initializePage() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
hideLoader();
|
hideLoader();
|
||||||
showAlert('Saved', 'Configuration saved successfully!', 'success');
|
showAlert(
|
||||||
|
t('tools:wasmSettings.savedTitle'),
|
||||||
|
t('tools:wasmSettings.savedMessage'),
|
||||||
|
'success'
|
||||||
|
);
|
||||||
} catch (e: unknown) {
|
} catch (e: unknown) {
|
||||||
hideLoader();
|
hideLoader();
|
||||||
const errorMessage = e instanceof Error ? e.message : 'Unknown error';
|
const errorMessage =
|
||||||
showAlert('Error', `Failed to save configuration: ${errorMessage}`);
|
e instanceof Error ? e.message : t('common.unknownError');
|
||||||
|
showAlert(
|
||||||
|
t('tools:wasmSettings.errorTitle'),
|
||||||
|
t('tools:wasmSettings.failedSave', { message: errorMessage })
|
||||||
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -225,10 +245,10 @@ function initializePage() {
|
|||||||
WasmProvider.hasEnvDefault('cpdf');
|
WasmProvider.hasEnvDefault('cpdf');
|
||||||
|
|
||||||
showAlert(
|
showAlert(
|
||||||
'Reset',
|
t('tools:wasmSettings.resetTitle'),
|
||||||
hasDefaults
|
hasDefaults
|
||||||
? 'Custom overrides cleared. Pre-configured defaults are active.'
|
? t('tools:wasmSettings.resetWithDefaults')
|
||||||
: 'All configurations and cached modules have been cleared.',
|
: t('tools:wasmSettings.resetNoDefaults'),
|
||||||
'success'
|
'success'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -200,7 +200,7 @@
|
|||||||
id="save-stamped-btn"
|
id="save-stamped-btn"
|
||||||
class="hidden btn-gradient w-full mt-6 flex items-center justify-center gap-2"
|
class="hidden btn-gradient w-full mt-6 flex items-center justify-center gap-2"
|
||||||
>
|
>
|
||||||
<span>Save Stamped PDF</span>
|
<span data-i18n="tools:addStamps.saveButton">Save Stamped PDF</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+49
-11
@@ -162,19 +162,26 @@
|
|||||||
id="auto-extract-checkbox"
|
id="auto-extract-checkbox"
|
||||||
class="w-4 h-4 accent-blue-500"
|
class="w-4 h-4 accent-blue-500"
|
||||||
/>
|
/>
|
||||||
<span>Auto-extract existing bookmarks</span>
|
<span data-i18n="tools:editBookmarks.autoExtractExisting"
|
||||||
|
>Auto-extract existing bookmarks</span
|
||||||
|
>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Import Bookmarks Section -->
|
<!-- Import Bookmarks Section -->
|
||||||
<div class="mt-8 pt-6 border-t border-gray-700">
|
<div class="mt-8 pt-6 border-t border-gray-700">
|
||||||
<h3 class="text-sm font-semibold text-gray-300 mb-4">
|
<h3
|
||||||
|
class="text-sm font-semibold text-gray-300 mb-4"
|
||||||
|
data-i18n="tools:editBookmarks.importSectionTitle"
|
||||||
|
>
|
||||||
Or Import Bookmarks
|
Or Import Bookmarks
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
<!-- CSV Upload -->
|
<!-- CSV Upload -->
|
||||||
<label class="block mb-4">
|
<label class="block mb-4">
|
||||||
<span class="text-xs text-gray-500"
|
<span
|
||||||
|
class="text-xs text-gray-500"
|
||||||
|
data-i18n="tools:editBookmarks.csvFormat"
|
||||||
>CSV format: title,page,level</span
|
>CSV format: title,page,level</span
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
@@ -183,8 +190,14 @@
|
|||||||
<div class="flex flex-col items-center justify-center pt-4 pb-4">
|
<div class="flex flex-col items-center justify-center pt-4 pb-4">
|
||||||
<i data-lucide="sheet" class="w-8 h-8 mb-2 text-gray-400"></i>
|
<i data-lucide="sheet" class="w-8 h-8 mb-2 text-gray-400"></i>
|
||||||
<p class="text-xs text-gray-400">
|
<p class="text-xs text-gray-400">
|
||||||
<span class="font-semibold">Click to upload CSV</span> or drag
|
<span
|
||||||
here
|
class="font-semibold"
|
||||||
|
data-i18n="tools:editBookmarks.uploadCsvAction"
|
||||||
|
>Click to upload CSV</span
|
||||||
|
>
|
||||||
|
<span data-i18n="tools:editBookmarks.orDragHere"
|
||||||
|
>or drag here</span
|
||||||
|
>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<input
|
<input
|
||||||
@@ -198,15 +211,25 @@
|
|||||||
|
|
||||||
<!-- JSON Upload -->
|
<!-- JSON Upload -->
|
||||||
<label class="block">
|
<label class="block">
|
||||||
<span class="text-xs text-gray-500">JSON format</span>
|
<span
|
||||||
|
class="text-xs text-gray-500"
|
||||||
|
data-i18n="tools:editBookmarks.jsonFormat"
|
||||||
|
>JSON format</span
|
||||||
|
>
|
||||||
<div
|
<div
|
||||||
class="relative flex flex-col items-center justify-center w-full h-32 mt-2 border-2 border-dashed border-gray-600 rounded-xl cursor-pointer bg-gray-800 hover:bg-gray-700 transition-colors duration-300"
|
class="relative flex flex-col items-center justify-center w-full h-32 mt-2 border-2 border-dashed border-gray-600 rounded-xl cursor-pointer bg-gray-800 hover:bg-gray-700 transition-colors duration-300"
|
||||||
>
|
>
|
||||||
<div class="flex flex-col items-center justify-center pt-4 pb-4">
|
<div class="flex flex-col items-center justify-center pt-4 pb-4">
|
||||||
<i data-lucide="braces" class="w-8 h-8 mb-2 text-gray-400"></i>
|
<i data-lucide="braces" class="w-8 h-8 mb-2 text-gray-400"></i>
|
||||||
<p class="text-xs text-gray-400">
|
<p class="text-xs text-gray-400">
|
||||||
<span class="font-semibold">Click to upload JSON</span> or
|
<span
|
||||||
drag here
|
class="font-semibold"
|
||||||
|
data-i18n="tools:editBookmarks.uploadJsonAction"
|
||||||
|
>Click to upload JSON</span
|
||||||
|
>
|
||||||
|
<span data-i18n="tools:editBookmarks.orDragHere"
|
||||||
|
>or drag here</span
|
||||||
|
>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<input
|
<input
|
||||||
@@ -659,7 +682,12 @@
|
|||||||
1
|
1
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-1">
|
<div class="flex-1">
|
||||||
<h3 class="text-lg font-semibold text-white mb-1">Upload File</h3>
|
<h3
|
||||||
|
class="text-lg font-semibold text-white mb-1"
|
||||||
|
data-i18n="howItWorks.step1Title"
|
||||||
|
>
|
||||||
|
Upload File
|
||||||
|
</h3>
|
||||||
<p class="text-gray-400" data-i18n="howItWorks.step1">
|
<p class="text-gray-400" data-i18n="howItWorks.step1">
|
||||||
Click or drag and drop your file to begin
|
Click or drag and drop your file to begin
|
||||||
</p>
|
</p>
|
||||||
@@ -672,7 +700,12 @@
|
|||||||
2
|
2
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-1">
|
<div class="flex-1">
|
||||||
<h3 class="text-lg font-semibold text-white mb-1">Process</h3>
|
<h3
|
||||||
|
class="text-lg font-semibold text-white mb-1"
|
||||||
|
data-i18n="howItWorks.step2Title"
|
||||||
|
>
|
||||||
|
Process
|
||||||
|
</h3>
|
||||||
<p class="text-gray-400" data-i18n="howItWorks.step2">
|
<p class="text-gray-400" data-i18n="howItWorks.step2">
|
||||||
Click the process button to start
|
Click the process button to start
|
||||||
</p>
|
</p>
|
||||||
@@ -685,7 +718,12 @@
|
|||||||
3
|
3
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-1">
|
<div class="flex-1">
|
||||||
<h3 class="text-lg font-semibold text-white mb-1">Download</h3>
|
<h3
|
||||||
|
class="text-lg font-semibold text-white mb-1"
|
||||||
|
data-i18n="howItWorks.step3Title"
|
||||||
|
>
|
||||||
|
Download
|
||||||
|
</h3>
|
||||||
<p class="text-gray-400" data-i18n="howItWorks.step3">
|
<p class="text-gray-400" data-i18n="howItWorks.step3">
|
||||||
Save your processed file instantly
|
Save your processed file instantly
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@@ -600,8 +600,18 @@
|
|||||||
class="flex flex-col items-center justify-center"
|
class="flex flex-col items-center justify-center"
|
||||||
>
|
>
|
||||||
<i data-lucide="file-text" class="w-8 h-8 mb-2 text-gray-400"></i>
|
<i data-lucide="file-text" class="w-8 h-8 mb-2 text-gray-400"></i>
|
||||||
<p class="text-sm text-gray-400">First PDF</p>
|
<p
|
||||||
<p class="text-xs text-gray-500">Click or drop</p>
|
class="text-sm text-gray-400"
|
||||||
|
data-i18n="tools:comparePdfs.firstPdf"
|
||||||
|
>
|
||||||
|
First PDF
|
||||||
|
</p>
|
||||||
|
<p
|
||||||
|
class="text-xs text-gray-500"
|
||||||
|
data-i18n="tools:comparePdfs.clickOrDrop"
|
||||||
|
>
|
||||||
|
Click or drop
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<input
|
<input
|
||||||
id="file-input-1"
|
id="file-input-1"
|
||||||
@@ -619,8 +629,18 @@
|
|||||||
class="flex flex-col items-center justify-center"
|
class="flex flex-col items-center justify-center"
|
||||||
>
|
>
|
||||||
<i data-lucide="file-text" class="w-8 h-8 mb-2 text-gray-400"></i>
|
<i data-lucide="file-text" class="w-8 h-8 mb-2 text-gray-400"></i>
|
||||||
<p class="text-sm text-gray-400">Second PDF</p>
|
<p
|
||||||
<p class="text-xs text-gray-500">Click or drop</p>
|
class="text-sm text-gray-400"
|
||||||
|
data-i18n="tools:comparePdfs.secondPdf"
|
||||||
|
>
|
||||||
|
Second PDF
|
||||||
|
</p>
|
||||||
|
<p
|
||||||
|
class="text-xs text-gray-500"
|
||||||
|
data-i18n="tools:comparePdfs.clickOrDrop"
|
||||||
|
>
|
||||||
|
Click or drop
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<input
|
<input
|
||||||
id="file-input-2"
|
id="file-input-2"
|
||||||
|
|||||||
+209
-39
@@ -134,10 +134,16 @@
|
|||||||
class="w-5 h-5 text-blue-400 flex-shrink-0 mt-0.5"
|
class="w-5 h-5 text-blue-400 flex-shrink-0 mt-0.5"
|
||||||
></i>
|
></i>
|
||||||
<div class="text-sm">
|
<div class="text-sm">
|
||||||
<p class="text-blue-300 font-medium">
|
<p
|
||||||
|
class="text-blue-300 font-medium"
|
||||||
|
data-i18n="tools:digitalSignPdf.internetRequiredTitle"
|
||||||
|
>
|
||||||
Internet connection required
|
Internet connection required
|
||||||
</p>
|
</p>
|
||||||
<p class="text-blue-400/80 mt-1">
|
<p
|
||||||
|
class="text-blue-400/80 mt-1"
|
||||||
|
data-i18n="tools:digitalSignPdf.internetRequiredDescription"
|
||||||
|
>
|
||||||
Signing may need to fetch certificate chain information from your
|
Signing may need to fetch certificate chain information from your
|
||||||
certificate issuer's server to validate the signature.
|
certificate issuer's server to validate the signature.
|
||||||
</p>
|
</p>
|
||||||
@@ -180,7 +186,12 @@
|
|||||||
<div id="file-display-area" class="mt-4 space-y-2"></div>
|
<div id="file-display-area" class="mt-4 space-y-2"></div>
|
||||||
|
|
||||||
<div id="certificate-section" class="hidden mt-6 space-y-4">
|
<div id="certificate-section" class="hidden mt-6 space-y-4">
|
||||||
<h2 class="text-lg font-semibold text-white">Certificate</h2>
|
<h2
|
||||||
|
class="text-lg font-semibold text-white"
|
||||||
|
data-i18n="tools:digitalSignPdf.certificateSection"
|
||||||
|
>
|
||||||
|
Certificate
|
||||||
|
</h2>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
id="cert-drop-zone"
|
id="cert-drop-zone"
|
||||||
@@ -188,7 +199,10 @@
|
|||||||
>
|
>
|
||||||
<div class="flex flex-col items-center justify-center py-4">
|
<div class="flex flex-col items-center justify-center py-4">
|
||||||
<i data-lucide="key" class="w-8 h-8 mb-2 text-gray-400"></i>
|
<i data-lucide="key" class="w-8 h-8 mb-2 text-gray-400"></i>
|
||||||
<p class="text-sm text-gray-400">
|
<p
|
||||||
|
class="text-sm text-gray-400"
|
||||||
|
data-i18n="tools:digitalSignPdf.uploadCert"
|
||||||
|
>
|
||||||
Upload certificate (.pfx, .p12, .pem)
|
Upload certificate (.pfx, .p12, .pem)
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -206,6 +220,7 @@
|
|||||||
<label
|
<label
|
||||||
for="cert-password"
|
for="cert-password"
|
||||||
class="block text-sm font-medium text-gray-300 mb-2"
|
class="block text-sm font-medium text-gray-300 mb-2"
|
||||||
|
data-i18n="tools:digitalSignPdf.certPassword"
|
||||||
>Certificate Password</label
|
>Certificate Password</label
|
||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
@@ -213,24 +228,40 @@
|
|||||||
id="cert-password"
|
id="cert-password"
|
||||||
class="w-full px-4 py-2 bg-gray-700 border border-gray-600 rounded-lg text-white placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-transparent"
|
class="w-full px-4 py-2 bg-gray-700 border border-gray-600 rounded-lg text-white placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-transparent"
|
||||||
placeholder="Enter certificate password"
|
placeholder="Enter certificate password"
|
||||||
|
data-i18n-placeholder="tools:digitalSignPdf.certPasswordPlaceholder"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="cert-info" class="hidden bg-gray-700 rounded-lg p-4">
|
<div id="cert-info" class="hidden bg-gray-700 rounded-lg p-4">
|
||||||
<h3 class="text-sm font-semibold text-white mb-2">
|
<h3
|
||||||
|
class="text-sm font-semibold text-white mb-2"
|
||||||
|
data-i18n="tools:digitalSignPdf.certInfo"
|
||||||
|
>
|
||||||
Certificate Information
|
Certificate Information
|
||||||
</h3>
|
</h3>
|
||||||
<div class="text-sm text-gray-300 space-y-1">
|
<div class="text-sm text-gray-300 space-y-1">
|
||||||
<p>
|
<p>
|
||||||
<span class="text-gray-400">Subject:</span>
|
<span
|
||||||
|
class="text-gray-400"
|
||||||
|
data-i18n="tools:digitalSignPdf.certSubject"
|
||||||
|
>Subject:</span
|
||||||
|
>
|
||||||
<span id="cert-subject">-</span>
|
<span id="cert-subject">-</span>
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<span class="text-gray-400">Issuer:</span>
|
<span
|
||||||
|
class="text-gray-400"
|
||||||
|
data-i18n="tools:digitalSignPdf.certIssuer"
|
||||||
|
>Issuer:</span
|
||||||
|
>
|
||||||
<span id="cert-issuer">-</span>
|
<span id="cert-issuer">-</span>
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<span class="text-gray-400">Valid:</span>
|
<span
|
||||||
|
class="text-gray-400"
|
||||||
|
data-i18n="tools:digitalSignPdf.certValidity"
|
||||||
|
>Valid:</span
|
||||||
|
>
|
||||||
<span id="cert-validity">-</span>
|
<span id="cert-validity">-</span>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -238,7 +269,10 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="signature-options" class="hidden mt-6 space-y-4">
|
<div id="signature-options" class="hidden mt-6 space-y-4">
|
||||||
<h2 class="text-lg font-semibold text-white">
|
<h2
|
||||||
|
class="text-lg font-semibold text-white"
|
||||||
|
data-i18n="tools:digitalSignPdf.signatureDetails"
|
||||||
|
>
|
||||||
Signature Details (Optional)
|
Signature Details (Optional)
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
@@ -246,6 +280,7 @@
|
|||||||
<label
|
<label
|
||||||
for="sign-reason"
|
for="sign-reason"
|
||||||
class="block text-sm font-medium text-gray-300 mb-2"
|
class="block text-sm font-medium text-gray-300 mb-2"
|
||||||
|
data-i18n="tools:digitalSignPdf.reason"
|
||||||
>Reason</label
|
>Reason</label
|
||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
@@ -253,6 +288,7 @@
|
|||||||
id="sign-reason"
|
id="sign-reason"
|
||||||
class="w-full px-4 py-2 bg-gray-700 border border-gray-600 rounded-lg text-white placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-transparent"
|
class="w-full px-4 py-2 bg-gray-700 border border-gray-600 rounded-lg text-white placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-transparent"
|
||||||
placeholder="e.g., I approve this document"
|
placeholder="e.g., I approve this document"
|
||||||
|
data-i18n-placeholder="tools:digitalSignPdf.reasonPlaceholder"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -260,6 +296,7 @@
|
|||||||
<label
|
<label
|
||||||
for="sign-location"
|
for="sign-location"
|
||||||
class="block text-sm font-medium text-gray-300 mb-2"
|
class="block text-sm font-medium text-gray-300 mb-2"
|
||||||
|
data-i18n="tools:digitalSignPdf.location"
|
||||||
>Location</label
|
>Location</label
|
||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
@@ -267,6 +304,7 @@
|
|||||||
id="sign-location"
|
id="sign-location"
|
||||||
class="w-full px-4 py-2 bg-gray-700 border border-gray-600 rounded-lg text-white placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-transparent"
|
class="w-full px-4 py-2 bg-gray-700 border border-gray-600 rounded-lg text-white placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-transparent"
|
||||||
placeholder="e.g., New York, USA"
|
placeholder="e.g., New York, USA"
|
||||||
|
data-i18n-placeholder="tools:digitalSignPdf.locationPlaceholder"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -274,6 +312,7 @@
|
|||||||
<label
|
<label
|
||||||
for="sign-contact"
|
for="sign-contact"
|
||||||
class="block text-sm font-medium text-gray-300 mb-2"
|
class="block text-sm font-medium text-gray-300 mb-2"
|
||||||
|
data-i18n="tools:digitalSignPdf.contactInfo"
|
||||||
>Contact Info</label
|
>Contact Info</label
|
||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
@@ -281,13 +320,19 @@
|
|||||||
id="sign-contact"
|
id="sign-contact"
|
||||||
class="w-full px-4 py-2 bg-gray-700 border border-gray-600 rounded-lg text-white placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-transparent"
|
class="w-full px-4 py-2 bg-gray-700 border border-gray-600 rounded-lg text-white placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-transparent"
|
||||||
placeholder="e.g., email@example.com"
|
placeholder="e.g., email@example.com"
|
||||||
|
data-i18n-placeholder="tools:digitalSignPdf.contactPlaceholder"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="visible-signature-section" class="hidden mt-6 space-y-4">
|
<div id="visible-signature-section" class="hidden mt-6 space-y-4">
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex items-center justify-between">
|
||||||
<h2 class="text-lg font-semibold text-white">Visible Signature</h2>
|
<h2
|
||||||
|
class="text-lg font-semibold text-white"
|
||||||
|
data-i18n="tools:digitalSignPdf.visibleSignature"
|
||||||
|
>
|
||||||
|
Visible Signature
|
||||||
|
</h2>
|
||||||
<label class="relative inline-flex items-center cursor-pointer">
|
<label class="relative inline-flex items-center cursor-pointer">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
@@ -299,7 +344,10 @@
|
|||||||
></div>
|
></div>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<p class="text-xs text-gray-500">
|
<p
|
||||||
|
class="text-xs text-gray-500"
|
||||||
|
data-i18n="tools:digitalSignPdf.visibleSignatureDescription"
|
||||||
|
>
|
||||||
When enabled, a visible signature box appears on the PDF. You can
|
When enabled, a visible signature box appears on the PDF. You can
|
||||||
upload an image/logo or add text. If neither is provided, the
|
upload an image/logo or add text. If neither is provided, the
|
||||||
signer's name from the certificate will be shown automatically.
|
signer's name from the certificate will be shown automatically.
|
||||||
@@ -307,7 +355,9 @@
|
|||||||
|
|
||||||
<div id="visible-sig-options" class="hidden space-y-4">
|
<div id="visible-sig-options" class="hidden space-y-4">
|
||||||
<div>
|
<div>
|
||||||
<label class="block text-sm font-medium text-gray-300 mb-2"
|
<label
|
||||||
|
class="block text-sm font-medium text-gray-300 mb-2"
|
||||||
|
data-i18n="tools:digitalSignPdf.signatureImage"
|
||||||
>Signature Image/Logo (Optional)</label
|
>Signature Image/Logo (Optional)</label
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
@@ -316,7 +366,10 @@
|
|||||||
>
|
>
|
||||||
<div class="flex flex-col items-center justify-center py-2">
|
<div class="flex flex-col items-center justify-center py-2">
|
||||||
<i data-lucide="image" class="w-6 h-6 mb-1 text-gray-400"></i>
|
<i data-lucide="image" class="w-6 h-6 mb-1 text-gray-400"></i>
|
||||||
<p class="text-xs text-gray-400">
|
<p
|
||||||
|
class="text-xs text-gray-400"
|
||||||
|
data-i18n="tools:digitalSignPdf.uploadSignatureImage"
|
||||||
|
>
|
||||||
Upload image (PNG, JPG, WebP)
|
Upload image (PNG, JPG, WebP)
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -339,6 +392,7 @@
|
|||||||
<button
|
<button
|
||||||
id="remove-sig-image"
|
id="remove-sig-image"
|
||||||
class="text-red-400 hover:text-red-300 text-sm"
|
class="text-red-400 hover:text-red-300 text-sm"
|
||||||
|
data-i18n="tools:digitalSignPdf.remove"
|
||||||
>
|
>
|
||||||
Remove
|
Remove
|
||||||
</button>
|
</button>
|
||||||
@@ -350,22 +404,38 @@
|
|||||||
<label
|
<label
|
||||||
for="sig-page"
|
for="sig-page"
|
||||||
class="block text-sm font-medium text-gray-300 mb-2"
|
class="block text-sm font-medium text-gray-300 mb-2"
|
||||||
|
data-i18n="tools:digitalSignPdf.page"
|
||||||
>Page</label
|
>Page</label
|
||||||
>
|
>
|
||||||
<select
|
<select
|
||||||
id="sig-page"
|
id="sig-page"
|
||||||
class="w-full px-4 py-2 bg-gray-700 border border-gray-600 rounded-lg text-white focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-transparent"
|
class="w-full px-4 py-2 bg-gray-700 border border-gray-600 rounded-lg text-white focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-transparent"
|
||||||
>
|
>
|
||||||
<option value="0">First page</option>
|
<option value="0" data-i18n="tools:digitalSignPdf.firstPage">
|
||||||
<option value="last">Last page</option>
|
First page
|
||||||
<option value="all">All pages</option>
|
</option>
|
||||||
<option value="custom">Custom page #</option>
|
<option
|
||||||
|
value="last"
|
||||||
|
data-i18n="tools:digitalSignPdf.lastPage"
|
||||||
|
>
|
||||||
|
Last page
|
||||||
|
</option>
|
||||||
|
<option value="all" data-i18n="tools:digitalSignPdf.allPages">
|
||||||
|
All pages
|
||||||
|
</option>
|
||||||
|
<option
|
||||||
|
value="custom"
|
||||||
|
data-i18n="tools:digitalSignPdf.customPage"
|
||||||
|
>
|
||||||
|
Custom page #
|
||||||
|
</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div id="custom-page-wrapper" class="hidden">
|
<div id="custom-page-wrapper" class="hidden">
|
||||||
<label
|
<label
|
||||||
for="sig-custom-page"
|
for="sig-custom-page"
|
||||||
class="block text-sm font-medium text-gray-300 mb-2"
|
class="block text-sm font-medium text-gray-300 mb-2"
|
||||||
|
data-i18n="tools:digitalSignPdf.pageNumber"
|
||||||
>Page #</label
|
>Page #</label
|
||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
@@ -383,6 +453,7 @@
|
|||||||
<label
|
<label
|
||||||
for="sig-x"
|
for="sig-x"
|
||||||
class="block text-sm font-medium text-gray-300 mb-2"
|
class="block text-sm font-medium text-gray-300 mb-2"
|
||||||
|
data-i18n="tools:digitalSignPdf.xPosition"
|
||||||
>X Position (left)</label
|
>X Position (left)</label
|
||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
@@ -397,6 +468,7 @@
|
|||||||
<label
|
<label
|
||||||
for="sig-y"
|
for="sig-y"
|
||||||
class="block text-sm font-medium text-gray-300 mb-2"
|
class="block text-sm font-medium text-gray-300 mb-2"
|
||||||
|
data-i18n="tools:digitalSignPdf.yPosition"
|
||||||
>Y Position (top)</label
|
>Y Position (top)</label
|
||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
@@ -414,6 +486,7 @@
|
|||||||
<label
|
<label
|
||||||
for="sig-width"
|
for="sig-width"
|
||||||
class="block text-sm font-medium text-gray-300 mb-2"
|
class="block text-sm font-medium text-gray-300 mb-2"
|
||||||
|
data-i18n="tools:digitalSignPdf.width"
|
||||||
>Width</label
|
>Width</label
|
||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
@@ -428,6 +501,7 @@
|
|||||||
<label
|
<label
|
||||||
for="sig-height"
|
for="sig-height"
|
||||||
class="block text-sm font-medium text-gray-300 mb-2"
|
class="block text-sm font-medium text-gray-300 mb-2"
|
||||||
|
data-i18n="tools:digitalSignPdf.height"
|
||||||
>Height</label
|
>Height</label
|
||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
@@ -447,7 +521,9 @@
|
|||||||
id="enable-sig-text"
|
id="enable-sig-text"
|
||||||
class="w-4 h-4 text-indigo-600 bg-gray-700 border-gray-600 rounded focus:ring-indigo-500"
|
class="w-4 h-4 text-indigo-600 bg-gray-700 border-gray-600 rounded focus:ring-indigo-500"
|
||||||
/>
|
/>
|
||||||
<span class="text-sm font-medium text-gray-300"
|
<span
|
||||||
|
class="text-sm font-medium text-gray-300"
|
||||||
|
data-i18n="tools:digitalSignPdf.addTextOverlay"
|
||||||
>Add text overlay</span
|
>Add text overlay</span
|
||||||
>
|
>
|
||||||
</label>
|
</label>
|
||||||
@@ -458,6 +534,7 @@
|
|||||||
<label
|
<label
|
||||||
for="sig-text"
|
for="sig-text"
|
||||||
class="block text-sm font-medium text-gray-300 mb-2"
|
class="block text-sm font-medium text-gray-300 mb-2"
|
||||||
|
data-i18n="tools:digitalSignPdf.text"
|
||||||
>Text</label
|
>Text</label
|
||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
@@ -465,6 +542,7 @@
|
|||||||
id="sig-text"
|
id="sig-text"
|
||||||
class="w-full px-4 py-2 bg-gray-700 border border-gray-600 rounded-lg text-white placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-transparent"
|
class="w-full px-4 py-2 bg-gray-700 border border-gray-600 rounded-lg text-white placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-transparent"
|
||||||
placeholder="e.g., Digitally signed by John Doe"
|
placeholder="e.g., Digitally signed by John Doe"
|
||||||
|
data-i18n-placeholder="tools:digitalSignPdf.textPlaceholder"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid grid-cols-2 gap-4">
|
<div class="grid grid-cols-2 gap-4">
|
||||||
@@ -472,6 +550,7 @@
|
|||||||
<label
|
<label
|
||||||
for="sig-text-color"
|
for="sig-text-color"
|
||||||
class="block text-sm font-medium text-gray-300 mb-2"
|
class="block text-sm font-medium text-gray-300 mb-2"
|
||||||
|
data-i18n="tools:digitalSignPdf.textColor"
|
||||||
>Text Color</label
|
>Text Color</label
|
||||||
>
|
>
|
||||||
<input type="color" id="sig-text-color" value="#000000" />
|
<input type="color" id="sig-text-color" value="#000000" />
|
||||||
@@ -480,6 +559,7 @@
|
|||||||
<label
|
<label
|
||||||
for="sig-text-size"
|
for="sig-text-size"
|
||||||
class="block text-sm font-medium text-gray-300 mb-2"
|
class="block text-sm font-medium text-gray-300 mb-2"
|
||||||
|
data-i18n="tools:digitalSignPdf.fontSize"
|
||||||
>Font Size</label
|
>Font Size</label
|
||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
@@ -500,6 +580,7 @@
|
|||||||
id="process-btn"
|
id="process-btn"
|
||||||
class="btn-gradient w-full mt-6"
|
class="btn-gradient w-full mt-6"
|
||||||
style="display: none"
|
style="display: none"
|
||||||
|
data-i18n="tools:digitalSignPdf.applySignature"
|
||||||
>
|
>
|
||||||
Apply Digital Signature
|
Apply Digital Signature
|
||||||
</button>
|
</button>
|
||||||
@@ -514,7 +595,11 @@
|
|||||||
class="bg-gray-800 p-8 rounded-lg flex flex-col items-center gap-4 border border-gray-700 shadow-xl"
|
class="bg-gray-800 p-8 rounded-lg flex flex-col items-center gap-4 border border-gray-700 shadow-xl"
|
||||||
>
|
>
|
||||||
<div class="solid-spinner"></div>
|
<div class="solid-spinner"></div>
|
||||||
<p id="loader-text" class="text-white text-lg font-medium">
|
<p
|
||||||
|
id="loader-text"
|
||||||
|
class="text-white text-lg font-medium"
|
||||||
|
data-i18n="loader.processing"
|
||||||
|
>
|
||||||
Processing...
|
Processing...
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -538,6 +623,7 @@
|
|||||||
<button
|
<button
|
||||||
id="alert-ok"
|
id="alert-ok"
|
||||||
class="w-full bg-indigo-600 hover:bg-indigo-700 text-white font-semibold py-2 px-4 rounded-lg transition-colors duration-200"
|
class="w-full bg-indigo-600 hover:bg-indigo-700 text-white font-semibold py-2 px-4 rounded-lg transition-colors duration-200"
|
||||||
|
data-i18n="common.ok"
|
||||||
>
|
>
|
||||||
OK
|
OK
|
||||||
</button>
|
</button>
|
||||||
@@ -559,8 +645,16 @@
|
|||||||
1
|
1
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-1">
|
<div class="flex-1">
|
||||||
<h3 class="text-lg font-semibold text-white mb-1">Upload PDF</h3>
|
<h3
|
||||||
<p class="text-gray-400">
|
class="text-lg font-semibold text-white mb-1"
|
||||||
|
data-i18n="tools:digitalSignPdf.howToStep1Title"
|
||||||
|
>
|
||||||
|
Upload PDF
|
||||||
|
</h3>
|
||||||
|
<p
|
||||||
|
class="text-gray-400"
|
||||||
|
data-i18n="tools:digitalSignPdf.howToStep1Text"
|
||||||
|
>
|
||||||
Select the PDF document you want to sign
|
Select the PDF document you want to sign
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -573,9 +667,14 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="flex-1">
|
<div class="flex-1">
|
||||||
<h3 class="text-lg font-semibold text-white mb-1">
|
<h3 class="text-lg font-semibold text-white mb-1">
|
||||||
Upload Certificate
|
<span data-i18n="tools:digitalSignPdf.howToStep2Title">
|
||||||
|
Upload Certificate
|
||||||
|
</span>
|
||||||
</h3>
|
</h3>
|
||||||
<p class="text-gray-400">
|
<p
|
||||||
|
class="text-gray-400"
|
||||||
|
data-i18n="tools:digitalSignPdf.howToStep2Text"
|
||||||
|
>
|
||||||
Provide your .pfx or .p12 certificate file and password
|
Provide your .pfx or .p12 certificate file and password
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -588,9 +687,14 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="flex-1">
|
<div class="flex-1">
|
||||||
<h3 class="text-lg font-semibold text-white mb-1">
|
<h3 class="text-lg font-semibold text-white mb-1">
|
||||||
Sign & Download
|
<span data-i18n="tools:digitalSignPdf.howToStep3Title">
|
||||||
|
Sign & Download
|
||||||
|
</span>
|
||||||
</h3>
|
</h3>
|
||||||
<p class="text-gray-400">
|
<p
|
||||||
|
class="text-gray-400"
|
||||||
|
data-i18n="tools:digitalSignPdf.howToStep3Text"
|
||||||
|
>
|
||||||
Apply the digital signature and download your signed PDF
|
Apply the digital signature and download your signed PDF
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -610,36 +714,86 @@
|
|||||||
href="encrypt-pdf.html"
|
href="encrypt-pdf.html"
|
||||||
class="block bg-gray-800 p-4 rounded-lg hover:bg-gray-700 transition-colors border border-gray-700"
|
class="block bg-gray-800 p-4 rounded-lg hover:bg-gray-700 transition-colors border border-gray-700"
|
||||||
>
|
>
|
||||||
<h3 class="text-white font-semibold mb-1">Encrypt PDF</h3>
|
<h3
|
||||||
<p class="text-gray-400 text-sm">Password protect your PDF</p>
|
class="text-white font-semibold mb-1"
|
||||||
|
data-i18n="tools:encryptPdf.name"
|
||||||
|
>
|
||||||
|
Encrypt PDF
|
||||||
|
</h3>
|
||||||
|
<p
|
||||||
|
class="text-gray-400 text-sm"
|
||||||
|
data-i18n="tools:digitalSignPdf.relatedEncryptDesc"
|
||||||
|
>
|
||||||
|
Password protect your PDF
|
||||||
|
</p>
|
||||||
</a>
|
</a>
|
||||||
<a
|
<a
|
||||||
href="decrypt-pdf.html"
|
href="decrypt-pdf.html"
|
||||||
class="block bg-gray-800 p-4 rounded-lg hover:bg-gray-700 transition-colors border border-gray-700"
|
class="block bg-gray-800 p-4 rounded-lg hover:bg-gray-700 transition-colors border border-gray-700"
|
||||||
>
|
>
|
||||||
<h3 class="text-white font-semibold mb-1">Decrypt PDF</h3>
|
<h3
|
||||||
<p class="text-gray-400 text-sm">Remove PDF password</p>
|
class="text-white font-semibold mb-1"
|
||||||
|
data-i18n="tools:decryptPdf.name"
|
||||||
|
>
|
||||||
|
Decrypt PDF
|
||||||
|
</h3>
|
||||||
|
<p
|
||||||
|
class="text-gray-400 text-sm"
|
||||||
|
data-i18n="tools:digitalSignPdf.relatedDecryptDesc"
|
||||||
|
>
|
||||||
|
Remove PDF password
|
||||||
|
</p>
|
||||||
</a>
|
</a>
|
||||||
<a
|
<a
|
||||||
href="flatten-pdf.html"
|
href="flatten-pdf.html"
|
||||||
class="block bg-gray-800 p-4 rounded-lg hover:bg-gray-700 transition-colors border border-gray-700"
|
class="block bg-gray-800 p-4 rounded-lg hover:bg-gray-700 transition-colors border border-gray-700"
|
||||||
>
|
>
|
||||||
<h3 class="text-white font-semibold mb-1">Flatten PDF</h3>
|
<h3
|
||||||
<p class="text-gray-400 text-sm">Make annotations permanent</p>
|
class="text-white font-semibold mb-1"
|
||||||
|
data-i18n="tools:flattenPdf.name"
|
||||||
|
>
|
||||||
|
Flatten PDF
|
||||||
|
</h3>
|
||||||
|
<p
|
||||||
|
class="text-gray-400 text-sm"
|
||||||
|
data-i18n="tools:digitalSignPdf.relatedFlattenDesc"
|
||||||
|
>
|
||||||
|
Make annotations permanent
|
||||||
|
</p>
|
||||||
</a>
|
</a>
|
||||||
<a
|
<a
|
||||||
href="sanitize-pdf.html"
|
href="sanitize-pdf.html"
|
||||||
class="block bg-gray-800 p-4 rounded-lg hover:bg-gray-700 transition-colors border border-gray-700"
|
class="block bg-gray-800 p-4 rounded-lg hover:bg-gray-700 transition-colors border border-gray-700"
|
||||||
>
|
>
|
||||||
<h3 class="text-white font-semibold mb-1">Sanitize PDF</h3>
|
<h3
|
||||||
<p class="text-gray-400 text-sm">Remove hidden data</p>
|
class="text-white font-semibold mb-1"
|
||||||
|
data-i18n="tools:sanitizePdf.name"
|
||||||
|
>
|
||||||
|
Sanitize PDF
|
||||||
|
</h3>
|
||||||
|
<p
|
||||||
|
class="text-gray-400 text-sm"
|
||||||
|
data-i18n="tools:digitalSignPdf.relatedSanitizeDesc"
|
||||||
|
>
|
||||||
|
Remove hidden data
|
||||||
|
</p>
|
||||||
</a>
|
</a>
|
||||||
<a
|
<a
|
||||||
href="change-permissions.html"
|
href="change-permissions.html"
|
||||||
class="block bg-gray-800 p-4 rounded-lg hover:bg-gray-700 transition-colors border border-gray-700"
|
class="block bg-gray-800 p-4 rounded-lg hover:bg-gray-700 transition-colors border border-gray-700"
|
||||||
>
|
>
|
||||||
<h3 class="text-white font-semibold mb-1">Change Permissions</h3>
|
<h3
|
||||||
<p class="text-gray-400 text-sm">Set PDF permissions</p>
|
class="text-white font-semibold mb-1"
|
||||||
|
data-i18n="tools:changePermissions.name"
|
||||||
|
>
|
||||||
|
Change Permissions
|
||||||
|
</h3>
|
||||||
|
<p
|
||||||
|
class="text-gray-400 text-sm"
|
||||||
|
data-i18n="tools:digitalSignPdf.relatedPermissionsDesc"
|
||||||
|
>
|
||||||
|
Set PDF permissions
|
||||||
|
</p>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
@@ -655,11 +809,15 @@
|
|||||||
<details class="bg-gray-800 p-5 rounded-lg border border-gray-700">
|
<details class="bg-gray-800 p-5 rounded-lg border border-gray-700">
|
||||||
<summary
|
<summary
|
||||||
class="cursor-pointer font-semibold text-white flex items-center justify-between"
|
class="cursor-pointer font-semibold text-white flex items-center justify-between"
|
||||||
|
data-i18n="tools:digitalSignPdf.faqWhatIsQuestion"
|
||||||
>
|
>
|
||||||
What is a digital signature?
|
What is a digital signature?
|
||||||
<i data-lucide="chevron-down" class="w-5 h-5"></i>
|
<i data-lucide="chevron-down" class="w-5 h-5"></i>
|
||||||
</summary>
|
</summary>
|
||||||
<p class="mt-3 text-gray-400">
|
<p
|
||||||
|
class="mt-3 text-gray-400"
|
||||||
|
data-i18n="tools:digitalSignPdf.faqWhatIsAnswer"
|
||||||
|
>
|
||||||
A digital signature is a cryptographic mechanism that verifies the
|
A digital signature is a cryptographic mechanism that verifies the
|
||||||
authenticity and integrity of a document. Unlike a drawn signature,
|
authenticity and integrity of a document. Unlike a drawn signature,
|
||||||
it uses public key cryptography (X.509 certificates) to prove the
|
it uses public key cryptography (X.509 certificates) to prove the
|
||||||
@@ -669,11 +827,15 @@
|
|||||||
<details class="bg-gray-800 p-5 rounded-lg border border-gray-700">
|
<details class="bg-gray-800 p-5 rounded-lg border border-gray-700">
|
||||||
<summary
|
<summary
|
||||||
class="cursor-pointer font-semibold text-white flex items-center justify-between"
|
class="cursor-pointer font-semibold text-white flex items-center justify-between"
|
||||||
|
data-i18n="tools:digitalSignPdf.faqFormatsQuestion"
|
||||||
>
|
>
|
||||||
What certificate formats are supported?
|
What certificate formats are supported?
|
||||||
<i data-lucide="chevron-down" class="w-5 h-5"></i>
|
<i data-lucide="chevron-down" class="w-5 h-5"></i>
|
||||||
</summary>
|
</summary>
|
||||||
<p class="mt-3 text-gray-400">
|
<p
|
||||||
|
class="mt-3 text-gray-400"
|
||||||
|
data-i18n="tools:digitalSignPdf.faqFormatsAnswer"
|
||||||
|
>
|
||||||
We support PKCS#12 format certificates (.pfx, .p12) which contain
|
We support PKCS#12 format certificates (.pfx, .p12) which contain
|
||||||
both your certificate and private key in a single encrypted file.
|
both your certificate and private key in a single encrypted file.
|
||||||
These are commonly issued by certificate authorities.
|
These are commonly issued by certificate authorities.
|
||||||
@@ -682,11 +844,15 @@
|
|||||||
<details class="bg-gray-800 p-5 rounded-lg border border-gray-700">
|
<details class="bg-gray-800 p-5 rounded-lg border border-gray-700">
|
||||||
<summary
|
<summary
|
||||||
class="cursor-pointer font-semibold text-white flex items-center justify-between"
|
class="cursor-pointer font-semibold text-white flex items-center justify-between"
|
||||||
|
data-i18n="tools:digitalSignPdf.faqPrivateKeyQuestion"
|
||||||
>
|
>
|
||||||
Is my private key safe?
|
Is my private key safe?
|
||||||
<i data-lucide="chevron-down" class="w-5 h-5"></i>
|
<i data-lucide="chevron-down" class="w-5 h-5"></i>
|
||||||
</summary>
|
</summary>
|
||||||
<p class="mt-3 text-gray-400">
|
<p
|
||||||
|
class="mt-3 text-gray-400"
|
||||||
|
data-i18n="tools:digitalSignPdf.faqPrivateKeyAnswer"
|
||||||
|
>
|
||||||
Yes! All processing happens entirely in your browser. Your
|
Yes! All processing happens entirely in your browser. Your
|
||||||
certificate, private key, and PDF files never leave your device or
|
certificate, private key, and PDF files never leave your device or
|
||||||
get uploaded to any server.
|
get uploaded to any server.
|
||||||
@@ -695,11 +861,15 @@
|
|||||||
<details class="bg-gray-800 p-5 rounded-lg border border-gray-700">
|
<details class="bg-gray-800 p-5 rounded-lg border border-gray-700">
|
||||||
<summary
|
<summary
|
||||||
class="cursor-pointer font-semibold text-white flex items-center justify-between"
|
class="cursor-pointer font-semibold text-white flex items-center justify-between"
|
||||||
|
data-i18n="tools:digitalSignPdf.faqValidReadersQuestion"
|
||||||
>
|
>
|
||||||
Will the signature be valid in PDF readers?
|
Will the signature be valid in PDF readers?
|
||||||
<i data-lucide="chevron-down" class="w-5 h-5"></i>
|
<i data-lucide="chevron-down" class="w-5 h-5"></i>
|
||||||
</summary>
|
</summary>
|
||||||
<p class="mt-3 text-gray-400">
|
<p
|
||||||
|
class="mt-3 text-gray-400"
|
||||||
|
data-i18n="tools:digitalSignPdf.faqValidReadersAnswer"
|
||||||
|
>
|
||||||
Yes, the tool creates standard PKCS#7 detached signatures that are
|
Yes, the tool creates standard PKCS#7 detached signatures that are
|
||||||
recognized by all major PDF viewers. For full validation, use a
|
recognized by all major PDF viewers. For full validation, use a
|
||||||
certificate from a trusted Certificate Authority.
|
certificate from a trusted Certificate Authority.
|
||||||
|
|||||||
@@ -166,7 +166,11 @@
|
|||||||
<div class="w-full border-t border-gray-600"></div>
|
<div class="w-full border-t border-gray-600"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="relative flex justify-center text-sm">
|
<div class="relative flex justify-center text-sm">
|
||||||
<span class="px-4 bg-gray-800 text-gray-400 font-medium">OR</span>
|
<span
|
||||||
|
class="px-4 bg-gray-800 text-gray-400 font-medium"
|
||||||
|
data-i18n="tools:createPdfForm.orSeparator"
|
||||||
|
>OR</span
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -176,7 +180,11 @@
|
|||||||
class="w-full bg-gray-700 hover:bg-gray-600 text-white p-4 rounded-lg flex items-center justify-center gap-3 transition-colors"
|
class="w-full bg-gray-700 hover:bg-gray-600 text-white p-4 rounded-lg flex items-center justify-center gap-3 transition-colors"
|
||||||
>
|
>
|
||||||
<i data-lucide="file-plus" class="w-5 h-5"></i>
|
<i data-lucide="file-plus" class="w-5 h-5"></i>
|
||||||
<span class="font-semibold">Create Blank PDF</span>
|
<span
|
||||||
|
class="font-semibold"
|
||||||
|
data-i18n="tools:createPdfForm.createBlankPdf"
|
||||||
|
>Create Blank PDF</span
|
||||||
|
>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<div id="pageSizeSelector" class="mt-4 hidden">
|
<div id="pageSizeSelector" class="mt-4 hidden">
|
||||||
|
|||||||
@@ -121,7 +121,10 @@
|
|||||||
>
|
>
|
||||||
PDF Form Filler
|
PDF Form Filler
|
||||||
</h1>
|
</h1>
|
||||||
<p class="text-gray-400 mb-4">
|
<p
|
||||||
|
class="text-gray-400 mb-4"
|
||||||
|
data-i18n="tools:pdfFormFiller.uploadHint"
|
||||||
|
>
|
||||||
Upload a PDF with form fields. Fill them directly in the viewer below,
|
Upload a PDF with form fields. Fill them directly in the viewer below,
|
||||||
then click the button to save and download the filled form. Also
|
then click the button to save and download the filled form. Also
|
||||||
supports XFA forms.
|
supports XFA forms.
|
||||||
@@ -131,12 +134,16 @@
|
|||||||
class="mb-6 p-3 bg-blue-900/20 border border-blue-700/50 rounded-lg"
|
class="mb-6 p-3 bg-blue-900/20 border border-blue-700/50 rounded-lg"
|
||||||
>
|
>
|
||||||
<p class="text-sm text-blue-300">
|
<p class="text-sm text-blue-300">
|
||||||
<strong>Note on XFA Forms:</strong> XFA (XML Forms Architecture) is
|
<strong data-i18n="tools:pdfFormFiller.xfaNoteTitle"
|
||||||
a legacy format that's only supported by certain PDF viewers like
|
>Note on XFA Forms:</strong
|
||||||
BentoPDF and Firefox. If you open an XFA PDF in other software and
|
>
|
||||||
see blank pages or no form fields, it means that viewer doesn't
|
<span data-i18n="tools:pdfFormFiller.xfaNoteDescription"
|
||||||
support XFA. To view and fill XFA forms properly, use Firefox or
|
>XFA (XML Forms Architecture) is a legacy format that's only
|
||||||
BentoPDF's Form Filler.
|
supported by certain PDF viewers like BentoPDF and Firefox. If you
|
||||||
|
open an XFA PDF in other software and see blank pages or no form
|
||||||
|
fields, it means that viewer doesn't support XFA. To view and fill
|
||||||
|
XFA forms properly, use Firefox or BentoPDF's Form Filler.</span
|
||||||
|
>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -120,9 +120,12 @@
|
|||||||
class="bg-yellow-900/30 border border-yellow-700 rounded-lg p-3 mb-6"
|
class="bg-yellow-900/30 border border-yellow-700 rounded-lg p-3 mb-6"
|
||||||
>
|
>
|
||||||
<p class="text-yellow-200 text-sm">
|
<p class="text-yellow-200 text-sm">
|
||||||
<strong>Note:</strong> Only JSON files created by the PDF-to-JSON
|
<strong data-i18n="tools:jsonToPdf.noteLabel">Note:</strong>
|
||||||
converter tool are supported. Standard JSON files from other tools
|
<span data-i18n="tools:jsonToPdf.noteText"
|
||||||
will not work.
|
>Only JSON files created by the PDF-to-JSON converter tool are
|
||||||
|
supported. Standard JSON files from other tools will not
|
||||||
|
work.</span
|
||||||
|
>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -141,7 +144,12 @@
|
|||||||
>
|
>
|
||||||
<span data-i18n="upload.orDragAndDrop">or drag and drop</span>
|
<span data-i18n="upload.orDragAndDrop">or drag and drop</span>
|
||||||
</p>
|
</p>
|
||||||
<p class="text-xs text-gray-500">Multiple JSON files</p>
|
<p
|
||||||
|
class="text-xs text-gray-500"
|
||||||
|
data-i18n="tools:jsonToPdf.acceptedFormats"
|
||||||
|
>
|
||||||
|
Multiple JSON files
|
||||||
|
</p>
|
||||||
<p
|
<p
|
||||||
class="text-xs text-gray-500"
|
class="text-xs text-gray-500"
|
||||||
data-i18n="upload.filesNeverLeave"
|
data-i18n="upload.filesNeverLeave"
|
||||||
@@ -161,7 +169,12 @@
|
|||||||
<!-- File Display Area -->
|
<!-- File Display Area -->
|
||||||
<div id="fileList" class="mt-4 hidden"></div>
|
<div id="fileList" class="mt-4 hidden"></div>
|
||||||
|
|
||||||
<button id="convertBtn" disabled class="btn-gradient w-full mt-6">
|
<button
|
||||||
|
id="convertBtn"
|
||||||
|
disabled
|
||||||
|
class="btn-gradient w-full mt-6"
|
||||||
|
data-i18n="tools:convertToPdf"
|
||||||
|
>
|
||||||
Convert to PDF
|
Convert to PDF
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+142
-34
@@ -131,29 +131,58 @@
|
|||||||
<!-- How it works info box -->
|
<!-- How it works info box -->
|
||||||
<div class="p-3 bg-gray-900 rounded-lg border border-gray-700 mb-6">
|
<div class="p-3 bg-gray-900 rounded-lg border border-gray-700 mb-6">
|
||||||
<p class="text-sm text-gray-300">
|
<p class="text-sm text-gray-300">
|
||||||
<strong class="text-white">How it works:</strong>
|
<strong class="text-white" data-i18n="tools:ocrPdf.howItWorksTitle"
|
||||||
|
>How it works:</strong
|
||||||
|
>
|
||||||
</p>
|
</p>
|
||||||
<ul
|
<ul
|
||||||
class="list-disc list-inside text-xs text-gray-400 mt-1 space-y-1"
|
class="list-disc list-inside text-xs text-gray-400 mt-1 space-y-1"
|
||||||
>
|
>
|
||||||
<li>
|
<li>
|
||||||
<strong class="text-white">Extract Text:</strong> Uses Tesseract
|
<strong
|
||||||
OCR to recognize text from scanned images or PDFs.
|
class="text-white"
|
||||||
|
data-i18n="tools:ocrPdf.extractTextLabel"
|
||||||
|
>Extract Text:</strong
|
||||||
|
>
|
||||||
|
<span data-i18n="tools:ocrPdf.extractTextDescription"
|
||||||
|
>Uses Tesseract OCR to recognize text from scanned images or
|
||||||
|
PDFs.</span
|
||||||
|
>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<strong class="text-white">Searchable Output:</strong> Creates a
|
<strong
|
||||||
new PDF with an invisible text layer, making your document fully
|
class="text-white"
|
||||||
searchable while preserving the original appearance.
|
data-i18n="tools:ocrPdf.searchableOutputLabel"
|
||||||
|
>Searchable Output:</strong
|
||||||
|
>
|
||||||
|
<span data-i18n="tools:ocrPdf.searchableOutputDescription"
|
||||||
|
>Creates a new PDF with an invisible text layer, making your
|
||||||
|
document fully searchable while preserving the original
|
||||||
|
appearance.</span
|
||||||
|
>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<strong class="text-white">Character Filtering:</strong> Use
|
<strong
|
||||||
whitelists to filter out unwanted characters and improve accuracy
|
class="text-white"
|
||||||
for specific document types (invoices, forms, etc.).
|
data-i18n="tools:ocrPdf.characterFilteringLabel"
|
||||||
|
>Character Filtering:</strong
|
||||||
|
>
|
||||||
|
<span data-i18n="tools:ocrPdf.characterFilteringDescription"
|
||||||
|
>Use whitelists to filter out unwanted characters and improve
|
||||||
|
accuracy for specific document types (invoices, forms,
|
||||||
|
etc.).</span
|
||||||
|
>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<strong class="text-white">Multi-language Support:</strong> Select
|
<strong
|
||||||
multiple languages for documents containing mixed language
|
class="text-white"
|
||||||
content.
|
data-i18n="tools:ocrPdf.multiLanguageSupportLabel"
|
||||||
|
>Multi-language Support:</strong
|
||||||
|
>
|
||||||
|
<span data-i18n="tools:ocrPdf.multiLanguageSupportDescription"
|
||||||
|
>Select multiple languages for documents containing mixed
|
||||||
|
language content.</span
|
||||||
|
>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
@@ -190,7 +219,9 @@
|
|||||||
<!-- OCR Options -->
|
<!-- OCR Options -->
|
||||||
<div id="tool-options" class="hidden mt-6 space-y-4">
|
<div id="tool-options" class="hidden mt-6 space-y-4">
|
||||||
<div>
|
<div>
|
||||||
<label class="block mb-2 text-sm font-medium text-gray-300"
|
<label
|
||||||
|
class="block mb-2 text-sm font-medium text-gray-300"
|
||||||
|
data-i18n="tools:ocrPdf.languagesInDocument"
|
||||||
>Languages in Document</label
|
>Languages in Document</label
|
||||||
>
|
>
|
||||||
<div class="relative">
|
<div class="relative">
|
||||||
@@ -199,6 +230,7 @@
|
|||||||
id="lang-search"
|
id="lang-search"
|
||||||
class="w-full bg-gray-900 border border-gray-600 text-white rounded-lg p-2.5 mb-2"
|
class="w-full bg-gray-900 border border-gray-600 text-white rounded-lg p-2.5 mb-2"
|
||||||
placeholder="Search for languages..."
|
placeholder="Search for languages..."
|
||||||
|
data-i18n-placeholder="tools:ocrPdf.searchLanguagesPlaceholder"
|
||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
id="lang-list"
|
id="lang-list"
|
||||||
@@ -208,8 +240,11 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p class="text-xs text-gray-500 mt-1">
|
<p class="text-xs text-gray-500 mt-1">
|
||||||
Selected:
|
<span data-i18n="tools:ocrPdf.selectedLabel">Selected:</span>
|
||||||
<span id="selected-langs-display" class="font-semibold"
|
<span
|
||||||
|
id="selected-langs-display"
|
||||||
|
class="font-semibold"
|
||||||
|
data-i18n="tools:ocrPdf.none"
|
||||||
>None</span
|
>None</span
|
||||||
>
|
>
|
||||||
</p>
|
</p>
|
||||||
@@ -224,7 +259,9 @@
|
|||||||
<summary
|
<summary
|
||||||
class="text-sm font-medium text-gray-300 cursor-pointer flex items-center justify-between"
|
class="text-sm font-medium text-gray-300 cursor-pointer flex items-center justify-between"
|
||||||
>
|
>
|
||||||
<span>Advanced Settings (Recommended to improve accuracy)</span>
|
<span data-i18n="tools:ocrPdf.advancedSettingsSummary"
|
||||||
|
>Advanced Settings (Recommended to improve accuracy)</span
|
||||||
|
>
|
||||||
<i
|
<i
|
||||||
data-lucide="chevron-down"
|
data-lucide="chevron-down"
|
||||||
class="w-4 h-4 transition-transform details-icon"
|
class="w-4 h-4 transition-transform details-icon"
|
||||||
@@ -236,15 +273,29 @@
|
|||||||
<label
|
<label
|
||||||
for="ocr-resolution"
|
for="ocr-resolution"
|
||||||
class="block mb-1 text-xs font-medium text-gray-400"
|
class="block mb-1 text-xs font-medium text-gray-400"
|
||||||
|
data-i18n="tools:ocrPdf.resolutionLabel"
|
||||||
>Resolution</label
|
>Resolution</label
|
||||||
>
|
>
|
||||||
<select
|
<select
|
||||||
id="ocr-resolution"
|
id="ocr-resolution"
|
||||||
class="w-full bg-gray-700 border border-gray-600 text-white rounded-lg p-2 text-sm"
|
class="w-full bg-gray-700 border border-gray-600 text-white rounded-lg p-2 text-sm"
|
||||||
>
|
>
|
||||||
<option value="2.0">Standard (192 DPI)</option>
|
<option
|
||||||
<option value="3.0" selected>High (288 DPI)</option>
|
value="2.0"
|
||||||
<option value="4.0">Ultra (384 DPI)</option>
|
data-i18n="tools:ocrPdf.resolutionStandard"
|
||||||
|
>
|
||||||
|
Standard (192 DPI)
|
||||||
|
</option>
|
||||||
|
<option
|
||||||
|
value="3.0"
|
||||||
|
selected
|
||||||
|
data-i18n="tools:ocrPdf.resolutionHigh"
|
||||||
|
>
|
||||||
|
High (288 DPI)
|
||||||
|
</option>
|
||||||
|
<option value="4.0" data-i18n="tools:ocrPdf.resolutionUltra">
|
||||||
|
Ultra (384 DPI)
|
||||||
|
</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<!-- Binarization -->
|
<!-- Binarization -->
|
||||||
@@ -256,7 +307,9 @@
|
|||||||
id="ocr-binarize"
|
id="ocr-binarize"
|
||||||
class="w-4 h-4 rounded text-indigo-600 bg-gray-700 border-gray-600"
|
class="w-4 h-4 rounded text-indigo-600 bg-gray-700 border-gray-600"
|
||||||
/>
|
/>
|
||||||
Binarize Image (Enhance Contrast for Clean Scans)
|
<span data-i18n="tools:ocrPdf.binarizeLabel"
|
||||||
|
>Binarize Image (Enhance Contrast for Clean Scans)</span
|
||||||
|
>
|
||||||
</label>
|
</label>
|
||||||
<label
|
<label
|
||||||
class="flex items-center gap-2 text-sm text-gray-300 cursor-pointer"
|
class="flex items-center gap-2 text-sm text-gray-300 cursor-pointer"
|
||||||
@@ -266,37 +319,69 @@
|
|||||||
id="ocr-embed-full-fonts"
|
id="ocr-embed-full-fonts"
|
||||||
class="w-4 h-4 rounded text-indigo-600 bg-gray-700 border-gray-600"
|
class="w-4 h-4 rounded text-indigo-600 bg-gray-700 border-gray-600"
|
||||||
/>
|
/>
|
||||||
Embed Full Fonts (Larger file, better compatibility)
|
<span data-i18n="tools:ocrPdf.embedFullFontsLabel"
|
||||||
|
>Embed Full Fonts (Larger file, better compatibility)</span
|
||||||
|
>
|
||||||
</label>
|
</label>
|
||||||
<!-- Whitelist Presets -->
|
<!-- Whitelist Presets -->
|
||||||
<div>
|
<div>
|
||||||
<label
|
<label
|
||||||
for="whitelist-preset"
|
for="whitelist-preset"
|
||||||
class="block mb-1 text-xs font-medium text-gray-400"
|
class="block mb-1 text-xs font-medium text-gray-400"
|
||||||
|
data-i18n="tools:ocrPdf.whitelistPresetLabel"
|
||||||
>Character Whitelist Preset</label
|
>Character Whitelist Preset</label
|
||||||
>
|
>
|
||||||
<select
|
<select
|
||||||
id="whitelist-preset"
|
id="whitelist-preset"
|
||||||
class="w-full bg-gray-700 border border-gray-600 text-white rounded-lg p-2 text-sm mb-2"
|
class="w-full bg-gray-700 border border-gray-600 text-white rounded-lg p-2 text-sm mb-2"
|
||||||
>
|
>
|
||||||
<option value="">None (All characters)</option>
|
<option value="" data-i18n="tools:ocrPdf.whitelistNone">
|
||||||
<option value="alphanumeric">
|
None (All characters)
|
||||||
|
</option>
|
||||||
|
<option
|
||||||
|
value="alphanumeric"
|
||||||
|
data-i18n="tools:ocrPdf.whitelistAlphanumeric"
|
||||||
|
>
|
||||||
Alphanumeric + Basic Punctuation
|
Alphanumeric + Basic Punctuation
|
||||||
</option>
|
</option>
|
||||||
<option value="numbers-currency">
|
<option
|
||||||
|
value="numbers-currency"
|
||||||
|
data-i18n="tools:ocrPdf.whitelistNumbersCurrency"
|
||||||
|
>
|
||||||
Numbers + Currency Symbols
|
Numbers + Currency Symbols
|
||||||
</option>
|
</option>
|
||||||
<option value="letters-only">Letters Only (A-Z, a-z)</option>
|
<option
|
||||||
<option value="numbers-only">Numbers Only (0-9)</option>
|
value="letters-only"
|
||||||
<option value="invoice">
|
data-i18n="tools:ocrPdf.whitelistLettersOnly"
|
||||||
|
>
|
||||||
|
Letters Only (A-Z, a-z)
|
||||||
|
</option>
|
||||||
|
<option
|
||||||
|
value="numbers-only"
|
||||||
|
data-i18n="tools:ocrPdf.whitelistNumbersOnly"
|
||||||
|
>
|
||||||
|
Numbers Only (0-9)
|
||||||
|
</option>
|
||||||
|
<option
|
||||||
|
value="invoice"
|
||||||
|
data-i18n="tools:ocrPdf.whitelistInvoice"
|
||||||
|
>
|
||||||
Invoice/Receipt (Numbers, $, ., -, /)
|
Invoice/Receipt (Numbers, $, ., -, /)
|
||||||
</option>
|
</option>
|
||||||
<option value="forms">
|
<option value="forms" data-i18n="tools:ocrPdf.whitelistForms">
|
||||||
Forms (Alphanumeric + Common Symbols)
|
Forms (Alphanumeric + Common Symbols)
|
||||||
</option>
|
</option>
|
||||||
<option value="custom">Custom...</option>
|
<option
|
||||||
|
value="custom"
|
||||||
|
data-i18n="tools:ocrPdf.whitelistCustom"
|
||||||
|
>
|
||||||
|
Custom...
|
||||||
|
</option>
|
||||||
</select>
|
</select>
|
||||||
<p class="text-xs text-gray-500 mt-1">
|
<p
|
||||||
|
class="text-xs text-gray-500 mt-1"
|
||||||
|
data-i18n="tools:ocrPdf.whitelistHelp"
|
||||||
|
>
|
||||||
Only these characters will be recognized. Leave empty for all
|
Only these characters will be recognized. Leave empty for all
|
||||||
characters.
|
characters.
|
||||||
</p>
|
</p>
|
||||||
@@ -306,6 +391,7 @@
|
|||||||
<label
|
<label
|
||||||
for="ocr-whitelist"
|
for="ocr-whitelist"
|
||||||
class="block mb-1 text-xs font-medium text-gray-400"
|
class="block mb-1 text-xs font-medium text-gray-400"
|
||||||
|
data-i18n="tools:ocrPdf.whitelistInputLabel"
|
||||||
>Character Whitelist (Optional)</label
|
>Character Whitelist (Optional)</label
|
||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
@@ -313,8 +399,12 @@
|
|||||||
id="ocr-whitelist"
|
id="ocr-whitelist"
|
||||||
class="w-full bg-gray-700 border border-gray-600 text-white rounded-lg p-2 text-sm"
|
class="w-full bg-gray-700 border border-gray-600 text-white rounded-lg p-2 text-sm"
|
||||||
placeholder="e.g., abcdefghijklmnopqrstuvwxyz0123456789$.,"
|
placeholder="e.g., abcdefghijklmnopqrstuvwxyz0123456789$.,"
|
||||||
|
data-i18n-placeholder="tools:ocrPdf.whitelistInputPlaceholder"
|
||||||
/>
|
/>
|
||||||
<p class="text-xs text-gray-500 mt-1">
|
<p
|
||||||
|
class="text-xs text-gray-500 mt-1"
|
||||||
|
data-i18n="tools:ocrPdf.whitelistHelp"
|
||||||
|
>
|
||||||
Only these characters will be recognized. Leave empty for all
|
Only these characters will be recognized. Leave empty for all
|
||||||
characters.
|
characters.
|
||||||
</p>
|
</p>
|
||||||
@@ -326,6 +416,7 @@
|
|||||||
id="process-btn"
|
id="process-btn"
|
||||||
class="btn-gradient w-full disabled:opacity-50"
|
class="btn-gradient w-full disabled:opacity-50"
|
||||||
disabled
|
disabled
|
||||||
|
data-i18n="tools:ocrPdf.startButton"
|
||||||
>
|
>
|
||||||
Start OCR
|
Start OCR
|
||||||
</button>
|
</button>
|
||||||
@@ -336,7 +427,13 @@
|
|||||||
id="ocr-progress"
|
id="ocr-progress"
|
||||||
class="hidden mt-6 p-4 bg-gray-900 border border-gray-700 rounded-lg"
|
class="hidden mt-6 p-4 bg-gray-900 border border-gray-700 rounded-lg"
|
||||||
>
|
>
|
||||||
<p id="progress-status" class="text-white mb-2">Initializing...</p>
|
<p
|
||||||
|
id="progress-status"
|
||||||
|
class="text-white mb-2"
|
||||||
|
data-i18n="tools:ocrPdf.progressInitializing"
|
||||||
|
>
|
||||||
|
Initializing...
|
||||||
|
</p>
|
||||||
<div class="w-full bg-gray-700 rounded-full h-4">
|
<div class="w-full bg-gray-700 rounded-full h-4">
|
||||||
<div
|
<div
|
||||||
id="progress-bar"
|
id="progress-bar"
|
||||||
@@ -352,8 +449,16 @@
|
|||||||
|
|
||||||
<!-- Results Section -->
|
<!-- Results Section -->
|
||||||
<div id="ocr-results" class="hidden mt-6">
|
<div id="ocr-results" class="hidden mt-6">
|
||||||
<h3 class="text-xl font-bold text-white mb-2">OCR Complete</h3>
|
<h3
|
||||||
<p class="mb-4 text-gray-400">
|
class="text-xl font-bold text-white mb-2"
|
||||||
|
data-i18n="tools:ocrPdf.resultsTitle"
|
||||||
|
>
|
||||||
|
OCR Complete
|
||||||
|
</h3>
|
||||||
|
<p
|
||||||
|
class="mb-4 text-gray-400"
|
||||||
|
data-i18n="tools:ocrPdf.resultsDescription"
|
||||||
|
>
|
||||||
Your searchable PDF is ready. You can also copy or download the
|
Your searchable PDF is ready. You can also copy or download the
|
||||||
extracted text below.
|
extracted text below.
|
||||||
</p>
|
</p>
|
||||||
@@ -368,6 +473,7 @@
|
|||||||
id="copy-text-btn"
|
id="copy-text-btn"
|
||||||
class="absolute top-2 right-2 bg-gray-700 hover:bg-gray-600 p-2 rounded-md"
|
class="absolute top-2 right-2 bg-gray-700 hover:bg-gray-600 p-2 rounded-md"
|
||||||
title="Copy to Clipboard"
|
title="Copy to Clipboard"
|
||||||
|
data-i18n-title="tools:ocrPdf.copyToClipboard"
|
||||||
>
|
>
|
||||||
<i data-lucide="clipboard-copy" class="w-4 h-4 text-gray-300"></i>
|
<i data-lucide="clipboard-copy" class="w-4 h-4 text-gray-300"></i>
|
||||||
</button>
|
</button>
|
||||||
@@ -376,12 +482,14 @@
|
|||||||
<button
|
<button
|
||||||
id="download-txt-btn"
|
id="download-txt-btn"
|
||||||
class="w-full bg-gray-700 text-white font-semibold py-3 rounded-lg hover:bg-gray-600"
|
class="w-full bg-gray-700 text-white font-semibold py-3 rounded-lg hover:bg-gray-600"
|
||||||
|
data-i18n="tools:ocrPdf.downloadTxt"
|
||||||
>
|
>
|
||||||
Download as .txt
|
Download as .txt
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
id="download-searchable-pdf"
|
id="download-searchable-pdf"
|
||||||
class="w-full bg-green-600 text-white font-semibold py-3 rounded-lg hover:bg-green-700"
|
class="w-full bg-green-600 text-white font-semibold py-3 rounded-lg hover:bg-green-700"
|
||||||
|
data-i18n="tools:ocrPdf.downloadSearchablePdf"
|
||||||
>
|
>
|
||||||
Download Searchable PDF
|
Download Searchable PDF
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -196,7 +196,11 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button id="process-btn" class="hidden btn-gradient w-full mt-6">
|
<button
|
||||||
|
id="process-btn"
|
||||||
|
class="hidden btn-gradient w-full mt-6"
|
||||||
|
data-i18n="tools:duplicateOrganize.saveChanges"
|
||||||
|
>
|
||||||
Save Changes
|
Save Changes
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -157,7 +157,12 @@
|
|||||||
<!-- File Display Area -->
|
<!-- File Display Area -->
|
||||||
<div id="fileList" class="mt-4 hidden"></div>
|
<div id="fileList" class="mt-4 hidden"></div>
|
||||||
|
|
||||||
<button id="convertBtn" disabled class="btn-gradient w-full mt-6">
|
<button
|
||||||
|
id="convertBtn"
|
||||||
|
disabled
|
||||||
|
class="btn-gradient w-full mt-6"
|
||||||
|
data-i18n="tools:pdfToJson.convertButton"
|
||||||
|
>
|
||||||
Convert to JSON
|
Convert to JSON
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -129,14 +129,11 @@
|
|||||||
class="bg-amber-900/30 border border-amber-700/50 rounded-lg p-3 mb-6"
|
class="bg-amber-900/30 border border-amber-700/50 rounded-lg p-3 mb-6"
|
||||||
>
|
>
|
||||||
<p class="text-amber-200 text-sm">
|
<p class="text-amber-200 text-sm">
|
||||||
<strong>Note:</strong> This tool works ONLY with digitally created
|
<strong data-i18n="tools:pdfToText.noteLabel">Note:</strong>
|
||||||
PDFs. For scanned documents or image-based PDFs, use our
|
<span data-i18n="tools:pdfToText.noteText"
|
||||||
<a
|
>This tool works ONLY with digitally created PDFs. For scanned
|
||||||
href="ocr-pdf.html"
|
documents or image-based PDFs, use our OCR PDF tool instead.</span
|
||||||
class="text-indigo-400 hover:text-indigo-300 underline"
|
|
||||||
>OCR PDF tool</a
|
|
||||||
>
|
>
|
||||||
instead.
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -173,7 +173,11 @@
|
|||||||
<!-- File Display Area -->
|
<!-- File Display Area -->
|
||||||
<div id="file-display-area" class="mt-4 space-y-2"></div>
|
<div id="file-display-area" class="mt-4 space-y-2"></div>
|
||||||
|
|
||||||
<button id="process-btn" class="btn-gradient w-full mt-6 hidden">
|
<button
|
||||||
|
id="process-btn"
|
||||||
|
class="btn-gradient w-full mt-6 hidden"
|
||||||
|
data-i18n="tools:repairPdf.name"
|
||||||
|
>
|
||||||
Repair PDF
|
Repair PDF
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -169,20 +169,26 @@
|
|||||||
<!-- Options Section -->
|
<!-- Options Section -->
|
||||||
<div class="mt-6 space-y-4">
|
<div class="mt-6 space-y-4">
|
||||||
<div>
|
<div>
|
||||||
<label class="block text-sm font-medium text-gray-300 mb-2">
|
<label
|
||||||
|
class="block text-sm font-medium text-gray-300 mb-2"
|
||||||
|
data-i18n="tools:tableOfContents.titleLabel"
|
||||||
|
>
|
||||||
TOC Title
|
TOC Title
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
id="toc-title"
|
id="toc-title"
|
||||||
value="Table of Contents"
|
|
||||||
class="w-full px-4 py-2 bg-gray-800 border border-gray-600 rounded-lg text-white focus:outline-none focus:ring-2 focus:ring-blue-500"
|
class="w-full px-4 py-2 bg-gray-800 border border-gray-600 rounded-lg text-white focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||||
placeholder="Table of Contents"
|
placeholder="Table of Contents"
|
||||||
|
data-i18n-placeholder="tools:tableOfContents.name"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label class="block text-sm font-medium text-gray-300 mb-2">
|
<label
|
||||||
|
class="block text-sm font-medium text-gray-300 mb-2"
|
||||||
|
data-i18n="tools:tableOfContents.fontSize"
|
||||||
|
>
|
||||||
Font Size
|
Font Size
|
||||||
</label>
|
</label>
|
||||||
<select
|
<select
|
||||||
@@ -209,7 +215,10 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label class="block text-sm font-medium text-gray-300 mb-2">
|
<label
|
||||||
|
class="block text-sm font-medium text-gray-300 mb-2"
|
||||||
|
data-i18n="tools:tableOfContents.fontFamily"
|
||||||
|
>
|
||||||
Font Family
|
Font Family
|
||||||
</label>
|
</label>
|
||||||
<select
|
<select
|
||||||
@@ -238,7 +247,11 @@
|
|||||||
checked
|
checked
|
||||||
class="w-4 h-4 accent-blue-500"
|
class="w-4 h-4 accent-blue-500"
|
||||||
/>
|
/>
|
||||||
<label for="add-bookmark" class="text-sm text-gray-300">
|
<label
|
||||||
|
for="add-bookmark"
|
||||||
|
class="text-sm text-gray-300"
|
||||||
|
data-i18n="tools:tableOfContents.addBookmark"
|
||||||
|
>
|
||||||
Add bookmark for TOC page
|
Add bookmark for TOC page
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
@@ -246,7 +259,11 @@
|
|||||||
|
|
||||||
<!-- Generate Button -->
|
<!-- Generate Button -->
|
||||||
<button id="generate-btn" disabled class="btn-gradient w-full mt-6">
|
<button id="generate-btn" disabled class="btn-gradient w-full mt-6">
|
||||||
<span id="generate-btn-text">Generate Table of Contents</span>
|
<span
|
||||||
|
id="generate-btn-text"
|
||||||
|
data-i18n="tools:tableOfContents.generateButton"
|
||||||
|
>Generate Table of Contents</span
|
||||||
|
>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<!-- Status Message -->
|
<!-- Status Message -->
|
||||||
|
|||||||
@@ -133,12 +133,14 @@
|
|||||||
<button
|
<button
|
||||||
id="txt-mode-upload-btn"
|
id="txt-mode-upload-btn"
|
||||||
class="flex-1 btn bg-indigo-600 text-white font-semibold py-2 rounded-md"
|
class="flex-1 btn bg-indigo-600 text-white font-semibold py-2 rounded-md"
|
||||||
|
data-i18n="tools:textToPdf.uploadFiles"
|
||||||
>
|
>
|
||||||
Upload Files
|
Upload Files
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
id="txt-mode-text-btn"
|
id="txt-mode-text-btn"
|
||||||
class="flex-1 btn bg-gray-700 text-gray-300 font-semibold py-2 rounded-md"
|
class="flex-1 btn bg-gray-700 text-gray-300 font-semibold py-2 rounded-md"
|
||||||
|
data-i18n="tools:textToPdf.typeText"
|
||||||
>
|
>
|
||||||
Type Text
|
Type Text
|
||||||
</button>
|
</button>
|
||||||
@@ -161,7 +163,12 @@
|
|||||||
>
|
>
|
||||||
<span data-i18n="upload.orDragAndDrop">or drag and drop</span>
|
<span data-i18n="upload.orDragAndDrop">or drag and drop</span>
|
||||||
</p>
|
</p>
|
||||||
<p class="text-xs text-gray-500">Text files (.txt)</p>
|
<p
|
||||||
|
class="text-xs text-gray-500"
|
||||||
|
data-i18n="tools:textToPdf.acceptedFormats"
|
||||||
|
>
|
||||||
|
Text files (.txt)
|
||||||
|
</p>
|
||||||
<p
|
<p
|
||||||
class="text-xs text-gray-500"
|
class="text-xs text-gray-500"
|
||||||
data-i18n="upload.filesNeverLeave"
|
data-i18n="upload.filesNeverLeave"
|
||||||
@@ -215,6 +222,7 @@
|
|||||||
<label
|
<label
|
||||||
for="font-family"
|
for="font-family"
|
||||||
class="block mb-2 text-sm font-medium text-gray-300"
|
class="block mb-2 text-sm font-medium text-gray-300"
|
||||||
|
data-i18n="tools:textToPdf.fontFamily"
|
||||||
>Font Family</label
|
>Font Family</label
|
||||||
>
|
>
|
||||||
<select
|
<select
|
||||||
@@ -231,6 +239,7 @@
|
|||||||
<label
|
<label
|
||||||
for="font-size"
|
for="font-size"
|
||||||
class="block mb-2 text-sm font-medium text-gray-300"
|
class="block mb-2 text-sm font-medium text-gray-300"
|
||||||
|
data-i18n="tools:textToPdf.fontSize"
|
||||||
>Font Size</label
|
>Font Size</label
|
||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
@@ -246,6 +255,7 @@
|
|||||||
<label
|
<label
|
||||||
for="text-color"
|
for="text-color"
|
||||||
class="block mb-2 text-sm font-medium text-gray-300"
|
class="block mb-2 text-sm font-medium text-gray-300"
|
||||||
|
data-i18n="tools:textToPdf.textColor"
|
||||||
>Text Color</label
|
>Text Color</label
|
||||||
>
|
>
|
||||||
<input type="color" id="text-color" value="#000000" />
|
<input type="color" id="text-color" value="#000000" />
|
||||||
@@ -254,6 +264,7 @@
|
|||||||
<label
|
<label
|
||||||
for="page-size"
|
for="page-size"
|
||||||
class="block mb-2 text-sm font-medium text-gray-300"
|
class="block mb-2 text-sm font-medium text-gray-300"
|
||||||
|
data-i18n="tools:textToPdf.pageSize"
|
||||||
>Page Size</label
|
>Page Size</label
|
||||||
>
|
>
|
||||||
<select
|
<select
|
||||||
@@ -312,11 +323,17 @@
|
|||||||
|
|
||||||
<p class="text-xs text-gray-500 mt-3">
|
<p class="text-xs text-gray-500 mt-3">
|
||||||
<i data-lucide="info" class="inline w-3 h-3"></i>
|
<i data-lucide="info" class="inline w-3 h-3"></i>
|
||||||
RTL languages (Arabic, Urdu, Persian, etc.) are automatically detected
|
<span data-i18n="tools:textToPdf.rtlAutoDetectNote"
|
||||||
and text direction is adjusted.
|
>RTL languages (Arabic, Urdu, Persian, etc.) are automatically
|
||||||
|
detected and text direction is adjusted.</span
|
||||||
|
>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<button id="process-btn" class="btn-gradient w-full mt-6">
|
<button
|
||||||
|
id="process-btn"
|
||||||
|
class="btn-gradient w-full mt-6"
|
||||||
|
data-i18n="tools:textToPdf.createButton"
|
||||||
|
>
|
||||||
Create PDF
|
Create PDF
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -79,10 +79,16 @@
|
|||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<h1 class="text-2xl font-bold text-white mb-2">
|
<h1
|
||||||
|
class="text-2xl font-bold text-white mb-2"
|
||||||
|
data-i18n="tools:wasmSettings.title"
|
||||||
|
>
|
||||||
Advanced Features Settings
|
Advanced Features Settings
|
||||||
</h1>
|
</h1>
|
||||||
<p class="text-gray-400 mb-6">
|
<p
|
||||||
|
class="text-gray-400 mb-6"
|
||||||
|
data-i18n="tools:wasmSettings.description"
|
||||||
|
>
|
||||||
Configure external processing modules to enable advanced PDF features.
|
Configure external processing modules to enable advanced PDF features.
|
||||||
These modules are optional and licensed separately.
|
These modules are optional and licensed separately.
|
||||||
</p>
|
</p>
|
||||||
@@ -98,10 +104,15 @@
|
|||||||
></i>
|
></i>
|
||||||
<div>
|
<div>
|
||||||
<p class="text-green-200 text-sm">
|
<p class="text-green-200 text-sm">
|
||||||
<strong>Pre-configured and ready to use.</strong> Advanced
|
<strong data-i18n="tools:wasmSettings.preconfiguredTitle"
|
||||||
processing modules are loaded automatically from CDN. You can
|
>Pre-configured and ready to use.</strong
|
||||||
override the URLs below if you need to use a custom source
|
>
|
||||||
(e.g., for air-gapped or self-hosted deployments).
|
<span data-i18n="tools:wasmSettings.preconfiguredDescription"
|
||||||
|
>Advanced processing modules are loaded automatically from
|
||||||
|
CDN. You can override the URLs below if you need to use a
|
||||||
|
custom source (e.g., for air-gapped or self-hosted
|
||||||
|
deployments).</span
|
||||||
|
>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -113,16 +124,25 @@
|
|||||||
<div class="flex items-center justify-between mb-3">
|
<div class="flex items-center justify-between mb-3">
|
||||||
<div>
|
<div>
|
||||||
<h3 class="font-semibold text-white">PyMuPDF</h3>
|
<h3 class="font-semibold text-white">PyMuPDF</h3>
|
||||||
<p class="text-xs text-gray-400">Document Processing Engine</p>
|
<p
|
||||||
|
class="text-xs text-gray-400"
|
||||||
|
data-i18n="tools:wasmSettings.pymupdfSubtitle"
|
||||||
|
>
|
||||||
|
Document Processing Engine
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<span
|
<span
|
||||||
id="pymupdf-status"
|
id="pymupdf-status"
|
||||||
class="text-xs px-2 py-1 rounded-full bg-gray-600 text-gray-300"
|
class="text-xs px-2 py-1 rounded-full bg-gray-600 text-gray-300"
|
||||||
|
data-i18n="tools:wasmSettings.status.notConfigured"
|
||||||
>
|
>
|
||||||
Not Configured
|
Not Configured
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<p class="text-sm text-gray-400 mb-3">
|
<p
|
||||||
|
class="text-sm text-gray-400 mb-3"
|
||||||
|
data-i18n="tools:wasmSettings.pymupdfFeatures"
|
||||||
|
>
|
||||||
Enables: PDF to Text, Markdown, SVG, DOCX, Excel • Extract
|
Enables: PDF to Text, Markdown, SVG, DOCX, Excel • Extract
|
||||||
Images/Tables • Format Conversion
|
Images/Tables • Format Conversion
|
||||||
</p>
|
</p>
|
||||||
@@ -136,12 +156,17 @@
|
|||||||
<button
|
<button
|
||||||
id="pymupdf-test"
|
id="pymupdf-test"
|
||||||
class="px-4 py-2 bg-gray-600 hover:bg-gray-500 text-white rounded-lg text-sm font-medium transition-colors"
|
class="px-4 py-2 bg-gray-600 hover:bg-gray-500 text-white rounded-lg text-sm font-medium transition-colors"
|
||||||
|
data-i18n="tools:wasmSettings.testButton"
|
||||||
>
|
>
|
||||||
Test
|
Test
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center gap-2 mt-2">
|
<div class="flex items-center gap-2 mt-2">
|
||||||
<span class="text-xs text-gray-500">Recommended:</span>
|
<span
|
||||||
|
class="text-xs text-gray-500"
|
||||||
|
data-i18n="tools:wasmSettings.recommendedLabel"
|
||||||
|
>Recommended:</span
|
||||||
|
>
|
||||||
<code
|
<code
|
||||||
class="text-xs text-indigo-400 bg-gray-800 px-2 py-1 rounded flex-1 truncate"
|
class="text-xs text-indigo-400 bg-gray-800 px-2 py-1 rounded flex-1 truncate"
|
||||||
>https://cdn.jsdelivr.net/npm/@bentopdf/pymupdf-wasm@0.11.16/</code
|
>https://cdn.jsdelivr.net/npm/@bentopdf/pymupdf-wasm@0.11.16/</code
|
||||||
@@ -150,6 +175,7 @@
|
|||||||
data-copy="https://cdn.jsdelivr.net/npm/@bentopdf/pymupdf-wasm@0.11.16/"
|
data-copy="https://cdn.jsdelivr.net/npm/@bentopdf/pymupdf-wasm@0.11.16/"
|
||||||
class="copy-btn p-1.5 bg-gray-600 hover:bg-gray-500 rounded text-gray-300 hover:text-white transition-colors"
|
class="copy-btn p-1.5 bg-gray-600 hover:bg-gray-500 rounded text-gray-300 hover:text-white transition-colors"
|
||||||
title="Copy to clipboard"
|
title="Copy to clipboard"
|
||||||
|
data-i18n-title="tools:wasmSettings.copyTitle"
|
||||||
>
|
>
|
||||||
<i data-lucide="copy" class="w-3.5 h-3.5"></i>
|
<i data-lucide="copy" class="w-3.5 h-3.5"></i>
|
||||||
</button>
|
</button>
|
||||||
@@ -161,16 +187,25 @@
|
|||||||
<div class="flex items-center justify-between mb-3">
|
<div class="flex items-center justify-between mb-3">
|
||||||
<div>
|
<div>
|
||||||
<h3 class="font-semibold text-white">Ghostscript</h3>
|
<h3 class="font-semibold text-white">Ghostscript</h3>
|
||||||
<p class="text-xs text-gray-400">PDF/A Conversion Engine</p>
|
<p
|
||||||
|
class="text-xs text-gray-400"
|
||||||
|
data-i18n="tools:wasmSettings.ghostscriptSubtitle"
|
||||||
|
>
|
||||||
|
PDF/A Conversion Engine
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<span
|
<span
|
||||||
id="ghostscript-status"
|
id="ghostscript-status"
|
||||||
class="text-xs px-2 py-1 rounded-full bg-gray-600 text-gray-300"
|
class="text-xs px-2 py-1 rounded-full bg-gray-600 text-gray-300"
|
||||||
|
data-i18n="tools:wasmSettings.status.notConfigured"
|
||||||
>
|
>
|
||||||
Not Configured
|
Not Configured
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<p class="text-sm text-gray-400 mb-3">
|
<p
|
||||||
|
class="text-sm text-gray-400 mb-3"
|
||||||
|
data-i18n="tools:wasmSettings.ghostscriptFeatures"
|
||||||
|
>
|
||||||
Enables: PDF/A-1b, PDF/A-2b, PDF/A-3b Conversion • Font to Outline
|
Enables: PDF/A-1b, PDF/A-2b, PDF/A-3b Conversion • Font to Outline
|
||||||
</p>
|
</p>
|
||||||
<div class="flex gap-2">
|
<div class="flex gap-2">
|
||||||
@@ -183,12 +218,17 @@
|
|||||||
<button
|
<button
|
||||||
id="ghostscript-test"
|
id="ghostscript-test"
|
||||||
class="px-4 py-2 bg-gray-600 hover:bg-gray-500 text-white rounded-lg text-sm font-medium transition-colors"
|
class="px-4 py-2 bg-gray-600 hover:bg-gray-500 text-white rounded-lg text-sm font-medium transition-colors"
|
||||||
|
data-i18n="tools:wasmSettings.testButton"
|
||||||
>
|
>
|
||||||
Test
|
Test
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center gap-2 mt-2">
|
<div class="flex items-center gap-2 mt-2">
|
||||||
<span class="text-xs text-gray-500">Recommended:</span>
|
<span
|
||||||
|
class="text-xs text-gray-500"
|
||||||
|
data-i18n="tools:wasmSettings.recommendedLabel"
|
||||||
|
>Recommended:</span
|
||||||
|
>
|
||||||
<code
|
<code
|
||||||
class="text-xs text-indigo-400 bg-gray-800 px-2 py-1 rounded flex-1 truncate"
|
class="text-xs text-indigo-400 bg-gray-800 px-2 py-1 rounded flex-1 truncate"
|
||||||
>https://cdn.jsdelivr.net/npm/@bentopdf/gs-wasm@0.1.1/assets/</code
|
>https://cdn.jsdelivr.net/npm/@bentopdf/gs-wasm@0.1.1/assets/</code
|
||||||
@@ -197,6 +237,7 @@
|
|||||||
data-copy="https://cdn.jsdelivr.net/npm/@bentopdf/gs-wasm@0.1.1/assets/"
|
data-copy="https://cdn.jsdelivr.net/npm/@bentopdf/gs-wasm@0.1.1/assets/"
|
||||||
class="copy-btn p-1.5 bg-gray-600 hover:bg-gray-500 rounded text-gray-300 hover:text-white transition-colors"
|
class="copy-btn p-1.5 bg-gray-600 hover:bg-gray-500 rounded text-gray-300 hover:text-white transition-colors"
|
||||||
title="Copy to clipboard"
|
title="Copy to clipboard"
|
||||||
|
data-i18n-title="tools:wasmSettings.copyTitle"
|
||||||
>
|
>
|
||||||
<i data-lucide="copy" class="w-3.5 h-3.5"></i>
|
<i data-lucide="copy" class="w-3.5 h-3.5"></i>
|
||||||
</button>
|
</button>
|
||||||
@@ -208,16 +249,25 @@
|
|||||||
<div class="flex items-center justify-between mb-3">
|
<div class="flex items-center justify-between mb-3">
|
||||||
<div>
|
<div>
|
||||||
<h3 class="font-semibold text-white">CoherentPDF</h3>
|
<h3 class="font-semibold text-white">CoherentPDF</h3>
|
||||||
<p class="text-xs text-gray-400">Bookmarks & Metadata Engine</p>
|
<p
|
||||||
|
class="text-xs text-gray-400"
|
||||||
|
data-i18n="tools:wasmSettings.cpdfSubtitle"
|
||||||
|
>
|
||||||
|
Bookmarks & Metadata Engine
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<span
|
<span
|
||||||
id="cpdf-status"
|
id="cpdf-status"
|
||||||
class="text-xs px-2 py-1 rounded-full bg-gray-600 text-gray-300"
|
class="text-xs px-2 py-1 rounded-full bg-gray-600 text-gray-300"
|
||||||
|
data-i18n="tools:wasmSettings.status.notConfigured"
|
||||||
>
|
>
|
||||||
Not Configured
|
Not Configured
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<p class="text-sm text-gray-400 mb-3">
|
<p
|
||||||
|
class="text-sm text-gray-400 mb-3"
|
||||||
|
data-i18n="tools:wasmSettings.cpdfFeatures"
|
||||||
|
>
|
||||||
Enables: Split by Bookmarks • Edit Bookmarks • PDF Metadata
|
Enables: Split by Bookmarks • Edit Bookmarks • PDF Metadata
|
||||||
</p>
|
</p>
|
||||||
<div class="flex gap-2">
|
<div class="flex gap-2">
|
||||||
@@ -230,12 +280,17 @@
|
|||||||
<button
|
<button
|
||||||
id="cpdf-test"
|
id="cpdf-test"
|
||||||
class="px-4 py-2 bg-gray-600 hover:bg-gray-500 text-white rounded-lg text-sm font-medium transition-colors"
|
class="px-4 py-2 bg-gray-600 hover:bg-gray-500 text-white rounded-lg text-sm font-medium transition-colors"
|
||||||
|
data-i18n="tools:wasmSettings.testButton"
|
||||||
>
|
>
|
||||||
Test
|
Test
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center gap-2 mt-2">
|
<div class="flex items-center gap-2 mt-2">
|
||||||
<span class="text-xs text-gray-500">Recommended:</span>
|
<span
|
||||||
|
class="text-xs text-gray-500"
|
||||||
|
data-i18n="tools:wasmSettings.recommendedLabel"
|
||||||
|
>Recommended:</span
|
||||||
|
>
|
||||||
<code
|
<code
|
||||||
class="text-xs text-indigo-400 bg-gray-800 px-2 py-1 rounded flex-1 truncate"
|
class="text-xs text-indigo-400 bg-gray-800 px-2 py-1 rounded flex-1 truncate"
|
||||||
>https://cdn.jsdelivr.net/npm/coherentpdf@2.5.5/dist/</code
|
>https://cdn.jsdelivr.net/npm/coherentpdf@2.5.5/dist/</code
|
||||||
@@ -244,6 +299,7 @@
|
|||||||
data-copy="https://cdn.jsdelivr.net/npm/coherentpdf@2.5.5/dist/"
|
data-copy="https://cdn.jsdelivr.net/npm/coherentpdf@2.5.5/dist/"
|
||||||
class="copy-btn p-1.5 bg-gray-600 hover:bg-gray-500 rounded text-gray-300 hover:text-white transition-colors"
|
class="copy-btn p-1.5 bg-gray-600 hover:bg-gray-500 rounded text-gray-300 hover:text-white transition-colors"
|
||||||
title="Copy to clipboard"
|
title="Copy to clipboard"
|
||||||
|
data-i18n-title="tools:wasmSettings.copyTitle"
|
||||||
>
|
>
|
||||||
<i data-lucide="copy" class="w-3.5 h-3.5"></i>
|
<i data-lucide="copy" class="w-3.5 h-3.5"></i>
|
||||||
</button>
|
</button>
|
||||||
@@ -253,12 +309,17 @@
|
|||||||
|
|
||||||
<!-- Action Buttons -->
|
<!-- Action Buttons -->
|
||||||
<div class="flex gap-3 mt-6">
|
<div class="flex gap-3 mt-6">
|
||||||
<button id="save-btn" class="btn-gradient flex-1">
|
<button
|
||||||
|
id="save-btn"
|
||||||
|
class="btn-gradient flex-1"
|
||||||
|
data-i18n="tools:wasmSettings.saveConfiguration"
|
||||||
|
>
|
||||||
Save Configuration
|
Save Configuration
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
id="clear-btn"
|
id="clear-btn"
|
||||||
class="px-6 py-2.5 bg-red-600/20 hover:bg-red-600/30 text-red-400 rounded-lg font-medium transition-colors border border-red-600/50"
|
class="px-6 py-2.5 bg-red-600/20 hover:bg-red-600/30 text-red-400 rounded-lg font-medium transition-colors border border-red-600/50"
|
||||||
|
data-i18n="tools:wasmSettings.resetDefaults"
|
||||||
>
|
>
|
||||||
Reset to Defaults
|
Reset to Defaults
|
||||||
</button>
|
</button>
|
||||||
@@ -269,12 +330,19 @@
|
|||||||
class="mt-6 p-4 bg-gray-700/30 rounded-lg border border-gray-600/50"
|
class="mt-6 p-4 bg-gray-700/30 rounded-lg border border-gray-600/50"
|
||||||
>
|
>
|
||||||
<p class="text-xs text-gray-500">
|
<p class="text-xs text-gray-500">
|
||||||
<strong class="text-gray-400">License Notice:</strong> The external
|
<strong
|
||||||
modules (PyMuPDF, Ghostscript, CoherentPDF) are licensed under
|
class="text-gray-400"
|
||||||
AGPL-3.0 or similar copyleft licenses. By configuring and using
|
data-i18n="tools:wasmSettings.licenseTitle"
|
||||||
these modules, you agree to their respective license terms. BentoPDF
|
>License Notice:</strong
|
||||||
is compatible with any Ghostscript WASM and PyMuPDF WASM
|
>
|
||||||
implementation that follows the expected interface.
|
<span data-i18n="tools:wasmSettings.licenseDescription"
|
||||||
|
>The external modules (PyMuPDF, Ghostscript, CoherentPDF) are
|
||||||
|
licensed under AGPL-3.0 or similar copyleft licenses. By
|
||||||
|
configuring and using these modules, you agree to their respective
|
||||||
|
license terms. BentoPDF is compatible with any Ghostscript WASM
|
||||||
|
and PyMuPDF WASM implementation that follows the expected
|
||||||
|
interface.</span
|
||||||
|
>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -307,13 +375,18 @@
|
|||||||
<div
|
<div
|
||||||
class="bg-gray-800 rounded-lg shadow-xl p-6 max-w-sm w-full border border-gray-700"
|
class="bg-gray-800 rounded-lg shadow-xl p-6 max-w-sm w-full border border-gray-700"
|
||||||
>
|
>
|
||||||
<h3 id="alert-title" class="text-xl font-bold text-white mb-2">
|
<h3
|
||||||
|
id="alert-title"
|
||||||
|
class="text-xl font-bold text-white mb-2"
|
||||||
|
data-i18n="alert.title"
|
||||||
|
>
|
||||||
Alert
|
Alert
|
||||||
</h3>
|
</h3>
|
||||||
<p id="alert-message" class="text-gray-300 mb-6"></p>
|
<p id="alert-message" class="text-gray-300 mb-6"></p>
|
||||||
<button
|
<button
|
||||||
id="alert-ok"
|
id="alert-ok"
|
||||||
class="w-full bg-indigo-600 hover:bg-indigo-700 text-white font-semibold py-2 px-4 rounded-lg transition-colors duration-200"
|
class="w-full bg-indigo-600 hover:bg-indigo-700 text-white font-semibold py-2 px-4 rounded-lg transition-colors duration-200"
|
||||||
|
data-i18n="common.ok"
|
||||||
>
|
>
|
||||||
OK
|
OK
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
Reference in new issue
Block a user