From 45c941b6641abefed643d7b02688f29702d53f1b Mon Sep 17 00:00:00 2001 From: ynlamy Date: Thu, 18 Jun 2026 09:42:20 +0200 Subject: [PATCH 01/71] (Feature) Add extraVolumes and extraVolumeMounts in chart Helm --- chart/templates/deployment.yaml | 6 ++++++ chart/values.yaml | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/chart/templates/deployment.yaml b/chart/templates/deployment.yaml index cbe2ca74..ea957f10 100644 --- a/chart/templates/deployment.yaml +++ b/chart/templates/deployment.yaml @@ -65,6 +65,9 @@ spec: mountPath: /var/cache/nginx - name: nginx-run mountPath: /var/run + {{- if .Values.extraVolumeMounts }} + {{- toYaml .Values.extraVolumeMounts | nindent 12 }} + {{- end }} volumes: - name: nginx-tmp emptyDir: {} @@ -72,3 +75,6 @@ spec: emptyDir: {} - name: nginx-run emptyDir: {} + {{- if .Values.extraVolumes }} + {{- toYaml .Values.extraVolumes | nindent 8 }} + {{- end }} diff --git a/chart/values.yaml b/chart/values.yaml index 676d38c6..20422f61 100644 --- a/chart/values.yaml +++ b/chart/values.yaml @@ -86,3 +86,7 @@ readinessProbe: httpGet: path: / port: http + +extraVolumes: [] + +extraVolumeMounts: [] From 94c60f01c89cf3f1a7e68e5aa93525c8d0ae67dc Mon Sep 17 00:00:00 2001 From: nine-dev9 Date: Mon, 22 Jun 2026 20:46:53 +0200 Subject: [PATCH 02/71] Add Polish translation --- public/locales/pl/common.json | 387 +++++++++++ public/locales/pl/tools.json | 1154 +++++++++++++++++++++++++++++++++ src/js/i18n/i18n.ts | 2 + vite.config.ts | 1 + 4 files changed, 1544 insertions(+) create mode 100644 public/locales/pl/common.json create mode 100644 public/locales/pl/tools.json diff --git a/public/locales/pl/common.json b/public/locales/pl/common.json new file mode 100644 index 00000000..e200c2f4 --- /dev/null +++ b/public/locales/pl/common.json @@ -0,0 +1,387 @@ +{ + "nav": { + "home": "Strona główna", + "about": "O nas", + "contact": "Kontakt", + "licensing": "Licencjonowanie", + "allTools": "Wszystkie narzędzia", + "docs": "Dokumentacja", + "openMainMenu": "Otwórz menu główne", + "language": "Język", + "searchLanguage": "Szukaj języka…", + "noLanguagesFound": "Nie znaleziono języków" + }, + "donation": { + "message": "Uwielbiasz BentoPDF? Pomóż nam utrzymać go jako darmowe i otwarte oprogramowanie!", + "button": "Wesprzyj" + }, + "hero": { + "title": "Twój", + "pdfToolkit": "zestaw narzędzi PDF", + "builtForPrivacy": "stworzony z myślą o prywatności", + "noSignups": "Brak rejestracji", + "unlimitedUse": "Nielimitowane korzystanie", + "worksOffline": "Działa offline", + "startUsing": "Zacznij używać teraz" + }, + "usedBy": { + "title": "Używane przez firmy i osoby pracujące w" + }, + "features": { + "title": "Dlaczego warto wybrać", + "bentoPdf": "BentoPDF?", + "noSignup": { + "title": "Bez rejestracji", + "description": "Zacznij od razu, bez kont i e-maili." + }, + "noUploads": { + "title": "Bez wysyłania na serwer", + "description": "W 100% po stronie klienta, Twoje pliki nigdy nie opuszczają urządzenia." + }, + "foreverFree": { + "title": "Zawsze darmowe", + "description": "Wszystkie narzędzia, bez okresów próbnych i ukrytych opłat." + }, + "noLimits": { + "title": "Bez limitów", + "description": "Używaj bez ograniczeń, brak ukrytych limitów." + }, + "batchProcessing": { + "title": "Przetwarzanie wsadowe", + "description": "Obsługuj nieograniczoną liczbę plików PDF za jednym razem." + }, + "lightningFast": { + "title": "Błyskawicznie", + "description": "Przetwarzaj pliki PDF natychmiast, bez czekania i opóźnień." + } + }, + "tools": { + "title": "Rozpocznij z", + "toolsLabel": "Narzędzia", + "subtitle": "Kliknij narzędzie, aby otworzyć przesyłanie plików", + "searchPlaceholder": "Szukaj narzędzia (np. 'podziel', 'organizuj'...)", + "backToTools": "Wróć do narzędzi", + "firstLoadNotice": "Pierwsze wczytywanie potrwa chwilę, ponieważ pobieramy nasz silnik konwersji. Potem wszystkie ładowania będą natychmiastowe." + }, + "upload": { + "clickToSelect": "Kliknij, aby wybrać plik", + "orDragAndDrop": "lub przeciągnij i upuść", + "pdfOrImages": "Pliki PDF lub obrazy", + "filesNeverLeave": "Twoje pliki nigdy nie opuszczają Twojego urządzenia.", + "addMore": "Dodaj więcej plików", + "clearAll": "Wyczyść wszystko", + "clearFiles": "Wyczyść pliki", + "hints": { + "singlePdf": "Pojedynczy plik PDF", + "pdfFile": "Plik PDF", + "multiplePdfs2": "Wiele plików PDF (co najmniej 2)", + "bmpImages": "Obrazy BMP", + "oneOrMorePdfs": "Jeden lub więcej plików PDF", + "pdfDocuments": "Dokumenty PDF", + "oneOrMoreCsv": "Jeden lub więcej plików CSV", + "multiplePdfsSupported": "Obsługiwane wiele plików PDF", + "singleOrMultiplePdfs": "Obsługiwane pojedyncze lub wielokrotne pliki PDF", + "singlePdfFile": "Pojedynczy plik PDF", + "pdfWithForms": "Plik PDF z polami formularza", + "heicImages": "Obrazy HEIC/HEIF", + "jpgImages": "Obrazy JPG, JPEG, JP2, JPX", + "pdfsOrImages": "Pliki PDF lub obrazy", + "oneOrMoreOdt": "Jeden lub więcej plików ODT", + "singlePdfOnly": "Tylko pojedynczy plik PDF", + "pdfFiles": "Pliki PDF", + "multiplePdfs": "Wiele plików PDF", + "pngImages": "Obrazy PNG", + "pdfFilesOneOrMore": "Pliki PDF (jeden lub więcej)", + "oneOrMoreRtf": "Jeden lub więcej plików RTF", + "svgGraphics": "Grafika SVG", + "tiffImages": "Obrazy TIFF", + "webpImages": "Obrazy WebP" + } + }, + "howItWorks": { + "title": "Jak to działa", + "step1Title": "Prześlij plik", + "step1": "Kliknij lub przeciągnij i upuść plik, aby rozpocząć", + "step2Title": "Przetwarzaj", + "step2": "Kliknij przycisk przetwarzania, aby rozpocząć", + "step3Title": "Pobierz", + "step3": "Natychmiast zapisz przetworzony plik" + }, + "relatedTools": { + "title": "Powiązane narzędzia PDF" + }, + "loader": { + "processing": "Przetwarzanie..." + }, + "alert": { + "title": "Uwaga", + "ok": "OK" + }, + "preview": { + "title": "Podgląd dokumentu", + "downloadAsPdf": "Pobierz jako PDF", + "close": "Zamknij" + }, + "settings": { + "title": "Ustawienia", + "shortcuts": "Skróty", + "preferences": "Preferencje", + "displayPreferences": "Preferencje wyświetlania", + "searchShortcuts": "Szukaj skrótów...", + "shortcutsInfo": "Naciśnij i przytrzymaj klawisze, aby ustawić skrót. Zmiany są zapisywane automatycznie.", + "shortcutsWarning": "⚠️ Unikaj popularnych skrótów przeglądarki (Cmd/Ctrl+W, Cmd/Ctrl+T, Cmd/Ctrl+N itp.), ponieważ mogą nie działać prawidłowo.", + "import": "Importuj", + "export": "Eksportuj", + "resetToDefaults": "Przywróć domyślne", + "fullWidthMode": "Tryb pełnej szerokości", + "fullWidthDescription": "Używaj pełnej szerokości ekranu dla wszystkich narzędzi zamiast wyśrodkowanego kontenera", + "compactMode": "Tryb kompaktowy", + "compactModeDescription": "Wyświetlaj narzędzia jako kompaktową listę zamiast kart", + "advancedSettings": "Ustawienia zaawansowane", + "advancedSettingsDescription": "Skonfiguruj zewnętrzne moduły przetwarzania (PyMuPDF, Ghostscript, CoherentPDF)", + "settingsAutoSaved": "Ustawienia są zapisywane automatycznie", + "clickToSet": "Kliknij, aby ustawić", + "pressKeys": "Naciśnij klawisze...", + "warnings": { + "alreadyInUse": "Skrót jest już w użyciu", + "assignedTo": "jest już przypisany do:", + "chooseDifferent": "Proszę wybrać inny skrót.", + "reserved": "Ostrzeżenie o zarezerwowanym skrócie", + "commonlyUsed": "jest powszechnie używany do:", + "unreliable": "Ten skrót może nie działać niezawodnie lub może kolidować z działaniem przeglądarki/systemu.", + "useAnyway": "Czy mimo to chcesz go użyć?", + "resetTitle": "Zresetuj skróty", + "resetMessage": "Czy na pewno chcesz zresetować wszystkie skróty do wartości domyślnych?

Tej akcji nie można cofnąć.", + "importSuccessTitle": "Import zakończony sukcesem", + "importSuccessMessage": "Skróty zostały pomyślnie zaimportowane!", + "importFailTitle": "Import nie powiódł się", + "importFailMessage": "Nie udało się zaimportować skrótów. Nieprawidłowy format pliku." + } + }, + "warning": { + "title": "Ostrzeżenie", + "cancel": "Anuluj", + "proceed": "Kontynuuj" + }, + "compliance": { + "title": "Twoje dane nigdy nie opuszczają Twojego urządzenia", + "weKeep": "Dbamy o", + "yourInfoSafe": "bezpieczeństwo Twoich informacji", + "byFollowingStandards": "przestrzegając globalnych standardów bezpieczeństwa.", + "processingLocal": "Całe przetwarzanie odbywa się lokalnie na Twoim urządzeniu.", + "gdpr": { + "title": "Zgodność z RODO", + "description": "Chroni dane osobowe i prywatność osób w Unii Europejskiej." + }, + "ccpa": { + "title": "Zgodność z CCPA", + "description": "Daje mieszkańcom Kalifornii prawa do kontrolowania sposobu gromadzenia, wykorzystywania i udostępniania ich danych osobowych." + }, + "hipaa": { + "title": "Zgodność z HIPAA", + "description": "Ustanawia zabezpieczenia w celu ochrony wrażliwych informacji zdrowotnych w systemie opieki zdrowotnej Stanów Zjednoczonych." + } + }, + "faq": { + "title": "Często Zadawane", + "questions": "Pytania", + "sectionTitle": "Często Zadawane Pytania", + "isFree": { + "question": "Czy BentoPDF jest naprawdę darmowy?", + "answer": "Tak, absolutnie. Wszystkie narzędzia w BentoPDF są w 100% darmowe do użytku, bez limitów plików, bez rejestracji i bez znaków wodnych. Wierzymy, że każdy zasługuje na dostęp do prostych, potężnych narzędzi PDF bez barier płatnych." + }, + "areFilesSecure": { + "question": "Czy moje pliki są bezpieczne? Gdzie są przetwarzane?", + "answer": "Twoje pliki są maksymalnie bezpieczne, ponieważ nigdy nie opuszczają Twojego komputera. Całe przetwarzanie odbywa się bezpośrednio w Twojej przeglądarce internetowej (po stronie klienta). Nigdy nie wysyłamy Twoich plików na serwer, dzięki czemu zachowujesz pełną prywatność i kontrolę nad swoimi dokumentami." + }, + "platforms": { + "question": "Czy to działa na Macu, Windowsie i urządzeniach mobilnych?", + "answer": "Tak! Ponieważ BentoPDF działa całkowicie w Twojej przeglądarce, obsługuje dowolny system operacyjny z nowoczesną przeglądarką internetową, w tym Windows, macOS, Linux, iOS oraz Android." + }, + "gdprCompliant": { + "question": "Czy BentoPDF jest zgodny z RODO?", + "answer": "Tak. BentoPDF jest w pełni zgodny z RODO. Ponieważ całe przetwarzanie plików odbywa się lokalnie w Twojej przeglądarce, a my nigdy nie zbieramy ani nie wysyłamy Twoich plików na żaden serwer, nie mamy dostępu do Twoich danych. Gwarantuje to, że zawsze sprawujesz pełną kontrolę nad swoimi dokumentami." + }, + "dataStorage": { + "question": "Czy przechowujecie lub śledzicie jakiekolwiek moje pliki?", + "answer": "Nie. Nigdy nie przechowujemy, nie śledzimy ani nie logujemy Twoich plików. Wszystko, co robisz w BentoPDF, odbywa się w pamięci Twojej przeglądarki i znika po zamknięciu strony. Nie ma żadnych transferów, logów historii ani serwerów." + }, + "different": { + "question": "Czym różni się BentoPDF od innych narzędzi PDF?", + "answer": "Większość narzędzi PDF wysyła Twoje pliki na serwer w celu ich przetworzenia. BentoPDF nigdy tego nie robi. Wykorzystujemy bezpieczną, nowoczesną technologię internetową, aby przetwarzać Twoje pliki bezpośrednio w przeglądarce. Oznacza to większą wydajność, silniejszą prywatność i pełen spokój ducha." + }, + "browserBased": { + "question": "W jaki sposób przetwarzanie w oparciu o przeglądarkę zapewnia mi bezpieczeństwo?", + "answer": "Działając całkowicie wewnątrz Twojej przeglądarki, BentoPDF gwarantuje, że Twoje pliki nigdy nie opuszczą Twojego urządzenia. Eliminuje to ryzyko ataków hakerskich na serwery, naruszeń bezpieczeństwa danych czy nieautoryzowanego dostępu. Twoje pliki pozostają Twoje — zawsze." + }, + "analytics": { + "question": "Czy używacie plików cookie lub analityki do mojego śledzenia?", + "answer": "Dbamy o Twoją prywatność. BentoPDF nie śledzi danych osobowych. Używamy Simple Analytics wyłącznie w celu sprawdzenia anonimowej liczby wizyt. Oznacza to, że wiemy, ilu użytkowników odwiedza naszą stronę, ale nigdy nie wiemy, kim jesteś. Simple Analytics jest w pełni zgodne z RODO i szanuje Twoją prywatność." + } + }, + "testimonials": { + "title": "Co Nasi", + "users": "Użytkownicy", + "say": "Mówią" + }, + "support": { + "title": "Podoba Ci się moja praca?", + "description": "BentoPDF to projekt z pasji, stworzony po to, aby udostępnić darmowy, prywatny i potężny zestaw narzędzi PDF dla każdego. Jeśli uznasz go za przydatny, rozważ wsparcie jego rozwoju. Każda kawa pomaga!", + "buyMeCoffee": "Postaw mi kawę" + }, + "footer": { + "copyright": "© 2026 BentoPDF. Wszelkie prawa zastrzeżone.", + "version": "Wersja", + "company": "Firma", + "aboutUs": "O nas", + "faqLink": "FAQ", + "contactUs": "Kontakt", + "legal": "Kwestie prawne", + "termsAndConditions": "Zasady i warunki", + "privacyPolicy": "Polityka prywatności", + "followUs": "Śledź nas" + }, + "merge": { + "title": "Połącz pliki PDF", + "description": "Połącz całe pliki lub wybierz konkretne strony do scalenia w nowy dokument.", + "fileMode": "Tryb pliku", + "pageMode": "Tryb strony", + "howItWorks": "Jak to działa:", + "fileModeInstructions": [ + "Kliknij i przeciągnij ikonę, aby zmienić kolejność plików.", + "W polu \"Strony\" dla każdego pliku możesz określić zakresy (np. \"1-3, 5\"), aby połączyć tylko te strony.", + "Pozostaw pole \"Strony\" puste, aby dołączyć wszystkie strony z tego pliku." + ], + "pageModeInstructions": [ + "Poniżej widoczne są wszystkie strony z przesłanych plików PDF.", + "Po prostu przeciągnij i upuść poszczególne miniatury stron, aby ułożyć je w dokładnej kolejności dla nowego pliku." + ], + "mergePdfs": "Połącz PDF-y" + }, + "common": { + "page": "Strona", + "pages": "Strony", + "of": "z", + "download": "Pobierz", + "cancel": "Anuluj", + "save": "Zapisz", + "delete": "Usuń", + "edit": "Edytuj", + "add": "Dodaj", + "remove": "Usuń", + "loading": "Ładowanie...", + "loadingPageCount": "Wczytywanie stron...", + "error": "Błąd", + "success": "Sukces", + "file": "Plik", + "files": "Pliki", + "close": "Zamknij", + "convert": "Konwertuj", + "unknownError": "Nieznany błąd" + }, + "about": { + "hero": { + "title": "Wierzymy, że narzędzia PDF powinny być", + "subtitle": "szybkie, prywatne i darmowe.", + "noCompromises": "Bez kompromisów." + }, + "mission": { + "title": "Nasza misja", + "description": "Zapewnienie najbardziej wszechstronnego zestawu narzędzi PDF, który szanuje Twoją prywatność i nigdy nie prosi o płatność. Wierzymy, że podstawowe narzędzia do dokumentów powinny być dostępne dla każdego, wszędzie i bez barier." + }, + "philosophy": { + "label": "Nasza główna filozofia", + "title": "Prywatność na pierwszym miejscu. Zawsze.", + "description": "W czasach, gdy dane są towarem, my przyjmujemy inne podejście. Całe przetwarzanie w narzędziach BentoPDF odbywa się lokalnie w Twojej przeglądarce. Oznacza to, że Twoje pliki nigdy nie stykają się z naszymi serwerami, nigdy nie widzimy Twoich dokumentów i nie śledzimy tego, co robisz. Twoje dokumenty pozostają całkowicie i bezsprzecznie prywatne. To nie tylko funkcja; to nasz fundament." + }, + "whyBentopdf": { + "title": "Dlaczego", + "speed": { + "title": "Zbudowane dla szybkości", + "description": "Bez czekania na wysłanie lub pobranie z serwera. Przetwarzając pliki bezpośrednio w Twojej przeglądarce przy użyciu nowoczesnych technologii internetowych, takich jak WebAssembly, oferujemy niezrównaną prędkość dla wszystkich naszych narzędzi." + }, + "free": { + "title": "Całkowicie darmowe", + "description": "Bez wersji próbnych, bez subskrypcji, bez ukrytych opłat i bez „funkcji premium” wziętych jako zakładników. Wierzymy, że potężne narzędzia PDF powinny być dobrem publicznym, a nie centrum zysków." + }, + "noAccount": { + "title": "Konto nie jest wymagane", + "description": "Zacznij natychmiast używać dowolnego narzędzia. Nie potrzebujemy Twojego e-maila, hasła ani żadnych danych osobowych. Twój przepływ pracy powinien być bezproblemowy i anonimowy." + }, + "openSource": { + "title": "Duch Open Source", + "description": "Stworzone z myślą o przejrzystości. Korzystamy z niesamowitych bibliotek open-source, takich jak PDF-lib i PDF.js, oraz wierzymy w społeczny wysiłek, dzięki któremu potężne narzędzia są dostępne dla wszystkich." + } + }, + "cta": { + "title": "Gotowy, aby zacząć?", + "description": "Dołącz do tysięcy użytkowników, którzy ufają BentoPDF w codziennych zadaniach z dokumentami. Poczuj różnicę, jaką potrafią zrobić prywatność i wydajność.", + "button": "Odkryj wszystkie narzędzia" + } + }, + "contact": { + "title": "Bądźmy w kontakcie", + "subtitle": "Z przyjemnością Cię wysłuchamy. Niezależnie od tego, czy masz pytanie, opinię, czy prośbę o nową funkcję, nie wahaj się do nas napisać.", + "email": "Możesz się z nami skontaktować bezpośrednio poprzez e-mail na adres:" + }, + "licensing": { + "title": "Licencjonowanie dla", + "subtitle": "Wybierz licencję, która odpowiada Twoim potrzebom." + }, + "multiTool": { + "uploadPdfs": "Prześlij pliki PDF", + "upload": "Prześlij", + "addBlankPage": "Dodaj pustą stronę", + "edit": "Edytuj:", + "undo": "Cofnij", + "redo": "Ponów", + "reset": "Zresetuj", + "selection": "Wybór:", + "selectAll": "Zaznacz wszystko", + "deselectAll": "Odznacz wszystko", + "rotate": "Obróć:", + "rotateLeft": "W lewo", + "rotateRight": "W prawo", + "transform": "Przekształć:", + "duplicate": "Powiel", + "split": "Podziel", + "clear": "Wyczyść:", + "delete": "Usuń", + "download": "Pobierz:", + "downloadSelected": "Pobierz wybrane", + "exportPdf": "Eksportuj PDF", + "uploadPdfFiles": "Wybierz pliki PDF lub obrazy", + "dragAndDrop": "Przeciągnij i upuść pliki PDF lub obrazy tutaj, albo kliknij, by wybrać", + "selectFiles": "Wybierz pliki", + "dropToAdd": "Upuść pliki PDF lub obrazy, aby dodać", + "convertingImages": "Konwertowanie obrazów do formatu PDF...", + "failedToConvertImages": "Nie udało się przekonwertować obrazów do pliku PDF.", + "renderingPages": "Renderowanie stron...", + "actions": { + "duplicatePage": "Powiel tę stronę", + "deletePage": "Usuń tę stronę", + "insertPdf": "Wstaw PDF po tej stronie", + "toggleSplit": "Przełącz podział po tej stronie" + }, + "pleaseWait": "Proszę czekać", + "pagesRendering": "Strony są nadal renderowane. Proszę czekać...", + "noPagesSelected": "Nie wybrano stron", + "selectOnePage": "Wybierz co najmniej jedną stronę do pobrania.", + "noPages": "Brak stron", + "noPagesToExport": "Nie ma stron do wyeksportowania.", + "renderingTitle": "Renderowanie podglądów stron", + "errorRendering": "Nie udało się wyrenderować miniatur stron", + "error": "Błąd", + "failedToLoad": "Nie udało się załadować" + }, + "simpleMode": { + "title": "Narzędzia PDF", + "subtitle": "Wybierz narzędzie, aby rozpocząć" + }, + "disabledTool": { + "title": "Narzędzie niedostępne", + "heading": "To narzędzie zostało wyłączone", + "message": "To narzędzie nie jest dostępne w Twoim środowisku. Skontaktuj się z administratorem, aby uzyskać więcej informacji.", + "backHome": "Powrót do strony głównej" + } +} diff --git a/public/locales/pl/tools.json b/public/locales/pl/tools.json new file mode 100644 index 00000000..e2a6a3c5 --- /dev/null +++ b/public/locales/pl/tools.json @@ -0,0 +1,1154 @@ +{ + "categories": { + "popularTools": "Popularne narzędzia", + "editAnnotate": "Edytuj i adnotuj", + "convertToPdf": "Konwertuj na PDF", + "convertFromPdf": "Konwertuj z PDF", + "organizeManage": "Organizuj i zarządzaj", + "optimizeRepair": "Optymalizuj i napraw", + "securePdf": "Zabezpiecz PDF", + "input": "Wejście", + "output": "Wyjście" + }, + "convertToPdf": "Konwertuj na PDF", + "pdfMultiTool": { + "name": "Wielofunkcyjne narzędzie PDF", + "subtitle": "Łącz, dziel, organizuj, usuwaj, obracaj, dodawaj puste strony, wyodrębniaj i powielaj w ujednoliconym interfejsie." + }, + "mergePdf": { + "name": "Połącz PDF", + "subtitle": "Połącz wiele plików PDF w jeden plik. Zachowuje zakładki.", + "retainPageLabels": "Zachowaj oryginalne etykiety stron z każdego pliku", + "retainPageLabelsHint": "Wyłączone (domyślnie): połączony PDF używa naturalnej numeracji stron 1–N. Włączone: oryginalne etykiety stron z każdego pliku są zachowane (może to powodować duplikaty etykiet)." + }, + "splitPdf": { + "name": "Podziel PDF", + "subtitle": "Wyodrębnij zakres stron do nowego pliku PDF." + }, + "compressPdf": { + "name": "Kompresuj PDF", + "subtitle": "Zmniejsz rozmiar pliku PDF.", + "algorithmLabel": "Algorytm kompresji", + "condense": "Kondensacja (Zalecane)", + "photon": "Foton (Dla PDF z dużą ilością zdjęć)", + "condenseInfo": "Kondensacja wykorzystuje zaawansowaną kompresję: usuwa zbędny balast, optymalizuje obrazy, zmniejsza liczbę czcionek. Najlepsze dla większości plików PDF.", + "photonInfo": "Foton konwertuje strony na obrazy. Używaj dla zeskanowanych/fotograficznych PDF.", + "photonWarning": "Ostrzeżenie: Tekst stanie się niemożliwy do zaznaczenia, a linki przestaną działać.", + "levelLabel": "Poziom kompresji", + "light": "Lekki (Zachowaj jakość)", + "balanced": "Zbalansowany (Zalecane)", + "aggressive": "Agresywny (Mniejsze pliki)", + "extreme": "Ekstremalny (Maksymalna kompresja)", + "grayscale": "Konwertuj na odcienie szarości", + "grayscaleHint": "Zmniejsza rozmiar pliku usuwając informacje o kolorze", + "customSettings": "Ustawienia niestandardowe", + "customSettingsHint": "Dostrój parametry kompresji:", + "outputQuality": "Jakość wyjściowa", + "resizeImagesTo": "Zmień rozmiar obrazów do", + "onlyProcessAbove": "Przetwarzaj tylko powyżej", + "removeMetadata": "Usuń metadane", + "subsetFonts": "Zredukuj czcionki (usuń nieużywane glify)", + "removeThumbnails": "Usuń osadzone miniatury", + "compressButton": "Kompresuj PDF" + }, + "pdfEditor": { + "name": "Edytor PDF", + "subtitle": "Dodawaj adnotacje, zakreślaj, redaguj, komentuj, dodawaj kształty/obrazy, wyszukuj i przeglądaj PDF." + }, + "jpgToPdf": { + "name": "JPG na PDF", + "subtitle": "Utwórz plik PDF z obrazów JPG, JPEG i JPEG2000 (JP2/JPX)." + }, + "signPdf": { + "name": "Podpisz PDF", + "subtitle": "Narysuj, wpisz lub prześlij swój podpis." + }, + "cropPdf": { + "name": "Przytnij PDF", + "subtitle": "Przytnij marginesy każdej strony w pliku PDF." + }, + "extractPages": { + "name": "Wyodrębnij strony", + "subtitle": "Zapisz wybrane strony jako nowe pliki." + }, + "duplicateOrganize": { + "name": "Duplikuj i organizuj", + "subtitle": "Duplikuj, zmieniaj kolejność i usuwaj strony.", + "saveChanges": "Zapisz zmiany" + }, + "deletePages": { + "name": "Usuń strony", + "subtitle": "Usuń określone strony ze swojego dokumentu." + }, + "editBookmarks": { + "name": "Edytuj zakładki", + "subtitle": "Dodawaj, edytuj, importuj, usuwaj i wyodrębniaj zakładki PDF.", + "autoExtractExisting": "Automatycznie wyodrębnij istniejące zakładki", + "importSectionTitle": "Lub zaimportuj zakładki", + "csvFormat": "Format CSV: tytuł,strona,poziom", + "jsonFormat": "Format JSON", + "uploadCsvAction": "Kliknij, aby przesłać CSV", + "uploadJsonAction": "Kliknij, aby przesłać JSON", + "orDragHere": "lub przeciągnij tutaj" + }, + "tableOfContents": { + "name": "Spis treści", + "subtitle": "Wygeneruj stronę spisu treści na podstawie zakładek PDF.", + "titleLabel": "Tytuł spisu treści", + "fontSize": "Rozmiar czcionki", + "fontFamily": "Krój czcionki", + "addBookmark": "Dodaj zakładkę dla strony spisu treści", + "generateButton": "Generuj spis treści", + "selectPdfFirst": "Proszę najpierw wybrać plik PDF.", + "statusReadingFileMainThread": "Odczytywanie pliku (Główny wątek)...", + "statusGenerating": "Generowanie spisu treści...", + "errorReadingFileWithMessage": "Błąd odczytu pliku: {{message}}", + "successGeneratedDownloadStarted": "Pomyślnie wygenerowano spis treści! Rozpoczęto pobieranie.", + "workerErrorWithMessage": "Błąd: {{message}}", + "workerErrorOccurred": "Wystąpił błąd workera. Sprawdź konsolę, aby uzyskać szczegóły." + }, + "pageNumbers": { + "name": "Numery stron", + "subtitle": "Wstaw numery stron do swojego dokumentu." + }, + "addPageLabels": { + "name": "Dodaj etykiety stron", + "subtitle": "Zastosuj etykiety stron PDF z cyframi rzymskimi, prefiksami i niestandardowymi wartościami początkowymi.", + "uploadHint": "Plik PDF", + "howLabelsWorkTitle": "Jak działają etykiety", + "howLabelsWorkStep1": "Pozostaw pole Zakres stron puste, aby dodać etykiety do wszystkich stron.", + "howLabelsWorkStep2": "Używaj stylów, takich jak cyfry rzymskie dla stron wprowadzających i numeracji dziesiętnej dla głównej treści.", + "howLabelsWorkStep3": "Użyj prefiksu z wartością początkową 0, aby utworzyć etykiety takie jak A-0, A-1, A-2.", + "howLabelsWorkStep4": "Włącz postęp, gdy jedna reguła używa rozłącznego zakresu, np. 1-9,30-40 lub nieparzyste.", + "labelRulesTitle": "Reguły etykiet", + "addRule": "Dodaj regułę", + "removeExistingLabels": "Usuń istniejące etykiety stron przed zastosowaniem tych reguł", + "cpdfNote": "To narzędzie korzysta z CoherentPDF w Twojej przeglądarce. Jeśli CoherentPDF nie jest skonfigurowany, zostaniesz poproszony o jego konfigurację w Ustawieniach WASM.", + "processButton": "Dodaj etykiety stron", + "howItWorksUploadTitle": "Prześlij plik", + "howItWorksUploadDescription": "Wybierz plik PDF, dla którego chcesz zmienić etykiety.", + "howItWorksDefineTitle": "Zdefiniuj reguły", + "howItWorksDefineDescription": "Ustaw jedną lub więcej reguł etykiet stron z zakresami stron, stylami, prefiksami i wartościami początkowymi.", + "howItWorksDownloadTitle": "Pobierz", + "howItWorksDownloadDescription": "Zapisz zaktualizowany plik PDF z nowymi etykietami stron.", + "relatedToolsTitle": "Powiązane narzędzia PDF", + "faqWhatIsQuestion": "Co to jest etykieta strony?", + "faqWhatIsAnswer": "Etykieta strony to numeracja wyświetlana przez czytniki PDF na miniaturach, w nawigacji po stronach i w oknach dialogowych drukowania. Nie nadrukowuje ona nowego tekstu na samej stronie.", + "faqMixQuestion": "Czy mogę łączyć cyfry rzymskie ze zwykłymi liczbami?", + "faqMixAnswer": "Tak. Dodaj wiele reguł, takich jak 1-4 z małych liter rzymskich (LowercaseRoman) i 5-20 z dziesiętnych arabskich (DecimalArabic).", + "faqPrivacyQuestion": "Czy moje pliki pozostają prywatne?", + "faqPrivacyAnswer": "Tak. Przetwarzanie odbywa się w Twojej przeglądarce za pomocą CoherentPDF WASM. Twój plik PDF nie opuszcza Twojego urządzenia.", + "invalidFileTitle": "Nieprawidłowy plik", + "invalidFileMessage": "Proszę przesłać prawidłowy plik PDF.", + "loadingPdf": "Wczytywanie pliku PDF...", + "protectedPdfTitle": "Chroniony plik PDF", + "protectedPdfMessage": "Ten plik PDF jest chroniony hasłem. Użyj najpierw narzędzia Odszyfruj lub Zmień uprawnienia.", + "loadErrorMessage": "Nie udało się załadować pliku PDF. Plik może być nieprawidłowy, uszkodzony lub chroniony hasłem.", + "fileMeta": "{{size}} • {{count}} stron", + "ruleTitle": "Reguła etykiety {{number}}", + "pageRangeLabel": "Zakres stron", + "pageRangePlaceholder": "Wszystkie strony lub np. 1-4, 7, nieparzyste", + "labelStyleLabel": "Styl etykiety", + "labelPrefixLabel": "Prefiks etykiety", + "labelPrefixPlaceholder": "Opcjonalny prefiks, np. A-", + "startValueLabel": "Wartość początkowa", + "continueNumbering": "Kontynuuj numerację przez rozłączne zakresy", + "examplesNote": "Przykłady: 1-4 dla początkowych stron rzymskich, 15-20 z prefiksem A- i wartością początkową 0, lub nieparzyste z włączonym postępem.", + "uploadFirstMessage": "Proszę najpierw przesłać plik PDF.", + "applyingLabels": "Stosowanie etykiet stron...", + "invalidRangeMessage": "Reguła {{number}} ma nieprawidłowy zakres stron: {{range}}", + "allPages": "wszystkie strony", + "emptyOutputMessage": "CoherentPDF wygenerował pusty plik.", + "successMessage": "Etykiety stron zostały pomyślnie dodane!", + "processErrorMessage": "Nie udało się dodać etykiet stron.", + "styleOptions": { + "DecimalArabic": "Dziesiętne Arabskie", + "LowercaseRoman": "Małe Rzymskie", + "UppercaseRoman": "Wielkie Rzymskie", + "LowercaseLetters": "Małe Litery", + "UppercaseLetters": "Wielkie Litery", + "NoLabelPrefixOnly": "Brak Etykiety, Tylko Prefiks" + } + }, + "batesNumbering": { + "name": "Numeracja Batesa", + "subtitle": "Dodaj sekwencyjną numerację Batesa do jednego lub wielu plików PDF." + }, + "addWatermark": { + "name": "Dodaj znak wodny", + "subtitle": "Odbij tekst lub obraz na swoich stronach PDF.", + "applyToAllPages": "Zastosuj do wszystkich stron" + }, + "headerFooter": { + "name": "Nagłówek i Stopka", + "subtitle": "Dodaj tekst na górze i na dole stron." + }, + "invertColors": { + "name": "Odwróć kolory", + "subtitle": "Utwórz wersję \"trybu ciemnego\" swojego pliku PDF." + }, + "scannerEffect": { + "name": "Efekt skanera", + "subtitle": "Spraw, by Twój PDF wyglądał jak zeskanowany dokument.", + "scanSettings": "Ustawienia skanowania", + "colorspace": "Przestrzeń barw", + "gray": "Szary", + "border": "Obramowanie", + "rotate": "Obrót", + "rotateVariance": "Wariancja obrotu", + "brightness": "Jasność", + "contrast": "Kontrast", + "blur": "Rozmycie", + "noise": "Szum", + "yellowish": "Zażółcenie", + "resolution": "Rozdzielczość", + "processButton": "Zastosuj efekt skanera" + }, + "adjustColors": { + "name": "Dostosuj kolory", + "subtitle": "Dostrój jasność, kontrast, nasycenie i wiele innych w swoim pliku PDF.", + "colorSettings": "Ustawienia kolorów", + "brightness": "Jasność", + "contrast": "Kontrast", + "saturation": "Nasycenie", + "hueShift": "Przesunięcie odcienia", + "temperature": "Temperatura", + "tint": "Odcień (Tint)", + "gamma": "Gamma", + "sepia": "Sepia", + "processButton": "Zastosuj dostosowanie kolorów" + }, + "backgroundColor": { + "name": "Kolor tła", + "subtitle": "Zmień kolor tła swojego pliku PDF." + }, + "changeTextColor": { + "name": "Zmień kolor tekstu", + "subtitle": "Zmień kolor tekstu w swoim pliku PDF." + }, + "addStamps": { + "name": "Dodaj pieczątki", + "subtitle": "Dodaj pieczątki graficzne do swojego PDF za pomocą paska adnotacji.", + "usernameLabel": "Nazwa użytkownika pieczątki", + "usernamePlaceholder": "Wpisz swoje imię (dla pieczątek)", + "usernameHint": "To imię pojawi się na tworzonych przez Ciebie pieczątkach.", + "saveButton": "Zapisz opieczętowany PDF" + }, + "removeAnnotations": { + "name": "Usuń adnotacje", + "subtitle": "Usuń komentarze, podświetlenia i linki." + }, + "pdfFormFiller": { + "name": "Wypełnianie formularzy PDF", + "subtitle": "Wypełniaj formularze bezpośrednio w przeglądarce. Obsługuje również formularze XFA.", + "uploadHint": "Prześlij plik PDF z polami formularza. Wypełnij je bezpośrednio w przeglądarce poniżej, a następnie kliknij przycisk, aby zapisać i pobrać wypełniony formularz. Obsługuje również formularze XFA.", + "xfaNoteTitle": "Uwaga dotycząca formularzy XFA:", + "xfaNoteDescription": "XFA (XML Forms Architecture) to starszy format obsługiwany tylko przez niektóre przeglądarki PDF, takie jak BentoPDF i Firefox. Jeśli otworzysz plik PDF z XFA w innym oprogramowaniu i zobaczysz puste strony lub brak pól formularza, oznacza to, że dana przeglądarka nie obsługuje XFA. Aby poprawnie wyświetlać i wypełniać formularze XFA, użyj Firefoksa lub narzędzia Form Filler w BentoPDF." + }, + "createPdfForm": { + "name": "Utwórz formularz PDF", + "subtitle": "Twórz interaktywne formularze PDF za pomocą pól tekstowych typu „przeciągnij i upuść”.", + "orSeparator": "LUB", + "createBlankPdf": "Utwórz pusty PDF" + }, + "removeBlankPages": { + "name": "Usuń puste strony", + "subtitle": "Automatycznie wykrywaj i usuwaj puste strony.", + "sensitivityHint": "Wyższa = bardziej rygorystyczna, tylko całkowicie puste strony. Niższa = pozwala na strony z niewielką ilością treści." + }, + "imageToPdf": { + "name": "Obrazy do PDF", + "subtitle": "Konwertuj formaty JPG, PNG, BMP, GIF, TIFF, PNM, PGM, PBM, PPM, PAM, JXR, JPX, JP2, PSD, SVG, HEIC, WebP na PDF." + }, + "pngToPdf": { + "name": "PNG na PDF", + "subtitle": "Utwórz plik PDF z jednego lub wielu obrazów PNG." + }, + "webpToPdf": { + "name": "WebP na PDF", + "subtitle": "Utwórz plik PDF z jednego lub wielu obrazów WebP." + }, + "svgToPdf": { + "name": "SVG na PDF", + "subtitle": "Utwórz plik PDF z jednego lub wielu obrazów SVG." + }, + "bmpToPdf": { + "name": "BMP na PDF", + "subtitle": "Utwórz plik PDF z jednego lub wielu obrazów BMP." + }, + "heicToPdf": { + "name": "HEIC na PDF", + "subtitle": "Utwórz plik PDF z jednego lub wielu obrazów HEIC." + }, + "tiffToPdf": { + "name": "TIFF na PDF", + "subtitle": "Utwórz plik PDF z jednego lub wielu obrazów TIFF." + }, + "textToPdf": { + "name": "Tekst na PDF", + "subtitle": "Konwertuj plik ze zwykłym tekstem na plik PDF.", + "uploadFiles": "Prześlij pliki", + "typeText": "Wpisz tekst", + "acceptedFormats": "Pliki tekstowe (.txt)", + "fontFamily": "Krój czcionki", + "fontSize": "Rozmiar czcionki", + "textColor": "Kolor tekstu", + "pageSize": "Rozmiar strony", + "rtlAutoDetectNote": "Języki od prawej do lewej (arabski, urdu, perski itp.) są wykrywane automatycznie, a kierunek tekstu jest dostosowywany.", + "createButton": "Utwórz PDF" + }, + "jsonToPdf": { + "name": "JSON na PDF", + "subtitle": "Konwertuj pliki JSON do formatu PDF.", + "noteLabel": "Uwaga:", + "noteText": "Obsługiwane są wyłącznie pliki JSON utworzone przez narzędzie konwertera PDF na JSON. Standardowe pliki JSON z innych narzędzi nie będą działać.", + "acceptedFormats": "Wiele plików JSON", + "status": { + "selectAtLeastOne": "Proszę wybrać co najmniej 1 plik JSON", + "selectedReady": "Wybrano {{count}} plik(i/ów). Gotowe do konwersji!", + "readingFiles": "Odczytywanie plików (Główny wątek)...", + "converting": "Konwertowanie plików JSON na PDF...", + "readError": "Błąd odczytu plików: {{message}}", + "creatingZip": "Tworzenie pliku ZIP...", + "success": "Pliki JSON pomyślnie przekonwertowano na PDF! Rozpoczęto pobieranie pliku ZIP.", + "zipError": "Błąd tworzenia ZIP: {{message}}", + "workerError": "Błąd workera: {{message}}", + "getStarted": "Wybierz pliki JSON, aby rozpocząć" + } + }, + "pdfToJpg": { + "name": "PDF na JPG", + "subtitle": "Konwertuj każdą stronę PDF na obraz JPG.", + "imageQuality": "Jakość obrazu", + "imageQualityExplanation": "Wyższa jakość = większy rozmiar pliku", + "alert": { + "invalidFile": "Nieprawidłowy plik", + "invalidFileExplanation": "Proszę przesłać plik PDF.", + "noFile": "Brak pliku", + "noFileExplanation": "Proszę najpierw przesłać plik PDF.", + "conversionSuccess": "Pomyślnie przekonwertowano PDF na pliki JPG!", + "conversionError": "Nie udało się przekonwertować PDF na JPG. Plik może być uszkodzony." + }, + "loader": { + "converting": "Konwertowanie na JPG..." + } + }, + "pdfToPng": { + "name": "PDF na PNG", + "subtitle": "Konwertuj każdą stronę PDF na obraz PNG.", + "imageScale": "Skala obrazu", + "imageScaleExplanation": "Wyższa skala = lepsza jakość, ale większy rozmiar pliku", + "alert": { + "invalidFile": "Nieprawidłowy plik", + "invalidFileExplanation": "Proszę przesłać plik PDF.", + "noFile": "Brak pliku", + "noFileExplanation": "Proszę najpierw przesłać plik PDF.", + "conversionSuccess": "Pomyślnie przekonwertowano PDF na pliki PNG!", + "conversionError": "Nie udało się przekonwertować PDF na PNG. Plik może być uszkodzony." + }, + "loader": { + "converting": "Konwertowanie na PNG..." + } + }, + "pdfToWebp": { + "name": "PDF na WebP", + "subtitle": "Konwertuj każdą stronę PDF na obraz WebP.", + "imageQuality": "Jakość obrazu", + "imageQualityExplanation": "Wyższa jakość = większy rozmiar pliku", + "alert": { + "invalidFile": "Nieprawidłowy plik", + "invalidFileExplanation": "Proszę przesłać plik PDF.", + "noFile": "Brak pliku", + "noFileExplanation": "Proszę najpierw przesłać plik PDF.", + "conversionSuccess": "Pomyślnie przekonwertowano PDF na pliki WebP!", + "conversionError": "Nie udało się przekonwertować PDF na WebP. Plik może być uszkodzony." + }, + "loader": { + "converting": "Konwertowanie na WebP..." + } + }, + "pdfToBmp": { + "name": "PDF na BMP", + "subtitle": "Konwertuj każdą stronę PDF na obraz BMP.", + "alert": { + "invalidFile": "Nieprawidłowy plik", + "invalidFileExplanation": "Proszę przesłać plik PDF.", + "noFile": "Brak pliku", + "noFileExplanation": "Proszę najpierw przesłać plik PDF.", + "conversionSuccess": "Pomyślnie przekonwertowano PDF na pliki BMP!", + "conversionError": "Nie udało się przekonwertować PDF na BMP. Plik może być uszkodzony." + }, + "loader": { + "converting": "Konwertowanie na BMP..." + } + }, + "pdfToTiff": { + "name": "PDF na TIFF", + "subtitle": "Konwertuj każdą stronę PDF na obraz TIFF.", + "dpi": "DPI (Rozdzielczość)", + "dpiExplanation": "Wyższe DPI = lepsza jakość do druku, większy rozmiar pliku", + "compression": "Kompresja", + "compressionExplanation": "LZW i Deflate są bezstratne. CCITT Group 4 jest najlepsze dla czarno-białych zeskanowanych dokumentów.", + "colorMode": "Tryb kolorów", + "multiPage": "Zapisz jako wielostronicowy TIFF (pojedynczy plik)", + "loadingVips": "Wczytywanie procesora obrazów...", + "converting": "Konwertowanie na TIFF...", + "alert": { + "invalidFile": "Nieprawidłowy plik", + "invalidFileExplanation": "Proszę przesłać plik PDF.", + "noFile": "Brak pliku", + "noFileExplanation": "Proszę najpierw przesłać plik PDF.", + "conversionSuccess": "Pomyślnie przekonwertowano PDF na pliki TIFF!", + "conversionError": "Nie udało się przekonwertować PDF na TIFF. Plik może być uszkodzony." + } + }, + "pdfToCbz": { + "name": "PDF na CBZ", + "subtitle": "Konwertuj plik PDF na plik CBZ (Comic Book Archive) do czytników komiksów.", + "imageFormat": "Format obrazu", + "quality": "Jakość obrazu", + "qualityExplanation": "Wyższa jakość = większy rozmiar pliku", + "scale": "Skala", + "scaleExplanation": "Wyższa skala = lepsza jakość dla ekranów o wysokiej rozdzielczości", + "grayscale": "Konwertuj na odcienie szarości", + "manga": "Tryb Manga (od prawej do lewej)", + "includeMetadata": "Dołącz metadane ComicInfo.xml", + "titleLabel": "Tytuł", + "seriesLabel": "Seria", + "authorLabel": "Autor(zy)", + "numberLabel": "Nr", + "volumeLabel": "Tom", + "publisherLabel": "Wydawca", + "tagsLabel": "Tagi / Gatunek", + "yearLabel": "Rok wydania", + "ratingLabel": "Ocena (0-5)", + "converting": "Konwertowanie na CBZ...", + "alert": { + "invalidFile": "Nieprawidłowy plik", + "invalidFileExplanation": "Proszę przesłać plik PDF.", + "noFile": "Brak pliku", + "noFileExplanation": "Proszę najpierw przesłać plik PDF.", + "conversionSuccess": "Pomyślnie przekonwertowano PDF na CBZ!", + "conversionError": "Nie udało się przekonwertować PDF na CBZ. Plik może być uszkodzony." + } + }, + "pdfToGreyscale": { + "name": "PDF na odcienie szarości", + "subtitle": "Konwertuj wszystkie kolory na czarno-białe." + }, + "pdfToJson": { + "name": "PDF na JSON", + "subtitle": "Konwertuj pliki PDF do formatu JSON.", + "convertButton": "Konwertuj na JSON", + "status": { + "selectAtLeastOne": "Proszę wybrać co najmniej 1 plik PDF", + "selectedReady": "Wybrano {{count}} plik(i/ów). Gotowe do konwersji!", + "checkingEncrypted": "Sprawdzanie pod kątem zaszyfrowanych plików PDF...", + "readingFiles": "Odczytywanie plików (Główny wątek)...", + "converting": "Konwertowanie plików PDF na JSON...", + "readError": "Błąd odczytu plików: {{message}}", + "creatingZip": "Tworzenie pliku ZIP...", + "success": "Pomyślnie przekonwertowano PDF na JSON! Rozpoczęto pobieranie pliku ZIP.", + "zipError": "Błąd tworzenia ZIP: {{message}}", + "workerError": "Błąd workera: {{message}}", + "getStarted": "Wybierz pliki PDF, aby rozpocząć" + } + }, + "ocrPdf": { + "name": "OCR PDF", + "subtitle": "Zrób PDF przeszukiwalnym i dającym się kopiować.", + "languagesInDocument": "Języki w dokumencie", + "searchLanguagesPlaceholder": "Szukaj języków...", + "selectedLabel": "Wybrane:", + "none": "Brak", + "advancedSettingsSummary": "Ustawienia zaawansowane (Zalecane dla poprawy dokładności)", + "resolutionLabel": "Rozdzielczość", + "resolutionStandard": "Standardowa (192 DPI)", + "resolutionHigh": "Wysoka (288 DPI)", + "resolutionUltra": "Ultra (384 DPI)", + "binarizeLabel": "Binaryzuj obraz (Zwiększ kontrast dla czystych skanów)", + "embedFullFontsLabel": "Osadź pełne czcionki (Większy plik, lepsza kompatybilność)", + "whitelistPresetLabel": "Zestaw dozwolonych znaków (Whitelist)", + "whitelistNone": "Brak (Wszystkie znaki)", + "whitelistAlphanumeric": "Alfanumeryczne + Podstawowa Interpunkcja", + "whitelistNumbersCurrency": "Liczby + Symbole Walut", + "whitelistLettersOnly": "Tylko litery (A-Z, a-z)", + "whitelistNumbersOnly": "Tylko liczby (0-9)", + "whitelistInvoice": "Faktura/Paragon (Liczby, $, ., -, /)", + "whitelistForms": "Formularze (Alfanumeryczne + Powszechne Symbole)", + "whitelistCustom": "Niestandardowe...", + "whitelistHelp": "Tylko te znaki będą rozpoznawane. Pozostaw puste dla wszystkich znaków.", + "whitelistInputLabel": "Dozwolone znaki (Opcjonalnie)", + "whitelistInputPlaceholder": "np. abcdefghijklmnopqrstuvwxyz0123456789$.,", + "startButton": "Rozpocznij OCR", + "progressInitializing": "Inicjowanie...", + "resultsTitle": "OCR Zakończone", + "resultsDescription": "Twój przeszukiwalny plik PDF jest gotowy. Możesz również skopiować lub pobrać wyodrębniony tekst poniżej.", + "copyToClipboard": "Skopiuj do schowka", + "downloadTxt": "Pobierz jako .txt", + "downloadSearchablePdf": "Pobierz przeszukiwalny PDF", + "statusPrefix": "Status: {{status}}", + "availabilityInvalidConfig": "To wdrożenie nie udostępnia żadnych prawidłowych języków OCR. Przebuduj je z VITE_TESSERACT_AVAILABLE_LANGUAGES ustawionym na prawidłowe kody Tesseract.", + "availabilityBundles": "To wdrożenie zawiera wbudowane pakiety OCR dla: {{languages}}.", + "noLanguagesAvailable": "W tym wdrożeniu nie ma dostępnych języków OCR.", + "noLanguagesTitle": "Nie wybrano języków", + "noLanguagesMessage": "Proszę wybrać co najmniej jeden język dla OCR.", + "noFileTitle": "Brak pliku", + "noFileMessage": "Proszę najpierw przesłać plik PDF.", + "languageUnavailableTitle": "Język OCR niedostępny", + "ocrErrorTitle": "Błąd OCR", + "ocrErrorMessage": "Wystąpił błąd podczas procesu OCR. Worker mógł nie zostać poprawnie załadowany. Spróbuj ponownie.", + "howItWorksTitle": "Jak to działa:", + "extractTextLabel": "Wyodrębnij tekst:", + "extractTextDescription": "Używa Tesseract OCR do rozpoznawania tekstu z zeskanowanych obrazów lub plików PDF.", + "searchableOutputLabel": "Wynik przeszukiwalny:", + "searchableOutputDescription": "Tworzy nowy plik PDF z niewidoczną warstwą tekstu, dzięki czemu dokument staje się w pełni przeszukiwalny, z zachowaniem oryginalnego wyglądu.", + "characterFilteringLabel": "Filtrowanie znaków:", + "characterFilteringDescription": "Używaj białych list, aby odfiltrować niechciane znaki i poprawić dokładność dla określonych typów dokumentów (faktury, formularze itp.).", + "multiLanguageSupportLabel": "Obsługa wielu języków:", + "multiLanguageSupportDescription": "Wybierz wiele języków dla dokumentów zawierających treść w różnych językach." + }, + "alternateMerge": { + "name": "Naprzemienne i mieszane strony", + "subtitle": "Połącz PDF, układając strony naprzemiennie z każdego PDF. Zachowuje zakładki.", + "retainPageLabels": "Zachowaj oryginalne etykiety stron z każdego pliku", + "retainPageLabelsHint": "Wyłączone (domyślnie): połączony PDF używa naturalnej numeracji stron 1–N. Włączone: oryginalne etykiety stron z każdego pliku są zachowane (może to powodować duplikaty etykiet)." + }, + "addAttachments": { + "name": "Dodaj załączniki", + "subtitle": "Osadź jeden lub wiele plików w swoim PDF." + }, + "extractAttachments": { + "name": "Wyodrębnij załączniki", + "subtitle": "Wyodrębnij wszystkie osadzone pliki z PDF jako plik ZIP." + }, + "editAttachments": { + "name": "Edytuj załączniki", + "subtitle": "Wyświetl lub usuń załączniki w swoim pliku PDF." + }, + "dividePages": { + "name": "Podziel strony", + "subtitle": "Podziel strony w poziomie lub w pionie." + }, + "addBlankPage": { + "name": "Dodaj pustą stronę", + "subtitle": "Wstaw pustą stronę w dowolnym miejscu pliku PDF." + }, + "reversePages": { + "name": "Odwróć strony", + "subtitle": "Odwróć kolejność wszystkich stron w swoim dokumencie." + }, + "rotatePdf": { + "name": "Obróć PDF", + "subtitle": "Obracaj strony w krokach co 90 stopni." + }, + "rotateCustom": { + "name": "Obróć o niestandardowy kąt", + "subtitle": "Obróć strony o dowolny, niestandardowy kąt." + }, + "nUpPdf": { + "name": "PDF N-Up", + "subtitle": "Rozmieść wiele stron na jednym arkuszu." + }, + "combineToSinglePage": { + "name": "Połącz w jedną stronę", + "subtitle": "Połącz wszystkie strony w jeden przewijany arkusz." + }, + "viewMetadata": { + "name": "Wyświetl metadane", + "subtitle": "Zbadaj ukryte właściwości swojego pliku PDF." + }, + "editMetadata": { + "name": "Edytuj metadane", + "subtitle": "Zmień autora, tytuł i inne właściwości." + }, + "pdfsToZip": { + "name": "PDF na ZIP", + "subtitle": "Zapakuj wiele plików PDF do archiwum ZIP." + }, + "comparePdfs": { + "name": "Porównaj PDF", + "subtitle": "Porównaj dwa pliki PDF obok siebie.", + "firstPdf": "Pierwszy PDF", + "secondPdf": "Drugi PDF", + "clickOrDrop": "Kliknij lub upuść", + "page": "Strona", + "overlay": "Nakładka", + "sideBySide": "Obok siebie", + "flicker": "Migotanie", + "syncScroll": "Zsynchronizowane przewijanie", + "export": "Eksportuj", + "exportAsPdf": "Eksportuj jako PDF", + "splitView": "Widok podzielony", + "alternating": "Naprzemienny", + "leftDocument": "Lewy dokument", + "rightDocument": "Prawy dokument", + "original": "Oryginał", + "modified": "Zmodyfikowany", + "searchChanges": "Szukaj zmian...", + "deleted": "Usunięto", + "added": "Dodano", + "prevPage": "Poprzednia strona", + "nextPage": "Następna strona", + "prevChange": "Poprzednia zmiana", + "nextChange": "Następna zmiana", + "uploadTwoPdfs": "Prześlij dwa pliki PDF, aby zobaczyć różnice.", + "noDifferences": "Nie wykryto różnic na tej stronie.", + "noMatchingChanges": "Żadne zmiany nie pasują do obecnego filtra.", + "pageNotExist": "Strona {{page}} nie istnieje w tym pliku PDF.", + "noPairedPage": "Brak sparowanej strony dla tej strony.", + "buildingModel": "Budowanie modelu parowania stron...", + "indexingPdf": "Indeksowanie PDF {{num}} strona {{page}} z {{total}}...", + "loadingComparison": "Wczytywanie porównania {{current}} z {{total}}...", + "runningOcr": "Uruchamianie OCR na stronie {{page}}...", + "preparingExport": "Przygotowywanie eksportu pliku PDF...", + "renderingPage": "Renderowanie strony {{current}} z {{total}}...", + "exportError": "Błąd eksportu", + "exportFailed": "Nie udało się wyeksportować porównawczego pliku PDF.", + "loadingFile": "Wczytywanie {{name}}...", + "invalidFile": "Nieprawidłowy plik", + "invalidFileMsg": "Wybierz prawidłowy plik PDF.", + "loadError": "Nie udało się załadować pliku PDF. Może być uszkodzony lub chroniony hasłem." + }, + "posterizePdf": { + "name": "Plakatowanie PDF", + "subtitle": "Podziel dużą stronę na wiele mniejszych stron." + }, + "fixPageSize": { + "name": "Napraw rozmiar strony", + "subtitle": "Znormalizuj wszystkie strony do jednolitego rozmiaru." + }, + "linearizePdf": { + "name": "Linearyzuj PDF", + "subtitle": "Zoptymalizuj PDF do szybkiego przeglądania w sieci." + }, + "pageDimensions": { + "name": "Wymiary strony", + "subtitle": "Analizuj rozmiar, orientację i jednostki stron." + }, + "removeRestrictions": { + "name": "Usuń restrykcje", + "subtitle": "Usuń ochronę hasłem i ograniczenia bezpieczeństwa powiązane z podpisanymi cyfrowo plikami PDF." + }, + "repairPdf": { + "name": "Napraw PDF", + "subtitle": "Odzyskaj dane z uszkodzonych lub zepsutych plików PDF." + }, + "encryptPdf": { + "name": "Szyfruj PDF", + "subtitle": "Zablokuj swój PDF, dodając hasło." + }, + "sanitizePdf": { + "name": "Sanityzuj PDF", + "subtitle": "Usuń metadane, adnotacje, skrypty i inne elementy." + }, + "decryptPdf": { + "name": "Odszyfruj PDF", + "subtitle": "Odblokuj PDF, usuwając ochronę hasłem." + }, + "flattenPdf": { + "name": "Spłaszcz PDF", + "subtitle": "Spraw, aby pola formularza i adnotacje były nieedytowalne." + }, + "removeMetadata": { + "name": "Usuń metadane", + "subtitle": "Usuń ukryte dane ze swojego pliku PDF." + }, + "changePermissions": { + "name": "Zmień uprawnienia", + "subtitle": "Ustaw lub zmień uprawnienia użytkownika dla pliku PDF." + }, + "odtToPdf": { + "name": "ODT na PDF", + "subtitle": "Konwertuj pliki OpenDocument Text do formatu PDF. Obsługuje wiele plików.", + "acceptedFormats": "Pliki ODT", + "convertButton": "Konwertuj na PDF" + }, + "csvToPdf": { + "name": "CSV na PDF", + "subtitle": "Konwertuj arkusze kalkulacyjne CSV do formatu PDF. Obsługuje wiele plików.", + "acceptedFormats": "Pliki CSV", + "convertButton": "Konwertuj na PDF" + }, + "rtfToPdf": { + "name": "RTF na PDF", + "subtitle": "Konwertuj dokumenty w formacie Rich Text na PDF. Obsługuje wiele plików.", + "acceptedFormats": "Pliki RTF", + "convertButton": "Konwertuj na PDF" + }, + "wordToPdf": { + "name": "Word na PDF", + "subtitle": "Konwertuj dokumenty Word (DOCX, DOC, ODT, RTF) do formatu PDF. Obsługuje wiele plików.", + "acceptedFormats": "Pliki DOCX, DOC, ODT, RTF", + "convertButton": "Konwertuj na PDF" + }, + "excelToPdf": { + "name": "Excel na PDF", + "subtitle": "Konwertuj arkusze kalkulacyjne Excel (XLSX, XLS, ODS, CSV) do formatu PDF. Obsługuje wiele plików.", + "acceptedFormats": "Pliki XLSX, XLS, ODS, CSV", + "convertButton": "Konwertuj na PDF" + }, + "powerpointToPdf": { + "name": "PowerPoint na PDF", + "subtitle": "Konwertuj prezentacje PowerPoint (PPTX, PPT, ODP) do formatu PDF. Obsługuje wiele plików.", + "acceptedFormats": "Pliki PPTX, PPT, ODP", + "convertButton": "Konwertuj na PDF" + }, + "markdownToPdf": { + "name": "Markdown na PDF", + "subtitle": "Napisz lub wklej Markdown i wyeksportuj jako pięknie sformatowany PDF.", + "paneMarkdown": "Markdown", + "panePreview": "Podgląd", + "btnUpload": "Prześlij", + "btnSyncScroll": "Zsynchronizowane przewijanie", + "btnSettings": "Ustawienia", + "btnExportPdf": "Eksportuj PDF", + "settingsTitle": "Ustawienia Markdown", + "settingsPreset": "Predefiniowane ustawienia", + "presetDefault": "Domyślne (styl GFM)", + "presetCommonmark": "CommonMark (ścisłe)", + "presetZero": "Minimalne (brak dodatkowych funkcji)", + "settingsOptions": "Opcje Markdown", + "optAllowHtml": "Zezwalaj na tagi HTML", + "optBreaks": "Konwertuj nowe linie na
", + "optLinkify": "Automatycznie konwertuj URL na linki", + "optTypographer": "Typograf (inteligentne cudzysłowy itp.)" + }, + "pdfBooklet": { + "name": "Broszura PDF", + "subtitle": "Zmień układ stron do dwustronnego druku broszur. Złóż i zszyj, aby stworzyć książeczkę.", + "howItWorks": "Jak to działa:", + "step1": "Prześlij plik PDF.", + "step2": "Strony zostaną ułożone w kolejności odpowiedniej dla broszury.", + "step3": "Wydrukuj dwustronnie, obracając wzdłuż krótkiej krawędzi, złóż i zszyj.", + "paperSize": "Rozmiar papieru", + "orientation": "Orientacja", + "portrait": "Pionowa", + "landscape": "Pozioma", + "pagesPerSheet": "Liczba stron na arkusz", + "createBooklet": "Utwórz broszurę", + "processing": "Przetwarzanie...", + "pageCount": "Liczba stron zostanie w razie potrzeby uzupełniona do wielokrotności liczby 4." + }, + "xpsToPdf": { + "name": "XPS na PDF", + "subtitle": "Konwertuj dokumenty XPS/OXPS do formatu PDF. Obsługuje wiele plików.", + "acceptedFormats": "Pliki XPS, OXPS", + "convertButton": "Konwertuj na PDF" + }, + "mobiToPdf": { + "name": "MOBI na PDF", + "subtitle": "Konwertuj e-booki MOBI do formatu PDF. Obsługuje wiele plików.", + "acceptedFormats": "Pliki MOBI", + "convertButton": "Konwertuj na PDF" + }, + "epubToPdf": { + "name": "EPUB na PDF", + "subtitle": "Konwertuj e-booki EPUB do formatu PDF. Obsługuje wiele plików.", + "acceptedFormats": "Pliki EPUB", + "convertButton": "Konwertuj na PDF" + }, + "fb2ToPdf": { + "name": "FB2 na PDF", + "subtitle": "Konwertuj e-booki FictionBook (FB2) do formatu PDF. Obsługuje wiele plików.", + "acceptedFormats": "Pliki FB2", + "convertButton": "Konwertuj na PDF" + }, + "cbzToPdf": { + "name": "CBZ na PDF", + "subtitle": "Konwertuj archiwa komiksów (CBZ/CBR) do formatu PDF. Obsługuje wiele plików.", + "acceptedFormats": "Pliki CBZ, CBR", + "convertButton": "Konwertuj na PDF" + }, + "wpdToPdf": { + "name": "WPD na PDF", + "subtitle": "Konwertuj dokumenty WordPerfect (WPD) do formatu PDF. Obsługuje wiele plików.", + "acceptedFormats": "Pliki WPD", + "convertButton": "Konwertuj na PDF" + }, + "wpsToPdf": { + "name": "WPS na PDF", + "subtitle": "Konwertuj dokumenty WPS Office do formatu PDF. Obsługuje wiele plików.", + "acceptedFormats": "Pliki WPS", + "convertButton": "Konwertuj na PDF" + }, + "xmlToPdf": { + "name": "XML na PDF", + "subtitle": "Konwertuj dokumenty XML do formatu PDF. Obsługuje wiele plików.", + "acceptedFormats": "Pliki XML", + "convertButton": "Konwertuj na PDF" + }, + "pagesToPdf": { + "name": "Pages na PDF", + "subtitle": "Konwertuj dokumenty Apple Pages do formatu PDF. Obsługuje wiele plików.", + "acceptedFormats": "Pliki Pages", + "convertButton": "Konwertuj na PDF" + }, + "odgToPdf": { + "name": "ODG na PDF", + "subtitle": "Konwertuj pliki OpenDocument Graphics (ODG) do formatu PDF. Obsługuje wiele plików.", + "acceptedFormats": "Pliki ODG", + "convertButton": "Konwertuj na PDF" + }, + "odsToPdf": { + "name": "ODS na PDF", + "subtitle": "Konwertuj pliki arkuszy kalkulacyjnych OpenDocument (ODS) do formatu PDF. Obsługuje wiele plików.", + "acceptedFormats": "Pliki ODS", + "convertButton": "Konwertuj na PDF" + }, + "odpToPdf": { + "name": "ODP na PDF", + "subtitle": "Konwertuj pliki prezentacji OpenDocument (ODP) do formatu PDF. Obsługuje wiele plików.", + "acceptedFormats": "Pliki ODP", + "convertButton": "Konwertuj na PDF" + }, + "pubToPdf": { + "name": "PUB na PDF", + "subtitle": "Konwertuj pliki Microsoft Publisher (PUB) do formatu PDF. Obsługuje wiele plików.", + "acceptedFormats": "Pliki PUB", + "convertButton": "Konwertuj na PDF" + }, + "vsdToPdf": { + "name": "VSD na PDF", + "subtitle": "Konwertuj pliki Microsoft Visio (VSD, VSDX) do formatu PDF. Obsługuje wiele plików.", + "acceptedFormats": "Pliki VSD, VSDX", + "convertButton": "Konwertuj na PDF" + }, + "psdToPdf": { + "name": "PSD na PDF", + "subtitle": "Konwertuj pliki Adobe Photoshop (PSD) do formatu PDF. Obsługuje wiele plików.", + "acceptedFormats": "Pliki PSD", + "convertButton": "Konwertuj na PDF" + }, + "pdfToSvg": { + "name": "PDF na SVG", + "subtitle": "Konwertuj każdą stronę pliku PDF na skalowalną grafikę wektorową (SVG), aby uzyskać idealną jakość w dowolnym rozmiarze." + }, + "extractTables": { + "name": "Wyodrębnij tabele PDF", + "subtitle": "Wyodrębniaj tabele z plików PDF i eksportuj je jako pliki CSV, JSON lub Markdown." + }, + "pdfToCsv": { + "name": "PDF na CSV", + "subtitle": "Wyodrębnij tabele z PDF i skonwertuj je do formatu CSV." + }, + "pdfToExcel": { + "name": "PDF na Excel", + "subtitle": "Wyodrębnij tabele z PDF i skonwertuj je do formatu Excel (XLSX)." + }, + "pdfToText": { + "name": "PDF na Tekst", + "subtitle": "Wyodrębnij tekst z plików PDF i zapisz jako zwykły tekst (.txt). Obsługuje wiele plików.", + "noteLabel": "Uwaga:", + "noteText": "To narzędzie działa WYŁĄCZNIE z cyfrowo utworzonymi plikami PDF. W przypadku zeskanowanych dokumentów lub plików PDF opartych na obrazach użyj naszego narzędzia OCR PDF.", + "convertButton": "Wyodrębnij tekst" + }, + "digitalSignPdf": { + "name": "Podpis cyfrowy PDF", + "pageTitle": "Podpis cyfrowy PDF - Dodaj podpis kryptograficzny | BentoPDF", + "subtitle": "Dodaj kryptograficzny podpis cyfrowy do pliku PDF, używając certyfikatów X.509. Obsługuje formaty PKCS#12 (.pfx, .p12) i PEM. Twój klucz prywatny nigdy nie opuszcza przeglądarki.", + "certificateSection": "Certyfikat", + "uploadCert": "Prześlij certyfikat (.pfx, .p12, .pem)", + "certPassword": "Hasło certyfikatu", + "privateKeyPassword": "Hasło klucza prywatnego", + "certPasswordPlaceholder": "Wpisz hasło certyfikatu", + "certInfo": "Informacje o certyfikacie", + "certSubject": "Podmiot", + "certIssuer": "Wystawca", + "certValidity": "Ważność", + "signatureDetails": "Szczegóły podpisu (Opcjonalnie)", + "reason": "Powód", + "reasonPlaceholder": "np. Zatwierdzam ten dokument", + "location": "Lokalizacja", + "locationPlaceholder": "np. Warszawa, Polska", + "contactInfo": "Dane kontaktowe", + "contactPlaceholder": "np. email@example.com", + "visibleSignature": "Podpis widoczny", + "visibleSignatureDescription": "Gdy opcja ta jest włączona, na pliku PDF pojawia się widoczne pole podpisu. Możesz przesłać obraz/logo lub dodać tekst. Jeśli nie podasz żadnego z nich, nazwa sygnatariusza z certyfikatu zostanie wyświetlona automatycznie.", + "signatureImage": "Obraz/Logo podpisu (Opcjonalnie)", + "uploadSignatureImage": "Prześlij obraz (PNG, JPG, WebP)", + "signaturePreviewAlt": "Podgląd podpisu", + "remove": "Usuń", + "page": "Strona", + "firstPage": "Pierwsza strona", + "lastPage": "Ostatnia strona", + "allPages": "Wszystkie strony", + "customPage": "Strona niestandardowa nr", + "pageNumber": "Strona nr", + "xPosition": "Pozycja X (od lewej)", + "yPosition": "Pozycja Y (od góry)", + "width": "Szerokość", + "height": "Wysokość", + "addTextOverlay": "Dodaj nakładkę tekstową", + "text": "Tekst", + "textPlaceholder": "np. Podpisane cyfrowo przez Jan Kowalski", + "textColor": "Kolor tekstu", + "fontSize": "Rozmiar czcionki", + "invalidImageTitle": "Nieprawidłowy obraz", + "invalidImageMessage": "Proszę wybrać obraz w formacie PNG, JPG lub WebP.", + "invalidFileTitle": "Nieprawidłowy plik", + "invalidFileMessage": "Proszę wybrać plik PDF.", + "invalidCertificateTitle": "Nieprawidłowy certyfikat", + "invalidCertificateMessage": "Proszę wybrać plik certyfikatu .pfx, .p12 lub .pem.", + "certificateLoaded": "Certyfikat załadowany", + "certificateUnlocked": "Certyfikat odblokowany", + "failedParsePem": "Nie udało się sparsować pliku PEM", + "enterPasswordToUnlock": "Wprowadź hasło, aby odblokować", + "invalidPasswordOrCertificate": "Nieprawidłowe hasło lub certyfikat", + "incorrectPassword": "Nieprawidłowe hasło", + "failedParseCertificate": "Nie udało się sparsować certyfikatu", + "missingDataTitle": "Brakujące dane", + "missingDataMessage": "Proszę przesłać zarówno plik PDF, jak i ważny certyfikat.", + "applyingSignature": "Aplikowanie podpisu cyfrowego...", + "signingFailedTitle": "Podpisywanie nie powiodło się", + "chainFetchFailed": "Nie udało się pobrać łańcucha certyfikatów. Może to być spowodowane problemami z siecią lub niedostępnością serwera proxy certyfikatów. Sprawdź swoje połączenie internetowe i spróbuj ponownie. Jeśli problem będzie się powtarzał, skontaktuj się z pomocą techniczną.", + "failedToSignPdf": "Nie udało się podpisać pliku PDF: {{message}}", + "defaultSignatureText": "Podpisane cyfrowo przez {{signer}}\n{{date}}", + "pageCount": "{{count}} stron(y)", + "howToStep1Title": "Prześlij PDF", + "howToStep1Text": "Wybierz dokument PDF, który chcesz podpisać", + "howToStep2Title": "Prześlij certyfikat", + "howToStep2Text": "Dostarcz plik certyfikatu .pfx lub .p12 i hasło", + "howToStep3Title": "Podpisz i Pobierz", + "howToStep3Text": "Zastosuj podpis cyfrowy i pobierz podpisany PDF", + "relatedEncryptDesc": "Zabezpiecz swój PDF hasłem", + "relatedDecryptDesc": "Usuń hasło z PDF", + "relatedFlattenDesc": "Utwardź adnotacje na stałe", + "relatedSanitizeDesc": "Usuń ukryte dane", + "relatedPermissionsDesc": "Ustaw uprawnienia PDF", + "faqWhatIsQuestion": "Co to jest podpis cyfrowy?", + "faqWhatIsAnswer": "Podpis cyfrowy to mechanizm kryptograficzny weryfikujący autentyczność i integralność dokumentu. W przeciwieństwie do narysowanego podpisu używa on kryptografii klucza publicznego (certyfikatów X.509) do udowodnienia tożsamości osoby podpisującej.", + "faqFormatsQuestion": "Jakie formaty certyfikatów są obsługiwane?", + "faqFormatsAnswer": "Obsługujemy certyfikaty w formacie PKCS#12 (.pfx, .p12), które zawierają zarówno Twój certyfikat, jak i klucz prywatny w jednym zaszyfrowanym pliku. Są one powszechnie wydawane przez urzędy certyfikacji.", + "faqPrivateKeyQuestion": "Czy mój klucz prywatny jest bezpieczny?", + "faqPrivateKeyAnswer": "Tak! Całe przetwarzanie odbywa się całkowicie w Twojej przeglądarce. Twój certyfikat, klucz prywatny i pliki PDF nigdy nie opuszczają Twojego urządzenia i nie są przesyłane na żaden serwer.", + "faqValidReadersQuestion": "Czy podpis będzie ważny w czytnikach PDF?", + "faqValidReadersAnswer": "Tak, narzędzie tworzy standardowe oddzielone podpisy PKCS#7, które są rozpoznawane przez wszystkie główne przeglądarki PDF. Aby uzyskać pełną weryfikację, użyj certyfikatu od zaufanego Urzędu Certyfikacji.", + "applySignature": "Zastosuj podpis cyfrowy", + "successMessage": "PDF został pomyślnie podpisany! Podpis można zweryfikować w dowolnym czytniku PDF.", + "internetRequiredTitle": "Wymagane połączenie z internetem", + "internetRequiredDescription": "Podpisywanie może wymagać pobrania informacji o łańcuchu certyfikatów z serwera wystawcy certyfikatu w celu zwalidowania podpisu." + }, + "validateSignaturePdf": { + "name": "Zweryfikuj podpis PDF", + "pageTitle": "Zweryfikuj podpis PDF - Sprawdź podpisy cyfrowe | BentoPDF", + "subtitle": "Zweryfikuj podpisy cyfrowe w plikach PDF. Sprawdź ważność certyfikatu, zobacz dane osoby podpisującej i potwierdź integralność dokumentu. Całe przetwarzanie odbywa się w Twojej przeglądarce." + }, + "timestampPdf": { + "name": "Znakowanie czasem PDF", + "pageTitle": "Znakowanie czasem PDF Online Za Darmo - Znacznik Czasu Dokumentu RFC 3161 | BentoPDF", + "subtitle": "Dodaj znacznik czasu RFC 3161 do pliku PDF, korzystając z serwera zaufanego urzędu znakowania czasem (TSA). Udowadnia, że Twój dokument istniał w określonym momencie w czasie. Certyfikat nie jest wymagany.", + "tsaSectionTitle": "Serwer znacznika czasu (TSA)", + "selectTsa": "Wybierz serwer TSA", + "applyTimestamp": "Zastosuj znacznik czasu", + "successMessage": "PDF został pomyślnie oznaczony czasem! Znacznik czasu można zweryfikować w dowolnym czytniku PDF." + }, + "emailToPdf": { + "name": "E-mail na PDF", + "subtitle": "Konwertuj pliki wiadomości e-mail (EML, MSG) do formatu PDF. Obsługuje eksporty z programu Outlook oraz standardowe formaty poczty elektronicznej.", + "acceptedFormats": "Pliki EML, MSG", + "convertButton": "Konwertuj na PDF" + }, + "fontToOutline": { + "name": "Czcionka na krzywe", + "subtitle": "Konwertuj wszystkie czcionki na krzywe wektorowe, aby zapewnić spójne renderowanie na wszystkich urządzeniach." + }, + "deskewPdf": { + "name": "Wyprostuj PDF", + "subtitle": "Automatycznie wyprostuj przekrzywione zeskanowane strony używając OpenCV." + }, + "pdfToWord": { + "name": "PDF na Word", + "subtitle": "Konwertuj pliki PDF na edytowalne dokumenty Word." + }, + "extractImages": { + "name": "Wyodrębnij obrazy", + "subtitle": "Wyodrębnij wszystkie osadzone obrazy ze swoich plików PDF." + }, + "pdfToMarkdown": { + "name": "PDF na Markdown", + "subtitle": "Konwertuj tekst i tabele z PDF do formatu Markdown." + }, + "preparePdfForAi": { + "name": "Przygotuj PDF dla AI", + "subtitle": "Wyodrębnij zawartość PDF w formacie LlamaIndex JSON dla rurociągów RAG/LLM." + }, + "pdfOcg": { + "name": "Warstwy PDF (OCG)", + "subtitle": "Przeglądaj, przełączaj, dodawaj i usuwaj warstwy OCG w swoim pliku PDF." + }, + "pdfToPdfa": { + "name": "PDF na PDF/A", + "subtitle": "Konwertuj PDF na PDF/A w celu długoterminowej archiwizacji." + }, + "rasterizePdf": { + "name": "Rasteryzuj PDF", + "subtitle": "Konwertuj PDF na plik PDF oparty na obrazach. Spłaszcz warstwy i usuń możliwość zaznaczania tekstu." + }, + "pdfWorkflow": { + "name": "Kreator przepływów PDF", + "subtitle": "Zbuduj niestandardowe rurociągi przetwarzania PDF w wizualnym edytorze węzłów.", + "nodes": "Węzły", + "searchNodes": "Szukaj węzłów...", + "run": "Uruchom", + "clear": "Wyczyść", + "save": "Zapisz", + "load": "Wczytaj", + "export": "Eksportuj", + "import": "Importuj", + "ready": "Gotowe", + "settings": "Ustawienia", + "processing": "Przetwarzanie...", + "saveTemplate": "Zapisz szablon", + "templateName": "Nazwa szablonu", + "templatePlaceholder": "np. Przepływ Faktur", + "cancel": "Anuluj", + "loadTemplate": "Wczytaj szablon", + "noTemplates": "Brak zapisanych szablonów.", + "ok": "OK", + "workflowCompleted": "Przepływ zakończony", + "errorDuringExecution": "Błąd podczas wykonywania", + "addNodeError": "Dodaj co najmniej jeden węzeł, aby uruchomić przepływ.", + "needInputOutput": "Twój przepływ wymaga co najmniej jednego węzła wejściowego i jednego węzła wyjściowego do uruchomienia.", + "enterName": "Proszę wpisać nazwę.", + "templateExists": "Szablon o tej nazwie już istnieje.", + "templateSaved": "Szablon \"{{name}}\" został zapisany.", + "templateLoaded": "Szablon \"{{name}}\" został wczytany.", + "failedLoadTemplate": "Nie udało się wczytać szablonu.", + "noSettings": "Brak konfigurowalnych ustawień dla tego węzła.", + "advancedSettings": "Ustawienia zaawansowane", + "specialNodes": { + "pdfInput": { + "name": "Wejście PDF", + "description": "Prześlij jeden lub więcej plików PDF" + }, + "download": { + "name": "Pobieranie", + "description": "Pobierz jako PDF lub ZIP automatycznie" + } + }, + "errors": { + "noPdfsConnected": "Brak plików PDF podłączonych do węzła {{node}}", + "noPdfInputs": "Brak plików PDF na wejściu", + "expectedPdfInput": "Oczekiwano wejścia PDF", + "failedToRenderPage": "Nie udało się wyrenderować strony {{page}}", + "failedToGetCanvasContext": "Nie udało się uzyskać kontekstu płótna (canvas) dla strony {{page}}", + "failedToRenderPageToImage": "Nie udało się wyrenderować strony {{page}} na obraz", + "noPagesProcessed": "Żadne strony nie zostały przetworzone", + "cpdfNotConfigured": "CoherentPDF nie jest skonfigurowany. Proszę skonfigurować go w Ustawieniach Zaawansowanych.", + "workerError": "Błąd workera: {{message}}", + "alternateMergeWorkerError": "Błąd workera naprzemiennego łączenia: {{message}}", + "noPdfFilesUploaded": "Brak przesłanych plików PDF w węźle Wejścia PDF", + "failedToLoadFile": "Nie udało się wczytać \"{{file}}\" - plik może być uszkodzony", + "noImagesUploaded": "Brak przesłanych obrazów w węźle Wejścia Obrazów", + "noWordDocsUploaded": "Brak przesłanych dokumentów w węźle Wejścia Word", + "noExcelUploaded": "Brak przesłanych arkuszy w węźle Wejścia Excel", + "noPowerPointUploaded": "Brak przesłanych prezentacji w węźle Wejścia PowerPoint", + "noCbzUploaded": "Brak przesłanych archiwów komiksów w węźle Wejścia CBZ", + "noEmailUploaded": "Brak przesłanych plików poczty w węźle Wejścia Email", + "noEpubUploaded": "Brak przesłanych plików EPUB w węźle Wejścia EPUB", + "noFb2Uploaded": "Brak przesłanych plików FB2 w węźle Wejścia FB2", + "noJsonUploaded": "Brak przesłanych plików JSON w węźle Wejścia JSON", + "noMarkdownUploaded": "Brak przesłanych plików Markdown w węźle Wejścia Markdown", + "noMobiUploaded": "Brak przesłanych plików MOBI w węźle Wejścia MOBI", + "noOdgUploaded": "Brak przesłanych plików ODG w węźle Wejścia ODG", + "noPagesUploaded": "Brak przesłanych plików Pages w węźle Wejścia Pages", + "noPubUploaded": "Brak przesłanych plików PUB w węźle Wejścia PUB", + "noSvgUploaded": "Brak przesłanych plików SVG w węźle Wejścia SVG", + "noTextUploaded": "Brak przesłanych plików tekstowych w węźle Wejścia Tekstu", + "noVsdUploaded": "Brak przesłanych plików Visio w węźle Wejścia VSD", + "noWpdUploaded": "Brak przesłanych plików WPD w węźle Wejścia WPD", + "noWpsUploaded": "Brak przesłanych plików WPS w węźle Wejścia WPS", + "noXmlUploaded": "Brak przesłanych plików XML w węźle Wejścia XML", + "noXpsUploaded": "Brak przesłanych plików XPS w węźle Wejścia XPS", + "alternateMergeNeedsTwo": "Naprzemienne Łączenie potrzebuje co najmniej dwóch plików PDF podłączonych do wejścia", + "cropMarginsExceed": "Marginesy przycinania przekraczają wymiary strony. Zmniejsz wartości przycięcia.", + "digitalSignNoCertificate": "Brak wczytanego certyfikatu w węźle Podpisu Cyfrowego", + "encryptUserPasswordRequired": "Do zaszyfrowania wymagane jest hasło użytkownika", + "extractImagesNoneFound": "Nie znaleziono obrazów w żadnym z podłączonych plików PDF", + "invertColorsFailedReadImage": "Nie udało się odczytać danych obrazu", + "overlayRequiresPdf": "Węzeł nakładki wymaga podania wejściowego pliku PDF nakładki.", + "pdfToCsvNoTables": "Nie znaleziono tabel w pliku PDF", + "pdfToXlsxNoTables": "Nie znaleziono tabel w pliku {{file}}", + "posterizeFailedTileCanvas": "Nie udało się uzyskać kontekstu płótna (canvas) kafelka", + "redactNoText": "Redaguj: Nie określono tekstu do zredagowania", + "removeBlankPagesAllBlank": "Wszystkie strony są puste", + "svgFailedToConvert": "Nie udało się przekonwertować SVG", + "svgFailedToLoad": "Nie udało się wczytać SVG", + "timestampFailed": "Oznaczenie czasem za pomocą TSA {{tsa}} nie powiodło się: {{message}}", + "noOutputNodes": "Nie znaleziono węzłów wyjściowych. Dodaj węzeł Pobierania, aby ukończyć swój przepływ.", + "circularDependency": "Wykryto zapętlenie zależnosci w przepływie. Usuń wszelkie pętle pomiędzy węzłami.", + "encryptOrdering": "Węzeł szyfrowania zasila \"{{target}}\", co może spowodować błędy na zaszyfrowanych danych. Przenieś Szyfrowanie bezpośrednio przed węzeł wyjściowy.", + "invalidWorkflowFile": "Nieprawidłowy plik przepływu: brakuje tablic węzłów lub połączeń.", + "storageQuotaExceeded": "Nie udało się zapisać przepływu: przekroczono limit pojemności pamięci. Spróbuj usunąć stare szablony.", + "failedToImport": "Nie udało się zaimportować przepływu: {{message}}" + } + }, + "wasmSettings": { + "title": "Ustawienia Zaawansowanych Funkcji", + "description": "Skonfiguruj zewnętrzne moduły przetwarzania, aby włączyć zaawansowane funkcje PDF. Te moduły są opcjonalne i licencjonowane osobno.", + "status": { + "testing": "Testowanie...", + "customOverride": "Niestandardowe nadpisanie", + "preConfigured": "Wstępnie skonfigurowane", + "notConfigured": "Nieskonfigurowane" + }, + "preconfiguredTitle": "Wstępnie skonfigurowane i gotowe do użycia.", + "preconfiguredDescription": "Zaawansowane moduły przetwarzania są ładowane automatycznie z CDN. Możesz nadpisać poniższe adresy URL, jeśli musisz użyć niestandardowego źródła (np. dla wdrożeń izolowanych sieciowo lub hostowanych na własnym serwerze).", + "usingDefault": "Używanie domyślnego: {{url}}", + "pymupdfSubtitle": "Silnik Przetwarzania Dokumentów", + "pymupdfFeatures": "Umożliwia: PDF na Tekst, Markdown, SVG, DOCX, Excel • Wyodrębnianie Obrazów/Tabel • Konwersję Formatów", + "testButton": "Testuj", + "recommendedLabel": "Zalecane:", + "copyTitle": "Skopiuj do schowka", + "ghostscriptSubtitle": "Silnik Konwersji PDF/A", + "ghostscriptFeatures": "Umożliwia: Konwersję do PDF/A-1b, PDF/A-2b, PDF/A-3b • Zamianę czcionki na krzywe", + "cpdfSubtitle": "Silnik Zakładek i Metadanych", + "cpdfFeatures": "Umożliwia: Podział wg Zakładek • Edycję Zakładek • Metadane PDF", + "saveConfiguration": "Zapisz Konfigurację", + "savingConfiguration": "Zapisywanie konfiguracji...", + "savedTitle": "Zapisano", + "savedMessage": "Konfiguracja pomyślnie zapisana!", + "errorTitle": "Błąd", + "failedSave": "Nie udało się zapisać konfiguracji: {{message}}", + "emptyUrlTitle": "Pusty adres URL", + "emptyUrlMessage": "Proszę wprowadzić adres URL do przetestowania.", + "testSuccessTitle": "Sukces", + "connectionSuccess": "Połączenie z {{package}} powiodło się!", + "connectionFailedTitle": "Połączenie Nie Powiodło Się", + "connectionFailedMessage": "Nie można było połączyć się z adresem URL.", + "resetDefaults": "Przywróć Domyślne", + "resetTitle": "Reset", + "resetWithDefaults": "Niestandardowe ustawienia zostały wyczyszczone. Aktywne są wstępnie skonfigurowane ustawienia domyślne.", + "resetNoDefaults": "Wszystkie konfiguracje i moduły z pamięci podręcznej zostały wyczyszczone.", + "licenseTitle": "Informacja licencyjna:", + "licenseDescription": "Zewnętrzne moduły (PyMuPDF, Ghostscript, CoherentPDF) są licencjonowane na podstawie AGPL-3.0 lub podobnych licencji copyleft. Konfigurując i używając tych modułów, zgadzasz się na ich odpowiednie warunki licencyjne. BentoPDF jest kompatybilne z dowolną implementacją Ghostscript WASM i PyMuPDF WASM, która podąża za oczekiwanym interfejsem." + }, + "pdfOverlay": { + "name": "Nakładka PDF", + "subtitle": "Nakładaj lub podkładaj strony z jednego pliku PDF na inny.", + "basePdfLabel": "Bazowy PDF", + "uploadBasePdf": "Prześlij bazowy plik PDF", + "overlayPdfLabel": "PDF jako Nakładka / Podkład", + "uploadOverlayPdf": "Prześlij PDF nakładki/podkładu", + "modeLabel": "Tryb", + "overlayOption": "Nakładka (na wierzchu stron)", + "underlayOption": "Podkład (pod stronami)", + "pageRangeLabel": "Zastosuj do stron (opcjonalnie)", + "pageRangeHint": "Użyj \"z\" dla ostatniej strony. Pozostaw puste, aby zastosować do wszystkich stron.", + "repeatLabel": "Zapętl strony nakładki/podkładu, jeśli baza jest dłuższa", + "processButton": "Zastosuj Nakładkę / Podkład", + "howItWorksUploadTitle": "Prześlij Dwa Pliki PDF", + "howItWorksUploadDescription": "Prześlij bazowy plik PDF oraz PDF, który chcesz nałożyć na wierzch lub pod spód.", + "howItWorksModeTitle": "Wybierz Tryb", + "howItWorksModeDescription": "Wybierz nakładkę (na wierzchu) lub podkład (pod spodem). Opcjonalnie ustaw zakres stron i powtarzanie.", + "howItWorksDownloadTitle": "Pobierz", + "howItWorksDownloadDescription": "Pobierz plik PDF z nałożoną nakładką lub podkładem.", + "faqDifferenceQuestion": "Jaka jest różnica między nakładką a podkładem?", + "faqDifferenceAnswer": "Nakładka umieszcza strony na wierzchu Twojego bazowego pliku PDF (jak znak wodny). Podkład umieszcza strony pod Twoim bazowym plikiem PDF (jak papier firmowy lub tło).", + "faqSinglePageQuestion": "Czy mogę użyć jednostronicowego PDF jako nakładki na wszystkie strony?", + "faqSinglePageAnswer": "Tak! Włącz opcję \"Zapętl\", a strony Twojego PDF-a z nakładką będą powtarzane na wszystkich stronach bazowych. Jednostronicowy znak wodny zostanie nałożony na każdą stronę.", + "faqPrivacyQuestion": "Czy moje pliki są prywatne i bezpieczne?", + "faqPrivacyAnswer": "Zdecydowanie tak! Całe przetwarzanie odbywa się w Twojej przeglądarce. Twoje pliki nigdy nie opuszczają Twojego urządzenia, co zapewnia całkowitą prywatność." + } +} diff --git a/src/js/i18n/i18n.ts b/src/js/i18n/i18n.ts index e0c80f70..9e326b3e 100644 --- a/src/js/i18n/i18n.ts +++ b/src/js/i18n/i18n.ts @@ -17,6 +17,7 @@ export const supportedLanguages = [ 'id', 'it', 'pt', + 'pl', 'nl', 'da', 'sv', @@ -42,6 +43,7 @@ export const languageNames: Record = { id: 'Bahasa Indonesia', it: 'Italiano', pt: 'Português', + pl: 'Polski', nl: 'Nederlands', da: 'Dansk', sv: 'Svenska', diff --git a/vite.config.ts b/vite.config.ts index 9bfe50a7..ca2acd97 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -26,6 +26,7 @@ const SUPPORTED_LANGUAGES = [ 'it', 'nl', 'pt', + 'pl', 'sv', 'tr', 'vi', From 01c61489041774882c7bd1e908c9df5bfe296015 Mon Sep 17 00:00:00 2001 From: nine-dev9 Date: Tue, 23 Jun 2026 01:05:12 +0200 Subject: [PATCH 03/71] Fix missing regex in i18n.ts --- src/js/i18n/i18n.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/js/i18n/i18n.ts b/src/js/i18n/i18n.ts index 9e326b3e..03bc5880 100644 --- a/src/js/i18n/i18n.ts +++ b/src/js/i18n/i18n.ts @@ -66,7 +66,7 @@ export const getLanguageFromUrl = (): SupportedLanguage => { } const langMatch = path.match( - /^\/(en|ar|fr|es|de|zh|zh-TW|vi|tr|id|it|pt|nl|be|da|ko|sv|ru|ja|uk|sk)(?:\/|$)/ + /^\/(en|ar|fr|es|de|zh|zh-TW|vi|tr|id|it|pt|pl|nl|be|da|ko|sv|ru|ja|uk|sk)(?:\/|$)/ ); if ( langMatch && @@ -156,7 +156,7 @@ export const changeLanguage = (lang: SupportedLanguage): void => { let pagePathWithoutLang = relativePath; const langPrefixMatch = relativePath.match( - /^\/(en|ar|fr|es|de|zh|zh-TW|vi|tr|id|it|pt|nl|be|da|ko|sv|ru|ja|uk|sk)(\/.*)?$/ + /^\/(en|ar|fr|es|de|zh|zh-TW|vi|tr|id|it|pt|pl|nl|be|da|ko|sv|ru|ja|uk|sk)(\/.*)?$/ ); if (langPrefixMatch) { pagePathWithoutLang = langPrefixMatch[2] || '/'; @@ -251,7 +251,7 @@ export const rewriteLinks = (): void => { } const langPrefixRegex = new RegExp( - `^(${basePath.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')})?/?(en|ar|fr|es|de|zh|zh-TW|vi|tr|id|it|pt|nl|be|da|ko|sv|ru|ja|uk|sk)(/|$)` + `^(${basePath.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')})?/?(en|ar|fr|es|de|zh|zh-TW|vi|tr|id|it|pt|pl|nl|be|da|ko|sv|ru|ja|uk|sk)(/|$)` ); if (langPrefixRegex.test(href)) { return; From 39024e1a63b11b9cbc29f34e33ace79dfdb47fb9 Mon Sep 17 00:00:00 2001 From: nine-dev9 Date: Tue, 23 Jun 2026 01:11:37 +0200 Subject: [PATCH 04/71] Revert "Fix missing regex in i18n.ts" This reverts commit 01c61489041774882c7bd1e908c9df5bfe296015. --- src/js/i18n/i18n.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/js/i18n/i18n.ts b/src/js/i18n/i18n.ts index 03bc5880..9e326b3e 100644 --- a/src/js/i18n/i18n.ts +++ b/src/js/i18n/i18n.ts @@ -66,7 +66,7 @@ export const getLanguageFromUrl = (): SupportedLanguage => { } const langMatch = path.match( - /^\/(en|ar|fr|es|de|zh|zh-TW|vi|tr|id|it|pt|pl|nl|be|da|ko|sv|ru|ja|uk|sk)(?:\/|$)/ + /^\/(en|ar|fr|es|de|zh|zh-TW|vi|tr|id|it|pt|nl|be|da|ko|sv|ru|ja|uk|sk)(?:\/|$)/ ); if ( langMatch && @@ -156,7 +156,7 @@ export const changeLanguage = (lang: SupportedLanguage): void => { let pagePathWithoutLang = relativePath; const langPrefixMatch = relativePath.match( - /^\/(en|ar|fr|es|de|zh|zh-TW|vi|tr|id|it|pt|pl|nl|be|da|ko|sv|ru|ja|uk|sk)(\/.*)?$/ + /^\/(en|ar|fr|es|de|zh|zh-TW|vi|tr|id|it|pt|nl|be|da|ko|sv|ru|ja|uk|sk)(\/.*)?$/ ); if (langPrefixMatch) { pagePathWithoutLang = langPrefixMatch[2] || '/'; @@ -251,7 +251,7 @@ export const rewriteLinks = (): void => { } const langPrefixRegex = new RegExp( - `^(${basePath.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')})?/?(en|ar|fr|es|de|zh|zh-TW|vi|tr|id|it|pt|pl|nl|be|da|ko|sv|ru|ja|uk|sk)(/|$)` + `^(${basePath.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')})?/?(en|ar|fr|es|de|zh|zh-TW|vi|tr|id|it|pt|nl|be|da|ko|sv|ru|ja|uk|sk)(/|$)` ); if (langPrefixRegex.test(href)) { return; From 4487f2c1c64bbdee34da506b1591117c5c32b5b2 Mon Sep 17 00:00:00 2001 From: nine-dev9 Date: Tue, 23 Jun 2026 01:11:51 +0200 Subject: [PATCH 05/71] Reapply "Fix missing regex in i18n.ts" This reverts commit 39024e1a63b11b9cbc29f34e33ace79dfdb47fb9. --- src/js/i18n/i18n.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/js/i18n/i18n.ts b/src/js/i18n/i18n.ts index 9e326b3e..03bc5880 100644 --- a/src/js/i18n/i18n.ts +++ b/src/js/i18n/i18n.ts @@ -66,7 +66,7 @@ export const getLanguageFromUrl = (): SupportedLanguage => { } const langMatch = path.match( - /^\/(en|ar|fr|es|de|zh|zh-TW|vi|tr|id|it|pt|nl|be|da|ko|sv|ru|ja|uk|sk)(?:\/|$)/ + /^\/(en|ar|fr|es|de|zh|zh-TW|vi|tr|id|it|pt|pl|nl|be|da|ko|sv|ru|ja|uk|sk)(?:\/|$)/ ); if ( langMatch && @@ -156,7 +156,7 @@ export const changeLanguage = (lang: SupportedLanguage): void => { let pagePathWithoutLang = relativePath; const langPrefixMatch = relativePath.match( - /^\/(en|ar|fr|es|de|zh|zh-TW|vi|tr|id|it|pt|nl|be|da|ko|sv|ru|ja|uk|sk)(\/.*)?$/ + /^\/(en|ar|fr|es|de|zh|zh-TW|vi|tr|id|it|pt|pl|nl|be|da|ko|sv|ru|ja|uk|sk)(\/.*)?$/ ); if (langPrefixMatch) { pagePathWithoutLang = langPrefixMatch[2] || '/'; @@ -251,7 +251,7 @@ export const rewriteLinks = (): void => { } const langPrefixRegex = new RegExp( - `^(${basePath.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')})?/?(en|ar|fr|es|de|zh|zh-TW|vi|tr|id|it|pt|nl|be|da|ko|sv|ru|ja|uk|sk)(/|$)` + `^(${basePath.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')})?/?(en|ar|fr|es|de|zh|zh-TW|vi|tr|id|it|pt|pl|nl|be|da|ko|sv|ru|ja|uk|sk)(/|$)` ); if (langPrefixRegex.test(href)) { return; From 994fd816265afff3b7f92ea4795fce3e3ed48b50 Mon Sep 17 00:00:00 2001 From: nine-dev9 Date: Tue, 23 Jun 2026 01:12:24 +0200 Subject: [PATCH 06/71] Revert "Reapply "Fix missing regex in i18n.ts"" This reverts commit 4487f2c1c64bbdee34da506b1591117c5c32b5b2. --- src/js/i18n/i18n.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/js/i18n/i18n.ts b/src/js/i18n/i18n.ts index 03bc5880..9e326b3e 100644 --- a/src/js/i18n/i18n.ts +++ b/src/js/i18n/i18n.ts @@ -66,7 +66,7 @@ export const getLanguageFromUrl = (): SupportedLanguage => { } const langMatch = path.match( - /^\/(en|ar|fr|es|de|zh|zh-TW|vi|tr|id|it|pt|pl|nl|be|da|ko|sv|ru|ja|uk|sk)(?:\/|$)/ + /^\/(en|ar|fr|es|de|zh|zh-TW|vi|tr|id|it|pt|nl|be|da|ko|sv|ru|ja|uk|sk)(?:\/|$)/ ); if ( langMatch && @@ -156,7 +156,7 @@ export const changeLanguage = (lang: SupportedLanguage): void => { let pagePathWithoutLang = relativePath; const langPrefixMatch = relativePath.match( - /^\/(en|ar|fr|es|de|zh|zh-TW|vi|tr|id|it|pt|pl|nl|be|da|ko|sv|ru|ja|uk|sk)(\/.*)?$/ + /^\/(en|ar|fr|es|de|zh|zh-TW|vi|tr|id|it|pt|nl|be|da|ko|sv|ru|ja|uk|sk)(\/.*)?$/ ); if (langPrefixMatch) { pagePathWithoutLang = langPrefixMatch[2] || '/'; @@ -251,7 +251,7 @@ export const rewriteLinks = (): void => { } const langPrefixRegex = new RegExp( - `^(${basePath.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')})?/?(en|ar|fr|es|de|zh|zh-TW|vi|tr|id|it|pt|pl|nl|be|da|ko|sv|ru|ja|uk|sk)(/|$)` + `^(${basePath.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')})?/?(en|ar|fr|es|de|zh|zh-TW|vi|tr|id|it|pt|nl|be|da|ko|sv|ru|ja|uk|sk)(/|$)` ); if (langPrefixRegex.test(href)) { return; From 9c90d08a14a9757eb53f79992436d53791a76897 Mon Sep 17 00:00:00 2001 From: pavel-miniutka Date: Tue, 1 Sep 2026 15:57:26 +0300 Subject: [PATCH 07/71] fix(i18n): Belarusian translation fixes --- public/locales/be/common.json | 28 +- public/locales/be/tools.json | 497 +++++++++++++++++----------------- 2 files changed, 263 insertions(+), 262 deletions(-) diff --git a/public/locales/be/common.json b/public/locales/be/common.json index 693411f6..96fe0b68 100644 --- a/public/locales/be/common.json +++ b/public/locales/be/common.json @@ -5,7 +5,7 @@ "contact": "Кантакты", "licensing": "Ліцэнзія", "allTools": "Усе інструменты", - "docs": "Docs", + "docs": "Дакументацыя", "openMainMenu": "Адкрыць галоўнае меню", "language": "Мова", "searchLanguage": "Пошук мовы…", @@ -59,7 +59,7 @@ "title": "Пачніце працу з", "toolsLabel": "інструментамі", "subtitle": "Націсніце на інструмент, каб адкрыць запампоўшчык", - "searchPlaceholder": "Пошук (напр., \"выдаліць\", \"сціснуць\"...)", + "searchPlaceholder": "Пошук (напр., «выдаліць», «сціснуць»...)", "backToTools": "Назад да інструментаў", "firstLoadNotice": "Першае адкрыццё займае крыху часу, пакуль загружаецца рухавік канвертацыі. Потым усё будзе адкрывацца імгненна." }, @@ -100,11 +100,11 @@ }, "howItWorks": { "title": "Як гэта працуе", - "step1Title": "Загрузіць файл", + "step1Title": "Запампуйце файл", "step1": "Націсніце або перацягніце файл, каб пачаць", - "step2Title": "Апрацоўка", + "step2Title": "Апрацуйце", "step2": "Націсніце кнопку апрацоўкі", - "step3Title": "Спампаваць", + "step3Title": "Спампуйце", "step3": "Імгненна захавайце апрацаваны файл" }, "relatedTools": { @@ -175,7 +175,7 @@ }, "ccpa": { "title": "Адпаведнасць CCPA", - "description": "Дае жыхарам Каліфорніі правы ведаць, як збіраецца, выкарыстоўваецца і перадаецца іх персанальная інфармацыя." + "description": "Дае жыхарам Каліфорніі правы адносна таго, як збіраецца, выкарыстоўваецца і перадаецца іх персанальная інфармацыя." }, "hipaa": { "title": "Адпаведнасць HIPAA", @@ -211,7 +211,7 @@ "answer": "Звычайна інструменты PDF запампоўваюць вашы файлы на сервер для апрацоўкі. BentoPDF ніколі так не робіць. Мы выкарыстоўваем бяспечныя сучасныя вэб-тэхналогіі, каб апрацоўваць вашы файлы непасрэдна ў браўзеры. Гэта азначае большую хуткасць, лепшую прыватнасць і поўны спакой." }, "browserBased": { - "question": "Чаму апрацоўка ў браўзеры - гэта бяспечна?", + "question": "Чаму апрацоўка ў браўзеры — гэта бяспечна?", "answer": "Працуючы цалкам у браўзеры, BentoPDF гарантуе, што вашы файлы ніколі не пакінуць вашу прыладу. Гэта ліквідуе рызыкі ўзлому сервераў, уцечак даных або несанкцыянаванага доступу. Вашы файлы застаюцца вашымі — заўсёды." }, "analytics": { @@ -264,7 +264,7 @@ "of": "з", "download": "Спампаваць", "cancel": "Скасаваць", - "save": "Захаваць", + "save": "Захавайце", "delete": "Выдаліць", "edit": "Рэдагаваць", "add": "Дадаць", @@ -302,7 +302,7 @@ }, "free": { "title": "Цалкам бясплатна", - "description": "Без пробных версій, падпісак, схаваных плацяжоў і без \"прэміум\" функцый. Мы верым, што магутныя інструменты PDF павінны быць грамадскай карысцю, а не цэнтрам прыбытку." + "description": "Без пробных версій, падпісак, схаваных плацяжоў і без «прэміум» функцый. Мы верым, што магутныя інструменты PDF павінны быць грамадскай карысцю, а не цэнтрам прыбытку." }, "noAccount": { "title": "Не патрэбны ўліковы запіс", @@ -350,12 +350,12 @@ "download": "Спампаваць:", "downloadSelected": "Спампаваць выбранае", "exportPdf": "Экспартаваць PDF", - "uploadPdfFiles": "Выбраць PDF або выявы", - "dragAndDrop": "Перацягніце PDF або выявы сюды або націсніце, каб выбраць", + "uploadPdfFiles": "Выбраць PDF або відарысы", + "dragAndDrop": "Перацягніце PDF або відарысы сюды або націсніце, каб выбраць", "selectFiles": "Выбраць файлы", - "dropToAdd": "Адпусціце PDF або выявы для дабаўлення", - "convertingImages": "Канвертацыя выяў у PDF...", - "failedToConvertImages": "Не ўдалося канвертаваць выявы ў PDF.", + "dropToAdd": "Адпусціце PDF або відарысы, каб дадаць", + "convertingImages": "Канвертаванне відарысаў у PDF...", + "failedToConvertImages": "Не ўдалося канвертаваць відарысы ў PDF.", "renderingPages": "Апрацоўка старонак...", "actions": { "duplicatePage": "Дубляваць гэту старонку", diff --git a/public/locales/be/tools.json b/public/locales/be/tools.json index b5ad9ab0..7a72b685 100644 --- a/public/locales/be/tools.json +++ b/public/locales/be/tools.json @@ -19,7 +19,8 @@ "name": "Аб'яднаць PDF", "subtitle": "Аб'яднаць некалькі PDF у адзін файл. Закладкі захоўваюцца.", "retainPageLabels": "Захоўваць арыгінальныя пазнакі старонак з кожнага файла", - "retainPageLabelsHint": "Выключана (па змаўчанні): аб’яднаны PDF выкарыстоўвае натуральную нумарацыю 1–N. Уключана: арыгінальныя пазнакі старонак кожнага файла захоўваюцца (могуць узнікнуць паўторы)." + "retainPageLabelsHint": "Выключана (прадвызначана): аб'яднаны PDF выкарыстоўвае натуральную нумарацыю 1–N. Уключана: арыгінальныя пазнакі старонак кожнага файла захоўваюцца (могуць узнікнуць паўторы).", + "removeDuplicateFonts": "Выдаліць дублікаты шрыфтоў" }, "splitPdf": { "name": "Падзяліць PDF", @@ -32,7 +33,7 @@ "condense": "Condense (Рэкамендуецца)", "photon": "Photon (Для PDF з вялікай колькасцю фота)", "condenseInfo": "Condense выкарыстоўвае прасунутае сцісканне: выдаляе лішняе, аптымізуе відарысы, паднаборы шрыфтоў. Найлепш пасуе для большасці PDF.", - "photonInfo": "Photon ператварае старонкі ў відарысы. Для PDF з вялікай колькасцю фота або сканіраваных PDF.", + "photonInfo": "Photon канвертуе старонкі ў відарысы. Для PDF з вялікай колькасцю фота або сканаваных PDF.", "photonWarning": "Папярэджанне: стане немагчыма вылучыць тэкст, і перастануць працаваць спасылкі.", "levelLabel": "Узровень сціскання", "light": "Лёгкі (Захаванне якасці)", @@ -57,24 +58,24 @@ }, "editPdfText": { "name": "Рэдагаваць тэкст PDF", - "subtitle": "Націсніце на любы абзац і рэдагуйце яго на месцы з імгненнай перакампаноўкай тэксту, шрыфтамі і стылямі.", + "subtitle": "Рэдагаваць любы абзац на месцы — з імгненнай перакампаноўкай тэксту, шрыфтамі і стылямі.", "saved": "PDF паспяхова захаваны! ({{size}} КБ)", "failedToLoad": "Не ўдалося загрузіць рэдактар тэксту PDF.", - "howToUpload": "Загрузіць PDF", + "howToUpload": "Запампуйце PDF", "howToClick": "Націсніце на абзац", "howToRestyle": "Змяніце стыль", - "relatedPdfEditor": "Каментуйце і разметьце PDF", - "relatedSignPdf": "Намалюйце, увядзіце або загрузіце подпіс", - "relatedWatermark": "Нанясіце тэкст або выявы", - "relatedStamps": "Размяшчайце штампы на старонках", - "relatedCompress": "Паменшыце памер файла", + "relatedPdfEditor": "Анатаваць і размячаць PDF", + "relatedSignPdf": "Намаляваць, увесці або запампаваць подпіс", + "relatedWatermark": "Нанесці тэкст або відарысы", + "relatedStamps": "Размясціць штампы на старонках", + "relatedCompress": "Паменшыць памер файла", "relatedOrganizeName": "Упарадкаваць PDF", - "relatedOrganize": "Мяняйце парадак і кіруйце старонкамі", + "relatedOrganize": "Змяніць парадак і кіраваць старонкамі", "open": "Адкрыць", "export": "Экспарт", "filterAll": "Усе", "filterText": "Тэкст", - "filterImages": "Выявы", + "filterImages": "Відарысы", "filterShapes": "Фігуры", "addText": "Дадаць тэкст", "langAuto": "Аўта", @@ -83,7 +84,7 @@ "next": "Далей", "replace": "Замяніць", "replaceAll": "Замяніць усё", - "emptyState": "Адкрыйце PDF, каб рэдагаваць тэкст, выявы і фігуры.", + "emptyState": "Адкрыйце PDF, каб рэдагаваць тэкст, відарысы і фігуры.", "choosePdf": "Выберыце PDF…", "font": "Шрыфт", "systemFonts": "Сістэмныя шрыфты", @@ -96,32 +97,32 @@ "direction": "Напрамак", "dirAuto": "Аўта", "pathStroke": "Абвядзенне контуру", - "tipBackToUpload": "Назад да загрузкі", + "tipBackToUpload": "Назад да запампоўкі", "tipOpenAnotherPdf": "Адкрыць іншы PDF", "tipExportS": "Экспарт (⌘S)", - "tipUndoZ": "Адмяніць (⌘Z)", - "tipRedoZ": "Паўтарыць (⇧⌘Z)", + "tipUndoZ": "Адрабіць (⌘Z)", + "tipRedoZ": "Узнавіць (⇧⌘Z)", "tipFileDetails": "Звесткі пра файл", "tipEditExistingContent": "Рэдагаваць наяўнае змесціва", "tipWhatTheEditToolTouchesNarrowTheScopeOnBus": "На што дзейнічае інструмент рэдагавання — звузьце вобласць на насычаных старонках", "tipClickThePageToAddATextBox": "Націсніце на старонку, каб дадаць тэкставае поле", "tipSpellCheckLanguage": "Мова праверкі правапісу", "tipFindAndReplace": "Знайсці і замяніць", - "tipAddAnImage": "Дадаць выяву", - "tipCopyThisPageSTextInReadingOrder": "Скапіяваць тэкст старонкі ў парадку чытання", + "tipAddAnImage": "Дадаць відарыс", + "tipCopyThisPageSTextInReadingOrder": "Скапіраваць тэкст старонкі ў парадку чытання", "tipCheckTheSpellingOfThisPage": "Праверыць правапіс на гэтай старонцы", "tipShowOrHideTheFormatPanel": "Паказаць або схаваць панэль фарматавання", "phReplaceWith": "Замяніць на", "tipAddToYourDictionary": "Дадаць у слоўнік", "tipClose": "Закрыць", "phFind": "Знайсці", - "tipPreviousMatch": "Папярэдні супадзенне", + "tipPreviousMatch": "Папярэдняе супадзенне", "tipNextMatch": "Наступнае супадзенне", "tipRotateLeft90": "Павярнуць на 90° улева", "tipRotateRight90": "Павярнуць на 90° управа", "tipFlipHorizontal": "Адлюстраваць гарызантальна", "tipFlipVertical": "Адлюстраваць вертыкальна", - "tipReplaceThisImageKeepingItsPlacement": "Замяніць выяву, захаваўшы размяшчэнне", + "tipReplaceThisImageKeepingItsPlacement": "Замяніць відарыс, захаваўшы размяшчэнне", "tipAlternateTextForAccessibilityTaggedPdfs": "Альтэрнатыўны тэкст для даступнасці (тэгаваныя PDF)", "tipBringToFront": "На пярэдні план", "tipSendToBack": "На задні план", @@ -160,7 +161,7 @@ "tipRightToLeft": "Справа налева", "tipStrokeColor": "Колер абвядзення", "tipStrokeWidth": "Таўшчыня абвядзення", - "tipZoomPresets": "Прадусталёўкі маштабу", + "tipZoomPresets": "Перадвызначаныя налады маштабу", "tipZoomOut": "Паменшыць", "tipZoomIn": "Павялічыць", "tipFitPage": "Па памеры старонкі", @@ -199,12 +200,12 @@ "editBookmarks": { "name": "Рэдагаваць закладкі", "subtitle": "Дадаць, рэдагаваць, імпартаваць, выдаліць і выняць закладкі PDF.", - "autoExtractExisting": "Аўтаматычна выманне існуючых закладак", + "autoExtractExisting": "Аўтаматычнае выманне наяўных закладак", "importSectionTitle": "Або імпартаваць закладкі", "csvFormat": "Фармат CSV: загаловак,старонка,узровень", "jsonFormat": "Фармат JSON", - "uploadCsvAction": "Націсніце, каб загрузіць CSV", - "uploadJsonAction": "Націсніце, каб загрузіць JSON", + "uploadCsvAction": "Націсніце, каб запампаваць CSV", + "uploadJsonAction": "Націсніце, каб запампаваць JSON", "orDragHere": "або перацягніце сюды" }, "tableOfContents": { @@ -213,15 +214,15 @@ "titleLabel": "Загаловак зместу", "fontSize": "Памер шрыфта", "fontFamily": "Сямейства шрыфтоў", - "addBookmark": "Додати закладку для сторінки змісту", + "addBookmark": "Дадаць закладку для старонкі зместу", "generateButton": "Стварыць змест", "selectPdfFirst": "Спачатку выберыце PDF-файл.", - "statusReadingFileMainThread": "Читання файлу (головний потік)...", + "statusReadingFileMainThread": "Чытанне файла (галоўны паток)...", "statusGenerating": "Стварэнне зместу...", - "errorReadingFileWithMessage": "Помилка читання файлу: {{message}}", + "errorReadingFileWithMessage": "Памылка чытання файла: {{message}}", "successGeneratedDownloadStarted": "Змест паспяхова створаны! Спампоўванне распачалося.", - "workerErrorWithMessage": "Помилка: {{message}}", - "workerErrorOccurred": "Адбылася памылка працаўніка. Падрабязнасці ў кансолі." + "workerErrorWithMessage": "Памылка: {{message}}", + "workerErrorOccurred": "Адбылася памылка апрацоўшчыка. Падрабязнасці ў кансолі." }, "pageNumbers": { "name": "Нумары старонак", @@ -238,18 +239,18 @@ "howLabelsWorkStep4": "Уключыце працяг нумарацыі, калі адно правіла выкарыстоўвае разарваны дыяпазон, напрыклад 1-9,30-40 або няцотныя старонкі.", "labelRulesTitle": "Правілы пазнак", "addRule": "Дадаць правіла", - "removeExistingLabels": "Выдаліць існуючыя пазнакі старонак перад прымяненнем гэтых правіл", + "removeExistingLabels": "Выдаліць наяўныя пазнакі старонак перад прымяненнем гэтых правіл", "cpdfNote": "Гэты інструмент выкарыстоўвае CoherentPDF у вашым браўзеры. Калі CoherentPDF не наладжаны, вам будзе прапанавана наладзіць яго ў наладах WASM.", "processButton": "Дадаць пазнакі старонак", - "howItWorksUploadTitle": "Запампаваць файл", - "howItWorksUploadDescription": "Выберыце PDF, які хочаце перапазначыць.", - "howItWorksDefineTitle": "Вызначыць правілы", + "howItWorksUploadTitle": "Запампуйце файл", + "howItWorksUploadDescription": "Выберыце PDF, у якім хочаце змяніць пазнакі.", + "howItWorksDefineTitle": "Вызначце правілы", "howItWorksDefineDescription": "Наладзьце адно або некалькі правіл пазнак старонак з дыяпазонамі, стылямі, прэфіксамі і пачатковымі значэннямі.", - "howItWorksDownloadTitle": "Спампаваць", + "howItWorksDownloadTitle": "Спампуйце", "howItWorksDownloadDescription": "Захавайце абноўлены PDF з новымі пазнакамі старонак.", "relatedToolsTitle": "Звязаныя інструменты PDF", "faqWhatIsQuestion": "Што такое пазнака старонкі?", - "faqWhatIsAnswer": "Пазнака старонкі - гэта нумарацыя, якую чытальнікі PDF паказваюць у мініяцюрах, навігацыі па старонках і дыялогах друку. Яна не друкуе новы тэкст на самой старонцы.", + "faqWhatIsAnswer": "Пазнака старонкі — гэта нумарацыя, якую чытальнікі PDF паказваюць у мініяцюрах, навігацыі па старонках і дыялогах друку. Яна не друкуе новы тэкст на самой старонцы.", "faqMixQuestion": "Ці можна спалучаць рымскія і звычайныя лічбы?", "faqMixAnswer": "Так. Дадайце некалькі правіл, напрыклад 1-4 з LowercaseRoman і 5-20 з DecimalArabic.", "faqPrivacyQuestion": "Ці застаюцца мае файлы прыватнымі?", @@ -301,12 +302,12 @@ }, "invertColors": { "name": "Інвертаваць колеры", - "subtitle": "Стварыць версію PDF у \"цёмнай тэме\"." + "subtitle": "Стварыць версію PDF у «цёмнай тэме»." }, "scannerEffect": { "name": "Эфект сканера", "subtitle": "Зрабіць PDF падобным да адсканаванага дакумента.", - "scanSettings": "Налады сканіравання", + "scanSettings": "Налады сканавання", "colorspace": "Каляровая прастора", "gray": "Градацыі шэрага", "border": "Рамка", @@ -331,7 +332,7 @@ "temperature": "Тэмпература", "tint": "Адценне", "gamma": "Гама", - "sepia": "Сэпія", + "sepia": "Сепія", "processButton": "Ужыць рэгуліроўкі колеру" }, "backgroundColor": { @@ -348,7 +349,7 @@ "usernameLabel": "Імя для штампа", "usernamePlaceholder": "Увядзіце сваё імя (для штампаў)", "usernameHint": "Гэта імя з'явіцца на створаных вамі штампах.", - "saveButton": "Захаваць PDF з пячаткай" + "saveButton": "Захаваць PDF са штампамі" }, "removeAnnotations": { "name": "Выдаліць анатацыі", @@ -357,9 +358,9 @@ "pdfFormFiller": { "name": "Запоўніць форму PDF", "subtitle": "Запоўніць форму непасрэдна ў браўзеры. Таксама падтрымліваюцца формы XFA.", - "uploadHint": "Завантажте PDF з полями форми. Заповніть їх безпосередньо у переглядачі нижче, потім натисніть кнопку, щоб зберегти та завантажити заповнену форму. Також підтримуються форми XFA.", + "uploadHint": "Запампуйце PDF з палямі формы. Запоўніце іх непасрэдна ў праглядальніку ніжэй, а затым націсніце кнопку, каб захаваць і спампаваць запоўненую форму. Таксама падтрымліваюцца формы XFA.", "xfaNoteTitle": "Заўвага па формах XFA:", - "xfaNoteDescription": "XFA (XML Forms Architecture) — застарілий формат, який підтримується лише певними PDF-переглядачами, такими як BentoPDF та Firefox. Якщо ви відкриваєте XFA PDF в іншому ПЗ і бачите порожні сторінки або відсутність полів форми, це означає, що цей переглядач не підтримує XFA. Щоб правильно переглядати та заповнювати форми XFA, використовуйте Firefox або заповнювач форм BentoPDF." + "xfaNoteDescription": "XFA (XML Forms Architecture) — састарэлы фармат, што падтрымліваецца толькі некаторымі праглядальнікамі PDF, напрыклад BentoPDF і Firefox. Калі адкрыць PDF XFA ў іншай праграме і ўбачыць пустыя старонкі або адсутнасць палёў формы, гэта азначае, што праглядальнік не падтрымлівае XFA. Для правільнага прагляду і запаўнення XFA выкарыстоўвайце Firefox або праграму запаўнення формаў BentoPDF." }, "createPdfForm": { "name": "Стварыць форму PDF", @@ -403,33 +404,33 @@ "textToPdf": { "name": "Тэкст у PDF", "subtitle": "Канвертаваць звычайны тэкставы файл у PDF.", - "uploadFiles": "Загрузіць файлы", + "uploadFiles": "Запампаваць файлы", "typeText": "Увесці тэкст", - "acceptedFormats": "Текстові файли (.txt)", + "acceptedFormats": "Тэкставыя файлы (.txt)", "fontFamily": "Сямейства шрыфтоў", "fontSize": "Памер шрыфта", "textColor": "Колер тэксту", "pageSize": "Памер старонкі", - "rtlAutoDetectNote": "Мови RTL (арабська, урду, перська тощо) автоматично визначаються, і напрямок тексту регулюється.", + "rtlAutoDetectNote": "Мовы з напрамкам справа налева (арабская, урду, персідская і інш.) вызначаюцца аўтаматычна, і кірунак тэксту карэктуецца.", "createButton": "Стварыць PDF" }, "jsonToPdf": { "name": "JSON у PDF", "subtitle": "Канвертаваць файлы JSON у фармат PDF.", - "noteLabel": "Примітка:", - "noteText": "Підтримуються лише JSON-файли, створені інструментом PDF→JSON. Стандартні JSON-файли від інших інструментів не працюють.", - "acceptedFormats": "Кілька JSON-файлів", + "noteLabel": "Нататка:", + "noteText": "Падтрымліваюцца толькі файлы JSON, створаныя інструментам канвертавання PDF у JSON. Стандартныя файлы JSON з іншых інструментаў не будуць працаваць.", + "acceptedFormats": "Некалькі файлаў JSON", "status": { - "selectAtLeastOne": "Виберіть принаймні 1 JSON-файл", - "selectedReady": "Вибрано {{count}} файл(ів). Готово до конвертації!", - "readingFiles": "Читання файлів (головний потік)...", - "converting": "Конвертація JSON-файлів у PDF...", - "readError": "Помилка читання файлів: {{message}}", - "creatingZip": "Створення ZIP-файлу...", - "success": "JSON-файли успішно конвертовано в PDF! Завантаження ZIP розпочато.", - "zipError": "Помилка створення ZIP: {{message}}", - "workerError": "Помилка Worker: {{message}}", - "getStarted": "Виберіть JSON-файли, щоб почати" + "selectAtLeastOne": "Выберыце хаця б 1 файл JSON", + "selectedReady": "Выбрана файлаў: {{count}}. Гатова да канвертавання!", + "readingFiles": "Чытанне файлаў (галоўны паток)...", + "converting": "Пераўтварэнне файлаў JSON у PDF...", + "readError": "Памылка чытання файлаў: {{message}}", + "creatingZip": "Стварэнне ZIP-файла...", + "success": "Файлы JSON паспяхова пераўтвораны ў PDF! Пачалося спампоўванне ZIP.", + "zipError": "Памылка стварэння ZIP: {{message}}", + "workerError": "Памылка апрацоўшчыка: {{message}}", + "getStarted": "Выберыце файлы JSON, каб пачаць" } }, "pdfToJpg": { @@ -515,7 +516,8 @@ "noFile": "Няма файла", "noFileExplanation": "Спачатку запампуйце файл PDF.", "conversionSuccess": "PDF паспяхова канвертаваны ў TIFFs!", - "conversionError": "Не ўдалося канвертаваць PDF у TIFF. Файл можа быць пашкоджаны." + "conversionError": "Не ўдалося канвертаваць PDF у TIFF. Файл можа быць пашкоджаны.", + "conversionOutOfMemory": "У браўзеры скончылася памяць падчас канвертавання. Паспрабуйце знізіць DPI або адключыць параметр шматстаронкавага TIFF, каб канвертаваць старонкі па адной." } }, "pdfToCbz": { @@ -555,19 +557,19 @@ "pdfToJson": { "name": "PDF у JSON", "subtitle": "Канвертаваць файлы PDF у фармат JSON.", - "convertButton": "Конвертувати у JSON", + "convertButton": "Пераўтварыць у JSON", "status": { - "selectAtLeastOne": "Виберіть принаймні 1 PDF-файл", - "selectedReady": "Вибрано {{count}} файл(ів). Готово до конвертації!", - "checkingEncrypted": "Перевірка зашифрованих PDF...", - "readingFiles": "Читання файлів (головний потік)...", - "converting": "Конвертація PDF у JSON...", - "readError": "Помилка читання файлів: {{message}}", - "creatingZip": "Створення ZIP-файлу...", - "success": "PDF успішно конвертовано у JSON! Завантаження ZIP розпочато.", - "zipError": "Помилка створення ZIP: {{message}}", - "workerError": "Помилка Worker: {{message}}", - "getStarted": "Виберіть PDF-файли, щоб почати" + "selectAtLeastOne": "Выберыце хаця б 1 файл PDF", + "selectedReady": "Выбрана файлаў: {{count}}. Гатова да канвертавання!", + "checkingEncrypted": "Праверка зашыфраваных PDF...", + "readingFiles": "Чытанне файлаў (галоўны паток)...", + "converting": "Пераўтварэнне PDF у JSON...", + "readError": "Памылка чытання файлаў: {{message}}", + "creatingZip": "Стварэнне ZIP-файла...", + "success": "PDF паспяхова пераўтвораны ў JSON! Пачалося спампоўванне ZIP.", + "zipError": "Памылка стварэння ZIP: {{message}}", + "workerError": "Памылка апрацоўшчыка: {{message}}", + "getStarted": "Выберыце файлы PDF, каб пачаць" } }, "ocrPdf": { @@ -577,62 +579,62 @@ "searchLanguagesPlaceholder": "Пошук моў...", "selectedLabel": "Выбрана:", "none": "Няма", - "advancedSettingsSummary": "Додаткові налаштування (рекомендовано для покращення точності)", + "advancedSettingsSummary": "Пашыраныя налады (рэкамендуецца для павышэння дакладнасці)", "resolutionLabel": "Раздзяляльная здольнасць", "resolutionStandard": "Стандартная (192 DPI)", "resolutionHigh": "Высокая (288 DPI)", "resolutionUltra": "Ультра (384 DPI)", - "binarizeLabel": "Бінаризувати зображення (покращити контраст для чистих сканів)", - "embedFullFontsLabel": "Вбудувати повні шрифти (більший файл, краща сумісність)", - "whitelistPresetLabel": "Передустановка білого списку символів", - "whitelistNone": "Немає (усі символи)", - "whitelistAlphanumeric": "Літери та цифри + базова пунктуація", - "whitelistNumbersCurrency": "Числа + Символи валют", - "whitelistLettersOnly": "Лише літери (A-Z, a-z)", - "whitelistNumbersOnly": "Лише числа (0-9)", - "whitelistInvoice": "Рахунок/Чек (числа, $, ., -, /)", - "whitelistForms": "Форми (літери та цифри + загальні символи)", - "whitelistCustom": "Користувацький...", - "whitelistHelp": "Будуть розпізнані лише ці символи. Залиште порожнім для всіх символів.", - "whitelistInputLabel": "Білий список символів (необов'язково)", + "binarizeLabel": "Бінарызаваць відарыс (павысіць кантраст для чыстых сканаў)", + "embedFullFontsLabel": "Убудаваць поўныя шрыфты (большы файл, лепшая сумяшчальнасць)", + "whitelistPresetLabel": "Перадвызначаная налада спісу дазволеных сімвалаў", + "whitelistNone": "Няма (усе сімвалы)", + "whitelistAlphanumeric": "Лічбавыя і літарныя сімвалы + асноўныя знакі прыпынку", + "whitelistNumbersCurrency": "Лічбы + сімвалы валют", + "whitelistLettersOnly": "Толькі літары (A-Z, a-z)", + "whitelistNumbersOnly": "Толькі лічбы (0-9)", + "whitelistInvoice": "Рахунак/квітанцыя (лічбы, $, ., -, /)", + "whitelistForms": "Формы (літары і лічбы + агульнаўжывальныя сімвалы)", + "whitelistCustom": "Уласны…", + "whitelistHelp": "Распазнаюцца толькі гэтыя сімвалы. Пакіньце поле пустым, каб дазволіць усе сімвалы.", + "whitelistInputLabel": "Спіс дазволеных сімвалаў (неабавязкова)", "whitelistInputPlaceholder": "напр., abcdefghijklmnopqrstuvwxyz0123456789$.,", "startButton": "Запусціць OCR", "progressInitializing": "Ініцыялізацыя...", "resultsTitle": "OCR завершаны", - "resultsDescription": "Ваш PDF з пошуком готовий. Ви також можете скопіювати або завантажити витягнутий текст нижче.", - "copyToClipboard": "Капіяваць у буфер абмену", + "resultsDescription": "PDF з магчымасцю пошуку гатовы. Ніжэй можна скапіраваць або спампаваць выняты тэкст.", + "copyToClipboard": "Капіраваць у буфер абмену", "downloadTxt": "Спампаваць як .txt", "downloadSearchablePdf": "Спампаваць пошукавы PDF", "statusPrefix": "Статус: {{status}}", - "availabilityInvalidConfig": "Цей реліз не надає дійсних мов OCR. Перебудуйте його з VITE_TESSERACT_AVAILABLE_LANGUAGES, встановленим на дійсні коди Tesseract.", - "availabilityBundles": "Цей реліз містить OCR для: {{languages}}.", + "availabilityInvalidConfig": "Гэта разгортванне не прапануе ніводнай дапушчальнай мовы OCR. Перазбярыце яго, задаўшы VITE_TESSERACT_AVAILABLE_LANGUAGES дапушчальнымі кодамі Tesseract.", + "availabilityBundles": "Гэта разгортванне ўключае OCR для: {{languages}}.", "noLanguagesAvailable": "У гэтым выпуску няма даступных моў OCR.", "noLanguagesTitle": "Мовы не выбраны", "noLanguagesMessage": "Выберыце прынамсі адну мову для OCR.", "noFileTitle": "Няма файла", - "noFileMessage": "Спачатку загрузіце PDF-файл.", + "noFileMessage": "Спачатку запампуйце PDF-файл.", "languageUnavailableTitle": "Мова OCR недаступная", "ocrErrorTitle": "Памылка OCR", - "ocrErrorMessage": "Падчас працэсу OCR адбылася памылка. Магчыма, працаўнік не загрузіўся. Паспрабуйце яшчэ раз.", + "ocrErrorMessage": "Падчас працэсу OCR адбылася памылка. Магчыма, апрацоўшчык не загрузіўся. Паспрабуйце яшчэ раз.", "howItWorksTitle": "Як гэта працуе:", - "extractTextLabel": "Витягти текст:", - "extractTextDescription": "Використовує Tesseract OCR для розпізнавання тексту на сканованих зображеннях або PDF.", - "searchableOutputLabel": "Вивід з можливістю пошуку:", - "searchableOutputDescription": "Створює новий PDF з невидимим текстовим шаром, роблячи ваш документ повністю придатним для пошуку, зберігаючи оригінальний вигляд.", - "characterFilteringLabel": "Фільтрація символів:", - "characterFilteringDescription": "Використовуйте білі списки для фільтрації небажаних символів і покращення точності для конкретних типів документів (рахунки, форми тощо).", - "multiLanguageSupportLabel": "Багатомовна підтримка:", - "multiLanguageSupportDescription": "Виберіть кілька мов для документів зі змішаним мовним вмістом." + "extractTextLabel": "Выняць тэкст:", + "extractTextDescription": "Выкарыстоўвае OCR Tesseract для распазнавання тэксту са сканаваных відарысаў або PDF.", + "searchableOutputLabel": "Вынік з магчымасцю пошуку:", + "searchableOutputDescription": "Стварае новы PDF з нябачным тэкставым слоем, робячы дакумент цалкам даступным для пошуку і захоўваючы яго першапачатковы выгляд.", + "characterFilteringLabel": "Фільтраванне сімвалаў:", + "characterFilteringDescription": "Дазваляе адфільтроўваць непатрэбныя сімвалы праз спісы дазволеных і павышае дакладнасць для пэўных тыпаў дакументаў (рахункаў, формаў і інш.).", + "multiLanguageSupportLabel": "Падтрымка некалькіх моў:", + "multiLanguageSupportDescription": "Дазваляе выбраць некалькі моў для дакументаў з тэкстам на розных мовах." }, "alternateMerge": { "name": "Чаргаваць і змяшаць старонкі", "subtitle": "Аб'яднаць PDF, чаргуючы старонкі з асобных PDF. Закладкі захоўваюцца.", "retainPageLabels": "Захоўваць арыгінальныя пазнакі старонак з кожнага файла", - "retainPageLabelsHint": "Выключана (па змаўчанні): аб’яднаны PDF выкарыстоўвае натуральную нумарацыю 1–N. Уключана: арыгінальныя пазнакі старонак кожнага файла захоўваюцца (могуць узнікнуць паўторы)." + "retainPageLabelsHint": "Выключана (прадвызначана): аб'яднаны PDF выкарыстоўвае натуральную нумарацыю 1–N. Уключана: арыгінальныя пазнакі старонак кожнага файла захоўваюцца (могуць узнікнуць паўторы)." }, "duplexCollate": { "name": "Сартаванне двухбаковага сканавання", - "subtitle": "Упарадкоўвае PDF, адсканаваны двума блокамі (спачатку ўсе пярэднія бакі, потым усе адваротныя), у правільны парадак пярэдні/адваротны.", + "subtitle": "Упарадкаваць PDF, адсканаваны двума блокамі (спачатку ўсе пярэднія бакі, потым усе адваротныя), у правільны парадак пярэдні/адваротны.", "totalPagesLabel": "Усяго старонак:", "splitAfterPageLabel": "Падзяліць пасля старонкі", "splitAfterPagePlaceholder": "напр. 50", @@ -644,7 +646,7 @@ "pagesPerDocumentLabel": "Старонак у зыходным дакуменце", "groupedHelp": "Калі ўключана, вынікам будзе ZIP-архіў з асобным PDF для кожнага згрупаванага дакумента.", "collateButton": "Сабраць PDF", - "invalidFileTitle": "Няправільны файл", + "invalidFileTitle": "Памылковы файл", "invalidFileMessage": "Выберыце файл PDF.", "loadingPdf": "Загрузка PDF...", "loadErrorMessage": "Не ўдалося загрузіць файл PDF.", @@ -653,18 +655,18 @@ "previewSummary": "Блок пярэдніх бакоў: {{frontCount}} стар., блок адваротных: {{backCount}} стар. Вынік: {{outputCount}} стар. у парадку пярэдні/адваротны.", "previewMismatchWarning": "Даўжыня блокаў пярэдніх і адваротных бакоў адрозніваецца ({{frontCount}} пярэдніх супраць {{backCount}} адваротных). Лішнія старонкі ({{extraCount}}) з даўжэйшага блока будуць дададзены без пары ў канец.", "missingFileTitle": "Файл не выбраны", - "missingFileMessage": "Перад апрацоўкай загрузіце PDF прынамсі з 2 старонкамі.", - "invalidSplitTitle": "Няправільны пункт падзелу", + "missingFileMessage": "Перад апрацоўкай запампуйце PDF прынамсі з 2 старонкамі.", + "invalidSplitTitle": "Памылковы пункт падзелу", "invalidSplitMessage": "Пункт падзелу павінен быць паміж старонкай 1 і старонкай {{maxSplit}}.", "unevenConfirmTitle": "Няроўныя блокі", "unevenConfirmMessage": "У блоку пярэдніх бакоў {{frontCount}} стар., у блоку адваротных — {{backCount}} стар.\nЗвычайна гэта азначае, што старонка адсканавана двойчы або яе не хапае.\n\nСтаронкі без пары ({{extraCount}}) будуць дададзены ў канец.\n\nУсё роўна працягнуць?", - "invalidGroupTitle": "Няправільны памер групы", + "invalidGroupTitle": "Памылковы памер групы", "invalidGroupMessage": "Увядзіце правільную колькасць старонак у зыходным дакуменце.", "collatingLoader": "Збор двухбаковага сканавання...", "successMessage": "Сабраны PDF паспяхова створаны.", "successGroupedMessage": "Збор завершаны. Створана файлаў: {{fileCount}}.", "processErrorMessage": "Не ўдалося сабраць PDF.", - "howItWorksStep1Title": "Загрузіце скан", + "howItWorksStep1Title": "Запампуйце скан", "howItWorksStep1": "Перацягніце адзін PDF, у якім спачатку ідуць усе пярэднія бакі, а потым усе адваротныя.", "howItWorksStep2Title": "Задайце пункт падзелу", "howItWorksStep2": "Пазначце, дзе заканчваецца блок пярэдніх бакоў, і выберыце, ці трэба перавярнуць блок адваротных.", @@ -673,7 +675,7 @@ "faqOddPagesQuestion": "Што рабіць, калі ў скане няцотная колькасць старонак?", "faqOddPagesAnswer": "Двухбаковае сканаванне павінна мець цотную колькасць старонак. Калі гэта не так, старонка, хутчэй за ўсё, адсканавана двойчы або прапушчана. Інструмент папярэдзіць вас перад апрацоўкай, а старонкі без пары будуць дададзены ў канец, каб нічога не згубілася.", "faqBackOrderQuestion": "Навошта пакідаць блок адваротных бакоў без змен?", - "faqBackOrderAnswer": "Гэта залежыць ад таго, як стос падавалі на другім праходзе. Калі перавярнуць увесь стос, адваротныя бакі ідуць у адваротным парадку — гэта варыянт па змаўчанні. Калі сканер выдаў іх у тым самым парадку, што і пярэднія бакі, выберыце пакінуць блок без змен." + "faqBackOrderAnswer": "Гэта залежыць ад таго, як стос падавалі на другім праходзе. Калі перавярнуць увесь стос, адваротныя бакі ідуць у адваротным парадку — гэта прадвызначаны варыянт. Калі сканер выдаў іх у тым самым парадку, што і пярэднія бакі, выберыце пакінуць блок без змен." }, "addAttachments": { "name": "Дадаць далучэнні", @@ -865,14 +867,14 @@ "btnSettings": "Налады", "btnExportPdf": "Экспартаваць PDF", "settingsTitle": "Налады Markdown", - "settingsPreset": "Набор налад", + "settingsPreset": "Перадвызначаная налада", "presetDefault": "Прадвызначаны (як GFM)", "presetCommonmark": "CommonMark (строгі)", "presetZero": "Мінімальны (без функцый)", "settingsOptions": "Параметры Markdown", "optAllowHtml": "Дазволіць HTML-тэгі", "optBreaks": "Пераўтвараць пераносы радкоў у
", - "optLinkify": "Аўтаматычна пераўтвараць URL-адрасы ў спасылкі", + "optLinkify": "Аўтаматычна канвертаваць URL-адрасы ў спасылкі", "optTypographer": "Тыпограф (разумныя двукоссі і інш.)" }, "pdfBooklet": { @@ -1001,9 +1003,8 @@ "name": "PDF у тэкст", "subtitle": "Выняць тэкст з файлаў PDF і захаваць як тэкставы файл (.txt). Падтрымлівае некалькі файлаў.", "noteLabel": "Заўвага:", - "noteText": "Цей інструмент працює ТІЛЬКИ з PDF, створеними цифровим способом. Для сканованих документів або PDF на основі зображень використовуйте натомість наш інструмент OCR PDF.", - "convertButton": "Выняць тэкст", - "note": "Гэты інструмент працуе ТОЛЬКІ з PDF, створанымі лічбавым спосабам. Для сканіраваных дакументаў або PDF на аснове відарысаў выкарыстоўвайце інструмент OCR PDF." + "noteText": "Гэты інструмент працуе ТОЛЬКІ з PDF, створанымі лічбавым спосабам. Для сканаваных дакументаў або PDF на аснове відарысаў выкарыстоўвайце наш інструмент OCR PDF.", + "convertButton": "Выняць тэкст" }, "digitalSignPdf": { "name": "Лічбавы подпіс PDF", @@ -1012,7 +1013,7 @@ "certificateSection": "Сертыфікат", "uploadCert": "Запампаваць сертыфікат (.pfx, .p12, .pem)", "certPassword": "Пароль сертыфіката", - "privateKeyPassword": "Пароль приватного ключа", + "privateKeyPassword": "Пароль прыватнага ключа", "certPasswordPlaceholder": "Увядзіце пароль сертыфіката", "certInfo": "Інфармацыя пра сертыфікат", "certSubject": "Суб'ект", @@ -1025,71 +1026,71 @@ "locationPlaceholder": "напрыклад, Мінск, Беларусь", "contactInfo": "Кантактная інфармацыя", "contactPlaceholder": "напрыклад, email@example.com", - "visibleSignature": "Видимий підпис", - "visibleSignatureDescription": "Якщо увімкнено, у PDF з'являється видиме поле підпису. Можна завантажити зображення/логотип або додати текст. Якщо не вказано жодного, ім'я підписанта автоматично відображається з сертифіката.", - "signatureImage": "Зображення/логотип підпису (необов'язково)", - "uploadSignatureImage": "Завантажити зображення (PNG, JPG, WebP)", - "signaturePreviewAlt": "Попередній перегляд підпису", - "remove": "Видалити", - "page": "Сторінка", - "firstPage": "Перша сторінка", - "lastPage": "Остання сторінка", - "allPages": "Усі сторінки", - "customPage": "Користувацька сторінка #", - "pageNumber": "Сторінка #", - "xPosition": "Позиція X (зліва)", - "yPosition": "Позиція Y (зверху)", - "width": "Ширина", - "height": "Висота", - "addTextOverlay": "Додати текстове накладання", - "text": "Текст", - "textPlaceholder": "напр., Підписано в цифровій формі Іваном Петренком", - "textColor": "Колір тексту", - "fontSize": "Розмір шрифту", - "invalidImageTitle": "Недійсне зображення", - "invalidImageMessage": "Виберіть зображення PNG, JPG або WebP.", - "invalidFileTitle": "Недійсний файл", - "invalidFileMessage": "Виберіть PDF-файл.", - "invalidCertificateTitle": "Недійсний сертифікат", - "invalidCertificateMessage": "Виберіть файл сертифіката .pfx, .p12 або .pem.", - "certificateLoaded": "Сертифікат завантажено", - "certificateUnlocked": "Сертифікат розблоковано", - "failedParsePem": "Не вдалося проаналізувати файл PEM", - "enterPasswordToUnlock": "Введіть пароль для розблокування", - "invalidPasswordOrCertificate": "Невірний пароль або сертифікат", - "incorrectPassword": "Невірний пароль", - "failedParseCertificate": "Не вдалося проаналізувати сертифікат", - "missingDataTitle": "Відсутні дані", - "missingDataMessage": "Завантажте і PDF, і дійсний сертифікат.", - "applyingSignature": "Застосування цифрового підпису...", - "signingFailedTitle": "Помилка підписання", - "chainFetchFailed": "Не вдалося отримати ланцюг сертифікатів. Можливо, проблема з мережею або проксі сертифікатів недоступний. Перевірте підключення до Інтернету та повторіть спробу. Якщо проблема не зникає, зверніться до підтримки.", - "failedToSignPdf": "Не вдалося підписати PDF: {{message}}", - "defaultSignatureText": "Підписано в цифровій формі {{signer}}\n{{date}}", - "pageCount": "{{count}} стор.", - "howToStep1Title": "Завантажити PDF", - "howToStep1Text": "Виберіть PDF-документ, який хочете підписати", - "howToStep2Title": "Завантажити сертифікат", - "howToStep2Text": "Надайте файл сертифіката .pfx або .p12 і пароль", - "howToStep3Title": "Підписати та завантажити", - "howToStep3Text": "Застосуйте цифровий підпис і завантажте підписаний PDF", - "relatedEncryptDesc": "Захистити PDF паролем", - "relatedDecryptDesc": "Видалити пароль PDF", - "relatedFlattenDesc": "Зробити анотації постійними", - "relatedSanitizeDesc": "Видалити приховані дані", - "relatedPermissionsDesc": "Встановити дозволи PDF", - "faqWhatIsQuestion": "Що таке цифровий підпис?", - "faqWhatIsAnswer": "Цифровий підпис — це криптографічний механізм, який перевіряє автентичність і цілісність документа. На відміну від намальованого підпису, він використовує криптографію відкритого ключа (сертифікати X.509) для підтвердження особи підписанта.", - "faqFormatsQuestion": "Які формати сертифікатів підтримуються?", - "faqFormatsAnswer": "Ми підтримуємо сертифікати у форматі PKCS#12 (.pfx, .p12), які містять і ваш сертифікат, і приватний ключ в одному зашифрованому файлі. Зазвичай вони видаються центрами сертифікації.", - "faqPrivateKeyQuestion": "Чи безпечний мій приватний ключ?", - "faqPrivateKeyAnswer": "Так! Уся обробка відбувається повністю у вашому браузері. Ваш сертифікат, приватний ключ і файли PDF ніколи не залишають ваш пристрій і не завантажуються на жоден сервер.", - "faqValidReadersQuestion": "Чи буде підпис дійсним у переглядачах PDF?", - "faqValidReadersAnswer": "Так, інструмент створює стандартні відокремлені підписи PKCS#7, які розпізнаються всіма основними програмами для перегляду PDF. Для повної перевірки використовуйте сертифікат від довіреного центру сертифікації.", + "visibleSignature": "Бачны подпіс", + "visibleSignatureDescription": "Калі ўключана, у PDF з'яўляецца бачнае поле подпісу. Можна запампаваць відарыс або лагатып альбо дадаць тэкст. Калі нічога не дадзена, аўтаматычна будзе паказана імя падпісанта з сертыфіката.", + "signatureImage": "Відарыс або лагатып подпісу (неабавязкова)", + "uploadSignatureImage": "Запампаваць відарыс (PNG, JPG, WebP)", + "signaturePreviewAlt": "Папярэдні прагляд подпісу", + "remove": "Выдаліць", + "page": "Старонка", + "firstPage": "Першая старонка", + "lastPage": "Апошняя старонка", + "allPages": "Усе старонкі", + "customPage": "Уласная старонка №", + "pageNumber": "Старонка №", + "xPosition": "Пазіцыя X (злева)", + "yPosition": "Пазіцыя Y (зверху)", + "width": "Шырыня", + "height": "Вышыня", + "addTextOverlay": "Дадаць накладзены тэкст", + "text": "Тэкст", + "textPlaceholder": "Напрыклад, падпісана лічбавым подпісам Джона Доу", + "textColor": "Колер тэксту", + "fontSize": "Памер шрыфта", + "invalidImageTitle": "Памылковы відарыс", + "invalidImageMessage": "Выберыце відарыс PNG, JPG або WebP.", + "invalidFileTitle": "Памылковы файл", + "invalidFileMessage": "Выберыце файл PDF.", + "invalidCertificateTitle": "Памылковы сертыфікат", + "invalidCertificateMessage": "Выберыце файл сертыфіката .pfx, .p12 або .pem.", + "certificateLoaded": "Сертыфікат загружаны", + "certificateUnlocked": "Сертыфікат разблакаваны", + "failedParsePem": "Не ўдалося разабраць файл PEM", + "enterPasswordToUnlock": "Увядзіце пароль, каб разблакаваць", + "invalidPasswordOrCertificate": "Памылковы пароль або сертыфікат", + "incorrectPassword": "Няправільны пароль", + "failedParseCertificate": "Не ўдалося разабраць сертыфікат", + "missingDataTitle": "Адсутнасць даных", + "missingDataMessage": "Дадайце PDF і сапраўдны сертыфікат.", + "applyingSignature": "Накладанне лічбавага подпісу...", + "signingFailedTitle": "Не ўдалося падпісаць", + "chainFetchFailed": "Не ўдалося атрымаць ланцужок сертыфікатаў. Гэта можа быць выклікана праблемамі з сеткай або недаступнасцю проксі-сервера сертыфікатаў. Праверце падлучэнне да інтэрнэту і паспрабуйце яшчэ раз. Калі праблема захоўваецца, звярніцеся ў службу падтрымкі.", + "failedToSignPdf": "Не ўдалося падпісаць PDF: {{message}}", + "defaultSignatureText": "Падпісана лічбавым подпісам {{signer}}\n{{date}}", + "pageCount": "{{count}} старонак", + "howToStep1Title": "Запампуйце PDF", + "howToStep1Text": "Выберыце дакумент PDF, які хочаце падпісаць", + "howToStep2Title": "Запампуйце сертыфікат", + "howToStep2Text": "Дадайце файл сертыфіката .pfx або .p12 і пароль", + "howToStep3Title": "Падпішыце і спампуйце", + "howToStep3Text": "Накладзіце лічбавы подпіс і спампуйце падпісаны PDF", + "relatedEncryptDesc": "Абараніць PDF паролем", + "relatedDecryptDesc": "Выдаліць пароль PDF", + "relatedFlattenDesc": "Зрабіць анатацыі сталымі", + "relatedSanitizeDesc": "Выдаліць схаваныя даныя", + "relatedPermissionsDesc": "Задаць дазволы PDF", + "faqWhatIsQuestion": "Што такое лічбавы подпіс?", + "faqWhatIsAnswer": "Лічбавы подпіс — гэта крыптаграфічны механізм, які правярае сапраўднасць і цэласнасць дакумента. У адрозненне ад намаляванага подпісу, ён выкарыстоўвае крыптаграфію з адкрытым ключом (сертыфікаты X.509), каб пацвердзіць асобу падпісанта.", + "faqFormatsQuestion": "Якія фарматы сертыфікатаў падтрымліваюцца?", + "faqFormatsAnswer": "Падтрымліваюцца сертыфікаты фармату PKCS#12 (.pfx, .p12), якія змяшчаюць сертыфікат і закрыты ключ карыстальніка ў адным зашыфраваным файле. Такія сертыфікаты звычайна выдаюцца цэнтрамі сертыфікацыі.", + "faqPrivateKeyQuestion": "Ці ў бяспецы мой закрыты ключ?", + "faqPrivateKeyAnswer": "Так! Уся апрацоўка адбываецца непасрэдна ў браўзеры. Сертыфікат, закрыты ключ і файлы PDF ніколі не пакідаюць прыладу карыстальніка і не запампоўваюцца на сервер.", + "faqValidReadersQuestion": "Ці будзе подпіс сапраўдным у праглядальніках PDF?", + "faqValidReadersAnswer": "Так, інструмент стварае стандартныя адасобленыя подпісы PKCS#7, якія распазнаюцца ўсімі асноўнымі праглядальнікамі PDF. Для поўнай праверкі выкарыстоўвайце сертыфікат ад даверанага цэнтра сертыфікацыі.", "applySignature": "Ужыць лічбавы подпіс", "successMessage": "PDF паспяхова падпісаны! Подпіс можна праверыць у любым PDF-чытальніку.", - "internetRequiredTitle": "Потрібне інтернет-з'єднання", - "internetRequiredDescription": "Для перевірки підпису може знадобитися отримати інформацію про ланцюг сертифікатів із сервера видавця сертифіката." + "internetRequiredTitle": "Патрабуецца падлучэнне да інтэрнэту", + "internetRequiredDescription": "Для падпісання можа спатрэбіцца атрымаць звесткі пра ланцужок сертыфікатаў з сервера выдаўца сертыфіката, каб праверыць подпіс." }, "validateSignaturePdf": { "name": "Праверыць подпіс PDF", @@ -1113,11 +1114,11 @@ }, "fontToOutline": { "name": "Шрыфт у контуры", - "subtitle": "Ператварыць усе шрыфты ў вектарныя контуры для стабільнага адлюстравання на ўсіх прыладах." + "subtitle": "Канвертаваць усе шрыфты ў вектарныя контуры для стабільнага адлюстравання на ўсіх прыладах." }, "deskewPdf": { "name": "Выпрастаць PDF", - "subtitle": "Аўтаматычна выраўняць нахіленыя адсканіраваныя старонкі з дапамогай OpenCV." + "subtitle": "Аўтаматычна выраўняць нахіленыя адсканаваныя старонкі з дапамогай OpenCV." }, "pdfToWord": { "name": "PDF у Word", @@ -1167,22 +1168,22 @@ "cancel": "Скасаваць", "loadTemplate": "Загрузіць шаблон", "noTemplates": "Пакуль няма захаваных шаблонаў.", - "ok": "OK", + "ok": "ОК", "workflowCompleted": "Рабочы працэс завершаны", "errorDuringExecution": "Памылка падчас выканання", "addNodeError": "Дадайце хаця б адзін вузел для запуску рабочага працэсу.", - "needInputOutput": "Для працы рабочага працэсу патрэбен хаця б адзін вузел уводу і адзін вузел вываду.", + "needInputOutput": "Для працы рабочага працэсу патрэбны хаця б адзін вузел уводу і адзін вузел вываду.", "enterName": "Увядзіце назву.", "templateExists": "Шаблон з такой назвай ужо існуе.", - "templateSaved": "Шаблон \"{{name}}\" захаваны.", - "templateLoaded": "Шаблон \"{{name}}\" загружаны.", + "templateSaved": "Шаблон «{{name}}» захаваны.", + "templateLoaded": "Шаблон «{{name}}» загружаны.", "failedLoadTemplate": "Не ўдалося загрузіць шаблон.", "noSettings": "Няма налад для гэтага вузла.", "advancedSettings": "Пашыраныя налады", "specialNodes": { "pdfInput": { "name": "Увод PDF", - "description": "Загрузіце адзін ці некалькі файлаў PDF" + "description": "Запампуйце адзін ці некалькі файлаў PDF" }, "download": { "name": "Спампаваць", @@ -1195,96 +1196,96 @@ "expectedPdfInput": "Чакаўся ўвод PDF", "failedToRenderPage": "Не атрымалася адлюстраваць старонку {{page}}", "failedToGetCanvasContext": "Не атрымалася атрымаць кантэкст палатна для старонкі {{page}}", - "failedToRenderPageToImage": "Не атрымалася адлюстраваць старонку {{page}} як выяву", + "failedToRenderPageToImage": "Не атрымалася адлюстраваць старонку {{page}} як відарыс", "noPagesProcessed": "Ніводнай старонкі не апрацавана", - "cpdfNotConfigured": "CoherentPDF не настроены. Настройце яго ў пашыраных параметрах.", - "workerError": "Памылка воркера: {{message}}", - "alternateMergeWorkerError": "Памылка воркера паслядоўнага зліцця: {{message}}", - "noPdfFilesUploaded": "У вузел PDF Input не загружаны PDF-файлы", - "failedToLoadFile": "Не атрымалася загрузіць \"{{file}}\" — файл можа быць пашкоджаны", - "noImagesUploaded": "У вузел Image Input не загружаны выявы", - "noWordDocsUploaded": "У вузел Word Input не загружаны дакументы", - "noExcelUploaded": "У вузел Excel Input не загружаны табліцы", - "noPowerPointUploaded": "У вузел PowerPoint Input не загружаны прэзентацыі", - "noCbzUploaded": "У вузел CBZ Input не загружаны архівы коміксаў", - "noEmailUploaded": "У вузел Email Input не загружаны файлы пошты", - "noEpubUploaded": "У вузел EPUB Input не загружаны файлы EPUB", - "noFb2Uploaded": "У вузел FB2 Input не загружаны файлы FB2", - "noJsonUploaded": "У вузел JSON Input не загружаны файлы JSON", - "noMarkdownUploaded": "У вузел Markdown Input не загружаны файлы Markdown", - "noMobiUploaded": "У вузел MOBI Input не загружаны файлы MOBI", - "noOdgUploaded": "У вузел ODG Input не загружаны файлы ODG", - "noPagesUploaded": "У вузел Pages Input не загружаны файлы Pages", - "noPubUploaded": "У вузел PUB Input не загружаны файлы PUB", - "noSvgUploaded": "У вузел SVG Input не загружаны файлы SVG", - "noTextUploaded": "У вузел Text Input не загружаны тэкставыя файлы", - "noVsdUploaded": "У вузел VSD Input не загружаны файлы Visio", - "noWpdUploaded": "У вузел WPD Input не загружаны файлы WPD", - "noWpsUploaded": "У вузел WPS Input не загружаны файлы WPS", - "noXmlUploaded": "У вузел XML Input не загружаны файлы XML", - "noXpsUploaded": "У вузел XPS Input не загружаны файлы XPS", + "cpdfNotConfigured": "CoherentPDF не сканфігураваны. Сканфігуруйце яго ў пашыраных наладах.", + "workerError": "Памылка апрацоўшчыка: {{message}}", + "alternateMergeWorkerError": "Памылка апрацоўшчыка паслядоўнага зліцця: {{message}}", + "noPdfFilesUploaded": "У вузел «Увод PDF» не запампаваны PDF-файлы", + "failedToLoadFile": "Не атрымалася загрузіць «{{file}}» — файл можа быць пашкоджаны", + "noImagesUploaded": "У вузел уводу відарысаў не запампаваны відарысы", + "noWordDocsUploaded": "У вузел уводу Word не запампаваны дакументы", + "noExcelUploaded": "У вузел уводу Excel не запампаваны табліцы", + "noPowerPointUploaded": "У вузел уводу PowerPoint не запампаваны прэзентацыі", + "noCbzUploaded": "У вузел уводу CBZ не запампаваны архівы коміксаў", + "noEmailUploaded": "У вузел уводу Email не запампаваны файлы пошты", + "noEpubUploaded": "У вузел уводу EPUB не запампаваны файлы EPUB", + "noFb2Uploaded": "У вузел уводу FB2 не запампаваны файлы FB2", + "noJsonUploaded": "У вузел уводу JSON не запампаваны файлы JSON", + "noMarkdownUploaded": "У вузел уводу Markdown не запампаваны файлы Markdown", + "noMobiUploaded": "У вузел уводу MOBI не запампаваны файлы MOBI", + "noOdgUploaded": "У вузел уводу ODG не запампаваны файлы ODG", + "noPagesUploaded": "У вузел уводу Pages не запампаваны файлы Pages", + "noPubUploaded": "У вузел уводу PUB не запампаваны файлы PUB", + "noSvgUploaded": "У вузел уводу SVG не запампаваны файлы SVG", + "noTextUploaded": "У вузел уводу тэксту не запампаваны тэкставыя файлы", + "noVsdUploaded": "У вузел уводу VSD не запампаваны файлы Visio", + "noWpdUploaded": "У вузел уводу WPD не запампаваны файлы WPD", + "noWpsUploaded": "У вузел уводу WPS не запампаваны файлы WPS", + "noXmlUploaded": "У вузел уводу XML не запампаваны файлы XML", + "noXpsUploaded": "У вузел уводу XPS не запампаваны файлы XPS", "alternateMergeNeedsTwo": "Паслядоўнаму зліццю патрэбна як мінімум два PDF, падключаныя да ўваходу", "cropMarginsExceed": "Палі абрэзкі перавышаюць памеры старонкі. Паменшыце значэнні.", "digitalSignNoCertificate": "У вузле лічбавага подпісу не загружаны сертыфікат", "encryptUserPasswordRequired": "Для шыфравання патрэбны карыстальніцкі пароль", - "extractImagesNoneFound": "У падключаных PDF не знойдзена выяў", - "invertColorsFailedReadImage": "Не атрымалася прачытаць даныя выявы", + "extractImagesNoneFound": "У падключаных PDF не знойдзена відарысаў", + "invertColorsFailedReadImage": "Не атрымалася прачытаць даныя відарыса", "overlayRequiresPdf": "Вузел накладання патрабуе ўвод PDF для накладання.", "pdfToCsvNoTables": "У PDF не знойдзена табліц", "pdfToXlsxNoTables": "У {{file}} не знойдзена табліц", "posterizeFailedTileCanvas": "Не атрымалася атрымаць кантэкст палатна пліткі", - "redactNoText": "Рэдагаванне: не вызначаны тэкст для рэдагавання", + "redactNoText": "Зацямненне: не вызначаны тэкст для зацямнення", "removeBlankPagesAllBlank": "Усе старонкі пустыя", "svgFailedToConvert": "Не атрымалася канвертаваць SVG", "svgFailedToLoad": "Не атрымалася загрузіць SVG", - "timestampFailed": "Не атрымалася паставіць метку часу праз TSA {{tsa}}: {{message}}", - "noOutputNodes": "Не знойдзена вузлоў вываду. Дадайце вузел Download, каб завяршыць ваш працоўны працэс.", - "circularDependency": "У працоўным працэсе выяўлена кругавая залежнасць. Выдаліце ўсе цыклы паміж вузламі.", - "encryptOrdering": "Вузел шыфравання падае даныя ў \"{{target}}\", што можа збой на зашыфраваных даных. Перамясціце шыфраванне непасрэдна перад вузлом вываду.", - "invalidWorkflowFile": "Несапраўдны файл працоўнага працэсу: адсутнічае масіў вузлоў або злучэнняў.", - "storageQuotaExceeded": "Не атрымалася захаваць працоўны працэс: перавышана квота сховішча. Паспрабуйце выдаліць старыя шаблоны.", - "failedToImport": "Не атрымалася імпартаваць працоўны працэс: {{message}}" + "timestampFailed": "Не атрымалася паставіць пазнаку часу праз TSA {{tsa}}: {{message}}", + "noOutputNodes": "Не знойдзена вузлоў вываду. Дадайце вузел «Спампаваць», каб завяршыць ваш рабочы працэс.", + "circularDependency": "У рабочым працэсе выяўлена кругавая залежнасць. Выдаліце ўсе цыклы паміж вузламі.", + "encryptOrdering": "Вузел шыфравання падае даныя ў «{{target}}», што можа даць збой на зашыфраваных даных. Перамясціце шыфраванне непасрэдна перад вузлом вываду.", + "invalidWorkflowFile": "Памылковы файл рабочага працэсу: адсутнічае масіў вузлоў або злучэнняў.", + "storageQuotaExceeded": "Не атрымалася захаваць рабочы працэс: перавышана квота сховішча. Паспрабуйце выдаліць старыя шаблоны.", + "failedToImport": "Не атрымалася імпартаваць рабочы працэс: {{message}}" } }, "wasmSettings": { "title": "Налады пашыраных функцый", - "description": "Налаштуйте зовнішні модулі обробки для увімкнення розширених функцій PDF. Ці модулі необов'язкові і ліцензуються окремо.", + "description": "Сканфігуруйце знешнія модулі апрацоўкі для ўключэння пашыраных магчымасцей PDF. Гэтыя модулі неабавязковыя і ліцэнзуюцца асобна.", "status": { - "testing": "Перевірка...", - "customOverride": "Користувацьке перевизначення", - "preConfigured": "Попередньо налаштовано", - "notConfigured": "Не налаштовано" + "testing": "Праверка…", + "customOverride": "Уласная замена", + "preConfigured": "Папярэдне сканфігураваны", + "notConfigured": "Не сканфігураваны" }, - "preconfiguredTitle": "Попередньо налаштовано і готово до використання.", - "preconfiguredDescription": "Розширені модулі обробки автоматично завантажуються з CDN. Ви можете перевизначити URL нижче, якщо потрібно використовувати власне джерело (наприклад, для air-gapped або самостійно розміщених розгортань).", - "usingDefault": "Використовується за замовчуванням: {{url}}", - "pymupdfSubtitle": "Рушій обробки документів", - "pymupdfFeatures": "Вмикає: PDF у текст, Markdown, SVG, DOCX, Excel • Витягти зображення/таблиці • Конвертацію формату", + "preconfiguredTitle": "Папярэдне сканфігураваны і гатовы да выкарыстання", + "preconfiguredDescription": "Пашыраныя модулі апрацоўкі аўтаматычна загружаюцца з CDN. Вы можаце перавызначыць URL ніжэй, калі вам трэба выкарыстоўваць уласную крыніцу (напрыклад, для разгортванняў у ізаляваным асяроддзі або з уласным хостынгам).", + "usingDefault": "Выкарыстоўваецца прадвызначанае значэнне: {{url}}", + "pymupdfSubtitle": "Рухавік апрацоўкі дакументаў", + "pymupdfFeatures": "Уключае: канвертаванне PDF у тэкст, Markdown, SVG, DOCX, Excel • выманне відарысаў і табліц • канвертаванне фарматаў", "testButton": "Праверыць", - "recommendedLabel": "Рекомендовано:", - "copyTitle": "Копіювати в буфер обміну", - "ghostscriptSubtitle": "Рушій конвертації PDF/A", - "ghostscriptFeatures": "Вмикає: Конвертацію PDF/A-1b, PDF/A-2b, PDF/A-3b • Шрифт у контур", - "cpdfSubtitle": "Рушій закладок і метаданих", - "cpdfFeatures": "Вмикає: Розділити за закладками • Редагувати закладки • Метадані PDF", + "recommendedLabel": "Рэкамендавана:", + "copyTitle": "Капіраваць у буфер абмену", + "ghostscriptSubtitle": "Рухавік канвертавання PDF/A", + "ghostscriptFeatures": "Уключае: канвертаванне ў PDF/A-1b, PDF/A-2b, PDF/A-3b • канвертаванне шрыфтоў у контуры", + "cpdfSubtitle": "Рухавік закладак і метаданых", + "cpdfFeatures": "Уключае: раздзяленне паводле закладак • рэдагаванне закладак • метаданыя PDF", "saveConfiguration": "Захаваць канфігурацыю", - "savingConfiguration": "Збереження конфігурації...", + "savingConfiguration": "Захаванне канфігурацыі...", "savedTitle": "Захавана", "savedMessage": "Канфігурацыя паспяхова захавана!", "errorTitle": "Памылка", - "failedSave": "Не вдалося зберегти конфігурацію: {{message}}", - "emptyUrlTitle": "Порожній URL", - "emptyUrlMessage": "Введіть URL для перевірки.", - "testSuccessTitle": "Успіх", - "connectionSuccess": "Підключення до {{package}} успішне!", - "connectionFailedTitle": "Збій підключення", - "connectionFailedMessage": "Не вдалося підключитися до URL.", + "failedSave": "Не ўдалося захаваць канфігурацыю: {{message}}", + "emptyUrlTitle": "Пусты URL", + "emptyUrlMessage": "Увядзіце URL для праверкі.", + "testSuccessTitle": "Поспех", + "connectionSuccess": "Злучэнне з {{package}} паспяховае!", + "connectionFailedTitle": "Не ўдалося ўсталяваць злучэнне", + "connectionFailedMessage": "Не ўдалося злучыцца з URL.", "resetDefaults": "Скінуць да стандартных", "resetTitle": "Скід", - "resetWithDefaults": "Користувацькі перевизначення очищено. Активні попередньо налаштовані значення за замовчуванням.", - "resetNoDefaults": "Усі конфігурації та кешовані модулі очищено.", - "licenseTitle": "Повідомлення про ліцензію:", - "licenseDescription": "Зовнішні модулі (PyMuPDF, Ghostscript, CoherentPDF) ліцензовані під AGPL-3.0 або подібними copyleft-ліцензіями. Налаштовуючи та використовуючи ці модулі, ви погоджуєтеся з їхніми відповідними умовами ліцензії. BentoPDF сумісний з будь-якою реалізацією Ghostscript WASM і PyMuPDF WASM, що дотримується очікуваного інтерфейсу." + "resetWithDefaults": "Уласныя перавызначэнні ачышчаныя. Актываваныя прадвызначаныя значэнні канфігурацыі.", + "resetNoDefaults": "Усе канфігурацыі і кэшаваныя модулі ачышчаныя.", + "licenseTitle": "Звесткі пра ліцэнзію:", + "licenseDescription": "Знешнія модулі (PyMuPDF, Ghostscript, CoherentPDF) распаўсюджваюцца паводле AGPL-3.0 або падобных ліцэнзій з копілефтам. Канфігуруючы і выкарыстоўваючы гэтыя модулі, вы згаджаецеся з умовамі адпаведных ліцэнзій. BentoPDF сумяшчальны з любой рэалізацыяй Ghostscript WASM і PyMuPDF WASM, якая адпавядае чаканаму інтэрфейсу." }, "pdfOverlay": { "name": "Накладанне PDF", @@ -1297,7 +1298,7 @@ "overlayOption": "Накладанне (зверху старонак)", "underlayOption": "Падкладанне (за старонкамі)", "pageRangeLabel": "Прымяніць да старонак (неабавязкова)", - "pageRangeHint": "Выкарыстоўвайце \"z\" для апошняй старонкі. Пакіньце пустым, каб прымяніць да ўсіх старонак.", + "pageRangeHint": "Выкарыстоўвайце «z» для апошняй старонкі. Пакіньце пустым, каб прымяніць да ўсіх старонак.", "repeatLabel": "Паўтараць накладанне/падкладанне, калі базавы PDF даўжэйшы", "processButton": "Прымяніць накладанне / падкладанне", "howItWorksUploadTitle": "Запампуйце два PDF", @@ -1309,7 +1310,7 @@ "faqDifferenceQuestion": "У чым розніца паміж накладаннем і падкладаннем?", "faqDifferenceAnswer": "Накладанне размяшчае старонкі зверху базавага PDF (як вадзяны знак). Падкладанне размяшчае старонкі за базавым PDF (як фірмовы бланк або фон).", "faqSinglePageQuestion": "Ці магу я выкарыстоўваць аднастаронкавы PDF як накладанне для ўсіх старонак?", - "faqSinglePageAnswer": "Так! Уключыце опцыю \"Паўтараць\" і старонкі накладання будуць паўтарацца на ўсіх старонках базавага файла. Аднастаронкавы вадзяны знак будзе прымяняцца да кожнай старонкі.", + "faqSinglePageAnswer": "Так! Уключыце опцыю «Паўтараць» і старонкі накладання будуць паўтарацца на ўсіх старонках базавага файла. Аднастаронкавы вадзяны знак будзе прымяняцца да кожнай старонкі.", "faqPrivacyQuestion": "Ці з'яўляюцца мае файлы прыватнымі і бяспечнымі?", "faqPrivacyAnswer": "Безумоўна! Уся апрацоўка адбываецца ў вашым браўзеры. Вашы файлы ніколі не пакідаюць вашу прыладу, забяспечваючы поўную прыватнасць." } From 47af6863bda5e180fbbe75b205c90852fd648dfb Mon Sep 17 00:00:00 2001 From: pavel-miniutka Date: Wed, 2 Sep 2026 09:38:08 +0300 Subject: [PATCH 08/71] fix(i18n): use a number-independent abbreviation for page count --- public/locales/be/tools.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/locales/be/tools.json b/public/locales/be/tools.json index 7a72b685..04162f0f 100644 --- a/public/locales/be/tools.json +++ b/public/locales/be/tools.json @@ -1067,7 +1067,7 @@ "chainFetchFailed": "Не ўдалося атрымаць ланцужок сертыфікатаў. Гэта можа быць выклікана праблемамі з сеткай або недаступнасцю проксі-сервера сертыфікатаў. Праверце падлучэнне да інтэрнэту і паспрабуйце яшчэ раз. Калі праблема захоўваецца, звярніцеся ў службу падтрымкі.", "failedToSignPdf": "Не ўдалося падпісаць PDF: {{message}}", "defaultSignatureText": "Падпісана лічбавым подпісам {{signer}}\n{{date}}", - "pageCount": "{{count}} старонак", + "pageCount": "{{count}} стар.", "howToStep1Title": "Запампуйце PDF", "howToStep1Text": "Выберыце дакумент PDF, які хочаце падпісаць", "howToStep2Title": "Запампуйце сертыфікат", From e95a631909a1613fdc17ec14e7f52cb2d9e826a2 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 2 Sep 2026 10:05:23 +0000 Subject: [PATCH 09/71] @tsueri has signed the CLA in alam00000/bentopdf#851 --- signatures/cla.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/signatures/cla.json b/signatures/cla.json index 8cf397d0..c84d84d0 100644 --- a/signatures/cla.json +++ b/signatures/cla.json @@ -575,6 +575,14 @@ "created_at": "2026-08-26T12:51:13Z", "repoId": 1074785178, "pullRequestNo": 845 + }, + { + "name": "tsueri", + "id": 13819344, + "comment_id": 5507876766, + "created_at": "2026-09-02T10:05:09Z", + "repoId": 1074785178, + "pullRequestNo": 851 } ] } \ No newline at end of file From 4e2d269dc329eee802dc0547d52773aae8ebff9d Mon Sep 17 00:00:00 2001 From: pavel-miniutka Date: Wed, 2 Sep 2026 14:04:47 +0300 Subject: [PATCH 10/71] common.save action label fix --- public/locales/be/common.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/locales/be/common.json b/public/locales/be/common.json index 96fe0b68..726c9be9 100644 --- a/public/locales/be/common.json +++ b/public/locales/be/common.json @@ -264,7 +264,7 @@ "of": "з", "download": "Спампаваць", "cancel": "Скасаваць", - "save": "Захавайце", + "save": "Захаваць", "delete": "Выдаліць", "edit": "Рэдагаваць", "add": "Дадаць", From f404ff021a40feae836d005dcd9632d1cbeb205e Mon Sep 17 00:00:00 2001 From: alam00000 Date: Wed, 2 Sep 2026 18:29:08 +0530 Subject: [PATCH 11/71] feat: add Kura and Hyper Compress product pages, redesign site --- README.md | 16 +- about.html | 320 ++-- contact.html | 98 +- faq.html | 141 +- hyper-compress.html | 692 ++++++++ index.html | 823 ++++----- kura.html | 683 ++++++++ licensing.html | 2214 +++++++++++++------------ pdf-converter.html | 40 +- pdf-editor.html | 40 +- pdf-merge-split.html | 40 +- pdf-security.html | 40 +- public/locales/ar/common.json | 6 +- public/locales/en/common.json | 6 +- public/locales/es/common.json | 4 +- public/locales/id/common.json | 6 +- public/locales/ru/common.json | 8 +- public/locales/sv/common.json | 4 +- public/locales/tr/common.json | 2 +- public/locales/vi/common.json | 6 +- public/site.webmanifest | 2 +- src/css/bookmark.css | 2 +- src/css/edit-pdf-text.css | 18 +- src/css/landing.css | 2049 +++++++++++++++++++++++ src/css/styles.css | 1089 +++++++++++- src/js/landing.ts | 23 + src/js/main.ts | 49 +- src/js/mobileMenu.ts | 46 + src/pages/add-attachments.html | 34 +- src/pages/add-blank-page.html | 34 +- src/pages/add-page-labels.html | 43 +- src/pages/add-stamps.html | 34 +- src/pages/add-watermark.html | 36 +- src/pages/adjust-colors.html | 34 +- src/pages/alternate-merge.html | 40 +- src/pages/background-color.html | 34 +- src/pages/bates-numbering.html | 34 +- src/pages/bmp-to-pdf.html | 34 +- src/pages/bookmark.html | 34 +- src/pages/cbz-to-pdf.html | 34 +- src/pages/change-permissions.html | 34 +- src/pages/combine-single-page.html | 34 +- src/pages/compare-pdfs.html | 34 +- src/pages/compress-pdf.html | 36 +- src/pages/crop-pdf.html | 34 +- src/pages/csv-to-pdf.html | 34 +- src/pages/decrypt-pdf.html | 34 +- src/pages/delete-pages.html | 34 +- src/pages/deskew-pdf.html | 34 +- src/pages/digital-sign-pdf.html | 42 +- src/pages/divide-pages.html | 34 +- src/pages/duplex-collate.html | 60 +- src/pages/edit-attachments.html | 34 +- src/pages/edit-metadata.html | 34 +- src/pages/edit-pdf-text.html | 54 +- src/pages/edit-pdf.html | 34 +- src/pages/email-to-pdf.html | 44 +- src/pages/encrypt-pdf.html | 34 +- src/pages/epub-to-pdf.html | 34 +- src/pages/excel-to-pdf.html | 34 +- src/pages/extract-attachments.html | 34 +- src/pages/extract-images.html | 34 +- src/pages/extract-pages.html | 34 +- src/pages/extract-tables.html | 34 +- src/pages/fb2-to-pdf.html | 34 +- src/pages/fix-page-size.html | 34 +- src/pages/flatten-pdf.html | 34 +- src/pages/font-to-outline.html | 44 +- src/pages/form-creator.html | 36 +- src/pages/form-filler.html | 34 +- src/pages/header-footer.html | 34 +- src/pages/heic-to-pdf.html | 34 +- src/pages/image-to-pdf.html | 34 +- src/pages/invert-colors.html | 34 +- src/pages/jpg-to-pdf.html | 34 +- src/pages/json-to-pdf.html | 34 +- src/pages/linearize-pdf.html | 34 +- src/pages/markdown-to-pdf.html | 34 +- src/pages/merge-pdf.html | 40 +- src/pages/mobi-to-pdf.html | 34 +- src/pages/n-up-pdf.html | 34 +- src/pages/ocr-pdf.html | 45 +- src/pages/odg-to-pdf.html | 34 +- src/pages/odp-to-pdf.html | 34 +- src/pages/ods-to-pdf.html | 34 +- src/pages/odt-to-pdf.html | 34 +- src/pages/organize-pdf.html | 34 +- src/pages/overlay-pdf.html | 43 +- src/pages/page-dimensions.html | 34 +- src/pages/page-numbers.html | 34 +- src/pages/pages-to-pdf.html | 34 +- src/pages/pdf-booklet.html | 34 +- src/pages/pdf-layers.html | 34 +- src/pages/pdf-to-bmp.html | 34 +- src/pages/pdf-to-cbz.html | 34 +- src/pages/pdf-to-csv.html | 34 +- src/pages/pdf-to-docx.html | 34 +- src/pages/pdf-to-excel.html | 34 +- src/pages/pdf-to-greyscale.html | 34 +- src/pages/pdf-to-jpg.html | 34 +- src/pages/pdf-to-json.html | 34 +- src/pages/pdf-to-markdown.html | 34 +- src/pages/pdf-to-pdfa.html | 34 +- src/pages/pdf-to-png.html | 34 +- src/pages/pdf-to-svg.html | 34 +- src/pages/pdf-to-text.html | 34 +- src/pages/pdf-to-tiff.html | 34 +- src/pages/pdf-to-webp.html | 34 +- src/pages/pdf-to-zip.html | 34 +- src/pages/png-to-pdf.html | 34 +- src/pages/posterize-pdf.html | 34 +- src/pages/powerpoint-to-pdf.html | 34 +- src/pages/prepare-pdf-for-ai.html | 34 +- src/pages/psd-to-pdf.html | 34 +- src/pages/pub-to-pdf.html | 34 +- src/pages/rasterize-pdf.html | 34 +- src/pages/remove-annotations.html | 34 +- src/pages/remove-blank-pages.html | 34 +- src/pages/remove-metadata.html | 34 +- src/pages/remove-restrictions.html | 34 +- src/pages/repair-pdf.html | 34 +- src/pages/reverse-pages.html | 34 +- src/pages/rotate-custom.html | 34 +- src/pages/rotate-pdf.html | 34 +- src/pages/rtf-to-pdf.html | 34 +- src/pages/sanitize-pdf.html | 34 +- src/pages/scanner-effect.html | 34 +- src/pages/sign-pdf.html | 34 +- src/pages/split-pdf.html | 34 +- src/pages/svg-to-pdf.html | 34 +- src/pages/table-of-contents.html | 34 +- src/pages/text-color.html | 34 +- src/pages/tiff-to-pdf.html | 34 +- src/pages/timestamp-pdf.html | 44 +- src/pages/txt-to-pdf.html | 34 +- src/pages/validate-signature-pdf.html | 34 +- src/pages/view-metadata.html | 34 +- src/pages/vsd-to-pdf.html | 34 +- src/pages/wasm-settings.html | 2 +- src/pages/webp-to-pdf.html | 34 +- src/pages/word-to-pdf.html | 34 +- src/pages/wpd-to-pdf.html | 34 +- src/pages/wps-to-pdf.html | 34 +- src/pages/xml-to-pdf.html | 34 +- src/pages/xps-to-pdf.html | 34 +- src/partials/footer.html | 17 +- src/partials/navbar.html | 50 +- vite.config.ts | 6 +- 148 files changed, 8097 insertions(+), 4520 deletions(-) create mode 100644 hyper-compress.html create mode 100644 kura.html create mode 100644 src/css/landing.css create mode 100644 src/js/landing.ts diff --git a/README.md b/README.md index d24cf108..05ffbcef 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,7 @@ - [Convert to PDF](#convert-to-pdf) - [Convert from PDF](#convert-from-pdf) - [Secure & Optimize PDFs](#secure--optimize-pdfs) +- [Other Products](#-other-products) - [Translations](#-translations) - [Getting Started](#-getting-started) - [Prerequisites](#prerequisites) @@ -175,6 +176,7 @@ BentoPDF offers a comprehensive suite of tools to handle all your PDF needs. | Tool Name | Description | | :------------------------ | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **PDF Editor** | Annotate, highlight, redact, comment, add shapes/images, search, and view PDFs. | +| **Edit PDF Text** | Edit existing text directly in your PDF. Reuses the document's embedded fonts and keeps the rest of the page untouched. | | **Create Fillable Forms** | Create professional fillable PDF forms with text fields, checkboxes, dropdowns, radio buttons, signatures, and more. Fully compliant with PDF standards for compatibility with all PDF viewers. | | **PDF Form Filler** | Fill in forms directly in the browser. Also supports XFA forms. | | **Add Page Numbers** | Easily add page numbers with customizable formatting. | @@ -1218,16 +1220,20 @@ BentoPDF was originally built using **HTML**, **CSS**, and **vanilla JavaScript* --- +## 📦 Other Products + +| Product | Description | Links | +| :----------------- | :------------------------------------------------------------------------------------------------------------------------------------ | :----------------------------------------------------------------------------------------------------- | +| **Kura** | PDF standards and preflight engine. Converts to every PDF/A level, PDF/UA, PDF/X, PDF/E and PDF/VT, and can perform preflight checks. | [Website](https://kura.bentopdf.com) · [GitHub](https://github.com/alam00000/bentopdf-kura) | +| **Hyper Compress** | The best open source PDF compression engine. | [Website](https://hyper.bentopdf.com) · [GitHub](https://github.com/alam00000/bentopdf-hyper-compress) | + +--- + ## 🗺️ Roadmap ### Planned Features: - **HTML to PDF**: Convert HTML files or web pages into PDF documents. -- **Markdown to PDF**: Enhanced support for converting `.md` files to PDF. -- **Convert to PDF/A**: Convert PDFs to the PDF/A archival format. -- **Edit PDF Content**: Directly edit text and other content within your PDF. -- **PDF to Office**: Converts PDF files into editable Word, Excel, and PowerPoint formats. -- **Office to PDF**: Converts Word, Excel, and PowerPoint documents into optimized PDFs. Contributions and discussions on the roadmap are welcome! Join the conversation via [Discord](https://discord.gg/Bgq3Ay3f2w). diff --git a/about.html b/about.html index cb1c1063..4a37e12c 100644 --- a/about.html +++ b/about.html @@ -51,6 +51,7 @@ + @@ -77,186 +78,144 @@ - + {{> navbar }} -
-
-

- We believe PDF tools should be - fast, private, and free. -

-

- No compromises. -

-
- -
- -
-
- -

- Our Mission -

-

- To provide the most comprehensive PDF toolbox that respects your - privacy and never asks for payment. We believe essential document - tools should be accessible to everyone, everywhere, without - barriers. -

-
-
- -
-
-
- Our Core Philosophy -

- Privacy First. Always. -

-

- In an era where data is a commodity, we take a different approach. - All processing for BentoPDF tools happens locally in your browser. - This means your files never touch our servers, we never see your - documents, and we don't track what you do. Your documents remain - completely and unequivocally private. It's not just a feature; - it's our foundation. -

-
-
-
-
-
- +
+
+
+
+
+

+ We believe PDF tools should be + fast, private, and free. +

+

+ No compromises. +

-
+ -
-

- Why - BentoPDF? -

-
-
- +
+
+
+

Our Mission

+
+ To provide the most comprehensive PDF toolbox that respects your + privacy and never asks for payment. We believe essential document + tools should be accessible to everyone, everywhere, without + barriers. +
+
+ + BentoPDF + Explore All Tools +
+
+
+
+ +
+
+
-

- Built for Speed -

-

+

+ Privacy First. Always. +

+

+ In an era where data is a commodity, we take a different + approach. All processing for BentoPDF tools happens locally in + your browser. This means your files never touch our servers, we + never see your documents, and we don't track what you do. Your + documents remain completely and unequivocally private. It's not + just a feature; it's our foundation. +

+
+
+
+
+ 0No Uploads +
+
+ 0No Signups +
+
+ $0Forever Free +
+
+
+
+ +
+
+
+
+

+ Why + BentoPDF? +

+
+
+
+
+ +

Built for Speed

+

No waiting for uploads or downloads to a server. By processing files directly in your browser using modern web technologies like WebAssembly, we offer unparalleled speed for all our tools.

-
-
- -
-

- Completely Free -

-

+

+ +

Completely Free

+

No trials, no subscriptions, no hidden fees, and no "premium" features held hostage. We believe powerful PDF tools should be a public utility, not a profit center.

-
-
- -
-

+
+ +

No Account Required

-

+

Start using any tool immediately. We don't need your email, a password, or any personal information. Your workflow should be frictionless and anonymous.

-

-
- -
-

+
+ +

Open Source Spirit

-

+

Built with transparency in mind. We leverage incredible open-source libraries like PDF-lib and PDF.js, and believe in the community-driven effort to make powerful tools accessible to @@ -267,30 +226,34 @@

-
- -
-

- Ready to get started? -

-

- Join thousands of users who trust BentoPDF for their daily document - needs. Experience the difference that privacy and performance can - make. -

- - Explore All Tools - +
+
+
+

+ Ready to get started? +

+

+ Join thousands of users who trust BentoPDF for their daily + document needs. Experience the difference that privacy and + performance can make. +

+ +
+
@@ -299,6 +262,7 @@ + + + + + + + + + diff --git a/index.html b/index.html index 52177c01..cf11a2e2 100644 --- a/index.html +++ b/index.html @@ -96,40 +96,34 @@ + - + {{> navbar }} -
+
@@ -319,8 +280,6 @@
-
-

Why choose @@ -328,131 +287,67 @@ >BentoPDF?

-
-
-
- -

- No Signup -

-
-

- Start instantly, no accounts or emails. -

+
+
+ 100+Tools
-
-
- -

- No Uploads -

-
-

- 100% client-side, your files never leave your device. -

+
+ 0No Uploads
-
-
- -

- Forever Free -

-
-

- All tools, no trials, no paywalls. -

+
+ ∞Unlimited Use
-
-
- -

- No Limits -

-
-

- Use as much as you want, no hidden caps. -

-
-
-
- -

- Batch Processing -

-
-

- Handle unlimited PDFs in one go. -

-
-
-
- -

- Lightning Fast -

-
-

- Process PDFs instantly, without waiting or delays. -

+
+ $0Forever Free
-
+
+

+ Two new + engines +

+ +

@@ -509,7 +404,7 @@ >

-
-
@@ -782,9 +675,7 @@ -
- -
+

@@ -794,334 +685,182 @@ >

-
- -
-

- Yes, absolutely. All tools on BentoPDF are 100% free to use, with - no file limits, no sign-ups, and no watermarks. We believe - everyone deserves access to simple, powerful PDF tools without a - paywall. -

-
-
- -
- -
-

- Your files are as secure as possible because they **never leave - your computer**. All processing happens directly in your web - browser (client-side). We never upload your files to a server, so - you maintain complete privacy and control over your documents. -

-
-
- -
- -
-

- Yes! Since BentoPDF runs entirely in your browser, it works on any - operating system with a modern web browser, including Windows, - macOS, Linux, iOS, and Android. -

-
-
- - -
- -
-

- Yes. BentoPDF is fully GDPR compliant. Since all file processing - happens locally in your browser and we never collect or transmit - your files to any server, we have no access to your data. This - ensures you are always in control of your documents. -

-
-
- - -
- -
-

- No. We never store, track, or log your files. Everything you do on - BentoPDF happens in your browser memory and disappears once you - close the page. There are no uploads, no history logs, and no - servers involved. -

-
-
- - -
- -
-

- Most PDF tools upload your files to a server for processing. - BentoPDF never does that. We use secure, modern web technology to - process your files directly in your browser. This means faster - performance, stronger privacy, and complete peace of mind. -

-
-
- - -
- -
-

- By running entirely inside your browser, BentoPDF ensures that - your files never leave your device. This eliminates the risks of - server hacks, data breaches, or unauthorized access. Your files - remain yours—always. -

-
-
- - -
- -
-

- No. BentoPDF does not track you at all. We do not use cookies, - analytics, or any tracking scripts, not even on the live website - at bentopdf.com. We never know who you are or what you do with the - tools. -

-
-
-
- -
- -
-

- What Our - Users - Say -

-
-
-
-
-

Sarah L.

-
- ★★★★★ -
+
+
+
+ +
+

+ Yes, absolutely. All tools on BentoPDF are 100% free to use, + with no file limits, no sign-ups, and no watermarks. We + believe everyone deserves access to simple, powerful PDF tools + without a paywall. +

-

- "This is the tool I've been searching for! It's fast, free, and I - love that my confidential documents never get uploaded to some - random server. A lifesaver for my freelance work." -

-
-
-
-
-

Mark Chen

-
- ★★★★★ -
+ +
+ +
+

+ Your files are as secure as possible because they **never + leave your computer**. All processing happens directly in your + web browser (client-side). We never upload your files to a + server, so you maintain complete privacy and control over your + documents. +

-

- "Finally, a PDF editor that just works. No ads, no sign-ups, no - nonsense. The merge tool is surprisingly powerful. I've already - bookmarked it on all my devices." -

-
-
-
-
-

Anonymous User A-35Z

-
- ★☆☆☆☆ -
+ +
+ +
+

+ Yes! Since BentoPDF runs entirely in your browser, it works on + any operating system with a modern web browser, including + Windows, macOS, Linux, iOS, and Android. +

-

- "Terrible. It won't let me upload my files to the cloud. How is my - Big Data Tech Overlord supposed to know I signed a permission slip - for my kid's field trip? Useless for my data profile." -

-
-
-
-
-

Dr. Brickson

-
- ★★★★★ -
+ + +
+ +
+

+ Yes. BentoPDF is fully GDPR compliant. Since all file + processing happens locally in your browser and we never + collect or transmit your files to any server, we have no + access to your data. This ensures you are always in control of + your documents. +

-

- "As a researcher, data privacy is paramount. BentoPDF's - client-side processing model is exactly what my institution - recommends. It's robust, reliable, and secure. A fantastic - resource." -

-
-
-
-
-

AdTracker Pro

-
- ★☆☆☆☆ -
+ + +
+ +
+

+ No. We never store, track, or log your files. Everything you + do on BentoPDF happens in your browser memory and disappears + once you close the page. There are no uploads, no history + logs, and no servers involved. +

-

- "This website is broken. My ad blocker says it hasn't blocked a - single tracker. How am I supposed to know if a product is good if - it's not following me around the internet for a week? 1 star." -

-
-
-
-
-

Raj P.

-
- ★★★★★ -
+ + +
+ +
+

+ Most PDF tools upload your files to a server for processing. + BentoPDF never does that. We use secure, modern web technology + to process your files directly in your browser. This means + faster performance, stronger privacy, and complete peace of + mind. +

+
+
+ + +
+ +
+

+ By running entirely inside your browser, BentoPDF ensures that + your files never leave your device. This eliminates the risks + of server hacks, data breaches, or unauthorized access. Your + files remain yours, always. +

+
+
+ + +
+ +
+

+ No. BentoPDF does not track you at all. We do not use cookies, + analytics, or any tracking scripts, not even on the live + website at bentopdf.com. We never know who you are or what you + do with the tools. +

-

- "Simple, elegant, and powerful. I needed to merge 50 reports, and - it handled it instantly without crashing my browser. This is what - a web tool should be. Highly recommended." -

diff --git a/kura.html b/kura.html new file mode 100644 index 00000000..8700973f --- /dev/null +++ b/kura.html @@ -0,0 +1,683 @@ + + + + + + + Kura - PDF/A, PDF/UA & PDF/X Conversion Engine | BentoPDF + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {{> navbar }} + +
+
+
+
+
+

+ Meet + Kura +

+

+ The PDF standards and preflight engine. Convert any PDF to every + PDF/A level, PDF/UA, PDF/X, PDF/E and PDF/VT, then preflight the + result against 396 bundled profiles to confirm it conforms. +

+

+ Ships as a CLI, npm package, browser WebAssembly build, Docker + image and C library. +

+ +
+
+ +
+
+ 25conformance targets +
+
+ 396bundled preflight profiles +
+
+ 0false findings in conformance testing +
+
+ 5form factors, one engine +
+
+
+
+ +
+
+
+
+ +

+ Open source, self-hosting and internal use stay free. + Kura is licensed under the AGPL-3.0. If your project is + AGPL-compatible, or you run Kura as-is for yourself, you never + need a commercial license. Commercial licenses are only for + shipping Kura inside closed-source software. +

+
+
+
+
+ +
+
+
+
+

+ Commercial + Licenses +

+

+ Per product, billed annually. Every tier includes all updates + and new releases while active. +

+
+
+ +
+
+

Solo

+

+ One developer, under $100k annual revenue +

+
$99/ year
+
    +
  • One closed-source product
  • +
  • All updates while active
  • +
  • Email support
  • +
+ Get Solo +
+
+

Indie

+

Companies under $1M annual revenue

+
$199/ year
+
    +
  • One closed-source product
  • +
  • Unlimited developers
  • +
  • All updates while active
  • +
  • Email support
  • +
+ Get Indie +
+
+

Business

+

Companies at $1M annual revenue or more

+
$499/ year
+
    +
  • One closed-source product
  • +
  • Unlimited developers
  • +
  • All updates while active
  • +
  • Priority email support
  • +
+ Get Business +
+
+

OEM

+

+ Redistribution, reselling as an SDK, or offering Kura as a + service +

+
+ from$1,999/ year +
+
    +
  • Redistribution rights
  • +
  • Terms shaped to your product
  • +
  • Priority support
  • +
+ Contact us +
+
+
+
+ +
+
+
+
+

+ Commercial license + details +

+
+
+
+
+
+

+ + Delivery & licensing model +

+
    +
  • + + No license key is required or provided. + Kura intentionally does not use license keys, to + streamline deployment and reduce operational + friction. +
  • +
  • + + Upon purchase you receive a ZIP archive containing the + complete Kura source code. +
  • +
  • + + Because Kura is open source, every release and every + update can always be downloaded from our + GitHub releases page. +
  • +
  • + + The source code provided is identical to the code + published in our public open-source repository. +
  • +
  • + + No refunds. Under no + circumstances shall a refund be made after purchase. +
  • +
+

+ GitHub repository: + github.com/alam00000/bentopdf-kura +

+
+ +
+

+ + Invoicing +

+
    +
  • + + We use Polar for + payments, which + automatically sends invoices + via email after purchase. +
  • +
  • + + Polar handles + VAT invoices for + businesses in applicable regions. +
  • +
  • + + For VAT invoices, select + "I'm purchasing as a business" + during checkout and enter your billing address and Tax/VAT + number. +
  • +
+
+
+
+
+
+ +
+
+
+
+

+ What each tier + covers +

+

+ Every tier lets you ship Kura inside one closed-source product. + The tiers differ by who you are, how many developers you have, + and whether Kura is passed on to anyone else. +

+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SoloIndieBusinessOEM
Who it's forOne developer, under $100k annual revenueCompanies under $1M annual revenueCompanies at $1M annual revenue or more + Anyone redistributing, reselling or hosting the engine +
Annual price$99$199$499from $1,999
Developers coveredOne developerUnlimitedUnlimitedDiscussed with you
Closed-source products coveredOneOneOneTerms shaped to your product
Updates while active
SupportEmailEmailPriority emailPriority
+ Redistribute inside someone else's product +
Resell as an SDK
Offer Kura as a hosted service
+
+

+ Redistribution, reselling and hosting are what separate OEM from + the rest. If Kura only ships inside your own closed-source + product, the choice between Solo, Indie and Business is purely a + question of your size. +

+
+
+
+ +
+
+
+
+

+ License + Terms +

+
+
+
+
+ +

Per product

+

+ A license covers one shipped product. A second product needs a + second license, or ask about covering your whole catalogue at + OEM. +

+
+
+ +

Updates included

+

+ Every release published while your license is active is yours. + If you let it lapse, you keep a perpetual right to the last + version you received. +

+
+
+ +

No AGPL obligations

+

+ The commercial license replaces the AGPL for your product. You + ship closed source, with no requirement to publish your changes + or your application. +

+
+
+ +

Clean provenance

+

+ Kura is written and owned by BentoPDF, and every third-party + component it links, including qpdf, PDFium and FreeType, is + permissively licensed. No copyleft surprises in your supply + chain. +

+
+
+
+
+ +
+
+
+
+

+ Frequently Asked + Questions +

+
+
+
+
+
+ +
+

+ Only if you ship Kura inside closed-source software. + Open-source projects under an AGPL-compatible license, + self-hosting, and internal use are all free under the + AGPL-3.0. +

+
+
+
+ +
+

+ No. Kura is a separate project with its own license. The + BentoPDF app license does not grant any rights to Kura, and + a Kura license does not cover BentoPDF. +

+
+
+
+ +
+

+ You move up to the matching tier at your next renewal. + Nothing retroactive. Growing past a threshold mid-term never + invalidates your current license. +

+
+
+
+
+
+
+ +
+
+
+

Not sure which tier fits?

+

+ Tell us what you're building and we'll tell you what it costs. No + calls required. +

+ +
+
+
+
+ + {{> footer }} + + + + + + + + diff --git a/licensing.html b/licensing.html index 9027743f..5ce4d2dd 100644 --- a/licensing.html +++ b/licensing.html @@ -49,6 +49,7 @@ + @@ -75,1122 +76,1172 @@ - + {{> navbar }} -
-
-

- Licensing for - BentoPDF -

-

- Choose the license that fits your needs. -

+
+
+
+
+
+

+ Licensing for + BentoPDF +

+

+ Choose the license that fits your needs. +

+
+
+
-
-
- - - LIFETIME LICENSE - +
+
+
+
+ + + LIFETIME LICENSE + - -

- Commercial License -

+ +

+ Commercial License +

- -
+ +
- -
-
-
- -
- Proprietary Use -
-
-
- -
- Unlimited Devices -
-
-
- -
- Enterprise Support -
-
-
- -
- Unlimited Users -
-
-
- -
- Early Access Features -
-
-
- -
- Lifetime Updates -
-
-
- -
- No AGPL Obligations -
-
-
- -
- Flexible Terms -
-
- - -
- - -
-
- $99 - $79 - one-time -
- - Get License Now - - - - - -
-
-
- -
- -
-
- -
-
- -

Open Source

-
-

- BentoPDF is licensed under the - GNU Affero General Public License v3.0 (AGPL-3.0). You are free to use, modify, and distribute BentoPDF in your - open-source projects. -

-
-
- -
-

Free to Use

-

- Use BentoPDF for free in open-source projects where you make - your source code publicly available. -

+ +
+
+
+ +
+ Proprietary Use +
+
+
+ +
+ Unlimited Devices +
+
+
+ +
+ Enterprise Support +
+
+
+ +
+ Unlimited Users +
+
+
+ +
+ Early Access Features +
+
+
+ +
+ Lifetime Updates +
+
+
+ +
+ No AGPL Obligations +
+
+
+ +
+ Flexible Terms
-
- -
-

- Modify & Distribute -

-

- Modify the source code and distribute your version, as long - as you comply with AGPL-3.0 requirements. -

+ + +
+ + +
+
+ $99 + $79 + one-time
-
-
- -
-

Share Alike

-

- Any modifications or derivative works must also be licensed - under AGPL-3.0 and made publicly available. -

-
-
-
- - View on GitHub - -
- - -
-
- -

Commercial

-
-

- If you want to use BentoPDF in a - closed-source or proprietary application - without sharing your source code, you must purchase a commercial - license. - The commercial license covers BentoPDF only and grants no - rights to - Kura - or - Hyper Compress. -

-
-
- -
-

Proprietary Use

-

- Use BentoPDF in closed-source applications without the - obligation to disclose your source code. -

-
-
-
- -
-

- Enterprise Support -

-

- Get priority support, custom features, and assistance with - integration. -

-
-
-
- -
-

- Early Access to New Features -

-

- Commercial license holders get early access to new features - and updates. -

-
-
-
- -
-

Flexible Terms

-

- Licensing terms tailored to your business needs and project - requirements. -

-
-
-
- - - Get Commercial License - - - - - -

- 💡 Custom requests and development are available for separate - charges. - Contact us - for details. -

-
-
-
- -
- -
-

- Do I Need a Commercial License? -

-

- Use this quick reference chart to determine if your use case requires - a commercial license. -

- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Use Case - - License Required -
- Personal use (not hosting as a service) - - - AGPL (Free) - -
- Open-source project with publicly available source code - - - AGPL (Free) - -
- Public website where you share your full modified source code - under AGPL - - - AGPL (Free) - -
- Educational/research project with publicly shared code - - - AGPL (Free) - -
- SaaS or web application (closed-source) - - - - Commercial - -
- Internal company tool/dashboard (source not shared with users) - - - - Commercial - -
- Commercial product (keeping source code private) - - - - Commercial - -
- Network service where source code is not accessible to users - - - - Commercial - -
- Any app where you want to keep modifications private - - - - Commercial - -
-
- -
- - Get Commercial License - $79 - - - - - -

- Still not sure? - Contact us - to discuss your specific use case. -

-
-
- -
- -
-

- AGPL Requirements -

-
-

- When using BentoPDF under AGPL-3.0, you must comply with the - following requirements: -

-
-
- -
-

- Producer Line & Copyright -

-

- You should mention our open-source and include AGPL license - details in the PDF metadata. You should also retain the - producer line in all PDFs created or modified using our - open-source. -

-
-
-
- -
-

- Code Modifications -

-

- Any modifications to our open-source must be disclosed under - the AGPL. This includes sharing the modified code with any - users interacting with it. -

-
-
-
- -
-

- AGPL-Compliant Environments Only -

-

- Usage of our open-source Community Edition must be limited to - AGPL-compliant environments, where all AGPL requirements are - fully respected. -

-
-
-
- -
-

- Source Code Disclosure -

-

- You cannot deploy our open-source as part of a server-based - application or service without disclosing your own - application's full source code under AGPL to any users - interacting with it. -

-
-
-
-
-
- -
- -
-

- What is AGPL-Compliant? -

-
- -
-
- -

AGPL-Compliant

-
-
    -
  • - - Open-source projects where you share your full source code - publicly -
  • -
  • - - Personal use where you're not distributing or hosting it as a - service -
  • -
  • - - Publicly hosted tools where you provide the complete source - code (including modifications) under AGPL -
  • -
  • - - Educational or research projects that make all code publicly - available -
  • -
-
- - -
-
- -

NOT AGPL-Compliant

-
-
    -
  • - - Proprietary/closed-source SaaS applications -
  • -
  • - - Internal company tools where source code is not shared with - users -
  • -
  • - - Commercial products that don't disclose the full source - code -
  • -
  • - - Network services that don't provide source code access to - users -
  • -
  • - - Any application where you want to keep your source code - private -
  • -
-

- ⚠️ These use cases require a commercial license. -

-
-
-
- -
- -
-

- Licensing FAQs -

-
-
- -
-

- If you're using BentoPDF on a public website and have not - modified the source code, you do not need a commercial license. - However, if you modify BentoPDF in any way and make it available - to users over a network, the AGPLv3 requires you to provide your - modified source code to those users. If you want to keep your - modifications closed-source, or if you are integrating BentoPDF - into a proprietary or commercial product, you will need a - commercial license. Contact us to discuss your specific use - case. -

-
-
- -
- -
-

- If your internal tool is closed-source and not shared publicly, - you will need a commercial license. The AGPL-3.0 license - requires that you make the source code of any network-accessible - service using BentoPDF available to its users. If you cannot or - do not want to do that, a commercial license is the right - choice. -

-
-
- -
- -
-

- If you modify BentoPDF and deploy it as a network service (e.g., - a web application), you must make your modified source code - available under AGPL-3.0. If you do not want to share your - modifications, you must obtain a commercial license. -

-
-
- -
- -
-

- BentoPDF is available under a lifetime, one-time purchase - commercial license. You can purchase it directly here: Buy Commercial License.

- If you have specific requirements or want a custom licensing - arrangement, feel free to - contact us - with details about your use case, company size, and deployment - needs. We're happy to work with you to find the best fit. -

-
-
- -
- -
-

- No. The BentoPDF commercial license covers BentoPDF - only. - It grants no rights to - Kura - or - Hyper Compress. Those are separate projects with their own licenses, and any - commercial use of them must be licensed separately. -

+ Get License Now + + + + + +
-
+
+
+
+
+ +
+
+ +

Open Source

+
+

+ BentoPDF is licensed under the + GNU Affero General Public License v3.0 (AGPL-3.0). You are free to use, modify, and distribute BentoPDF in + your open-source projects. +

+
+
+ +
+

Free to Use

+

+ Use BentoPDF for free in open-source projects where you + make your source code publicly available. +

+
+
+
+ +
+

+ Modify & Distribute +

+

+ Modify the source code and distribute your version, as + long as you comply with AGPL-3.0 requirements. +

+
+
+
+ +
+

Share Alike

+

+ Any modifications or derivative works must also be + licensed under AGPL-3.0 and made publicly available. +

+
+
+
+ + View on GitHub + +
-
-

- Commercial License Details -

- -
-
-

- - Delivery & Licensing Model -

- -

- GitHub Repository: + Get Commercial License + + + + + +

+ 💡 Custom requests and development are available for separate + charges. + Contact us + for details. +

+
+
+
+
+
+ +
+
+
+

+ Do I Need a Commercial License? +

+

+ Use this quick reference chart to determine if your use case + requires a commercial license. +

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Use Case + + License Required +
+ Personal use (not hosting as a service) + + + AGPL (Free) + +
+ Open-source project with publicly available source code + + + AGPL (Free) + +
+ Public website where you share your full modified source + code under AGPL + + + AGPL (Free) + +
+ Educational/research project with publicly shared code + + + AGPL (Free) + +
+ SaaS or web application (closed-source) + + + + Commercial + +
+ Internal company tool/dashboard (source not shared with + users) + + + + Commercial + +
+ Commercial product (keeping source code private) + + + + Commercial + +
+ Network service where source code is not accessible to + users + + + + Commercial + +
+ Any app where you want to keep modifications private + + + + Commercial + +
+
+ + - -
-

- - Invoicing -

-
    -
  • - - We use Polar for - payments, which - automatically sends invoices - via email after purchase. -
  • -
  • - - Polar handles - VAT invoices for - businesses in applicable regions. + + + +

    + Still not sure? + Contact us -

  • -
  • - - For VAT invoices, select - "I'm purchasing as a business" - during checkout and enter your billing address and Tax/VAT - number. -
  • -
-
- -
-

- - AGPL Components - Not Bundled -

-

- BentoPDF - does not bundle AGPL-licensed - processing libraries. The following components must be configured - separately via - Advanced Settings if you wish - to use their features: -

-
    -
  • - PyMuPDF (AGPL-3.0) -
  • -
  • - Ghostscript (AGPL-3.0) -
  • -
  • - CoherentPDF / CPDF (AGPL-3.0) -
  • -
-

- To enable features powered by these libraries: -

-
    -
  • - 1. - Navigate to - Advanced Settings in - BentoPDF -
  • -
  • - 2. - Configure the URL for each WASM module you need -
  • -
  • - 3. - You can host your own files, use a - WASM proxy, or use any compatible CDN -
  • -
-

- - The commercial license covers - BentoPDF's own code only. It - does not bypass the AGPL licensing of these components. Users must - comply with the AGPL v3 terms for these components. -

+ to discuss your specific use case. +

+
-
+
+
+
+

+ AGPL Requirements +

+
+

+ When using BentoPDF under AGPL-3.0, you must comply with the + following requirements: +

+
+
+ +
+

+ Producer Line & Copyright +

+

+ You should mention our open-source and include AGPL + license details in the PDF metadata. You should also + retain the producer line in all PDFs created or modified + using our open-source. +

+
+
+
+ +
+

+ Code Modifications +

+

+ Any modifications to our open-source must be disclosed + under the AGPL. This includes sharing the modified code + with any users interacting with it. +

+
+
+
+ +
+

+ AGPL-Compliant Environments Only +

+

+ Usage of our open-source Community Edition must be limited + to AGPL-compliant environments, where all AGPL + requirements are fully respected. +

+
+
+
+ +
+

+ Source Code Disclosure +

+

+ You cannot deploy our open-source as part of a + server-based application or service without disclosing + your own application's full source code under AGPL to any + users interacting with it. +

+
+
+
+
+
+
+
-
-

- Still have questions? -

-

- We're here to help. Reach out to discuss your licensing needs. -

- - Contact Us - +
+
+
+

+ What is AGPL-Compliant? +

+
+ +
+
+ +

AGPL-Compliant

+
+
    +
  • + + Open-source projects where you share your full source + code publicly +
  • +
  • + + Personal use where you're not distributing or hosting it + as a service +
  • +
  • + + Publicly hosted tools where you provide the complete + source code (including modifications) under AGPL +
  • +
  • + + Educational or research projects that make all code + publicly available +
  • +
+
+ + +
+
+ +

+ NOT AGPL-Compliant +

+
+
    +
  • + + Proprietary/closed-source SaaS applications +
  • +
  • + + Internal company tools where source code is not shared + with users +
  • +
  • + + Commercial products that don't disclose the full source + code +
  • +
  • + + Network services that don't provide source code access to + users +
  • +
  • + + Any application where you want to keep your source code + private +
  • +
+

+ ⚠️ These use cases require a commercial license. +

+
+
+
+
+
+ +
+
+
+
+

+ Licensing + FAQs +

+
+
+
+
+
+ +
+

+ If you're using BentoPDF on a public website and have not + modified the source code, you do not need a commercial + license. However, if you modify BentoPDF in any way and make + it available to users over a network, the AGPLv3 requires + you to provide your modified source code to those users. If + you want to keep your modifications closed-source, or if you + are integrating BentoPDF into a proprietary or commercial + product, you will need a commercial license. Contact us to + discuss your specific use case. +

+
+
+ +
+ +
+

+ If your internal tool is closed-source and not shared + publicly, you will need a commercial license. The AGPL-3.0 + license requires that you make the source code of any + network-accessible service using BentoPDF available to its + users. If you cannot or do not want to do that, a commercial + license is the right choice. +

+
+
+ +
+ +
+

+ If you modify BentoPDF and deploy it as a network service + (e.g., a web application), you must make your modified + source code available under AGPL-3.0. If you do not want to + share your modifications, you must obtain a commercial + license. +

+
+
+ +
+ +
+

+ BentoPDF is available under a lifetime, one-time purchase + commercial license. You can purchase it directly here: + Buy Commercial License.

+ If you have specific requirements or want a custom licensing + arrangement, feel free to + contact us + with details about your use case, company size, and + deployment needs. We're happy to work with you to find the + best fit. +

+
+
+ +
+ +
+

+ No. The BentoPDF commercial license covers BentoPDF + only. + It grants no rights to + Kura + or + Hyper Compress. Those are separate projects with their own licenses, and + any commercial use of them must be licensed separately. +

+
+
+
+
+
+
+ +
+
+
+

+ Commercial License Details +

+ +
+
+

+ + Delivery & Licensing Model +

+
    +
  • + + No license key is required or provided. + BentoPDF intentionally does not use license keys to + streamline deployment and reduce operational friction for + users. +
  • +
  • + + Upon purchase, users receive a ZIP archive containing the + complete BentoPDF source code and binaries. +
  • +
  • + + Because BentoPDF is open source, every release and every + update can always be downloaded from our + GitHub releases page. +
  • +
  • + + The source code provided is identical to the code + published in our public open-source repository. +
  • +
  • + + No refunds. Under no + circumstances shall a refund be made after purchase. +
  • +
+

+ GitHub Repository: + github.com/alam00000/bentopdf +

+
+ +
+

+ + Invoicing +

+
    +
  • + + We use Polar for + payments, which + automatically sends invoices + via email after purchase. +
  • +
  • + + Polar handles + VAT invoices for + businesses in applicable regions. +
  • +
  • + + For VAT invoices, select + "I'm purchasing as a business" + during checkout and enter your billing address and Tax/VAT + number. +
  • +
+
+ +
+

+ + AGPL Components - Not Bundled +

+

+ BentoPDF + does not bundle + AGPL-licensed processing libraries. The following components + must be configured separately via + Advanced Settings if you + wish to use their features: +

+
    +
  • + PyMuPDF (AGPL-3.0) +
  • +
  • + Ghostscript (AGPL-3.0) +
  • +
  • + CoherentPDF / CPDF (AGPL-3.0) +
  • +
+

+ To enable features powered by these libraries: +

+
    +
  • + 1. + Navigate to + Advanced Settings in + BentoPDF +
  • +
  • + 2. + Configure the URL for each WASM module you need +
  • +
  • + 3. + You can host your own files, use a + WASM proxy, or use any compatible CDN +
  • +
+

+ + The commercial license covers + BentoPDF's own code only. + It does not bypass the AGPL licensing of these components. + Users must comply with the AGPL v3 terms for these components. +

+
+
+
+
+
+ +
+
+
+

Still have questions?

+

+ We're here to help. Reach out to discuss your licensing needs. +

+ +
+
@@ -1198,6 +1249,7 @@ + + + + + + + diff --git a/blog/edit-pdf-without-uploading.html b/blog/edit-pdf-without-uploading.html new file mode 100644 index 00000000..dd3297dd --- /dev/null +++ b/blog/edit-pdf-without-uploading.html @@ -0,0 +1,472 @@ + + + + + + + How to Edit a PDF Without Uploading It Anywhere | BentoPDF Blog + + + + + + + + + + + + + + + + + + + {{> navbar }} + +
+ + +

+ How to edit a PDF without uploading it anywhere +

+ +
+ Alam +
+ Alam, builds BentoPDF · + +
+
+ +

+ You can edit a PDF in your browser without uploading the file to a + server. +

+

+ Open + BentoPDF's PDF editor, pick your file, make your changes, and download the result. The PDF + stays on your device. There's no account and no watermark. +

+

+ But “edit a PDF” can mean a few different things. You might want to + change existing text, fill out a form, add a signature, redact + something, or just highlight a paragraph. The right tool depends on what + you're trying to do. +

+

+ Why edit a PDF without uploading it? +

+

+ Think about the PDFs you normally edit. +

+

+ Contracts. Bank statements. Tax documents. Forms with your address or ID + number. +

+

+ Those aren't necessarily files you want to upload to a random “free + PDF editor.” +

+

+ With an on-device PDF editor, the file stays on your computer while + you're working on it. +

+

+ You can even check this yourself. Open your browser's developer + tools, go to the Network tab, and watch what happens while you edit. The + PDF itself doesn't need to be sent to a server. +

+

+ How to edit the actual text in a PDF +

+

+ If you want to change words that are already in the PDF, use + Edit PDF Text. +

+
    +
  1. Open the tool.
  2. +
  3. Drop in your PDF.
  4. +
  5. Click on the text you want to change.
  6. +
  7. Type your changes.
  8. +
  9. Download the edited PDF.
  10. +
+

+ BentoPDF loads the PDF in your browser and does the editing on your + device. +

+

+ This is one of the harder things to do with PDFs because PDF text + doesn't work quite like text in a Word document. The PDF is mostly + concerned with putting things at particular positions on a page, so + changing a sentence can mean figuring out how the surrounding text + should move. +

+

+ It works well for ordinary documents, but PDFs with unusual embedded + fonts or very complicated layouts can be trickier. I'd always open + the downloaded PDF and check it. +

+

+ How to annotate a PDF +

+

+ If you don't need to change the existing text, annotating a PDF is + much simpler. +

+

+ The + PDF editor + lets you add highlights, comments, shapes, stamps, text boxes, and + images. +

+

+ Open the PDF, add your annotations, and download the result. +

+

+ Again, the editing happens in your browser rather than on a remote + server. +

+

+ How to fill out a PDF form +

+

+ There are two common kinds of PDF forms. +

+

+ If the PDF has actual form fields, open it in + PDF Form Filler + and type into the fields. It handles standard AcroForm fields, and also + XFA forms, which are the legacy XML-based format. XFA is worth calling + out because Chrome and most other viewers show those files as blank + pages, which is why some government forms tell you to open them in Adobe + Reader. Firefox and BentoPDF's form filler render them properly. +

+

+ If it's a scanned or flattened form, there aren't any fields to + click. In that case, you can put text boxes over the blank spaces in the + PDF editor + and type into them. If you'd rather have real fields, + Create PDF Form + can add them to the document first. +

+

+ This is especially useful for government and HR forms, which often + contain personal information I'd rather not upload somewhere just to + fill in a few boxes. +

+

+ If the PDF is a scan and you actually need to edit the scanned text + itself, you'll need OCR first. + BentoPDF's OCR tool + can recognize the text in the document while keeping the processing on + your device. +

+

+ How to redact a PDF properly +

+

+ This one is important because putting a black box over text isn't + necessarily redaction. +

+

+ If you draw a rectangle over a name, the original name may still exist + underneath it. It might still be selectable, searchable, or extractable. +

+

+ Proper redaction removes the underlying content. +

+

+ The + PDF editor + has redaction tools that permanently remove the underlying content + rather than drawing over it. For documents where you also want to strip + metadata or other hidden content, + Sanitize PDF + can help with that. +

+

+ There's also a privacy reason to do redaction locally: if you upload + the original, unredacted PDF to a redaction service, that service has + already received the information you're trying to hide. +

+

+ How to sign a PDF without uploading it +

+

+ Sign PDF + lets you add a drawn, typed, or image signature to a PDF. Place it on + the page, resize it, and optionally flatten it so it becomes part of the + page instead of an annotation someone can drag away later. +

+

+ The signature is added on your device, so you don't need to upload + the document to a signing service just to place a signature on it. +

+

+ One thing to keep in mind: adding a signature image to a PDF is not the + same thing as applying a cryptographic digital signature. If the + recipient needs a signature that can actually be verified, use + Digital Signature + instead. It signs the document with an X.509 certificate (PKCS#12 .pfx + and .p12, or PEM), which proves who signed it and shows whether anything + changed afterwards. You can also add a visible signature block on top of + that. The certificate password and private key stay in your browser, + same as the PDF. +

+

+ Can you edit a PDF offline? +

+

Yes.

+

+ There's an easy way to test it: load the editor, turn off Wi-Fi, and + edit a PDF. +

+

+ The PDF processing code runs in your browser using WebAssembly. Once the + application has loaded, the actual PDF processing doesn't need a + server. +

+

+ This is also something you can inspect yourself in your browser's + developer tools. The website is how you get the software; it doesn't + have to be where your PDF gets processed. +

+

+ If you want to run the whole thing yourself, BentoPDF is + open source and self-hostable. You can run your own instance instead of relying on ours. +

+

+ What about scanned PDFs? +

+

+ A scanned PDF is basically a collection of images. +

+

+ If you want to change the words in it, an ordinary PDF text editor + can't simply edit them because there isn't any text there yet. +

+

+ You'll need OCR (optical character recognition) to turn the pixels + into text. +

+

+ You can either OCR the PDF first and then edit the resulting text, or, + if you're just filling out a scanned form, put text boxes on top of + the existing page. +

+

+ Is there a file size limit? +

+

+ There isn't an imposed file-size limit. +

+

+ The practical limit is your device's available memory. Normal PDFs + are usually fine, but a thousand-page scanned archive is a very + different workload from a five-page contract. +

+

+ For very large PDFs, a desktop application may be a better choice. +

+

+ Will editing a digitally signed PDF break the signature? +

+

Yes.

+

+ Changing a digitally signed PDF will invalidate its existing signature. + This isn't specific to BentoPDF; it's a consequence of changing + a document that has already been signed. +

+

So the usual order is:

+

+ Edit first. Sign last. +

+

+ If you need to make changes to a signed document, make sure you + understand the signature requirements before doing so. +

+ +
+

Edit your PDF now

+

+ Free, no signup. Your file stays on your device. +

+ Open the PDF editor +
+
+ + {{> footer }} + + + + + + + + + diff --git a/blog/index.html b/blog/index.html new file mode 100644 index 00000000..98d2cd25 --- /dev/null +++ b/blog/index.html @@ -0,0 +1,87 @@ + + + + + + The BentoPDF Blog | Privacy-First PDF Guides + + + + + + + + + + + + + + + + + + {{> navbar }} + +
+

+ The BentoPDF Blog +

+

+ I'm + Alam. I build BentoPDF and write about PDFs, how they work, and the weird + things I run into along the way. +

+
+ +
+ +
+ + {{> footer }} + + + + + + diff --git a/blog/posts/edit-pdf-without-uploading.md b/blog/posts/edit-pdf-without-uploading.md new file mode 100644 index 00000000..8493401a --- /dev/null +++ b/blog/posts/edit-pdf-without-uploading.md @@ -0,0 +1,136 @@ +--- +{ + 'title': 'How to Edit a PDF Without Uploading It Anywhere | BentoPDF Blog', + 'h1': 'How to edit a PDF without uploading it anywhere', + 'ogTitle': 'How to Edit a PDF Without Uploading It Anywhere', + 'breadcrumb': 'Edit a PDF without uploading', + 'description': 'Edit PDF text, fill forms, redact, and sign in your browser while the file stays on your device. Step by step, with the right tool for each job.', + 'card': 'Rewrite text, fill forms, redact properly, and sign, locally on your device.', + 'date': '2026-09-03', + 'cta': + { + 'heading': 'Edit your PDF now', + 'text': 'Free, no signup. Your file stays on your device.', + 'href': '/edit-pdf', + 'label': 'Open the PDF editor', + }, +} +--- + +You can edit a PDF in your browser without uploading the file to a server. + +Open [BentoPDF's PDF editor](/edit-pdf), pick your file, make your changes, and download the result. The PDF stays on your device. There's no account and no watermark. + +But “edit a PDF” can mean a few different things. You might want to change existing text, fill out a form, add a signature, redact something, or just highlight a paragraph. The right tool depends on what you're trying to do. + +## Why edit a PDF without uploading it? + +Think about the PDFs you normally edit. + +Contracts. Bank statements. Tax documents. Forms with your address or ID number. + +Those aren't necessarily files you want to upload to a random “free PDF editor.” + +With an on-device PDF editor, the file stays on your computer while you're working on it. + +You can even check this yourself. Open your browser's developer tools, go to the Network tab, and watch what happens while you edit. The PDF itself doesn't need to be sent to a server. + +## How to edit the actual text in a PDF + +If you want to change words that are already in the PDF, use [Edit PDF Text](/edit-pdf-text). + +1. Open the tool. +2. Drop in your PDF. +3. Click on the text you want to change. +4. Type your changes. +5. Download the edited PDF. + +BentoPDF loads the PDF in your browser and does the editing on your device. + +This is one of the harder things to do with PDFs because PDF text doesn't work quite like text in a Word document. The PDF is mostly concerned with putting things at particular positions on a page, so changing a sentence can mean figuring out how the surrounding text should move. + +It works well for ordinary documents, but PDFs with unusual embedded fonts or very complicated layouts can be trickier. I'd always open the downloaded PDF and check it. + +## How to annotate a PDF + +If you don't need to change the existing text, annotating a PDF is much simpler. + +The [PDF editor](/edit-pdf) lets you add highlights, comments, shapes, stamps, text boxes, and images. + +Open the PDF, add your annotations, and download the result. + +Again, the editing happens in your browser rather than on a remote server. + +## How to fill out a PDF form + +There are two common kinds of PDF forms. + +If the PDF has actual form fields, open it in [PDF Form Filler](/form-filler) and type into the fields. It handles standard AcroForm fields, and also XFA forms, which are the legacy XML-based format. XFA is worth calling out because Chrome and most other viewers show those files as blank pages, which is why some government forms tell you to open them in Adobe Reader. Firefox and BentoPDF's form filler render them properly. + +If it's a scanned or flattened form, there aren't any fields to click. In that case, you can put text boxes over the blank spaces in the [PDF editor](/edit-pdf) and type into them. If you'd rather have real fields, [Create PDF Form](/form-creator) can add them to the document first. + +This is especially useful for government and HR forms, which often contain personal information I'd rather not upload somewhere just to fill in a few boxes. + +If the PDF is a scan and you actually need to edit the scanned text itself, you'll need OCR first. [BentoPDF's OCR tool](/ocr-pdf) can recognize the text in the document while keeping the processing on your device. + +## How to redact a PDF properly + +This one is important because putting a black box over text isn't necessarily redaction. + +If you draw a rectangle over a name, the original name may still exist underneath it. It might still be selectable, searchable, or extractable. + +Proper redaction removes the underlying content. + +The [PDF editor](/edit-pdf) has redaction tools that permanently remove the underlying content rather than drawing over it. For documents where you also want to strip metadata or other hidden content, [Sanitize PDF](/sanitize-pdf) can help with that. + +There's also a privacy reason to do redaction locally: if you upload the original, unredacted PDF to a redaction service, that service has already received the information you're trying to hide. + +## How to sign a PDF without uploading it + +[Sign PDF](/sign-pdf) lets you add a drawn, typed, or image signature to a PDF. Place it on the page, resize it, and optionally flatten it so it becomes part of the page instead of an annotation someone can drag away later. + +The signature is added on your device, so you don't need to upload the document to a signing service just to place a signature on it. + +One thing to keep in mind: adding a signature image to a PDF is not the same thing as applying a cryptographic digital signature. If the recipient needs a signature that can actually be verified, use [Digital Signature](/digital-sign-pdf) instead. It signs the document with an X.509 certificate (PKCS#12 .pfx and .p12, or PEM), which proves who signed it and shows whether anything changed afterwards. You can also add a visible signature block on top of that. The certificate password and private key stay in your browser, same as the PDF. + +## Can you edit a PDF offline? + +Yes. + +There's an easy way to test it: load the editor, turn off Wi-Fi, and edit a PDF. + +The PDF processing code runs in your browser using WebAssembly. Once the application has loaded, the actual PDF processing doesn't need a server. + +This is also something you can inspect yourself in your browser's developer tools. The website is how you get the software; it doesn't have to be where your PDF gets processed. + +If you want to run the whole thing yourself, BentoPDF is [open source and self-hostable](https://github.com/alam00000/bentopdf). You can run your own instance instead of relying on ours. + +## What about scanned PDFs? + +A scanned PDF is basically a collection of images. + +If you want to change the words in it, an ordinary PDF text editor can't simply edit them because there isn't any text there yet. + +You'll need OCR (optical character recognition) to turn the pixels into text. + +You can either OCR the PDF first and then edit the resulting text, or, if you're just filling out a scanned form, put text boxes on top of the existing page. + +## Is there a file size limit? + +There isn't an imposed file-size limit. + +The practical limit is your device's available memory. Normal PDFs are usually fine, but a thousand-page scanned archive is a very different workload from a five-page contract. + +For very large PDFs, a desktop application may be a better choice. + +## Will editing a digitally signed PDF break the signature? + +Yes. + +Changing a digitally signed PDF will invalidate its existing signature. This isn't specific to BentoPDF; it's a consequence of changing a document that has already been signed. + +So the usual order is: + +**Edit first. Sign last.** + +If you need to make changes to a signed document, make sure you understand the signature requirements before doing so. diff --git a/docs/.vitepress/config.mts b/docs/.vitepress/config.mts index f7ec0fa6..c4591fa8 100644 --- a/docs/.vitepress/config.mts +++ b/docs/.vitepress/config.mts @@ -115,7 +115,7 @@ export default defineConfig({ { text: 'PDF to Excel', link: '/tools/pdf-to-excel' }, { text: 'PDF to Greyscale', link: '/tools/pdf-to-greyscale' }, { text: 'PDF to JSON', link: '/tools/pdf-to-json' }, - { text: 'PDF to Word', link: '/tools/pdf-to-docx' }, + { text: 'PDF to Word', link: '/tools/pdf-to-word' }, { text: 'Extract Images', link: '/tools/extract-images' }, { text: 'PDF to Markdown', link: '/tools/pdf-to-markdown' }, { text: 'Prepare PDF for AI', link: '/tools/prepare-pdf-for-ai' }, @@ -176,9 +176,9 @@ export default defineConfig({ text: 'Secure PDF', collapsed: true, items: [ - { text: 'Encrypt PDF', link: '/tools/encrypt-pdf' }, + { text: 'Protect PDF', link: '/tools/protect-pdf' }, { text: 'Sanitize PDF', link: '/tools/sanitize-pdf' }, - { text: 'Decrypt PDF', link: '/tools/decrypt-pdf' }, + { text: 'Unlock PDF', link: '/tools/unlock-pdf' }, { text: 'Flatten PDF', link: '/tools/flatten-pdf' }, { text: 'Remove Metadata', link: '/tools/remove-metadata' }, { text: 'Change Permissions', link: '/tools/change-permissions' }, diff --git a/docs/tools/change-permissions.md b/docs/tools/change-permissions.md index 46608ed8..e237f97c 100644 --- a/docs/tools/change-permissions.md +++ b/docs/tools/change-permissions.md @@ -56,6 +56,6 @@ If you set only an owner password (no user password), anyone can open the file b ## Related Tools -- [Encrypt PDF](./encrypt-pdf) -- simple password protection without granular permissions -- [Decrypt PDF](./decrypt-pdf) -- remove encryption entirely +- [Encrypt PDF](./protect-pdf) -- simple password protection without granular permissions +- [Decrypt PDF](./unlock-pdf) -- remove encryption entirely - [Remove Restrictions](./remove-restrictions) -- strip all restrictions when you have the owner password diff --git a/docs/tools/digital-sign-pdf.md b/docs/tools/digital-sign-pdf.md index bc6797fa..7b42f87f 100644 --- a/docs/tools/digital-sign-pdf.md +++ b/docs/tools/digital-sign-pdf.md @@ -61,5 +61,5 @@ Signing may require an internet connection. The signing library fetches the cert - [Validate Signature](./validate-signature-pdf) -- verify digital signatures in signed PDFs - [Flatten PDF](./flatten-pdf) -- flatten forms before signing to prevent modifications -- [Encrypt PDF](./encrypt-pdf) -- add password protection on top of the digital signature +- [Encrypt PDF](./protect-pdf) -- add password protection on top of the digital signature - [Remove Metadata](./remove-metadata) -- strip metadata before signing diff --git a/docs/tools/flatten-pdf.md b/docs/tools/flatten-pdf.md index b361a324..82e3a437 100644 --- a/docs/tools/flatten-pdf.md +++ b/docs/tools/flatten-pdf.md @@ -48,4 +48,4 @@ The tool uses pdf-lib to flatten form fields (via `form.flatten()`) and a dedica - [Sanitize PDF](./sanitize-pdf) -- flatten forms plus remove metadata, scripts, and more - [Rasterize PDF](./rasterize-pdf) -- convert to image-based PDF for maximum flattening - [Font to Outline](./font-to-outline) -- flatten fonts to vector paths -- [Encrypt PDF](./encrypt-pdf) -- lock the flattened PDF with a password +- [Encrypt PDF](./protect-pdf) -- lock the flattened PDF with a password diff --git a/docs/tools/index.md b/docs/tools/index.md index 08b4053a..a55fdbbe 100644 --- a/docs/tools/index.md +++ b/docs/tools/index.md @@ -95,7 +95,7 @@ Extract content from PDFs into images, documents, and data formats. - [**PDF to Excel**](./pdf-to-excel) — Extract tables from PDF and convert to Excel (XLSX). - [**PDF to Greyscale**](./pdf-to-greyscale) — Convert all colors to black and white. - [**PDF to JSON**](./pdf-to-json) — Convert PDF files to JSON format. -- [**PDF to Word**](./pdf-to-docx) — Convert PDF files to editable Word documents. +- [**PDF to Word**](./pdf-to-word) — Convert PDF files to editable Word documents. - [**Extract Images**](./extract-images) — Extract all embedded images from your PDF files. - [**PDF to Markdown**](./pdf-to-markdown) — Convert PDF text and tables to Markdown format. - [**Prepare PDF for AI**](./prepare-pdf-for-ai) — Extract PDF content as LlamaIndex JSON for RAG/LLM pipelines. @@ -171,9 +171,9 @@ Protect, encrypt, and control access to your PDF documents.
-- [**Encrypt PDF**](./encrypt-pdf) — Lock your PDF by adding a password. +- [**Encrypt PDF**](./protect-pdf) — Lock your PDF by adding a password. - [**Sanitize PDF**](./sanitize-pdf) — Remove metadata, annotations, scripts, and more. -- [**Decrypt PDF**](./decrypt-pdf) — Unlock PDF by removing password protection. +- [**Decrypt PDF**](./unlock-pdf) — Unlock PDF by removing password protection. - [**Flatten PDF**](./flatten-pdf) — Make form fields and annotations non-editable. - [**Remove Metadata**](./remove-metadata) — Strip hidden data from your PDF. - [**Change Permissions**](./change-permissions) — Set or change user permissions on a PDF. diff --git a/docs/tools/pdf-to-markdown.md b/docs/tools/pdf-to-markdown.md index dd180d3c..54552b98 100644 --- a/docs/tools/pdf-to-markdown.md +++ b/docs/tools/pdf-to-markdown.md @@ -39,5 +39,5 @@ Converts PDF files to Markdown (`.md`) format, preserving headings, paragraphs, ## Related Tools - [PDF to Text](./pdf-to-text) -- [PDF to Word](./pdf-to-docx) +- [PDF to Word](./pdf-to-word) - [Prepare PDF for AI](./prepare-pdf-for-ai) diff --git a/docs/tools/pdf-to-text.md b/docs/tools/pdf-to-text.md index e95c6123..acea1c83 100644 --- a/docs/tools/pdf-to-text.md +++ b/docs/tools/pdf-to-text.md @@ -40,4 +40,4 @@ This tool has no configurable options. All text content is extracted from every - [PDF to Markdown](./pdf-to-markdown) - [Prepare PDF for AI](./prepare-pdf-for-ai) -- [PDF to Word](./pdf-to-docx) +- [PDF to Word](./pdf-to-word) diff --git a/docs/tools/pdf-to-docx.md b/docs/tools/pdf-to-word.md similarity index 100% rename from docs/tools/pdf-to-docx.md rename to docs/tools/pdf-to-word.md diff --git a/docs/tools/encrypt-pdf.md b/docs/tools/protect-pdf.md similarity index 97% rename from docs/tools/encrypt-pdf.md rename to docs/tools/protect-pdf.md index 8b402da3..62e781ac 100644 --- a/docs/tools/encrypt-pdf.md +++ b/docs/tools/protect-pdf.md @@ -58,7 +58,7 @@ AES-256 is computationally infeasible to brute-force with current technology. Th ## Related Tools -- [Decrypt PDF](./decrypt-pdf) -- remove encryption when you know the password +- [Decrypt PDF](./unlock-pdf) -- remove encryption when you know the password - [Change Permissions](./change-permissions) -- modify specific usage restrictions - [Remove Restrictions](./remove-restrictions) -- strip all security from a PDF - [Sanitize PDF](./sanitize-pdf) -- remove hidden content before encrypting diff --git a/docs/tools/remove-metadata.md b/docs/tools/remove-metadata.md index e27adbf4..3918c725 100644 --- a/docs/tools/remove-metadata.md +++ b/docs/tools/remove-metadata.md @@ -46,5 +46,5 @@ No options to configure. The tool is thorough by design: it clears everything. ## Related Tools - [Sanitize PDF](./sanitize-pdf) -- remove metadata plus scripts, attachments, and more -- [Encrypt PDF](./encrypt-pdf) -- protect the cleaned PDF with a password +- [Encrypt PDF](./protect-pdf) -- protect the cleaned PDF with a password - [Compress PDF](./compress-pdf) -- removing metadata can slightly reduce file size; compress for more savings diff --git a/docs/tools/remove-restrictions.md b/docs/tools/remove-restrictions.md index 8f41f4f0..180a5ca8 100644 --- a/docs/tools/remove-restrictions.md +++ b/docs/tools/remove-restrictions.md @@ -40,6 +40,6 @@ The tool uses QPDF's `--decrypt` and `--remove-restrictions` flags to produce a ## Related Tools -- [Decrypt PDF](./decrypt-pdf) -- unlock a PDF when you know the user password -- [Encrypt PDF](./encrypt-pdf) -- re-apply encryption with new settings +- [Decrypt PDF](./unlock-pdf) -- unlock a PDF when you know the user password +- [Encrypt PDF](./protect-pdf) -- re-apply encryption with new settings - [Change Permissions](./change-permissions) -- selectively modify which actions are allowed diff --git a/docs/tools/sanitize-pdf.md b/docs/tools/sanitize-pdf.md index 327f4fb3..916d41ee 100644 --- a/docs/tools/sanitize-pdf.md +++ b/docs/tools/sanitize-pdf.md @@ -49,5 +49,5 @@ All options are enabled by default. Uncheck any you want to preserve. - [Remove Metadata](./remove-metadata) -- strip only metadata without touching other content - [Flatten PDF](./flatten-pdf) -- flatten forms and annotations specifically -- [Encrypt PDF](./encrypt-pdf) -- add password protection after sanitizing +- [Encrypt PDF](./protect-pdf) -- add password protection after sanitizing - [Rasterize PDF](./rasterize-pdf) -- the nuclear option: convert to images to eliminate all hidden content diff --git a/docs/tools/decrypt-pdf.md b/docs/tools/unlock-pdf.md similarity index 97% rename from docs/tools/decrypt-pdf.md rename to docs/tools/unlock-pdf.md index f21965a0..e329b8a1 100644 --- a/docs/tools/decrypt-pdf.md +++ b/docs/tools/unlock-pdf.md @@ -41,6 +41,6 @@ If you have the password to an encrypted PDF, this tool removes the encryption e ## Related Tools -- [Encrypt PDF](./encrypt-pdf) -- re-apply encryption with a new password +- [Encrypt PDF](./protect-pdf) -- re-apply encryption with a new password - [Remove Restrictions](./remove-restrictions) -- remove usage restrictions without full decryption - [Change Permissions](./change-permissions) -- modify specific permissions on an encrypted PDF diff --git a/index.html b/index.html index cf11a2e2..6adb458a 100644 --- a/index.html +++ b/index.html @@ -12,7 +12,7 @@ />
+ > + {{> tool-links-static }} +
JSON to PDF

Data to PDF

- + @@ -425,48 +425,144 @@
- Are these pdf converter tools really free? - - -

- Yes! All BentoPDF pdf converter tools are 100% free with no hidden - fees, no premium tiers, and no subscription required. Use - unlimited tools, unlimited times. -

-
- -
- - Are my files private and secure? + Which file formats can I convert to PDF?

- Absolutely! All processing happens entirely in your browser. Your - files never leave your device, are never uploaded to servers. - Complete privacy guaranteed. + Word, Excel, and PowerPoint files (including the older DOC, XLS, + and PPT formats), OpenDocument text, spreadsheets, presentations, + and drawings, RTF, plain text, Markdown, CSV, XML, ebooks in EPUB, + MOBI, FB2, and CBZ, XPS, Publisher, Visio, WordPerfect, Microsoft + Works, Apple Pages, and images in JPG, PNG, HEIC, WebP, TIFF, BMP, + SVG, and PSD. If you have a folder of mixed image types, + Images to PDF + accepts them all in one batch and puts each image on its own page.

-
- Is there a file size limit? + What can I convert a PDF into?

- No file size limits! Process files of any size. Browser-based - processing means no artificial limitations. + Word (DOCX), Excel (XLSX), CSV, plain text, Markdown, SVG, and + page images in JPG, PNG, WebP, TIFF, or BMP, with multi-page PDFs + delivered as a ZIP holding one image per page. For long-term + archiving, + PDF to PDF/A + outputs PDF/A-1b, 2b, or 3b, and a separate tool turns a color PDF + into a grayscale one.

-
- Do I need to install software? + Does PDF to Word keep the layout?

- No installation required! All tools are web-based and work - directly in your browser. Just open the page and start using - - works on any device. + PDF to Word + rebuilds the document with its text, basic formatting, and general + layout, and it can convert a batch of files in one run. Pages with + multiple columns, embedded forms, or heavy graphics may not come + across perfectly, so expect to tidy those up in your word + processor. +

+
+
+ + Why is my converted Word or text file empty? + + +

+ The PDF is almost certainly a scan, which stores each page as a + picture with no text layer, so PDF to Word, PDF to Text, and the + table converters have nothing to pull out. Run the file through + OCR PDF + first to add a searchable text layer, then convert the result. +

+
+
+ + Can I get tables out of a PDF into Excel? + + +

+ PDF to Excel + scans every page for tables and writes each one to its own + worksheet, named after the page it came from. If it reports that + no tables were found, the PDF lays the data out as loose text + rather than a real table structure; PDF to CSV and Extract Tables + rely on the same detection, so try PDF to Text to grab the raw + content instead. +

+
+
+ + Do I need Microsoft Office installed to convert Word, Excel, or + PowerPoint files? + + +

+ No. Those files, along with Publisher, Visio, RTF, and + WordPerfect, are converted by a LibreOffice engine that runs + inside your browser, so there's nothing to install; + Word to PDF, for example, also takes DOC, ODT, and RTF directly. The engine + downloads once per session, which makes the first conversion take + a few seconds longer than the ones after it. +

+
+
+ + Will converting a PDF to JPG or PNG lose quality? + + +

+ Pages are rendered at twice their native size, so a letter-size + page becomes an image of roughly 1,224 by 1,584 pixels. + PDF to JPG + is lossy with a quality slider that defaults to 90%, which keeps a + good balance between sharpness and file size; PDF to PNG and PDF + to TIFF are lossless, and PNG adds a scale control from 1x to 3x + for print-quality output. +

+
+
+ + Are my files uploaded to a server during conversion? + + +

+ No. Every converter on this page, including the Office, ebook, and + image converters, runs as WebAssembly inside your browser tab, so + the file is read from your device and the result is written + straight back to it. There's no upload queue, no server copy, and + nothing to delete afterward.

diff --git a/pdf-editor.html b/pdf-editor.html index 066b3a57..ee52abf2 100644 --- a/pdf-editor.html +++ b/pdf-editor.html @@ -5,7 +5,7 @@ - PDF Editor - Free Online PDF Editor Tools | BentoPDF + PDF Editing Tools - All Free Online PDF Editors | BentoPDF - +
- Are these pdf editor tools really free? - - -

- Yes! All BentoPDF pdf editor tools are 100% free with no hidden - fees, no premium tiers, and no subscription required. Use - unlimited tools, unlimited times. -

-
- -
- - Are my files private and secure? + Can I change the existing text in a PDF?

- Absolutely! All processing happens entirely in your browser. Your - files never leave your device, are never uploaded to servers. - Complete privacy guaranteed. + Edit PDF Text + lets you click any paragraph and rewrite it in place, with the + surrounding text reflowing as you type and controls for fonts and + styling. For adding new text boxes, comments, highlights, shapes, + or images on top of the page, use the general Edit PDF tool + instead.

-
- Is there a file size limit? + What can I do in the Edit PDF tool?

- No file size limits! Process files of any size. Browser-based - processing means no artificial limitations. + The + Edit PDF + toolbar covers highlighting, underlining, strikethrough, freehand + drawing, text and comments, shapes and images, permanent + redaction, and full-text search. It keeps the original PDF + structure, so fonts, layouts, and form fields stay intact, and you + can keep up to 10 documents open in tabs and switch between them.

-
- Do I need to install software? + How do I make a PDF smaller?

- No installation required! All tools are web-based and work - directly in your browser. Just open the page and start using - - works on any device. + Compress PDF + offers two methods. Condense strips unused structure, downsamples + images to a target DPI, and subsets fonts while keeping text + selectable and links working; Photon re-renders each page as a + JPEG, which saves more on scans and photo-heavy files but leaves + text unselectable. Start with the Balanced level and only step up + to Aggressive or Extreme if the file is still too large. +

+
+
+ + Which editing tools keep my text selectable? + + +

+ Page-level tools such as Rotate, Organize, Delete Pages, + Background Color, and Remove Annotations work on the PDF structure + and leave text searchable. Invert Colors, Change Text Color, and + PDF to Greyscale re-render every page as an image, so text in + their output can no longer be selected or searched, and the Photon + compression mode does the same. If you need searchable text after + one of those, run the result through + OCR PDF. +

+
+
+ + Can I add page numbers or a header and footer? + + +

+ Page Numbers + puts a number in any of six positions on every page, in plain or + "page X of Y" style, with your choice of font size and color. + Header and Footer adds text to six slots per page (left, center, + and right at top and bottom), understands {page} and {total} + placeholders so a footer like "Page {page} of {total}" fills in + correctly on each page, and can be limited to a page range. +

+
+
+ + Can I put a watermark on every page? + + +

+ Add Watermark + stamps text or an image onto your pages, and you position it by + dragging on a live preview, then set opacity, rotation, and size. + A tiled mode repeats the mark across the whole page so it's much + harder to crop out, and you can apply one watermark to all pages, + restrict it to a page range, or set a different watermark on each + page. +

+
+
+ + Can I rotate a single page, or fix a slightly tilted scan? + + +

+ Rotate PDF + shows a thumbnail of every page with its own left and right + buttons for 90-degree turns, plus a bulk control for the whole + document. For a scan that's off by a few degrees, Rotate by Custom + Degrees accepts any angle, per page or for all pages at once. +

+
+
+ + Does editing a PDF here upload it anywhere? + + +

+ No. The editor and every other tool on this page run as + WebAssembly inside your browser, so the file is opened, changed, + and saved on your own device without a server in between. Nothing + is stored, so there's no copy to delete when you're done.

diff --git a/pdf-merge-split.html b/pdf-merge-split.html index ff1a75ac..c1ef1161 100644 --- a/pdf-merge-split.html +++ b/pdf-merge-split.html @@ -254,48 +254,142 @@
- Are these pdf merge & split tools really free? - - -

- Yes! All BentoPDF pdf merge & split tools are 100% free with no - hidden fees, no premium tiers, and no subscription required. Use - unlimited tools, unlimited times. -

-
- -
- - Are my files private and secure? + How do I combine several PDFs into one file?

- Absolutely! All processing happens entirely in your browser. Your - files never leave your device, are never uploaded to servers. - Complete privacy guaranteed. + Add two or more files to + Merge PDF + and drag them into the order you want. File Mode joins whole + documents, with an optional page range per file such as 1-3, 5, + while Page Mode lays out every page as a thumbnail so you can + build the exact sequence. There's no cap on file count or total + pages, and pages are copied without re-encoding, so quality + doesn't change.

-
- Is there a file size limit? + What are the different ways to split a PDF?

- No file size limits! Process files of any size. Browser-based - processing means no artificial limitations. + Split PDF + has six modes: page ranges, visual selection from thumbnails, even + or odd pages only, one file per page, splitting at bookmark + boundaries with a choice of bookmark level, and fixed chunks of + every N pages. A single range downloads as one PDF, while multiple + ranges or per-page output arrive as a ZIP. Bookmark mode needs a + PDF that actually contains bookmarks.

-
- Do I need to install software? + What's the difference between Split, Extract Pages, and Delete + Pages?

- No installation required! All tools are web-based and work - directly in your browser. Just open the page and start using - - works on any device. + Extract Pages + keeps only the pages you list and saves them as a new file, Delete + Pages removes the pages you list and keeps everything else, and + Split breaks one document into several files. Extract and Delete + are inverses of each other, so pick whichever needs the shorter + list of page numbers. +

+
+
+ + Can I reorder pages or duplicate a page? + + +

+ Organize PDF + shows every page as a draggable thumbnail with a duplicate and a + delete button on each one. You can also type a complete page order + such as 3, 1, 2, 4 to rearrange everything in one step, and + Reverse Pages flips an entire document, or a batch of them, in one + click. +

+
+
+ + My scanner put all the front pages first and all the backs after. + How do I fix the order? + + +

+ Duplex Collate + handles exactly that: it interleaves the two blocks into front 1, + back 1, front 2, back 2 order, with an option to reverse the back + block for stacks that were flipped before the second pass. If the + fronts and backs are in two separate files, Alternate Merge + interleaves pages from multiple PDFs the same way. +

+
+
+ + How do I print a PDF as a folded booklet? + + +

+ PDF Booklet + reorders the pages into saddle-stitch imposition and shows a + preview of each sheet before you download. Print the result + double-sided with "flip on short edge", fold the stack in half, + and staple at the spine; if the page count isn't a multiple of + four, blank pages are added automatically to fill the last sheet. +

+
+
+ + Can I see what changed between two versions of a PDF? + + +

+ Compare PDFs + pairs up the pages of two documents and highlights differences in + text, images, annotations, headers and footers, and formatting, in + either a side-by-side or an overlay view. Filters let you hide the + change types you don't care about, OCR can be switched on for + scanned documents, and the comparison can be exported as a PDF + report. +

+
+
+ + Are my files uploaded when I merge or split them? + + +

+ No. Merging, splitting, and reordering run as WebAssembly inside + your browser, so the files are read from your disk and the result + is written back to it without passing through a server. That holds + for large scans and multi-file batches too.

diff --git a/pdf-security.html b/pdf-security.html index 434c7cb2..2f92c51e 100644 --- a/pdf-security.html +++ b/pdf-security.html @@ -111,12 +111,12 @@
- +

Encrypt PDF

Add password

- +

Decrypt PDF

Remove password

@@ -229,48 +229,148 @@
- Are these PDF security tools really free? - - -

- Yes! All BentoPDF PDF security tools are 100% free with no hidden - fees, no premium tiers, and no subscription required. Use - unlimited tools, unlimited times. -

-
- -
- - Are my files private and secure? + What's the difference between protecting a PDF with a password and + restricting its permissions?

- Absolutely! All processing happens entirely in your browser. Your - files never leave your device and are never uploaded to servers. - Complete privacy is guaranteed. + A user password, set with + Protect PDF, is required to open the file at all. Permissions are flags + stored inside the encryption that control what a reader can do + after opening, such as printing, copying, editing, annotating, or + filling forms, and they only take effect when an owner password is + set. Change Permissions lets you allow or deny each action + individually, while Protect PDF applies the strictest set as soon + as you add an owner password.

-
- Is there a file size limit? + How strong is the password protection?

- No file size limits! Process files of any size. Browser-based - processing means no artificial limitations. + Protect PDF and Change Permissions use 256-bit AES encryption, the + PDF 2.0 standard, applied by QPDF running in your browser. The + encryption itself isn't practical to brute-force, so the weak + point is the password: use a long passphrase and send it through a + different channel than the file. Permission flags are a separate + matter, since they rely on the reader honoring them and some + third-party tools ignore them.

-
- Do I need to install software? + Can I remove a password from a PDF if I don't know it?

- No installation required! All tools are web-based and work - directly in your browser. Just open the page and start using - - works on any device. + No. + Unlock PDF + needs the password and then saves a copy with no encryption or + restrictions left, and none of the tools crack or brute-force + passwords. For a file that opens fine but blocks printing or + copying, use Remove Restrictions instead, which asks for the owner + password if the file has one. +

+
+
+ + What's the difference between Sign PDF and a digital signature? + + +

+ Sign PDF places a drawn, typed, or uploaded signature image on the + page, with an option to flatten it so nobody can move or delete it + later. + Digital Signature + applies a cryptographic signature with your own X.509 certificate + (.pfx, .p12, or .pem), which proves who signed and that the file + hasn't changed since, and Validate Signature checks signatures + already in a file. Certificate signing may need an internet + connection to fetch the certificate chain, and self-signed + certificates will show warnings in Adobe Reader. +

+
+
+ + How do I redact text so it's actually gone? + + +

+ Use the redaction tool in the + PDF Editor, which permanently removes the marked content from the page + instead of just covering it with a box. Redaction only deals with + what's on the page, so if the file's properties, comments, or + attachments could reveal the same information, run Remove Metadata + or Sanitize PDF on the result as well. +

+
+
+ + What's the difference between Remove Metadata and Sanitize PDF? + + +

+ Remove Metadata + strips only the document properties: title, author, dates, + producer, XMP data, document IDs, and application-specific data, + and it leaves pages, forms, links, and bookmarks untouched. + Sanitize PDF goes further and can also flatten forms and delete + annotations, embedded JavaScript, attachments, layers, links, and + structure tags, with each item selectable. Both are irreversible, + so keep your original file. +

+
+
+ + What does flattening a PDF do, and when should I use it? + + +

+ Flatten PDF + burns form fields and annotations (comments, highlights, stamps, + sticky notes, signature fields) into the page content, so they + look the same but can no longer be edited, moved, or removed. Use + it after a form is filled in or a signature is placed and before + you send the file, because there's no way to unflatten. Text stays + selectable and searchable, and bookmarks are kept. +

+
+
+ + Are my passwords, certificates, or files sent to a server? + + +

+ No. Encrypting, unlocking, sanitizing, and signing all run as + WebAssembly in your browser, so the document, the password you + type, and your certificate's private key stay on your device. The + one network exception is Digital Signature, which may contact your + certificate authority's servers to fetch the certificate chain; + the document itself is still never sent.

diff --git a/public/images/author-alam.jpg b/public/images/author-alam.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2aebe4fc26d41ec45d901948359342c5387942ad GIT binary patch literal 7663 zcmbW6cQ72#+wYeZtBV>$x1x8VExU*oExPEkdhfjxLi83ykmv*%^X&J%1Y>dp@EVQ)jq8!}(0>Z+=3~b_3VuBD}Az?ubTwGiNd;%&$ zLMlNfS|-8&XFYZTNN@lHfB_%|GXRqW14x4L*n{y60Kj;H@m~V`Z((2pv7TUqaB%VP zp8_y3fIv(v;FBjp?B`# zxOkM$sHkaJU$C)ra0-jO6crPfkb5Psps1w$T3bg~Pv79JA>7i++Q!z--ow+&+sD_> zKO*vdRP=|K*p$??^o&oLS=rwT3X6(MO3TV?f7aFiYG`a~{@vZv+t)uZIE0v*o|&DS zUszn<*xcIQ+1=YeK%Sjnpf0bjZ*DOF!2ibixBoZL|G`7@j|USA3y1~!4-W>W&%XsE z!Fs|ZfK4i+39@h_V-^gk`j}k1r&WijG(ti>C-vNdHe-Zr; z(Eso}E&>RE82=ImBmqDHdr{sO#+d_c7n-E4Uwtf!X^z;~~vXPg7Iye`ya1Nk^pm8#)i)$1iD zFxy|wglv?ViQqs*Fxhla6fY(d(iAo^i?{_4Vd*e@cCk$nXm)$}H+NCb!hw9;f>dCU z{+EQ?Z0RS8f@EXt7#3+5h$5jG5$qC!`OAE)47K4mEOaxTi%P>u#RW#x4ME*7LOrlo z5o59*>2D8&kRF*zlgnB@L5@XJg{ENXPUXuOPqWCf%~RALcp@T{GfIz+Gp8bkt1!A- zpVqo41b3ug7-N)!RUpWeBBS5gJFo z{_+S2ovYxB3=L_7ayI5tE=(%^vsD)fyZP`{%?OQ;xAbfIq7oU{@5_gLt(5LsAJ~EY z>!%~T5qU$E)$fg~wM}btX}k6~y-p7{OZH*(5)km8rcvd8S4zI9wlE{=pAJ)h1Vjc& zJpuTErSa3&$n9JHnUWNb06m9!ZMFCS;-QLBx8lXD!2M)BTHNQgIW{hHRAN`ueewXm zSJHq~@4#wA9n-0pDS@0wN!7h#-H*89JX^X|X3B%DVT5feFuT5FeBscoHqqGQMt_D#LG&ES3eS-P; zTZ5||zb%kQSc#lC-Ch@ALHFK_5m73hkH@g^hR7Alne2J3f33K!kGGS?1JI#-lek{O z(+Yc-)boz>Dx4R9J-rdQ)Kn+oyOLL~^Pj4%!=Rr*@7GWXZ>Y7{9a zNoxB5VFcn*W&Cz;+c-WihH@Tem)mCZ%;v8N#Nf(9d*;{lqa0}3CL4@=(zBvWqp zy7wc&bNPV^(^>&`7c+q>PYH$(aIhG5jaLfR8iMfXluRfy-fVv(2`sC_lyOA$1$dEn zu2;(qyB3I_O}`@dPw2=Rym#}1&)YXhRjJ(^PJE#Uj`JS(KfD*W zqpN$TlBHwePZoyD$W;!m#i>1tOA)J9N=Dc=B;cVK%+MX@)%bG|H9OuC zinhWV->!K@`OQ=mOW2;!0ax{8pyidQ1jPrdbKYb`VB&G3W@4FE2p-I*SRVV6e|B6x zWasmaY*Bg5Qk37N2+33e`$mD0(forU*oU{ zH<1H=YuFp-c)*p8=*bkC0>P?oI9UvQHA2dl$tDAFl@KpkQqkEO<`6#J3QVE#lEfO6!Q4bE3A@rtd<~#^e z+ODmZy2x;Wga`)H`}4W%<92RezmlJcMv-)rVdR~pf`Z<8J5WxfBFG1vZEi@`Xnw@m z7o^B-uRqP^$)2$0^Ue>tuA?hTBr(;0+-ER>^`kEip)|*goglcM&NkvKZ7M-_Xm}}c z)LUGJH9HW9iXM({FfX9pZqKiQ8vb6w#-+YQm3?)7R1hYS%hVsgEs*bCtt%QpH0?5mH5RZ zw!sKF?Yex6sZ(bYrJh~C2QcaJXg!hiEA8#^yPKZ!p>lN2$Caf;q?I29(L4eu_*eVH zM*#*4%0G0qOBEBoeSY}LP?`_2r%W>2KVKMYinV0#o}U|DJkH`xt}tF0X)$Hv43aKb zY)=T1&on196+((?{%S>HzDn)`heOmjA9mmq4Ebo^BUK`5t3Ugi1HGZBGM}CTE?jT= z%KmN5I`>wEwXX|}n9E_}oezWnJTYLqZC`h|A`A2P{adfuGEe6EL=QN(242K;_GBZ% zqUK$~t6JdT(e)c_O2PJvfY?7_EX!BV=rb$-1U*x2{+V^mOp+8?(dV6Wd3gw&T$?Zc=~vKdyX5)y8RMO$XR*xMcg~=1*M14EHNUe4Z*xL80XysNqULM4_1qpf zc`O-Ml_%uBvKmB&GM>DzCSR|-#d5NAv_aC+Y&W>U=;*UH+B{T~)e=gCxgL5g8qhb8 zV6S~N{dM8bo+O9Z8jT$M4+?PUzZh!|Vz>G+-4TQLqqcuq8RO?WPo~H*E?nB#c1;r0$h=namF%{eudDOUJhiZ$q95DQrgu1M& z!bSNPgp4dLO)8QcRbVlti5ijf%VHH%NP#z4vbLWsPusL>)1lZ5cSYDZN!wc@tWiHs z%@x6+r69E*I?rnSVHHDp%xxw2JLRUiIoz6hdFsHvnw(x;8GJVZs=kJ+M@_B&6;db| zYqCzU?iU{)f}Z3ATQ@Gl(b80RbNSca%j>6xZ(qwvd{g}{L7pOFg)TU)A~u4tIcfo! zF#{)!F3Uu=M~fl>Kb1CF?$KUjJ@bLL`nqd(b|O5+28Dz8D;S_`jZvDPfbEdQKP~hZ zoyYe=Yw1YVNQuPDFdA1!1&g?-w1{v8WG5&g8Zz6_!<6s)tjk3t_lu*5O7)T822CE50CCY>*;(O_}#zV>7Can6*8zNP%*8MO2c-*y&ZDTMD+u_WnocGYEdrhB6Q8 zqssM6<;K(Jb}{(zJ=^@aJmadQt^(uap=bCVq-KYgm%p+Lz!R{$us0+*dD=H<&yLgB zsxqMRxAAt*u{(}=T!DkiPKz5|hX8yP{L;eAwh@fW0e(0s{95Kf^2{};LPc@9Zs0`o z#E~_=^Y?SElKAP|8>bs+^sXwAKb`auAK~{O5Um#~-wUiKq&!TL8m1U)RDA31URp&C z@=VXMW}CT!mgqw7N7XizH;@W#p11ZZAGuWYn2KcoyoK`)^#HJy%%OPw(-+E)e52W` zxLK1}s@TBoU+EBJ6qXOI7I30fJbz(v+$E&M@55w;VgOdDP8s8oMXq?C*nt#|$kZ`) zH8{^$f+0q?s_MyoMiRGXGVjduG_t5}OM)b*#HABoxAsA{qyEH!cdqedj6POgTHN`* zD&FVNivs`K*cOIJm))t&mZ-}`GXc3$YCzc*ZQkj3$xJ>TXByn~WUy(E*A=KSAOEhu zw7?fdkwdz6p>SWeqBe;pm9E1G7%|gSveI1AWvE?daOwN>S6{L5eh+ilnDeR>JzG## zN*MXD5F+7n=~?)Iyg^_Nn=sLZ7`iO#&!I{`sRp0nge8B$Mly zJ82)bz(@`q7L}Jd=+CE+X?Hh3RV!S}g;?2?JKzS8WJ&i}D@7~Xj=9~C`fbKt<`cER zVp3l{9R<6%S?9e=g9(p`nM?CCye~54x2nHW;lwT*{KX<2dobDTe?iP?V22%kKvjJPhQ&kW} z7xr-WvC;@n_hfWSM7r~W_-&hMc?ue37pl%;`g3L~i;MKx<<-++r zQpd3pi|iDO?ENGA%#Orf6=t|d%QZDECwbqd1bOIs9wH1JV+Fgz3$0sxg+EGZD+yvb z7!^_zHFe!{gzfV9PN{-Z*ds#8*WD(}gLCx8zHIzC;uiK!X;wJUdIj3{V!hyoIz$FvhR2A}xt$tijmi0Q2Yww>f_fa4JmR3-GM|tfd)BcXix_;tqRXgo(J)jrda9SZ{GkR_ZJjnzH{n9`Z92GtD*)Met_WXN5E5t zXy|)qXX&&x(K7AHD0W~s&Ksd{kc?^Asf)6cN z{ced=Tg6;3fyzVrlab@l%A?=EM|?TST@`;B@9wJ-4fh)I=B!)F=Mz$+Ma&mUsL$4VR0)@PDoXLPE;f-kXDPSv7z2PAu-`JFc-jCiG zaOE*|wuPqHrl{5T2e(5Q(VeD|1D4H>*O5}4) z-5(CBfnP)AR%y9Dqe(Ej-`=-p@L6H;`jGe3!@q7Z%MnBcXsK3aC)!(i2 zx1Wyi;3gdbVEW*Q*-&Zg`sOLpy)4R&aXTi0Cq9 z=<{bQp)bzb_6IV>M^$yS-euDB1ljPkHw3salkN)u;3t;In=OXEwrAbXGBONby?o*H zlSQ0c#-!hEKl@{EFkSAg0qQx%=gd%|(6vSoW1<_{U!TP?VX{u26sKetxx1%+Tf_U=Sv`-2)l_me9J)C zs%W(?Wq)j<5R`#1N@pbO_wAx3x`!i+LAAcli|qHhxa-7=~o9vj+V-yt&lfx^T_g|(nG$k!qA~$h!&^F>PTAp{r zS2(=mx%h}%m>Jf7fHoQHU!@BXP$GucAS`Md+op@nByP{-{T80ZB~U2-7!T13igGUV z03$LBlBpxG?V!zyRu^5n(5-9Kr+z{&AGr`Lvd&GrvoJ-?qq)3F7lZ4WdiG(vZ$n2l zsg8dNvO?CtNvqLph)~J;Y@uQl zfFN)drJ6%Qs49ImB!QfK>f2d!hXAT7NU{_45<*Eb3ASd5% z>a23sV5t0*8O9$A<@??4eBEp3<+pLTY{(J#$5+*rUuLu&fZsAfmO|VHun#mjRh!6I zHL5Y#s!bpvh^HC^SROli9mZX5Hi&FCI?ea9)cfZ}OEWF)J$-ApSlQDYsonQYX+>(3 zv|)J{Dz>OdH82jU*FtK%-<;cNoU5aht!?rNjnCRl5nAmK8w>EvCsL97P`M#dmJ+xj z4E&0!h9gR*)=o!ilx|x5rXlh1<+3#ZpIwJUjWqq3g;nK}r5G{}K}&ZDZ;@5I>_|%K zr$%L;y|%ksdXwCJfW&+4c9&rPSaYwTuW5og5fiaA()PKZ_*GQQ)tQ=>oMObq&Dx`v zysik348dBMbP%cl9d(|;=2F3j}!fQw7n zxkU0^41Uce#m?0)(G{K~`s>$B;J|9(TKAoJIQSyrwkhi&O^#;vl!`xQM?oE7b%1vx(9Jmc_ z(qiGZ9xaRljEw`-`-$pYgPB{TP?{+ueNjm1p^u=wAS9J5o$0frt3O_a1@R(eAX=+c z8#5CUt7RZSA5H%CtAM zKSO(MZ{H+I7q^_ezs+&AR~TCJx=G_dJYWY(DkJNj$<7Y)*KgEgN z(_Ztv+u4GzCY7^!u1JZTBhWTfQ;E2mRF)V-5nt*1uG=72rGp3FoK5zmtAEgg0SiRm zLqOj+aMDk)w)#;b_(z%D_jf~A$1%jW4N$Xns43SJOOjwX4&wz&l3mz&NKC85qC$%k z>(c7N&+jV+De^;qVVDx7gAk%N3C}IvC+LaR)Aba}6gWX|kq-D6bX~Jb8*px#i2SG< zp&P(}zrd^!_!GC-^>Z8xC^W!^G0#z-;w$H`FJ*RIoc+?f(Ib+vXG(;fYz#8lFpp2o zHh-KJ52l09z}$xq+qAo<6p;z*T`NP1t`3cp=1o&B#Zz8X=uywuNn!V-l5|F|!~UC{ zCMm6f`4wSDydPbj=yk~ESux0K?az9ttq%|Eb=)f8&*^&X6@7I<7aSfqApdJ$rWGeHg9UmOkan+GS&fVFGqb?+bwC zTw2#gmuM_6?+HFn`T(bPRVR5QR5NdSuHLr=Ezbi-w{AZICI|z^mP7E&ovyzvWT0Gd zHoTrE-oZjNBW`AR=)IyfNz;Z(*_@oNtI-f1blJZy)9cY3vho?-*l?DQyPRA_SF_VX z8Z7gEe6~ob`t?n6FAo0Ta}2a!`D~Db{~Q{!^9b;K1hBv;FJ4XD!#+Am4qKHbkQb~Q zJxtBt>E#5|O?x`&;eU*gKh90TJhO4EAwD6SON1MTynh62S=RqUjkt-uB!r`7L_1Ku z9m$1HG-wSS8cgvUI$Cr4Hr0({w3x`bS)&C8uy-KvI0knK{do4#Al!|-8|L#zz}!^G zi|Rb>>P=OgtT-)fTI)8+&ef;&bQ1Fmt%uy^7O!q3rKsRJ{;}uJ6Ta1Z@?Bs5o6R%q z!stAG8h}TmWQF>og*Ts6s01x@QuF+)ix#>{)TnabtZ!*@#Z@V|Wg7&a7B4^a-Lqqw z(JY48*-x7Ksb3~BFnizyqhxbZ0!Si~G@OZLjQ{!vHO~CS6I{0YDZw&89%p&PbUqm> zm008>8iG9h9x|sKa$!& f.endsWith('.html')) + .map((f) => path.join(DIST_DIR, f)); +} + +function imageExists(url) { + if (!url) return true; + let pathname; + try { + pathname = url.startsWith('http') ? new URL(url).pathname : url; + } catch { + return true; + } + if (!pathname.startsWith('/images/')) return true; + return fs.existsSync(path.join(DIST_DIR, pathname.replace(/^\//, ''))); +} + +function fixSocialImages(document) { + const selectors = ['meta[property="og:image"]', 'meta[name="twitter:image"]']; + for (const selector of selectors) { + for (const meta of document.querySelectorAll(selector)) { + const value = meta.getAttribute('content'); + if (!imageExists(value)) { + meta.setAttribute('content', `${SITE_URL}${FALLBACK_SOCIAL_IMAGE}`); + } + } + } +} + +function fixApplicationCategory(document) { + for (const script of document.querySelectorAll( + 'script[type="application/ld+json"]' + )) { + let data; + try { + data = JSON.parse(script.textContent || ''); + } catch { + continue; + } + if ( + data && + (data['@type'] === 'SoftwareApplication' || + data['@type'] === 'WebApplication') && + data.applicationCategory !== 'UtilitiesApplication' + ) { + data.applicationCategory = 'UtilitiesApplication'; + script.textContent = JSON.stringify(data, null, 2); + } + } +} + +function hasLdType(document, typeName) { + return [ + ...document.querySelectorAll('script[type="application/ld+json"]'), + ].some((s) => (s.textContent || '').includes(`"${typeName}"`)); +} + +function injectFaqSchema(document) { + if (hasLdType(document, 'FAQPage')) return false; + const items = []; + for (const details of document.querySelectorAll('details.faq-d')) { + const summary = details.querySelector('summary'); + const answer = details.querySelector('p'); + if (!summary || !answer) continue; + const question = summary.textContent.replace(/\s+/g, ' ').trim(); + const answerText = answer.textContent.replace(/\s+/g, ' ').trim(); + if (!question || !answerText) continue; + items.push({ + '@type': 'Question', + name: question, + acceptedAnswer: { '@type': 'Answer', text: answerText }, + }); + } + if (items.length === 0) return false; + const script = document.createElement('script'); + script.setAttribute('type', 'application/ld+json'); + script.textContent = JSON.stringify( + { + '@context': 'https://schema.org', + '@type': 'FAQPage', + mainEntity: items, + }, + null, + 2 + ); + document.body.appendChild(script); + return true; +} + +function injectWebsiteSchema(document) { + if (hasLdType(document, 'WebSite')) return; + const script = document.createElement('script'); + script.setAttribute('type', 'application/ld+json'); + script.textContent = JSON.stringify( + { + '@context': 'https://schema.org', + '@type': 'WebSite', + name: 'BentoPDF', + alternateName: ['Bento PDF', 'BentoPDF.com'], + url: `${SITE_URL}/`, + }, + null, + 2 + ); + document.body.appendChild(script); +} + +function rewriteInternalLinks(document, knownSlugs) { + for (const link of document.querySelectorAll('a[href]')) { + const href = link.getAttribute('href'); + if (!href || /^(https?:|\/\/|#|mailto:|tel:|data:)/.test(href)) continue; + const match = href.match( + /^(?:\.\/|\/)?([a-z0-9][a-z0-9-]{0,64})\.html(#[^#]{0,128})?$/ + ); + if (!match) continue; + if (!knownSlugs.has(match[1])) continue; + const target = match[1] === 'index' ? '/' : `/${match[1]}`; + link.setAttribute('href', `${target}${match[2] || ''}`); + } +} + +function enhance() { + if (!fs.existsSync(DIST_DIR)) { + console.error('enhance-seo-pages: dist not found, run vite build first'); + process.exit(1); + } + const files = listTopLevelHtml(); + const knownSlugs = new Set(files.map((f) => path.basename(f, '.html'))); + + let faqSchemaCount = 0; + for (const file of files) { + const slug = path.basename(file, '.html'); + const dom = new JSDOM(fs.readFileSync(file, 'utf-8')); + const document = dom.window.document; + + fixSocialImages(document); + fixApplicationCategory(document); + rewriteInternalLinks(document, knownSlugs); + + if (slug === 'index') { + injectWebsiteSchema(document); + } + + if (slug !== '404') { + if (injectFaqSchema(document)) faqSchemaCount++; + } + + fs.writeFileSync(file, dom.serialize()); + dom.window.close(); + } + console.log( + `SEO enhance: ${files.length} pages processed, ${faqSchemaCount} FAQPage schemas added.` + ); +} + +enhance(); diff --git a/scripts/generate-blog.mjs b/scripts/generate-blog.mjs new file mode 100644 index 00000000..cc7c16d5 --- /dev/null +++ b/scripts/generate-blog.mjs @@ -0,0 +1,429 @@ +import fs from 'fs'; +import path from 'path'; +import { marked } from 'marked'; +import { fileURLToPath } from 'url'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +const POSTS_DIR = path.resolve(__dirname, '../blog/posts'); +const BLOG_DIR = path.resolve(__dirname, '../blog'); +const SITE_URL = 'https://www.bentopdf.com'; +const AUTHOR = { + name: 'Alam', + url: `${SITE_URL}/blog/author-alam`, + image: `${SITE_URL}/images/author-alam.jpg`, + profiles: [ + 'https://github.com/alam00000', + 'https://www.linkedin.com/in/abdullah-alam01/', + ], +}; + +const LINK_CLASS = 'text-indigo-300 hover:text-indigo-400'; + +function escapeHtml(value) { + return value + .replace(/&/g, '&') + .replace(//g, '>') + .replace(/"/g, '"'); +} + +function styleBody(html) { + return html + .replace(/

/g, '

') + .replace(/

/g, '

') + .replace(/

/g, '

') + .replace( + /

    /g, + '
      ' + ) + .replace( + /
        /g, + '
          ' + ) + .replace( + /#]/g, '') + .replace(/^\s*\d+\.\s+/gm, '') + .replace(/^\s*[-+]\s+/gm, '') + .replace(/\s+/g, ' ') + .trim(); +} + +function questionSections(body) { + const sections = []; + const parts = body.split(/^##\s+/m).slice(1); + for (const part of parts) { + const newline = part.indexOf('\n'); + const heading = (newline === -1 ? part : part.slice(0, newline)).trim(); + if (!heading.endsWith('?')) continue; + const answer = plainText(newline === -1 ? '' : part.slice(newline + 1)); + if (!answer) continue; + sections.push({ q: heading, a: answer.slice(0, 600) }); + } + return sections; +} + +function faqSchema(entries) { + if (entries.length === 0) return ''; + return ` + `; +} + +function renderFaqs(faqs) { + if (!faqs || faqs.length === 0) return ''; + const items = faqs + .map( + (f) => `
          + ${escapeHtml(f.q)} +

          + ${renderInline(f.a)} +

          +
          ` + ) + .join('\n'); + return ` +

          FAQ

          +
          +${items} +
          `; +} + +function renderCta(cta) { + if (!cta) return ''; + return ` +
          `; +} + +function renderPost({ slug, meta, body }) { + const url = `${SITE_URL}/blog/${slug}`; + const updated = meta.updated || meta.date; + const bodyHtml = styleBody(marked.parse(body)); + const faqEntries = + meta.faqs && meta.faqs.length > 0 ? meta.faqs : questionSections(body); + + return ` + + + + + ${escapeHtml(meta.title)} + + + + + + + + + + + + + + + + + + {{> navbar }} + +
          + + +

          + ${escapeHtml(meta.h1)} +

          + +
          + ${AUTHOR.name} +
          + ${AUTHOR.name}, + builds BentoPDF · + +
          +
          + +${bodyHtml} +${renderCta(meta.cta)} +${renderFaqs(meta.faqs)} +
          + + {{> footer }} + + + + + + ${faqSchema(faqEntries)} + + +`; +} + +function renderIndex(posts) { + const cards = posts + .map( + ({ slug, meta }) => ` +

          + ${escapeHtml(meta.h1)} +

          +

          + ${escapeHtml(meta.card)} +

          + ${formatDate(meta.date)} +
          ` + ) + .join('\n\n'); + + return ` + + + + + The BentoPDF Blog | Privacy-First PDF Guides + + + + + + + + + + + + + + + + + + {{> navbar }} + +
          +

          The BentoPDF Blog

          +

          + I'm Alam. I build + BentoPDF and write about PDFs, how they work, and the weird things I + run into along the way. +

          +
          + +
          +
          +${cards} +
          +
          + + {{> footer }} + + + + + + +`; +} + +function generate() { + if (!fs.existsSync(POSTS_DIR)) { + console.log('generate-blog: no blog/posts directory, skipping'); + return; + } + const files = fs + .readdirSync(POSTS_DIR) + .filter((f) => f.endsWith('.md')) + .sort(); + const posts = files.map(parsePost); + posts.sort((a, b) => (a.meta.date < b.meta.date ? 1 : -1)); + + const keep = new Set(['index.html', 'author-alam.html']); + for (const post of posts) { + fs.writeFileSync( + path.join(BLOG_DIR, `${post.slug}.html`), + renderPost(post) + ); + keep.add(`${post.slug}.html`); + } + fs.writeFileSync(path.join(BLOG_DIR, 'index.html'), renderIndex(posts)); + + for (const entry of fs.readdirSync(BLOG_DIR)) { + if (entry.endsWith('.html') && !keep.has(entry)) { + fs.rmSync(path.join(BLOG_DIR, entry)); + console.log(`generate-blog: removed stale ${entry}`); + } + } + + console.log( + `generate-blog: ${posts.length} posts + index generated from blog/posts/` + ); +} + +generate(); diff --git a/scripts/generate-i18n-pages.mjs b/scripts/generate-i18n-pages.mjs index b65b0271..01af4cd5 100644 --- a/scripts/generate-i18n-pages.mjs +++ b/scripts/generate-i18n-pages.mjs @@ -59,7 +59,47 @@ function buildUrl(langPrefix, pagePath) { if (BASE_PATH && BASE_PATH !== '') parts.push(BASE_PATH.replace(/^\//, '')); if (langPrefix) parts.push(langPrefix); if (pagePath) parts.push(pagePath.replace(/^\//, '')); - return parts.filter(Boolean).join('/').replace(/\/+$/, '') || SITE_URL; + const url = parts.filter(Boolean).join('/').replace(/\/+$/, '') || SITE_URL; + return langPrefix && !pagePath ? `${url}/` : url; +} + +function resolveTranslation(langResources, key) { + let namespace = 'common'; + let keyPath = key; + const colonIndex = key.indexOf(':'); + if (colonIndex !== -1) { + namespace = key.slice(0, colonIndex); + keyPath = key.slice(colonIndex + 1); + } + let node = langResources[namespace]; + for (const segment of keyPath.split('.')) { + if (node == null || typeof node !== 'object') return null; + node = node[segment]; + } + return typeof node === 'string' && node ? node : null; +} + +function applyServerTranslations(document, langResources) { + document.querySelectorAll('[data-i18n]').forEach((element) => { + const key = element.getAttribute('data-i18n'); + if (!key) return; + const translation = resolveTranslation(langResources, key); + if (translation) element.textContent = translation; + }); + + document.querySelectorAll('[data-i18n-placeholder]').forEach((element) => { + const key = element.getAttribute('data-i18n-placeholder'); + if (!key) return; + const translation = resolveTranslation(langResources, key); + if (translation) element.setAttribute('placeholder', translation); + }); + + document.querySelectorAll('[data-i18n-title]').forEach((element) => { + const key = element.getAttribute('data-i18n-title'); + if (!key) return; + const translation = resolveTranslation(langResources, key); + if (translation) element.setAttribute('title', translation); + }); } const ORGANIZATION_LD_MARKER = 'data-bentopdf-organization'; @@ -105,10 +145,24 @@ function buildLocalHomeHref(lang) { return `${BASE_PATH}${langSegment}`.replace(/\/+/g, '/'); } +function removeStaticBreadcrumbLd(document) { + for (const script of document.querySelectorAll( + `script[type="application/ld+json"]:not([${BREADCRUMB_MARKER}])` + )) { + try { + const parsed = JSON.parse(script.textContent || ''); + if (parsed && parsed['@type'] === 'BreadcrumbList') script.remove(); + } catch { + continue; + } + } +} + function injectToolBreadcrumb(document, lang, toolName, toolUrl) { const h1 = document.querySelector('h1[data-i18n^="tools:"]'); if (!h1) return; if (document.querySelector(`[${BREADCRUMB_MARKER}]`)) return; + removeStaticBreadcrumbLd(document); const homeUrl = buildUrl(lang === 'en' ? '' : lang, ''); @@ -191,6 +245,8 @@ function processFileForLanguage( document.documentElement.lang = lang; document.documentElement.dir = lang === 'ar' ? 'rtl' : 'ltr'; + applyServerTranslations(document, translations[lang]); + let title = null; let description = null; @@ -247,14 +303,13 @@ function processFileForLanguage( document.head.appendChild(defaultLink); const localizedUrl = buildUrl(lang, pagePath); - const canonicalUrl = buildUrl('', pagePath); let canonical = document.querySelector('link[rel="canonical"]'); if (!canonical) { canonical = document.createElement('link'); canonical.rel = 'canonical'; document.head.appendChild(canonical); } - canonical.href = canonicalUrl; + canonical.href = localizedUrl; const ogUrl = document.querySelector('meta[property="og:url"]'); if (ogUrl) ogUrl.content = localizedUrl; @@ -288,6 +343,8 @@ function processFileForLanguage( if (href.startsWith('/assets/') || href.includes('/assets/')) return; + if (href === '/blog' || href.startsWith('/blog/')) return; + const langPrefixRegex = new RegExp( `^(${BASE_PATH})?/(${languages.join('|')})(/|$)` ); diff --git a/scripts/generate-sitemap.mjs b/scripts/generate-sitemap.mjs index 9a6f87f8..019d01fe 100644 --- a/scripts/generate-sitemap.mjs +++ b/scripts/generate-sitemap.mjs @@ -1,5 +1,6 @@ import fs from 'fs'; import path from 'path'; +import { execFileSync } from 'child_process'; import { fileURLToPath } from 'url'; const __filename = fileURLToPath(import.meta.url); @@ -32,9 +33,17 @@ const PRIORITY_MAP = { 'excel-to-pdf': 0.9, 'powerpoint-to-pdf': 0.9, 'jpg-to-pdf': 0.9, - 'pdf-to-docx': 0.9, + 'pdf-to-word': 0.9, + 'unlock-pdf': 0.9, + 'protect-pdf': 0.9, 'pdf-to-excel': 0.9, 'pdf-to-jpg': 0.9, + 'compress-pdf-to-100kb': 0.8, + 'compress-pdf-to-200kb': 0.8, + 'compress-pdf-to-500kb': 0.8, + 'compress-pdf-to-1mb': 0.8, + 'compress-pdf-to-2mb': 0.8, + 'compress-pdf-for-email': 0.8, about: 0.8, faq: 0.8, contact: 0.7, @@ -52,7 +61,7 @@ function buildUrl(lang, pageName) { if (lang === 'en') { return pagePath ? `${SITE_URL}/${pagePath}` : SITE_URL; } - return pagePath ? `${SITE_URL}/${lang}/${pagePath}` : `${SITE_URL}/${lang}`; + return pagePath ? `${SITE_URL}/${lang}/${pagePath}` : `${SITE_URL}/${lang}/`; } function generateSitemap() { @@ -66,22 +75,48 @@ function generateSitemap() { .map((file) => file.replace('.html', '')) .filter((name) => !EXCLUDED_PAGES.has(name)); + const projectRoot = path.resolve(__dirname, '..'); const lastModCache = new Map(); - const getLastMod = (lang, pageName) => { - const cacheKey = `${lang}::${pageName}`; - if (lastModCache.has(cacheKey)) return lastModCache.get(cacheKey); + const getLastMod = (pageName) => { + if (lastModCache.has(pageName)) return lastModCache.get(pageName); const fileName = `${pageName}.html`; - const filePath = - lang === 'en' - ? path.join(DIST_DIR, fileName) - : path.join(DIST_DIR, lang, fileName); - let iso; - try { - iso = fs.statSync(filePath).mtime.toISOString().slice(0, 10); - } catch { - iso = new Date().toISOString().slice(0, 10); + const candidates = [ + path.join(projectRoot, 'src', 'pages', fileName), + path.join(projectRoot, fileName), + ]; + let iso = null; + for (const sourcePath of candidates) { + if (!fs.existsSync(sourcePath)) continue; + try { + const out = execFileSync( + 'git', + ['log', '-1', '--format=%cI', '--', sourcePath], + { cwd: projectRoot, encoding: 'utf-8' } + ).trim(); + if (out) iso = out.slice(0, 10); + } catch { + iso = null; + } + if (!iso) { + try { + iso = fs.statSync(sourcePath).mtime.toISOString().slice(0, 10); + } catch { + iso = null; + } + } + break; } - lastModCache.set(cacheKey, iso); + if (!iso) { + try { + iso = fs + .statSync(path.join(DIST_DIR, fileName)) + .mtime.toISOString() + .slice(0, 10); + } catch { + iso = new Date().toISOString().slice(0, 10); + } + } + lastModCache.set(pageName, iso); return iso; }; @@ -93,12 +128,11 @@ function generateSitemap() { for (const pageName of htmlFiles) { const priority = getPriority(pageName); const url = buildUrl('en', pageName); - const lastmod = getLastMod('en', pageName); + const lastmod = getLastMod(pageName); sitemap += ` ${url} ${lastmod} - weekly ${priority} `; @@ -114,6 +148,48 @@ function generateSitemap() { `; } + const blogDir = path.join(DIST_DIR, 'blog'); + let blogCount = 0; + if (fs.existsSync(blogDir)) { + const blogFiles = fs + .readdirSync(blogDir) + .filter((file) => file.endsWith('.html')) + .map((file) => file.replace('.html', '')); + for (const name of blogFiles) { + const url = + name === 'index' ? `${SITE_URL}/blog/` : `${SITE_URL}/blog/${name}`; + const sourcePath = path.join(projectRoot, 'blog', `${name}.html`); + let lastmod; + try { + const out = execFileSync( + 'git', + ['log', '-1', '--format=%cI', '--', sourcePath], + { cwd: projectRoot, encoding: 'utf-8' } + ).trim(); + lastmod = out ? out.slice(0, 10) : null; + } catch { + lastmod = null; + } + if (!lastmod) { + try { + lastmod = fs.statSync(sourcePath).mtime.toISOString().slice(0, 10); + } catch { + lastmod = new Date().toISOString().slice(0, 10); + } + } + sitemap += ` + ${url} + ${lastmod} + 0.7 + +`; + blogCount++; + } + } + if (blogCount > 0) { + console.log(` Blog: ${blogCount} URLs added (English only)`); + } + sitemap += ` `; diff --git a/scripts/generate-static-tool-links.mjs b/scripts/generate-static-tool-links.mjs new file mode 100644 index 00000000..c0bc4756 --- /dev/null +++ b/scripts/generate-static-tool-links.mjs @@ -0,0 +1,106 @@ +import fs from 'fs'; +import path from 'path'; +import { fileURLToPath } from 'url'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +const TOOLS_CONFIG = path.resolve(__dirname, '../src/js/config/tools.ts'); +const PAGES_DIR = path.resolve(__dirname, '../src/pages'); +const PARTIAL_PATH = path.resolve( + __dirname, + '../src/partials/tool-links-static.html' +); + +function escapeHtml(value) { + return value + .replace(/&/g, '&') + .replace(//g, '>') + .replace(/"/g, '"'); +} + +function unescapeTs(value) { + return value.replace(/\\'/g, "'").replace(/\\\\/g, '\\'); +} + +function parseCategories(source) { + const headers = [ + ...source.matchAll(/name:\s*'((?:[^'\\]|\\.)*)',\s*\n\s*tools:\s*\[/g), + ].map((m) => ({ name: unescapeTs(m[1]), index: m.index })); + + const toolMatches = [ + ...source.matchAll( + /\{[^{}]*?href:\s*import\.meta\.env\.BASE_URL\s*\+\s*'((?:[^'\\]|\\.)*)'[^{}]*?\}/gs + ), + ]; + const categories = headers.map((h) => ({ name: h.name, tools: [] })); + for (const match of toolMatches) { + const block = match[0]; + const hrefFile = unescapeTs(match[1]); + const nameMatch = block.match(/name:\s*'((?:[^'\\]|\\.)*)'/s); + const subtitleMatch = block.match(/subtitle:\s*\n?\s*'((?:[^'\\]|\\.)*)'/s); + if (!nameMatch) continue; + + let categoryIndex = -1; + for (let i = 0; i < headers.length; i++) { + if (headers[i].index < match.index) categoryIndex = i; + } + if (categoryIndex === -1) continue; + + categories[categoryIndex].tools.push({ + slug: hrefFile.replace(/\.html$/, ''), + name: unescapeTs(nameMatch[1]), + subtitle: subtitleMatch ? unescapeTs(subtitleMatch[1]) : '', + }); + } + return categories.filter((c) => c.tools.length > 0); +} + +function generate() { + const source = fs.readFileSync(TOOLS_CONFIG, 'utf-8'); + const categories = parseCategories(source); + const existingPages = new Set( + fs + .readdirSync(PAGES_DIR) + .filter((f) => f.endsWith('.html')) + .map((f) => f.replace(/\.html$/, '')) + ); + + const seen = new Set(); + const lines = []; + let toolCount = 0; + for (const category of categories) { + const tools = category.tools.filter( + (t) => existingPages.has(t.slug) && !seen.has(t.slug) + ); + if (tools.length === 0) continue; + for (const t of tools) seen.add(t.slug); + lines.push( + `

          ${escapeHtml(category.name)}

          ` + ); + for (const tool of tools) { + toolCount++; + lines.push( + `` + + `

          ${escapeHtml(tool.name)}

          ` + + `

          ${escapeHtml(tool.subtitle)}

          ` + + `
          ` + ); + } + } + + if (toolCount < 50) { + console.error( + `generate-static-tool-links: only ${toolCount} tools parsed from tools.ts — parser is likely out of sync with the config format` + ); + process.exit(1); + } + + fs.writeFileSync(PARTIAL_PATH, lines.join('\n') + '\n'); + console.log( + `Static tool links: ${toolCount} tools in ${categories.length} categories -> src/partials/tool-links-static.html` + ); +} + +generate(); diff --git a/scripts/include-docs-in-dist.js b/scripts/include-docs-in-dist.js index 64c4b935..12bee6a7 100644 --- a/scripts/include-docs-in-dist.js +++ b/scripts/include-docs-in-dist.js @@ -11,46 +11,95 @@ const mainDistPath = path.join(projectRoot, 'dist'); const targetDocsPath = path.join(mainDistPath, 'docs'); function copyDir(src, dest) { - if (!fs.existsSync(dest)) { - fs.mkdirSync(dest, { recursive: true }); - } + if (!fs.existsSync(dest)) { + fs.mkdirSync(dest, { recursive: true }); + } - const entries = fs.readdirSync(src, { withFileTypes: true }); + const entries = fs.readdirSync(src, { withFileTypes: true }); - for (const entry of entries) { - const srcPath = path.join(src, entry.name); - const destPath = path.join(dest, entry.name); + for (const entry of entries) { + const srcPath = path.join(src, entry.name); + const destPath = path.join(dest, entry.name); - if (entry.isDirectory()) { - copyDir(srcPath, destPath); - } else { - fs.copyFileSync(srcPath, destPath); - } + if (entry.isDirectory()) { + copyDir(srcPath, destPath); + } else { + fs.copyFileSync(srcPath, destPath); } + } } console.log('Including docs in dist...'); if (!fs.existsSync(docsDistPath)) { - console.error('Error: Docs build not found. Please run "npm run docs:build" first.'); - process.exit(1); + console.error( + 'Error: Docs build not found. Please run "npm run docs:build" first.' + ); + process.exit(1); } if (!fs.existsSync(mainDistPath)) { - console.error('Error: Main dist folder not found. Please run "npm run build" first.'); - process.exit(1); + console.error( + 'Error: Main dist folder not found. Please run "npm run build" first.' + ); + process.exit(1); } try { - console.log(`Copying from: ${docsDistPath}`); - console.log(`Copying to: ${targetDocsPath}`); + console.log(`Copying from: ${docsDistPath}`); + console.log(`Copying to: ${targetDocsPath}`); - copyDir(docsDistPath, targetDocsPath); + copyDir(docsDistPath, targetDocsPath); - console.log('Docs successfully included in dist/docs!'); + console.log('Docs successfully included in dist/docs!'); - const files = fs.readdirSync(targetDocsPath); - console.log(`Copied ${files.length} items to dist/docs`); + const files = fs.readdirSync(targetDocsPath); + console.log(`Copied ${files.length} items to dist/docs`); + + addDocsToSitemap(); } catch (error) { - console.error('Error copying docs:', error.message); - process.exit(1); + console.error('Error copying docs:', error.message); + process.exit(1); +} + +function listDocsHtml(dir, prefix) { + const urls = []; + for (const entry of fs.readdirSync(dir, { withFileTypes: true })) { + if (entry.isDirectory()) { + if (entry.name === 'assets' || entry.name.startsWith('.')) continue; + urls.push( + ...listDocsHtml(path.join(dir, entry.name), `${prefix}/${entry.name}`) + ); + } else if (entry.name.endsWith('.html') && entry.name !== '404.html') { + const slug = entry.name.replace(/\.html$/, ''); + urls.push(slug === 'index' ? `${prefix}/` : `${prefix}/${slug}`); + } + } + return urls; +} + +function addDocsToSitemap() { + const siteUrl = (process.env.SITE_URL || 'https://www.bentopdf.com').replace( + /\/+$/, + '' + ); + const sitemapPath = path.join(mainDistPath, 'sitemap.xml'); + if (!fs.existsSync(sitemapPath)) { + console.warn( + 'sitemap.xml not found in dist; skipping docs sitemap entries' + ); + return; + } + let xml = fs.readFileSync(sitemapPath, 'utf-8'); + if (xml.includes(`${siteUrl}/docs/`)) return; + + const urls = listDocsHtml(targetDocsPath, '/docs'); + const entries = urls + .map( + (url) => + ` \n ${siteUrl}${url}\n 0.6\n \n` + ) + .join(''); + xml = xml.replace('', `${entries}`); + fs.writeFileSync(sitemapPath, xml); + console.log(`Added ${urls.length} docs URLs to sitemap.xml`); } diff --git a/scripts/seo-audit.mjs b/scripts/seo-audit.mjs index ba866cee..d9fbce93 100644 --- a/scripts/seo-audit.mjs +++ b/scripts/seo-audit.mjs @@ -67,6 +67,12 @@ function findAll(html, regex) { return out; } +const LOCALE_DIRS = new Set( + fs + .readdirSync(LOCALES_DIR) + .filter((d) => fs.statSync(path.join(LOCALES_DIR, d)).isDirectory()) +); + function expectedCanonicalForFile(rel) { const parts = rel.split('/'); const fileName = parts.pop(); @@ -74,12 +80,40 @@ function expectedCanonicalForFile(rel) { const slug = baseName === 'index' ? '' : baseName; const segments = [SITE_URL]; if (BASE_PATH) segments.push(BASE_PATH.replace(/^\//, '')); + for (const dir of parts) { + if (LOCALE_DIRS.has(dir) || dir === 'blog') segments.push(dir); + } if (slug) segments.push(slug); return segments.join('/').replace(/\/+$/, '') || SITE_URL; } -function auditHtml(file) { +function auditHtml(file, knownSlugs) { const html = fs.readFileSync(file.full, 'utf-8'); + const isLocalized = file.rel.split('/').some((seg) => LOCALE_DIRS.has(seg)); + + if (!isLocalized && /[—–]/.test(html)) { + fail( + 'em-dash', + `${file.rel}: contains an em or en dash (house style forbids them)` + ); + } + + if (!isLocalized) { + const internal = findAll(html, /]+href=["'](\/[^"'#?]*)["']/g); + for (const href of internal) { + const clean = href.replace(/\/$/, ''); + if (clean === '') continue; + const seg = clean.slice(1); + if (seg.includes('/')) continue; + if (LOCALE_DIRS.has(seg) || seg === 'blog' || seg === 'docs') continue; + if (!knownSlugs.has(seg)) { + fail( + 'dead-link', + `${file.rel}: links to "${href}" but no such page exists in dist` + ); + } + } + } const titles = findAll(html, /]*>[\s\S]*?<\/title>/g); if (titles.length === 0) { fail('title', `${file.rel}: no `); @@ -147,7 +181,7 @@ function auditHtml(file) { ); } - const emptyI18n = html.match(/<span[^>]*data-i18n="[^"]+"[^>]*>\s*<\/span>/g); + const emptyI18n = html.match(/<span[^>]*data-i18n="[^"]+"[^>]*><\/span>/g); if (emptyI18n && emptyI18n.length > 0) { fail( 'data-i18n', @@ -176,10 +210,76 @@ function auditHtml(file) { `${file.rel}: hreflang href host "${url.hostname}" != expected "${HOST}"` ); } + const trimmed = url.pathname.replace(/^\/|\/$/g, ''); + if (LOCALE_DIRS.has(trimmed) && !url.pathname.endsWith('/')) { + fail( + 'hreflang', + `${file.rel}: language-home hreflang "${m[1]}" must end with "/" (the server 301s the slashless form)` + ); + } } catch { fail('hreflang', `${file.rel}: hreflang href "${m[1]}" not a valid URL`); } } + + const descriptions = findAll( + html, + /<meta[^>]+name=["']description["'][^>]*content=["']([^"']*)["']/g + ); + if (descriptions.length > 1) { + fail( + 'description', + `${file.rel}: ${descriptions.length} meta description tags (expected 1)` + ); + } + for (const desc of descriptions) { + if (desc.includes('★')) { + fail('description', `${file.rel}: meta description contains "★"`); + } + } + + const isTopLevel = !file.rel.includes('/'); + if (isTopLevel) { + const socialImages = findAll( + html, + /<meta[^>]+(?:property=["']og:image["']|name=["']twitter:image["'])[^>]*content=["']([^"']+)["']/g + ); + for (const image of socialImages) { + let pathname; + try { + pathname = image.startsWith('http') ? new URL(image).pathname : image; + } catch { + continue; + } + if ( + pathname.startsWith('/images/') && + !fs.existsSync(path.join(DIST_DIR, pathname.replace(/^\//, ''))) + ) { + fail( + 'social-image', + `${file.rel}: og/twitter image "${pathname}" does not exist in dist` + ); + } + } + + if (html.includes('faq-d') && !html.includes('"FAQPage"')) { + fail( + 'faq-schema', + `${file.rel}: visible FAQ section without FAQPage JSON-LD` + ); + } + + const internalHtmlLinks = findAll( + html, + /<a[^>]+href=["'](\/?[a-z0-9][a-z0-9-]*\.html)["']/g + ); + for (const href of internalHtmlLinks) { + fail( + 'internal-link', + `${file.rel}: internal link "${href}" should be extensionless` + ); + } + } } function auditSitemap() { @@ -248,7 +348,12 @@ function main() { fail('audit', 'no HTML files found in dist/'); } - for (const file of files) auditHtml(file); + const knownSlugs = new Set( + files + .filter((f) => !f.rel.includes('/')) + .map((f) => f.rel.replace(/\.html$/, '')) + ); + for (const file of files) auditHtml(file, knownSlugs); auditSitemap(); const total = failures.length + warnings.length; diff --git a/src/js/config/tools.ts b/src/js/config/tools.ts index 88b67fd1..9b55ab7e 100644 --- a/src/js/config/tools.ts +++ b/src/js/config/tools.ts @@ -499,7 +499,7 @@ const baseCategories = [ subtitle: 'Convert PDF files to JSON format.', }, { - href: import.meta.env.BASE_URL + 'pdf-to-docx.html', + href: import.meta.env.BASE_URL + 'pdf-to-word.html', name: 'PDF to Word', icon: 'ph-microsoft-word-logo', subtitle: 'Convert PDF files to editable Word documents.', @@ -778,10 +778,10 @@ const baseCategories = [ name: 'Secure PDF', tools: [ { - href: import.meta.env.BASE_URL + 'encrypt-pdf.html', - name: 'Encrypt PDF', + href: import.meta.env.BASE_URL + 'protect-pdf.html', + name: 'Protect PDF', icon: 'ph-lock', - subtitle: 'Lock your PDF by adding a password.', + subtitle: 'Password protect a PDF with strong AES encryption.', }, { href: import.meta.env.BASE_URL + 'sanitize-pdf.html', @@ -790,10 +790,10 @@ const baseCategories = [ subtitle: 'Remove metadata, annotations, scripts, and more.', }, { - href: import.meta.env.BASE_URL + 'decrypt-pdf.html', - name: 'Decrypt PDF', + href: import.meta.env.BASE_URL + 'unlock-pdf.html', + name: 'Unlock PDF', icon: 'ph-lock-open', - subtitle: 'Unlock PDF by removing password protection.', + subtitle: 'Remove the password from a PDF so it opens freely.', }, { href: import.meta.env.BASE_URL + 'flatten-pdf.html', diff --git a/src/js/logic/pdf-to-docx-page.ts b/src/js/logic/pdf-to-word-page.ts similarity index 100% rename from src/js/logic/pdf-to-docx-page.ts rename to src/js/logic/pdf-to-word-page.ts diff --git a/src/js/logic/encrypt-pdf-page.ts b/src/js/logic/protect-pdf-page.ts similarity index 100% rename from src/js/logic/encrypt-pdf-page.ts rename to src/js/logic/protect-pdf-page.ts diff --git a/src/js/logic/decrypt-pdf-page.ts b/src/js/logic/unlock-pdf-page.ts similarity index 100% rename from src/js/logic/decrypt-pdf-page.ts rename to src/js/logic/unlock-pdf-page.ts diff --git a/src/js/utils/disabled-tools.ts b/src/js/utils/disabled-tools.ts index 5f35c622..cf759288 100644 --- a/src/js/utils/disabled-tools.ts +++ b/src/js/utils/disabled-tools.ts @@ -1,6 +1,18 @@ import type { AppConfig } from '@/types'; -const disabledToolsSet = new Set<string>(__DISABLED_TOOLS__); +const RENAMED_TOOL_IDS: Record<string, string> = { + 'decrypt-pdf': 'unlock-pdf', + 'encrypt-pdf': 'protect-pdf', + 'pdf-to-docx': 'pdf-to-word', +}; + +function normalizeToolId(toolId: string): string { + return RENAMED_TOOL_IDS[toolId] ?? toolId; +} + +const disabledToolsSet = new Set<string>( + __DISABLED_TOOLS__.map(normalizeToolId) +); let runtimeConfigLoaded = false; let editorDisabledCategories: string[] = []; @@ -23,7 +35,7 @@ export async function loadRuntimeConfig(): Promise<void> { if (Array.isArray(config.disabledTools)) { for (const toolId of config.disabledTools) { if (typeof toolId === 'string') { - disabledToolsSet.add(toolId); + disabledToolsSet.add(normalizeToolId(toolId)); } } } diff --git a/src/js/workflow/nodes/registry.ts b/src/js/workflow/nodes/registry.ts index 2525c2a3..48bdf156 100644 --- a/src/js/workflow/nodes/registry.ts +++ b/src/js/workflow/nodes/registry.ts @@ -557,7 +557,7 @@ export const nodeRegistry: Record<string, NodeRegistryEntry> = { icon: 'ph-lock', description: 'Encrypt PDF with password', factory: () => new EncryptNode(), - toolPageId: 'encrypt-pdf', + toolPageId: 'protect-pdf', }, DecryptNode: { label: 'Decrypt', @@ -565,7 +565,7 @@ export const nodeRegistry: Record<string, NodeRegistryEntry> = { icon: 'ph-lock-open', description: 'Remove PDF password protection', factory: () => new DecryptNode(), - toolPageId: 'decrypt-pdf', + toolPageId: 'unlock-pdf', }, SanitizeNode: { label: 'Sanitize', @@ -653,7 +653,7 @@ export const nodeRegistry: Record<string, NodeRegistryEntry> = { icon: 'ph-microsoft-word-logo', description: 'Convert PDF to Word document', factory: () => new PdfToDocxNode(), - toolPageId: 'pdf-to-docx', + toolPageId: 'pdf-to-word', }, PdfToXlsxNode: { label: 'PDF to XLSX', diff --git a/src/pages/add-attachments.html b/src/pages/add-attachments.html index df3cf972..b9f9f4d1 100644 --- a/src/pages/add-attachments.html +++ b/src/pages/add-attachments.html @@ -11,7 +11,7 @@ /> <meta name="description" - content="★ Add Attachments online free - Add attachments PDFs easily ★ No signup ★ Unlimited files ★ Privacy-first ★ Works in browser ★ Fast & secure" + content="Embed one or more files into your PDF. Free, no uploads, no signup. Runs entirely in your browser." /> <meta name="keywords" content="add attachments, online pdf" /> <meta name="author" content="BentoPDF" /> @@ -35,7 +35,7 @@ /> <meta property="og:description" - content="★ Add Attachments online free - Add attachments PDFs easily ★ No signup ★ Unlimited files ★ Privacy-first ★ Works in browser ★ Fast & secure" + content="Embed one or more files into your PDF. Free, no uploads, no signup. Runs entirely in your browser." /> <meta property="og:image" @@ -54,7 +54,7 @@ <meta name="twitter:title" content="Add Attachments Free" /> <meta name="twitter:description" - content="★ Add Attachments online free - Add attachments PDFs easily ★ No signup ★ Unlimited files ★ Privacy-first ★ Works in browser" + content="Embed one or more files into your PDF. Free, no uploads, no signup. Runs entirely in your browser." /> <meta name="twitter:image" @@ -68,10 +68,6 @@ <meta name="apple-mobile-web-app-title" content="Add Attachments" /> <title>Add Attachments to PDF - BentoPDF - @@ -389,32 +385,115 @@
          - Is add attachments really free? + What kinds of files can I embed in a PDF?

          - Yes! BentoPDF is 100% free with no hidden fees, no signup required, - and unlimited file processing. + Any file type: spreadsheets, images, ZIP archives, CAD drawings, + even executables. The tool doesn't inspect or convert the file; it + stores the bytes inside the PDF under the original file name, and + you can embed several files in one pass.

          - Are my files private and secure? + What's the difference between document-level and page-level + attachments?

          - Absolutely! All processing happens in your browser. Your files never - leave your device, ensuring complete privacy. + Document-level attachments belong to the PDF as a whole and appear + in the reader's attachments panel. Page-level attachments are tied + to the pages you list in the page range field (for example 1,3,5-7), + and the same file is attached to every page in that range. Document + level is the safer choice, since some viewers never show page-level + attachments.

          - Is there a file size limit? + Where do the attached files show up when someone opens the PDF?

          - No! Process files of any size, as many times as you want, completely - free. + In readers that have an attachments panel, such as Adobe Acrobat + Reader or Firefox's built-in viewer, they're listed by file name and + can be opened or saved from there. Viewers without that panel won't + show them at all, although the files are still inside the PDF. +

          +
          +
          + + Does embedding files make the PDF bigger? + + +

          + Yes, by roughly the size of each attachment, since the file's bytes + are stored inside the PDF. A 40 MB spreadsheet attached to a 1 MB + report yields a PDF of about 41 MB, so keep attachment size in mind + before emailing the result. +

          +
          +
          + + Is the file I attach uploaded anywhere when I embed it? + + +

          + No. The PDF and the attachments are read and combined in your + browser by the CoherentPDF WebAssembly module, and the result is + downloaded straight from the page. Nothing is sent to a server. +

          +
          +
          + + Why does the tool say an advanced processing module is required? + + +

          + Embedding uses the CoherentPDF (cpdf) module, which loads on demand + from a CDN the first time you use it rather than shipping with the + main site. If you self-host BentoPDF or work in an air-gapped setup, + you can point the tool at your own copy of the module on the + Advanced Features settings + page. +

          +
          +
          + + Can I remove an attachment later? + + +

          + Yes. + Edit Attachments + lists every embedded file and lets you remove individual ones or all + of them, and Extract Attachments saves them back out as separate + downloads. +

          +
          +
          + + Will attaching files break a digital signature on the PDF? + + +

          + Yes. Adding attachments rewrites the file, which invalidates any + existing digital signature. Attach the files first, then sign the + finished PDF with + Digital Sign PDF.

          diff --git a/src/pages/add-blank-page.html b/src/pages/add-blank-page.html index 054d4f3a..17cc878e 100644 --- a/src/pages/add-blank-page.html +++ b/src/pages/add-blank-page.html @@ -11,7 +11,7 @@ /> @@ -32,7 +32,7 @@ /> Add Blank Page - BentoPDF - @@ -377,32 +373,105 @@
          - Is add blank page really free? + Where will the blank page be inserted?

          - Yes! BentoPDF is 100% free with no hidden fees, no signup required, - and unlimited file processing. + The position number is how many existing pages come before the new + blank pages. Enter 0 to put them at the very start, 3 to insert them + after page 3, or the total page count to append them at the end.

          - Are my files private and secure? + What size are the blank pages?

          - Absolutely! All processing happens in your browser. Your files never - leave your device, ensuring complete privacy. + Each blank page copies the width and height of your document's first + page, so a Letter document gets Letter blanks and an A4 document + gets A4 blanks. If your PDF mixes page sizes, the blanks still match + page 1 rather than the pages next to them.

          - Is there a file size limit? + Can I add more than one blank page at a time?

          - No! Process files of any size, as many times as you want, completely - free. + Enter any count of 1 or more and all of them are inserted together + at the same position. To add blanks at several different spots, run + the tool again on the output, or use + PDF Multi Tool + to arrange pages visually. +

          +
          +
          + + Does it keep bookmarks and document properties? + + +

          + Page content, images, text, and annotations on the pages are kept as + they are. The document is rebuilt page by page, so bookmarks (the + outline panel) and properties such as title and author aren't + carried over to the new file. +

          +
          +
          + + Is the inserted page completely empty? + + +

          + Yes. It has no text, no page number, and no printed note, just a + white page of the same size as page 1. If you want page numbers on + it afterward, run the result through + Page Numbers. +

          +
          +
          + + Can I use this to make every chapter start on a right-hand page for + double-sided printing? + + +

          + You can, one position per run. Insert a blank after each chapter + that ends on an odd page, download, then repeat on the new file for + the next chapter. The output keeps the original filename, so rename + copies as you go to avoid mixing them up. +

          +
          +
          + + Can I add blank pages to a password-protected PDF? + + +

          + If the file needs a password to open, the tool asks for it before + reading the page count. The new file is saved without the password, + so protect it again afterward if you need to. +

          +
          +
          + + Is my PDF uploaded to add the page? + + +

          + No. The page count is read and the new document is assembled in your + browser with pdf-lib, a JavaScript PDF library, and the download + comes straight from memory. Nothing is sent to a server.

          diff --git a/src/pages/add-page-labels.html b/src/pages/add-page-labels.html index 30d36ceb..7caa68a6 100644 --- a/src/pages/add-page-labels.html +++ b/src/pages/add-page-labels.html @@ -465,39 +465,105 @@
          - What is a page label? + How do I label appendix pages A-1, A-2, A-3? -

          - A page label is the numbering shown by PDF readers in thumbnails, - page navigation, and print dialogs. It does not print new text onto - the page itself. +

          + Add a rule for the appendix page range, keep Decimal Arabic as the + style, and type A- in the Label Prefix field. With the default start + value of 1 the pages become A-1, A-2, A-3, and a second rule with + the prefix B- handles the next appendix.

          - Can I mix Roman numerals and normal numbers? + Can page numbering start at 0 or at a number other than 1? -

          - Yes. Add multiple rules, such as 1-4 with LowercaseRoman and 5-20 - with DecimalArabic. +

          + Each rule has a Start Value field that defaults to 1. Set it to 0 + for zero-based numbering, or to any other number, for example 15 so + a chapter extracted from a longer book keeps its original page + numbers.

          - Do my files stay private? + What does 'Continue numbering across disjoint ranges' do? -

          - Yes. The processing happens in your browser using CoherentPDF WASM. - Your PDF does not leave your device. +

          + Turn it on when one rule covers pages that aren't contiguous, such + as 1-9,30-40 or odd, and you want the labels to keep counting in + sequence across the gap. With it off, each separate block of pages + starts again from the start value. +

          +
          +
          + + What happens to the page labels the PDF already has? + + +

          + The 'Remove existing page labels' box is checked by default, so the + old labels are cleared before your rules are applied. Uncheck it if + you only want to relabel some pages and keep the existing labels on + the rest. +

          +
          +
          + + Which page range formats can I type? + + +

          + Leave the field empty to cover every page, or use forms like 1-4, 7, + odd, or 1-9,30-40. Page numbers refer to physical positions in the + file, not to labels the PDF may already display. +

          +
          +
          + + Can I add labels to a password-protected PDF? + + +

          + Not directly. The tool stops with a Protected PDF message, so remove + the password first with + Unlock PDF + and then upload the copy that no longer needs one. +

          +
          +
          + + Why does the tool ask me to configure CoherentPDF? + + +

          + Page labels are written by the CoherentPDF engine, which normally + loads from a CDN the first time you use the tool. If that default + has been turned off in a self-hosted build, you'll be prompted to + point + WASM Settings + at a copy of the library. +

          +
          +
          + + How do I check that the labels were applied? + + +

          + Open the downloaded PDF in a reader that displays page labels, such + as Adobe Acrobat or Firefox's built-in viewer, and look at the page + number box in the toolbar. It shows the label, for example iv or + A-1, instead of the plain page index.

          diff --git a/src/pages/add-stamps.html b/src/pages/add-stamps.html index 74428d51..b52b5011 100644 --- a/src/pages/add-stamps.html +++ b/src/pages/add-stamps.html @@ -11,7 +11,7 @@ /> @@ -32,7 +32,7 @@ />
          - Is add stamps really free? + What kind of stamps can I add with this tool?

          - Yes! BentoPDF is 100% free with no hidden fees, no signup required, - and unlimited file processing. + This tool places image stamps, so you pick an image file such as a + PNG or JPG (a company seal, an APPROVED graphic, a scanned notary + stamp) and drop it onto the page. For text-only marks like a + diagonal DRAFT label, + Add Watermark + is the better fit.

          - Are my files private and secure? + What does the Stamp Username field do?

          - Absolutely! All processing happens in your browser. Your files never - leave your device, ensuring complete privacy. + The name you enter is recorded on each stamp you create as its + author, so reviewers can see who placed it. Set it before you upload + the PDF. It's optional, and leaving it blank creates stamps without + a name attached.

          - Is there a file size limit? + Can I put the same stamp on every page at once?

          - No! Process files of any size, as many times as you want, completely - free. + No. Stamps are placed one at a time on the page you're viewing, and + you can move and resize each one before saving. If you need an + identical mark on all pages, use the image mode in + Add Watermark, which can apply one image to every page in a single step. +

          +
          +
          + + Are the stamps permanent, or can they be removed later? + + +

          + Stamps are saved as PDF stamp annotations, so a PDF editor can still + select, move, or delete them. If you want them merged into the page + content so they can't be lifted off, run the saved file through + Flatten PDF. +

          +
          +
          + + How do I move or resize a stamp after placing it? + + +

          + Click the stamp in the viewer to select it, then drag it to a new + position or pull its corner handles to change the size. Nothing is + final until you click Save Stamped PDF, so you can adjust as much as + you like first. +

          +
          +
          + + What's the difference between this and Sign PDF? + + +

          + Sign PDF + is built for signatures: you draw one, type one, or upload one and + place it on the page. Add Stamps is for reusable image marks such as + seals, RECEIVED stamps, or QC stamps, with your name recorded as the + author of each one. +

          +
          +
          + + Does the stamp tool work on password-protected PDFs? + + +

          + If the file needs a password to open, the tool asks for it before + loading the viewer. You need the open password; the tool doesn't + bypass encryption. +

          +
          +
          + + Is my document uploaded when I stamp it? + + +

          + No. The viewer, the stamp editor, and the export all run in your + browser, and the stamped PDF is written on your device. Nothing is + sent to a server, which matters when you're stamping contracts, + inspection reports, or notarized documents.

diff --git a/src/pages/add-watermark.html b/src/pages/add-watermark.html index e5095c3a..89406342 100644 --- a/src/pages/add-watermark.html +++ b/src/pages/add-watermark.html @@ -7,11 +7,11 @@ @@ -28,11 +28,11 @@ - + - Add Watermark - BentoPDF - + Watermark PDF Free - Add Text or Image Watermarks | BentoPDF @@ -776,32 +775,101 @@
- Is add watermark really free? + Can I watermark only certain pages of a PDF?

- Yes! BentoPDF is 100% free with no hidden fees, no signup required, - and unlimited file processing. + Yes. Type a range such as 1-3, 5, 7-9 in the Page Range field, or + leave it set to "all". If you want different text or a different + position on individual pages, uncheck "Apply to all pages" and use + the page arrows above the preview to set each page separately.

- Are my files private and secure? + How do I add a diagonal CONFIDENTIAL or DRAFT watermark across the + page?

- Absolutely! All processing happens in your browser. Your files never - leave your device, ensuring complete privacy. + Stay in Text mode, type the word, and raise the font size (10 to 200 + points, default 72) until it spans the page. The angle slider + already defaults to -45 degrees for the classic diagonal look, so + usually you only need to enlarge the text and drag it to the center + of the preview.

- Is there a file size limit? + Can I use a logo image as the watermark?

- No! Process files of any size, as many times as you want, completely - free. + Switch to Image mode and upload a PNG or JPG; other image formats + aren't accepted. A PNG with a transparent background blends best + with the page. You can scale it from 10% to 200%, set its opacity + and angle, and drag it into position on the preview. +

+
+
+ + What does the Tiled layout do? + + +

+ Tiled repeats the watermark across the whole page in a diagonal grid + that follows the rotation angle, so the mark runs edge to edge. The + horizontal and vertical gap sliders control the spacing between + tiles as a percentage of the watermark size. Lower the opacity when + tiling so the document underneath stays readable. +

+
+
+ + Can someone remove the watermark afterward? + + +

+ The watermark is drawn into the page content rather than added as a + separate annotation, so it can't be deleted with one click in a PDF + viewer. It isn't tamper-proof though. For a harder-to-strip result, + use Tiled mode, or check "Flatten watermark" to bake every page into + pixels, which also makes the document's text unselectable. +

+
+
+ + Does adding a watermark change the original text or image quality? + + +

+ No. The pages keep their original text, images, and dimensions, and + the watermark is placed on top, so text stays selectable and + searchable. The exception is the "Flatten watermark" option, which + re-renders every page as an image at 2.5x scale and removes + selectable text. +

+
+
+ + What opacity should I use for a watermark? + + +

+ The slider runs from 0.05 to 1 and defaults to 0.3. Values between + 0.2 and 0.4 keep the mark visible without hiding the content beneath + it; go higher only for small marks placed in a margin or corner. +

+
+
+ + Is my PDF uploaded when I add a watermark? + + +

+ No. The live preview, the drag-and-drop editor, and the final + rendering all run inside your browser with pdf-lib, so neither the + PDF nor a logo image you add leaves your device.

diff --git a/src/pages/adjust-colors.html b/src/pages/adjust-colors.html index f703ab7d..d9292a24 100644 --- a/src/pages/adjust-colors.html +++ b/src/pages/adjust-colors.html @@ -10,7 +10,7 @@ /> Adjust Colors - BentoPDF - @@ -467,7 +463,7 @@

Change PDF background

Text Color

@@ -486,32 +482,115 @@
- Is adjust colors really free? + How do I brighten a dark scanned PDF?

- Yes! BentoPDF is 100% free with no hidden fees, no signup required, - and unlimited file processing. + Move the Brightness slider (range -100 to +100) up to lighten the + page, and raise Contrast if the text still looks washed out. When + only the midtones are too dark, the Gamma slider (0.2 to 5.0) lifts + them without blowing out the white background. The preview updates + as you drag, so you can check the first page before applying the + settings to all of them.

- Are my files private and secure? + Can I convert a color PDF to grayscale with this tool?

- Absolutely! All processing happens in your browser. Your files never - leave your device, ensuring complete privacy. + Drag the Saturation slider all the way to -100 and every page + becomes grayscale, which also cuts ink use when printing. If you + don't need any of the other adjustments, the + grayscale conversion tool + does the same thing in one step.

- Is there a file size limit? + What do the hue, temperature, and tint sliders do?

- No! Process files of any size, as many times as you want, completely - free. + Hue Shift rotates every color around the color wheel by 0 to 360 + degrees while leaving whites, grays, and blacks untouched. + Temperature (-50 to +50) shifts the page toward blue on the cool end + or yellow-orange on the warm end, and Tint (-50 to +50) shifts + between green and magenta, which is useful for photos scanned with a + color cast. +

+
+
+ + Will the text still be selectable after adjusting colors? + + +

+ No. To apply the changes, each page is rendered to an image at 2x + resolution and saved into a new PDF, so the output is image-based + and text can't be selected or searched. Keep your original for + editing, or run the result through + OCR + to add a searchable text layer. +

+
+
+ + Why is my PDF larger after adjusting the colors? + + +

+ Every page is stored as a full-page PNG image instead of text and + vector drawing commands, so the file usually grows, especially for + text-heavy documents. Running the result through + Compress PDF + afterward brings the size back down. +

+
+
+ + Can I give a PDF a sepia or vintage look? + + +

+ Raise the Sepia slider (0 to 100) to add a brown tone; higher values + give a stronger antique look. Combine it with a small drop in + Contrast or Saturation to soften the result, and click Reset at any + point to return every slider to its default. +

+
+
+ + Does the preview show every page or only the first one? + + +

+ The live preview renders the first page only, so you can test + settings quickly. When you click Apply, the same settings are + processed on every page of the document and the adjusted PDF + downloads. +

+
+
+ + Is my PDF uploaded anywhere when I adjust its colors? + + +

+ No. The page rendering and the color math run in your browser, and + the adjusted PDF is assembled on your device, so the file never + leaves your computer.

diff --git a/src/pages/alternate-merge.html b/src/pages/alternate-merge.html index 367892f9..c37b4323 100644 --- a/src/pages/alternate-merge.html +++ b/src/pages/alternate-merge.html @@ -11,7 +11,7 @@ /> @@ -35,7 +35,7 @@ /> Alternate & Mix PDF Pages - BentoPDF - @@ -360,32 +356,116 @@
- Is alternate merge really free? + What does alternate merge do that a normal merge doesn't?

- Yes! BentoPDF is 100% free with no hidden fees, no signup required, - and unlimited file processing. + A normal merge appends whole files one after another. Alternate + merge takes page 1 from each file in turn, then page 2 from each, + and so on, so the pages of two or more PDFs are interleaved into a + single document. If you only need files back to back, use + Merge PDF.

- Are my files private and secure? + How do I fix a double-sided scan where the fronts and backs are in + separate PDFs?

- Absolutely! All processing happens in your browser. Your files never - leave your device, ensuring complete privacy. + Upload the fronts PDF first and the backs PDF second, then click Mix + Pages. The output alternates front 1, back 1, front 2, back 2 and so + on. If the backs were scanned last page first, flip that file with + Reverse Pages + before mixing.

- Is there a file size limit? + The fronts and backs are in the same PDF, not separate files. Which + tool do I need?

- No! Process files of any size, as many times as you want, completely - free. + This tool interleaves separate files. If one PDF holds all the + fronts followed by all the backs, + Duplex Collate + splits that single file at the midpoint and interleaves the two + halves, with an option to reverse the back block. +

+
+
+ + What happens if the PDFs have different page counts? + + +

+ Interleaving continues until the shorter file runs out, and the + remaining pages from the longer file are appended in order at the + end. No pages are dropped. +

+
+
+ + Can I interleave more than two PDFs? + + +

+ Any number of files from two upward. With three files the output + goes A1, B1, C1, A2, B2, C2 and so on, following the order shown in + the file list, which you can change by dragging the grip handles. +

+
+
+ + Does the output keep bookmarks and page numbers from the original + files? + + +

+ Bookmarks from each source file are carried into the mixed PDF. Page + labels are reset to a plain 1 to N sequence by default; turn on the + option to keep original page labels if you want each file's own + labels, which can produce duplicates such as two pages both labeled + 1. +

+
+
+ + Can I alternate pages from password-protected PDFs? + + +

+ If a file is encrypted you're asked for its password when it loads, + and the decrypted copy is used for mixing. The output isn't + encrypted, so use + Protect PDF + afterward if it needs a password again. +

+
+
+ + Are the PDFs uploaded to a server while they're being interleaved? + + +

+ No. The files are read in your browser and interleaved by a + WebAssembly build of cpdf running in a background worker on your + device, and the finished alternated-mixed.pdf is saved straight from + the browser.

diff --git a/src/pages/background-color.html b/src/pages/background-color.html index c6c93e5a..80a8373c 100644 --- a/src/pages/background-color.html +++ b/src/pages/background-color.html @@ -11,7 +11,7 @@ /> @@ -35,7 +35,7 @@ /> Change Background Color - BentoPDF - @@ -332,32 +328,107 @@
- Is background color really free? + How do I change the background color of a PDF without losing the + text?

- Yes! BentoPDF is 100% free with no hidden fees, no signup required, - and unlimited file processing. + Upload the PDF, pick a color, and the tool draws a solid rectangle + behind each page and places the original page content on top of it. + The text stays real text, so it remains selectable and searchable, + and the page dimensions don't change.

- Are my files private and secure? + Why didn't the background color show up on some pages?

- Absolutely! All processing happens in your browser. Your files never - leave your device, ensuring complete privacy. + The color sits underneath the existing content, so any page that + already has an opaque background covers it up. Scanned pages, which + are usually one full-page image, and pages with a drawn white + background are the most common cases.

- Is there a file size limit? + Does the color apply to every page or can I pick specific pages?

- No! Process files of any size, as many times as you want, completely - free. + There's no page range option, so the same color is applied to every + page in the document. To color only certain pages, pull them out + with + Split PDF, color that file, and merge it back. +

+
+
+ + What colors work best as a PDF background? + + +

+ Light, muted tones such as cream, ivory, or pale yellow keep black + text readable, which is why the default is a light yellow (#FFFFCC). + A dark background makes normal black text hard to read because the + text color isn't changed; use + Change Text Color + on the result if you want light text on a dark page. +

+
+
+ + Will links, form fields, or bookmarks survive the color change? + + +

+ No. Each page is re-embedded as a drawing on top of the color layer + and written into a new file, so link annotations, form fields, + comments, and bookmarks aren't carried over. Change the background + first and add those elements afterward. +

+
+
+ + Does changing the background turn my pages into images or make the + file bigger? + + +

+ Pages aren't rasterized. The tool works at the PDF object level and + only adds a filled rectangle per page, so fonts and vector graphics + stay intact and the file size stays close to the original. +

+
+
+ + Is my PDF uploaded when I change its background color? + + +

+ No. The color layer is added by code running in your browser and the + finished file is saved directly from the page to your device. The + document isn't sent to a server at any point. +

+
+
+ + Can I change the background color of a password-protected PDF? + + +

+ If the PDF needs a password to open, the tool prompts you for it and + then processes the file as usual. The output is saved without that + password, so protect it again with + Protect PDF + if you still need it locked.

diff --git a/src/pages/bates-numbering.html b/src/pages/bates-numbering.html index 81c328b9..09943d3a 100644 --- a/src/pages/bates-numbering.html +++ b/src/pages/bates-numbering.html @@ -476,33 +476,104 @@
- What is Bates numbering? + What does the Bates number look like on the page?

- Bates numbering is a method of indexing legal documents for easy - identification and retrieval. Each page receives a unique sequential - number, often combined with a prefix or suffix. + By default it's a six-digit zero-padded number such as 000001 placed + at the footer center in 10 pt Helvetica. Presets can add an exhibit + number, a case label, and a page number, for example Exhibit 1 Case + XYZ 000001 Page 1, and the preview box shows the exact text before + you process anything.

- Can I number multiple files at once? + Can I use my own prefix or case number instead of the presets?

- Yes! Upload multiple PDFs and the bates numbers will continue - sequentially across all files. Drag files to reorder them. + Yes. Pick Custom style and write a template with placeholders: + [BATES] for the sequential number, [PAGE] for the page number within + the file, [FILE] for the file counter, and [FILENAME] for the source + file name. A template like SMITH-[BATES] produces SMITH-000001, + SMITH-000002, and so on.

- Are my files secure? + Does the numbering continue across multiple PDFs or restart for each + file?

- All processing happens entirely in your browser. Your files never - leave your device. + It continues. If the first file has 30 pages and numbering starts at + 1, the second file begins at 000031, following the order of the file + list, which you can rearrange by dragging. There's no option to + restart the count per file; process the files separately if you need + that. +

+
+
+ + How many digits can the number have? + + +

+ Zero padding can be 3, 4, 5, or 6 digits, or turned off so 1, 2, 3 + print without leading zeros. The count itself isn't capped; if it + grows past the padding width, the extra digits are still printed. +

+
+
+ + Where does the stamp go, and will it cover my content? + + +

+ You choose one of six spots: header or footer, at the left, center, + or right. The margin scales with the page, roughly 4 percent of the + width or height with a floor of 8 points and a cap of 40, so the + stamp sits in the same relative place on Letter, A4, and oversized + exhibits. Existing content isn't shifted, so on pages printed edge + to edge the stamp can overlap it. +

+
+
+ + Are Bates numbers searchable text or an image? + + +

+ They're real text drawn in Helvetica, Times New Roman, or Courier, + so they can be selected, searched, and read by review software + without OCR. These are the built-in PDF standard fonts, which cover + Latin characters only, so a template containing other scripts will + fail. +

+
+
+ + Are my discovery documents uploaded to a server for stamping? + + +

+ No. Stamping happens inside your browser and the numbered files are + written straight to your downloads folder. Nothing about the + documents, the case name, or the numbering leaves the machine, which + matters for privileged material. +

+
+
+ + What do I get when I stamp several files at once? + + +

+ Each PDF is numbered as its own file and keeps its original name; a + single file downloads directly, and two or more download together as + bates_numbered.zip. The files aren't merged, so the page counts and + order inside each document stay as they were.

diff --git a/src/pages/bmp-to-pdf.html b/src/pages/bmp-to-pdf.html index cdf8ea43..7c78ff16 100644 --- a/src/pages/bmp-to-pdf.html +++ b/src/pages/bmp-to-pdf.html @@ -11,7 +11,7 @@ /> @@ -32,7 +32,7 @@ /> BMP to PDF - BentoPDF - @@ -326,32 +322,108 @@
- Is bmp to pdf really free? + Can I combine several BMP files into one PDF?

- Yes! BentoPDF is 100% free with no hidden fees, no signup required, - and unlimited file processing. + Yes. Every BMP you add becomes its own page in a single PDF, in the + order shown in the file list. There's no option to produce one PDF + per file, so convert files separately if you need them split.

- Are my files private and secure? + Why is the PDF smaller than my BMP files?

- Absolutely! All processing happens in your browser. Your files never - leave your device, ensuring complete privacy. + BMP stores uncompressed pixels, so the files are large. The + converter redraws each image and stores it in the PDF as lossless + PNG, which usually shrinks it considerably without changing a single + pixel.

- Is there a file size limit? + Is any image quality lost in the conversion?

- No! Process files of any size, as many times as you want, completely - free. + No. Pixels are stored losslessly and there's no quality setting on + this tool, so the output has the same resolution and colors as the + source. If you need a smaller file afterward, run the PDF through + Compress PDF. +

+
+
+ + What page size does the PDF get when I convert a BMP? + + +

+ Each page is sized to the image's pixel dimensions at one point per + pixel, so a 2480 by 3508 pixel scan produces a page about 34 by 49 + inches rather than A4. Viewers and printers scale it to fit, and + Fix Page Size + can resize every page to A4 or Letter afterward. +

+
+
+ + Why does it say one of my files is invalid? + + +

+ Images are decoded by your browser, which handles standard Windows + bitmaps. Unusual variants such as OS/2 headers or rare compression + modes can fail; re-saving the file as a standard 24-bit BMP or as + PNG in any image editor fixes it. +

+
+
+ + Can I mix BMP with JPG or PNG files? + + +

+ This tool accepts only .bmp files and skips anything else you add. + Use + Images to PDF + when you need to combine several formats into one document. +

+
+
+ + Does the BMP's DPI setting affect the result? + + +

+ No. The resolution stored in the file header is ignored and page + size comes purely from pixel count, so two images with the same + pixel dimensions produce identical pages regardless of their DPI. +

+
+
+ + Are my BMP files uploaded anywhere? + + +

+ No. Decoding uses your browser's own image support and the PDF is + assembled locally with pdf-lib, so scanner or medical imaging + exports never leave your computer.

diff --git a/src/pages/bookmark.html b/src/pages/bookmark.html index 485a2afc..d82eb23e 100644 --- a/src/pages/bookmark.html +++ b/src/pages/bookmark.html @@ -11,7 +11,7 @@ /> @@ -32,7 +32,7 @@ />
- Is bookmark really free? + How do I add bookmarks to a PDF that doesn't have any?

- Yes! BentoPDF is 100% free with no hidden fees, no signup required, - and unlimited file processing. + Upload the PDF, go to a page, type a title, and click Add to Page; + drag entries to nest or reorder them. Click Save PDF with Bookmarks + to download the result. For a printed contents page inside the + document rather than sidebar navigation, use + Table of Contents + instead.

- Are my files private and secure? + Will my existing bookmarks be kept?

- Absolutely! All processing happens in your browser. Your files never - leave your device, ensuring complete privacy. + Only if you check Auto-extract existing bookmarks before uploading, + or use the extract button afterward, so they load into the panel. + When you save, the panel's contents replace the PDF's bookmark tree + entirely, so anything not loaded into the editor is dropped.

- Is there a file size limit? + What is the CSV format for importing bookmarks?

- No! Process files of any size, as many times as you want, completely - free. + A header row followed by one line per bookmark with three columns: + title,page,level. Titles containing commas go in double quotes, page + is the 1-based page number, and level controls nesting, with the + lowest number for top-level entries and each deeper child adding + one. +

+
+
+ + Can a bookmark jump to a specific spot on a page instead of the top? + + +

+ Open the bookmark's edit dialog, turn on Set custom destination, and + either type X and Y coordinates plus a zoom percentage or click the + pick button and then click the exact spot on the page preview. The + bookmark is saved as an XYZ destination, which most readers honor. +

+
+
+ + Can I color or bold bookmarks? + + +

+ Each bookmark can be red, blue, green, yellow, purple, or a custom + hex color, and styled bold, italic, or bold italic. Turn on Batch + Mode to select several bookmarks and apply a color or style to all + of them at once. +

+
+
+ + How do I get bookmarks out of a PDF for editing in a spreadsheet? + + +

+ Load them with Auto-extract, then use Export to CSV or Export to + JSON; the file is named after your PDF with a -bookmarks suffix. The + CSV opens in Excel or Google Sheets, and once you've edited it you + can import it back and save a new PDF. +

+
+
+ + Does the editor work on password-protected PDFs? + + +

+ You'll be asked for the password when you upload the file, and the + editor opens once it's entered. The saved PDF is written without the + password, so protect it again afterward if you need to. +

+
+
+ + Is my PDF uploaded while I edit bookmarks? + + +

+ No. The page preview, the bookmark tree, and the final save are all + handled in your browser with PDF.js and pdf-lib, so the file never + leaves your computer.

diff --git a/src/pages/cbz-to-pdf.html b/src/pages/cbz-to-pdf.html index 72962f88..bcb24f52 100644 --- a/src/pages/cbz-to-pdf.html +++ b/src/pages/cbz-to-pdf.html @@ -11,7 +11,7 @@ /> @@ -32,7 +32,7 @@ /> CBZ to PDF - Convert XPS/OCBZ to PDF - BentoPDF - @@ -333,32 +329,103 @@
- Is cbz to pdf really free? + Does converting a CBZ to PDF reduce the image quality?

- Yes! BentoPDF is 100% free with no hidden fees, no signup required, - and unlimited file processing. + JPEG and PNG pages are copied into the PDF as they are, with no + re-encoding, so the artwork looks exactly like the original and the + file size stays about the same. Other formats such as WebP, GIF, or + BMP are decoded and re-saved as lossless PNG before embedding.

- Are my files private and secure? + How does the tool decide the page order?

- Absolutely! All processing happens in your browser. Your files never - leave your device, ensuring complete privacy. + Pages are sorted by filename using natural ordering, so page2.jpg + comes before page10.jpg. Files in subfolders are included and sorted + by their full path, and non-image files such as ComicInfo.xml are + ignored.

- Is there a file size limit? + What page size do the comic pages get in the PDF?

- No! Process files of any size, as many times as you want, completely - free. + Each page is sized to the pixel dimensions of its image, one point + per pixel, so a double-page spread comes out as a wide landscape + page and single pages stay portrait. There's no option to force one + size here; if you need uniform pages, run the result through + Fix Page Size. +

+
+
+ + Can I convert CBR files as well as CBZ? + + +

+ .cbr archives are accepted and can be mixed with .cbz files in the + same batch. CBR files are routed through the PyMuPDF engine, which + downloads on first use, so they take a little longer than CBZ files, + which are unpacked directly in the browser. +

+
+
+ + Which image formats inside the archive are supported? + + +

+ JPEG and PNG are embedded directly. GIF, BMP, WebP, AVIF, TIFF, + HEIC, and JXL are converted to PNG by your browser first, so those + less common formats only work if your browser can display them; + TIFF, HEIC, and JXL fail in some browsers. The converter checks the + actual image data rather than the extension, so a PNG named .jpg + still works. +

+
+
+ + Is there a limit on archive size or page count? + + +

+ A single CBZ can hold up to 2,000 images, with each image capped at + 100 MB and 500 MB of uncompressed image data per archive. Those + limits keep the browser from running out of memory, and they're far + above a typical comic issue. +

+
+
+ + What happens when I convert several comics at once? + + +

+ Each archive becomes its own PDF named after the original file. One + file downloads directly; two or more are bundled into + comic-converted.zip. +

+
+
+ + Are my comic files uploaded anywhere? + + +

+ No. CBZ archives are unzipped and rebuilt as PDFs entirely inside + your browser, and CBR files are handled by an engine that also runs + locally. Nothing from your collection leaves your device.

diff --git a/src/pages/change-permissions.html b/src/pages/change-permissions.html index 0d03155d..04201e8d 100644 --- a/src/pages/change-permissions.html +++ b/src/pages/change-permissions.html @@ -11,7 +11,7 @@ /> @@ -35,7 +35,7 @@ /> Change PDF Permissions - Manage PDF Security - BentoPDF - @@ -445,32 +441,111 @@
- Is change permissions really free? + What is the difference between a user password and an owner + password?

- Yes! BentoPDF is 100% free with no hidden fees, no signup required, - and unlimited file processing. + The user password is required to open the PDF at all. The owner + password protects the permission settings and is what someone needs + to change or remove them later. Set only an owner password if anyone + should be able to open the file but with printing, copying, or + editing restricted.

- Are my files private and secure? + Why does the tool ask for an owner password when I set permissions?

- Absolutely! All processing happens in your browser. Your files never - leave your device, ensuring complete privacy. + Permission flags are only enforced when an owner password exists; + without one, PDF readers treat the file as unrestricted. The tool + therefore requires a New Owner Password whenever you set permissions + or a user password.

- Is there a file size limit? + How do I stop people from copying text or printing my PDF?

- No! Process files of any size, as many times as you want, completely - free. + Uncheck "Allow Copying Text" and "Allow Printing", enter a New Owner + Password, and click Change Permissions. Adobe Reader and other + compliant viewers will then block those actions. Some third-party + tools ignore permission flags, so for sensitive material consider + rasterizing the pages + as well. +

+
+
+ + Which permissions can I control? + + +

+ Seven checkboxes: printing, copying text, modifying content, + annotating, filling forms, document assembly (inserting, deleting, + or rotating pages), and page extraction. An unchecked box means the + action is not allowed. +

+
+
+ + What encryption does Change Permissions use? + + +

+ The output is encrypted with 256-bit AES. That also makes this a + quick way to upgrade an old RC4-encrypted PDF: enter its current + password, set new passwords, and the file is rewritten with AES-256. +

+
+
+ + Can I change permissions on a PDF that is already password + protected? + + +

+ Yes, enter the existing password in the Current Password field. The + tool opens the file with it, then re-encrypts it with your new + passwords and permission settings; a wrong current password produces + an error and nothing is changed. +

+
+
+ + How do I remove all restrictions instead of changing them? + + +

+ Leave both new password fields empty and click Change Permissions. + The output is fully decrypted with no passwords and no permission + flags. If you don't have the current password, use + Remove Restrictions + instead, which works without one when the PDF opens freely. +

+
+
+ + Is my PDF or its owner password sent anywhere when I change + permissions? + + +

+ No. The encryption is done by QPDF compiled to WebAssembly inside + your browser tab, so the file and every password you type stay on + your device.

diff --git a/src/pages/combine-single-page.html b/src/pages/combine-single-page.html index 58e4ffc8..a0f6bd19 100644 --- a/src/pages/combine-single-page.html +++ b/src/pages/combine-single-page.html @@ -11,7 +11,7 @@ /> @@ -35,7 +35,7 @@ /> Combine to Single Page - BentoPDF - @@ -409,32 +405,100 @@
- Is combine single page really free? + How do I merge all pages of a PDF into one long page?

- Yes! BentoPDF is 100% free with no hidden fees, no signup required, - and unlimited file processing. + Upload the PDF, keep Layout Direction set to Vertical, and click the + process button. Every page is placed top to bottom on one continuous + page, with the output width matching the widest source page and + narrower pages centered.

- Are my files private and secure? + Can I put the pages side by side instead of stacked?

- Absolutely! All processing happens in your browser. Your files never - leave your device, ensuring complete privacy. + Choose Horizontal (Left to Right) in Layout Direction. Pages are + laid out in order from left to right on a single wide page, and + pages shorter than the tallest one are centered vertically.

- Is there a file size limit? + Can I add a gap or a line between the pages?

- No! Process files of any size, as many times as you want, completely - free. + Spacing (0 by default) adds a gap between pages, measured in the + PDF's own units where 72 equals one inch, and Background Color fills + that gap. Turn on Add Separator Lines to draw a line through the + middle of each gap, with its own thickness (0.5 units and up, in + steps of 0.5) and color. +

+
+
+ + Does the background color apply to the whole page or only the gaps? + + +

+ It fills the whole output page underneath the source pages, so it + shows in the spacing between pages and in any margin where a + narrower page is centered. With white selected, the default, no fill + is drawn at all. +

+
+
+ + Will the text in the combined page still be selectable? + + +

+ No. Each source page is rendered to an image at 2x resolution and + drawn onto the new page, so the result is a picture of your pages + rather than live text. Keep the original PDF if you need to copy or + search text later. +

+
+
+ + Is there a limit to how many pages I can stitch together? + + +

+ The tool doesn't set one, but the output grows with every page you + add: a 100-page document becomes a page roughly 100 pages tall. Some + readers struggle with very large pages; Adobe Reader, for example, + doesn't display pages larger than 200 inches on a side. +

+
+
+ + What is a single long-page PDF useful for? + + +

+ It suits scrolling previews for the web, design mockups, comic + strips, and storyboards where the reader scrolls instead of flipping + pages. If you want several pages printed on one sheet in a grid, + N-Up PDF + is the better fit. +

+
+
+ + Does the combined PDF get uploaded to a server? + + +

+ No. Rendering the pages and building the new single-page PDF both + happen in your browser, and the file stays on your device the whole + time.

diff --git a/src/pages/compare-pdfs.html b/src/pages/compare-pdfs.html index 408e5d6b..3e802fd6 100644 --- a/src/pages/compare-pdfs.html +++ b/src/pages/compare-pdfs.html @@ -11,7 +11,7 @@ /> @@ -32,7 +32,7 @@ /> Compare PDFs - BentoPDF - - + {{> navbar }} +

+ PDF Workflow Builder Free Online - Chain PDF Tools Into One Run +

+
@@ -405,6 +411,8 @@
+ {{> footer-compact }} +
+ + +{{/unless}} From e01f80867b22ecee6a827c4434669bbdc9ccf1c7 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 8 Sep 2026 19:55:41 +0000 Subject: [PATCH 19/71] @franklioxygen has signed the CLA in alam00000/bentopdf#865 --- signatures/cla.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/signatures/cla.json b/signatures/cla.json index 17ea0b1a..4c29e7fb 100644 --- a/signatures/cla.json +++ b/signatures/cla.json @@ -591,6 +591,14 @@ "created_at": "2026-09-03T12:19:31Z", "repoId": 1074785178, "pullRequestNo": 757 + }, + { + "name": "franklioxygen", + "id": 2637636, + "comment_id": 5591002573, + "created_at": "2026-09-08T19:55:31Z", + "repoId": 1074785178, + "pullRequestNo": 865 } ] } \ No newline at end of file From 597e36904e8ccacc0af98463589805cb9ee910d2 Mon Sep 17 00:00:00 2001 From: alam00000 Date: Thu, 10 Sep 2026 13:42:57 +0530 Subject: [PATCH 20/71] feat: add URL redirection rules --- nginx.conf | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/nginx.conf b/nginx.conf index fc0700aa..7afc77f0 100644 --- a/nginx.conf +++ b/nginx.conf @@ -43,6 +43,21 @@ http { return 301 /uk$1; } + if ($request_uri ~ ^/en/?(\?.*)?$) { + return 301 /$1; + } + if ($request_uri ~ ^/en/(.+)$) { + return 301 /$1; + } + + if ($request_uri ~ ^(/(?:ar|be|da|de|es|fr|id|it|ko|nl|pt|ru|sk|sv|tr|vi|zh|zh-TW|uk|ja))?/src/pages/([a-z0-9][a-z0-9-]*)\.html(\?.*)?$) { + return 301 $1/$2$3; + } + + if ($request_uri ~ ^(/(?:ar|be|da|de|es|fr|id|it|ko|nl|pt|ru|sk|sv|tr|vi|zh|zh-TW|uk|ja))?/change-text-color(?:\.html)?/?(\?.*)?$) { + return 301 $1/text-color$2; + } + if ($request_uri ~ ^/tools/$) { return 301 /tools; } From c5ec840d10f6e37a9239a765333569972364d496 Mon Sep 17 00:00:00 2001 From: alam00000 Date: Mon, 14 Sep 2026 02:37:46 +0530 Subject: [PATCH 21/71] feat: add testimonial with real users --- about.html | 197 +++++++++++++++------ blog/author-alam.html | 13 +- blog/edit-pdf-without-uploading.html | 3 +- index.html | 246 ++++++++++++++++++++++----- public/locales/ar/common.json | 3 +- public/locales/be/common.json | 3 +- public/locales/da/common.json | 3 +- public/locales/de/common.json | 3 +- public/locales/en/common.json | 19 ++- public/locales/es/common.json | 3 +- public/locales/fr/common.json | 5 +- public/locales/id/common.json | 3 +- public/locales/it/common.json | 3 +- public/locales/ja/common.json | 1 + public/locales/ko/common.json | 5 +- public/locales/nl/common.json | 3 +- public/locales/pt/common.json | 3 +- public/locales/ru/common.json | 3 +- public/locales/sk/common.json | 3 +- public/locales/sv/common.json | 3 +- public/locales/tr/common.json | 3 +- public/locales/uk/common.json | 5 +- public/locales/vi/common.json | 3 +- public/locales/zh-TW/common.json | 1 + public/locales/zh/common.json | 1 + scripts/generate-blog.mjs | 1 + src/css/landing.css | 132 ++++++++++++-- src/partials/footer.html | 2 +- src/partials/navbar.html | 10 +- 29 files changed, 537 insertions(+), 146 deletions(-) diff --git a/about.html b/about.html index 4a37e12c..be49594a 100644 --- a/about.html +++ b/about.html @@ -5,7 +5,7 @@ - About BentoPDF - Privacy-First Free PDF Tools | Our Mission + About BentoPDF - Privacy-First Free PDF Tools | Our Story navbar }}
-
+
-
-
+
+

- We believe PDF tools should be - fast, private, and free. + Hi, I'm Alam. + I build BentoPDF.

-

- No compromises. +

+ Alam + GitHub + LinkedIn + X +
+
+
+

+ BentoPDF started off as just a simple internal tool I used for + quickly merging and splitting PDFs. +

+

+ At some point, I decided to + share it on Reddit. Someone in the comments + asked if it was open source. I thought, “Why not?” So a couple of weeks later, I + put the code on GitHub. +

+

+ I posted it on + r/selfhosted + the next day, and that's when things really started to take off. +

+

+ I honestly never thought BentoPDF would grow into what it is + today. It started as a little tool I made for myself, and + somehow it turned into a much bigger project used by people all + over the world.

+
+
+ 15K+GitHub stars +
+
+ 10M+Downloads +
+
+ 1.3K+Forks +
+ + 60+Contributors + +
+
+

+ I don't build BentoPDF alone anymore. More than 60 people have + contributed code, translations and fixes, and thousands more have + starred it, shared it, reported bugs and asked for features. Thank + you. +

+

Enough about me. Here's more about BentoPDF.

+
-

Our Mission

+

+ Our + Mission +

-
- - BentoPDF - Explore All Tools -
@@ -136,17 +221,20 @@

- Privacy First. Always.PDF tools should be + fast, private, and free.

+

+ No compromises. +

- In an era where data is a commodity, we take a different - approach. All processing for BentoPDF tools happens locally in - your browser. This means your files never touch our servers, we - never see your documents, and we don't track what you do. Your - documents remain completely and unequivocally private. It's not - just a feature; it's our foundation. + Every BentoPDF tool runs locally in your browser. Your files are + never uploaded, nobody else sees your documents, and nothing + tracks what you do.

@@ -183,20 +271,19 @@

Built for Speed

- No waiting for uploads or downloads to a server. By processing - files directly in your browser using modern web technologies - like WebAssembly, we offer unparalleled speed for all our tools. + There's no upload or download step. Files are processed right in + your browser using WebAssembly, so you're never waiting on a + server.

-

Completely Free

+

Free to Use

- No trials, no subscriptions, no hidden fees, and no "premium" - features held hostage. We believe powerful PDF tools should be a - public utility, not a profit center. + Every tool is free, with no trials, no subscriptions and no + watermarks. Development is funded by commercial licenses.

@@ -205,21 +292,19 @@ No Account Required

- Start using any tool immediately. We don't need your email, a - password, or any personal information. Your workflow should be - frictionless and anonymous. + Open any tool and start right away. No email, no password, no + personal information.

- Open Source Spirit + Open Source

- Built with transparency in mind. We leverage incredible - open-source libraries like PDF-lib and PDF.js, and believe in - the community-driven effort to make powerful tools accessible to - everyone. + The code is public on GitHub under AGPL-3.0, so you can check + exactly how your files are handled. It builds on open-source + projects like PDF.js, pdf-lib, qpdf and LibreOffice.

@@ -270,8 +355,20 @@ "@context": "https://schema.org", "@type": "AboutPage", "name": "About BentoPDF", - "description": "Learn about BentoPDF's mission to provide free, privacy-first PDF tools", - "url": "https://www.bentopdf.com/about" + "description": "How BentoPDF started, told by its creator Alam", + "url": "https://www.bentopdf.com/about", + "mainEntity": { + "@type": "Person", + "name": "Alam", + "url": "https://www.bentopdf.com/blog/author-alam", + "image": "https://www.bentopdf.com/images/author-alam.jpg", + "jobTitle": "Creator and maintainer of BentoPDF", + "sameAs": [ + "https://github.com/alam00000", + "https://www.linkedin.com/in/abdullah-alam01/", + "https://x.com/alamdraws" + ] + } } diff --git a/blog/author-alam.html b/blog/author-alam.html index 7881ecc0..804e17aa 100644 --- a/blog/author-alam.html +++ b/blog/author-alam.html @@ -95,13 +95,19 @@ rel="me noopener" class="text-indigo-300 hover:text-indigo-400" >GitHub - and + >, LinkedIn + and + X.

@@ -133,7 +139,8 @@ "jobTitle": "Creator and maintainer of BentoPDF", "sameAs": [ "https://github.com/alam00000", - "https://www.linkedin.com/in/abdullah-alam01/" + "https://www.linkedin.com/in/abdullah-alam01/", + "https://x.com/alamdraws" ] } } diff --git a/blog/edit-pdf-without-uploading.html b/blog/edit-pdf-without-uploading.html index dd3297dd..8b0fa39e 100644 --- a/blog/edit-pdf-without-uploading.html +++ b/blog/edit-pdf-without-uploading.html @@ -390,7 +390,8 @@ "url": "https://www.bentopdf.com/blog/author-alam", "sameAs": [ "https://github.com/alam00000", - "https://www.linkedin.com/in/abdullah-alam01/" + "https://www.linkedin.com/in/abdullah-alam01/", + "https://x.com/alamdraws" ] }, "publisher": { diff --git a/index.html b/index.html index 6adb458a..0f33e5a4 100644 --- a/index.html +++ b/index.html @@ -305,50 +305,6 @@
-
-

- Two new - engines -

- -
-

Get Started with @@ -677,6 +633,208 @@ +
+

+ What Our + Users + Say +

+
+
+
+ My dad is a very frequent user at 70+ yo and I never ever received + a call or a question or a complaint about this app, unlike many + others 😂 it just works and never gives headaches of any kind! +
+
+ u/Cyberpunk627 + Reddit +
+
+
+
+ I work in indigenous healthcare. … I need total confidentiality of + my data, as you can imagine, and I need to split pdfs. Bento is + the first time this trivial task has become possible + confidentially. +
+
+ ballantynedewolf + GitHub +
+
+
+
+ Really awesome tool. I’m in the legal field and have been stuck + with Adobe because they do have pretty robust redaction tools, + although it is super clunky and resource intensive. Bento is + quickly gaining market share in my legal stack. +
+
+ u/sewersurfin + Reddit +
+
+
+
+ BentoPDF provides tools that I have ended up using on a daily + basis, and I can do it secure in the knowledge that my documents + are remaining private. It just works. +
+
+ Fubarpie + Trustpilot +
+
+
+
+ Huge fan of Bento PDF. We don't have a decent PDF suite at work so + most of my colleagues turn to online tools that are likely to + collect your data. I selfhosted Bento for my team and their + reactions are very positive. +
+
+ Schlemmy + Lemmy +
+
+
+
+ I've used it before for a job application! I needed to send them + sensitive data. Tysm! Great intuitive UI, does what it says, and + it's fast. 5/5 +
+
+ Lemminary + Lemmy +
+
+
+
+ BentoPDF is fantastic, I never knew something like this existed. … + I fired Bento up and was done in under a minute. +
+
+ suicidaleggroll + Lemmy +
+
+
+
+ A great open source software tool that has helped me deal with + PDF's on numerous occasions. Support and use this project. It + needs the love and attention to grow even bigger. +
+
+ Jeffrey Jansma + Trustpilot +
+
+
+
+ Fantastic project. The workflow builder literally just saved me + half a day of my life so huge thanks. +
+
+ nomandera + GitHub +
+
+
+
+ Thank you so much for this. We just started using it at our + school. +
+
+ Limeade3425 + Lemmy +
+
+
+
+ My first reaction after trying Bento was "this is magic, how does + this work?" +
+
+ darcmage + Lemmy +
+
+
+
+ BentoPDF has covered 100% of my PDF needs and represents + impressive software engineering indeed! +
+
+ PrestonMcAfee + GitHub +
+
+
+
+