diff --git a/README.md b/README.md index 844a34fe..a13c83ba 100644 --- a/README.md +++ b/README.md @@ -192,7 +192,7 @@ Stirling-PDF currently supports 37 languages! | Language | Progress | | -------------------------------------------- | -------------------------------------- | | Arabic (العربية) (ar_AR) | ![98%](https://geps.dev/progress/98) | -| Azerbaijani (Azərbaycan Dili) (az_AZ) | ![76%](https://geps.dev/progress/76) | +| Azerbaijani (Azərbaycan Dili) (az_AZ) | ![97%](https://geps.dev/progress/97) | | Basque (Euskara) (eu_ES) | ![54%](https://geps.dev/progress/54) | | Bulgarian (Български) (bg_BG) | ![94%](https://geps.dev/progress/94) | | Catalan (Català) (ca_CA) | ![88%](https://geps.dev/progress/88) | @@ -206,23 +206,23 @@ Stirling-PDF currently supports 37 languages! | German (Deutsch) (de_DE) | ![97%](https://geps.dev/progress/97) | | Greek (Ελληνικά) (el_GR) | ![95%](https://geps.dev/progress/95) | | Hindi (हिंदी) (hi_IN) | ![93%](https://geps.dev/progress/93) | -| Hungarian (Magyar) (hu_HU) | ![96%](https://geps.dev/progress/96) | +| Hungarian (Magyar) (hu_HU) | ![95%](https://geps.dev/progress/95) | | Indonesian (Bahasa Indonesia) (id_ID) | ![95%](https://geps.dev/progress/95) | | Irish (Gaeilge) (ga_IE) | ![86%](https://geps.dev/progress/86) | -| Italian (Italiano) (it_IT) | ![98%](https://geps.dev/progress/98) | +| Italian (Italiano) (it_IT) | ![99%](https://geps.dev/progress/99) | | Japanese (日本語) (ja_JP) | ![83%](https://geps.dev/progress/83) | | Korean (한국어) (ko_KR) | ![93%](https://geps.dev/progress/93) | -| Norwegian (Norsk) (no_NB) | ![86%](https://geps.dev/progress/86) | -| Polish (Polski) (pl_PL) | ![95%](https://geps.dev/progress/95) | +| Norwegian (Norsk) (no_NB) | ![85%](https://geps.dev/progress/85) | +| Polish (Polski) (pl_PL) | ![94%](https://geps.dev/progress/94) | | Portuguese (Português) (pt_PT) | ![95%](https://geps.dev/progress/95) | | Portuguese Brazilian (Português) (pt_BR) | ![96%](https://geps.dev/progress/96) | | Romanian (Română) (ro_RO) | ![88%](https://geps.dev/progress/88) | | Russian (Русский) (ru_RU) | ![95%](https://geps.dev/progress/95) | -| Serbian Latin alphabet (Srpski) (sr_LATN_RS) | ![69%](https://geps.dev/progress/69) | +| Serbian Latin alphabet (Srpski) (sr_LATN_RS) | ![68%](https://geps.dev/progress/68) | | Simplified Chinese (简体中文) (zh_CN) | ![89%](https://geps.dev/progress/89) | | Slovakian (Slovensky) (sk_SK) | ![80%](https://geps.dev/progress/80) | | Spanish (Español) (es_ES) | ![96%](https://geps.dev/progress/96) | -| Swedish (Svenska) (sv_SE) | ![95%](https://geps.dev/progress/95) | +| Swedish (Svenska) (sv_SE) | ![94%](https://geps.dev/progress/94) | | Thai (ไทย) (th_TH) | ![94%](https://geps.dev/progress/94) | | Traditional Chinese (繁體中文) (zh_TW) | ![96%](https://geps.dev/progress/96) | | Turkish (Türkçe) (tr_TR) | ![90%](https://geps.dev/progress/90) | diff --git a/src/main/resources/messages_ar_AR.properties b/src/main/resources/messages_ar_AR.properties index aff70807..1202616b 100644 --- a/src/main/resources/messages_ar_AR.properties +++ b/src/main/resources/messages_ar_AR.properties @@ -958,6 +958,8 @@ multiTool.moveLeft=تحريك إلى اليسار multiTool.moveRight=تحريك إلى اليمين multiTool.delete=حذف multiTool.dragDropMessage=الصفحات المحددة +multiTool.undo=تراجع +multiTool.redo=إعادة إجراء #multiTool-advert multiTool-advert.message=هذه الميزة متوفرة في صفحة الأدوات المتعددة لدينا. اطلع عليها للحصول على واجهة مستخدم محسّنة لكل صفحة وميزات إضافية! diff --git a/src/main/resources/messages_az_AZ.properties b/src/main/resources/messages_az_AZ.properties index 4b2fcf55..2aca8d4d 100644 --- a/src/main/resources/messages_az_AZ.properties +++ b/src/main/resources/messages_az_AZ.properties @@ -34,10 +34,10 @@ sizes.small=Kiçik sizes.medium=Orta sizes.large=Böyük sizes.x-large=Ekstra Böyük -error.pdfPassword=PDF sənədi şifrələnmişdir və şifrə təmin edilməmişdir və ya yanlışdır. +error.pdfPassword=PDF sənədi şifrlənmişdir və şifr təmin edilməmişdir və ya yanlışdır. delete=Sil username=İstifadəçi Adı -password=Şifrə +password=Şifr welcome=Xoş gəldiniz property=Xüsusiyyət black=Qara @@ -53,11 +53,11 @@ no=Xeyr changedCredsMessage=Etibarnamələr dəyişdirildi! notAuthenticatedMessage=İstifadəçinin kimliyi təsdiqlənməyib. userNotFoundMessage=İstifadəçi tapılmadı. -incorrectPasswordMessage=Cari şifrə yanlışdır. +incorrectPasswordMessage=Cari şifr yanlışdır. usernameExistsMessage=İstifadəçi adı mövcuddur. invalidUsernameMessage=Yanlış istifadəçi adı, istifadəçi adı sadəcə hərflərdən, rəqəmlərdən və @._+- xüsusi simvollarından ibarət ola bilər və ya düzgün email ünvanı olmalıdır. -invalidPasswordMessage=Şifrə boş olmamalıdır, başlanğıc və sonunda boşluqdan istifadə edilməməlidir. -confirmPasswordErrorMessage=Yeni Şifrə və Yeni Şifrəni Doğrula uyğun olmalıdır. +invalidPasswordMessage=Şifr boş olmamalıdır, başlanğıc və sonunda boşluqdan istifadə edilməməlidir. +confirmPasswordErrorMessage=Yeni Şifr və Yeni Şifri Doğrula uyğun olmalıdır. deleteCurrentUserMessage=Hazırda daxil olmuş istifadəçini silmək mümkün deyil. deleteUsernameExistsMessage=İstifadəçi adı mövcud deyildir və silinə bilməz. downgradeCurrentUserMessage=Cari istifadəçinin rolunu aşağı salmaq mümkün deyil @@ -70,8 +70,8 @@ oops=Oops! help=Yardım goHomepage=Ana səhifəyə get joinDiscord=Discord serverimizə qatıl -seeDockerHub=Docker Hub'a bax -visitGithub=Github Repository'ə Baş Çək +seeDockerHub=Docker Hub-a bax +visitGithub=Github Repository-ə Baş Çək donate=İanə Ver color=Rəng sponsor=Sponsor @@ -126,9 +126,9 @@ enterpriseEdition.ssoAdvert=Daha çox istifadəçi-idarəetmə xüsusiyyətləri ################# # Analytics # ################# -analytics.title=Stirling PDF'i daha yaxşı etmək istəyirsinizmi? +analytics.title=Stirling PDF-i daha yaxşı etmək istəyirsinizmi? analytics.paragraph1=Stirling PDF bizə məhsulu inkişaf etdirməyə kömək etmək üçün analitikaya üstünlük verib. Biz heç bir şəxsi məlumatı və ya fayl məzmununu izləmirik. -analytics.paragraph2=Zəhmət olmasa, Stringling-PDF'ə inkişaf etməkdə və istifadəçilərimizi daha yaxşı anlamaqda yardım etmək üçün analitikanı aktivləşdirməyi nəzərə alın. +analytics.paragraph2=Zəhmət olmasa, Stringling-PDF-ə inkişaf etməkdə və istifadəçilərimizi daha yaxşı anlamaqda yardım etmək üçün analitikanı aktivləşdirməyi nəzərə alın. analytics.enable=Analitikanı aktivləşdir analytics.disable=Analitikanı deaktivləşdir analytics.settings=Analitikanın parametrlərini config/settings.yml faylından dəyişə bilərsiniz. @@ -141,11 +141,11 @@ navbar.darkmode=Qaranlıq Tema navbar.language=Dillər navbar.settings=Parametrlər navbar.allTools=Alətlər -navbar.multiTool=Çox Alət +navbar.multiTool=Multi-Alət navbar.search=Axtar navbar.sections.organize=Təşkil et -navbar.sections.convertTo=PDF'ə Çevir -navbar.sections.convertFrom=PDF'dən Çevir +navbar.sections.convertTo=PDF-ə Çevir +navbar.sections.convertFrom=PDF-dən Çevir navbar.sections.security=İmza & Təhlükəsizlik navbar.sections.advance=Qabaqcıl navbar.sections.edit=Bax & Redaktə et @@ -171,11 +171,11 @@ settings.cacheInputs.help=Gələcək əməliyyatlar üçün əvvəllər istifad changeCreds.title=Məlumatları dəyişdirin changeCreds.header=Hesab Məlumatlarınızı Yeniləyin -changeCreds.changePassword=Siz standart giriş məlumatlarından istifadə edirsiniz. Zəhmət olmasa, yeni şifrə daxil edin +changeCreds.changePassword=Siz standart giriş məlumatlarından istifadə edirsiniz. Zəhmət olmasa, yeni şifr daxil edin changeCreds.newUsername=Yeni İstifadəçi Adı -changeCreds.oldPassword=Cari Şifrə -changeCreds.newPassword=Yeni Şifrə -changeCreds.confirmNewPassword=Yeni Şifrəni Təsdiqləyin +changeCreds.oldPassword=Cari Şifr +changeCreds.newPassword=Yeni Şifr +changeCreds.confirmNewPassword=Yeni Şifri Təsdiqləyin changeCreds.submit=Dəyişiklikləri Təsdiqlə @@ -186,11 +186,11 @@ account.adminSettings=Admin Paramterləri - İstifadəçilər Əlavə Et və Onl account.userControlSettings=İstifadəçi İdarəetmə Parametrləri account.changeUsername=İstifadəçi Adını Dəyiş account.newUsername=Yeni İstifadəçi Adı -account.password=Təsdiqləmə Şifrəsi -account.oldPassword=Keçmiş Şifrə -account.newPassword=Yeni Şifrə -account.changePassword=Şifrəni Dəyiş -account.confirmNewPassword=Yeni Şifrəni Təsdiqlə +account.password=Təsdiqləmə Şifri +account.oldPassword=Keçmiş Şifr +account.newPassword=Yeni Şifr +account.changePassword=Şifri Dəyiş +account.confirmNewPassword=Yeni Şifri Təsdiqlə account.signOut=Çıxış account.yourApiKey=Sizin API Açarınız account.syncTitle=Brauzer parametrlərini hesabla sinxronlaşdırın @@ -543,7 +543,7 @@ login.title=Daxil olun login.header=Daxil olun login.signin=Daxil olun login.rememberme=Məni xatırla -login.invalid=Etibarsız istifadəçi adı və ya şifrə. +login.invalid=Etibarsız istifadəçi adı və ya şifr. login.locked=Sizin hesabınız kilidlənmişdir. login.signinTitle=Zəhmət olmasa, daxil olun login.ssoSignIn=Single Sign-on vasitəsilə daxil olun @@ -581,8 +581,8 @@ showJS.submit=Göstər #pdfToSinglePage -pdfToSinglePage.title=PDF'dən Tək Səhifəyə -pdfToSinglePage.header=PDF'dən Tək Səhifəyə +pdfToSinglePage.title=PDF-dən Tək Səhifəyə +pdfToSinglePage.header=PDF-dən Tək Səhifəyə pdfToSinglePage.submit=Tək Səhifəyə Çevir @@ -601,8 +601,8 @@ getPdfInfo.downloadJson=JSON yüklə #markdown-to-pdf -MarkdownToPDF.title=Markdown'dan PDF'ə -MarkdownToPDF.header=Markdown'dan PDF'ə +MarkdownToPDF.title=Markdown-dan PDF-ə +MarkdownToPDF.header=Markdown-dan PDF-ə MarkdownToPDF.submit=Çevir MarkdownToPDF.help=İş davam edir MarkdownToPDF.credit=WeasyPrint İstifadə Edir @@ -617,8 +617,8 @@ URLToPDF.credit=WeasyPrint İstifadə Edir #html-to-pdf -HTMLToPDF.title=HTML'dən PDF'ə -HTMLToPDF.header=HTML'dən PDF'ə +HTMLToPDF.title=HTML-dən PDF-ə +HTMLToPDF.header=HTML-dən PDF-ə HTMLToPDF.help=HTML fayllarını və tərkibində mütləq html/css/images və s. olan ZIP fayllarını qəbul edir HTMLToPDF.submit=Çevir HTMLToPDF.credit=WeasyPrint İstifadə Edir @@ -656,14 +656,14 @@ AddStampRequest.submit=Təsdiqlə #sanitizePDF -sanitizePDF.title=PDF'i Təmizlə +sanitizePDF.title=PDF-i Təmizlə sanitizePDF.header=PDF Faylını Təmizlə sanitizePDF.selectText.1=JavaScript Fəaliyyətlərini Sil sanitizePDF.selectText.2=Daxil Edilmiş Faylları Sil sanitizePDF.selectText.3=Metadatanı Sil sanitizePDF.selectText.4=Linkləri Sil sanitizePDF.selectText.5=Şriftləri Sil -sanitizePDF.submit=PDF'i Təmizlə +sanitizePDF.submit=PDF-i Təmizlə #addPageNumbers @@ -683,7 +683,7 @@ addPageNumbers.submit=Səhifə Nömrələri əlavə edin #auto-rename auto-rename.title=Avtomatik Yenidən Adlandır -auto-rename.header=Pdf'in Adını Avtomatik Yenidən Adlandır +auto-rename.header=Pdf-in Adını Avtomatik Yenidən Adlandır auto-rename.submit=Avtomatik Yenidən Adlandır @@ -698,7 +698,7 @@ adjustContrast.download=Yüklə #crop crop.title=Kəs -crop.header=Pdf'ləri Kəs +crop.header=Pdf-ləri Kəs crop.submit=Təsdiq Et @@ -722,8 +722,8 @@ pipeline.title=Pipeline #pageLayout -pageLayout.title=Çoxsəhifəli Sxem -pageLayout.header=Çoxsəhifəli Sxem +pageLayout.title=Çoxsəhifəli Tərtibat +pageLayout.header=Çoxsəhifəli Tərtibat pageLayout.pagesPerSheet=Vərəqdəki Səhifə Sayı: pageLayout.addBorder=Çərçivə Əlavə Et pageLayout.submit=Təsdiq et @@ -739,22 +739,22 @@ scalePages.submit=Təsdiq edin #certSign -certSign.title=Certificate Signing -certSign.header=Sign a PDF with your certificate (Work in progress) -certSign.selectPDF=Select a PDF File for Signing: -certSign.jksNote=Note: If your certificate type is not listed below, please convert it to a Java Keystore (.jks) file using the keytool command line tool. Then, choose the .jks file option below. -certSign.selectKey=Select Your Private Key File (PKCS#8 format, could be .pem or .der): -certSign.selectCert=Select Your Certificate File (X.509 format, could be .pem or .der): -certSign.selectP12=Select Your PKCS#12 Keystore File (.p12 or .pfx) (Optional, If provided, it should contain your private key and certificate): -certSign.selectJKS=Select Your Java Keystore File (.jks or .keystore): -certSign.certType=Certificate Type -certSign.password=Enter Your Keystore or Private Key Password (If Any): -certSign.showSig=Show Signature -certSign.reason=Reason -certSign.location=Location -certSign.name=Name -certSign.showLogo=Show Logo -certSign.submit=Sign PDF +certSign.title=Sertifikatla İmzala +certSign.header=PDF-i Sertifikatınızla İmzalayın (İşlənilir) +certSign.selectPDF=İmzalamaq üçün PDF Faylı seçin: +certSign.jksNote=Note: Əgər sertifikatınızın tipi aşağıda göstərilməyibsə, zəhmət olmasa "Keytool command line tool" istifadə edərək onu "Java Keystroke" (.jks) faylına çevirin. Sonra, aşağıdan .jks faylını seçin. +certSign.selectKey=Şəxsi Açar faylınızı seçin (PKCS#8 format, .pem və ya .der ola bilər): +certSign.selectCert=Sertifikat faylınızı seçin (X.509 format, .pem və ya .der ola bilər): +certSign.selectP12=PKCS#12 Keystore Faylınızı seçin (.p12 və ya .pfx) (İstəyə bağlı, əgər təmin olunarsa, şəxsi açar və sertifikatınızı ehtiva etməlidir): +certSign.selectJKS=Java Keystore Faylınızı seçin (.jks və ya .keystore): +certSign.certType=Sertifikat Tipi +certSign.password=Keystore və ya Şəxsi Açar daxil edin (Əgər varsa): +certSign.showSig=İmzanı Göstər +certSign.reason=Səbəb +certSign.location=Məkan +certSign.name=Ad +certSign.showLogo=Loqonu Göstər +certSign.submit=PDF-i İmzala #removeCertSign @@ -765,13 +765,13 @@ removeCertSign.submit=İmzanı silin #removeBlanks -removeBlanks.title=Remove Blanks -removeBlanks.header=Remove Blank Pages -removeBlanks.threshold=Pixel Whiteness Threshold: -removeBlanks.thresholdDesc=Threshold for determining how white a white pixel must be to be classed as 'White'. 0 = Black, 255 pure white. -removeBlanks.whitePercent=White Percent (%): -removeBlanks.whitePercentDesc=Percent of page that must be 'white' pixels to be removed -removeBlanks.submit=Remove Blanks +removeBlanks.title=Boş Səhifələri Sil +removeBlanks.header=Boş SƏhifələri Silir +removeBlanks.threshold=Minimal Piksel Bəyazlığı: +removeBlanks.thresholdDesc=Pikselin "Ağ" hesab olunması üçün minimal nə qədər bəyaz olmalı olduğunu təyin edin. 0 = Qara, 255 Ağappaq. +removeBlanks.whitePercent=Bəyaz Faizi (%): +removeBlanks.whitePercentDesc=Silinmək üçün səhifənin neçə faizi "ağ" piksellərdən təşkil olunmalıdır +removeBlanks.submit=Boş Səhifələri Sil #removeAnnotations @@ -781,16 +781,16 @@ removeAnnotations.submit=Sil #compare -compare.title=Compare -compare.header=Compare PDFs -compare.highlightColor.1=Highlight Color 1: -compare.highlightColor.2=Highlight Color 2: -compare.document.1=Document 1 -compare.document.2=Document 2 -compare.submit=Compare -compare.complex.message=One or both of the provided documents are large files, accuracy of comparison may be reduced -compare.large.file.message=One or Both of the provided documents are too large to process -compare.no.text.message=One or both of the selected PDFs have no text content. Please choose PDFs with text for comparison. +compare.title=Müqayisə Et +compare.header=PDF-ləri Müqayisə Et +compare.highlightColor.1=Önə Çıxarma Rəngi 1: +compare.highlightColor.2=Önə Çıxarma Rəngi 2: +compare.document.1=Sənəd 1 +compare.document.2=Sənəd 2 +compare.submit=Müqayisə Et +compare.complex.message=Fayllardan biri və ya ikisi də böyük fayldır. Müqayisə effektivliyi azala bilər. +compare.large.file.message=Fayllardan biri və ya ikisi də işləmək üçün çox böyükdür. +compare.no.text.message=Fayllardan birində və ya ikisində də mətn məzmunu yoxdur. Zəhmət olmasa, müqayisə üçün mətn məzmunlu PDF seçin. #BookToPDF BookToPDF.title=Kitabları və Komiksləri PDF-ə @@ -818,12 +818,12 @@ sign.save=İmzanı yadda Saxla sign.personalSigs=Şəxsi İmzalar sign.sharedSigs=Paylaşılan İmzalar sign.noSavedSigs=Saxlanmış imza tapılmadı -sign.addToAll=Add to all pages -sign.delete=Delete -sign.first=First page -sign.last=Last page -sign.next=Next page -sign.previous=Previous page +sign.addToAll=Bütün səhiflərə əlavə et +sign.delete=Sil +sign.first=İlk səhifə +sign.last=Son səhifə +sign.next=Növbəti səhifə +sign.previous=Əvvəlki səhifə #repair repair.title=Bərpa Et @@ -839,37 +839,37 @@ flatten.submit=Düzləşdirin #ScannerImageSplit -ScannerImageSplit.selectText.1=Angle Threshold: -ScannerImageSplit.selectText.2=Sets the minimum absolute angle required for the image to be rotated (default: 10). -ScannerImageSplit.selectText.3=Tolerance: -ScannerImageSplit.selectText.4=Determines the range of color variation around the estimated background color (default: 30). -ScannerImageSplit.selectText.5=Minimum Area: -ScannerImageSplit.selectText.6=Sets the minimum area threshold for a photo (default: 10000). -ScannerImageSplit.selectText.7=Minimum Contour Area: -ScannerImageSplit.selectText.8=Sets the minimum contour area threshold for a photo -ScannerImageSplit.selectText.9=Border Size: -ScannerImageSplit.selectText.10=Sets the size of the border added and removed to prevent white borders in the output (default: 1). -ScannerImageSplit.info=Python is not installed. It is required to run. +ScannerImageSplit.selectText.1=Bucaq Aşağı Limiti: +ScannerImageSplit.selectText.2=Şəklin fırladılması üçün lazım olan minimal mütləq bucağı təyin edir (defolt: 10). +ScannerImageSplit.selectText.3=Rəng Toleransı: +ScannerImageSplit.selectText.4=Təxmin olunan arxaplan rənginin ətrafındakı rəng fərqliliyi intervalını təyin edir (defolt: 30). +ScannerImageSplit.selectText.5=Minimal Sahə: +ScannerImageSplit.selectText.6=Foto üçün minimal sahənin aşağı limitini təyin edir (defolt: 10000). +ScannerImageSplit.selectText.7=Minimal Kontur Sahəsi: +ScannerImageSplit.selectText.8=Fotonun kontur sahəsi üçün minimal aşağı limiti təyin edir +ScannerImageSplit.selectText.9=Sərhəd Ölçüsü: +ScannerImageSplit.selectText.10=Faylda ağ sərhədlərin olmasının qarşısını almaq üçün əlavə ediləcək sərhədin ölçüsünü təyin edir (defolt: 1). +ScannerImageSplit.info=Python yüklənməyib. İşə salmaq üçün Python lazımdır. #OCR -ocr.title=OCR / Scan Cleanup -ocr.header=Cleanup Scans / OCR (Optical Character Recognition) -ocr.selectText.1=Select languages that are to be detected within the PDF (Ones listed are the ones currently detected): -ocr.selectText.2=Produce text file containing OCR text alongside the OCR'ed PDF -ocr.selectText.3=Correct pages were scanned at a skewed angle by rotating them back into place -ocr.selectText.4=Clean page so its less likely that OCR will find text in background noise. (No output change) -ocr.selectText.5=Clean page so its less likely that OCR will find text in background noise, maintains cleanup in output. -ocr.selectText.6=Ignores pages that have interactive text on them, only OCRs pages that are images -ocr.selectText.7=Force OCR, will OCR Every page removing all original text elements -ocr.selectText.8=Normal (Will error if PDF contains text) -ocr.selectText.9=Additional Settings -ocr.selectText.10=OCR Mode -ocr.selectText.11=Remove images after OCR (Removes ALL images, only useful if part of conversion step) -ocr.selectText.12=Render Type (Advanced) -ocr.help=Please read this documentation on how to use this for other languages and/or use not in docker -ocr.credit=This service uses qpdf and Tesseract for OCR. -ocr.submit=Process PDF with OCR +ocr.title=OST (OCR) / Skan Təmizləmə +ocr.header=Skanları Təmizlə / OST (Optik Simvol Tanınması) +ocr.selectText.1=PDF-də aşkar olunacaq dilləri seçin (Göstərilmiş dillər hazırda aşkar olunmuşlardır): +ocr.selectText.2=OST-lənmiş PDF ilə yanaşı daxilində OST edilmiş mətn olan PDF yaradın +ocr.selectText.3=Əyri skan olunmuş səhifələri yerinə fırladaraq düzəldin +ocr.selectText.4=OST-in arxaplandakı artıq mətni aşkar etməsinin qarşısını almaq üçün səhifəni təmizləyin. (Çıxış dəyişmir) +ocr.selectText.5=OST-in arxaplandakı artıq mətni aşkar etməsinin qarşısını almaq üçün səhifəni təmizləyin, təmizləməni çıxışa verilən faylda saxlayır. +ocr.selectText.6=Üzərində interaktiv yazı olan səhifələri nəzərə almır, yalnız şəkil olan səhifələri OST edir. +ocr.selectText.7=OST-ə məcbur et, bütün orijinal mətn elementlərini silərək hər səhifəni OST edir +ocr.selectText.8=Normal (PDF-də mətn varsa, xəta verəcək) +ocr.selectText.9=Əlavə Parametrlər +ocr.selectText.10=OST (OCR) Rejimi +ocr.selectText.11=OST-dən sonra şəkilləri sil (BÜTÜN şəkilləri silir, ancaq çevirmə prosesinin bir hissəsi olduqda işə yarayır) +ocr.selectText.12=Render Tipi (Qabaqcıl) +ocr.help=Bunu digər dillər üçün necə istifadə etmək və/və ya docker-də istifadə etməmək üçün bu dokumentasiyanı oxuyun +ocr.credit=Bu servis OST (OCR) üçün "OCRmyPDF" və "Tesseract" istifadə edir. +ocr.submit=PDF-i OST ilə işlə #extractImages @@ -890,15 +890,15 @@ fileToPDF.submit=PDF-ə Çevir #compress -compress.title=Compress -compress.header=Compress PDF -compress.credit=This service uses qpdf for PDF Compress/Optimisation. -compress.selectText.1=Manual Mode - From 1 to 4 -compress.selectText.2=Optimization level: -compress.selectText.3=4 (Terrible for text images) -compress.selectText.4=Auto mode - Auto adjusts quality to get PDF to exact size -compress.selectText.5=Expected PDF Size (e.g. 25MB, 10.8MB, 25KB) -compress.submit=Compress +compress.title=Sıxışdır +compress.header=PDF-i Sıxışdır +compress.credit=Bu servis PDF sıxışdırılması/Optimizasiyası üçün Ghostscript istifadə edir. +compress.selectText.1=Manual Mod - 1-dən 4-ə +compress.selectText.2=Optimizasiya səviyyəsi: +compress.selectText.3=4 (Mətn şəkilləri üçün yaxşı deyil) +compress.selectText.4=Avto mod - PDF-in dəqiq ölçüsünü əldə etmək üçün keyfiyyəti avtomatik tənzimləyir +compress.selectText.5=Gözlənilən PDF Ölçüsü (məsələn, 25MB, 10.8MB, 25KB) +compress.submit=Sıxışdır #Add image @@ -919,35 +919,35 @@ merge.submit=Birləşdirin #pdfOrganiser -pdfOrganiser.title=Page Organiser -pdfOrganiser.header=PDF Page Organiser -pdfOrganiser.submit=Rearrange Pages -pdfOrganiser.mode=Mode -pdfOrganiser.mode.1=Custom Page Order -pdfOrganiser.mode.2=Reverse Order -pdfOrganiser.mode.3=Duplex Sort -pdfOrganiser.mode.4=Booklet Sort -pdfOrganiser.mode.5=Side Stitch Booklet Sort -pdfOrganiser.mode.6=Odd-Even Split -pdfOrganiser.mode.7=Remove First -pdfOrganiser.mode.8=Remove Last -pdfOrganiser.mode.9=Remove First and Last -pdfOrganiser.mode.10=Odd-Even Merge -pdfOrganiser.placeholder=(e.g. 1,3,2 or 4-8,2,10-12 or 2n-1) +pdfOrganiser.title=Səhifə Tənzimləyicisi +pdfOrganiser.header=PDF Səhifə Tənzimləyicisi +pdfOrganiser.submit=Səhifələri Yenidən Təşkil Edin +pdfOrganiser.mode=Rejim +pdfOrganiser.mode.1=Fərdi Səhifə Düzülüşü +pdfOrganiser.mode.2=Tərs Düzülüş +pdfOrganiser.mode.3=İkitərəfli Çeşidləmə +pdfOrganiser.mode.4=Kitabça Çeşidləmə +pdfOrganiser.mode.5=Yan Tikiş Kitabçasının Çeşidlənməsi +pdfOrganiser.mode.6=Tək-Cüt Bölünmə +pdfOrganiser.mode.7=Birincini Sil +pdfOrganiser.mode.8=Sonuncunu Sil +pdfOrganiser.mode.9=Birinci və Sonuncunu Sil +pdfOrganiser.mode.10=Tək-Cüt Birləşdirmə +pdfOrganiser.placeholder=(məs., 1,3,2 və ya 4-8,2,10-12 və ya 2n-1) #multiTool -multiTool.title=PDF Multi Tool -multiTool.header=PDF Multi Tool -multiTool.uploadPrompts=File Name -multiTool.selectAll=Select All -multiTool.deselectAll=Deselect All -multiTool.selectPages=Page Select -multiTool.selectedPages=Selected Pages -multiTool.page=Page -multiTool.deleteSelected=Delete Selected -multiTool.downloadAll=Export -multiTool.downloadSelected=Export Selected +multiTool.title=PDF Multi-Alət +multiTool.header=PDF Multi-Alət +multiTool.uploadPrompts=Fayl Adı +multiTool.selectAll=Hamısını Seç +multiTool.deselectAll=Hamısını Seçməni Ləğv Et +multiTool.selectPages=Səhifə Seçimi +multiTool.selectedPages=Seçilmiş Səhifələr +multiTool.page=Səhifə +multiTool.deleteSelected=Seçilmişi Sil +multiTool.downloadAll=İxrac Et +multiTool.downloadSelected=Seçilmişi İxrac Et multiTool.insertPageBreak=Insert Page Break multiTool.addFile=Add File @@ -957,10 +957,12 @@ multiTool.split=Split multiTool.moveLeft=Move Left multiTool.moveRight=Move Right multiTool.delete=Delete -multiTool.dragDropMessage=Page(s) Selected +multiTool.dragDropMessage=Seçilmiş Səhifə(lər) +multiTool.undo=Undo +multiTool.redo=Redo #multiTool-advert -multiTool-advert.message=This feature is also available in our multi-tool page. Check it out for enhanced page-by-page UI and additional features! +multiTool-advert.message=Bu xüsusiyyət bizim multi-alət səhifəmizdə də mövcuddur. Əlavə xüsusiyyətlər və səhifə-səhifə interfeys üçün sınaqdan keçirin! #view pdf viewPdf.title=PDF-ə baxın @@ -982,32 +984,32 @@ rotate.submit=Fırladın #split-pdfs -split.title=Split PDF -split.header=Split PDF -split.desc.1=The numbers you select are the page number you wish to do a split on -split.desc.2=As such selecting 1,3,7-9 would split a 10 page document into 6 separate PDFS with: -split.desc.3=Document #1: Page 1 -split.desc.4=Document #2: Page 2 and 3 -split.desc.5=Document #3: Page 4, 5, 6 and 7 -split.desc.6=Document #4: Page 8 -split.desc.7=Document #5: Page 9 -split.desc.8=Document #6: Page 10 -split.splitPages=Enter pages to split on: -split.submit=Split +split.title=PDF-i Bölün +split.header=PDF-i Bölün +split.desc.1=Seçdiyiniz Nömrələr Bölmək İstədiyiniz Səhifə Nömrəsidir +split.desc.2=Beləliklə, 1,3,7-9 Seçimi 10 Səhifəlik Sənədi 6 Ayrı PDF-ə Böləcək: +split.desc.3=Sənəd #1: Səhifə 1 +split.desc.4=Sənəd #2: Səhifə 2 və 3 +split.desc.5=Sənəd #3: Səhifə 4, 5, 6 və 7 +split.desc.6=Sənəd #4: Səhifə 8 +split.desc.7=Sənəd #5: Səhifə 9 +split.desc.8=Sənəd #6: Səhifə 10 +split.splitPages=Bölünəcək Səhifələri Daxil Edin: +split.submit=Bölün #merge -imageToPDF.title=Image to PDF -imageToPDF.header=Image to PDF -imageToPDF.submit=Convert -imageToPDF.selectLabel=Image Fit Options -imageToPDF.fillPage=Fill Page -imageToPDF.fitDocumentToImage=Fit Page to Image -imageToPDF.maintainAspectRatio=Maintain Aspect Ratios -imageToPDF.selectText.2=Auto rotate PDF -imageToPDF.selectText.3=Multi file logic (Only enabled if working with multiple images) -imageToPDF.selectText.4=Merge into single PDF -imageToPDF.selectText.5=Convert to separate PDFs +imageToPDF.title=Şəkli PDF-ə +imageToPDF.header=Şəkli PDF-ə +imageToPDF.submit=Çevir +imageToPDF.selectLabel=Şəkil Uyğunluğu Seçimləri +imageToPDF.fillPage=Səhifəni Doldur +imageToPDF.fitDocumentToImage=Şəklə Uyğun Səhifə +imageToPDF.maintainAspectRatio=Aspekt Nisbətlərini Qoruyun +imageToPDF.selectText.2=PDF-i Avtomatik Fırlat +imageToPDF.selectText.3=Çoxsaylı Fayl Məntiqi (Yalnız Birdən Çox Şəkil İlə İşləyərkən Aktivdir) +imageToPDF.selectText.4=Tək Bir PDF-ə Birləşdir +imageToPDF.selectText.5=Ayrı PDF-lərə Çevirin #pdfToImage @@ -1026,97 +1028,97 @@ pdfToImage.info=Python Yüklü Deyil.WebP Çevirməsi Üçün Vacibdir #addPassword -addPassword.title=Add Password -addPassword.header=Add password (Encrypt) -addPassword.selectText.1=Select PDF to encrypt -addPassword.selectText.2=User Password -addPassword.selectText.3=Encryption Key Length -addPassword.selectText.4=Higher values are stronger, but lower values have better compatibility. -addPassword.selectText.5=Permissions to set (Recommended to be used along with Owner password) -addPassword.selectText.6=Prevent assembly of document -addPassword.selectText.7=Prevent content extraction -addPassword.selectText.8=Prevent extraction for accessibility -addPassword.selectText.9=Prevent filling in form -addPassword.selectText.10=Prevent modification -addPassword.selectText.11=Prevent annotation modification -addPassword.selectText.12=Prevent printing -addPassword.selectText.13=Prevent printing different formats -addPassword.selectText.14=Owner Password -addPassword.selectText.15=Restricts what can be done with the document once it is opened (Not supported by all readers) -addPassword.selectText.16=Restricts the opening of the document itself -addPassword.submit=Encrypt +addPassword.title=Şifr Əlavə Et +addPassword.header=Şifr Əlavə Et (Şifrləmə) +addPassword.selectText.1=Şifrlənəcək PDF-i seç +addPassword.selectText.2=İstifadəçi Şifri +addPassword.selectText.3=Şifrləmə Açarı Uzunluğu +addPassword.selectText.4=Böyük dəyərlər daha güclüdür, lakin kiçik dəyərlərin uyğunluğu yüksəkdir. +addPassword.selectText.5=Təyin olunacaq icazə (Sahib (Owner) Şifri ilə birgə istifadə olunması tövsiyə olunur.) +addPassword.selectText.6=Sənədin strukturunun dəyişilməsinin qarşısını al +addPassword.selectText.7=Məzmun xaric edilməsinin qarşısını al +addPassword.selectText.8=Əlçatanlıq üçün xaricetmənin qarşısını al +addPassword.selectText.9=Anketin doldurulmasının qarşısını al +addPassword.selectText.10=Modifikasiyanın qarşısını al +addPassword.selectText.11=Sitat modifikasiyasının qarşısını al +addPassword.selectText.12=Çap etmənin qarşısını al +addPassword.selectText.13=Müxtəlif formatların çap edilməsinin qarşısını al +addPassword.selectText.14=Sahib Şifri +addPassword.selectText.15=Sənəd açıldıqdan sonra onunla nə edilə biləcəyini limitləndir (Bütün oxuyucular dəstəkləmir) +addPassword.selectText.16=Sənədin özünün açılmağını limitləndirir +addPassword.submit=Şifrlə #watermark -watermark.title=Add Watermark -watermark.header=Add Watermark -watermark.selectText.1=Select PDF to add watermark to: -watermark.selectText.2=Watermark Text: -watermark.selectText.3=Font Size: -watermark.selectText.4=Rotation (0-360): -watermark.selectText.5=widthSpacer (Space between each watermark horizontally): -watermark.selectText.6=heightSpacer (Space between each watermark vertically): -watermark.selectText.7=Opacity (0% - 100%): -watermark.selectText.8=Watermark Type: -watermark.selectText.9=Watermark Image: -watermark.selectText.10=Convert PDF to PDF-Image -watermark.submit=Add Watermark -watermark.type.1=Text -watermark.type.2=Image +watermark.title=Watermark Əlavə Et +watermark.header=Watermark Əlavə Et +watermark.selectText.1=Watermark əlavə olunacaq PDF-i seç +watermark.selectText.2=Watermark Mətni: +watermark.selectText.3=Şrift Ölçüsü: +watermark.selectText.4=Fırlatma (0-360): +watermark.selectText.5=enBoşluq (Üfuqi olaraq watermark-lar arasındakı məsafə): +watermark.selectText.6=uzunluqBoşluq (Şaquli olaraq watermark-lar arasındakı məsafə): +watermark.selectText.7=Şəffaflıq (0% - 100%): +watermark.selectText.8=Watermark Tipi: +watermark.selectText.9=Watermark Şəkili: +watermark.selectText.10=PDF-i PDF-Şəkil-ə çevir +watermark.submit=Watermark Əlavə Et +watermark.type.1=Mətn +watermark.type.2=Şəkil #Change permissions -permissions.title=Change Permissions -permissions.header=Change Permissions -permissions.warning=Warning to have these permissions be unchangeable it is recommended to set them with a password via the add-password page -permissions.selectText.1=Select PDF to change permissions -permissions.selectText.2=Permissions to set -permissions.selectText.3=Prevent assembly of document -permissions.selectText.4=Prevent content extraction -permissions.selectText.5=Prevent extraction for accessibility -permissions.selectText.6=Prevent filling in form -permissions.selectText.7=Prevent modification -permissions.selectText.8=Prevent annotation modification -permissions.selectText.9=Prevent printing -permissions.selectText.10=Prevent printing different formats -permissions.submit=Change +permissions.title=İcazələri Dəyişdir +permissions.header=İcazələri Dəyişdir +permissions.warning=Bu İcazələrin Dəyişməz Olması İlə Bağlı Xəbərdarlıq Edərək, Onları Parol Əlavə Et Səhifəsi Vasitəsilə Parolla Təyin Etmək Tövsiyə Olunur. +permissions.selectText.1=İcazələri Dəyişdirmək Üçün PDF-i Seç +permissions.selectText.2=Tənzimlənmiş İcazələr +permissions.selectText.3=Sənədin Yığılmasının Qarşısını Al +permissions.selectText.4=Məzmunun Çıxarılmasının Qarşısını Al +permissions.selectText.5=Əlçatanlıq Üçün Çıxarılmasının Qarşısını Alın +permissions.selectText.6=Formanın Doldurulmasının Qarşısını Alır +permissions.selectText.7=Modifikasiyanın Qarşısını Al +permissions.selectText.8=Annotasiyanın Dəyişdirilməsinin Qarşısını Almaq +permissions.selectText.9=Çapın Qarşısını Al +permissions.selectText.10=Fərqli Formatlarda Çapın Qarşısını Al +permissions.submit=Dəyiş #remove password -removePassword.title=Remove password -removePassword.header=Remove password (Decrypt) -removePassword.selectText.1=Select PDF to Decrypt -removePassword.selectText.2=Password -removePassword.submit=Remove +removePassword.title=Şifri Sil +removePassword.header=Şifri Sil (Deşifr) +removePassword.selectText.1=Deşifr Üçün PDF-i Seç +removePassword.selectText.2=Şifr +removePassword.submit=Sil #changeMetadata -changeMetadata.title=Change Metadata -changeMetadata.header=Change Metadata -changeMetadata.selectText.1=Please edit the variables you wish to change -changeMetadata.selectText.2=Delete all metadata -changeMetadata.selectText.3=Show Custom Metadata: -changeMetadata.author=Author: -changeMetadata.creationDate=Creation Date (yyyy/MM/dd HH:mm:ss): -changeMetadata.creator=Creator: -changeMetadata.keywords=Keywords: -changeMetadata.modDate=Modification Date (yyyy/MM/dd HH:mm:ss): -changeMetadata.producer=Producer: -changeMetadata.subject=Subject: -changeMetadata.trapped=Trapped: -changeMetadata.selectText.4=Other Metadata: -changeMetadata.selectText.5=Add Custom Metadata Entry -changeMetadata.submit=Change +changeMetadata.title=Metadata-nı Dəyiş +changeMetadata.header=Metadata-nı Dəyiş +changeMetadata.selectText.1=Dəyişmək istədiyiniz dəyişənləri redaktə edin +changeMetadata.selectText.2=Bütün Metadata-nı Sil +changeMetadata.selectText.3=Fərdi Metadatanı göstərin: +changeMetadata.author=Müəllif: +changeMetadata.creationDate=Yaradılma Tarixi (yyyy/MM/dd HH:mm:ss): +changeMetadata.creator=Yaradıcı: +changeMetadata.keywords=Açar Sözlər: +changeMetadata.modDate=Dəyişiklik Tarixi (yyyy/MM/dd HH:mm:ss): +changeMetadata.producer=İstehsalçı: +changeMetadata.subject=Mövzu: +changeMetadata.trapped=Tələ: +changeMetadata.selectText.4=Digər Metadata: +changeMetadata.selectText.5=Xüsusi Metadata girişi əlavə edin +changeMetadata.submit=Dəyiş #pdfToPDFA -pdfToPDFA.title=PDF To PDF/A -pdfToPDFA.header=PDF To PDF/A -pdfToPDFA.credit=This service uses qpdf for PDF/A conversion -pdfToPDFA.submit=Convert -pdfToPDFA.tip=Currently does not work for multiple inputs at once -pdfToPDFA.outputFormat=Output format -pdfToPDFA.pdfWithDigitalSignature=The PDF contains a digital signature. This will be removed in the next step. +pdfToPDFA.title=PDF-i PDF/A-ya +pdfToPDFA.header=PDF-i PDF/A-ya +pdfToPDFA.credit=Bu Servis PDF/A Çevirmək Üçün ghostscript İşlədir +pdfToPDFA.submit=Çevir +pdfToPDFA.tip=Hazırda Birdən Çox Giriş Üçün İşləmir +pdfToPDFA.outputFormat=Çıxış Formatı +pdfToPDFA.pdfWithDigitalSignature=PDF Rəqəmsal İmza Ehtiva Edir.Bu, növbəti addımda silinəcək. #PDFToWord @@ -1263,8 +1265,8 @@ splitByChapters.submit=PDF-i Ayır #release notes -releases.footer=Releases -releases.title=Release Notes -releases.header=Release Notes -releases.current.version=Current Release -releases.note=Release notes are only available in English +releases.footer=Buraxılışlar +releases.title=Buraxılış Qeydləri +releases.header=Buraxılış Qeydləri +releases.current.version=Hazırki Buraxılış +releases.note=Buraxılış Qeydləri yalnız ingiliscə mövcuddur diff --git a/src/main/resources/messages_bg_BG.properties b/src/main/resources/messages_bg_BG.properties index 9e2d727b..f1e5fc3b 100644 --- a/src/main/resources/messages_bg_BG.properties +++ b/src/main/resources/messages_bg_BG.properties @@ -958,6 +958,8 @@ multiTool.moveLeft=Move Left multiTool.moveRight=Move Right multiTool.delete=Delete multiTool.dragDropMessage=Page(s) Selected +multiTool.undo=Undo +multiTool.redo=Redo #multiTool-advert multiTool-advert.message=This feature is also available in our multi-tool page. Check it out for enhanced page-by-page UI and additional features! diff --git a/src/main/resources/messages_ca_CA.properties b/src/main/resources/messages_ca_CA.properties index 38ae93a9..aa860cb7 100644 --- a/src/main/resources/messages_ca_CA.properties +++ b/src/main/resources/messages_ca_CA.properties @@ -958,6 +958,8 @@ multiTool.moveLeft=Move Left multiTool.moveRight=Move Right multiTool.delete=Delete multiTool.dragDropMessage=Page(s) Selected +multiTool.undo=Undo +multiTool.redo=Redo #multiTool-advert multiTool-advert.message=This feature is also available in our multi-tool page. Check it out for enhanced page-by-page UI and additional features! diff --git a/src/main/resources/messages_cs_CZ.properties b/src/main/resources/messages_cs_CZ.properties index 10c5ce88..3c50d387 100644 --- a/src/main/resources/messages_cs_CZ.properties +++ b/src/main/resources/messages_cs_CZ.properties @@ -958,6 +958,8 @@ multiTool.moveLeft=Move Left multiTool.moveRight=Move Right multiTool.delete=Delete multiTool.dragDropMessage=Page(s) Selected +multiTool.undo=Undo +multiTool.redo=Redo #multiTool-advert multiTool-advert.message=This feature is also available in our multi-tool page. Check it out for enhanced page-by-page UI and additional features! diff --git a/src/main/resources/messages_da_DK.properties b/src/main/resources/messages_da_DK.properties index 86e4b3cc..ddaf3c60 100644 --- a/src/main/resources/messages_da_DK.properties +++ b/src/main/resources/messages_da_DK.properties @@ -958,6 +958,8 @@ multiTool.moveLeft=Move Left multiTool.moveRight=Move Right multiTool.delete=Delete multiTool.dragDropMessage=Page(s) Selected +multiTool.undo=Undo +multiTool.redo=Redo #multiTool-advert multiTool-advert.message=This feature is also available in our multi-tool page. Check it out for enhanced page-by-page UI and additional features! diff --git a/src/main/resources/messages_de_DE.properties b/src/main/resources/messages_de_DE.properties index 1c9609c5..087b7be7 100644 --- a/src/main/resources/messages_de_DE.properties +++ b/src/main/resources/messages_de_DE.properties @@ -958,6 +958,8 @@ multiTool.moveLeft=Move Left multiTool.moveRight=Move Right multiTool.delete=Delete multiTool.dragDropMessage=Page(s) Selected +multiTool.undo=Undo +multiTool.redo=Redo #multiTool-advert multiTool-advert.message=Diese Funktion ist auch auf unserer PDF-Multitool-Seite verfügbar. Probieren Sie sie aus, denn sie bietet eine verbesserte Benutzeroberfläche und zusätzliche Funktionen! diff --git a/src/main/resources/messages_el_GR.properties b/src/main/resources/messages_el_GR.properties index b6be4be1..75720377 100644 --- a/src/main/resources/messages_el_GR.properties +++ b/src/main/resources/messages_el_GR.properties @@ -958,6 +958,8 @@ multiTool.moveLeft=Move Left multiTool.moveRight=Move Right multiTool.delete=Delete multiTool.dragDropMessage=Page(s) Selected +multiTool.undo=Undo +multiTool.redo=Redo #multiTool-advert multiTool-advert.message=This feature is also available in our multi-tool page. Check it out for enhanced page-by-page UI and additional features! diff --git a/src/main/resources/messages_en_GB.properties b/src/main/resources/messages_en_GB.properties index 8a471ade..e2f74fbc 100644 --- a/src/main/resources/messages_en_GB.properties +++ b/src/main/resources/messages_en_GB.properties @@ -958,6 +958,8 @@ multiTool.moveLeft=Move Left multiTool.moveRight=Move Right multiTool.delete=Delete multiTool.dragDropMessage=Page(s) Selected +multiTool.undo=Undo +multiTool.redo=Redo #multiTool-advert multiTool-advert.message=This feature is also available in our multi-tool page. Check it out for enhanced page-by-page UI and additional features! diff --git a/src/main/resources/messages_en_US.properties b/src/main/resources/messages_en_US.properties index cd43508c..cde361d9 100644 --- a/src/main/resources/messages_en_US.properties +++ b/src/main/resources/messages_en_US.properties @@ -958,6 +958,8 @@ multiTool.moveLeft=Move Left multiTool.moveRight=Move Right multiTool.delete=Delete multiTool.dragDropMessage=Page(s) Selected +multiTool.undo=Undo +multiTool.redo=Redo #multiTool-advert multiTool-advert.message=This feature is also available in our multi-tool page. Check it out for enhanced page-by-page UI and additional features! diff --git a/src/main/resources/messages_es_ES.properties b/src/main/resources/messages_es_ES.properties index 6869b4f4..db712d42 100644 --- a/src/main/resources/messages_es_ES.properties +++ b/src/main/resources/messages_es_ES.properties @@ -958,6 +958,8 @@ multiTool.moveLeft=Move Left multiTool.moveRight=Move Right multiTool.delete=Delete multiTool.dragDropMessage=Page(s) Selected +multiTool.undo=Undo +multiTool.redo=Redo #multiTool-advert multiTool-advert.message=This feature is also available in our multi-tool page. Check it out for enhanced page-by-page UI and additional features! diff --git a/src/main/resources/messages_eu_ES.properties b/src/main/resources/messages_eu_ES.properties index 6022513c..0daedb19 100644 --- a/src/main/resources/messages_eu_ES.properties +++ b/src/main/resources/messages_eu_ES.properties @@ -958,6 +958,8 @@ multiTool.moveLeft=Move Left multiTool.moveRight=Move Right multiTool.delete=Delete multiTool.dragDropMessage=Page(s) Selected +multiTool.undo=Undo +multiTool.redo=Redo #multiTool-advert multiTool-advert.message=This feature is also available in our multi-tool page. Check it out for enhanced page-by-page UI and additional features! diff --git a/src/main/resources/messages_fr_FR.properties b/src/main/resources/messages_fr_FR.properties index 9b902ae0..7ac4a8a9 100644 --- a/src/main/resources/messages_fr_FR.properties +++ b/src/main/resources/messages_fr_FR.properties @@ -958,6 +958,8 @@ multiTool.moveLeft=Déplacer vers la gauche multiTool.moveRight=Déplacer vers la droite multiTool.delete=Supprimer multiTool.dragDropMessage=Page(s) sélectionnées +multiTool.undo=Undo +multiTool.redo=Redo #multiTool-advert multiTool-advert.message=Cette fonctionnalité est aussi disponible dans la page de l'outil multifonction. Allez-y pour une interface page par page améliorée et des fonctionnalités additionnelles ! diff --git a/src/main/resources/messages_ga_IE.properties b/src/main/resources/messages_ga_IE.properties index c1d46c03..8a95af6d 100644 --- a/src/main/resources/messages_ga_IE.properties +++ b/src/main/resources/messages_ga_IE.properties @@ -958,6 +958,8 @@ multiTool.moveLeft=Move Left multiTool.moveRight=Move Right multiTool.delete=Delete multiTool.dragDropMessage=Page(s) Selected +multiTool.undo=Undo +multiTool.redo=Redo #multiTool-advert multiTool-advert.message=This feature is also available in our multi-tool page. Check it out for enhanced page-by-page UI and additional features! diff --git a/src/main/resources/messages_hi_IN.properties b/src/main/resources/messages_hi_IN.properties index 490d8bf9..1c61b7ec 100644 --- a/src/main/resources/messages_hi_IN.properties +++ b/src/main/resources/messages_hi_IN.properties @@ -958,6 +958,8 @@ multiTool.moveLeft=Move Left multiTool.moveRight=Move Right multiTool.delete=Delete multiTool.dragDropMessage=Page(s) Selected +multiTool.undo=Undo +multiTool.redo=Redo #multiTool-advert multiTool-advert.message=This feature is also available in our multi-tool page. Check it out for enhanced page-by-page UI and additional features! diff --git a/src/main/resources/messages_hr_HR.properties b/src/main/resources/messages_hr_HR.properties index 1e76ba92..efc41e4f 100644 --- a/src/main/resources/messages_hr_HR.properties +++ b/src/main/resources/messages_hr_HR.properties @@ -958,6 +958,8 @@ multiTool.moveLeft=Move Left multiTool.moveRight=Move Right multiTool.delete=Delete multiTool.dragDropMessage=Page(s) Selected +multiTool.undo=Undo +multiTool.redo=Redo #multiTool-advert multiTool-advert.message=This feature is also available in our multi-tool page. Check it out for enhanced page-by-page UI and additional features! diff --git a/src/main/resources/messages_hu_HU.properties b/src/main/resources/messages_hu_HU.properties index 4bef0201..841c71fd 100644 --- a/src/main/resources/messages_hu_HU.properties +++ b/src/main/resources/messages_hu_HU.properties @@ -958,6 +958,8 @@ multiTool.moveLeft=Move Left multiTool.moveRight=Move Right multiTool.delete=Delete multiTool.dragDropMessage=Page(s) Selected +multiTool.undo=Undo +multiTool.redo=Redo #multiTool-advert multiTool-advert.message=This feature is also available in our multi-tool page. Check it out for enhanced page-by-page UI and additional features! diff --git a/src/main/resources/messages_id_ID.properties b/src/main/resources/messages_id_ID.properties index b04de894..fdd3816b 100644 --- a/src/main/resources/messages_id_ID.properties +++ b/src/main/resources/messages_id_ID.properties @@ -958,6 +958,8 @@ multiTool.moveLeft=Move Left multiTool.moveRight=Move Right multiTool.delete=Delete multiTool.dragDropMessage=Page(s) Selected +multiTool.undo=Undo +multiTool.redo=Redo #multiTool-advert multiTool-advert.message=This feature is also available in our multi-tool page. Check it out for enhanced page-by-page UI and additional features! diff --git a/src/main/resources/messages_it_IT.properties b/src/main/resources/messages_it_IT.properties index a34a050b..e9f09ee0 100644 --- a/src/main/resources/messages_it_IT.properties +++ b/src/main/resources/messages_it_IT.properties @@ -958,6 +958,8 @@ multiTool.moveLeft=Sposta a sinistra multiTool.moveRight=Sposta a destra multiTool.delete=Elimina multiTool.dragDropMessage=Pagina(e) selezionata(e) +multiTool.undo=Undo +multiTool.redo=Redo #multiTool-advert multiTool-advert.message=Questa funzione è disponibile anche nella nostra pagina multi-strumento. Scoprila per un'interfaccia utente pagina per pagina migliorata e funzionalità aggiuntive! @@ -1263,8 +1265,8 @@ splitByChapters.submit=Dividi PDF #release notes -releases.footer=Releases -releases.title=Release Notes -releases.header=Release Notes -releases.current.version=Current Release -releases.note=Release notes are only available in English +releases.footer=Rilasci +releases.title=Note di rilascio +releases.header=Note di rilascio +releases.current.version=Rilascio corrente +releases.note=Le note di rilascio sono disponibili solo in inglese diff --git a/src/main/resources/messages_ja_JP.properties b/src/main/resources/messages_ja_JP.properties index 5574521c..e893029b 100644 --- a/src/main/resources/messages_ja_JP.properties +++ b/src/main/resources/messages_ja_JP.properties @@ -958,6 +958,8 @@ multiTool.moveLeft=Move Left multiTool.moveRight=Move Right multiTool.delete=Delete multiTool.dragDropMessage=Page(s) Selected +multiTool.undo=Undo +multiTool.redo=Redo #multiTool-advert multiTool-advert.message=This feature is also available in our multi-tool page. Check it out for enhanced page-by-page UI and additional features! diff --git a/src/main/resources/messages_ko_KR.properties b/src/main/resources/messages_ko_KR.properties index 27db7dd6..aa77af63 100644 --- a/src/main/resources/messages_ko_KR.properties +++ b/src/main/resources/messages_ko_KR.properties @@ -958,6 +958,8 @@ multiTool.moveLeft=Move Left multiTool.moveRight=Move Right multiTool.delete=Delete multiTool.dragDropMessage=Page(s) Selected +multiTool.undo=Undo +multiTool.redo=Redo #multiTool-advert multiTool-advert.message=This feature is also available in our multi-tool page. Check it out for enhanced page-by-page UI and additional features! diff --git a/src/main/resources/messages_nl_NL.properties b/src/main/resources/messages_nl_NL.properties index b6f0ef0e..23ac465a 100644 --- a/src/main/resources/messages_nl_NL.properties +++ b/src/main/resources/messages_nl_NL.properties @@ -958,6 +958,8 @@ multiTool.moveLeft=Move Left multiTool.moveRight=Move Right multiTool.delete=Delete multiTool.dragDropMessage=Page(s) Selected +multiTool.undo=Undo +multiTool.redo=Redo #multiTool-advert multiTool-advert.message=This feature is also available in our multi-tool page. Check it out for enhanced page-by-page UI and additional features! diff --git a/src/main/resources/messages_no_NB.properties b/src/main/resources/messages_no_NB.properties index 0a4461cc..8d1220e6 100644 --- a/src/main/resources/messages_no_NB.properties +++ b/src/main/resources/messages_no_NB.properties @@ -958,6 +958,8 @@ multiTool.moveLeft=Move Left multiTool.moveRight=Move Right multiTool.delete=Delete multiTool.dragDropMessage=Page(s) Selected +multiTool.undo=Undo +multiTool.redo=Redo #multiTool-advert multiTool-advert.message=This feature is also available in our multi-tool page. Check it out for enhanced page-by-page UI and additional features! diff --git a/src/main/resources/messages_pl_PL.properties b/src/main/resources/messages_pl_PL.properties index ffc2e33a..02469e1f 100755 --- a/src/main/resources/messages_pl_PL.properties +++ b/src/main/resources/messages_pl_PL.properties @@ -958,6 +958,8 @@ multiTool.moveLeft=Move Left multiTool.moveRight=Move Right multiTool.delete=Delete multiTool.dragDropMessage=Page(s) Selected +multiTool.undo=Undo +multiTool.redo=Redo #multiTool-advert multiTool-advert.message=This feature is also available in our multi-tool page. Check it out for enhanced page-by-page UI and additional features! diff --git a/src/main/resources/messages_pt_BR.properties b/src/main/resources/messages_pt_BR.properties index aba81922..b7af46b1 100644 --- a/src/main/resources/messages_pt_BR.properties +++ b/src/main/resources/messages_pt_BR.properties @@ -958,6 +958,8 @@ multiTool.moveLeft=Move Left multiTool.moveRight=Move Right multiTool.delete=Delete multiTool.dragDropMessage=Page(s) Selected +multiTool.undo=Undo +multiTool.redo=Redo #multiTool-advert multiTool-advert.message=This feature is also available in our multi-tool page. Check it out for enhanced page-by-page UI and additional features! diff --git a/src/main/resources/messages_pt_PT.properties b/src/main/resources/messages_pt_PT.properties index 0f3830c2..f5f2137b 100644 --- a/src/main/resources/messages_pt_PT.properties +++ b/src/main/resources/messages_pt_PT.properties @@ -958,6 +958,8 @@ multiTool.moveLeft=Move Left multiTool.moveRight=Move Right multiTool.delete=Delete multiTool.dragDropMessage=Page(s) Selected +multiTool.undo=Undo +multiTool.redo=Redo #multiTool-advert multiTool-advert.message=This feature is also available in our multi-tool page. Check it out for enhanced page-by-page UI and additional features! diff --git a/src/main/resources/messages_ro_RO.properties b/src/main/resources/messages_ro_RO.properties index d289ff96..6be97127 100644 --- a/src/main/resources/messages_ro_RO.properties +++ b/src/main/resources/messages_ro_RO.properties @@ -958,6 +958,8 @@ multiTool.moveLeft=Move Left multiTool.moveRight=Move Right multiTool.delete=Delete multiTool.dragDropMessage=Page(s) Selected +multiTool.undo=Undo +multiTool.redo=Redo #multiTool-advert multiTool-advert.message=This feature is also available in our multi-tool page. Check it out for enhanced page-by-page UI and additional features! diff --git a/src/main/resources/messages_ru_RU.properties b/src/main/resources/messages_ru_RU.properties index 35aefdd0..1908496b 100644 --- a/src/main/resources/messages_ru_RU.properties +++ b/src/main/resources/messages_ru_RU.properties @@ -958,6 +958,8 @@ multiTool.moveLeft=Move Left multiTool.moveRight=Move Right multiTool.delete=Delete multiTool.dragDropMessage=Page(s) Selected +multiTool.undo=Undo +multiTool.redo=Redo #multiTool-advert multiTool-advert.message=This feature is also available in our multi-tool page. Check it out for enhanced page-by-page UI and additional features! diff --git a/src/main/resources/messages_sk_SK.properties b/src/main/resources/messages_sk_SK.properties index 0c78dad1..57bb598a 100644 --- a/src/main/resources/messages_sk_SK.properties +++ b/src/main/resources/messages_sk_SK.properties @@ -958,6 +958,8 @@ multiTool.moveLeft=Move Left multiTool.moveRight=Move Right multiTool.delete=Delete multiTool.dragDropMessage=Page(s) Selected +multiTool.undo=Undo +multiTool.redo=Redo #multiTool-advert multiTool-advert.message=This feature is also available in our multi-tool page. Check it out for enhanced page-by-page UI and additional features! diff --git a/src/main/resources/messages_sr_LATN_RS.properties b/src/main/resources/messages_sr_LATN_RS.properties index 9ac101ad..34b737d1 100644 --- a/src/main/resources/messages_sr_LATN_RS.properties +++ b/src/main/resources/messages_sr_LATN_RS.properties @@ -958,6 +958,8 @@ multiTool.moveLeft=Move Left multiTool.moveRight=Move Right multiTool.delete=Delete multiTool.dragDropMessage=Page(s) Selected +multiTool.undo=Undo +multiTool.redo=Redo #multiTool-advert multiTool-advert.message=This feature is also available in our multi-tool page. Check it out for enhanced page-by-page UI and additional features! diff --git a/src/main/resources/messages_sv_SE.properties b/src/main/resources/messages_sv_SE.properties index c2a7de32..98ccaaa1 100644 --- a/src/main/resources/messages_sv_SE.properties +++ b/src/main/resources/messages_sv_SE.properties @@ -958,6 +958,8 @@ multiTool.moveLeft=Move Left multiTool.moveRight=Move Right multiTool.delete=Delete multiTool.dragDropMessage=Page(s) Selected +multiTool.undo=Undo +multiTool.redo=Redo #multiTool-advert multiTool-advert.message=This feature is also available in our multi-tool page. Check it out for enhanced page-by-page UI and additional features! diff --git a/src/main/resources/messages_th_TH.properties b/src/main/resources/messages_th_TH.properties index 1b58842b..08e0281b 100644 --- a/src/main/resources/messages_th_TH.properties +++ b/src/main/resources/messages_th_TH.properties @@ -958,6 +958,8 @@ multiTool.moveLeft=Move Left multiTool.moveRight=Move Right multiTool.delete=Delete multiTool.dragDropMessage=Page(s) Selected +multiTool.undo=Undo +multiTool.redo=Redo #multiTool-advert multiTool-advert.message=This feature is also available in our multi-tool page. Check it out for enhanced page-by-page UI and additional features! diff --git a/src/main/resources/messages_tr_TR.properties b/src/main/resources/messages_tr_TR.properties index 79130da2..e7116536 100644 --- a/src/main/resources/messages_tr_TR.properties +++ b/src/main/resources/messages_tr_TR.properties @@ -958,6 +958,8 @@ multiTool.moveLeft=Move Left multiTool.moveRight=Move Right multiTool.delete=Delete multiTool.dragDropMessage=Page(s) Selected +multiTool.undo=Undo +multiTool.redo=Redo #multiTool-advert multiTool-advert.message=This feature is also available in our multi-tool page. Check it out for enhanced page-by-page UI and additional features! diff --git a/src/main/resources/messages_uk_UA.properties b/src/main/resources/messages_uk_UA.properties index 4b9cbd26..1c2b60cf 100644 --- a/src/main/resources/messages_uk_UA.properties +++ b/src/main/resources/messages_uk_UA.properties @@ -958,6 +958,8 @@ multiTool.moveLeft=Move Left multiTool.moveRight=Move Right multiTool.delete=Delete multiTool.dragDropMessage=Page(s) Selected +multiTool.undo=Undo +multiTool.redo=Redo #multiTool-advert multiTool-advert.message=This feature is also available in our multi-tool page. Check it out for enhanced page-by-page UI and additional features! diff --git a/src/main/resources/messages_vi_VN.properties b/src/main/resources/messages_vi_VN.properties index 14e78b02..bfb7d9c7 100644 --- a/src/main/resources/messages_vi_VN.properties +++ b/src/main/resources/messages_vi_VN.properties @@ -958,6 +958,8 @@ multiTool.moveLeft=Move Left multiTool.moveRight=Move Right multiTool.delete=Delete multiTool.dragDropMessage=Page(s) Selected +multiTool.undo=Undo +multiTool.redo=Redo #multiTool-advert multiTool-advert.message=This feature is also available in our multi-tool page. Check it out for enhanced page-by-page UI and additional features! diff --git a/src/main/resources/messages_zh_CN.properties b/src/main/resources/messages_zh_CN.properties index 12f2b69b..dfec712b 100644 --- a/src/main/resources/messages_zh_CN.properties +++ b/src/main/resources/messages_zh_CN.properties @@ -958,6 +958,8 @@ multiTool.moveLeft=Move Left multiTool.moveRight=Move Right multiTool.delete=Delete multiTool.dragDropMessage=Page(s) Selected +multiTool.undo=Undo +multiTool.redo=Redo #multiTool-advert multiTool-advert.message=This feature is also available in our multi-tool page. Check it out for enhanced page-by-page UI and additional features! diff --git a/src/main/resources/messages_zh_TW.properties b/src/main/resources/messages_zh_TW.properties index fd3529a7..c1b3929a 100644 --- a/src/main/resources/messages_zh_TW.properties +++ b/src/main/resources/messages_zh_TW.properties @@ -958,6 +958,8 @@ multiTool.moveLeft=Move Left multiTool.moveRight=Move Right multiTool.delete=Delete multiTool.dragDropMessage=Page(s) Selected +multiTool.undo=Undo +multiTool.redo=Redo #multiTool-advert multiTool-advert.message=This feature is also available in our multi-tool page. Check it out for enhanced page-by-page UI and additional features! diff --git a/src/main/resources/static/js/fileInput.js b/src/main/resources/static/js/fileInput.js index 7c810de0..4553128d 100644 --- a/src/main/resources/static/js/fileInput.js +++ b/src/main/resources/static/js/fileInput.js @@ -85,9 +85,9 @@ function setupFileInput(chooser) { const isDragAndDrop = e.detail?.source == 'drag-drop'; if (element instanceof HTMLInputElement && element.hasAttribute("multiple")) { - allFiles = isDragAndDrop ? allFiles : [...allFiles, ...element.files]; + allFiles = isDragAndDrop ? allFiles : [... allFiles, ... element.files]; } else { - allFiles = isDragAndDrop ? allFiles : [element.files[0]]; + allFiles = Array.from(isDragAndDrop ? allFiles : [element.files[0]]); } if (!isDragAndDrop) { diff --git a/src/main/resources/static/js/multitool/PdfActionsManager.js b/src/main/resources/static/js/multitool/PdfActionsManager.js index b83beb5e..17386fd7 100644 --- a/src/main/resources/static/js/multitool/PdfActionsManager.js +++ b/src/main/resources/static/js/multitool/PdfActionsManager.js @@ -1,12 +1,20 @@ +import { DeletePageCommand } from "./commands/delete-page.js"; +import { SelectPageCommand } from "./commands/select.js"; +import { SplitFileCommand } from "./commands/split.js"; +import { UndoManager } from "./UndoManager.js"; + class PdfActionsManager { pageDirection; pagesContainer; static selectedPages = []; // Static property shared across all instances + undoManager; - constructor(id) { + constructor(id, undoManager) { this.pagesContainer = document.getElementById(id); this.pageDirection = document.documentElement.getAttribute("dir"); + this.undoManager = undoManager || new UndoManager(); + var styleElement = document.createElement("link"); styleElement.rel = "stylesheet"; styleElement.href = "css/pdfActions.css"; @@ -27,7 +35,8 @@ class PdfActionsManager { const sibling = imgContainer.previousSibling; if (sibling) { - this.movePageTo(imgContainer, sibling, true); + let movePageCommand = this.movePageTo(imgContainer, sibling, true, true); + this._pushUndoClearRedo(movePageCommand); } } @@ -35,7 +44,12 @@ class PdfActionsManager { var imgContainer = this.getPageContainer(e.target); const sibling = imgContainer.nextSibling; if (sibling) { - this.movePageTo(imgContainer, sibling.nextSibling, true); + let movePageCommand = this.movePageTo( + imgContainer, + sibling.nextSibling, + true + ); + this._pushUndoClearRedo(movePageCommand); } } @@ -43,30 +57,27 @@ class PdfActionsManager { var imgContainer = this.getPageContainer(e.target); const img = imgContainer.querySelector("img"); - this.rotateElement(img, -90); + let rotateCommand = this.rotateElement(img, -90); + this._pushUndoClearRedo(rotateCommand); } rotateCWButtonCallback(e) { var imgContainer = this.getPageContainer(e.target); const img = imgContainer.querySelector("img"); - this.rotateElement(img, 90); + let rotateCommand = this.rotateElement(img, 90); + this._pushUndoClearRedo(rotateCommand); } deletePageButtonCallback(e) { - var imgContainer = this.getPageContainer(e.target); - this.pagesContainer.removeChild(imgContainer); - if (this.pagesContainer.childElementCount === 0) { - const filenameInput = document.getElementById("filename-input"); - const filenameParagraph = document.getElementById("filename"); - const downloadBtn = document.getElementById("export-button"); + let imgContainer = this.getPageContainer(e.target); + let deletePageCommand = new DeletePageCommand( + imgContainer, + this.pagesContainer + ); + deletePageCommand.execute(); - filenameInput.disabled = true; - filenameInput.value = ""; - filenameParagraph.innerText = ""; - - downloadBtn.disabled = true; - } + this._pushUndoClearRedo(deletePageCommand); } insertFileButtonCallback(e) { @@ -81,7 +92,15 @@ class PdfActionsManager { splitFileButtonCallback(e) { var imgContainer = this.getPageContainer(e.target); - imgContainer.classList.toggle("split-before"); + + let splitFileCommand = new SplitFileCommand(imgContainer, "split-before"); + splitFileCommand.execute(); + + this._pushUndoClearRedo(splitFileCommand); + } + + _pushUndoClearRedo(command) { + this.undoManager.pushUndoClearRedo(command); } setActions({ movePageTo, addFiles, rotateElement }) { @@ -159,25 +178,10 @@ class PdfActionsManager { selectCheckbox.onchange = () => { const pageNumber = Array.from(div.parentNode.children).indexOf(div) + 1; - if (selectCheckbox.checked) { - //adds to array of selected pages - window.selectedPages.push(pageNumber); - } else { - //remove page from selected pages array - const index = window.selectedPages.indexOf(pageNumber); - if (index !== -1) { - window.selectedPages.splice(index, 1); - } - } + let selectPageCommand = new SelectPageCommand(pageNumber, selectCheckbox); + selectPageCommand.execute(); - if (window.selectedPages.length > 0 && !window.selectPage) { - window.toggleSelectPageVisibility(); - } - if (window.selectedPages.length == 0 && window.selectPage) { - window.toggleSelectPageVisibility(); - } - - window.updateSelectedPagesDisplay(); + this._pushUndoClearRedo(selectPageCommand); }; const insertFileButtonContainer = document.createElement("div"); diff --git a/src/main/resources/static/js/multitool/PdfContainer.js b/src/main/resources/static/js/multitool/PdfContainer.js index d87fd6cb..b5721dfa 100644 --- a/src/main/resources/static/js/multitool/PdfContainer.js +++ b/src/main/resources/static/js/multitool/PdfContainer.js @@ -1,11 +1,18 @@ +import { MovePageUpCommand, MovePageDownCommand } from "./commands/move-page.js"; +import { RemoveSelectedCommand } from "./commands/remove.js"; +import { RotateAllCommand, RotateElementCommand } from "./commands/rotate.js"; +import { SplitAllCommand } from "./commands/split.js"; +import { UndoManager } from "./UndoManager.js"; + class PdfContainer { fileName; pagesContainer; pagesContainerWrapper; pdfAdapters; downloadLink; + undoManager; - constructor(id, wrapperId, pdfAdapters) { + constructor(id, wrapperId, pdfAdapters, undoManager) { this.pagesContainer = document.getElementById(id); this.pagesContainerWrapper = document.getElementById(wrapperId); this.downloadLink = null; @@ -31,6 +38,8 @@ class PdfContainer { this.removeAllElements = this.removeAllElements.bind(this); this.resetPages = this.resetPages.bind(this); + this.undoManager = undoManager || new UndoManager(); + this.pdfAdapters = pdfAdapters; this.pdfAdapters.forEach((adapter) => { @@ -58,6 +67,33 @@ class PdfContainer { window.removeAllElements = this.removeAllElements; window.resetPages = this.resetPages; + let undoBtn = document.getElementById('undo-btn'); + let redoBtn = document.getElementById('redo-btn'); + + document.addEventListener('undo-manager-update', (e) => { + let canUndo = e.detail.canUndo; + let canRedo = e.detail.canRedo; + + undoBtn.disabled = !canUndo; + redoBtn.disabled = !canRedo; + }) + + window.undo = () => { + if (undoManager.canUndo()) undoManager.undo(); + else { + undoBtn.disabled = !undoManager.canUndo(); + redoBtn.disabled = !undoManager.canRedo(); + } + } + + window.redo = () => { + if (undoManager.canRedo()) undoManager.redo(); + else { + undoBtn.disabled = !undoManager.canUndo(); + redoBtn.disabled = !undoManager.canRedo(); + } + } + const filenameInput = document.getElementById("filename-input"); const downloadBtn = document.getElementById("export-button"); @@ -68,32 +104,28 @@ class PdfContainer { downloadBtn.disabled = true; } - movePageTo(startElement, endElement, scrollTo = false) { - const childArray = Array.from(this.pagesContainer.childNodes); - const startIndex = childArray.indexOf(startElement); - const endIndex = childArray.indexOf(endElement); - - // Check & remove page number elements here too if they exist because Firefox doesn't fire the relevant event on page move. - const pageNumberElement = startElement.querySelector(".page-number"); - if (pageNumberElement) { - startElement.removeChild(pageNumberElement); - } - - this.pagesContainer.removeChild(startElement); - if (!endElement) { - this.pagesContainer.append(startElement); + movePageTo(startElement, endElement, scrollTo = false, moveUp = false) { + let movePageCommand; + if (moveUp) { + movePageCommand = new MovePageUpCommand( + startElement, + endElement, + this.pagesContainer, + this.pagesContainerWrapper, + scrollTo + ); } else { - this.pagesContainer.insertBefore(startElement, endElement); + movePageCommand = new MovePageDownCommand( + startElement, + endElement, + this.pagesContainer, + this.pagesContainerWrapper, + scrollTo + ); } - if (scrollTo) { - const { width } = startElement.getBoundingClientRect(); - const vector = endIndex !== -1 && startIndex > endIndex ? 0 - width : width; - - this.pagesContainerWrapper.scroll({ - left: this.pagesContainerWrapper.scrollLeft + vector, - }); - } + movePageCommand.execute(); + return movePageCommand; } addFiles(nextSiblingElement, blank = false) { @@ -165,56 +197,22 @@ class PdfContainer { async addFilesBlank(nextSiblingElement) { - const pdfContent = ` - %PDF-1.4 - 1 0 obj - << /Type /Catalog /Pages 2 0 R >> - endobj - 2 0 obj - << /Type /Pages /Kids [3 0 R] /Count 1 >> - endobj - 3 0 obj - << /Type /Page /Parent 2 0 R /MediaBox [0 0 595 842] /Contents 5 0 R >> - endobj - 5 0 obj - << /Length 44 >> - stream - 0 0 0 595 0 842 re - W - n - endstream - endobj - xref - 0 6 - 0000000000 65535 f - 0000000010 00000 n - 0000000071 00000 n - 0000000121 00000 n - 0000000205 00000 n - 0000000400 00000 n - trailer - << /Size 6 /Root 1 0 R >> - startxref - 278 - %%EOF - `; - const blob = new Blob([pdfContent], { type: 'application/pdf' }); - const url = URL.createObjectURL(blob); - const file = new File([blob], "blank_page.pdf", { type: "application/pdf" }); - await this.addPdfFile(file, nextSiblingElement); + let doc = await PDFLib.PDFDocument.create(); + let docBytes = await doc.save(); + + const url = URL.createObjectURL(new Blob([docBytes], { type: 'application/pdf' })); + + const renderer = await this.toRenderer(url); + + await this.addPdfFile(renderer, doc, nextSiblingElement); } rotateElement(element, deg) { - var lastTransform = element.style.rotate; - if (!lastTransform) { - lastTransform = "0"; - } - const lastAngle = parseInt(lastTransform.replace(/[^\d-]/g, "")); - const newAngle = lastAngle + deg; - - element.style.rotate = newAngle + "deg"; + let rotateCommand = new RotateElementCommand(element, deg); + rotateCommand.execute(); + return rotateCommand; } async addPdfFile(renderer, pdfDocument, nextSiblingElement) { @@ -309,6 +307,7 @@ class PdfContainer { } rotateAll(deg) { + let elementsToRotate = []; for (let i = 0; i < this.pagesContainer.childNodes.length; i++) { const child = this.pagesContainer.children[i]; if (!child) continue; @@ -320,8 +319,13 @@ class PdfContainer { const img = child.querySelector("img"); if (!img) continue; - this.rotateElement(img, deg); + elementsToRotate.push(img); } + + let rotateAllCommand = new RotateAllCommand(elementsToRotate, deg); + rotateAllCommand.execute(); + + this.undoManager.pushUndoClearRedo(rotateAllCommand); } removeAllElements(){ @@ -336,34 +340,13 @@ class PdfContainer { deleteSelected() { window.selectedPages.sort((a, b) => a - b); - let deletions = 0; + let removeSelectedCommand = new RemoveSelectedCommand( + this.pagesContainer, + window.selectedPages, + this.updatePageNumbersAndCheckboxes + ); - window.selectedPages.forEach((pageIndex) => { - const adjustedIndex = pageIndex - 1 - deletions; - const child = this.pagesContainer.children[adjustedIndex]; - if (child) { - this.pagesContainer.removeChild(child); - deletions++; - } - }); - - if (this.pagesContainer.childElementCount === 0) { - const filenameInput = document.getElementById("filename-input"); - const filenameParagraph = document.getElementById("filename"); - const downloadBtn = document.getElementById("export-button"); - - if (filenameInput) - filenameInput.disabled = true; - filenameInput.value = ""; - if (filenameParagraph) - filenameParagraph.innerText = ""; - - downloadBtn.disabled = true; - } - - window.selectedPages = []; - this.updatePageNumbersAndCheckboxes(); - document.dispatchEvent(new Event("selectedPagesUpdated")); + this.undoManager.pushUndoClearRedo(removeSelectedCommand); } toggleSelectAll() { @@ -531,34 +514,17 @@ class PdfContainer { splitAll() { const allPages = this.pagesContainer.querySelectorAll(".page-container"); + let splitAllCommand = new SplitAllCommand( + allPages, + window.selectPage, + window.selectedPages, + "split-before" + ); + splitAllCommand.execute(); - if (!window.selectPage) { - const hasSplit = this.pagesContainer.querySelectorAll(".split-before").length > 0; - if (hasSplit) { - allPages.forEach(page => { - page.classList.remove("split-before"); - }); - } else { - allPages.forEach(page => { - page.classList.add("split-before"); - }); - } - return; - } - - allPages.forEach((page, index) => { - const pageIndex = index; - if (window.selectPage && !window.selectedPages.includes(pageIndex)) return; - - if (page.classList.contains("split-before")) { - page.classList.remove("split-before"); - } else { - page.classList.add("split-before"); - } - }); + this.undoManager.pushUndoClearRedo(splitAllCommand); } - async splitPDF(baseDocBytes, splitters) { const baseDocument = await PDFLib.PDFDocument.load(baseDocBytes); const pageNum = baseDocument.getPages().length; diff --git a/src/main/resources/static/js/multitool/UndoManager.js b/src/main/resources/static/js/multitool/UndoManager.js new file mode 100644 index 00000000..39202f3f --- /dev/null +++ b/src/main/resources/static/js/multitool/UndoManager.js @@ -0,0 +1,65 @@ +export class UndoManager { + _undoStack; + _redoStack; + + constructor() { + this._undoStack = []; + this._redoStack = []; + } + + pushUndo(command) { + this._undoStack.push(command); + this._dispatchStateChange(); + } + + pushRedo(command) { + this._redoStack.push(command); + this._dispatchStateChange(); + } + + pushUndoClearRedo(command) { + this._undoStack.push(command); + this._redoStack = []; + this._dispatchStateChange(); + } + + undo() { + if (!this.canUndo()) return; + + let cmd = this._undoStack.pop(); + cmd.undo(); + + this._redoStack.push(cmd); + this._dispatchStateChange(); + } + + canUndo() { + return this._undoStack && this._undoStack.length > 0; + } + + redo() { + if (!this.canRedo()) return; + + let cmd = this._redoStack.pop(); + cmd.redo(); + + this._undoStack.push(cmd); + this._dispatchStateChange(); + } + + canRedo() { + return this._redoStack && this._redoStack.length > 0; + } + + _dispatchStateChange() { + document.dispatchEvent( + new CustomEvent("undo-manager-update", { + bubbles: true, + detail: { + canUndo: this.canUndo(), + canRedo: this.canRedo(), + }, + }) + ); + } +} diff --git a/src/main/resources/static/js/multitool/commands/command.js b/src/main/resources/static/js/multitool/commands/command.js new file mode 100644 index 00000000..a4ae5fdf --- /dev/null +++ b/src/main/resources/static/js/multitool/commands/command.js @@ -0,0 +1,5 @@ +export class Command { + execute() {} + undo() {} + redo() {} +} diff --git a/src/main/resources/static/js/multitool/commands/delete-page.js b/src/main/resources/static/js/multitool/commands/delete-page.js new file mode 100644 index 00000000..f9a00e7a --- /dev/null +++ b/src/main/resources/static/js/multitool/commands/delete-page.js @@ -0,0 +1,74 @@ +import { Command } from "./command.js"; + +export class DeletePageCommand extends Command { + constructor(element, pagesContainer) { + super(); + + this.element = element; + this.pagesContainer = pagesContainer; + + this.filenameInputValue = document.getElementById("filename-input").value; + + const filenameParagraph = document.getElementById("filename"); + this.filenameParagraphText = filenameParagraph ? filenameParagraph.innerText : ""; + } + + execute() { + this.nextSibling = this.element.nextSibling; + + this.pagesContainer.removeChild(this.element); + if (this.pagesContainer.childElementCount === 0) { + const filenameInput = document.getElementById("filename-input"); + const filenameParagraph = document.getElementById("filename"); + const downloadBtn = document.getElementById("export-button"); + + filenameInput.disabled = true; + filenameInput.value = ""; + filenameParagraph.innerText = ""; + + downloadBtn.disabled = true; + } + } + + undo() { + let node = this.nextSibling; + if (node) this.pagesContainer.insertBefore(this.element, node); + else this.pagesContainer.appendChild(this.element); + + const pageNumberElement = this.element.querySelector(".page-number"); + if (pageNumberElement) { + this.element.removeChild(pageNumberElement); + } + + const filenameInput = document.getElementById("filename-input"); + const filenameParagraph = document.getElementById("filename"); + const downloadBtn = document.getElementById("export-button"); + + filenameInput.disabled = false; + filenameInput.value = this.filenameInputValue; + if (this.filenameParagraph) + filenameParagraph.innerText = this.filenameParagraphText; + + downloadBtn.disabled = false; + } + + redo() { + const pageNumberElement = this.element.querySelector(".page-number"); + if (pageNumberElement) { + this.element.removeChild(pageNumberElement); + } + + this.pagesContainer.removeChild(this.element); + if (this.pagesContainer.childElementCount === 0) { + const filenameInput = document.getElementById("filename-input"); + const filenameParagraph = document.getElementById("filename"); + const downloadBtn = document.getElementById("export-button"); + + filenameInput.disabled = true; + filenameInput.value = ""; + filenameParagraph.innerText = ""; + + downloadBtn.disabled = true; + } + } +} diff --git a/src/main/resources/static/js/multitool/commands/move-page.js b/src/main/resources/static/js/multitool/commands/move-page.js new file mode 100644 index 00000000..6f7b185e --- /dev/null +++ b/src/main/resources/static/js/multitool/commands/move-page.js @@ -0,0 +1,133 @@ +import { Command } from "./command.js"; + +export class AbstractMovePageCommand extends Command { + constructor( + startElement, + endElement, + pagesContainer, + pagesContainerWrapper, + scrollTo = false + ) { + super(); + + this.pagesContainer = pagesContainer; + const childArray = Array.from(this.pagesContainer.childNodes); + + this.startIndex = childArray.indexOf(startElement); + this.endIndex = childArray.indexOf(endElement); + + this.startElement = startElement; + this.endElement = endElement; + + this.scrollTo = scrollTo; + this.pagesContainerWrapper = pagesContainerWrapper; + } + + execute() { + // Check & remove page number elements here too if they exist because Firefox doesn't fire the relevant event on page move. + const pageNumberElement = this.startElement.querySelector(".page-number"); + if (pageNumberElement) { + this.startElement.removeChild(pageNumberElement); + } + + this.pagesContainer.removeChild(this.startElement); + if (!this.endElement) { + this.pagesContainer.append(this.startElement); + } else { + this.pagesContainer.insertBefore(this.startElement, this.endElement); + } + + if (this.scrollTo) { + const { width } = this.startElement.getBoundingClientRect(); + const vector = + this.endIndex !== -1 && this.startIndex > this.endIndex + ? 0 - width + : width; + + this.pagesContainerWrapper.scroll({ + left: this.pagesContainerWrapper.scrollLeft + vector, + }); + } + } + + undo() { + // Requires overriding in child classes + + } + + redo() { + this.execute(); + } +} + +export class MovePageUpCommand extends AbstractMovePageCommand { + constructor( + startElement, + endElement, + pagesContainer, + pagesContainerWrapper, + scrollTo = false + ) { + super(startElement, endElement, pagesContainer, pagesContainerWrapper, scrollTo); + } + + undo() { + if (this.endElement) { + this.pagesContainer.removeChild(this.endElement); + this.startElement.insertAdjacentElement("beforebegin", this.endElement); + } + + if (this.scrollTo) { + const { width } = this.startElement.getBoundingClientRect(); + const vector = + this.endIndex === -1 || this.startIndex <= this.endIndex + ? 0 - width + : width; + + this.pagesContainerWrapper.scroll({ + left: this.pagesContainerWrapper.scrollLeft - vector, + }); + } + } + + redo() { + this.execute(); + } +} + +export class MovePageDownCommand extends AbstractMovePageCommand { + constructor( + startElement, + endElement, + pagesContainer, + pagesContainerWrapper, + scrollTo = false + ) { + super(startElement, endElement, pagesContainer, pagesContainerWrapper, scrollTo); + } + + undo() { + let previousElement = this.startElement.previousSibling; + + if (this.startElement) { + this.pagesContainer.removeChild(this.startElement); + previousElement.insertAdjacentElement("beforebegin", this.startElement); + } + + if (this.scrollTo) { + const { width } = this.startElement.getBoundingClientRect(); + const vector = + this.endIndex === -1 || this.startIndex <= this.endIndex + ? 0 - width + : width; + + this.pagesContainerWrapper.scroll({ + left: this.pagesContainerWrapper.scrollLeft - vector, + }); + } + } + + redo() { + this.execute(); + } +} diff --git a/src/main/resources/static/js/multitool/commands/remove.js b/src/main/resources/static/js/multitool/commands/remove.js new file mode 100644 index 00000000..0c2dc14e --- /dev/null +++ b/src/main/resources/static/js/multitool/commands/remove.js @@ -0,0 +1,101 @@ +import { Command } from "./command.js"; + +export class RemoveSelectedCommand extends Command { + constructor(pagesContainer, selectedPages, updatePageNumbersAndCheckboxes) { + super(); + this.pagesContainer = pagesContainer; + this.selectedPages = selectedPages; + + this.deletedChildren = []; + + if (updatePageNumbersAndCheckboxes) { + this.updatePageNumbersAndCheckboxes = updatePageNumbersAndCheckboxes; + } else { + const pageDivs = document.querySelectorAll(".pdf-actions_container"); + + pageDivs.forEach((div, index) => { + const pageNumber = index + 1; + const checkbox = div.querySelector(".pdf-actions_checkbox"); + checkbox.id = `selectPageCheckbox-${pageNumber}`; + checkbox.setAttribute("data-page-number", pageNumber); + checkbox.checked = window.selectedPages.includes(pageNumber); + }); + } + + const filenameInput = document.getElementById("filename-input"); + const filenameParagraph = document.getElementById("filename"); + + this.originalFilenameInputValue = filenameInput ? filenameInput.value : ""; + if (filenameParagraph) + this.originalFilenameParagraphText = filenameParagraph.innerText; + } + + execute() { + let deletions = 0; + + this.selectedPages.forEach((pageIndex) => { + const adjustedIndex = pageIndex - 1 - deletions; + const child = this.pagesContainer.children[adjustedIndex]; + if (child) { + this.pagesContainer.removeChild(child); + deletions++; + + this.deletedChildren.push({ + idx: adjustedIndex, + childNode: child, + }); + } + }); + + if (this.pagesContainer.childElementCount === 0) { + const filenameInput = document.getElementById("filename-input"); + const filenameParagraph = document.getElementById("filename"); + const downloadBtn = document.getElementById("export-button"); + + if (filenameInput) filenameInput.disabled = true; + filenameInput.value = ""; + if (filenameParagraph) filenameParagraph.innerText = ""; + + downloadBtn.disabled = true; + } + + window.selectedPages = []; + this.updatePageNumbersAndCheckboxes(); + document.dispatchEvent(new Event("selectedPagesUpdated")); + } + + undo() { + while (this.deletedChildren.length > 0) { + let deletedChild = this.deletedChildren.pop(); + if (this.pagesContainer.children.length <= deletedChild.idx) + this.pagesContainer.appendChild(deletedChild.childNode); + else { + this.pagesContainer.insertBefore( + deletedChild.childNode, + this.pagesContainer.children[deletedChild.idx] + ); + } + } + + if (this.pagesContainer.childElementCount > 0) { + const filenameInput = document.getElementById("filename-input"); + const filenameParagraph = document.getElementById("filename"); + const downloadBtn = document.getElementById("export-button"); + + if (filenameInput) filenameInput.disabled = false; + filenameInput.value = this.originalFilenameInputValue; + if (filenameParagraph) + filenameParagraph.innerText = this.originalFilenameParagraphText; + + downloadBtn.disabled = false; + } + + window.selectedPages = this.selectedPages; + this.updatePageNumbersAndCheckboxes(); + document.dispatchEvent(new Event("selectedPagesUpdated")); + } + + redo() { + this.execute(); + } +} diff --git a/src/main/resources/static/js/multitool/commands/rotate.js b/src/main/resources/static/js/multitool/commands/rotate.js new file mode 100644 index 00000000..6fb08cb9 --- /dev/null +++ b/src/main/resources/static/js/multitool/commands/rotate.js @@ -0,0 +1,74 @@ +import { Command } from "./command.js"; + +export class RotateElementCommand extends Command { + constructor(element, degree) { + super(); + this.element = element; + this.degree = degree; + } + + execute() { + let lastTransform = this.element.style.rotate; + if (!lastTransform) { + lastTransform = "0"; + } + const lastAngle = parseInt(lastTransform.replace(/[^\d-]/g, "")); + const newAngle = lastAngle + parseInt(this.degree); + + this.element.style.rotate = newAngle + "deg"; + } + + undo() { + let lastTransform = this.element.style.rotate; + if (!lastTransform) { + lastTransform = "0"; + } + + const currentAngle = parseInt(lastTransform.replace(/[^\d-]/g, "")); + const undoAngle = currentAngle + -parseInt(this.degree); + + this.element.style.rotate = undoAngle + "deg"; + } + + redo() { + this.execute(); + } +} + +export class RotateAllCommand extends Command { + constructor(elements, degree) { + super(); + this.elements = elements; + this.degree = degree; + } + + execute() { + for (let element of this.elements) { + let lastTransform = element.style.rotate; + if (!lastTransform) { + lastTransform = "0"; + } + const lastAngle = parseInt(lastTransform.replace(/[^\d-]/g, "")); + const newAngle = lastAngle + this.degree; + + element.style.rotate = newAngle + "deg"; + } + } + + undo() { + for (let element of this.elements) { + let lastTransform = element.style.rotate; + if (!lastTransform) { + lastTransform = "0"; + } + const currentAngle = parseInt(lastTransform.replace(/[^\d-]/g, "")); + const undoAngle = currentAngle + -this.degree; + + element.style.rotate = undoAngle + "deg"; + } + } + + redo() { + this.execute(); + } +} diff --git a/src/main/resources/static/js/multitool/commands/select.js b/src/main/resources/static/js/multitool/commands/select.js new file mode 100644 index 00000000..b76a25ca --- /dev/null +++ b/src/main/resources/static/js/multitool/commands/select.js @@ -0,0 +1,59 @@ +import { Command } from "./command.js"; + +export class SelectPageCommand extends Command { + constructor(pageNumber, checkbox) { + super(); + this.pageNumber = pageNumber; + this.selectCheckbox = checkbox; + } + + execute() { + if (this.selectCheckbox.checked) { + //adds to array of selected pages + window.selectedPages.push(this.pageNumber); + } else { + //remove page from selected pages array + const index = window.selectedPages.indexOf(this.pageNumber); + if (index !== -1) { + window.selectedPages.splice(index, 1); + } + } + + if (window.selectedPages.length > 0 && !window.selectPage) { + window.toggleSelectPageVisibility(); + } + if (window.selectedPages.length == 0 && window.selectPage) { + window.toggleSelectPageVisibility(); + } + + window.updateSelectedPagesDisplay(); + } + + undo() { + this.selectCheckbox.checked = !this.selectCheckbox.checked; + if (this.selectCheckbox.checked) { + //adds to array of selected pages + window.selectedPages.push(this.pageNumber); + } else { + //remove page from selected pages array + const index = window.selectedPages.indexOf(this.pageNumber); + if (index !== -1) { + window.selectedPages.splice(index, 1); + } + } + + if (window.selectedPages.length > 0 && !window.selectPage) { + window.toggleSelectPageVisibility(); + } + if (window.selectedPages.length == 0 && window.selectPage) { + window.toggleSelectPageVisibility(); + } + + window.updateSelectedPagesDisplay(); + } + + redo() { + this.selectCheckbox.checked = !this.selectCheckbox.checked; + this.execute(); + } +} diff --git a/src/main/resources/static/js/multitool/commands/split.js b/src/main/resources/static/js/multitool/commands/split.js new file mode 100644 index 00000000..3cbc32cd --- /dev/null +++ b/src/main/resources/static/js/multitool/commands/split.js @@ -0,0 +1,101 @@ +import { Command } from "./command.js"; + +export class SplitFileCommand extends Command { + constructor(element, splitClass) { + super(); + this.element = element; + this.splitClass = splitClass; + } + + execute() { + this.element.classList.toggle(this.splitClass); + } + + undo() { + this.element.classList.toggle(this.splitClass); + } + + redo() { + this.execute(); + } +} + +export class SplitAllCommand extends Command { + constructor(elements, isSelectedInWindow, selectedPages, splitClass) { + super(); + this.elements = elements; + this.isSelectedInWindow = isSelectedInWindow; + this.selectedPages = selectedPages; + this.splitClass = splitClass; + } + + execute() { + if (!this.isSelectedInWindow) { + const hasSplit = this._hasSplit(this.elements, this.splitClass); + if (hasSplit) { + this.elements.forEach((page) => { + page.classList.remove(this.splitClass); + }); + } else { + this.elements.forEach((page) => { + page.classList.add(this.splitClass); + }); + } + return; + } + + this.elements.forEach((page, index) => { + const pageIndex = index; + if (this.isSelectedInWindow && !this.selectedPages.includes(pageIndex)) + return; + + if (page.classList.contains(this.splitClass)) { + page.classList.remove(this.splitClass); + } else { + page.classList.add(this.splitClass); + } + }); + } + + _hasSplit() { + if (!this.elements || this.elements.length == 0) return false; + + for (const node of this.elements) { + if (node.classList.contains(this.splitClass)) return true; + } + + return false; + } + + undo() { + if (!this.isSelectedInWindow) { + const hasSplit = this._hasSplit(this.elements, this.splitClass); + if (hasSplit) { + this.elements.forEach((page) => { + page.classList.remove(this.splitClass); + }); + } else { + this.elements.forEach((page) => { + page.classList.add(this.splitClass); + }); + } + return; + } + + this.elements.forEach((page, index) => { + const pageIndex = index; + if (this.isSelectedInWindow && !this.selectedPages.includes(pageIndex)) + return; + + if (page.classList.contains(this.splitClass)) { + page.classList.remove(this.splitClass); + } else { + page.classList.add(this.splitClass); + } + }); + } + + redo() { + this.execute(); + } +} diff --git a/src/main/resources/templates/multi-tool.html b/src/main/resources/templates/multi-tool.html index 2a47a1e9..14e5a85e 100644 --- a/src/main/resources/templates/multi-tool.html +++ b/src/main/resources/templates/multi-tool.html @@ -57,6 +57,27 @@ + + + + +