diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 0f3580d5a..2725e5f5a 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,5 +1,5 @@ blank_issues_enabled: true contact_links: - name: 💬 Discord Server - url: https://discord.gg/Cn8pWhQRxZ + url: https://discord.gg/HYmhKj45pU about: You can join our Discord server for real time discussion and support diff --git a/Dockerfile-ultra-lite b/Dockerfile-ultra-lite index c1bdd80de..09e4a5a38 100644 --- a/Dockerfile-ultra-lite +++ b/Dockerfile-ultra-lite @@ -1,5 +1,5 @@ # use alpine -FROM alpine:3.20.3 +FROM alpine:3.21.0 ARG VERSION_TAG diff --git a/README.md b/README.md index 543173bbb..5bf814773 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@

Stirling-PDF

[![Docker Pulls](https://img.shields.io/docker/pulls/frooodle/s-pdf)](https://hub.docker.com/r/frooodle/s-pdf) -[![Discord](https://img.shields.io/discord/1068636748814483718?label=Discord)](https://discord.gg/Cn8pWhQRxZ) +[![Discord](https://img.shields.io/discord/1068636748814483718?label=Discord)](https://discord.gg/HYmhKj45pU) [![Docker Image Version (tag latest semver)](https://img.shields.io/docker/v/frooodle/s-pdf/latest)](https://github.com/Stirling-Tools/Stirling-PDF/) [![GitHub Repo stars](https://img.shields.io/github/stars/stirling-tools/stirling-pdf?style=social)](https://github.com/Stirling-Tools/stirling-pdf) @@ -191,44 +191,44 @@ Stirling-PDF currently supports 38 languages! | Language | Progress | | -------------------------------------------- | -------------------------------------- | -| Arabic (العربية) (ar_AR) | ![95%](https://geps.dev/progress/95) | +| Arabic (العربية) (ar_AR) | ![94%](https://geps.dev/progress/94) | | Azerbaijani (Azərbaycan Dili) (az_AZ) | ![93%](https://geps.dev/progress/93) | -| Basque (Euskara) (eu_ES) | ![54%](https://geps.dev/progress/54) | +| Basque (Euskara) (eu_ES) | ![53%](https://geps.dev/progress/53) | | Bulgarian (Български) (bg_BG) | ![90%](https://geps.dev/progress/90) | -| Catalan (Català) (ca_CA) | ![85%](https://geps.dev/progress/85) | -| Croatian (Hrvatski) (hr_HR) | ![92%](https://geps.dev/progress/92) | +| Catalan (Català) (ca_CA) | ![84%](https://geps.dev/progress/84) | +| Croatian (Hrvatski) (hr_HR) | ![91%](https://geps.dev/progress/91) | | Czech (Česky) (cs_CZ) | ![91%](https://geps.dev/progress/91) | | Danish (Dansk) (da_DK) | ![90%](https://geps.dev/progress/90) | -| Dutch (Nederlands) (nl_NL) | ![90%](https://geps.dev/progress/90) | +| Dutch (Nederlands) (nl_NL) | ![89%](https://geps.dev/progress/89) | | English (English) (en_GB) | ![100%](https://geps.dev/progress/100) | | English (US) (en_US) | ![100%](https://geps.dev/progress/100) | -| French (Français) (fr_FR) | ![93%](https://geps.dev/progress/93) | -| German (Deutsch) (de_DE) | ![100%](https://geps.dev/progress/100) | -| Greek (Ελληνικά) (el_GR) | ![91%](https://geps.dev/progress/91) | -| Hindi (हिंदी) (hi_IN) | ![89%](https://geps.dev/progress/89) | -| Hungarian (Magyar) (hu_HU) | ![92%](https://geps.dev/progress/92) | +| French (Français) (fr_FR) | ![92%](https://geps.dev/progress/92) | +| German (Deutsch) (de_DE) | ![99%](https://geps.dev/progress/99) | +| Greek (Ελληνικά) (el_GR) | ![90%](https://geps.dev/progress/90) | +| Hindi (हिंदी) (hi_IN) | ![88%](https://geps.dev/progress/88) | +| Hungarian (Magyar) (hu_HU) | ![91%](https://geps.dev/progress/91) | | Indonesian (Bahasa Indonesia) (id_ID) | ![91%](https://geps.dev/progress/91) | | Irish (Gaeilge) (ga_IE) | ![83%](https://geps.dev/progress/83) | | Italian (Italiano) (it_IT) | ![99%](https://geps.dev/progress/99) | -| Japanese (日本語) (ja_JP) | ![81%](https://geps.dev/progress/81) | -| Korean (한국어) (ko_KR) | ![90%](https://geps.dev/progress/90) | -| Norwegian (Norsk) (no_NB) | ![83%](https://geps.dev/progress/83) | -| Persian (فارسی) (fa_IR) | ![100%](https://geps.dev/progress/100) | -| Polish (Polski) (pl_PL) | ![91%](https://geps.dev/progress/91) | +| Japanese (日本語) (ja_JP) | ![93%](https://geps.dev/progress/93) | +| Korean (한국어) (ko_KR) | ![89%](https://geps.dev/progress/89) | +| Norwegian (Norsk) (no_NB) | ![82%](https://geps.dev/progress/82) | +| Persian (فارسی) (fa_IR) | ![99%](https://geps.dev/progress/99) | +| Polish (Polski) (pl_PL) | ![90%](https://geps.dev/progress/90) | | Portuguese (Português) (pt_PT) | ![91%](https://geps.dev/progress/91) | -| Portuguese Brazilian (Português) (pt_BR) | ![92%](https://geps.dev/progress/92) | +| Portuguese Brazilian (Português) (pt_BR) | ![98%](https://geps.dev/progress/98) | | Romanian (Română) (ro_RO) | ![85%](https://geps.dev/progress/85) | -| Russian (Русский) (ru_RU) | ![91%](https://geps.dev/progress/91) | +| Russian (Русский) (ru_RU) | ![90%](https://geps.dev/progress/90) | | Serbian Latin alphabet (Srpski) (sr_LATN_RS) | ![67%](https://geps.dev/progress/67) | -| Simplified Chinese (简体中文) (zh_CN) | ![86%](https://geps.dev/progress/86) | +| Simplified Chinese (简体中文) (zh_CN) | ![93%](https://geps.dev/progress/93) | | Slovakian (Slovensky) (sk_SK) | ![78%](https://geps.dev/progress/78) | -| Spanish (Español) (es_ES) | ![92%](https://geps.dev/progress/92) | -| Swedish (Svenska) (sv_SE) | ![91%](https://geps.dev/progress/91) | -| Thai (ไทย) (th_TH) | ![91%](https://geps.dev/progress/91) | -| Traditional Chinese (繁體中文) (zh_TW) | ![92%](https://geps.dev/progress/92) | -| Turkish (Türkçe) (tr_TR) | ![87%](https://geps.dev/progress/87) | +| Spanish (Español) (es_ES) | ![91%](https://geps.dev/progress/91) | +| Swedish (Svenska) (sv_SE) | ![90%](https://geps.dev/progress/90) | +| Thai (ไทย) (th_TH) | ![90%](https://geps.dev/progress/90) | +| Traditional Chinese (繁體中文) (zh_TW) | ![91%](https://geps.dev/progress/91) | +| Turkish (Türkçe) (tr_TR) | ![86%](https://geps.dev/progress/86) | | Ukrainian (Українська) (uk_UA) | ![76%](https://geps.dev/progress/76) | -| Vietnamese (Tiếng Việt) (vi_VN) | ![84%](https://geps.dev/progress/84) | +| Vietnamese (Tiếng Việt) (vi_VN) | ![83%](https://geps.dev/progress/83) | ## Contributing (Creating Issues, Translations, Fixing Bugs, etc.) diff --git a/build.gradle b/build.gradle index 422fd5bc7..6a0862a82 100644 --- a/build.gradle +++ b/build.gradle @@ -296,7 +296,7 @@ dependencies { if (System.getenv("DOCKER_ENABLE_SECURITY") != "false") { implementation "org.springframework.boot:spring-boot-starter-security:$springBootVersion" - implementation "org.thymeleaf.extras:thymeleaf-extras-springsecurity5:3.1.2.RELEASE" + implementation "org.thymeleaf.extras:thymeleaf-extras-springsecurity5:3.1.3.RELEASE" implementation "org.springframework.boot:spring-boot-starter-data-jpa:$springBootVersion" implementation "org.springframework.boot:spring-boot-starter-oauth2-client:$springBootVersion" diff --git a/scripts/ignore_translation.toml b/scripts/ignore_translation.toml index 75cd2e0eb..281cf8638 100644 --- a/scripts/ignore_translation.toml +++ b/scripts/ignore_translation.toml @@ -77,6 +77,11 @@ ignore = [ 'language.direction', ] +[fa_IR] +ignore = [ + 'language.direction', +] + [fr_FR] ignore = [ 'AddStampRequest.alphabet', diff --git a/src/main/java/stirling/software/SPDF/controller/api/security/PasswordController.java b/src/main/java/stirling/software/SPDF/controller/api/security/PasswordController.java index d738ae795..be6b5019b 100644 --- a/src/main/java/stirling/software/SPDF/controller/api/security/PasswordController.java +++ b/src/main/java/stirling/software/SPDF/controller/api/security/PasswordController.java @@ -39,10 +39,7 @@ public class PasswordController { } @PostMapping(consumes = "multipart/form-data", value = "/remove-password") - @Operation( - summary = "Remove password from a PDF file", - description = - "This endpoint removes the password from a protected PDF file. Users need to provide the existing password. Input:PDF Output:PDF Type:SISO") + @Operation(summary = "Remove password from a PDF file", description = "This endpoint removes the password from a protected PDF file. Users need to provide the existing password. Input:PDF Output:PDF Type:SISO") public ResponseEntity removePassword(@ModelAttribute PDFPasswordRequest request) throws IOException { MultipartFile fileInput = request.getFileInput(); @@ -52,15 +49,12 @@ public class PasswordController { return WebResponseUtils.pdfDocToWebResponse( document, Filenames.toSimpleFileName(fileInput.getOriginalFilename()) - .replaceFirst("[.][^.]+$", "") + .replaceFirst("[.][^.]+$", "") + "_password_removed.pdf"); } @PostMapping(consumes = "multipart/form-data", value = "/add-password") - @Operation( - summary = "Add password to a PDF file", - description = - "This endpoint adds password protection to a PDF file. Users can specify a set of permissions that should be applied to the file. Input:PDF Output:PDF") + @Operation(summary = "Add password to a PDF file", description = "This endpoint adds password protection to a PDF file. Users can specify a set of permissions that should be applied to the file. Input:PDF Output:PDF") public ResponseEntity addPassword(@ModelAttribute AddPasswordRequest request) throws IOException { MultipartFile fileInput = request.getFileInput(); @@ -98,12 +92,12 @@ public class PasswordController { return WebResponseUtils.pdfDocToWebResponse( document, Filenames.toSimpleFileName(fileInput.getOriginalFilename()) - .replaceFirst("[.][^.]+$", "") + .replaceFirst("[.][^.]+$", "") + "_permissions.pdf"); return WebResponseUtils.pdfDocToWebResponse( document, Filenames.toSimpleFileName(fileInput.getOriginalFilename()) - .replaceFirst("[.][^.]+$", "") + .replaceFirst("[.][^.]+$", "") + "_passworded.pdf"); } } diff --git a/src/main/java/stirling/software/SPDF/utils/GeneralUtils.java b/src/main/java/stirling/software/SPDF/utils/GeneralUtils.java index b5654c7dc..1494b785e 100644 --- a/src/main/java/stirling/software/SPDF/utils/GeneralUtils.java +++ b/src/main/java/stirling/software/SPDF/utils/GeneralUtils.java @@ -88,15 +88,45 @@ public class GeneralUtils { public static boolean isURLReachable(String urlStr) { try { + // Parse the URL URL url = URI.create(urlStr).toURL(); + + // Allow only http and https protocols + String protocol = url.getProtocol(); + if (!protocol.equals("http") && !protocol.equals("https")) { + return false; // Disallow other protocols + } + + // Check if the host is a local address + String host = url.getHost(); + if (isLocalAddress(host)) { + return false; // Exclude local addresses + } + + // Check if the URL is reachable HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("HEAD"); + // connection.setConnectTimeout(5000); // Set connection timeout + // connection.setReadTimeout(5000); // Set read timeout int responseCode = connection.getResponseCode(); return (200 <= responseCode && responseCode <= 399); - } catch (MalformedURLException e) { - return false; - } catch (IOException e) { - return false; + } catch (Exception e) { + return false; // Return false in case of any exception + } + } + + private static boolean isLocalAddress(String host) { + try { + // Resolve DNS to IP address + InetAddress address = InetAddress.getByName(host); + + // Check for local addresses + return address.isAnyLocalAddress() || // Matches 0.0.0.0 or similar + address.isLoopbackAddress() || // Matches 127.0.0.1 or ::1 + address.isSiteLocalAddress() || // Matches private IPv4 ranges: 192.168.x.x, 10.x.x.x, 172.16.x.x to 172.31.x.x + address.getHostAddress().startsWith("fe80:"); // Matches link-local IPv6 addresses + } catch (Exception e) { + return false; // Return false for invalid or unresolved addresses } } diff --git a/src/main/resources/messages_ar_AR.properties b/src/main/resources/messages_ar_AR.properties index a519beccf..954ce64b3 100644 --- a/src/main/resources/messages_ar_AR.properties +++ b/src/main/resources/messages_ar_AR.properties @@ -965,6 +965,16 @@ multiTool.dragDropMessage=الصفحات المحددة multiTool.undo=تراجع multiTool.redo=إعادة إجراء +#decrypt +decrypt.passwordPrompt=This file is password-protected. Please enter the password: +decrypt.cancelled=Operation cancelled for PDF: {0} +decrypt.noPassword=No password provided for encrypted PDF: {0} +decrypt.invalidPassword=Please try again with the correct password. +decrypt.invalidPasswordHeader=Incorrect password or unsupported encryption for PDF: {0} +decrypt.unexpectedError=There was an error processing the file. Please try again. +decrypt.serverError=Server error while decrypting: {0} +decrypt.success=File decrypted successfully. + #multiTool-advert multiTool-advert.message=هذه الميزة متوفرة في صفحة الأدوات المتعددة لدينا. اطلع عليها للحصول على واجهة مستخدم محسّنة لكل صفحة وميزات إضافية! diff --git a/src/main/resources/messages_az_AZ.properties b/src/main/resources/messages_az_AZ.properties index 07d170b05..dcffafa66 100644 --- a/src/main/resources/messages_az_AZ.properties +++ b/src/main/resources/messages_az_AZ.properties @@ -965,6 +965,16 @@ multiTool.dragDropMessage=Seçilmiş Səhifə(lər) multiTool.undo=Undo multiTool.redo=Redo +#decrypt +decrypt.passwordPrompt=This file is password-protected. Please enter the password: +decrypt.cancelled=Operation cancelled for PDF: {0} +decrypt.noPassword=No password provided for encrypted PDF: {0} +decrypt.invalidPassword=Please try again with the correct password. +decrypt.invalidPasswordHeader=Incorrect password or unsupported encryption for PDF: {0} +decrypt.unexpectedError=There was an error processing the file. Please try again. +decrypt.serverError=Server error while decrypting: {0} +decrypt.success=File decrypted successfully. + #multiTool-advert 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! diff --git a/src/main/resources/messages_bg_BG.properties b/src/main/resources/messages_bg_BG.properties index 16f9d5bcc..8c6b510f6 100644 --- a/src/main/resources/messages_bg_BG.properties +++ b/src/main/resources/messages_bg_BG.properties @@ -965,6 +965,16 @@ multiTool.dragDropMessage=Page(s) Selected multiTool.undo=Undo multiTool.redo=Redo +#decrypt +decrypt.passwordPrompt=This file is password-protected. Please enter the password: +decrypt.cancelled=Operation cancelled for PDF: {0} +decrypt.noPassword=No password provided for encrypted PDF: {0} +decrypt.invalidPassword=Please try again with the correct password. +decrypt.invalidPasswordHeader=Incorrect password or unsupported encryption for PDF: {0} +decrypt.unexpectedError=There was an error processing the file. Please try again. +decrypt.serverError=Server error while decrypting: {0} +decrypt.success=File decrypted successfully. + #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 b847662db..2cf560b14 100644 --- a/src/main/resources/messages_ca_CA.properties +++ b/src/main/resources/messages_ca_CA.properties @@ -965,6 +965,16 @@ multiTool.dragDropMessage=Page(s) Selected multiTool.undo=Undo multiTool.redo=Redo +#decrypt +decrypt.passwordPrompt=This file is password-protected. Please enter the password: +decrypt.cancelled=Operation cancelled for PDF: {0} +decrypt.noPassword=No password provided for encrypted PDF: {0} +decrypt.invalidPassword=Please try again with the correct password. +decrypt.invalidPasswordHeader=Incorrect password or unsupported encryption for PDF: {0} +decrypt.unexpectedError=There was an error processing the file. Please try again. +decrypt.serverError=Server error while decrypting: {0} +decrypt.success=File decrypted successfully. + #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 86147c844..fbf4b21f9 100644 --- a/src/main/resources/messages_cs_CZ.properties +++ b/src/main/resources/messages_cs_CZ.properties @@ -965,6 +965,16 @@ multiTool.dragDropMessage=Page(s) Selected multiTool.undo=Undo multiTool.redo=Redo +#decrypt +decrypt.passwordPrompt=This file is password-protected. Please enter the password: +decrypt.cancelled=Operation cancelled for PDF: {0} +decrypt.noPassword=No password provided for encrypted PDF: {0} +decrypt.invalidPassword=Please try again with the correct password. +decrypt.invalidPasswordHeader=Incorrect password or unsupported encryption for PDF: {0} +decrypt.unexpectedError=There was an error processing the file. Please try again. +decrypt.serverError=Server error while decrypting: {0} +decrypt.success=File decrypted successfully. + #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 127a8cdde..ad383ff81 100644 --- a/src/main/resources/messages_da_DK.properties +++ b/src/main/resources/messages_da_DK.properties @@ -965,6 +965,16 @@ multiTool.dragDropMessage=Page(s) Selected multiTool.undo=Undo multiTool.redo=Redo +#decrypt +decrypt.passwordPrompt=This file is password-protected. Please enter the password: +decrypt.cancelled=Operation cancelled for PDF: {0} +decrypt.noPassword=No password provided for encrypted PDF: {0} +decrypt.invalidPassword=Please try again with the correct password. +decrypt.invalidPasswordHeader=Incorrect password or unsupported encryption for PDF: {0} +decrypt.unexpectedError=There was an error processing the file. Please try again. +decrypt.serverError=Server error while decrypting: {0} +decrypt.success=File decrypted successfully. + #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 9e00754dc..06de0a844 100644 --- a/src/main/resources/messages_de_DE.properties +++ b/src/main/resources/messages_de_DE.properties @@ -965,6 +965,16 @@ multiTool.dragDropMessage=Ausgewählte Seite(n) multiTool.undo=Rückgängig machen multiTool.redo=Wiederherstellen +#decrypt +decrypt.passwordPrompt=This file is password-protected. Please enter the password: +decrypt.cancelled=Operation cancelled for PDF: {0} +decrypt.noPassword=No password provided for encrypted PDF: {0} +decrypt.invalidPassword=Please try again with the correct password. +decrypt.invalidPasswordHeader=Incorrect password or unsupported encryption for PDF: {0} +decrypt.unexpectedError=There was an error processing the file. Please try again. +decrypt.serverError=Server error while decrypting: {0} +decrypt.success=File decrypted successfully. + #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 6b3f1a8ec..9c2e427df 100644 --- a/src/main/resources/messages_el_GR.properties +++ b/src/main/resources/messages_el_GR.properties @@ -965,6 +965,16 @@ multiTool.dragDropMessage=Page(s) Selected multiTool.undo=Undo multiTool.redo=Redo +#decrypt +decrypt.passwordPrompt=This file is password-protected. Please enter the password: +decrypt.cancelled=Operation cancelled for PDF: {0} +decrypt.noPassword=No password provided for encrypted PDF: {0} +decrypt.invalidPassword=Please try again with the correct password. +decrypt.invalidPasswordHeader=Incorrect password or unsupported encryption for PDF: {0} +decrypt.unexpectedError=There was an error processing the file. Please try again. +decrypt.serverError=Server error while decrypting: {0} +decrypt.success=File decrypted successfully. + #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 0f7bdd1c0..4056f9726 100644 --- a/src/main/resources/messages_en_GB.properties +++ b/src/main/resources/messages_en_GB.properties @@ -965,6 +965,16 @@ multiTool.dragDropMessage=Page(s) Selected multiTool.undo=Undo multiTool.redo=Redo +#decrypt +decrypt.passwordPrompt=This file is password-protected. Please enter the password: +decrypt.cancelled=Operation cancelled for PDF: {0} +decrypt.noPassword=No password provided for encrypted PDF: {0} +decrypt.invalidPassword=Please try again with the correct password. +decrypt.invalidPasswordHeader=Incorrect password or unsupported encryption for PDF: {0} +decrypt.unexpectedError=There was an error processing the file. Please try again. +decrypt.serverError=Server error while decrypting: {0} +decrypt.success=File decrypted successfully. + #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 f5f2b8f83..dbd67e2c2 100644 --- a/src/main/resources/messages_en_US.properties +++ b/src/main/resources/messages_en_US.properties @@ -965,6 +965,16 @@ multiTool.dragDropMessage=Page(s) Selected multiTool.undo=Undo multiTool.redo=Redo +#decrypt +decrypt.passwordPrompt=This file is password-protected. Please enter the password: +decrypt.cancelled=Operation cancelled for PDF: {0} +decrypt.noPassword=No password provided for encrypted PDF: {0} +decrypt.invalidPassword=Please try again with the correct password. +decrypt.invalidPasswordHeader=Incorrect password or unsupported encryption for PDF: {0} +decrypt.unexpectedError=There was an error processing the file. Please try again. +decrypt.serverError=Server error while decrypting: {0} +decrypt.success=File decrypted successfully. + #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 4f3fcfbe6..d1c50df73 100644 --- a/src/main/resources/messages_es_ES.properties +++ b/src/main/resources/messages_es_ES.properties @@ -965,6 +965,16 @@ multiTool.dragDropMessage=Page(s) Selected multiTool.undo=Undo multiTool.redo=Redo +#decrypt +decrypt.passwordPrompt=This file is password-protected. Please enter the password: +decrypt.cancelled=Operation cancelled for PDF: {0} +decrypt.noPassword=No password provided for encrypted PDF: {0} +decrypt.invalidPassword=Please try again with the correct password. +decrypt.invalidPasswordHeader=Incorrect password or unsupported encryption for PDF: {0} +decrypt.unexpectedError=There was an error processing the file. Please try again. +decrypt.serverError=Server error while decrypting: {0} +decrypt.success=File decrypted successfully. + #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 393722c4e..aebd93e3e 100644 --- a/src/main/resources/messages_eu_ES.properties +++ b/src/main/resources/messages_eu_ES.properties @@ -965,6 +965,16 @@ multiTool.dragDropMessage=Page(s) Selected multiTool.undo=Undo multiTool.redo=Redo +#decrypt +decrypt.passwordPrompt=This file is password-protected. Please enter the password: +decrypt.cancelled=Operation cancelled for PDF: {0} +decrypt.noPassword=No password provided for encrypted PDF: {0} +decrypt.invalidPassword=Please try again with the correct password. +decrypt.invalidPasswordHeader=Incorrect password or unsupported encryption for PDF: {0} +decrypt.unexpectedError=There was an error processing the file. Please try again. +decrypt.serverError=Server error while decrypting: {0} +decrypt.success=File decrypted successfully. + #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_fa_IR.properties b/src/main/resources/messages_fa_IR.properties index 750776f2a..13c0a09de 100644 --- a/src/main/resources/messages_fa_IR.properties +++ b/src/main/resources/messages_fa_IR.properties @@ -122,6 +122,7 @@ enterpriseEdition.warning=این ویژگی فقط برای کاربران حر enterpriseEdition.yamlAdvert=Stirling PDF Pro از فایل‌های پیکربندی YAML و دیگر ویژگی‌های SSO پشتیبانی می‌کند. enterpriseEdition.ssoAdvert=به دنبال ویژگی‌های بیشتر برای مدیریت کاربران هستید؟ Stirling PDF Pro را بررسی کنید + ################# # Analytics # ################# @@ -515,6 +516,7 @@ home.validateSignature.title=اعتبارسنجی امضای PDF home.validateSignature.desc=تأیید امضاها و گواهی‌های دیجیتال در اسناد PDF validateSignature.tags=امضا، تأیید، اعتبارسنجی، PDF، گواهی‌نامه، امضای دیجیتال +#replace-invert-color replace-color.title=جایگزینی/معکوس کردن رنگ replace-color.header=جایگزینی/معکوس کردن رنگ PDF home.replaceColorPdf.title=جایگزینی و معکوس کردن رنگ @@ -535,7 +537,6 @@ replace-color.submit=جایگزینی - ########################### # # # WEB PAGES # @@ -611,6 +612,7 @@ MarkdownToPDF.help=در حال پیشرفت MarkdownToPDF.credit=از WeasyPrint استفاده می‌کند + #url-to-pdf URLToPDF.title=URL به PDF URLToPDF.header=URL به PDF @@ -903,7 +905,7 @@ compress.selectText.5=اندازه PDF مورد انتظار (مثلاً ۲۵MB compress.submit=فشرده‌سازی -# Add image +#Add image addImage.title=افزودن تصویر addImage.header=افزودن تصویر به PDF addImage.everyPage=هر صفحه؟ @@ -911,7 +913,7 @@ addImage.upload=افزودن تصویر addImage.submit=افزودن تصویر -# Merge +#merge merge.title=ادغام merge.header=ادغام چندین PDF (۲+) merge.sortByName=مرتب‌سازی بر اساس نام @@ -920,7 +922,7 @@ merge.removeCertSign=حذف امضای دیجیتال در فایل ادغام merge.submit=ادغام -# PDF Organizer +#pdfOrganiser pdfOrganiser.title=سازماندهی صفحات pdfOrganiser.header=سازماندهی صفحات PDF pdfOrganiser.submit=بازآرایی صفحات @@ -938,7 +940,7 @@ pdfOrganiser.mode.10=ادغام فرد-زوج pdfOrganiser.placeholder=(مثال: ۱,۳,۲ یا ۴-۸,۲,۱۰-۱۲ یا 2n-1) -# Multi Tool +#multiTool multiTool.title=ابزار چندگانه PDF multiTool.header=ابزار چندگانه PDF multiTool.uploadPrompts=نام فایل @@ -963,14 +965,24 @@ multiTool.dragDropMessage=صفحه(ها) انتخاب شده‌اند multiTool.undo=واگرد multiTool.redo=بازگرداندن -# Multi Tool Advert +#decrypt +decrypt.passwordPrompt=This file is password-protected. Please enter the password: +decrypt.cancelled=Operation cancelled for PDF: {0} +decrypt.noPassword=No password provided for encrypted PDF: {0} +decrypt.invalidPassword=Please try again with the correct password. +decrypt.invalidPasswordHeader=Incorrect password or unsupported encryption for PDF: {0} +decrypt.unexpectedError=There was an error processing the file. Please try again. +decrypt.serverError=Server error while decrypting: {0} +decrypt.success=File decrypted successfully. + +#multiTool-advert multiTool-advert.message=این ویژگی همچنین در صفحه ابزار چندگانه ما موجود است. برای رابط کاربری صفحه به صفحه پیشرفته و ویژگی‌های اضافی بررسی کنید! -# View PDF +#view pdf viewPdf.title=مشاهده PDF viewPdf.header=مشاهده PDF -# Page Remover +#pageRemover pageRemover.title=حذف صفحات pageRemover.header=حذف صفحات PDF pageRemover.pagesToDelete=صفحات برای حذف (یک لیست از اعداد صفحه جدا شده با کاما وارد کنید): @@ -978,14 +990,14 @@ pageRemover.submit=حذف صفحات pageRemover.placeholder=(مثال: ۱,۲,۶ یا ۱-۱۰,۱۵-۳۰) -# Rotate +#rotate rotate.title=چرخش PDF rotate.header=چرخش PDF rotate.selectAngle=زاویه چرخش را انتخاب کنید (به مضرب‌های ۹۰ درجه): rotate.submit=چرخش -# Split PDFs +#split-pdfs split.title=تقسیم PDF split.header=تقسیم PDF split.desc.1=اعدادی که انتخاب می‌کنید شماره صفحه‌هایی هستند که می‌خواهید بر روی آنها تقسیم انجام دهید @@ -1014,7 +1026,7 @@ imageToPDF.selectText.4=ادغام در یک PDF واحد imageToPDF.selectText.5=تبدیل به PDF های جداگانه -# PDF to Image +#pdfToImage pdfToImage.title=PDF به تصویر pdfToImage.header=PDF به تصویر pdfToImage.selectText=فرمت تصویر @@ -1029,7 +1041,7 @@ pdfToImage.submit=تبدیل pdfToImage.info=پایتون نصب نشده است. برای تبدیل WebP لازم است. -# Add Password +#addPassword addPassword.title=افزودن گذرواژه addPassword.header=افزودن گذرواژه (رمزنگاری) addPassword.selectText.1=انتخاب PDF برای رمزنگاری @@ -1051,7 +1063,7 @@ addPassword.selectText.16=محدودیت‌های باز شدن خود سند addPassword.submit=رمزنگاری -# Watermark +#watermark watermark.title=افزودن واترمارک watermark.header=افزودن واترمارک watermark.customColor=رنگ متن سفارشی @@ -1070,7 +1082,7 @@ watermark.type.1=متن watermark.type.2=تصویر -# Change Permissions +#Change permissions permissions.title=تغییر مجوزها permissions.header=تغییر مجوزها permissions.warning=برای اینکه این مجوزها غیرقابل تغییر باشند، توصیه می‌شود آنها را با گذرواژه از طریق صفحه افزودن گذرواژه تنظیم کنید @@ -1087,7 +1099,7 @@ permissions.selectText.10=جلوگیری از چاپ فرمت‌های مختل permissions.submit=تغییر -# Remove Password +#remove password removePassword.title=حذف گذرواژه removePassword.header=حذف گذرواژه (رمزگشایی) removePassword.selectText.1=PDFی را برای رمزگشایی انتخاب کنید @@ -1095,7 +1107,7 @@ removePassword.selectText.2=گذرواژه removePassword.submit=حذف -# Change Metadata +#changeMetadata changeMetadata.title=عنوان: changeMetadata.header=تغییر متاداده‌ها changeMetadata.selectText.1=لطفاً متغیرهایی که مایل به تغییر آنها هستید را ویرایش کنید @@ -1114,7 +1126,7 @@ changeMetadata.selectText.5=افزودن ورودی متاداده سفارشی changeMetadata.submit=تغییر -# PDF to PDF/A +#pdfToPDFA pdfToPDFA.title=PDF به PDF/A pdfToPDFA.header=PDF به PDF/A pdfToPDFA.credit=این سرویس از qpdf برای تبدیل PDF/A استفاده می‌کند @@ -1124,7 +1136,7 @@ pdfToPDFA.outputFormat=فرمت خروجی pdfToPDFA.pdfWithDigitalSignature=PDF حاوی یک امضای دیجیتال است. این در مرحله بعد حذف خواهد شد. -# PDF to Word +#PDFToWord PDFToWord.title=PDF به ورد PDFToWord.header=PDF به ورد PDFToWord.selectText.1=فرمت فایل خروجی @@ -1132,7 +1144,7 @@ PDFToWord.credit=این سرویس از LibreOffice برای تبدیل فایل PDFToWord.submit=تبدیل -# PDF to Presentation +#PDFToPresentation PDFToPresentation.title=PDF به ارائه PDFToPresentation.header=PDF به ارائه PDFToPresentation.selectText.1=فرمت فایل خروجی @@ -1140,7 +1152,7 @@ PDFToPresentation.credit=این سرویس از LibreOffice برای تبدیل PDFToPresentation.submit=تبدیل -# PDF to Text +#PDFToText PDFToText.title=PDF به RTF (متن) PDFToText.header=PDF به RTF (متن) PDFToText.selectText.1=فرمت فایل خروجی @@ -1148,27 +1160,26 @@ PDFToText.credit=این سرویس از LibreOffice برای تبدیل فایل PDFToText.submit=تبدیل -# PDF to HTML +#PDFToHTML PDFToHTML.title=PDF به HTML PDFToHTML.header=PDF به HTML PDFToHTML.credit=این سرویس از pdftohtml برای تبدیل فایل استفاده می‌کند. PDFToHTML.submit=تبدیل -# PDF to XML +#PDFToXML PDFToXML.title=PDF به XML PDFToXML.header=PDF به XML PDFToXML.credit=این سرویس از LibreOffice برای تبدیل فایل استفاده می‌کند. PDFToXML.submit=تبدیل -# PDF to CSV +#PDFToCSV PDFToCSV.title=PDF به CSV PDFToCSV.header=PDF به CSV PDFToCSV.prompt=صفحه‌ای که می‌خواهید جدول استخراج شود را انتخاب کنید PDFToCSV.submit=استخراج - -# Split by Size or Count +#split-by-size-or-count split-by-size-or-count.title=تقسیم PDF بر اساس اندازه یا تعداد split-by-size-or-count.header=تقسیم PDF بر اساس اندازه یا تعداد split-by-size-or-count.type.label=انتخاب نوع تقسیم @@ -1180,7 +1191,7 @@ split-by-size-or-count.value.placeholder=اندازه را وارد کنید (م split-by-size-or-count.submit=ارسال -# Overlay PDFs +#overlay-pdfs overlay-pdfs.header=ترکیب فایل‌های PDF overlay-pdfs.baseFile.label=انتخاب فایل پایه PDF overlay-pdfs.overlayFiles.label=انتخاب فایل‌های ترکیبی PDF @@ -1196,7 +1207,7 @@ overlay-pdfs.position.background=پس‌زمینه overlay-pdfs.submit=ارسال -# Split by Sections +#split-by-sections split-by-sections.title=تقسیم PDF به بخش‌ها split-by-sections.header=تقسیم PDF به بخش‌ها split-by-sections.horizontal.label=تقسیمات افقی @@ -1207,7 +1218,7 @@ split-by-sections.submit=تقسیم PDF split-by-sections.merge=ادغام به یک PDF -# Print File +#printFile printFile.title=چاپ فایل printFile.header=چاپ فایل به چاپگر printFile.selectText.1=انتخاب فایل برای چاپ @@ -1215,7 +1226,7 @@ printFile.selectText.2=نام چاپگر را وارد کنید printFile.submit=چاپ -# Licenses +#licenses licenses.nav=مجوزها licenses.title=مجوزهای شخص ثالث licenses.header=مجوزهای شخص ثالث @@ -1223,7 +1234,7 @@ licenses.module=ماژول licenses.version=نسخه licenses.license=مجوز -# Survey +#survey survey.nav=نظرسنجی survey.title=نظرسنجی Stirling-PDF survey.description=Stirling-PDF هیچ ردیابی ندارد، بنابراین ما می‌خواهیم از کاربران خود بشنویم تا Stirling-PDF را بهبود دهیم! @@ -1235,7 +1246,7 @@ survey.button=شرکت در نظرسنجی survey.dontShowAgain=دیگر نشان نده -# Error +#error error.sorry=متأسفیم برای مشکل موجود! error.needHelp=نیاز به کمک / یافتن مشکلی؟ error.contactTip=اگر هنوز مشکلی دارید، دریغ نکنید که با ما تماس بگیرید. می‌توانید یک تیکت در صفحه GitHub ما ارسال کنید یا از طریق Discord با ما تماس بگیرید: @@ -1249,14 +1260,13 @@ error.githubSubmit=GitHub - ارسال تیکت error.discordSubmit=Discord - ارسال پست پشتیبانی -# Remove Image +#remove-image removeImage.title=حذف تصویر removeImage.header=حذف تصویر removeImage.removeImage=حذف تصویر removeImage.submit=حذف تصویر -# Split by Chapters splitByChapters.title=تقسیم PDF بر اساس فصل‌ها splitByChapters.header=تقسیم PDF بر اساس فصل‌ها splitByChapters.bookmarkLevel=سطح نشانک @@ -1268,20 +1278,20 @@ splitByChapters.desc.3=شامل متادیتا: اگر انتخاب شده، م splitByChapters.desc.4=اجازه‌ی تکرار: اگر انتخاب شده باشد، اجازه می‌دهد نشانک‌های متعدد در یک صفحه، فایل‌های PDF جداگانه ایجاد کنند. splitByChapters.submit=تقسیم PDF -# File Chooser +#File Chooser fileChooser.click=کلیک کنید fileChooser.or=یا fileChooser.dragAndDrop=بکشید و رها کنید fileChooser.hoveredDragAndDrop=فایل(های) خود را اینجا بکشید و رها کنید -# Release Notes +#release notes releases.footer=نسخه‌ها releases.title=یادداشت‌های نسخه releases.header=یادداشت‌های نسخه releases.current.version=نسخه فعلی releases.note=یادداشت‌های نسخه فقط به زبان انگلیسی موجود است -# Validate Signature +#Validate Signature validateSignature.title=اعتبارسنجی امضاهای PDF validateSignature.header=اعتبارسنجی امضای دیجیتال validateSignature.selectPDF=فایل PDF امضاشده را انتخاب کنید diff --git a/src/main/resources/messages_fr_FR.properties b/src/main/resources/messages_fr_FR.properties index 2e26c3ede..90f670c3f 100644 --- a/src/main/resources/messages_fr_FR.properties +++ b/src/main/resources/messages_fr_FR.properties @@ -965,6 +965,16 @@ multiTool.dragDropMessage=Page(s) sélectionnées multiTool.undo=Undo multiTool.redo=Redo +#decrypt +decrypt.passwordPrompt=This file is password-protected. Please enter the password: +decrypt.cancelled=Operation cancelled for PDF: {0} +decrypt.noPassword=No password provided for encrypted PDF: {0} +decrypt.invalidPassword=Please try again with the correct password. +decrypt.invalidPasswordHeader=Incorrect password or unsupported encryption for PDF: {0} +decrypt.unexpectedError=There was an error processing the file. Please try again. +decrypt.serverError=Server error while decrypting: {0} +decrypt.success=File decrypted successfully. + #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 6dfacc52c..087924ef3 100644 --- a/src/main/resources/messages_ga_IE.properties +++ b/src/main/resources/messages_ga_IE.properties @@ -965,6 +965,16 @@ multiTool.dragDropMessage=Page(s) Selected multiTool.undo=Undo multiTool.redo=Redo +#decrypt +decrypt.passwordPrompt=This file is password-protected. Please enter the password: +decrypt.cancelled=Operation cancelled for PDF: {0} +decrypt.noPassword=No password provided for encrypted PDF: {0} +decrypt.invalidPassword=Please try again with the correct password. +decrypt.invalidPasswordHeader=Incorrect password or unsupported encryption for PDF: {0} +decrypt.unexpectedError=There was an error processing the file. Please try again. +decrypt.serverError=Server error while decrypting: {0} +decrypt.success=File decrypted successfully. + #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 4a991aee6..957238e06 100644 --- a/src/main/resources/messages_hi_IN.properties +++ b/src/main/resources/messages_hi_IN.properties @@ -965,6 +965,16 @@ multiTool.dragDropMessage=Page(s) Selected multiTool.undo=Undo multiTool.redo=Redo +#decrypt +decrypt.passwordPrompt=This file is password-protected. Please enter the password: +decrypt.cancelled=Operation cancelled for PDF: {0} +decrypt.noPassword=No password provided for encrypted PDF: {0} +decrypt.invalidPassword=Please try again with the correct password. +decrypt.invalidPasswordHeader=Incorrect password or unsupported encryption for PDF: {0} +decrypt.unexpectedError=There was an error processing the file. Please try again. +decrypt.serverError=Server error while decrypting: {0} +decrypt.success=File decrypted successfully. + #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 a1b50f5c2..f22c1272f 100644 --- a/src/main/resources/messages_hr_HR.properties +++ b/src/main/resources/messages_hr_HR.properties @@ -965,6 +965,16 @@ multiTool.dragDropMessage=Page(s) Selected multiTool.undo=Undo multiTool.redo=Redo +#decrypt +decrypt.passwordPrompt=This file is password-protected. Please enter the password: +decrypt.cancelled=Operation cancelled for PDF: {0} +decrypt.noPassword=No password provided for encrypted PDF: {0} +decrypt.invalidPassword=Please try again with the correct password. +decrypt.invalidPasswordHeader=Incorrect password or unsupported encryption for PDF: {0} +decrypt.unexpectedError=There was an error processing the file. Please try again. +decrypt.serverError=Server error while decrypting: {0} +decrypt.success=File decrypted successfully. + #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 17ad8054d..0ac19e2f8 100644 --- a/src/main/resources/messages_hu_HU.properties +++ b/src/main/resources/messages_hu_HU.properties @@ -965,6 +965,16 @@ multiTool.dragDropMessage=Page(s) Selected multiTool.undo=Undo multiTool.redo=Redo +#decrypt +decrypt.passwordPrompt=This file is password-protected. Please enter the password: +decrypt.cancelled=Operation cancelled for PDF: {0} +decrypt.noPassword=No password provided for encrypted PDF: {0} +decrypt.invalidPassword=Please try again with the correct password. +decrypt.invalidPasswordHeader=Incorrect password or unsupported encryption for PDF: {0} +decrypt.unexpectedError=There was an error processing the file. Please try again. +decrypt.serverError=Server error while decrypting: {0} +decrypt.success=File decrypted successfully. + #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 486760f2e..4acf4dd44 100644 --- a/src/main/resources/messages_id_ID.properties +++ b/src/main/resources/messages_id_ID.properties @@ -965,6 +965,16 @@ multiTool.dragDropMessage=Page(s) Selected multiTool.undo=Undo multiTool.redo=Redo +#decrypt +decrypt.passwordPrompt=This file is password-protected. Please enter the password: +decrypt.cancelled=Operation cancelled for PDF: {0} +decrypt.noPassword=No password provided for encrypted PDF: {0} +decrypt.invalidPassword=Please try again with the correct password. +decrypt.invalidPasswordHeader=Incorrect password or unsupported encryption for PDF: {0} +decrypt.unexpectedError=There was an error processing the file. Please try again. +decrypt.serverError=Server error while decrypting: {0} +decrypt.success=File decrypted successfully. + #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 3586a3f64..d2b422c25 100644 --- a/src/main/resources/messages_it_IT.properties +++ b/src/main/resources/messages_it_IT.properties @@ -965,6 +965,16 @@ multiTool.dragDropMessage=Pagina(e) selezionata(e) multiTool.undo=Annulla multiTool.redo=Rifai +#decrypt +decrypt.passwordPrompt=Questo file è protetto da password. Inserisci la password: +decrypt.cancelled=Operazione annullata per il PDF: {0} +decrypt.noPassword=Nessuna password fornita per il PDF crittografato: {0} +decrypt.invalidPassword=Riprova con la password corretta. +decrypt.invalidPasswordHeader=Password errata o crittografia non supportata per il PDF: {0} +decrypt.unexpectedError=Si è verificato un errore durante l'elaborazione del file. Riprova.. +decrypt.serverError=Errore del server durante la decrittazione: {0} +decrypt.success=File decrittografato con successo. + #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! diff --git a/src/main/resources/messages_ja_JP.properties b/src/main/resources/messages_ja_JP.properties index 7d19771e7..efaae9571 100644 --- a/src/main/resources/messages_ja_JP.properties +++ b/src/main/resources/messages_ja_JP.properties @@ -56,12 +56,12 @@ userNotFoundMessage=ユーザーが見つかりません。 incorrectPasswordMessage=現在のパスワードが正しくありません。 usernameExistsMessage=新しいユーザー名はすでに存在します。 invalidUsernameMessage=ユーザー名が無効です。ユーザー名には文字、数字、およびそれに続く特殊文字 @._+- のみを含めることができます。または、有効な電子メール アドレスである必要があります。 -invalidPasswordMessage=The password must not be empty and must not have spaces at the beginning or end. +invalidPasswordMessage=パスワードは空にすることはできません。また、先頭・末尾にスペースを含めることもできません。 confirmPasswordErrorMessage=新しいパスワードと新しいパスワードの確認は一致する必要があります。 deleteCurrentUserMessage=現在ログインしているユーザーは削除できません。 deleteUsernameExistsMessage=そのユーザー名は存在しないため削除できません。 downgradeCurrentUserMessage=現在のユーザーの役割をダウングレードできません -disabledCurrentUserMessage=The current user cannot be disabled +disabledCurrentUserMessage=現在のユーザーを無効にすることはできません downgradeCurrentUserLongMessage=現在のユーザーの役割をダウングレードできません。したがって、現在のユーザーは表示されません。 userAlreadyExistsOAuthMessage=ユーザーは既にOAuth2ユーザーとして存在します。 userAlreadyExistsWebMessage=ユーザーは既にWebユーザーとして存在します。 @@ -76,12 +76,12 @@ donate=寄付する color=色 sponsor=スポンサー info=Info -pro=Pro -page=Page -pages=Pages -loading=Loading... -addToDoc=Add to Document -reset=Reset +pro=pro +page=ページ +pages=ページ +loading=読込中... +addToDoc=ドキュメントに追加 +reset=リセット legal.privacy=プライバシーポリシー legal.terms=利用規約 @@ -92,7 +92,7 @@ legal.impressum=著作権利者情報 ############### # Pipeline # ############### -pipeline.header=パイプラインメニュー (Alpha) +pipeline.header=パイプラインメニュー (Beta) pipeline.uploadButton=カスタムのアップロード pipeline.configureButton=設定 pipeline.defaultOption=カスタム @@ -117,21 +117,21 @@ pipelineOptions.validateButton=検証 ######################## # ENTERPRISE EDITION # ######################## -enterpriseEdition.button=Upgrade to Pro -enterpriseEdition.warning=This feature is only available to Pro users. -enterpriseEdition.yamlAdvert=Stirling PDF Pro supports YAML configuration files and other SSO features. -enterpriseEdition.ssoAdvert=Looking for more user management features? Check out Stirling PDF Pro +enterpriseEdition.button=Proにアップグレード +enterpriseEdition.warning=この機能はProユーザーのみが利用できます。 +enterpriseEdition.yamlAdvert=Stirling PDF Proは、YAML構成ファイルやその他のSSO機能をサポートしています。 +enterpriseEdition.ssoAdvert=より多くのユーザー管理機能をお探しですか? Stirling PDF Proをご覧ください ################# # Analytics # ################# -analytics.title=Do you want make Stirling PDF better? -analytics.paragraph1=Stirling PDF has opt in analytics to help us improve the product. We do not track any personal information or file contents. -analytics.paragraph2=Please consider enabling analytics to help Stirling-PDF grow and to allow us to understand our users better. -analytics.enable=Enable analytics -analytics.disable=Disable analytics -analytics.settings=You can change the settings for analytics in the config/settings.yml file +analytics.title=Stirling PDFをもっと良くしたいですか? +analytics.paragraph1=Stirling PDFでは、製品の改善に役立つ分析機能をオプトインしています。個人情報やファイルの内容を追跡することはありません。 +analytics.paragraph2=Stirling-PDFの成長を支援しユーザーをより深く理解できるように分析を有効にすることを検討してください。 +analytics.enable=分析を有効にする +analytics.disable=分析を無効にする +analytics.settings=config/settings.ymlファイルでアナリティクスの設定を変更できます。 ############# # NAVBAR # @@ -142,14 +142,14 @@ navbar.language=言語 navbar.settings=設定 navbar.allTools=ツール navbar.multiTool=マルチツール -navbar.search=Search +navbar.search=検索 navbar.sections.organize=整理 navbar.sections.convertTo=PDFへ変換 navbar.sections.convertFrom=PDFから変換 navbar.sections.security=署名とセキュリティ navbar.sections.advance=アドバンスド navbar.sections.edit=閲覧と編集 -navbar.sections.popular=Popular +navbar.sections.popular=人気 ############# # SETTINGS # @@ -208,7 +208,7 @@ adminUserSettings.user=ユーザー adminUserSettings.addUser=新しいユーザを追加 adminUserSettings.deleteUser=ユーザの削除 adminUserSettings.confirmDeleteUser=ユーザを本当に削除しますか? -adminUserSettings.confirmChangeUserStatus=Should the user be disabled/enabled? +adminUserSettings.confirmChangeUserStatus=ユーザーを無効/有効にする必要がありますか? adminUserSettings.usernameInfo=ユーザー名には、文字、数字、および次の特殊文字 @._+- のみを含めることができます。または、有効な電子メール アドレスである必要があります。 adminUserSettings.roles=役割 adminUserSettings.role=役割 @@ -247,8 +247,8 @@ database.fileNotFound=ファイルが見つかりません database.fileNullOrEmpty=ファイルは null または空であってはなりません database.failedImportFile=ファイルのインポートに失敗 -session.expired=Your session has expired. Please refresh the page and try again. -session.refreshPage=Refresh Page +session.expired=セッションが期限切れです。ページを更新してもう一度お試しください。 +session.refreshPage=ページを更新 ############# # HOME-PAGE # @@ -488,52 +488,52 @@ overlay-pdfs.tags=Overlay home.split-by-sections.title=PDFをセクションで分割 home.split-by-sections.desc=PDFの各ページを縦横に分割します。 -split-by-sections.tags=Section Split, Divide, Customize +split-by-sections.tags=Section Split, Divide, Customize,Customise home.AddStampRequest.title=PDFにスタンプを追加 home.AddStampRequest.desc=設定した位置にテキストや画像のスタンプを追加できます -AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Customize +AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Customize,Customise home.PDFToBook.title=PDFを書籍に変換 home.PDFToBook.desc=calibreを使用してPDFを書籍/コミック形式に変換します -PDFToBook.tags=Book,Comic,Calibre,Convert,manga,amazon,kindle +PDFToBook.tags=Book,Comic,Calibre,Convert,manga,amazon,kindle,epub,mobi,azw3,docx,rtf,txt,html,lit,fb2,pdb,lrf home.BookToPDF.title=PDFを書籍に変換 home.BookToPDF.desc=calibreを使用してPDFを書籍/コミック形式に変換します -BookToPDF.tags=Book,Comic,Calibre,Convert,manga,amazon,kindle +BookToPDF.tags=Book,Comic,Calibre,Convert,manga,amazon,kindle,epub,mobi,azw3,docx,rtf,txt,html,lit,fb2,pdb,lrf home.removeImagePdf.title=画像の削除 home.removeImagePdf.desc=PDFから画像を削除してファイルサイズを小さくします removeImagePdf.tags=Remove Image,Page operations,Back end,server side -home.splitPdfByChapters.title=Split PDF by Chapters -home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure. +home.splitPdfByChapters.title=PDFをチャプターごとに分割 +home.splitPdfByChapters.desc=チャプターの構造に基づいてPDFを複数のファイルに分割します splitPdfByChapters.tags=split,chapters,bookmarks,organize -home.validateSignature.title=Validate PDF Signature -home.validateSignature.desc=Verify digital signatures and certificates in PDF documents +home.validateSignature.title=PDF署名の検証 +home.validateSignature.desc=PDF文書のデジタル署名と証明書を検証します validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate #replace-invert-color -replace-color.title=Replace-Invert-Color -replace-color.header=Replace-Invert Color PDF -home.replaceColorPdf.title=Replace and Invert Color -home.replaceColorPdf.desc=Replace color for text and background in PDF and invert full color of pdf to reduce file size +replace-color.title=色の置換・反転 +replace-color.header=PDFの色の置換・反転 +home.replaceColorPdf.title=色の置換と反転 +home.replaceColorPdf.desc=PDF内のテキストと背景の色を置き換え、PDFのフルカラーを反転してファイルサイズを縮小します。 replaceColorPdf.tags=Replace Color,Page operations,Back end,server side -replace-color.selectText.1=Replace or Invert color Options -replace-color.selectText.2=Default(Default high contrast colors) -replace-color.selectText.3=Custom(Customized colors) -replace-color.selectText.4=Full-Invert(Invert all colors) -replace-color.selectText.5=High contrast color options -replace-color.selectText.6=white text on black background -replace-color.selectText.7=Black text on white background -replace-color.selectText.8=Yellow text on black background -replace-color.selectText.9=Green text on black background -replace-color.selectText.10=Choose text Color -replace-color.selectText.11=Choose background Color -replace-color.submit=Replace +replace-color.selectText.1=色の置換または反転オプション +replace-color.selectText.2=デフォルト(デフォルトの高コントラスト色) +replace-color.selectText.3=カスタム(カスタマイズされた色) +replace-color.selectText.4=フル反転(すべての色を反転) +replace-color.selectText.5=高コントラストカラーオプション +replace-color.selectText.6=黒背景に白文字 +replace-color.selectText.7=白背景に黒文字 +replace-color.selectText.8=黒背景に黄色文字 +replace-color.selectText.9=黒背景に緑文字 +replace-color.selectText.10=テキストの色を選択 +replace-color.selectText.11=背景色を選択 +replace-color.submit=置換 @@ -560,9 +560,9 @@ login.oauth2AccessDenied=アクセス拒否 login.oauth2InvalidTokenResponse=無効なトークン応答 login.oauth2InvalidIdToken=無効なIDトークン login.userIsDisabled=ユーザーは非アクティブ化されており、現在このユーザー名でのログインはブロックされています。管理者に連絡してください。 -login.alreadyLoggedIn=You are already logged in to -login.alreadyLoggedIn2=devices. Please log out of the devices and try again. -login.toManySessions=You have too many active sessions +login.alreadyLoggedIn=すでにログインしています +login.alreadyLoggedIn2=デバイスからログアウトしてもう一度お試しください。 +login.toManySessions=アクティブなセッションが多すぎます #auto-redact autoRedact.title=自動塗りつぶし @@ -578,8 +578,8 @@ autoRedact.submitButton=送信 #showJS -showJS.title=JavaScriptを表示 -showJS.header=JavaScriptを表示 +showJS.title=Javascriptを表示 +showJS.header=Javascriptを表示 showJS.downloadJS=Javascriptをダウンロード showJS.submit=表示 @@ -757,7 +757,7 @@ certSign.showSig=署名を表示 certSign.reason=理由 certSign.location=場所 certSign.name=名前 -certSign.showLogo=Show Logo +certSign.showLogo=ロゴを表示 certSign.submit=PDFに署名 @@ -792,9 +792,9 @@ compare.highlightColor.2=ハイライトカラー 2: compare.document.1=ドキュメント 1 compare.document.2=ドキュメント 2 compare.submit=比較 -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.complex.message=提供された文書の一方または両方が大きなファイルであるため、比較の精度が低下する可能性があります。 +compare.large.file.message=提供された文書の1つまたは両方が大きすぎて処理できません +compare.no.text.message=選択したPDFの1つまたは両方にテキストコンテンツがありません。比較するには、テキストを含むPDFを選択してください。 #BookToPDF BookToPDF.title=書籍やコミックをPDFに変換 @@ -803,8 +803,8 @@ BookToPDF.credit=calibreを使用 BookToPDF.submit=変換 #PDFToBook -PDFToBook.title=書籍をPDFに変換 -PDFToBook.header=書籍をPDFに変換 +PDFToBook.title=PDFを書籍に変換 +PDFToBook.header=PDFを書籍に変換 PDFToBook.selectText.1=フォーマット PDFToBook.credit=calibreを使用 PDFToBook.submit=変換 @@ -817,17 +817,17 @@ sign.draw=署名を書く sign.text=テキスト入力 sign.clear=クリア sign.add=追加 -sign.saved=Saved Signatures -sign.save=Save Signature -sign.personalSigs=Personal Signatures -sign.sharedSigs=Shared Signatures -sign.noSavedSigs=No saved signatures found -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.saved=保存された署名 +sign.save=署名を保存 +sign.personalSigs=個人署名 +sign.sharedSigs=共有署名 +sign.noSavedSigs=保存された署名が見つかりません +sign.addToAll=すべてのページに追加 +sign.delete=削除 +sign.first=最初のページ +sign.last=最後のページ +sign.next=次のページ +sign.previous=前のページ #repair repair.title=修復 @@ -944,29 +944,39 @@ pdfOrganiser.placeholder=(例:1,3,2または4-8,2,10-12または2n-1) multiTool.title=PDFマルチツール multiTool.header=PDFマルチツール multiTool.uploadPrompts=ファイル名 -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.selectAll=すべて選択 +multiTool.deselectAll=選択を解除 +multiTool.selectPages=ページ選択 +multiTool.selectedPages=選択したページ +multiTool.page=ページ +multiTool.deleteSelected=選択項目を削除 +multiTool.downloadAll=エクスポート +multiTool.downloadSelected=選択項目をエクスポート -multiTool.insertPageBreak=Insert Page Break -multiTool.addFile=Add File -multiTool.rotateLeft=Rotate Left -multiTool.rotateRight=Rotate Right -multiTool.split=Split -multiTool.moveLeft=Move Left -multiTool.moveRight=Move Right -multiTool.delete=Delete -multiTool.dragDropMessage=Page(s) Selected -multiTool.undo=Undo -multiTool.redo=Redo +multiTool.insertPageBreak=改ページを挿入 +multiTool.addFile=ファイルを追加 +multiTool.rotateLeft=左回転 +multiTool.rotateRight=右回転 +multiTool.split=分割 +multiTool.moveLeft=左に移動 +multiTool.moveRight=右に移動 +multiTool.delete=削除 +multiTool.dragDropMessage=選択されたページ +multiTool.undo=元に戻す +multiTool.redo=やり直す + +#decrypt +decrypt.passwordPrompt=このファイルはパスワードで保護されています。パスワードを入力してください: +decrypt.cancelled=PDFの操作がキャンセルされました: {0} +decrypt.noPassword=暗号化されたPDFにパスワードが指定されていません: {0} +decrypt.invalidPassword=正しいパスワードでもう一度お試しください。 +decrypt.invalidPasswordHeader=PDFのパスワードが正しくないか、暗号化がサポートされていません: {0} +decrypt.unexpectedError=ファイルの処理中にエラーが発生しました。もう一度お試しください。 +decrypt.serverError=復号化中にサーバーエラーが発生しました: {0} +decrypt.success=ファイルの暗号化が正常に完了しました。 #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=この機能は、マルチツールでもご利用いただけます。強化されたページごとのUIと追加機能についてはこちらをご覧ください。 #view pdf viewPdf.title=PDFを表示 @@ -1122,8 +1132,8 @@ pdfToPDFA.header=PDFをPDF/Aに変換 pdfToPDFA.credit=本サービスはPDF/Aの変換にqpdfを使用しています。 pdfToPDFA.submit=変換 pdfToPDFA.tip=現在、一度に複数の入力に対して機能しません -pdfToPDFA.outputFormat=Output format -pdfToPDFA.pdfWithDigitalSignature=PDF にはデジタル署名が含まれています。これは次の手順で削除されます。 +pdfToPDFA.outputFormat=出力形式 +pdfToPDFA.pdfWithDigitalSignature=PDFにはデジタル署名が含まれています。これは次の手順で削除されます。 #PDFToWord @@ -1228,8 +1238,8 @@ licenses.license=ライセンス survey.nav=アンケート survey.title=Stirling-PDFのアンケート survey.description=Stirling-PDFには追跡機能がないため、Stirling-PDFをより良くするために皆様の意見を聞かせてください! -survey.changes=Stirling-PDF has changed since the last survey! To find out more please check our blog post here: -survey.changes2=With these changes we are getting paid business support and funding +survey.changes=Stirling-PDFは前回の調査から変更されました。詳細についてはこちらのブログ投稿をご覧ください。 +survey.changes2=これらの変更により私たちは有償のビジネスサポートと資金援助を受けています survey.please=アンケートにご協力ください! survey.disabled=(アンケートのポップアップは、次の更新では無効になりますが、ページの下部に表示されます。) survey.button=アンケートに答える @@ -1257,61 +1267,61 @@ removeImage.removeImage=画像の削除 removeImage.submit=画像を削除 -splitByChapters.title=Split PDF by Chapters -splitByChapters.header=Split PDF by Chapters -splitByChapters.bookmarkLevel=Bookmark Level -splitByChapters.includeMetadata=Include Metadata -splitByChapters.allowDuplicates=Allow Duplicates -splitByChapters.desc.1=This tool splits a PDF file into multiple PDFs based on its chapter structure. -splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for splitting (0 for top-level, 1 for second-level, etc.). -splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF. -splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs. -splitByChapters.submit=Split PDF +splitByChapters.title=PDFをチャプターごとに分割 +splitByChapters.header=PDFをチャプターごとに分割 +splitByChapters.bookmarkLevel=ブックマークレベル +splitByChapters.includeMetadata=メタデータを含める +splitByChapters.allowDuplicates=重複を許可する +splitByChapters.desc.1=このツールは、チャプター構造に基づいてPDFファイルを複数のPDFに分割します。 +splitByChapters.desc.2=ブックマークレベル:分割に使用するブックマークのレベルを選択します(最上位レベルの場合は0、第2レベルの場合は1など)。 +splitByChapters.desc.3=メタデータを含める:チェックすると、元のPDFのメタデータが各分割PDFに含まれます。 +splitByChapters.desc.4=重複を許可:チェックすると同じページ上の複数のブックマークから個別のPDFを作成できます。 +splitByChapters.submit=PDFを分割 #File Chooser -fileChooser.click=Click -fileChooser.or=or -fileChooser.dragAndDrop=Drag & Drop -fileChooser.hoveredDragAndDrop=Drag & Drop file(s) here +fileChooser.click=クリック +fileChooser.or=または +fileChooser.dragAndDrop=ドラッグ&ドロップ +fileChooser.hoveredDragAndDrop=ファイルをここにドラッグ&ドロップ #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=リリース +releases.title=リリースノート +releases.header=リリースノート +releases.current.version=現在のリリース +releases.note=リリースノートは英語でのみで提供されています #Validate Signature -validateSignature.title=Validate PDF Signatures -validateSignature.header=Validate Digital Signatures -validateSignature.selectPDF=Select signed PDF file -validateSignature.submit=Validate Signatures -validateSignature.results=Validation Results -validateSignature.status=Status -validateSignature.signer=Signer -validateSignature.date=Date -validateSignature.reason=Reason -validateSignature.location=Location -validateSignature.noSignatures=No digital signatures found in this document -validateSignature.status.valid=Valid -validateSignature.status.invalid=Invalid -validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity -validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified -validateSignature.cert.expired=Certificate has expired -validateSignature.cert.revoked=Certificate has been revoked -validateSignature.signature.info=Signature Information -validateSignature.signature=Signature -validateSignature.signature.mathValid=Signature is mathematically valid BUT: -validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional) -validateSignature.cert.info=Certificate Details -validateSignature.cert.issuer=Issuer -validateSignature.cert.subject=Subject -validateSignature.cert.serialNumber=Serial Number -validateSignature.cert.validFrom=Valid From -validateSignature.cert.validUntil=Valid Until -validateSignature.cert.algorithm=Algorithm -validateSignature.cert.keySize=Key Size -validateSignature.cert.version=Version -validateSignature.cert.keyUsage=Key Usage -validateSignature.cert.selfSigned=Self-Signed -validateSignature.cert.bits=bits +validateSignature.title=PDF署名の検証 +validateSignature.header=デジタル署名の検証 +validateSignature.selectPDF=署名済みPDFファイルを選択 +validateSignature.submit=署名の検証 +validateSignature.results=検証結果 +validateSignature.status=状態 +validateSignature.signer=署名者 +validateSignature.date=日付 +validateSignature.reason=理由 +validateSignature.location=場所 +validateSignature.noSignatures=この文書にはデジタル署名が見つかりません +validateSignature.status.valid=有効 +validateSignature.status.invalid=無効 +validateSignature.chain.invalid=証明書チェーンの検証に失敗しました - 署名者の身元を確認できません +validateSignature.trust.invalid=証明書が信頼ストアにありません - ソースを検証できません +validateSignature.cert.expired=証明書の有効期限が切れています +validateSignature.cert.revoked=証明書は取り消されました +validateSignature.signature.info=署名情報 +validateSignature.signature=署名 +validateSignature.signature.mathValid=署名は数学的には有効ですが: +validateSignature.selectCustomCert=カスタム証明書ファイル X.509 (オプション) +validateSignature.cert.info=証明書の詳細 +validateSignature.cert.issuer=発行者 +validateSignature.cert.subject=主題 +validateSignature.cert.serialNumber=シリアルナンバー +validateSignature.cert.validFrom=有効開始日 +validateSignature.cert.validUntil=有効期限 +validateSignature.cert.algorithm=アルゴリズム +validateSignature.cert.keySize=キーサイズ +validateSignature.cert.version=バージョン +validateSignature.cert.keyUsage=キーの使用法 +validateSignature.cert.selfSigned=自己署名 +validateSignature.cert.bits=ビット diff --git a/src/main/resources/messages_ko_KR.properties b/src/main/resources/messages_ko_KR.properties index bd0c4f405..d418fb1e0 100644 --- a/src/main/resources/messages_ko_KR.properties +++ b/src/main/resources/messages_ko_KR.properties @@ -965,6 +965,16 @@ multiTool.dragDropMessage=Page(s) Selected multiTool.undo=Undo multiTool.redo=Redo +#decrypt +decrypt.passwordPrompt=This file is password-protected. Please enter the password: +decrypt.cancelled=Operation cancelled for PDF: {0} +decrypt.noPassword=No password provided for encrypted PDF: {0} +decrypt.invalidPassword=Please try again with the correct password. +decrypt.invalidPasswordHeader=Incorrect password or unsupported encryption for PDF: {0} +decrypt.unexpectedError=There was an error processing the file. Please try again. +decrypt.serverError=Server error while decrypting: {0} +decrypt.success=File decrypted successfully. + #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 7bbf83236..63425f1ab 100644 --- a/src/main/resources/messages_nl_NL.properties +++ b/src/main/resources/messages_nl_NL.properties @@ -965,6 +965,16 @@ multiTool.dragDropMessage=Page(s) Selected multiTool.undo=Undo multiTool.redo=Redo +#decrypt +decrypt.passwordPrompt=This file is password-protected. Please enter the password: +decrypt.cancelled=Operation cancelled for PDF: {0} +decrypt.noPassword=No password provided for encrypted PDF: {0} +decrypt.invalidPassword=Please try again with the correct password. +decrypt.invalidPasswordHeader=Incorrect password or unsupported encryption for PDF: {0} +decrypt.unexpectedError=There was an error processing the file. Please try again. +decrypt.serverError=Server error while decrypting: {0} +decrypt.success=File decrypted successfully. + #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 930f9754b..25bd2d4ac 100644 --- a/src/main/resources/messages_no_NB.properties +++ b/src/main/resources/messages_no_NB.properties @@ -965,6 +965,16 @@ multiTool.dragDropMessage=Page(s) Selected multiTool.undo=Undo multiTool.redo=Redo +#decrypt +decrypt.passwordPrompt=This file is password-protected. Please enter the password: +decrypt.cancelled=Operation cancelled for PDF: {0} +decrypt.noPassword=No password provided for encrypted PDF: {0} +decrypt.invalidPassword=Please try again with the correct password. +decrypt.invalidPasswordHeader=Incorrect password or unsupported encryption for PDF: {0} +decrypt.unexpectedError=There was an error processing the file. Please try again. +decrypt.serverError=Server error while decrypting: {0} +decrypt.success=File decrypted successfully. + #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 1d44e0276..2e142b822 100644 --- a/src/main/resources/messages_pl_PL.properties +++ b/src/main/resources/messages_pl_PL.properties @@ -965,6 +965,16 @@ multiTool.dragDropMessage=Page(s) Selected multiTool.undo=Undo multiTool.redo=Redo +#decrypt +decrypt.passwordPrompt=This file is password-protected. Please enter the password: +decrypt.cancelled=Operation cancelled for PDF: {0} +decrypt.noPassword=No password provided for encrypted PDF: {0} +decrypt.invalidPassword=Please try again with the correct password. +decrypt.invalidPasswordHeader=Incorrect password or unsupported encryption for PDF: {0} +decrypt.unexpectedError=There was an error processing the file. Please try again. +decrypt.serverError=Server error while decrypting: {0} +decrypt.success=File decrypted successfully. + #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 1c4371f1e..e5431c417 100644 --- a/src/main/resources/messages_pt_BR.properties +++ b/src/main/resources/messages_pt_BR.properties @@ -5,14 +5,14 @@ language.direction=ltr addPageNumbers.fontSize=Tamanho da Fonte addPageNumbers.fontName=Nome da Fonte -pdfPrompt=Selecione PDF(s) -multiPdfPrompt=Selecione PDFs (2+) -multiPdfDropPrompt=Selecione (ou arraste e solte) todos os PDFs desejados +pdfPrompt=Selecione o(s) PDF(s) +multiPdfPrompt=Selecione os PDFs (2+) +multiPdfDropPrompt=Selecione (ou arraste e solte) todos os PDFs desejados: imgPrompt=Selecione a(s) Imagem(ns) genericSubmit=Enviar -processTimeWarning=Aviso: esse processo pode levar até um minuto, dependendo do tamanho do arquivo -pageOrderPrompt=Ordem de Página Personalizada (Digite uma lista de números de páginas, separadas por vírgula ou Funções como 2n+1): -pageSelectionPrompt=Seleção de Página Personalizada (Digite uma lista de números de páginas, separadas por vírgula 1,5,6 ou Funções como 2n+1) : +processTimeWarning=Aviso: Este processo pode levar até um minuto, dependendo do tamanho do arquivo +pageOrderPrompt=Ordem de Página Personalizada (Digite uma lista de números de páginas, separadas por vírgula ou funções como 2n+1): +pageSelectionPrompt=Seleção de Página Personalizada (Digite uma lista de números de páginas, separadas por vírgula como 1,5,6 ou funções como 2n+1): goToPage=Ir true=Verdadeiro false=Falso @@ -23,7 +23,7 @@ close=Fechar filesSelected=Arquivos Selecionados noFavourites=Nenhum Favorito Adicionado downloadComplete=Download Completo -bored=Entediado Esperando? +bored=Entediado? Clique aqui! alphabet=Alfabeto downloadPdf=Baixar PDF text=Texto @@ -34,7 +34,7 @@ sizes.small=Pequeno sizes.medium=Médio sizes.large=Grande sizes.x-large=Extra grande -error.pdfPassword=O documento PDF está protegido por senha e a senha não foi fornecida ou está incorreta +error.pdfPassword=O PDF está protegido por senha e a senha não foi fornecida ou está incorreta delete=Apagar username=Usuário password=Senha @@ -46,7 +46,7 @@ red=Vermelho green=Verde blue=Azul custom=Personalizado... -WorkInProgess=Trabalho em progresso, Talvez não funcione ou apresente erros, Por favor, reporte qualquer problema! +WorkInProgess=Trabalho em progresso, talvez não funcione ou apresente erros, Por favor, reporte qualquer problema! poweredBy=Distribuído por yes=Sim no=Não @@ -55,11 +55,11 @@ notAuthenticatedMessage=Usuário não autenticado. userNotFoundMessage=Usuário não encontrado. incorrectPasswordMessage=A senha atual está incorreta. usernameExistsMessage=Novo Usuário já existe. -invalidUsernameMessage=Usuário inválido, nome de usuário só pode incluir letras, números e os seguintes caracteres especiais @._+- ou deve ser um e-mail válido. +invalidUsernameMessage=Usuário inválido, nome de usuário só pode conter letras, números e os seguintes caracteres especiais @._+- ou deve ser um e-mail válido. invalidPasswordMessage=A senha não deve estar vazia e não deve conter espaços no início ou no final. confirmPasswordErrorMessage=Nova Senha e Confirmar Nova Senha devem ser iguais. deleteCurrentUserMessage=Não é possível apagar usuário conectado no momento. -deleteUsernameExistsMessage=O usuário não existe e não pode ser apagado. +deleteUsernameExistsMessage=O usuário não existe e desta forma não pode ser apagado. downgradeCurrentUserMessage=Não é possível fazer downgrade da função do usuário conectado no momento. disabledCurrentUserMessage=O usuário atual não pode ser desativado. downgradeCurrentUserLongMessage=Não é possível fazer downgrade da função do usuário atual. Portanto, o usuário atual não será mostrado. @@ -70,8 +70,8 @@ oops=Ops! help=Ajuda goHomepage=Ir para a Página Inicial joinDiscord=Junte-se ao nosso servidor Discord -seeDockerHub=Visite o Docker Hub -visitGithub=Visite o repositório no GitHub +seeDockerHub=Visite nosso Docker Hub +visitGithub=Visite nosso repositório no GitHub donate=Doar color=Cor sponsor=Patrocinador @@ -81,7 +81,7 @@ page=Página pages=Páginas loading=Carregando... addToDoc=Adicionar ao Documento -reset=Reset +reset=Reiniciar legal.privacy=Política de Privacidade legal.terms=Termos e Condições @@ -93,42 +93,42 @@ legal.impressum=Informações legais # Pipeline # ############### pipeline.header=Menu do Pipeline (Beta) -pipeline.uploadButton=Upload Personalizado +pipeline.uploadButton=Upload de Arquivo Personalizado pipeline.configureButton=Configurar -pipeline.defaultOption=Personalizado +pipeline.defaultOption=Arquivo Personalizado pipeline.submitButton=Enviar -pipeline.help=Ajuda do Pipeline -pipeline.scanHelp=Ajuda para scanner de pastas -pipeline.deletePrompt=Tem certeza de que deseja excluir o pipeline +pipeline.help=Ajuda relacionada ao Pipeline +pipeline.scanHelp=Ajuda para leitura e processamento de pastas +pipeline.deletePrompt=Tem certeza de que deseja excluir o pipeline -> ###################### # Pipeline Options # ###################### pipelineOptions.header=Configuração do Pipeline -pipelineOptions.pipelineNameLabel=Nome do Pipeline +pipelineOptions.pipelineNameLabel=Nome do Pipeline: pipelineOptions.saveSettings=Salvar Configurações da Operação -pipelineOptions.pipelineNamePrompt=Insira o nome do pipeline aqui -pipelineOptions.selectOperation=Selecione uma Operação -pipelineOptions.addOperationButton=Adicione uma Operação +pipelineOptions.pipelineNamePrompt=Insira o nome do pipeline neste campo +pipelineOptions.selectOperation=Selecione uma Operação: +pipelineOptions.addOperationButton=Adicione a Operação pipelineOptions.pipelineHeader=Pipeline: -pipelineOptions.saveButton=Baixar +pipelineOptions.saveButton=Baixar (JSON) pipelineOptions.validateButton=Validar ######################## # ENTERPRISE EDITION # ######################## -enterpriseEdition.button=Atualize para versão Pro -enterpriseEdition.warning=Esse recurso só está disponivel para usuários da versão Pro. +enterpriseEdition.button=Atualize para a versão Pro +enterpriseEdition.warning=Este recurso só está disponivel para usuários da versão Pro. enterpriseEdition.yamlAdvert=Stirling PDF Pro suporta arquivos de configuração YAML e outros recursos SSO. -enterpriseEdition.ssoAdvert=Procurando por mais recursos de controle de usuários? Veja Stirling PDF Pro +enterpriseEdition.ssoAdvert=Procurando por mais recursos de controle de usuários? Veja a versão Pro do Stirling PDF ################# # Analytics # ################# -analytics.title=Você quer melhorar Stirling PDF? +analytics.title=Você quer melhorar o Stirling PDF? analytics.paragraph1=Stirling PDF possui coleta de dados opcional para ajudar a melhorar o produto. Nós não rastreamos nenhuma informação pessoal ou conteúdo dos arquivos. -analytics.paragraph2=Por favor considere habilitar coleta de dados para ajudar Stirling-PDF a crescer e nos ajudar a entender nossos usuários melhor. +analytics.paragraph2=Por favor considere habilitar a coleta de dados para ajudar Stirling PDF a crescer e nos ajudar a entender melhor nossos usuários. analytics.enable=Habilitar coleta de dados analytics.disable=Desabilitar coleta de dados analytics.settings=Você pode alterar as configurações de coleta de dados no arquivo config/settings.yml @@ -142,13 +142,13 @@ navbar.language=Idiomas navbar.settings=Configurações navbar.allTools=Ferramentas navbar.multiTool=Multiferramentas -navbar.search=Search +navbar.search=Pesquisar navbar.sections.organize=Organizar navbar.sections.convertTo=Converter para PDF navbar.sections.convertFrom=Converter de PDF navbar.sections.security=Assinatura & Segurança navbar.sections.advance=Avançado -navbar.sections.edit=Visualizar & editar +navbar.sections.edit=Visualizar & Editar navbar.sections.popular=Populares ############# @@ -157,16 +157,16 @@ navbar.sections.popular=Populares settings.title=Configurações settings.update=Atualização disponível settings.updateAvailable={0} é a versão atualmente instalada. Uma nova versão ({1}) está disponível. -settings.appVersion=Versão do aplicativo: -settings.downloadOption.title=Escolha a opção de download (para downloads não compactados de arquivo único): +settings.appVersion=Versão do Aplicativo: +settings.downloadOption.title=Escolha a opção de download (para download de arquivo único, não compactados): settings.downloadOption.1=Abrir na mesma janela settings.downloadOption.2=Abrir em nova janela -settings.downloadOption.3=Baixar arquivo -settings.zipThreshold=Compactar arquivos quando o número de arquivos baixados exceder +settings.downloadOption.3=Baixar o arquivo +settings.zipThreshold=Compactar os arquivos quando o número baixado exceder: settings.signOut=Sair -settings.accountSettings=Configurações de conta +settings.accountSettings=Configurações da Conta settings.bored.help=Habilitar jogos secretos -settings.cacheInputs.name=Salvar entradas do formulário +settings.cacheInputs.name=Salvar entradas do formulário. settings.cacheInputs.help=Habilitar para armazenar entradas usadas anteriormente para execuções futuras changeCreds.title=Alterar Credenciais @@ -180,8 +180,8 @@ changeCreds.submit=Enviar Alterações -account.title=Configurações de Conta -account.accountSettings=Configurações de Conta +account.title=Configurações da Conta +account.accountSettings=Configurações da Conta account.adminSettings=Configurações de Administrador – Visualizar e Adicionar Usuários account.userControlSettings=Configurações de Controle de Usuário account.changeUsername=Alterar Usuário @@ -193,8 +193,8 @@ account.changePassword=Alterar a Senha account.confirmNewPassword=Confirme a Nova Senha account.signOut=Sair account.yourApiKey=Sua chave de API -account.syncTitle=Sincronize as configurações do navegador com a conta -account.settingsCompare=Comparação de Configurações: +account.syncTitle=Sincronize as configurações do navegador com sua conta: +account.settingsCompare=Comparação das Configurações: account.property=Propriedade account.webBrowserSettings=Configuração do navegador Web account.syncToBrowser=Sincronizar Conta -> Navegador @@ -217,7 +217,7 @@ adminUserSettings.apiUser=Usuário de API limitado adminUserSettings.extraApiUser=Usuário de API limitado adicional adminUserSettings.webOnlyUser=Usuário web apenas adminUserSettings.demoUser=Usuário demo (Sem configurações personalizadas) -adminUserSettings.internalApiUser=Usuário interno de API +adminUserSettings.internalApiUser=Usuário de API interno adminUserSettings.forceChange=Forçar usuário a trocar a senha ao iniciar sessão adminUserSettings.submit=Salvar Usuário adminUserSettings.changeUserRole=Alterar Função do Usuário @@ -225,22 +225,22 @@ adminUserSettings.authenticated=Autenticado adminUserSettings.editOwnProfil=Editar próprio perfil adminUserSettings.enabledUser=usuário habilitado adminUserSettings.disabledUser=usuário desabilitado -adminUserSettings.activeUsers=Usuários ativos: -adminUserSettings.disabledUsers=Usuários desabilitados: -adminUserSettings.totalUsers=Total de usuários: +adminUserSettings.activeUsers=Usuários Ativos: +adminUserSettings.disabledUsers=Usuários Desabilitados: +adminUserSettings.totalUsers=Total de Usuários: adminUserSettings.lastRequest=Última solicitação database.title=Importar/Exportar banco de dados database.header=Importar/Exportar banco de dados -database.fileName=Nome do arquivo -database.creationDate=Data de criação -database.fileSize=Tamanho do arquivo +database.fileName=Nome do Arquivo +database.creationDate=Data de Criação +database.fileSize=Tamanho do Arquivo database.deleteBackupFile=Apagar arquivo de backup database.importBackupFile=Importar arquivo de backup database.downloadBackupFile=Baixar arquivo de backup database.info_1=Ao importar dados, é crucial garantir a estrutura correta. Se você não tem certeza do que está fazendo procure auxílio de um profissional. Um erro na estrutura pode ocasionar em mau funcionamento da aplicação, incluindo a impossibilidade da aplicação ser executada. -database.info_2=O nome do arquivo não importa ao enviar. Ele será renomeado em seguida para seguir o formato backup_user_yyyyMMddHHmm.sql, garantindo uma convenção de nomes coerente. +database.info_2=O nome do arquivo não importa ao enviar. Ele será renomeado em seguida para seguir o formato backup_usuario_yyyyMMddHHmm.sql, garantindo uma convenção de nomes coerente. database.submit=Importar Backup database.importIntoDatabaseSuccessed=Importação para o banco de dados bem sucedida database.fileNotFound=Arquivo não encontrado @@ -248,29 +248,29 @@ database.fileNullOrEmpty=O arquivo não pode estar nulo ou vazio database.failedImportFile=Falha ao importar arquivo session.expired=Sua sessão expirou. Por gentileza atualize a página e tente novamente. -session.refreshPage=Refresh Page +session.refreshPage=Atualizar Página ############# # HOME-PAGE # ############# -home.desc=Seu tudo-em-um hospedado localmente para tudo relacionado a PDFs. +home.desc=Seu tudo-em-um hospedado localmente para tudo relacionado a PDFs home.searchBar=Pesquisar funcionalidades... home.viewPdf.title=Visualizar PDF -home.viewPdf.desc=Visualizar, anotar, adicionar texto ou imagens +home.viewPdf.desc=Visualizar, anotar, adicionar texto ou imagens ao PDF. viewPdf.tags=visualizar,ler,anotar,texto,imagem -home.multiTool.title=Multiferramenta de PDF -home.multiTool.desc=Mesclar, girar, reorganizar, dividir e remover páginas -multiTool.tags=Multiferramenta, múltiplas operações, Interface do Usuário, Clique e arraste, front-end, lado do cliente, interativo, intratável, movimento, excluir, migrar, dividir +home.multiTool.title=Multiferramentas de PDF +home.multiTool.desc=Mesclar, girar, reorganizar, dividir, inserir e remover páginas. +multiTool.tags=Multiferramentas,múltiplas operações,Interface do Usuário,Clique e arraste,front-end,lado do cliente,interativo,intratável,movimento,excluir,migrar,dividir home.merge.title=Mesclar home.merge.desc=Mescle facilmente vários PDFs em um só. merge.tags=mesclar,Operações de Página,Back-end,lado do servidor home.split.title=Dividir -home.split.desc=Dividir PDFs em vários documentos +home.split.desc=Dividir PDFs em vários documentos/arquivos. split.tags=Operações de Página,dividir,Múltiplas Páginas,cortar,lado do servidor home.rotate.title=Girar @@ -279,41 +279,41 @@ rotate.tags=Lado do servidor home.imageToPdf.title=Imagem para PDF -home.imageToPdf.desc=Converter uma imagem (PNG, JPEG, GIF) em PDF. +home.imageToPdf.desc=Converter uma imagem (PNG, JPG, GIF) em PDF. imageToPdf.tags=conversão,img,jpg,imagem,foto home.pdfToImage.title=PDF para Imagem -home.pdfToImage.desc=Converter um PDF em uma imagem. (PNG, JPG, GIF) +home.pdfToImage.desc=Converter PDF em uma imagem (PNG, JPG, GIF e outros). pdfToImage.tags=conversão,img,jpg,imagem,foto -home.pdfOrganiser.title=Organizar -home.pdfOrganiser.desc=Remover/reorganizar as páginas em qualquer ordem. +home.pdfOrganiser.title=Organizar Páginas +home.pdfOrganiser.desc=Remover/reorganizar as páginas de diversas formas diferentes. pdfOrganiser.tags=duplex,par,ímpar,ordenar,mover home.addImage.title=Adicionar Imagem -home.addImage.desc=Adicionar uma imagem em um local definido no PDF +home.addImage.desc=Adicionar imagens em um local definido no PDF. addImage.tags=img,jpg,imagem,foto home.watermark.title=Adicionar Marca d'água -home.watermark.desc=Adicionar uma marca d'água personalizada ao seu documento PDF. +home.watermark.desc=Adicionar uma marca d'água personalizada ao seu PDF. watermark.tags=Texto,repetindo,rótulo,próprio,direitos autorais,marca registrada,img,jpg,imagem,foto home.permissions.title=Alterar Permissões -home.permissions.desc=Alterar as permissões do seu documento PDF. +home.permissions.desc=Alterar as permissões do seu PDF. permissions.tags=leitura,escrita,edição,impressão -home.removePages.title=Remover -home.removePages.desc=Excluir as páginas indesejadas do seu documento PDF. +home.removePages.title=Remover Páginas +home.removePages.desc=Excluir páginas indesejadas do seu PDF. removePages.tags=Remover páginas,excluir páginas -home.addPassword.title=Adicionar Senha -home.addPassword.desc=Criptografar seu documento PDF com uma senha. +home.addPassword.title=Proteger PDF +home.addPassword.desc=Criptografar seu PDF com uma senha podendo realizar alterações de permissões. addPassword.tags=seguro,segurança -home.removePassword.title=Remover Senha -home.removePassword.desc=Remover a proteção por senha do seu documento PDF. +home.removePassword.title=Desproteger PDF +home.removePassword.desc=Descriptografar o PDF realizando a remoção da senha. removePassword.tags=seguro, descriptografar, segurança, remover senha home.compressPdfs.title=Comprimir @@ -322,189 +322,189 @@ compressPdfs.tags=compactar,pequeno,mínimo home.changeMetadata.title=Alterar Metadados -home.changeMetadata.desc=Alterar/remover/adicionar metadados de um documento PDF. +home.changeMetadata.desc=Alterar/remover/adicionar metadados de um PDF. changeMetadata.tags=Título,autor,data,criação,hora,editor,produtor,estatísticas home.fileToPDF.title=Converter Arquivo para PDF -home.fileToPDF.desc=Converter praticamente qualquer arquivo em PDF (DOCX, PNG, XLS, PPT, TXT e mais) +home.fileToPDF.desc=Converter praticamente qualquer arquivo em PDF (DOCX, PNG, XLS, PPT, TXT e outros). fileToPDF.tags=transformação,formato,documento,imagem,slide,texto,conversão,escritório,documentos,word,excel,powerpoint -home.ocr.title=OCR / Limpeza de Digitalizações -home.ocr.desc=A limpeza verifica e detecta texto em imagens de um PDF e o adiciona novamente como texto. +home.ocr.title=Processamento de OCR +home.ocr.desc=Reconhecimento Óptico de Caracteres transforma PDFs com imagens em documentos pesquisáveis e com texto selecionável. ocr.tags=reconhecimento,texto,imagem,digitalização,leitura,identificação,detecção,editável home.extractImages.title=Extrair Imagens -home.extractImages.desc=Extrair todas as imagens de um PDF e salvá-las em um arquivo zip. +home.extractImages.desc=Extrair as imagens de um PDF e salvá-las em um arquivo compactado. extractImages.tags=imagem,foto,salvar,arquivo,zip,captura,coleta home.pdfToPDFA.title=PDF para PDF/A -home.pdfToPDFA.desc=Converter PDF para o formato PDF/A para armazenamento a longo prazo. +home.pdfToPDFA.desc=Converter o PDF para o formato PDF/A, voltado a armazenamento a longo prazo. pdfToPDFA.tags=arquivo,longo prazo,padrão,conversão,armazenamento,preservação home.PDFToWord.title=PDF para Word -home.PDFToWord.desc=Converter PDF para formatos Word (DOC, DOCX e ODT) +home.PDFToWord.desc=Converter PDF para formatos Word (DOC, DOCX e ODT). PDFToWord.tags=doc,docx,odt,word,transformação,formato,conversão,escritório,microsoft,doc home.PDFToPresentation.title=PDF para Apresentação -home.PDFToPresentation.desc=Converter PDF para formatos de apresentação (PPT, PPTX e ODP) +home.PDFToPresentation.desc=Converter PDF para formatos de Apresentação (PPT, PPTX e ODP). PDFToPresentation.tags=slides,apresentação,escritório,microsoft -home.PDFToText.title=PDF para Texto/RTF -home.PDFToText.desc=Converter PDF em formato de texto ou RTF +home.PDFToText.title=PDF para TXT/RTF +home.PDFToText.desc=Converter PDF em formato de TXT ou RTF. PDFToText.tags=formato rich,formato richtext,formato rich text home.PDFToHTML.title=PDF para HTML -home.PDFToHTML.desc=Converter PDF para o formato HTML +home.PDFToHTML.desc=Converter PDF para o formato HTML. PDFToHTML.tags=conteúdo web,compatível com navegador home.PDFToXML.title=PDF para XML -home.PDFToXML.desc=Converter PDF para formato XML +home.PDFToXML.desc=Converter PDF para formato XML. PDFToXML.tags=extração-de-dados,conteúdo-estruturado,interoperabilidade,transformação,converter home.ScannerImageSplit.title=Detectar/Dividir Fotos Digitalizadas -home.ScannerImageSplit.desc=Divide várias fotos de dentro de uma imagem/PDF +home.ScannerImageSplit.desc=Divide várias fotos de dentro de uma imagem/PDF. ScannerImageSplit.tags=separar,detecção-automática,digitalizações,fotos-múltiplas,organizar home.sign.title=Assinar -home.sign.desc=Adicionar assinatura ao PDF por desenho, texto ou imagem +home.sign.desc=Adicionar assinatura ao PDF por desenho, texto ou imagem. sign.tags=autorizar,iniciais,assinatura-desenhada,assinatura-de-texto,assinatura-de-imagem home.flatten.title=Achatar -home.flatten.desc=Remover todos os elementos e formulários interativos de um PDF +home.flatten.desc=Combinar todos os elementos e formulários interativos de um PDF em uma única camada fixa, não editável. flatten.tags=estático,desativar,não-interativo,otimizar home.repair.title=Reparar -home.repair.desc=Tentar reparar um PDF corrompido/quebrado +home.repair.desc=Tentar reparar um PDF corrompido/quebrado. repair.tags=corrigir,restaurar,correção,recuperar home.removeBlanks.title=Remover Páginas em Branco -home.removeBlanks.desc=Detectar e remover páginas em branco de um documento +home.removeBlanks.desc=Detectar e remover páginas em branco de um PDF. removeBlanks.tags=limpeza,otimização,sem-conteúdo,organizar home.removeAnnotations.title=Remover Anotações -home.removeAnnotations.desc=Remove todos os comentários/anotações de um PDF +home.removeAnnotations.desc=Remove todos os comentários/anotações de um PDF. removeAnnotations.tags=comentários,destaque,notas,marcação,remover home.compare.title=Comparar -home.compare.desc=Comparar e mostrar as diferenças entre 2 documentos PDF +home.compare.desc=Comparar e mostrar as diferenças entre dois documentos PDF. compare.tags=diferenciar,contraste,mudanças,análise home.certSign.title=Assinar com Certificado -home.certSign.desc=Assinar um PDF com um Certificado/Chave (PEM/P12) +home.certSign.desc=Assinar PDF com um Certificado/Chave (PEM/P12/JKS). certSign.tags=autenticar,PEM,P12,oficial,criptografar home.removeCertSign.title=Remover Assinatura com Certificado -home.removeCertSign.desc=Remover assinatura com certificado de PDF +home.removeCertSign.desc=Remover assinatura com Certificado/Chave (PEM/P12/JKS) em um PDF. removeCertSign.tags=autenticar,PEM,P12,oficial,descriptografar home.pageLayout.title=Layout de Múltiplas Páginas -home.pageLayout.desc=Mesclar várias páginas de um documento PDF em uma única página +home.pageLayout.desc=Mesclar várias páginas de um documento PDF em uma única página. pageLayout.tags=mesclar,composto,vista-única,organizar -home.scalePages.title=Ajustar Tamanho/Escala de Página +home.scalePages.title=Ajustar Tamanho/Escala da Página home.scalePages.desc=Alterar o tamanho/escala da página e/ou seu conteúdo. scalePages.tags=redimensionar,modificar,dimensão,adaptar home.pipeline.title=Pipeline -home.pipeline.desc=Executar várias ações em PDFs definindo scripts de pipeline +home.pipeline.desc=Executar várias ações em PDFs seguindo scripts de operações. pipeline.tags=automatizar,sequência,scriptado,processo-em-lote home.add-page-numbers.title=Adicionar Números de Página -home.add-page-numbers.desc=Adicionar números de página em todo o documento em um local definido +home.add-page-numbers.desc=Adicionar números de página no documento, em um local definido. add-page-numbers.tags=paginar,rotular,organizar,índice -home.auto-rename.title=Renomear Automaticamente o Arquivo PDF -home.auto-rename.desc=Renomeia automaticamente um arquivo PDF com base no cabeçalho detectado +home.auto-rename.title=Renomear Automaticamente o PDF +home.auto-rename.desc=Renomeia automaticamente o PDF com base no cabeçalho detectado. auto-rename.tags=detecção-automática,baseado-em-cabeçalho,organizar,relabel -home.adjust-contrast.title=Ajustar Cores/Contraste -home.adjust-contrast.desc=Ajustar Contraste, Saturação e Brilho de um PDF +home.adjust-contrast.title=Ajuste Visual do PDF +home.adjust-contrast.desc=Ajustar Contraste, Saturação e Brilho de um PDF. adjust-contrast.tags=correção-de-cor,ajustar,modificar,realçar -home.crop.title=Cortar PDF -home.crop.desc=Cortar um PDF para reduzir o tamanho (mantém o texto!) +home.crop.title=Recortar +home.crop.desc=Recortar trecho de um PDF para reduzir o tamanho. crop.tags=aparar,encolher,editar,formato home.autoSplitPDF.title=Divisão Automática de Páginas -home.autoSplitPDF.desc=Dividir automaticamente um PDF digitalizado com separador de páginas físicas QR Code +home.autoSplitPDF.desc=Dividir automaticamente um PDF digitalizado utilizando um separador de páginas físico com QR Code. autoSplitPDF.tags=baseado-em-QR,separar,segmento-de-digitalização,organizar home.sanitizePdf.title=Higienizar -home.sanitizePdf.desc=Remover scripts e outros elementos de arquivos PDF +home.sanitizePdf.desc=Remover scripts, links, metadados e outros elementos de um PDF. sanitizePdf.tags=limpar,seguro,protegido,remover-ameaças home.URLToPDF.title=Converter URL/Site para PDF -home.URLToPDF.desc=Converte qualquer página da internet para um arquivo PDF +home.URLToPDF.desc=Converter qualquer página da internet para um PDF. URLToPDF.tags=captura-de-web,salvar-página,web-para-doc,arquivar home.HTMLToPDF.title=HTML para PDF -home.HTMLToPDF.desc=Converte qualquer arquivo HTML ou zip para PDF +home.HTMLToPDF.desc=Converter qualquer arquivo HTML ou zip para PDF. HTMLToPDF.tags=marcação,conteúdo-web,transformação,converter home.MarkdownToPDF.title=Markdown para PDF -home.MarkdownToPDF.desc=Converte qualquer arquivo Markdown para PDF +home.MarkdownToPDF.desc=Converte qualquer arquivo Markdown para PDF. MarkdownToPDF.tags=marcação,conteúdo-web,transformação,converter -home.getPdfInfo.title=Obter TODAS as Informações de um PDF -home.getPdfInfo.desc=Obtém todas as informações possíveis de um PDF +home.getPdfInfo.title=Obter Informações de um PDF +home.getPdfInfo.desc=Obtém informações (metadata) de um PDF. getPdfInfo.tags=informações,dados,estatísticas home.extractPage.title=Extrair Página(s) -home.extractPage.desc=Extrai páginas selecionadas de um PDF +home.extractPage.desc=Extrair determinadas páginas de um PDF. extractPage.tags=extrair -home.PdfToSinglePage.title=PDF para Página Única Grande -home.PdfToSinglePage.desc=Combina todas as páginas de um PDF em uma única página grande +home.PdfToSinglePage.title=PDF para Página Única +home.PdfToSinglePage.desc=Combina todas as páginas de um PDF em uma única página. PdfToSinglePage.tags=página única home.showJS.title=Mostrar Javascript -home.showJS.desc=Procura e exibe qualquer JavaScript injetado em um PDF +home.showJS.desc=Procura, exibe e extrai qualquer JavaScript injetado em um PDF. showJS.tags=JavaScript -home.autoRedact.title=Auto Ocultar -home.autoRedact.desc=Ocultação automática (escurecimento) de texto em um PDF com base no texto de entrada +home.autoRedact.title=Ocultação de Texto +home.autoRedact.desc=Ocultação automática (escurecimento) de texto em um PDF com base em texto de entrada. autoRedact.tags=Redigir,ocultar,escurecer,preto,marcador,oculto home.tableExtraxt.title=PDF para CSV -home.tableExtraxt.desc=Extrai tabelas de um PDF convertendo para CSV +home.tableExtraxt.desc=Extração de tabelas de um PDF convertendo para CSV. tableExtraxt.tags=CSV,extração de tabela,extrair,converter -home.autoSizeSplitPDF.title=Divisão automática por tamanho/contagem -home.autoSizeSplitPDF.desc=Divida um único PDF em vários documentos com base no tamanho, contagem de páginas ou contagem de documentos +home.autoSizeSplitPDF.title=Divisão Manual do PDF +home.autoSizeSplitPDF.desc=Divida um PDF em vários, com base no tamanho, contagem de páginas ou contagem de documentos. autoSizeSplitPDF.tags=pdf,divisão,documento,organização home.overlay-pdfs.title=Sobrepor PDFs -home.overlay-pdfs.desc=Sobrepõe PDFs sobre outro PDF +home.overlay-pdfs.desc=Sobrepõe PDF sobre outro PDF. overlay-pdfs.tags=Sobreposição home.split-by-sections.title=Dividir PDF por Seções -home.split-by-sections.desc=Divida cada página de um PDF em seções horizontais e verticais menores +home.split-by-sections.desc=Divida cada página de um PDF em seções horizontais e/ou verticais menores. split-by-sections.tags=Seção Dividir, Dividir, Personalizar home.AddStampRequest.title=Adicionar Carimbo ao PDF -home.AddStampRequest.desc=Adicione texto ou carimbos de imagem em locais definidos +home.AddStampRequest.desc=Adicione texto ou carimbos de imagem em locais definidos. AddStampRequest.tags=Carimbo,Adicionar imagem,centralizar imagem,Marca d'água,PDF,Incorporar,Personalizar home.PDFToBook.title=PDF para Livro -home.PDFToBook.desc=Converte PDF para formatos de livro/quadrinhos usando Calibre +home.PDFToBook.desc=Converter PDF para formatos de livro/quadrinhos usando Calibre. PDFToBook.tags=Livro,Quadrinhos,Calibre,Converter,manga,amazon,kindle,epub,mobi,azw3,docx,rtf,txt,html,lit,fb2,pdb,lrf home.BookToPDF.title=Livro para PDF -home.BookToPDF.desc=Converte formatos de livros/quadrinhos para PDF usando Calibre +home.BookToPDF.desc=Converter formatos de livros/quadrinhos para PDF usando Calibre. BookToPDF.tags=Livro,Quadrinhos,Calibre,Converter,manga,amazon,kindle,epub,mobi,azw3,docx,rtf,txt,html,lit,fb2,pdb,lrf home.removeImagePdf.title=Remover Imagem -home.removeImagePdf.desc=Remova a imagem do PDF para reduzir o tamanho do arquivo +home.removeImagePdf.desc=Remova imagens do PDF para reduzir o tamanho do arquivo. removeImagePdf.tags=Remover imagem,operações de página,back-end,lado do servidor @@ -512,27 +512,27 @@ home.splitPdfByChapters.title=Divide PDF por Capítulos home.splitPdfByChapters.desc=Divide um PDF em vários arquivos baseado na sua estrutura de capítulos. splitPdfByChapters.tags=dividir,capítulos,favoritos,organizar -home.validateSignature.title=Validate PDF Signature -home.validateSignature.desc=Verify digital signatures and certificates in PDF documents -validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate +home.validateSignature.title=Verificar Assinatura com Certificado +home.validateSignature.desc=Verifica assinatura digital e certificado em um PDF. +validateSignature.tags=assinatura,verificação,validação,pdf,certificado,assinatura digital,validar assinatura,validar certificado #replace-invert-color -replace-color.title=Substituir-Inverter-Cor -replace-color.header=Substitui-Inverter Cor PDF -home.replaceColorPdf.title=Substitui e Inverte Cor -home.replaceColorPdf.desc=Substitui cor de um texto e plano de fundo de um PDF e inverte a toda cor do PDF para reduzir o tamanho +replace-color.title=Substitui e Inverte Cores +replace-color.header=Substitui e Inverte Cores +home.replaceColorPdf.title=Substitui e Inverte Cores +home.replaceColorPdf.desc=Substitui cor do texto e plano de fundo de um PDF e/ou inverte a toda cor do PDF para reduzir o tamanho. replaceColorPdf.tags=Substitui Cor, Operações na Página, back end, lado do servidor -replace-color.selectText.1=Substituir ou inverter cor Opções -replace-color.selectText.2=Padrão(Padrão cores de alto constraste) -replace-color.selectText.3=Customizado(Cores customizadas) -replace-color.selectText.4=Inversão Completa(Inverte todas cores) -replace-color.selectText.5=Opções de cores de alto contraste +replace-color.selectText.1=Substituir ou inverter cores Opções: +replace-color.selectText.2=Padrão (Cores de alto constraste) +replace-color.selectText.3=Customizado (Cores customizadas) +replace-color.selectText.4=Inversão Completa (Inverte todas cores) +replace-color.selectText.5=Opções de cores de alto contraste: replace-color.selectText.6=Texto branco em um plano de fundo preto replace-color.selectText.7=Texto preto em um plano de fundo branco replace-color.selectText.8=Texto amarelo em um plano de fundo preto replace-color.selectText.9=Texto verde em um plano de fundo preto -replace-color.selectText.10=Escolha cor do texto -replace-color.selectText.11=Escolha cor do plano de fundo +replace-color.selectText.10=Escolha a cor do texto: +replace-color.selectText.11=Escolha a cor do plano de fundo: replace-color.submit=Substituir @@ -560,28 +560,28 @@ login.oauth2AccessDenied=Acesso Negado login.oauth2InvalidTokenResponse=Resposta de Token Inválida login.oauth2InvalidIdToken=Id de Token Inválido login.userIsDisabled=O usuário está desativado, o login está atualmente bloqueado com este nome de usuário. Entre em contato com o administrador. -login.alreadyLoggedIn=Você já está conectado +login.alreadyLoggedIn=Você já está conectado em login.alreadyLoggedIn2=aparelhos. Por favor saia dos aparelhos e tente novamente. login.toManySessions=Você tem muitas sessões ativas #auto-redact -autoRedact.title=Redação Automática de Dados -autoRedact.header=Redação Automática de Dados -autoRedact.colorLabel=Cor -autoRedact.textsToRedactLabel=Texto para redigir (separado por linha) -autoRedact.textsToRedactPlaceholder=por exemplo: \nConfidencial \nSecreto -autoRedact.useRegexLabel=Usar Regex (expressão regular) -autoRedact.wholeWordSearchLabel=Pesquisa de palavras inteiras -autoRedact.customPaddingLabel=Preenchimento extra personalizado -autoRedact.convertPDFToImageLabel=Converter PDF em imagem PDF (Usado para remover o texto atrás da caixa) +autoRedact.title=Ocultação de Texto +autoRedact.header=Ocultação de Texto +autoRedact.colorLabel=Cor: +autoRedact.textsToRedactLabel=Texto para ocultar (um por linha): +autoRedact.textsToRedactPlaceholder=Por exemplo: \nConfidencial \nSecreto +autoRedact.useRegexLabel=Usar Regex (expressão regular). +autoRedact.wholeWordSearchLabel=Pesquisa apenas palavras inteiras. +autoRedact.customPaddingLabel=Preenchimento extra personalizado: +autoRedact.convertPDFToImageLabel=Converter PDF em imagem PDF (Usado para remover o texto atrás da caixa). autoRedact.submitButton=Enviar #showJS -showJS.title=Exibir JavaScript -showJS.header=Exibir JavaScript +showJS.title=Mostrar JavaScript +showJS.header=Mostrar JavaScript showJS.downloadJS=Baixar JavaScript -showJS.submit=Exibir +showJS.submit=Mostrar #pdfToSinglePage @@ -591,8 +591,8 @@ pdfToSinglePage.submit=Converter para Página Única #pageExtracter -pageExtracter.title=Extrair Páginas -pageExtracter.header=Extrair Páginas +pageExtracter.title=Extrair Página(s) +pageExtracter.header=Extrair Páginas(s) pageExtracter.submit=Extrair pageExtracter.placeholder=(por exemplo 1,2,8 or 4,7,12-16 ou 2n-1) @@ -608,25 +608,25 @@ getPdfInfo.downloadJson=Baixar JSON MarkdownToPDF.title=Markdown para PDF MarkdownToPDF.header=Markdown para PDF MarkdownToPDF.submit=Converter -MarkdownToPDF.help=Em desenvolvimento -MarkdownToPDF.credit=Usa o WeasyPrint +MarkdownToPDF.help=Em desenvolvimento. +MarkdownToPDF.credit=Utiliza o WeasyPrint. #url-to-pdf -URLToPDF.title=URL para PDF -URLToPDF.header=URL para PDF +URLToPDF.title=Converter URL/Site para PDF +URLToPDF.header=Converter URL/Site para PDF URLToPDF.submit=Converter -URLToPDF.credit=Usa o WeasyPrint +URLToPDF.credit=Utiliza o WeasyPrint. #html-to-pdf HTMLToPDF.title=HTML para PDF HTMLToPDF.header=HTML para PDF -HTMLToPDF.help=Aceita arquivos HTML e ZIPs contendo html, css, imagens, etc. necessários +HTMLToPDF.help=Aceita arquivos HTML e ZIPs contendo html, css, imagens, etc. HTMLToPDF.submit=Converter -HTMLToPDF.credit=Usa o WeasyPrint -HTMLToPDF.zoom=Nível de zoom para exibição do site. +HTMLToPDF.credit=Utiliza o WeasyPrint. +HTMLToPDF.zoom=Nível de zoom para exibição do site: HTMLToPDF.pageWidth=Largura da página em centímetros. (Em branco para padrão) HTMLToPDF.pageHeight=Altura da página em centímetros. (Em branco para padrão) HTMLToPDF.marginTop=Margem superior da página em milímetros. (Em branco para padrão) @@ -642,58 +642,58 @@ HTMLToPDF.screen=Tela #AddStampRequest -AddStampRequest.header=Carimbar PDF -AddStampRequest.title=Carimbar PDF -AddStampRequest.stampType=Tipo de carimbo -AddStampRequest.stampText=Texto do carimbo -AddStampRequest.stampImage=Imagem do carimbo -AddStampRequest.alphabet=Alfabeto -AddStampRequest.fontSize=Tamanho da fonte/imagem -AddStampRequest.rotation=Rotação -AddStampRequest.opacity=Opacidade -AddStampRequest.position=Posição -AddStampRequest.overrideX=Substituir Coordenada X -AddStampRequest.overrideY=Substituir Coordenada Y -AddStampRequest.customMargin=Margem personalizada -AddStampRequest.customColor=Cor de texto personalizada +AddStampRequest.header=Adicionar Carimbo ao PDF +AddStampRequest.title=Adicionar Carimbo ao PDF +AddStampRequest.stampType=Tipo de carimbo: +AddStampRequest.stampText=Texto do carimbo: +AddStampRequest.stampImage=Imagem do carimbo: +AddStampRequest.alphabet=Alfabeto: +AddStampRequest.fontSize=Tamanho da fonte/imagem: +AddStampRequest.rotation=Rotação: +AddStampRequest.opacity=Opacidade: +AddStampRequest.position=Posição: +AddStampRequest.overrideX=Substituir coordenada X: +AddStampRequest.overrideY=Substituir coordenada Y: +AddStampRequest.customMargin=Margem personalizada: +AddStampRequest.customColor=Cor de texto personalizada: AddStampRequest.submit=Enviar #sanitizePDF -sanitizePDF.title=Higienizar PDF -sanitizePDF.header=Higienizar um arquivo PDF -sanitizePDF.selectText.1=Remover ações de JavaScript -sanitizePDF.selectText.2=Remover arquivos embutidos -sanitizePDF.selectText.3=Remover metadados -sanitizePDF.selectText.4=Remover links -sanitizePDF.selectText.5=Remover fontes +sanitizePDF.title=Higienizar +sanitizePDF.header=Higienizar +sanitizePDF.selectText.1=Remover scripts de JavaScript. +sanitizePDF.selectText.2=Remover arquivos embutidos. +sanitizePDF.selectText.3=Remover metadados. +sanitizePDF.selectText.4=Remover links. +sanitizePDF.selectText.5=Remover fontes. sanitizePDF.submit=Higienizar PDF #addPageNumbers -addPageNumbers.title=Adicionar números de página -addPageNumbers.header=Adicionar números de página +addPageNumbers.title=Adicionar Números de Página +addPageNumbers.header=Adicionar Números de Página addPageNumbers.selectText.1=Selecionar arquivo PDF: -addPageNumbers.selectText.2=Tamanho da margem -addPageNumbers.selectText.3=Posição -addPageNumbers.selectText.4=Número inicial -addPageNumbers.selectText.5=Páginas a numerar -addPageNumbers.selectText.6=Texto personalizado -addPageNumbers.customTextDesc=Texto personalizado +addPageNumbers.selectText.2=Tamanho da margem: +addPageNumbers.selectText.3=Posição: +addPageNumbers.selectText.4=Número inicial: +addPageNumbers.selectText.5=Páginas a numerar: +addPageNumbers.selectText.6=Texto personalizado: +addPageNumbers.customTextDesc=Texto personalizado: addPageNumbers.numberPagesDesc=Quais páginas numerar, padrão 'todas', também aceita 1-5 ou 2,5,9,etc. addPageNumbers.customNumberDesc=O padrão é {n}, também aceita 'Página {n} de {total}', 'Texto-{n}', '{nome do arquivo}-{n}' -addPageNumbers.submit=Adicionar números de página +addPageNumbers.submit=Adicionar Números de Página #auto-rename -auto-rename.title=Renomeação automática -auto-rename.header=Renomeação automática de PDF -auto-rename.submit=Renomeação automática +auto-rename.title=Renomear Automaticamente o PDF +auto-rename.header=Renomear Automaticamente o PDF +auto-rename.submit=Renomeação Automática #adjustContrast -adjustContrast.title=Ajustar Contraste -adjustContrast.header=Ajustar Contraste +adjustContrast.title=Ajuste Visual do PDF +adjustContrast.header=Ajuste Visual do PDF adjustContrast.contrast=Contraste: adjustContrast.brightness=Brilho: adjustContrast.saturation=Saturação: @@ -701,21 +701,21 @@ adjustContrast.download=Baixar #crop -crop.title=Cortar -crop.header=Cortar PDF +crop.title=Recortar +crop.header=Recortar crop.submit=Enviar #autoSplitPDF -autoSplitPDF.title=Divisão Automática de PDF -autoSplitPDF.header=Divisão Automática de PDF -autoSplitPDF.description=Imprima, insira, digitalize, faça o upload e deixe que a gente divida seus documentos automaticamente. Nenhuma classificação manual necessária. -autoSplitPDF.selectText.1=Imprima algumas folhas divisórias abaixo (preto e branco está bom). -autoSplitPDF.selectText.2=Digitalize todos os seus documentos de uma vez, inserindo a folha divisória entre eles. -autoSplitPDF.selectText.3=Faça o upload do único arquivo PDF grande digitalizado e deixe o Stirling PDF cuidar do resto. +autoSplitPDF.title=Divisão Automática de Páginas +autoSplitPDF.header=Divisão Automática de Páginas +autoSplitPDF.description=Imprima, insira, digitalize, faça o upload e deixe que a gente divida seus documentos automaticamente. +autoSplitPDF.selectText.1=Imprima algumas folhas divisórias, descritas abaixo (preto e branco ou colorido). +autoSplitPDF.selectText.2=Digitalize todos os seus documentos de uma vez, inserindo a folha divisória enre os documentos que deseja separar. +autoSplitPDF.selectText.3=Faça o upload do arquivo único PDF digitalizado e deixe o Stirling PDF cuidar do resto. autoSplitPDF.selectText.4=As páginas divisórias são detectadas e removidas automaticamente, garantindo um documento final organizado. autoSplitPDF.formPrompt=Enviar PDF contendo folhas divisórias Stirling-PDF: -autoSplitPDF.duplexMode=Modo Duplex (Digitalização frente e verso) +autoSplitPDF.duplexMode=Modo Duplex (Digitalização frente e verso). autoSplitPDF.dividerDownload1=Baixar 'Folha Divisória Automática (mínimo).pdf' autoSplitPDF.dividerDownload2=Baixar 'Folha Divisória Automática (com instruções).pdf' autoSplitPDF.submit=Enviar @@ -729,31 +729,31 @@ pipeline.title=Pipeline pageLayout.title=Layout de Múltiplas Páginas pageLayout.header=Layout de Múltiplas Páginas pageLayout.pagesPerSheet=Páginas por folha: -pageLayout.addBorder=Adicionar bordas +pageLayout.addBorder=Adicionar bordas. pageLayout.submit=Enviar #scalePages scalePages.title=Ajustar Tamanho/Escala da Página scalePages.header=Ajustar Tamanho/Escala da Página -scalePages.pageSize=Tamanho de uma página do documento. -scalePages.keepPageSize=Tamanho original -scalePages.scaleFactor=Fator de zoom (corte) de uma página. +scalePages.pageSize=Tamanho desejado do documento: +scalePages.keepPageSize=Tamanho Original +scalePages.scaleFactor=Fator de zoom (corte) de uma página: scalePages.submit=Enviar #certSign certSign.title=Assinatura com Certificado -certSign.header=Assine um PDF com o seu certificado (Em desenvolvimento) +certSign.header=Assinatura com Certificado (Em desenvolvimento) certSign.selectPDF=Selecione um arquivo PDF para assinatura: certSign.jksNote=Nota: Se o seu tipo de certificado não estiver listado abaixo, converta-o em um arquivo Java Keystore (.jks) usando a ferramenta de linha de comando keytool. Em seguida, escolha a opção de arquivo .jks abaixo. certSign.selectKey=Selecione o seu arquivo de chave privada (formato PKCS#8, pode ser .pem ou .der): certSign.selectCert=Selecione o seu arquivo de certificado (formato X.509, pode ser .pem ou .der): certSign.selectP12=Selecione o seu arquivo de armazenamento de chave PKCS#12 (.p12 ou .pfx) (opcional, se fornecido, deve conter a sua chave privada e certificado): certSign.selectJKS=Selecione seu arquivo Java Keystore (.jks ou .keystore): -certSign.certType=Tipo de Certificado +certSign.certType=Tipo de Certificado: certSign.password=Digite a senha do seu armazenamento de chave ou chave privada (se aplicável): -certSign.showSig=Mostrar Assinatura +certSign.showSig=Mostrar Assinatura. certSign.reason=Razão certSign.location=Localização certSign.name=Nome @@ -762,20 +762,20 @@ certSign.submit=Assinar PDF #removeCertSign -removeCertSign.title=Remover Assinatura do Certificado -removeCertSign.header=Remover o certificado digital do PDF +removeCertSign.title=Remover Assinatura com Certificado +removeCertSign.header=Remover Assinatura com Certificado removeCertSign.selectPDF=Selecione um arquivo PDF: -removeCertSign.submit=Remover assinatura +removeCertSign.submit=Remover Assinatura #removeBlanks -removeBlanks.title=Remover páginas em branco -removeBlanks.header=Remover páginas em branco +removeBlanks.title=Remover Páginas em Branco +removeBlanks.header=Remover Páginas em Branco removeBlanks.threshold=Limite de brancura de pixel: -removeBlanks.thresholdDesc=Limite para determinar o quão branco um pixel branco deve ser para ser classificado como 'Branco'. 0 = Preto, 255 branco puro. -removeBlanks.whitePercent=Porcentagem de Branco (%): -removeBlanks.whitePercentDesc=Porcentagem da página que devem ter pixels “brancos” para serem removidas -removeBlanks.submit=Remover páginas em branco +removeBlanks.thresholdDesc=Limite para determinar o quão branco um pixel branco deve ser para ser classificado como "branco", para remoção. 0 = Preto, 255 = branco puro. +removeBlanks.whitePercent=Porcentagem de branco (%): +removeBlanks.whitePercentDesc=Porcentagem da página que devem ter pixels classificados como “brancos” para serem removidas. +removeBlanks.submit=Remover Páginas em Branco #removeAnnotations @@ -786,79 +786,79 @@ removeAnnotations.submit=Remover #compare compare.title=Comparar -compare.header=Comparar PDFs +compare.header=Comparar compare.highlightColor.1=Cor de destaque 1: compare.highlightColor.2=Cor de destaque 2: -compare.document.1=Documento 1 -compare.document.2=Documento 2 +compare.document.1=Documento 1: +compare.document.2=Documento 2: compare.submit=Comparar -compare.complex.message=Um ou ambos os documentos fornecidos são arquivos grandes, a precisão da comparação pode ser reduzida -compare.large.file.message=Um ou ambos os documentos fornecidos são muito grandes para processar +compare.complex.message=Um ou ambos os documentos fornecidos são arquivos grandes, a precisão da comparação pode ser reduzida. +compare.large.file.message=Um ou ambos os documentos fornecidos são muito grandes para processar. compare.no.text.message=Um ou ambos os PDFs selecionados não possuem conteúdo de texto. Por favor, escolha PDFs com texto para comparação. #BookToPDF -BookToPDF.title=Livros e Quadrinhos para PDF +BookToPDF.title=Livro para PDF BookToPDF.header=Livro para PDF -BookToPDF.credit=Usa o Calibre +BookToPDF.credit=Utiliza o Calibre. BookToPDF.submit=Converter #PDFToBook PDFToBook.title=PDF para Livro PDFToBook.header=PDF para Livro -PDFToBook.selectText.1=Formato -PDFToBook.credit=Usa o Calibre +PDFToBook.selectText.1=Formato: +PDFToBook.credit=Utiliza o Calibre. PDFToBook.submit=Converter #sign sign.title=Assinar -sign.header=Assinar PDFs -sign.upload=Enviar imagem +sign.header=Assinar +sign.upload=Enviar Imagem sign.draw=Desenhar Assinatura -sign.text=Inserir texto +sign.text=Inserir Texto sign.clear=Limpar sign.add=Adicionar sign.saved=Assinaturas Salvas sign.save=Salvar Assinatura sign.personalSigs=Assinaturas Pessoais sign.sharedSigs=Assinaturas Compartilhadas -sign.noSavedSigs=Nenhuma assinatura salva encontrada -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.noSavedSigs=Nenhuma assinatura salva encontrada. +sign.addToAll=Adicionar em todas páginas +sign.delete=Apagar +sign.first=Primeira página +sign.last=Última página +sign.next=Próxima página +sign.previous=Página anterior #repair repair.title=Reparar -repair.header=Reparar PDFs +repair.header=Reparar repair.submit=Reparar #flatten flatten.title=Achatar -flatten.header=Achatar PDFs -flatten.flattenOnlyForms=Achatar apenas formulários +flatten.header=Achatar +flatten.flattenOnlyForms=Achatar apenas formulários interativos. flatten.submit=Achatar #ScannerImageSplit -ScannerImageSplit.selectText.1=Limite de Ângulo: +ScannerImageSplit.selectText.1=Limite de ângulo: ScannerImageSplit.selectText.2=Define o ângulo absoluto mínimo necessário para que a imagem seja girada (padrão: 10). ScannerImageSplit.selectText.3=Tolerância: ScannerImageSplit.selectText.4=Determina o intervalo de variação de cor em torno da cor de fundo estimada (padrão: 30). -ScannerImageSplit.selectText.5=Área Mínima: +ScannerImageSplit.selectText.5=Área mínima: ScannerImageSplit.selectText.6=Define o limite mínimo de área para uma foto (padrão: 10000). ScannerImageSplit.selectText.7=Área mínima de contorno: -ScannerImageSplit.selectText.8=Define o limite mínimo da área de contorno para uma foto +ScannerImageSplit.selectText.8=Define o limite mínimo da área de contorno para uma foto. ScannerImageSplit.selectText.9=Tamanho da borda: ScannerImageSplit.selectText.10=Define o tamanho da borda adicionada e removida para evitar bordas brancas na saída (padrão: 1). ScannerImageSplit.info=Python não está instalado. É necessário para executar. #OCR -ocr.title=OCR / Limpeza de Digitalização -ocr.header=OCR / Limpeza de Digitalização (Reconhecimento Óptico de Caracteres) +ocr.title=Processamento de OCR +ocr.header=Processamento de OCR (Reconhecimento Óptico de Caracteres) ocr.selectText.1=Selecione os idiomas a serem detectados no PDF (os listados são os atualmente instalados): ocr.selectText.2=Criar um arquivo de texto contendo o texto OCR junto do PDF com OCR ocr.selectText.3=Páginas corretamente digitalizadas em um ângulo inclinado, gire-as de volta à posição original @@ -868,46 +868,46 @@ ocr.selectText.6=Ignorar páginas com texto interativo, processar por OCR apenas ocr.selectText.7=Forçar OCR, executar OCR em todas as páginas, removendo todos os elementos de texto originais ocr.selectText.8=Normal (gerará um erro se o PDF já contiver texto) ocr.selectText.9=Configurações Adicionais -ocr.selectText.10=Modo OCR +ocr.selectText.10=Modo OCR: ocr.selectText.11=Remover imagens após o OCR (remove TODAS as imagens, útil apenas como parte do processo de conversão) -ocr.selectText.12=Tipo de Renderização (avançado) -ocr.help=Por favor, leia a documentação sobre como usar isso para outros idiomas e/ou fora do ambiente Docker -ocr.credit=Este serviço usa qpdf e Tesseract para OCR. -ocr.submit=Processar PDF com OCR +ocr.selectText.12=Tipo de renderização (Avançado): +ocr.help=Por favor, leia a documentação abaixo para saber mais sobre OCR e sua utilização. +ocr.credit=Este serviço usa Qpdf e Tesseract para OCR. +ocr.submit=Processar OCR no PDF #extractImages extractImages.title=Extrair Imagens extractImages.header=Extrair Imagens -extractImages.selectText=Selecione o formato de imagem para converter as imagens extraídas -extractImages.allowDuplicates=Salvar imagens duplicadas +extractImages.selectText=Selecione o formato de saída das imagens extraídas: +extractImages.allowDuplicates=Salvar imagens duplicadas. extractImages.submit=Extrair #File to PDF -fileToPDF.title=Arquivo para PDF -fileToPDF.header=Converter Qualquer Arquivo para PDF -fileToPDF.credit=Este serviço usa o LibreOffice e o Unoconv para conversão de arquivos. -fileToPDF.supportedFileTypesInfo=Tipos de arquivos suportados -fileToPDF.supportedFileTypes=Os tipos de arquivo suportados devem incluir os listados abaixo. No entanto, para obter uma lista atualizada completa dos formatos suportados, consulte a documentação do LibreOffice. +fileToPDF.title=Converter Arquivo para PDF +fileToPDF.header=Converter Arquivo para PDF +fileToPDF.credit=Este serviço usa o LibreOffice e o Unoconv realizar a conversão de arquivos. +fileToPDF.supportedFileTypesInfo=Tipos de Arquivos Suportados +fileToPDF.supportedFileTypes=A listagem abaixo não é exaustiva, para obter uma lista atualizada completa dos formatos suportados, consulte a documentação do LibreOffice. fileToPDF.submit=Converter para PDF #compress compress.title=Comprimir -compress.header=Comprimir PDF -compress.credit=Este serviço usa o qpdf para compressão/otimização de PDF. -compress.selectText.1=Modo Manual - De 1 a 4 +compress.header=Comprimir +compress.credit=Este serviço usa o Qpdf para compressão/otimização de PDF. +compress.selectText.1=Modo Manual - 1 (Menos) a 9 (Mais) compress.selectText.2=Nível de Otimização: compress.selectText.3=4 (Pior para imagens de texto) -compress.selectText.4=Modo Automático - Ajusta automaticamente a qualidade para atingir o tamanho exato do PDF -compress.selectText.5=Tamanho esperado do PDF (por exemplo, 25 MB, 10,8 MB, 25 KB) +compress.selectText.4=Modo Automático - Ajusta automaticamente a qualidade para atingir o tamanho exato desejado +compress.selectText.5=Tamanho esperado do PDF (por exemplo, 25 MB, 10,8 MB, 25 KB): compress.submit=Comprimir #Add image addImage.title=Adicionar Imagem -addImage.header=Adicionar imagem ao PDF +addImage.header=Adicionar Imagem addImage.everyPage=Para cada página? addImage.upload=Enviar imagem addImage.submit=Adicionar imagem @@ -915,18 +915,18 @@ addImage.submit=Adicionar imagem #merge merge.title=Mesclar -merge.header=Mesclar vários PDFs (2+) -merge.sortByName=Classificar por nome -merge.sortByDate=Classificar por data +merge.header=Mesclar +merge.sortByName=Classificar por Nome +merge.sortByDate=Classificar por Data merge.removeCertSign=Remover a assinatura digital do arquivo mesclado? merge.submit=Mesclar #pdfOrganiser -pdfOrganiser.title=Organizador de páginas -pdfOrganiser.header=Organizador de páginas PDF -pdfOrganiser.submit=Reorganizar páginas -pdfOrganiser.mode=Modo +pdfOrganiser.title=Organizar Páginas +pdfOrganiser.header=Organizar Páginas +pdfOrganiser.submit=Reorganizar Páginas +pdfOrganiser.mode=Modo: pdfOrganiser.mode.1=Ordem de página personalizada pdfOrganiser.mode.2=Ordem inversa pdfOrganiser.mode.3=Classificação duplex @@ -941,90 +941,100 @@ pdfOrganiser.placeholder=(por exemplo 1,3,2 ou 4-8,2,10-12 ou 2n-1) #multiTool -multiTool.title=Multiferramenta de PDF -multiTool.header=Multiferramenta de PDF -multiTool.uploadPrompts=Nome do arquivo -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=Multiferramentas de PDF +multiTool.header=Multiferramentas de PDF +multiTool.uploadPrompts=Nome do Arquivo: +multiTool.selectAll=Selecionar Tudo +multiTool.deselectAll=Desselecionar Tudo +multiTool.selectPages=Selecionar Páginas +multiTool.selectedPages=Páginas Selecionadas +multiTool.page=Página +multiTool.deleteSelected=Apagar Selecionados +multiTool.downloadAll=Exportar +multiTool.downloadSelected=Exportar Selecionados -multiTool.insertPageBreak=Insert Page Break -multiTool.addFile=Add File -multiTool.rotateLeft=Rotate Left -multiTool.rotateRight=Rotate Right -multiTool.split=Split -multiTool.moveLeft=Move Left -multiTool.moveRight=Move Right -multiTool.delete=Delete -multiTool.dragDropMessage=Page(s) Selected -multiTool.undo=Undo -multiTool.redo=Redo +multiTool.insertPageBreak=Inserir Página em Branco +multiTool.addFile=Inserir Arquivo +multiTool.rotateLeft=Girar para Esquerda +multiTool.rotateRight=Girar para Direita +multiTool.split=Dividir +multiTool.moveLeft=Mover para Esquerda +multiTool.moveRight=Mover para Direita +multiTool.delete=Apagar +multiTool.dragDropMessage=Página(s) Selecionadas +multiTool.undo=Desfazer +multiTool.redo=Refazer + +#decrypt +decrypt.passwordPrompt=This file is password-protected. Please enter the password: +decrypt.cancelled=Operation cancelled for PDF: {0} +decrypt.noPassword=No password provided for encrypted PDF: {0} +decrypt.invalidPassword=Please try again with the correct password. +decrypt.invalidPasswordHeader=Incorrect password or unsupported encryption for PDF: {0} +decrypt.unexpectedError=There was an error processing the file. Please try again. +decrypt.serverError=Server error while decrypting: {0} +decrypt.success=File decrypted successfully. #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=Esta função também está disponível em Multiferramentas de PDF. Com uma interface mais completa e funções adicionais. #view pdf viewPdf.title=Visualizar PDF viewPdf.header=Visualizar PDF #pageRemover -pageRemover.title=Remover página -pageRemover.header=Remover páginas do PDF -pageRemover.pagesToDelete=Páginas a serem excluídas (insira uma lista separada por vírgulas de números de página): -pageRemover.submit=Excluir páginas +pageRemover.title=Remover Páginas +pageRemover.header=Remover Páginas +pageRemover.pagesToDelete=Páginas a serem excluídas (insira uma lista separada por vírgulas, com os números de páginas): +pageRemover.submit=Excluir Páginas pageRemover.placeholder=(por exemplo 1,2,6 ou 1-10,15-30) #rotate -rotate.title=Girar PDF -rotate.header=Girar PDF +rotate.title=Girar +rotate.header=Girar rotate.selectAngle=Selecione o ângulo de rotação (múltiplos de 90 graus): rotate.submit=Girar #split-pdfs -split.title=Dividir PDF -split.header=Dividir PDF -split.desc.1=Os números selecionados correspondem às páginas onde você deseja fazer a divisão. -split.desc.2=Por exemplo, selecionar 1,3,7-9 dividirá um documento de 10 páginas em 6 PDFs separados da seguinte forma: +split.title=Dividir +split.header=Dividir +split.desc.1=Os números selecionados correspondem às páginas onde você deseja realizar a divisão. +split.desc.2=Por exemplo, selecionar 1,3,7-9 dividirá um documento de 11 páginas em 6 PDFs separados, da seguinte forma: split.desc.3=Documento Nº1: Página 1 split.desc.4=Documento Nº2: Páginas 2 e 3 split.desc.5=Documento Nº3: Páginas 4, 5, 6 e 7 split.desc.6=Documento Nº4: Página 8 split.desc.7=Documento Nº5: Página 9 -split.desc.8=Documento Nº6: Página 10 +split.desc.8=Documento Nº6: Página 10 e 11 (e mais se tiver) split.splitPages=Digite as páginas para a divisão: split.submit=Dividir #merge imageToPDF.title=Imagem para PDF -imageToPDF.header=Converter imagem para PDF +imageToPDF.header=Imagem para PDF imageToPDF.submit=Converter -imageToPDF.selectLabel=Opções de ajuste de imagem -imageToPDF.fillPage=Preencher página +imageToPDF.selectLabel=Opções de ajuste da imagem: +imageToPDF.fillPage=Preencher a página imageToPDF.fitDocumentToImage=Ajustar página à imagem imageToPDF.maintainAspectRatio=Manter proporções -imageToPDF.selectText.2=Girar automaticamente -imageToPDF.selectText.3=Lógica de vários arquivos (Ativada apenas ao trabalhar com várias imagens) +imageToPDF.selectText.2=Girar automaticamente. +imageToPDF.selectText.3=Lógica de vários arquivos (Ativada apenas ao trabalhar com várias imagens): imageToPDF.selectText.4=Mesclar em um único PDF imageToPDF.selectText.5=Converter em PDFs separados #pdfToImage pdfToImage.title=PDF para Imagem -pdfToImage.header=Converter PDF para imagem -pdfToImage.selectText=Formato de imagem -pdfToImage.singleOrMultiple=Tipo de resultado de imagem -pdfToImage.single=Imagem grande única combinando todas as páginas -pdfToImage.multi=Várias imagens, uma imagem por página -pdfToImage.colorType=Tipo de cor -pdfToImage.color=Colorida +pdfToImage.header=PDF para Imagem +pdfToImage.selectText=Formato da imagem: +pdfToImage.singleOrMultiple=Resultado da conversão: +pdfToImage.single=Imagem grande única combinando todas as páginas do PDF +pdfToImage.multi=Várias imagens, uma imagem por página do PDF +pdfToImage.colorType=Cor de saída: +pdfToImage.color=Colorido pdfToImage.grey=Escala de Cinza pdfToImage.blackwhite=Preto e Branco (pode perder informações!) pdfToImage.submit=Converter @@ -1032,24 +1042,24 @@ pdfToImage.info=Python não está instalado. Necessário para conversão WebP. #addPassword -addPassword.title=Adicionar senha -addPassword.header=Adicionar Senha (Criptografar) -addPassword.selectText.1=Selecione o PDF para Criptografar -addPassword.selectText.2=Senha -addPassword.selectText.3=Tamanho da Chave de Criptografia +addPassword.title=Proteger PDF +addPassword.header=Proteger PDF (Criptografar) +addPassword.selectText.1=Selecione o PDF para Criptografar: +addPassword.selectText.2=Senha de acesso: +addPassword.selectText.3=Tamanho da chave de criptografia: addPassword.selectText.4=Valores mais altos são mais seguros, mas valores mais baixos são melhores para compatibilidade. -addPassword.selectText.5=Permissões a serem definidas (recomendado para uso junto com a senha do proprietário) -addPassword.selectText.6=Impedir a montagem do documento -addPassword.selectText.7=Impedir a extração de conteúdo -addPassword.selectText.8=Impedir a extração para acessibilidade -addPassword.selectText.9=Impedir o preenchimento do formulário -addPassword.selectText.10=Impedir modificação -addPassword.selectText.11=Impedir modificação de anotação -addPassword.selectText.12=Impedir impressão -addPassword.selectText.13=Impedir impressão de formatos diferentes -addPassword.selectText.14=Senha do proprietário -addPassword.selectText.15=Restringe o que pode ser feito com o documento depois de aberto (não suportado por todos os leitores) -addPassword.selectText.16=Restringe a abertura do próprio documento +addPassword.selectText.5=Permissões a serem definidas (recomendado para uso junto com a senha do proprietário): +addPassword.selectText.6=Impedir a montagem do documento. +addPassword.selectText.7=Impedir a extração de conteúdo. +addPassword.selectText.8=Impedir a extração para acessibilidade. +addPassword.selectText.9=Impedir o preenchimento do formulário. +addPassword.selectText.10=Impedir modificação. +addPassword.selectText.11=Impedir modificação de anotações. +addPassword.selectText.12=Impedir impressão. +addPassword.selectText.13=Impedir impressão de formatos diferentes. +addPassword.selectText.14=Senha do proprietário: +addPassword.selectText.15=Restringe o que pode ser feito com o documento depois de aberto (não suportado por todos os leitores). +addPassword.selectText.16=Restringe a abertura do próprio documento. addPassword.submit=Criptografar @@ -1061,13 +1071,13 @@ watermark.selectText.1=Selecione PDF para adicionar a marca d'água: watermark.selectText.2=Texto da marca d'água: watermark.selectText.3=Tamanho da fonte: watermark.selectText.4=Rotação (0-360): -watermark.selectText.5=Width Spacer (Espaço entre cada marca d'água horizontalmente): -watermark.selectText.6=Height Spacer (Espaço entre cada marca d'água verticalmente): +watermark.selectText.5=Espaçador de Largura (Espaço entre cada marca d'água horizontalmente): +watermark.selectText.6=Espaçador de Altura (Espaço entre cada marca d'água verticalmente): watermark.selectText.7=Opacidade (0% - 100%): watermark.selectText.8=Tipo de marca d'água: watermark.selectText.9=Imagem da marca d'água: -watermark.selectText.10=Converter PDF em imagem PDF -watermark.submit=Adicionar marca d'água +watermark.selectText.10=Converter PDF em imagem PDF. +watermark.submit=Adicionar Marca D'água watermark.type.1=Texto watermark.type.2=Imagem @@ -1075,61 +1085,61 @@ watermark.type.2=Imagem #Change permissions permissions.title=Alterar Permissões permissions.header=Alterar Permissões -permissions.warning=Aviso: para que essas permissões sejam imutáveis, é recomendável defini-las com uma senha através da página Adicionar Senha -permissions.selectText.1=Selecione o PDF para alterar as permissões -permissions.selectText.2=Permissões para definir -permissions.selectText.3=Impedir montagem do documento -permissions.selectText.4=Impedir extração de conteúdo -permissions.selectText.5=Impedir extração para acessibilidade -permissions.selectText.6=Impedir preenchimento de formulário -permissions.selectText.7=Impedir modificações -permissions.selectText.8=Impedir modificação de anotação -permissions.selectText.9=Impedir impressão -permissions.selectText.10=Impedir impressão de formatos diferentes +permissions.warning=Aviso: para que essas permissões sejam imutáveis, é recomendável defini-las com uma senha através da página "Proteger PDF". +permissions.selectText.1=Selecione o PDF para alterar as permissões: +permissions.selectText.2=Permissões para definir: +permissions.selectText.3=Impedir montagem do documento. +permissions.selectText.4=Impedir extração de conteúdo. +permissions.selectText.5=Impedir extração para acessibilidade. +permissions.selectText.6=Impedir preenchimento de formulário. +permissions.selectText.7=Impedir modificações. +permissions.selectText.8=Impedir modificação de anotações. +permissions.selectText.9=Impedir impressão. +permissions.selectText.10=Impedir impressão de formatos diferentes. permissions.submit=Alterar #remove password -removePassword.title=Remover Senha -removePassword.header=Remover senha (descriptografar) -removePassword.selectText.1=Selecione o PDF para descriptografar +removePassword.title=Desproteger PDF +removePassword.header=Desproteger PDF (descriptografar) +removePassword.selectText.1=Selecione o PDF para descriptografar: removePassword.selectText.2=Senha -removePassword.submit=Remover +removePassword.submit=Descriptografar #changeMetadata changeMetadata.title=Alterar Metadados -changeMetadata.header=Alterar metadados -changeMetadata.selectText.1=Edite as variáveis ​​que deseja alterar -changeMetadata.selectText.2=Excluir todos os metadados -changeMetadata.selectText.3=Mostrar metadados personalizados: +changeMetadata.header=Alterar Metadados +changeMetadata.selectText.1=Edite as variáveis ​​que deseja alterar. +changeMetadata.selectText.2=Excluir todos os metadados. +changeMetadata.selectText.3=Mostrar metadados personalizados. changeMetadata.author=Autor: -changeMetadata.creationDate=Data de criação (aaaa/MM/dd HH:mm:ss): +changeMetadata.creationDate=Data de criação (aaaa/mm/dd HH:mm:ss): changeMetadata.creator=Criador: changeMetadata.keywords=Palavras-chave: -changeMetadata.modDate=Data de modificação (aaaa/MM/dd HH:mm:ss): +changeMetadata.modDate=Data de modificação (aaaa/mm/dd HH:mm:ss): changeMetadata.producer=Produtor: changeMetadata.subject=Assunto: -changeMetadata.trapped=Atrapado: +changeMetadata.trapped=Metadados trapping: changeMetadata.selectText.4=Outros metadados: -changeMetadata.selectText.5=Adicionar entrada de metadados personalizada +changeMetadata.selectText.5=Adicionar Entrada de Metadados Personalizada changeMetadata.submit=Alterar #pdfToPDFA pdfToPDFA.title=PDF para PDF/A pdfToPDFA.header=PDF para PDF/A -pdfToPDFA.credit=Este serviço usa qpdf para conversão de PDF/A +pdfToPDFA.credit=Este serviço usa Qpdf para conversão para PDF/A. pdfToPDFA.submit=Converter -pdfToPDFA.tip=Atualmente não funciona para múltiplas entradas ao mesmo tempo -pdfToPDFA.outputFormat=Formato de saída +pdfToPDFA.tip=Atenção, atualmente não funciona para múltiplas entradas ao mesmo tempo. +pdfToPDFA.outputFormat=Formato de saída: pdfToPDFA.pdfWithDigitalSignature=O PDF contém uma assinatura digital. Isso será removido na próxima etapa. #PDFToWord PDFToWord.title=PDF para Word PDFToWord.header=PDF para Word -PDFToWord.selectText.1=Formato do arquivo de saída +PDFToWord.selectText.1=Formato do arquivo de saída: PDFToWord.credit=Este serviço usa o LibreOffice para conversão de arquivos. PDFToWord.submit=Converter @@ -1137,15 +1147,15 @@ PDFToWord.submit=Converter #PDFToPresentation PDFToPresentation.title=PDF para Apresentação PDFToPresentation.header=PDF para Apresentação -PDFToPresentation.selectText.1=Formato do arquivo de saída +PDFToPresentation.selectText.1=Formato do arquivo de saída: PDFToPresentation.credit=Este serviço usa o LibreOffice para conversão de arquivos. PDFToPresentation.submit=Converter #PDFToText -PDFToText.title=PDF para RTF (Texto) -PDFToText.header=PDF para RTF (Texto) -PDFToText.selectText.1=Formato do arquivo de saída +PDFToText.title=PDF para TXT/RTF +PDFToText.header=PDF para TXT/RTF +PDFToText.selectText.1=Formato do arquivo de saída: PDFToText.credit=Este serviço usa o LibreOffice para conversão de arquivos. PDFToText.submit=Converter @@ -1166,26 +1176,26 @@ PDFToXML.submit=Converter #PDFToCSV PDFToCSV.title=PDF para CSV PDFToCSV.header=PDF para CSV -PDFToCSV.prompt=Escolha a página para extrair a tabela +PDFToCSV.prompt=Escolha a página para extração da tabela: PDFToCSV.submit=Extrair #split-by-size-or-count -split-by-size-or-count.title=Divida o PDF por tamanho ou contagem -split-by-size-or-count.header=Divida o PDF por tamanho ou contagem -split-by-size-or-count.type.label=Selecione o tipo de divisão +split-by-size-or-count.title=Divisão Manual do PDF +split-by-size-or-count.header=Divisão Manual do PDF +split-by-size-or-count.type.label=Selecione o tipo de divisão: split-by-size-or-count.type.size=Por tamanho split-by-size-or-count.type.pageCount=Por contagem de páginas split-by-size-or-count.type.docCount=Por contagem de documentos -split-by-size-or-count.value.label=Insira o valor +split-by-size-or-count.value.label=Insira o valor: split-by-size-or-count.value.placeholder=Insira o tamanho (por exemplo, 2 MB ou 3 KB) ou a contagem (por exemplo, 5) split-by-size-or-count.submit=Enviar #overlay-pdfs -overlay-pdfs.header=Sobrepor Arquivos PDF -overlay-pdfs.baseFile.label=Selecione o arquivo PDF base -overlay-pdfs.overlayFiles.label=Selecione os arquivos PDF para sobreposição -overlay-pdfs.mode.label=Selecione o modo de sobreposição +overlay-pdfs.header=Sobrepor PDFs +overlay-pdfs.baseFile.label=Selecione o arquivo PDF base: +overlay-pdfs.overlayFiles.label=Selecione os arquivos PDF para sobreposição: +overlay-pdfs.mode.label=Selecione o modo de sobreposição: overlay-pdfs.mode.sequential=Sobreposição sequencial overlay-pdfs.mode.interleaved=Sobreposição intercalada overlay-pdfs.mode.fixedRepeat=Sobreposição de repetição fixa @@ -1198,14 +1208,14 @@ overlay-pdfs.submit=Enviar #split-by-sections -split-by-sections.title=Dividir PDF por seções -split-by-sections.header=Divida o PDF em seções -split-by-sections.horizontal.label=Divisões Horizontais -split-by-sections.vertical.label=Divisões Verticais +split-by-sections.title=Dividir PDF por Seções +split-by-sections.header=Dividir PDF por Seções +split-by-sections.horizontal.label=Divisões Horizontais: +split-by-sections.vertical.label=Divisões Verticais: split-by-sections.horizontal.placeholder=Insira o número de divisões horizontais split-by-sections.vertical.placeholder=Insira o número de divisões verticais -split-by-sections.submit=Dividir PDF -split-by-sections.merge=Mesclar em um PDF +split-by-sections.submit=Dividir +split-by-sections.merge=Mesclar em um PDF. #printFile @@ -1227,13 +1237,13 @@ licenses.license=Licença #survey survey.nav=Pesquisa survey.title=Pesquisa Stirling-PDF -survey.description=Stirling-PDF não tem rastreamento, então queremos ouvir nossos usuários para melhorar o Stirling-PDF! -survey.changes=Stirling-PDF mudou desde o a última pesquisa! Para saber mais acesse nosso post no blog: -survey.changes2=Com essas mudanças estamos implementando suporte empresarial pago e financeamento +survey.description=Stirling-PDF não possui rastreamento, então queremos ouvir nossos usuários para melhorar o Stirling-PDF! +survey.changes=Stirling-PDF mudou desde sua última pesquisa! Para saber mais acesse nosso blog: +survey.changes2=Com essas mudanças estamos implementando suporte empresarial pago e financeamento. survey.please=Por favor, considere responder à nossa pesquisa! survey.disabled=(O pop-up da pesquisa será desativado nas atualizações seguintes, mas estará disponível no rodapé da página) -survey.button=Responda a pesquisa -survey.dontShowAgain=Não mostre novamente +survey.button=Responder a Pesquisa +survey.dontShowAgain=Não mostre novamente. #error @@ -1252,66 +1262,66 @@ error.discordSubmit=Discord - Submeter um post de suporte #remove-image removeImage.title=Remover Imagem -removeImage.header=Remover imagem -removeImage.removeImage=Remover imagem -removeImage.submit=Remover imagem +removeImage.header=Remover Imagem +removeImage.removeImage=Remover Imagem +removeImage.submit=Remover Imagem -splitByChapters.title=Dividir PDF por Capítulos -splitByChapters.header=Dividir PDF por Capítulos -splitByChapters.bookmarkLevel=Nível de Marcador -splitByChapters.includeMetadata=Incluir Metadados -splitByChapters.allowDuplicates=Permitir Cópias -splitByChapters.desc.1=Essa ferramenta divide um arquivo PDF em vários arquivos PDFs baseado na estrutura de cápitulos. -splitByChapters.desc.2=Nível de Marcador: Escolha o nível de marcador a ser usado para divisão (0 para o primeiro nível, 1 para o segundo nível, etc). -splitByChapters.desc.3=Incluir Metadados: Se marcado, os metadados do PDF original serão incluidos em cada divisão do PDF. +splitByChapters.title=Divide PDF por Capítulos +splitByChapters.header=Divide PDF por Capítulos +splitByChapters.bookmarkLevel=Nível do Marcador: +splitByChapters.includeMetadata=Incluir Metadados. +splitByChapters.allowDuplicates=Permitir Cópias. +splitByChapters.desc.1=Essa ferramenta divide um arquivo PDF em vários arquivos PDFs baseado na estrutura de capítulos. +splitByChapters.desc.2=Nível do Marcador: Escolha o nível do marcador a ser usado para divisão (0 para o primeiro nível, 1 para o segundo nível, etc). +splitByChapters.desc.3=Incluir Metadados: Se marcado, os metadados do PDF original serão incluidos em cada arquivo gerado pela divisão do PDF. splitByChapters.desc.4=Permitir Cópias: Se marcado, habilita vários marcadores na mesma página para criar PDFs separados. -splitByChapters.submit=Dividir PDF +splitByChapters.submit=Dividir #File Chooser -fileChooser.click=Click -fileChooser.or=or -fileChooser.dragAndDrop=Drag & Drop -fileChooser.hoveredDragAndDrop=Drag & Drop file(s) here +fileChooser.click=Clique +fileChooser.or=ou +fileChooser.dragAndDrop=Arraste & Solte +fileChooser.hoveredDragAndDrop=Arraste & Solte arquivo(s) aqui #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=Versões +releases.title=Notas de Lançamento +releases.header=Notas de Lançamento +releases.current.version=Versão Atual +releases.note=Notas de Lançamento estão disponíveis apenas em Inglês #Validate Signature -validateSignature.title=Validate PDF Signatures -validateSignature.header=Validate Digital Signatures -validateSignature.selectPDF=Select signed PDF file -validateSignature.submit=Validate Signatures -validateSignature.results=Validation Results -validateSignature.status=Status -validateSignature.signer=Signer -validateSignature.date=Date -validateSignature.reason=Reason -validateSignature.location=Location -validateSignature.noSignatures=No digital signatures found in this document -validateSignature.status.valid=Valid -validateSignature.status.invalid=Invalid -validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity -validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified -validateSignature.cert.expired=Certificate has expired -validateSignature.cert.revoked=Certificate has been revoked -validateSignature.signature.info=Signature Information -validateSignature.signature=Signature -validateSignature.signature.mathValid=Signature is mathematically valid BUT: -validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional) -validateSignature.cert.info=Certificate Details -validateSignature.cert.issuer=Issuer -validateSignature.cert.subject=Subject -validateSignature.cert.serialNumber=Serial Number -validateSignature.cert.validFrom=Valid From -validateSignature.cert.validUntil=Valid Until -validateSignature.cert.algorithm=Algorithm -validateSignature.cert.keySize=Key Size -validateSignature.cert.version=Version -validateSignature.cert.keyUsage=Key Usage -validateSignature.cert.selfSigned=Self-Signed +validateSignature.title=Verificar Assinatura com Certificado +validateSignature.header=Verificar Assinatura com Certificado +validateSignature.selectPDF=Selecione PDF com assinatura por certificado: +validateSignature.submit=Verificar Assinatura +validateSignature.results=Resultados da Verificação +validateSignature.status=Situação +validateSignature.signer=Signatário +validateSignature.date=Data +validateSignature.reason=Motivo +validateSignature.location=Localização +validateSignature.noSignatures=Nenhuma assinatura digital encontrada no documento. +validateSignature.status.valid=Valido +validateSignature.status.invalid=Inválido +validateSignature.chain.invalid=Falha na validação da cadeia de certificados - não é possível verificar a identidade do signatário +validateSignature.trust.invalid=Certificado não está presente no repositório de confiança, a fonte não pode ser verificada +validateSignature.cert.expired=Certificate expirou +validateSignature.cert.revoked=Certificado foi revogado +validateSignature.signature.info=Informações da assinatura +validateSignature.signature=Assinatura +validateSignature.signature.mathValid=Assinatura é matematicamente valida PORÉM: +validateSignature.selectCustomCert=Arquivo customizado de certificado X.509 (Opcional) +validateSignature.cert.info=Detalhes do certificado +validateSignature.cert.issuer=Emissor +validateSignature.cert.subject=Assunto +validateSignature.cert.serialNumber=Número de serial +validateSignature.cert.validFrom=Valido de +validateSignature.cert.validUntil=Valido até +validateSignature.cert.algorithm=Algoritmo +validateSignature.cert.keySize=Tamanho da chave +validateSignature.cert.version=Versão +validateSignature.cert.keyUsage=Uso da chave +validateSignature.cert.selfSigned=Autoassinados validateSignature.cert.bits=bits diff --git a/src/main/resources/messages_pt_PT.properties b/src/main/resources/messages_pt_PT.properties index 9038ffa2d..f8e3a1269 100644 --- a/src/main/resources/messages_pt_PT.properties +++ b/src/main/resources/messages_pt_PT.properties @@ -965,6 +965,16 @@ multiTool.dragDropMessage=Page(s) Selected multiTool.undo=Undo multiTool.redo=Redo +#decrypt +decrypt.passwordPrompt=This file is password-protected. Please enter the password: +decrypt.cancelled=Operation cancelled for PDF: {0} +decrypt.noPassword=No password provided for encrypted PDF: {0} +decrypt.invalidPassword=Please try again with the correct password. +decrypt.invalidPasswordHeader=Incorrect password or unsupported encryption for PDF: {0} +decrypt.unexpectedError=There was an error processing the file. Please try again. +decrypt.serverError=Server error while decrypting: {0} +decrypt.success=File decrypted successfully. + #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 bd0d8fb1f..e8547092c 100644 --- a/src/main/resources/messages_ro_RO.properties +++ b/src/main/resources/messages_ro_RO.properties @@ -965,6 +965,16 @@ multiTool.dragDropMessage=Page(s) Selected multiTool.undo=Undo multiTool.redo=Redo +#decrypt +decrypt.passwordPrompt=This file is password-protected. Please enter the password: +decrypt.cancelled=Operation cancelled for PDF: {0} +decrypt.noPassword=No password provided for encrypted PDF: {0} +decrypt.invalidPassword=Please try again with the correct password. +decrypt.invalidPasswordHeader=Incorrect password or unsupported encryption for PDF: {0} +decrypt.unexpectedError=There was an error processing the file. Please try again. +decrypt.serverError=Server error while decrypting: {0} +decrypt.success=File decrypted successfully. + #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 4aaa428aa..55f20961b 100644 --- a/src/main/resources/messages_ru_RU.properties +++ b/src/main/resources/messages_ru_RU.properties @@ -965,6 +965,16 @@ multiTool.dragDropMessage=Page(s) Selected multiTool.undo=Undo multiTool.redo=Redo +#decrypt +decrypt.passwordPrompt=This file is password-protected. Please enter the password: +decrypt.cancelled=Operation cancelled for PDF: {0} +decrypt.noPassword=No password provided for encrypted PDF: {0} +decrypt.invalidPassword=Please try again with the correct password. +decrypt.invalidPasswordHeader=Incorrect password or unsupported encryption for PDF: {0} +decrypt.unexpectedError=There was an error processing the file. Please try again. +decrypt.serverError=Server error while decrypting: {0} +decrypt.success=File decrypted successfully. + #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 925f113d4..4a3e09c64 100644 --- a/src/main/resources/messages_sk_SK.properties +++ b/src/main/resources/messages_sk_SK.properties @@ -965,6 +965,16 @@ multiTool.dragDropMessage=Page(s) Selected multiTool.undo=Undo multiTool.redo=Redo +#decrypt +decrypt.passwordPrompt=This file is password-protected. Please enter the password: +decrypt.cancelled=Operation cancelled for PDF: {0} +decrypt.noPassword=No password provided for encrypted PDF: {0} +decrypt.invalidPassword=Please try again with the correct password. +decrypt.invalidPasswordHeader=Incorrect password or unsupported encryption for PDF: {0} +decrypt.unexpectedError=There was an error processing the file. Please try again. +decrypt.serverError=Server error while decrypting: {0} +decrypt.success=File decrypted successfully. + #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 3c87ec58d..eca995603 100644 --- a/src/main/resources/messages_sr_LATN_RS.properties +++ b/src/main/resources/messages_sr_LATN_RS.properties @@ -965,6 +965,16 @@ multiTool.dragDropMessage=Page(s) Selected multiTool.undo=Undo multiTool.redo=Redo +#decrypt +decrypt.passwordPrompt=This file is password-protected. Please enter the password: +decrypt.cancelled=Operation cancelled for PDF: {0} +decrypt.noPassword=No password provided for encrypted PDF: {0} +decrypt.invalidPassword=Please try again with the correct password. +decrypt.invalidPasswordHeader=Incorrect password or unsupported encryption for PDF: {0} +decrypt.unexpectedError=There was an error processing the file. Please try again. +decrypt.serverError=Server error while decrypting: {0} +decrypt.success=File decrypted successfully. + #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 de9f606e1..006ef41da 100644 --- a/src/main/resources/messages_sv_SE.properties +++ b/src/main/resources/messages_sv_SE.properties @@ -965,6 +965,16 @@ multiTool.dragDropMessage=Page(s) Selected multiTool.undo=Undo multiTool.redo=Redo +#decrypt +decrypt.passwordPrompt=This file is password-protected. Please enter the password: +decrypt.cancelled=Operation cancelled for PDF: {0} +decrypt.noPassword=No password provided for encrypted PDF: {0} +decrypt.invalidPassword=Please try again with the correct password. +decrypt.invalidPasswordHeader=Incorrect password or unsupported encryption for PDF: {0} +decrypt.unexpectedError=There was an error processing the file. Please try again. +decrypt.serverError=Server error while decrypting: {0} +decrypt.success=File decrypted successfully. + #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 27f0ef9d5..1d60581ed 100644 --- a/src/main/resources/messages_th_TH.properties +++ b/src/main/resources/messages_th_TH.properties @@ -965,6 +965,16 @@ multiTool.dragDropMessage=Page(s) Selected multiTool.undo=Undo multiTool.redo=Redo +#decrypt +decrypt.passwordPrompt=This file is password-protected. Please enter the password: +decrypt.cancelled=Operation cancelled for PDF: {0} +decrypt.noPassword=No password provided for encrypted PDF: {0} +decrypt.invalidPassword=Please try again with the correct password. +decrypt.invalidPasswordHeader=Incorrect password or unsupported encryption for PDF: {0} +decrypt.unexpectedError=There was an error processing the file. Please try again. +decrypt.serverError=Server error while decrypting: {0} +decrypt.success=File decrypted successfully. + #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 ebf41c730..d6c750764 100644 --- a/src/main/resources/messages_tr_TR.properties +++ b/src/main/resources/messages_tr_TR.properties @@ -965,6 +965,16 @@ multiTool.dragDropMessage=Page(s) Selected multiTool.undo=Undo multiTool.redo=Redo +#decrypt +decrypt.passwordPrompt=This file is password-protected. Please enter the password: +decrypt.cancelled=Operation cancelled for PDF: {0} +decrypt.noPassword=No password provided for encrypted PDF: {0} +decrypt.invalidPassword=Please try again with the correct password. +decrypt.invalidPasswordHeader=Incorrect password or unsupported encryption for PDF: {0} +decrypt.unexpectedError=There was an error processing the file. Please try again. +decrypt.serverError=Server error while decrypting: {0} +decrypt.success=File decrypted successfully. + #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 e1ae0fc43..7a96d49ed 100644 --- a/src/main/resources/messages_uk_UA.properties +++ b/src/main/resources/messages_uk_UA.properties @@ -965,6 +965,16 @@ multiTool.dragDropMessage=Page(s) Selected multiTool.undo=Undo multiTool.redo=Redo +#decrypt +decrypt.passwordPrompt=This file is password-protected. Please enter the password: +decrypt.cancelled=Operation cancelled for PDF: {0} +decrypt.noPassword=No password provided for encrypted PDF: {0} +decrypt.invalidPassword=Please try again with the correct password. +decrypt.invalidPasswordHeader=Incorrect password or unsupported encryption for PDF: {0} +decrypt.unexpectedError=There was an error processing the file. Please try again. +decrypt.serverError=Server error while decrypting: {0} +decrypt.success=File decrypted successfully. + #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 55ac301cb..1b97853f9 100644 --- a/src/main/resources/messages_vi_VN.properties +++ b/src/main/resources/messages_vi_VN.properties @@ -965,6 +965,16 @@ multiTool.dragDropMessage=Page(s) Selected multiTool.undo=Undo multiTool.redo=Redo +#decrypt +decrypt.passwordPrompt=This file is password-protected. Please enter the password: +decrypt.cancelled=Operation cancelled for PDF: {0} +decrypt.noPassword=No password provided for encrypted PDF: {0} +decrypt.invalidPassword=Please try again with the correct password. +decrypt.invalidPasswordHeader=Incorrect password or unsupported encryption for PDF: {0} +decrypt.unexpectedError=There was an error processing the file. Please try again. +decrypt.serverError=Server error while decrypting: {0} +decrypt.success=File decrypted successfully. + #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 18558dc78..6f3f67dac 100644 --- a/src/main/resources/messages_zh_CN.properties +++ b/src/main/resources/messages_zh_CN.properties @@ -3,11 +3,11 @@ ########### # the direction that the language is written (ltr = left to right, rtl = right to left) language.direction=ltr -addPageNumbers.fontSize=Font Size -addPageNumbers.fontName=Font Name -pdfPrompt=选择PDF -multiPdfPrompt=选择多个PDF(2个或更多) -multiPdfDropPrompt=选择(或拖拽)所需的PDF +addPageNumbers.fontSize=字体大小 +addPageNumbers.fontName=字体名称 +pdfPrompt=选择 PDF +multiPdfPrompt=选择多个 PDF(2个或更多) +multiPdfDropPrompt=选择(或拖拽)所需的 PDF imgPrompt=选择图像 genericSubmit=提交 processTimeWarning=警告:此过程可能需要多达一分钟,具体时间取决于文件大小 @@ -25,7 +25,7 @@ noFavourites=没有添加收藏夹 downloadComplete=下载完成 bored=等待时觉得无聊? alphabet=字母表 -downloadPdf=下载PDF +downloadPdf=下载 PDF text=文本 font=字体 selectFillter=-- 选择-- @@ -63,15 +63,15 @@ deleteUsernameExistsMessage=用户名不存在,无法删除。 downgradeCurrentUserMessage=无法降级当前用户的角色 disabledCurrentUserMessage=无法禁用当前用户。 downgradeCurrentUserLongMessage=无法降级当前用户的角色。因此,当前用户将不会显示。 -userAlreadyExistsOAuthMessage=该用户已作为OAuth2用户存在。 -userAlreadyExistsWebMessage=该用户已作为Web用户存在。 +userAlreadyExistsOAuthMessage=该用户已作为 OAuth2 用户存在。 +userAlreadyExistsWebMessage=该用户已作为 Web 用户存在。 error=错误 oops=哎呀! help=帮助 goHomepage=返回主页 -joinDiscord=加入我们的Discord服务器 -seeDockerHub=查看Docker Hub -visitGithub=访问Github仓库 +joinDiscord=加入我们的 Discord 服务器 +seeDockerHub=查看 Docker Hub +visitGithub=访问 Github 仓库 donate=捐款 color=颜色 sponsor=赞助 @@ -79,14 +79,14 @@ info=信息 pro=Pro page=Page pages=Pages -loading=Loading... +loading=加载中... addToDoc=Add to Document -reset=Reset +reset=重置 -legal.privacy=Privacy Policy -legal.terms=Terms and Conditions -legal.accessibility=Accessibility -legal.cookie=Cookie Policy +legal.privacy=隐私政策 +legal.terms=服务条款 +legal.accessibility=无障碍 +legal.cookie=Cookie 政策 legal.impressum=Impressum ############### @@ -117,8 +117,8 @@ pipelineOptions.validateButton=验证 ######################## # ENTERPRISE EDITION # ######################## -enterpriseEdition.button=Upgrade to Pro -enterpriseEdition.warning=This feature is only available to Pro users. +enterpriseEdition.button=升级到 Pro 版本 +enterpriseEdition.warning=此功能仅适用于 Pro 版本 enterpriseEdition.yamlAdvert=Stirling PDF Pro supports YAML configuration files and other SSO features. enterpriseEdition.ssoAdvert=Looking for more user management features? Check out Stirling PDF Pro @@ -192,11 +192,11 @@ account.newPassword=新密码 account.changePassword=更改密码 account.confirmNewPassword=确认新密码 account.signOut=退出登录 -account.yourApiKey=您的API密钥 +account.yourApiKey=您的 API 密钥 account.syncTitle=将浏览器设置与账户同步 account.settingsCompare=设置比较: account.property=属性 -account.webBrowserSettings=Web浏览器设置 +account.webBrowserSettings=Web 浏览器设置 account.syncToBrowser=同步账户 -> 浏览器 account.syncToAccount=同步账户 <- 浏览器 @@ -213,11 +213,11 @@ adminUserSettings.usernameInfo=用户名只能包含字母、数字和以下特 adminUserSettings.roles=角色 adminUserSettings.role=角色 adminUserSettings.actions=操作 -adminUserSettings.apiUser=受限制的API用户 -adminUserSettings.extraApiUser=额外受限制的API用户 -adminUserSettings.webOnlyUser=仅限Web用户 +adminUserSettings.apiUser=受限制的 API 用户 +adminUserSettings.extraApiUser=额外受限制的 API 用户 +adminUserSettings.webOnlyUser=仅限 Web 用户 adminUserSettings.demoUser=演示用户(无自定义设置) -adminUserSettings.internalApiUser=内部API用户 +adminUserSettings.internalApiUser=内部 API 用户 adminUserSettings.forceChange=强制用户在登录时更改用户名/密码 adminUserSettings.submit=保存用户 adminUserSettings.changeUserRole=更改用户角色 @@ -247,26 +247,26 @@ database.fileNotFound=未找到文件 database.fileNullOrEmpty=文件不能为空 database.failedImportFile=导入文件失败 -session.expired=Your session has expired. Please refresh the page and try again. -session.refreshPage=Refresh Page +session.expired=您的会话已过期。请刷新页面并重试。 +session.refreshPage=刷新页面 ############# # HOME-PAGE # ############# -home.desc=本地部署的一站式服务,满足您的所有PDF需求。 +home.desc=本地部署的一站式服务,满足您的所有 PDF 需求。 home.searchBar=搜索您需要的功能... -home.viewPdf.title=浏览PDF +home.viewPdf.title=浏览 PDF home.viewPdf.desc=浏览、注释、添加文本或图像 viewPdf.tags=浏览、阅读、注释、文本、图像 -home.multiTool.title=PDF多功能工具 -home.multiTool.desc=合并、旋转、重新排列和删除PDF页面 +home.multiTool.title=PDF 多功能工具 +home.multiTool.desc=合并、旋转、重新排列和删除 PDF 页面 multiTool.tags=多工具,多操作,用户界面,点击拖动,前端,客户端 home.merge.title=合并 -home.merge.desc=轻松合并多个PDF为一个。 +home.merge.desc=轻松将多个 PDF 合并成一个。 merge.tags=合并,页面操作,后端,服务器端 home.split.title=拆分 @@ -274,16 +274,16 @@ home.split.desc=将 PDF 拆分为多个文档。 split.tags=页面操作,划分,多页面,剪切,服务器端 home.rotate.title=旋转 -home.rotate.desc=旋转PDF。 +home.rotate.desc=旋转 PDF。 rotate.tags=服务器端 -home.imageToPdf.title=转换图像到PDF -home.imageToPdf.desc=将图像(PNG、JPEG、GIF)转换为PDF。 +home.imageToPdf.title=转换图像到 PDF +home.imageToPdf.desc=将图像(PNG、JPEG、GIF)转换为 PDF。 imageToPdf.tags=转换、图像、JPG、图片、照片 -home.pdfToImage.title=转换PDF到图像 -home.pdfToImage.desc=将PDF转换为图像(PNG、JPEG、GIF)。 +home.pdfToImage.title=转换 PDF 到图像 +home.pdfToImage.desc=将 PDF 转换为图像(PNG、JPEG、GIF)。 pdfToImage.tags=转换、图像、JPG、图片、照片 home.pdfOrganiser.title=整理 @@ -291,92 +291,92 @@ home.pdfOrganiser.desc=按任意顺序删除/重新排列页面。 pdfOrganiser.tags=双面、偶数、奇数、排序、移动 -home.addImage.title=在PDF中添加图片 -home.addImage.desc=将图像添加到PDF的指定位置。 +home.addImage.title=在 PDF 中添加图片 +home.addImage.desc=将图像添加到 PDF 的指定位置。 addImage.tags=图像、JPG、图片、照片 home.watermark.title=添加水印 -home.watermark.desc=在PDF中添加自定义水印。 +home.watermark.desc=在 PDF 中添加自定义水印。 watermark.tags=文本、重复、标签、自定义、版权、商标、图像、JPG、图片、照片 home.permissions.title=更改权限 -home.permissions.desc=更改PDF文档的权限。 +home.permissions.desc=更改 PDF 文档的权限。 permissions.tags=阅读、写入、编辑、打印 home.removePages.title=删除 -home.removePages.desc=从PDF文档中删除不需要的页面。 +home.removePages.desc=从 PDF 文档中删除不需要的页面。 removePages.tags=删除页面、删除 home.addPassword.title=添加密码 -home.addPassword.desc=使用密码对PDF文档进行加密。 +home.addPassword.desc=使用密码对 PDF 文档进行加密。 addPassword.tags=安全、密码、加密 home.removePassword.title=删除密码 -home.removePassword.desc=从PDF文档中移除密码保护。 +home.removePassword.desc=从 PDF 文档中移除密码保护。 removePassword.tags=安全、解密、密码、安全性、删除密码 home.compressPdfs.title=压缩 -home.compressPdfs.desc=压缩PDF文件以减小文件大小。 +home.compressPdfs.desc=压缩 PDF 文件以减小文件大小。 compressPdfs.tags=压缩、小、微小 home.changeMetadata.title=更改元数据 -home.changeMetadata.desc=更改/删除/添加PDF文档的元数据。 +home.changeMetadata.desc=更改/删除/添加 PDF 文档的元数据。 changeMetadata.tags=标题、作者、日期、创建、时间、发布者、制作人、统计数据 -home.fileToPDF.title=将文件转换为PDF文件 -home.fileToPDF.desc=将几乎所有文件转换为PDF(DOCX、PNG、XLS、PPT、TXT等)。 +home.fileToPDF.title=将文件转换为 PDF 文件 +home.fileToPDF.desc=将几乎所有文件转换为 PDF (DOCX、PNG、XLS、PPT、TXT等)。 fileToPDF.tags=转换、格式、文档、图片、幻灯片、文本、转换、Office、Docs、Word、Excel、PowerPoint -home.ocr.title=运行OCR/清理扫描 -home.ocr.desc=清理和识别PDF中的图像文本,并将其转换为可编辑文本。 +home.ocr.title=运行 OCR /清理扫描 +home.ocr.desc=清理和识别 PDF 中的图像文本,并将其转换为可编辑文本。 ocr.tags=识别、文本、图像、扫描、阅读、识别、检测、可编辑 home.extractImages.title=提取图像 -home.extractImages.desc=从PDF中提取所有图像并保存到压缩包中。 +home.extractImages.desc=从 PDF 中提取所有图像并保存到压缩包中。 extractImages.tags=图片、照片、保存、归档、压缩包、截取、抓取 -home.pdfToPDFA.title=PDF转PDF/A -home.pdfToPDFA.desc=将PDF转换为PDF/A以进行长期保存。 +home.pdfToPDFA.title=PDF 转 PDF/A +home.pdfToPDFA.desc=将 PDF 转换为 PDF/A 以进行长期保存。 pdfToPDFA.tags=归档、长期、标准、转换、存储、保存 -home.PDFToWord.title=PDF转Word +home.PDFToWord.title=PDF 转 Word home.PDFToWord.desc=将PDF转换为Word格式(DOC、DOCX和ODT)。 PDFToWord.tags=doc、docx、odt、word、转换、格式、Office、Microsoft、文档 -home.PDFToPresentation.title=PDF转演示文稿 -home.PDFToPresentation.desc=将PDF转换为演示文稿格式(PPT、PPTX和ODP)。 +home.PDFToPresentation.title=PDF 转演示文稿 +home.PDFToPresentation.desc=将 PDF 转换为演示文稿格式(PPT、PPTX 和 ODP)。 PDFToPresentation.tags=幻灯片、展示、Office、Microsoft -home.PDFToText.title=PDF转RTF(文本) -home.PDFToText.desc=将PDF转换为文本或RTF格式。 +home.PDFToText.title=PDF 转 RTF(文本) +home.PDFToText.desc=将PDF转换为文本或 RTF 格式。 PDFToText.tags=富文本格式、RTF、富文本格式 -home.PDFToHTML.title=PDF转HTML -home.PDFToHTML.desc=将PDF转换为HTML格式。 +home.PDFToHTML.title=PDF 转 HTML +home.PDFToHTML.desc=将 PDF 转换为 HTML 格式。 PDFToHTML.tags=网页内容、浏览器友好 -home.PDFToXML.title=PDF转XML -home.PDFToXML.desc=将PDF转换为XML格式。 +home.PDFToXML.title=PDF 转 XML +home.PDFToXML.desc=将 PDF 转换为 XML 格式。 PDFToXML.tags=数据提取、结构化内容、互操作、转换 home.ScannerImageSplit.title=检测/分割扫描图像 -home.ScannerImageSplit.desc=从一张照片或PDF中分割出多张照片。 +home.ScannerImageSplit.desc=从一张照片或 PDF 中分割出多张照片。 ScannerImageSplit.tags=分离、自动检测、扫描、多张照片、整理 home.sign.title=签名 -home.sign.desc=通过绘图、文字或图像向PDF添加签名 +home.sign.desc=通过绘图、文字或图像向 PDF 添加签名 sign.tags=授权、缩写、手绘签名、文本签名、图像签名 home.flatten.title=展平 -home.flatten.desc=从PDF中删除所有互动元素和表单 +home.flatten.desc=从 PDF 中删除所有互动元素和表单 flatten.tags=静态、停用、非交互、简化 home.repair.title=修复 -home.repair.desc=尝试修复损坏/损坏的PDF +home.repair.desc=尝试修复损坏/损坏的 PDF repair.tags=修复、恢复、纠正、恢复 home.removeBlanks.title=删除空白页 @@ -384,11 +384,11 @@ home.removeBlanks.desc=检测并删除文档中的空白页 removeBlanks.tags=清理、简化、非内容、整理 home.removeAnnotations.title=删除标注 -home.removeAnnotations.desc=删除PDF中的所有标注/评论 +home.removeAnnotations.desc=删除 PDF 中的所有标注/评论 removeAnnotations.tags=评论、高亮、笔记、标注、删除 home.compare.title=比较 -home.compare.desc=比较并显示两个PDF文档之间的差异 +home.compare.desc=比较并显示两个 PDF 文档之间的差异 compare.tags=区分、对比、更改、分析 home.certSign.title=使用证书签名 @@ -396,11 +396,11 @@ home.certSign.desc=使用证书/密钥(PEM/P12)对PDF进行签名 certSign.tags=身份验证、PEM、P12、官方、加密 home.removeCertSign.title=移除证书签名 -home.removeCertSign.desc=移除PDF的证书签名 +home.removeCertSign.desc=移除 PDF 的证书签名 removeCertSign.tags=身份验证、PEM、P12、官方、加密 home.pageLayout.title=多页布局 -home.pageLayout.desc=将PDF文档的多个页面合并成一页 +home.pageLayout.desc=将 PDF 文档的多个页面合并成一页 pageLayout.tags=合并、组合、单视图、整理 home.scalePages.title=调整页面尺寸/缩放 @@ -408,86 +408,86 @@ home.scalePages.desc=调整页面及/或其内容的尺寸/缩放 scalePages.tags=调整大小、修改、尺寸、适应 home.pipeline.title=流水线(高级版) -home.pipeline.desc=通过定义流水线脚本在PDF上运行多个操作 +home.pipeline.desc=通过定义流水线脚本在 PDF 上运行多个操作 pipeline.tags=自动化、顺序、脚本化、批处理 home.add-page-numbers.title=添加页码 home.add-page-numbers.desc=在文档的指定位置添加页码 add-page-numbers.tags=分页、标签、整理、索引 -home.auto-rename.title=自动重命名PDF文件 -home.auto-rename.desc=根据检测到的标题自动对PDF文件进行重命名 +home.auto-rename.title=自动重命名 PDF 文件 +home.auto-rename.desc=根据检测到的标题自动对 PDF 文件进行重命名 auto-rename.tags=自动检测、基于标题、整理、重新标记 home.adjust-contrast.title=调整颜色/对比度 -home.adjust-contrast.desc=调整PDF的对比度、饱和度和亮度 +home.adjust-contrast.desc=调整 PDF 的对比度、饱和度和亮度 adjust-contrast.tags=颜色校正、调节、修改、增强 -home.crop.title=裁剪PDF -home.crop.desc=裁剪PDF以减小其文件大小(保留文本!) +home.crop.title=裁剪 PDF +home.crop.desc=裁剪 PDF 以减小其文件大小(保留文本!) crop.tags=修剪、缩小、编辑、形状 home.autoSplitPDF.title=自动拆分页面 -home.autoSplitPDF.desc=使用物理扫描页面分割器QR代码自动拆分扫描的PDF -autoSplitPDF.tags=基于QR码、分离、扫描分割、整理 +home.autoSplitPDF.desc=使用物理扫描页面分割器 QR 代码自动拆分扫描的 PDF +autoSplitPDF.tags=基于 QR 码、分离、扫描分割、整理 home.sanitizePdf.title=清理 -home.sanitizePdf.desc=从PDF文件中删除脚本和其他元素 +home.sanitizePdf.desc=从 PDF 文件中删除脚本和其他元素 sanitizePdf.tags=清理、安全、安全、删除威胁 -home.URLToPDF.title=URL/网站转PDF -home.URLToPDF.desc=将任何http(s)URL转换为PDF +home.URLToPDF.title=URL/网站转 PDF +home.URLToPDF.desc=将任何 http(s)URL 转换为PDF URLToPDF.tags=网页捕获、保存网页、网页转文档、归档 -home.HTMLToPDF.title=HTML转PDF -home.HTMLToPDF.desc=将任何HTML文件或zip文件转换为PDF +home.HTMLToPDF.title=HTML 转 PDF +home.HTMLToPDF.desc=将任何 HTML 文件或 zip 文件转换为 PDF HTMLToPDF.tags=标记、网页内容、转换、转换 -home.MarkdownToPDF.title=Markdown转PDF -home.MarkdownToPDF.desc=将任何Markdown文件转换为PDF +home.MarkdownToPDF.title=Markdown 转 PDF +home.MarkdownToPDF.desc=将任何 Markdown 文件转换为 PDF MarkdownToPDF.tags=标记、网页内容、转换、转换 -home.getPdfInfo.title=获取PDF的所有信息 -home.getPdfInfo.desc=获取PDF的所有可能的信息 +home.getPdfInfo.title=获取 PDF 的所有信息 +home.getPdfInfo.desc=获取 PDF 的所有可能的信息 getPdfInfo.tags=信息、数据、统计、统计数据 home.extractPage.title=提取页面 -home.extractPage.desc=从PDF中提取选定的页面 +home.extractPage.desc=从 PDF 中提取选定的页面 extractPage.tags=提取 -home.PdfToSinglePage.title=PDF转单一大页 -home.PdfToSinglePage.desc=将所有PDF页面合并为一个大的单页 +home.PdfToSinglePage.title=PDF 转单一大页 +home.PdfToSinglePage.desc=将所有 PDF 页面合并为一个大的单页 PdfToSinglePage.tags=单页 -home.showJS.title=显示JavaScript -home.showJS.desc=搜索并显示嵌入到PDF中的任何JavaScript代码 +home.showJS.title=显示 JavaScript +home.showJS.desc=搜索并显示嵌入到 PDF 中的任何 JavaScript 代码 showJS.tags=JavaScript home.autoRedact.title=自动删除 -home.autoRedact.desc=根据输入文本自动删除(覆盖)PDF中的文本 +home.autoRedact.desc=根据输入文本自动删除(覆盖)PDF 中的文本 autoRedact.tags=脱敏、隐藏、涂黑、标记、不可见 -home.tableExtraxt.title=PDF转CSV -home.tableExtraxt.desc=从PDF中提取表格并将其转换为CSV +home.tableExtraxt.title=PDF 转 CSV +home.tableExtraxt.desc=从 PDF 中提取表格并将其转换为 CSV tableExtraxt.tags=CSV、表格提取、提取、转换 -home.autoSizeSplitPDF.title=自动根据大小/数目拆分PDF -home.autoSizeSplitPDF.desc=将单个PDF拆分为多个文档,基于大小、页数或文档数 +home.autoSizeSplitPDF.title=自动根据大小/数目拆分 PDF +home.autoSizeSplitPDF.desc=将单个 PDF 拆分为多个文档,基于大小、页数或文档数 autoSizeSplitPDF.tags=pdf、拆分、文件、组织 -home.overlay-pdfs.title=叠加PDF -home.overlay-pdfs.desc=将PDF叠加在另一个PDF上 +home.overlay-pdfs.title=叠加 PDF +home.overlay-pdfs.desc=将 PDF 叠加在另一个 PDF 上 overlay-pdfs.tags=叠加 -home.split-by-sections.title=拆分PDF成小块 -home.split-by-sections.desc=将PDF的每一页分割成更小的水平和垂直的部分 +home.split-by-sections.title=拆分 PDF 成小块 +home.split-by-sections.desc=将 PDF 的每一页分割成更小的水平和垂直的部分 split-by-sections.tags=章节拆分、分割、自定义 home.AddStampRequest.title=添加图章 @@ -495,34 +495,34 @@ home.AddStampRequest.desc=在指定位置添加文本或图片图章 AddStampRequest.tags=图章、添加图片、图片居中、水印、PDF、嵌入、自定义 -home.PDFToBook.title=PDF转电子书 -home.PDFToBook.desc=使用Calibre将PDF转换成电子书/漫画 +home.PDFToBook.title=PDF 转电子书 +home.PDFToBook.desc=使用 Calibre 将 PDF 转换成电子书/漫画 PDFToBook.tags=电子书、漫画、Calibre、转换、日本漫画、亚马逊、kindle -home.BookToPDF.title=电子书转PDF -home.BookToPDF.desc=使用Calibre将电子书/漫画转换成PDF +home.BookToPDF.title=电子书转 PDF +home.BookToPDF.desc=使用 Calibre 将电子书/漫画转换成 PDF BookToPDF.tags=电子书、漫画、Calibre、转换、日本漫画、亚马逊、kindle home.removeImagePdf.title=删除图像 -home.removeImagePdf.desc=删除图像减少PDF大小 +home.removeImagePdf.desc=删除图像减少 PDF 大小 removeImagePdf.tags=删除图像, 页面操作, 后端, 服务端 -home.splitPdfByChapters.title=Split PDF by Chapters -home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure. -splitPdfByChapters.tags=split,chapters,bookmarks,organize +home.splitPdfByChapters.title=按章节拆分 PDF +home.splitPdfByChapters.desc=根据其章节结构将 PDF 拆分为多个文件。 +splitPdfByChapters.tags=分割,章节,书签,组织 -home.validateSignature.title=Validate PDF Signature -home.validateSignature.desc=Verify digital signatures and certificates in PDF documents -validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate +home.validateSignature.title=验证 PDF 签名 +home.validateSignature.desc=验证 PDF 文档中的数字签名和证书 +validateSignature.tags=签名,验证,验证,PDF,证书,数字签名,验证签名,验证证书 #replace-invert-color -replace-color.title=Replace-Invert-Color -replace-color.header=Replace-Invert Color PDF -home.replaceColorPdf.title=Replace and Invert Color -home.replaceColorPdf.desc=Replace color for text and background in PDF and invert full color of pdf to reduce file size +replace-color.title=替换-反转-颜色 +replace-color.header=替换-反转 PDF 颜色 +home.replaceColorPdf.title=替换和反转颜色 +home.replaceColorPdf.desc=替换 PDF 中文本和背景的颜色,并将PDF全色反转以减小文件大小 replaceColorPdf.tags=Replace Color,Page operations,Back end,server side -replace-color.selectText.1=Replace or Invert color Options +replace-color.selectText.1=替换或反转颜色选项 replace-color.selectText.2=Default(Default high contrast colors) replace-color.selectText.3=Custom(Customized colors) replace-color.selectText.4=Full-Invert(Invert all colors) @@ -551,18 +551,18 @@ login.invalid=用户名或密码无效。 login.locked=您的账户已被锁定。 login.signinTitle=请登录 login.ssoSignIn=通过单点登录登录 -login.oauth2AutoCreateDisabled=OAuth2自动创建用户已禁用 +login.oauth2AutoCreateDisabled=OAuth2 自动创建用户已禁用 login.oauth2AdminBlockedUser=目前已阻止未注册用户的注册或登录。请联系管理员。 login.oauth2RequestNotFound=找不到验证请求 login.oauth2InvalidUserInfoResponse=无效的用户信息响应 login.oauth2invalidRequest=无效请求 login.oauth2AccessDenied=拒绝访问 -login.oauth2InvalidTokenResponse=无效的Token响应 -login.oauth2InvalidIdToken=无效的Token +login.oauth2InvalidTokenResponse=无效的 Token 响应 +login.oauth2InvalidIdToken=无效的 Token login.userIsDisabled=用户被禁用,登录已被阻止。请联系管理员。 -login.alreadyLoggedIn=You are already logged in to -login.alreadyLoggedIn2=devices. Please log out of the devices and try again. -login.toManySessions=You have too many active sessions +login.alreadyLoggedIn=您已经登录到了 +login.alreadyLoggedIn2=设备,请注销设备后重试。 +login.toManySessions=你已经有太多的会话了。请注销一些设备后重试。 #auto-redact autoRedact.title=自动删除 @@ -578,15 +578,15 @@ autoRedact.submitButton=提交 #showJS -showJS.title=显示JavaScript -showJS.header=显示JavaScript -showJS.downloadJS=下载JavaScript +showJS.title=显示 JavaScript +showJS.header=显示 JavaScript +showJS.downloadJS=下载 JavaScript showJS.submit=显示 #pdfToSinglePage -pdfToSinglePage.title=PDF转单页 -pdfToSinglePage.header=将PDF转换为单页 +pdfToSinglePage.title=PDF 转单页 +pdfToSinglePage.header=将 PDF 转换为单页 pdfToSinglePage.submit=转为单页 @@ -598,34 +598,34 @@ pageExtracter.placeholder=(例如:1,2,8 或 4,7,12-16 或 2n-1) #getPdfInfo -getPdfInfo.title=获取PDF信息 -getPdfInfo.header=获取PDF信息 +getPdfInfo.title=获取 PDF 信息 +getPdfInfo.header=获取 PDF 信息 getPdfInfo.submit=获取信息 -getPdfInfo.downloadJson=下载JSON +getPdfInfo.downloadJson=下载 JSON #markdown-to-pdf -MarkdownToPDF.title=Markdown转PDF -MarkdownToPDF.header=将Markdown转换为PDF +MarkdownToPDF.title=Markdown 转 PDF +MarkdownToPDF.header=将 Markdown 转换为 PDF MarkdownToPDF.submit=转换 MarkdownToPDF.help=正在努力中 -MarkdownToPDF.credit=此服务使用WeasyPrint进行文件转换。 +MarkdownToPDF.credit=此服务使用 WeasyPrint 进行文件转换。 #url-to-pdf -URLToPDF.title=URL转PDF -URLToPDF.header=将URL转换为PDF +URLToPDF.title=URL 转 PDF +URLToPDF.header=将 URL 转换为 PDF URLToPDF.submit=转换 -URLToPDF.credit=此服务使用WeasyPrint进行文件转换。 +URLToPDF.credit=此服务使用 WeasyPrint 进行文件转换。 #html-to-pdf -HTMLToPDF.title=HTML转PDF -HTMLToPDF.header=将HTML转换为PDF -HTMLToPDF.help=接受HTML文件和包含所需的html/css/images等的ZIP文件 +HTMLToPDF.title=HTML 转 PDF +HTMLToPDF.header=将 HTML 转换为 PDF +HTMLToPDF.help=接受 HTML 文件和包含所需的 html/css/images 等的 ZIP 文件 HTMLToPDF.submit=转换 -HTMLToPDF.credit=此服务使用WeasyPrint进行文件转换。 +HTMLToPDF.credit=此服务使用 WeasyPrint 进行文件转换。 HTMLToPDF.zoom=网站显示缩放级别 HTMLToPDF.pageWidth=页面宽度-以厘米为单位(填空则使用默认值) HTMLToPDF.pageHeight=页面高度-以厘米为单位(填空则使用默认值) @@ -635,7 +635,7 @@ HTMLToPDF.marginLeft=页面左上边距-以毫米为单位(填空则使用默 HTMLToPDF.marginRight=页面右边距-以毫米为单位(填空则使用默认值) HTMLToPDF.printBackground=页面背景渲染 HTMLToPDF.defaultHeader=启用默认页头(文件名称和页码) -HTMLToPDF.cssMediaType=更换页面的CSS媒体类型。 +HTMLToPDF.cssMediaType=更换页面的 CSS 媒体类型。 HTMLToPDF.none=无 HTMLToPDF.print=打印 HTMLToPDF.screen=屏幕 @@ -660,9 +660,9 @@ AddStampRequest.submit=提交 #sanitizePDF -sanitizePDF.title=清理PDF -sanitizePDF.header=清理PDF文件 -sanitizePDF.selectText.1=移除JavaScript操作 +sanitizePDF.title=清理 PDF +sanitizePDF.header=清理 PDF 文件 +sanitizePDF.selectText.1=移除 JavaScript 操作 sanitizePDF.selectText.2=移除嵌入的文件 sanitizePDF.selectText.3=移除元数据 sanitizePDF.selectText.4=移除链接 @@ -681,13 +681,13 @@ addPageNumbers.selectText.5=添加页码的页数 addPageNumbers.selectText.6=自定义文本 addPageNumbers.customTextDesc=自定义文本 addPageNumbers.numberPagesDesc=要添加页码的页数,默认为“所有”,也可以接受1-5或2,5,9等 -addPageNumbers.customNumberDesc=默认为{n},也可以接受“第{n}页/共{total}页”,“文本-{n}”,“{filename}-{n}” +addPageNumbers.customNumberDesc=默认为 {n},也可以接受“第 {n} 页/共 {total} 页”,“文本-{n}”,“{filename}-{n}” addPageNumbers.submit=添加页码 #auto-rename auto-rename.title=自动重命名 -auto-rename.header=自动重命名PDF +auto-rename.header=自动重命名 PDF auto-rename.submit=自动重命名 @@ -702,19 +702,19 @@ adjustContrast.download=下载 #crop crop.title=裁剪 -crop.header=裁剪PDF +crop.header=裁剪 PDF crop.submit=提交 #autoSplitPDF -autoSplitPDF.title=自动拆分PDF -autoSplitPDF.header=自动拆分PDF +autoSplitPDF.title=自动拆分 PDF +autoSplitPDF.header=自动拆分 PDF autoSplitPDF.description=打印、插入、扫描、上传,让我们自动分离您的文档。无需手动排序。 autoSplitPDF.selectText.1=从下面打印一些分隔页(黑白打印即可)。 autoSplitPDF.selectText.2=在文档之间插入分隔页,一次性扫描所有文档。 -autoSplitPDF.selectText.3=上传单个大型扫描的PDF文件,让Stirling PDF处理剩下的事情。 +autoSplitPDF.selectText.3=上传单个大型扫描的 PDF 文件,让 Stirling PDF 处理剩下的事情。 autoSplitPDF.selectText.4=分隔页会自动检测和删除,确保最终文档整洁。 -autoSplitPDF.formPrompt=提交包含Stirling-PDF分隔页的PDF: +autoSplitPDF.formPrompt=提交包含 Stirling-PDF 分隔页的 PDF: autoSplitPDF.duplexMode=双面模式(正反面扫描) autoSplitPDF.dividerDownload1=下载“自动拆分分隔页(最小化).pdf” autoSplitPDF.dividerDownload2=下载“自动拆分分隔页(带指导说明).pdf” @@ -737,34 +737,34 @@ pageLayout.submit=提交 scalePages.title=调整页面缩放比例 scalePages.header=调整页面缩放比例 scalePages.pageSize=文档页面的尺寸。 -scalePages.keepPageSize=Original Size +scalePages.keepPageSize=保持页面原尺寸 scalePages.scaleFactor=页面的缩放级别(裁剪)。 scalePages.submit=提交 #certSign certSign.title=证书签名 -certSign.header=使用您的证书签名PDF(进行中) -certSign.selectPDF=选择要签名的PDF文件: -certSign.jksNote=注意:如果您的证书类型未在下面列出,请使用keytool命令行工具将其转换为Java Keystore(.jks)文件。 然后,选择下面的.jks文件选项。 +certSign.header=使用您的证书签名 PDF(进行中) +certSign.selectPDF=选择要签名的 PDF 文件: +certSign.jksNote=注意:如果您的证书类型未在下面列出,请使用keytool命令行工具将其转换为 Java Keystore(.jks)文件。 然后,选择下面的.jks文件选项。 certSign.selectKey=选择您的私钥文件(PKCS#8格式,可以是.pem或.der): certSign.selectCert=选择您的证书文件(X.509格式,可以是.pem或.der): -certSign.selectP12=选择您的PKCS#12密钥库文件(.p12或.pfx)(可选,如果提供,它应该包含您的私钥和证书): -certSign.selectJKS=选择你的Java Keystore文件 (.jks或.keystore): +certSign.selectP12=选择您的 PKCS#12 密钥库文件(.p12或.pfx)(可选,如果提供,它应该包含您的私钥和证书): +certSign.selectJKS=选择你的 Java Keystore 文件 (.jks或.keystore): certSign.certType=证书类型 certSign.password=输入您的密钥库或私钥密码(如果有): certSign.showSig=显示签名 certSign.reason=原因 certSign.location=位置 certSign.name=名称 -certSign.showLogo=Show Logo -certSign.submit=给PDF签名 +certSign.showLogo=显示 Logo +certSign.submit=给 PDF 签名 #removeCertSign removeCertSign.title=移除证书签名 -removeCertSign.header=移除PDF的证书签名 -removeCertSign.selectPDF=选择PDF文件: +removeCertSign.header=移除 PDF 的证书签名 +removeCertSign.selectPDF=选择 PDF 文件: removeCertSign.submit=移除签名 @@ -792,21 +792,21 @@ compare.highlightColor.2=高亮颜色 2: compare.document.1=文档 1 compare.document.2=文档 2 compare.submit=比较 -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.complex.message=提供的一份或两份文件是大文件,比较的准确性可能会降低。 +compare.large.file.message=提供的文件中有一份或两份过大,无法处理。 +compare.no.text.message=所选的 PDF 文件中有一个或两个没有文本内容。请选择包含文本的 PDF 文件进行对比。 #BookToPDF -BookToPDF.title=电子书和漫画转换成PDF -BookToPDF.header=电子书转PDF -BookToPDF.credit=此服务使用Calibre进行文件转换。 +BookToPDF.title=电子书和漫画转换成 PDF +BookToPDF.header=电子书转 PDF +BookToPDF.credit=此服务使用 Calibre 进行文件转换。 BookToPDF.submit=转换 #PDFToBook -PDFToBook.title=PDF转电子书 -PDFToBook.header=PDF转电子书 +PDFToBook.title=PDF 转电子书 +PDFToBook.header=PDF 转电子书 PDFToBook.selectText.1=格式 -PDFToBook.credit=此服务使用Calibre进行文件转换。 +PDFToBook.credit=此服务使用 Calibre 进行文件转换。 PDFToBook.submit=转换 #sign @@ -817,21 +817,21 @@ sign.draw=绘制签名 sign.text=文本输入 sign.clear=清除 sign.add=添加 -sign.saved=Saved Signatures -sign.save=Save Signature -sign.personalSigs=Personal Signatures +sign.saved=已保存签名 +sign.save=保存签名 +sign.personalSigs=个人签名 sign.sharedSigs=Shared Signatures -sign.noSavedSigs=No saved signatures found -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.noSavedSigs=未找到已保存的签名 +sign.addToAll=添加到所有页面 +sign.delete=删除 +sign.first=首页 +sign.last=末页 +sign.next=下一页 +sign.previous=上一页 #repair repair.title=修复 -repair.header=修复PDF +repair.header=修复 PDF repair.submit=修复 @@ -853,27 +853,27 @@ ScannerImageSplit.selectText.7=最小轮廓面积: ScannerImageSplit.selectText.8=设置照片的最小轮廓面积阈值。 ScannerImageSplit.selectText.9=边框尺寸: ScannerImageSplit.selectText.10=设置添加和删除的边框大小,以防止输出中出现白边(默认值:1)。 -ScannerImageSplit.info=此功能需要安装Python +ScannerImageSplit.info=此功能需要安装 Python #OCR ocr.title=OCR/扫描清理 ocr.header=清理扫描件/OCR(光学字符识别)。 -ocr.selectText.1=选择要在PDF中检测的语言(列出的语言是目前检测到的): -ocr.selectText.2=生成包含OCR文本的文本文件,与OCR编辑的PDF一起。 +ocr.selectText.1=选择要在 PDF 中检测的语言(列出的语言是目前检测到的): +ocr.selectText.2=生成包含 OCR 文本的文本文件,与 OCR 编辑的 PDF 一起。 ocr.selectText.3=通过将页面旋转回原位来纠正偏斜的扫描角度 -ocr.selectText.4=清理页面,降低OCR在噪点中识别到文本的可能。(没有输出变化) -ocr.selectText.5=清洁页面,降低OCR在噪点中识别到文本的可能,保持输出的清洁。 -ocr.selectText.6=忽略有交互式文本的页面,只对有图像的页面进行OCR。 -ocr.selectText.7=强制OCR,将OCR每个页面,删除所有的原始文本元素。 -ocr.selectText.8=正常 (如果PDF包含文本,将出现错误) +ocr.selectText.4=清理页面,降低 OCR 在噪点中识别到文本的可能。(没有输出变化) +ocr.selectText.5=清洁页面,降低 OCR 在噪点中识别到文本的可能,保持输出的清洁。 +ocr.selectText.6=忽略有交互式文本的页面,只对有图像的页面进行 OCR。 +ocr.selectText.7=强制 OCR,将 OCR 每个页面,删除所有的原始文本元素。 +ocr.selectText.8=正常 (如果 PDF 包含文本,将出现错误) ocr.selectText.9=额外设置 -ocr.selectText.10=OCR模式 -ocr.selectText.11=OCR后移除图像(移除所有图像,只有在转换步骤中才有用)。 +ocr.selectText.10=OCR 模式 +ocr.selectText.11=OCR 后移除图像(移除所有图像,只有在转换步骤中才有用)。 ocr.selectText.12=渲染类型(高级) -ocr.help=请阅读此文档,了解如何将其用于其他语言和/或不在docker中使用。 -ocr.credit=此服务使用qpdf和Tesseract进行OCR。 -ocr.submit=用OCR处理PDF +ocr.help=请阅读此文档,了解如何将其用于其他语言和/或不在 docker 中使用。 +ocr.credit=此服务使用 qpdf 和 Tesseract 进行 OCR。 +ocr.submit=用 OCR 处理 PDF #extractImages @@ -885,18 +885,18 @@ extractImages.submit=提取 #File to PDF -fileToPDF.title=文件转换为PDF -fileToPDF.header=将任何文件转换为PDF。 -fileToPDF.credit=此服务使用LibreOffice和Unoconv进行文件转换。 +fileToPDF.title=文件转换为 PDF +fileToPDF.header=将任何文件转换为 PDF。 +fileToPDF.credit=此服务使用 LibreOffice 和 Unoconv 进行文件转换。 fileToPDF.supportedFileTypesInfo=支持的文件类型 -fileToPDF.supportedFileTypes=支持的文件类型应该包括以下几种,但是,对于支持的格式的完整更新列表,请参考LibreOffice文档。 +fileToPDF.supportedFileTypes=支持的文件类型应该包括以下几种,但是,对于支持的格式的完整更新列表,请参考 LibreOffice 文档。 fileToPDF.submit=转换为 PDF #compress compress.title=压缩 -compress.header=压缩PDF -compress.credit=此服务使用qpdf进行PDF压缩/优化。 +compress.header=压缩 PDF +compress.credit=此服务使用qpdf进行 PDF 压缩/优化。 compress.selectText.1=手动模式 - 从 1 到 4 compress.selectText.2=优化级别: compress.selectText.3=4(文本图像很糟糕) @@ -907,7 +907,7 @@ compress.submit=压缩 #Add image addImage.title=添加图像 -addImage.header=添加图片到PDF +addImage.header=添加图片到 PDF addImage.everyPage=每一页? addImage.upload=添加图片 addImage.submit=添加图片 @@ -915,7 +915,7 @@ addImage.submit=添加图片 #merge merge.title=合并 -merge.header=合并多个PDF(2个以上)。 +merge.header=合并多个 PDF(2个以上)。 merge.sortByName=按名称排序 merge.sortByDate=按日期排序 merge.removeCertSign=删除合并文件的数字签名吗? @@ -924,7 +924,7 @@ merge.submit=合并 #pdfOrganiser pdfOrganiser.title=页面排序 -pdfOrganiser.header=PDF页面排序 +pdfOrganiser.header=PDF 页面排序 pdfOrganiser.submit=重新排列页面 pdfOrganiser.mode=模式 pdfOrganiser.mode.1=自定义页面顺序 @@ -941,84 +941,94 @@ pdfOrganiser.placeholder=(例如:1,3,2 或 4-8,2,10-12 或 2n-1) #multiTool -multiTool.title=PDF多功能工具 -multiTool.header=PDF多功能工具 +multiTool.title=PDF 多功能工具 +multiTool.header=PDF 多功能工具 multiTool.uploadPrompts=文件名 -multiTool.selectAll=Select All -multiTool.deselectAll=Deselect All +multiTool.selectAll=选择所有 +multiTool.deselectAll=取消选择所有 multiTool.selectPages=Page Select -multiTool.selectedPages=Selected Pages +multiTool.selectedPages=已选择的页面 multiTool.page=Page -multiTool.deleteSelected=Delete Selected -multiTool.downloadAll=Export -multiTool.downloadSelected=Export Selected +multiTool.deleteSelected=删除已选 +multiTool.downloadAll=导出全部 +multiTool.downloadSelected=导出已选 -multiTool.insertPageBreak=Insert Page Break -multiTool.addFile=Add File -multiTool.rotateLeft=Rotate Left -multiTool.rotateRight=Rotate Right -multiTool.split=Split -multiTool.moveLeft=Move Left -multiTool.moveRight=Move Right -multiTool.delete=Delete -multiTool.dragDropMessage=Page(s) Selected +multiTool.insertPageBreak=插入分页符 +multiTool.addFile=添加文件 +multiTool.rotateLeft=向左旋转 +multiTool.rotateRight=向右旋转 +multiTool.split=分割 +multiTool.moveLeft=向做移动 +multiTool.moveRight=向右移动 +multiTool.delete=删除 +multiTool.dragDropMessage=选择页面 multiTool.undo=Undo multiTool.redo=Redo +#decrypt +decrypt.passwordPrompt=此文件受密码保护。请输入密码: +decrypt.cancelled=PDF 操作已取消: {0} +decrypt.noPassword=未提供加密 PDF 的密码: {0} +decrypt.invalidPassword=请使用正确的密码重试。 +decrypt.invalidPasswordHeader=密码错误或不支持的 PDF 加密: {0} +decrypt.unexpectedError=处理文件时发生错误。请再试一次。 +decrypt.serverError=服务器解密时发生错误: {0} +decrypt.success=文件解密成功。 + #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=此功能也适用于我们的“多功能工具页面”。查看它以获得增强的逐页 UI 以及其他功能! #view pdf -viewPdf.title=浏览PDF -viewPdf.header=浏览PDF +viewPdf.title=浏览 PDF +viewPdf.header=浏览 PDF #pageRemover pageRemover.title=删除页面 -pageRemover.header=PDF页面移除器 +pageRemover.header=PDF 页面移除器 pageRemover.pagesToDelete=要删除的页面(输入一个用逗号分隔的页码列表): pageRemover.submit=删除页面 pageRemover.placeholder=(例如:1,2,6 或 1-10,15-30) #rotate -rotate.title=旋转PDF -rotate.header=旋转PDF -rotate.selectAngle=选择旋转角度(以90度的倍数): +rotate.title=旋转 PDF +rotate.header=旋转 PDF +rotate.selectAngle=选择旋转角度(以 90 度的倍数): rotate.submit=旋转 #split-pdfs -split.title=拆分PDF -split.header=拆分PDF +split.title=拆分 PDF +split.header=拆分 PDF split.desc.1=选择希望进行分割的页数 -split.desc.2=如选择1,3,7-9将把一个10页的文件分割成6个独立的PDF: -split.desc.3=文档 #1:第1页 -split.desc.4=文档 #2:第2页和第3页 -split.desc.5=文档 #3:第4页、第5页、第6页和第7页 -split.desc.6=文档 #4:第7页 -split.desc.7=文档 #5:第8页 -split.desc.8=文档 #6:第9页和第10页 +split.desc.2=如选择1,3,7-9将把一个 10 页的文件分割成6个独立的PDF: +split.desc.3=文档 #1:第 1 页 +split.desc.4=文档 #2:第 2 页和第 3 页 +split.desc.5=文档 #3:第 4 页、第 5 页、第 6 页和第 7 页 +split.desc.6=文档 #4:第 7 页 +split.desc.7=文档 #5:第 8 页 +split.desc.8=文档 #6:第 9 页和第 10 页 split.splitPages=输入要分割的页面: split.submit=拆分 #merge -imageToPDF.title=图片转PDF -imageToPDF.header=将图片转换为PDF +imageToPDF.title=图片转 PDF +imageToPDF.header=将图片转换为 PDF imageToPDF.submit=转换 imageToPDF.selectLabel=图片适应选项 imageToPDF.fillPage=填充页面 imageToPDF.fitDocumentToImage=适应图片大小 imageToPDF.maintainAspectRatio=保持纵横比例 -imageToPDF.selectText.2=自动旋转PDF +imageToPDF.selectText.2=自动旋转 PDF imageToPDF.selectText.3=多文件逻辑(仅在处理多个图像时启用) -imageToPDF.selectText.4=合并成一个PDF文件 -imageToPDF.selectText.5=转换为独立的PDF文件 +imageToPDF.selectText.4=合并成一个 PDF 文件 +imageToPDF.selectText.5=转换为独立的 PDF 文件 #pdfToImage -pdfToImage.title=PDF转图片 -pdfToImage.header=将PDF转换为图片 +pdfToImage.title=PDF 转图片 +pdfToImage.header=将 PDF 转换为图片 pdfToImage.selectText=图像格式 pdfToImage.singleOrMultiple=图像结果类型 pdfToImage.single=单张图片 @@ -1028,13 +1038,13 @@ pdfToImage.color=颜色 pdfToImage.grey=灰度 pdfToImage.blackwhite=黑白(可能会丢失数据!)。 pdfToImage.submit=转换 -pdfToImage.info=WebP转换需要安装Python +pdfToImage.info=WebP 转换需要安装 Python #addPassword addPassword.title=添加密码 addPassword.header=添加密码(加密)。 -addPassword.selectText.1=选择要加密的PDF。 +addPassword.selectText.1=选择要加密的 PDF。 addPassword.selectText.2=密码 addPassword.selectText.3=加密密钥长度 addPassword.selectText.4=值越高越强,但值越低兼容性越好。 @@ -1057,7 +1067,7 @@ addPassword.submit=加密 watermark.title=添加水印 watermark.header=添加水印 watermark.customColor=自定义文本颜色 -watermark.selectText.1=选择要添加水印的PDF: +watermark.selectText.1=选择要添加水印的 PDF: watermark.selectText.2=水印文本: watermark.selectText.3=字体大小: watermark.selectText.4=旋转(0-360): @@ -1066,7 +1076,7 @@ watermark.selectText.6=垂直间距(每个水印之间的垂直距离): watermark.selectText.7=透明度(0% - 100%): watermark.selectText.8=水印类型: watermark.selectText.9=水印图片: -watermark.selectText.10=将PDF转换为PDF-Image +watermark.selectText.10=将 PDF 转换为 PDF-Image watermark.submit=添加水印 watermark.type.1=文字 watermark.type.2=图片 @@ -1076,7 +1086,7 @@ watermark.type.2=图片 permissions.title=更改权限 permissions.header=改变权限 permissions.warning=警告,为了使这些权限不能被改变,建议通过添加密码页面设置密码。 -permissions.selectText.1=选择PDF来改变权限 +permissions.selectText.1=选择 PDF 来改变权限 permissions.selectText.2=要设置的权限 permissions.selectText.3=防止文件的拼接 permissions.selectText.4=防止内容提取 @@ -1092,7 +1102,7 @@ permissions.submit=改变 #remove password removePassword.title=删除密码 removePassword.header=移除密码(解密)。 -removePassword.selectText.1=选择要解密的PDF +removePassword.selectText.1=选择要解密的 PDF removePassword.selectText.2=密码 removePassword.submit=删除 @@ -1117,9 +1127,9 @@ changeMetadata.submit=更改 #pdfToPDFA -pdfToPDFA.title=PDF转PDF/A -pdfToPDFA.header=将PDF转换为PDF/A -pdfToPDFA.credit=此服务使用qpdf进行PDF/A转换 +pdfToPDFA.title=PDF 转 PDF/A +pdfToPDFA.header=将 PDF 转换为 PDF/A +pdfToPDFA.credit=此服务使用 qpdf 进行 PDF/A 转换 pdfToPDFA.submit=转换 pdfToPDFA.tip=目前不支持上传多个 pdfToPDFA.outputFormat=输出格式 @@ -1127,51 +1137,51 @@ pdfToPDFA.pdfWithDigitalSignature=该PDF包含数字签名,下一步将移除 #PDFToWord -PDFToWord.title=PDF转Word -PDFToWord.header=将PDF转换为Word +PDFToWord.title=PDF 转 Word +PDFToWord.header=将 PDF 转换为 Word PDFToWord.selectText.1=输出文件格式 -PDFToWord.credit=此服务使用LibreOffice进行文件转换。 +PDFToWord.credit=此服务使用 LibreOffice 进行文件转换。 PDFToWord.submit=转换 #PDFToPresentation -PDFToPresentation.title=PDF转演示文稿 -PDFToPresentation.header=将PDF转换为演示文稿 +PDFToPresentation.title=PDF 转演示文稿 +PDFToPresentation.header=将 PDF 转换为演示文稿 PDFToPresentation.selectText.1=输出文件格式 -PDFToPresentation.credit=此服务使用LibreOffice进行文件转换。 +PDFToPresentation.credit=此服务使用 LibreOffice 进行文件转换。 PDFToPresentation.submit=转换 #PDFToText -PDFToText.title=PDF转文本/RTF -PDFToText.header=将PDF转换为文本/RTF +PDFToText.title=PDF 转文本/RTF +PDFToText.header=将 PDF 转换为文本/RTF PDFToText.selectText.1=输出文件格式 -PDFToText.credit=此服务使用LibreOffice进行文件转换。 +PDFToText.credit=此服务使用 LibreOffice 进行文件转换。 PDFToText.submit=转换 #PDFToHTML -PDFToHTML.title=PDF转HTML -PDFToHTML.header=将PDF转换为HTML -PDFToHTML.credit=此服务使用pdftohtml进行文件转换。 +PDFToHTML.title=PDF 转 HTML +PDFToHTML.header=将 PDF 转换为 HTML +PDFToHTML.credit=此服务使用 pdftohtml 进行文件转换。 PDFToHTML.submit=转换 #PDFToXML -PDFToXML.title=PDF转XML -PDFToXML.header=将PDF转换为XML -PDFToXML.credit=此服务使用LibreOffice进行文件转换。 +PDFToXML.title=PDF 转 XML +PDFToXML.header=将 PDF 转换为 XML +PDFToXML.credit=此服务使用 LibreOffice 进行文件转换。 PDFToXML.submit=转换 #PDFToCSV -PDFToCSV.title=PDF转CSV -PDFToCSV.header=将PDF转换为CSV +PDFToCSV.title=PDF 转 CSV +PDFToCSV.header=将 PDF 转换为 CSV PDFToCSV.prompt=选择需要提取表格的页面 PDFToCSV.submit=提取 #split-by-size-or-count -split-by-size-or-count.title=按照大小或数目拆分PDF -split-by-size-or-count.header=按照大小或数目拆分PDF +split-by-size-or-count.title=按照大小或数目拆分 PDF +split-by-size-or-count.header=按照大小或数目拆分 PDF split-by-size-or-count.type.label=选择拆分类型 split-by-size-or-count.type.size=按照大小 split-by-size-or-count.type.pageCount=按照页数 @@ -1182,9 +1192,9 @@ split-by-size-or-count.submit=提交 #overlay-pdfs -overlay-pdfs.header=叠加PDF文件 -overlay-pdfs.baseFile.label=选择基础PDF文件 -overlay-pdfs.overlayFiles.label=选择需要叠加在基础上的PDF文件 +overlay-pdfs.header=叠加 PDF 文件 +overlay-pdfs.baseFile.label=选择基础 PDF 文件 +overlay-pdfs.overlayFiles.label=选择需要叠加在基础上的 PDF 文件 overlay-pdfs.mode.label=选择叠加模式 overlay-pdfs.mode.sequential=按顺序叠加 overlay-pdfs.mode.interleaved=交错叠加 @@ -1198,14 +1208,14 @@ overlay-pdfs.submit=提交 #split-by-sections -split-by-sections.title=按照块(Section)拆分PDF -split-by-sections.header=将PDF拆分成块 +split-by-sections.title=按照块(Section)拆分 PDF +split-by-sections.header=将 PDF 拆分成块 split-by-sections.horizontal.label=水平分割 split-by-sections.vertical.label=垂直分割 split-by-sections.horizontal.placeholder=输入水平分割数 split-by-sections.vertical.placeholder=输入垂直分割数 -split-by-sections.submit=分割PDF -split-by-sections.merge=是否合并为一个pdf +split-by-sections.submit=分割 PDF +split-by-sections.merge=是否合并为一个 pdf #printFile @@ -1225,11 +1235,11 @@ licenses.version=版本 licenses.license=许可证 #survey -survey.nav=调查 -survey.title=Stirling-PDF调查 -survey.description=Stirling-PDF没有跟踪器,所以我们希望听取用户的意见来改进Stirling-PDF! -survey.changes=Stirling-PDF has changed since the last survey! To find out more please check our blog post here: -survey.changes2=With these changes we are getting paid business support and funding +survey.nav=问卷调查 +survey.title=Stirling-PDF 问卷调查 +survey.description=Stirling-PDF 没有跟踪器,所以我们希望听取用户的意见来改进 Stirling-PDF! +survey.changes=自上次调查以来,Stirling-PDF 已经发生了变化!要了解更多信息,请在此处查看我们的博客文章: +survey.changes2=通过这些变化,我们得到了商业支持和资金援助。 survey.please=请考虑参加我们的调查! survey.disabled=(调查弹出窗口将在后续更新中被禁用,但可在页脚处查看) survey.button=参与调查 @@ -1239,11 +1249,11 @@ survey.dontShowAgain=不再显示 #error error.sorry=对此问题感到抱歉! error.needHelp=需要帮助 / 发现问题? -error.contactTip=如果你仍然遇到问题,不要犹豫,向我们寻求帮助。你可以在我们的GitHub页面上提交工单,或者通过Discord与我们联系: +error.contactTip=如果你仍然遇到问题,不要犹豫,向我们寻求帮助。你可以在我们的 GitHub 页面上提交工单,或者通过 Discord 与我们联系: error.404.head=404 - 页面未找到 | 哎呀,我们在代码中触发了错误! error.404.1=我们似乎找不到你寻找的页面。 error.404.2=出了些问题 -error.github=在GitHub上提交工单 +error.github=在 GitHub 上提交工单 error.showStack=显示堆栈跟踪 error.copyStack=复制堆栈跟踪 error.githubSubmit=GitHub - 提交工单 @@ -1257,29 +1267,29 @@ removeImage.removeImage=删除图像 removeImage.submit=删除图像 -splitByChapters.title=Split PDF by Chapters -splitByChapters.header=Split PDF by Chapters -splitByChapters.bookmarkLevel=Bookmark Level -splitByChapters.includeMetadata=Include Metadata -splitByChapters.allowDuplicates=Allow Duplicates +splitByChapters.title=按章节拆分 PDF +splitByChapters.header=按章节拆分 PDF +splitByChapters.bookmarkLevel=书签级别 +splitByChapters.includeMetadata=包含元数据 +splitByChapters.allowDuplicates=允许重复 splitByChapters.desc.1=This tool splits a PDF file into multiple PDFs based on its chapter structure. splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for splitting (0 for top-level, 1 for second-level, etc.). splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF. splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs. -splitByChapters.submit=Split PDF +splitByChapters.submit=拆分 PDF #File Chooser -fileChooser.click=Click -fileChooser.or=or -fileChooser.dragAndDrop=Drag & Drop -fileChooser.hoveredDragAndDrop=Drag & Drop file(s) here +fileChooser.click=单击 +fileChooser.or=或 +fileChooser.dragAndDrop=拖放文件 +fileChooser.hoveredDragAndDrop=拖放文件到此处 #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=版本 +releases.title=版本说明 +releases.header=版本说明 +releases.current.version=当前版本 +releases.note=版本说明仅提供英文版本 #Validate Signature validateSignature.title=Validate PDF Signatures diff --git a/src/main/resources/messages_zh_TW.properties b/src/main/resources/messages_zh_TW.properties index 478e6966c..6938f6837 100644 --- a/src/main/resources/messages_zh_TW.properties +++ b/src/main/resources/messages_zh_TW.properties @@ -965,6 +965,16 @@ multiTool.dragDropMessage=Page(s) Selected multiTool.undo=Undo multiTool.redo=Redo +#decrypt +decrypt.passwordPrompt=This file is password-protected. Please enter the password: +decrypt.cancelled=Operation cancelled for PDF: {0} +decrypt.noPassword=No password provided for encrypted PDF: {0} +decrypt.invalidPassword=Please try again with the correct password. +decrypt.invalidPasswordHeader=Incorrect password or unsupported encryption for PDF: {0} +decrypt.unexpectedError=There was an error processing the file. Please try again. +decrypt.serverError=Server error while decrypting: {0} +decrypt.success=File decrypted successfully. + #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/3rdPartyLicenses.json b/src/main/resources/static/3rdPartyLicenses.json index aa0e6e30e..682ba443f 100644 --- a/src/main/resources/static/3rdPartyLicenses.json +++ b/src/main/resources/static/3rdPartyLicenses.json @@ -172,6 +172,13 @@ "moduleLicense": "The Apache Software License, Version 2.0", "moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt" }, + { + "moduleName": "com.google.code.gson:gson", + "moduleUrl": "https://github.com/google/gson", + "moduleVersion": "2.11.0", + "moduleLicense": "Apache-2.0", + "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt" + }, { "moduleName": "com.google.errorprone:error_prone_annotations", "moduleUrl": "https://errorprone.info/error_prone_annotations", @@ -591,6 +598,34 @@ "moduleLicense": "GPL2 w/ CPE", "moduleLicenseUrl": "https://oss.oracle.com/licenses/CDDL+GPL-1.1" }, + { + "moduleName": "me.friwi:gluegen-rt", + "moduleUrl": "http://jogamp.org/gluegen/www/", + "moduleVersion": "v2.4.0-rc-20210111", + "moduleLicense": "BSD-4 License", + "moduleLicenseUrl": "http://www.spdx.org/licenses/BSD-4-Clause" + }, + { + "moduleName": "me.friwi:jcef-api", + "moduleUrl": "https://bitbucket.org/chromiumembedded/java-cef/", + "moduleVersion": "jcef-99c2f7a+cef-127.3.1+g6cbb30e+chromium-127.0.6533.100", + "moduleLicense": "BSD License", + "moduleLicenseUrl": "https://bitbucket.org/chromiumembedded/java-cef/src/master/LICENSE.txt" + }, + { + "moduleName": "me.friwi:jcefmaven", + "moduleUrl": "https://github.com/jcefmaven/jcefmaven/", + "moduleVersion": "127.3.1", + "moduleLicense": "Apache-2.0 License", + "moduleLicenseUrl": "https://github.com/jcefmaven/jcefmaven/blob/master/LICENSE" + }, + { + "moduleName": "me.friwi:jogl-all", + "moduleUrl": "http://jogamp.org/jogl/www/", + "moduleVersion": "v2.4.0-rc-20210111", + "moduleLicense": "Ubuntu Font Licence 1.0", + "moduleLicenseUrl": "http://font.ubuntu.com/ufl/ubuntu-font-licence-1.0.txt" + }, { "moduleName": "net.bytebuddy:byte-buddy", "moduleVersion": "1.15.10", @@ -631,6 +666,13 @@ "moduleLicense": "Apache License, Version 2.0", "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt" }, + { + "moduleName": "org.apache.commons:commons-compress", + "moduleUrl": "https://commons.apache.org/proper/commons-compress/", + "moduleVersion": "1.21", + "moduleLicense": "Apache License, Version 2.0", + "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt" + }, { "moduleName": "org.apache.commons:commons-csv", "moduleUrl": "https://commons.apache.org/proper/commons-csv/", @@ -1079,6 +1121,30 @@ "moduleLicense": "Eclipse Public License, Version 2.0", "moduleLicenseUrl": "https://github.com/locationtech/jts/blob/master/LICENSE_EPLv2.txt" }, + { + "moduleName": "org.openjfx:javafx-base", + "moduleVersion": "21", + "moduleLicense": "GPLv2+CE", + "moduleLicenseUrl": "https://openjdk.java.net/legal/gplv2+ce.html" + }, + { + "moduleName": "org.openjfx:javafx-controls", + "moduleVersion": "21", + "moduleLicense": "GPLv2+CE", + "moduleLicenseUrl": "https://openjdk.java.net/legal/gplv2+ce.html" + }, + { + "moduleName": "org.openjfx:javafx-graphics", + "moduleVersion": "21", + "moduleLicense": "GPLv2+CE", + "moduleLicenseUrl": "https://openjdk.java.net/legal/gplv2+ce.html" + }, + { + "moduleName": "org.openjfx:javafx-swing", + "moduleVersion": "21", + "moduleLicense": "GPLv2+CE", + "moduleLicenseUrl": "https://openjdk.java.net/legal/gplv2+ce.html" + }, { "moduleName": "org.opensaml:opensaml-core", "moduleVersion": "4.3.2", @@ -1479,7 +1545,7 @@ }, { "moduleName": "org.thymeleaf.extras:thymeleaf-extras-springsecurity5", - "moduleVersion": "3.1.2.RELEASE", + "moduleVersion": "3.1.3.RELEASE", "moduleLicense": "The Apache Software License, Version 2.0", "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt" }, @@ -1491,7 +1557,7 @@ }, { "moduleName": "org.thymeleaf:thymeleaf-spring5", - "moduleVersion": "3.1.2.RELEASE", + "moduleVersion": "3.1.3.RELEASE", "moduleLicense": "The Apache Software License, Version 2.0", "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt" }, diff --git a/src/main/resources/static/css/home.css b/src/main/resources/static/css/home.css index 8faa91638..301abe81b 100644 --- a/src/main/resources/static/css/home.css +++ b/src/main/resources/static/css/home.css @@ -65,6 +65,7 @@ overflow: hidden; margin: -20px; padding: 20px; + box-sizing:content-box; } .feature-group-container.animated-group { diff --git a/src/main/resources/static/js/DecryptFiles.js b/src/main/resources/static/js/DecryptFiles.js new file mode 100644 index 000000000..a06687b1d --- /dev/null +++ b/src/main/resources/static/js/DecryptFiles.js @@ -0,0 +1,131 @@ +export class DecryptFile { + async decryptFile(file, requiresPassword) { + try { + async function getCsrfToken() { + const cookieValue = document.cookie + .split('; ') + .find((row) => row.startsWith('XSRF-TOKEN=')) + ?.split('=')[1]; + + if (cookieValue) { + return cookieValue; + } + + const csrfElement = document.querySelector('input[name="_csrf"]'); + return csrfElement ? csrfElement.value : null; + } + const csrfToken = await getCsrfToken(); + const formData = new FormData(); + formData.append('fileInput', file); + if (requiresPassword) { + const password = prompt(`${window.decrypt.passwordPrompt}`); + + if (password === null) { + // User cancelled + console.error(`Password prompt cancelled for PDF: ${file.name}`); + return null; // No file to return + } + + if (!password) { + // No password provided + console.error(`No password provided for encrypted PDF: ${file.name}`); + this.showErrorBanner( + `${window.decrypt.noPassword.replace('{0}', file.name)}`, + '', + `${window.decrypt.unexpectedError}` + ); + return null; // No file to return + } + + formData.append('password', password); + } + // Send decryption request + const response = await fetch('/api/v1/security/remove-password', { + method: 'POST', + body: formData, + headers: csrfToken ? {'X-XSRF-TOKEN': csrfToken} : undefined, + }); + + if (response.ok) { + const decryptedBlob = await response.blob(); + this.removeErrorBanner(); + return new File([decryptedBlob], file.name, {type: 'application/pdf'}); + } else { + const errorText = await response.text(); + console.error(`${window.decrypt.invalidPassword} ${errorText}`); + this.showErrorBanner( + `${window.decrypt.invalidPassword}`, + errorText, + `${window.decrypt.invalidPasswordHeader.replace('{0}', file.name)}` + ); + return null; // No file to return + } + } catch (error) { + // Handle network or unexpected errors + console.error(`Failed to decrypt PDF: ${file.name}`, error); + this.showErrorBanner( + `${window.decrypt.unexpectedError.replace('{0}', file.name)}`, + `${error.message || window.decrypt.unexpectedError}`, + error + ); + return null; // No file to return + } + } + + async checkFileEncrypted(file) { + try { + if (file.type !== 'application/pdf') { + return {isEncrypted: false, requiresPassword: false}; + } + + pdfjsLib.GlobalWorkerOptions.workerSrc = './pdfjs-legacy/pdf.worker.mjs'; + const arrayBuffer = await file.arrayBuffer(); + const arrayBufferForPdfLib = arrayBuffer.slice(0); + + const loadingTask = pdfjsLib.getDocument({ + data: arrayBuffer, + }); + + await loadingTask.promise; + + try { + //Uses PDFLib.PDFDocument to check if unpassworded but encrypted + const pdfDoc = await PDFLib.PDFDocument.load(arrayBufferForPdfLib); + return {isEncrypted: false, requiresPassword: false}; + } catch (error) { + if (error.message.includes('Input document to `PDFDocument.load` is encrypted')) { + return {isEncrypted: true, requiresPassword: false}; + } + console.error('Error checking encryption:', error); + throw new Error('Failed to determine if the file is encrypted.'); + } + } catch (error) { + if (error.name === 'PasswordException') { + if (error.code === pdfjsLib.PasswordResponses.NEED_PASSWORD) { + return {isEncrypted: true, requiresPassword: true}; + } else if (error.code === pdfjsLib.PasswordResponses.INCORRECT_PASSWORD) { + return {isEncrypted: true, requiresPassword: false}; + } + } + + console.error('Error checking encryption:', error); + throw new Error('Failed to determine if the file is encrypted.'); + } + } + + showErrorBanner(message, stackTrace, error) { + const errorContainer = document.getElementById('errorContainer'); + errorContainer.style.display = 'block'; // Display the banner + errorContainer.querySelector('.alert-heading').textContent = error; + errorContainer.querySelector('p').textContent = message; + document.querySelector('#traceContent').textContent = stackTrace; + } + + removeErrorBanner() { + const errorContainer = document.getElementById('errorContainer'); + errorContainer.style.display = 'none'; // Hide the banner + errorContainer.querySelector('.alert-heading').textContent = ''; + errorContainer.querySelector('p').textContent = ''; + document.querySelector('#traceContent').textContent = ''; + } +} diff --git a/src/main/resources/static/js/download.js b/src/main/resources/static/js/download.js new file mode 100644 index 000000000..8eed99f9a --- /dev/null +++ b/src/main/resources/static/js/download.js @@ -0,0 +1,27 @@ +document.getElementById('download-pdf').addEventListener('click', async () => { + const modifiedPdf = await DraggableUtils.getOverlayedPdfDocument(); + let decryptedFile = modifiedPdf; + let isEncrypted = false; + let requiresPassword = false; + await this.decryptFile + .checkFileEncrypted(decryptedFile) + .then((result) => { + isEncrypted = result.isEncrypted; + requiresPassword = result.requiresPassword; + }) + .catch((error) => { + console.error(error); + }); + if (decryptedFile.type === 'application/pdf' && isEncrypted) { + decryptedFile = await this.decryptFile.decryptFile(decryptedFile, requiresPassword); + if (!decryptedFile) { + throw new Error('File decryption failed.'); + } + } + const modifiedPdfBytes = await modifiedPdf.save(); + const blob = new Blob([modifiedPdfBytes], {type: 'application/pdf'}); + const link = document.createElement('a'); + link.href = URL.createObjectURL(blob); + link.download = originalFileName + '_signed.pdf'; + link.click(); +}); diff --git a/src/main/resources/static/js/downloader.js b/src/main/resources/static/js/downloader.js index d7718f02f..57ae8c47b 100644 --- a/src/main/resources/static/js/downloader.js +++ b/src/main/resources/static/js/downloader.js @@ -42,7 +42,7 @@ event.preventDefault(); firstErrorOccurred = false; const url = this.action; - const files = $('#fileInput-input')[0].files; + let files = $('#fileInput-input')[0].files; const formData = new FormData(this); const submitButton = document.getElementById('submitBtn'); const showGameBtn = document.getElementById('show-game-btn'); @@ -71,6 +71,16 @@ }, 5000); try { + if (!url.includes('remove-password')) { + // Check if any PDF files are encrypted and handle decryption if necessary + const decryptedFiles = await checkAndDecryptFiles(url, files); + files = decryptedFiles; + // Append decrypted files to formData + decryptedFiles.forEach((file, index) => { + formData.set(`fileInput`, file); + }); + } + submitButton.textContent = 'Processing...'; submitButton.disabled = true; @@ -133,6 +143,98 @@ } } + async function checkAndDecryptFiles(url, files) { + const decryptedFiles = []; + pdfjsLib.GlobalWorkerOptions.workerSrc = './pdfjs-legacy/pdf.worker.mjs'; + + // Extract the base URL + const baseUrl = new URL(url); + let removePasswordUrl = `${baseUrl.origin}`; + + // Check if there's a path before /api/ + const apiIndex = baseUrl.pathname.indexOf('/api/'); + if (apiIndex > 0) { + removePasswordUrl += baseUrl.pathname.substring(0, apiIndex); + } + + // Append the new endpoint + removePasswordUrl += '/api/v1/security/remove-password'; + + console.log(`Remove password URL: ${removePasswordUrl}`); + + for (const file of files) { + console.log(`Processing file: ${file.name}`); + if (file.type !== 'application/pdf') { + console.log(`Skipping non-PDF file: ${file.name}`); + decryptedFiles.push(file); + continue; + } + try { + const arrayBuffer = await file.arrayBuffer(); + const loadingTask = pdfjsLib.getDocument({data: arrayBuffer}); + + console.log(`Attempting to load PDF: ${file.name}`); + const pdf = await loadingTask.promise; + console.log(`File is not encrypted: ${file.name}`); + decryptedFiles.push(file); // If no error, file is not encrypted + } catch (error) { + if (error.name === 'PasswordException' && error.code === 1) { + console.log(`PDF requires password: ${file.name}`, error); + console.log(`Attempting to remove password from PDF: ${file.name} with password.`); + const password = prompt(`${window.translations.decrypt.passwordPrompt}`); + + if (!password) { + console.error(`No password provided for encrypted PDF: ${file.name}`); + showErrorBanner( + `${window.translations.decrypt.noPassword.replace('{0}', file.name)}`, + `${window.translations.decrypt.unexpectedError}` + ); + throw error; + } + + try { + // Prepare FormData for the decryption request + const formData = new FormData(); + formData.append('fileInput', file); + formData.append('password', password); + + // Use handleSingleDownload to send the request + const decryptionResult = await fetch(removePasswordUrl, {method: 'POST', body: formData}); + + if (decryptionResult && decryptionResult.blob) { + const decryptedBlob = await decryptionResult.blob(); + const decryptedFile = new File([decryptedBlob], file.name, {type: 'application/pdf'}); + + /* // Create a link element to download the file + const link = document.createElement('a'); + link.href = URL.createObjectURL(decryptedBlob); + link.download = 'test.pdf'; + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); +*/ + decryptedFiles.push(decryptedFile); + console.log(`Successfully decrypted PDF: ${file.name}`); + } else { + throw new Error('Decryption failed: No valid response from server'); + } + } catch (decryptError) { + console.error(`Failed to decrypt PDF: ${file.name}`, decryptError); + showErrorBanner( + `${window.translations.invalidPasswordHeader.replace('{0}', file.name)}`, + `${window.translations.invalidPassword}` + ); + throw decryptError; + } + } else { + console.log(`Error loading PDF: ${file.name}`, error); + throw error; + } + } + } + return decryptedFiles; + } + async function handleSingleDownload(url, formData, isMulti = false, isZip = false) { const startTime = performance.now(); const file = formData.get('fileInput'); diff --git a/src/main/resources/static/js/draggable-utils.js b/src/main/resources/static/js/draggable-utils.js index bdd75a44a..aa0c15a03 100644 --- a/src/main/resources/static/js/draggable-utils.js +++ b/src/main/resources/static/js/draggable-utils.js @@ -1,6 +1,6 @@ const DraggableUtils = { - boxDragContainer: document.getElementById("box-drag-container"), - pdfCanvas: document.getElementById("pdf-canvas"), + boxDragContainer: document.getElementById('box-drag-container'), + pdfCanvas: document.getElementById('pdf-canvas'), nextId: 0, pdfDoc: null, pageIndex: 0, @@ -9,19 +9,17 @@ const DraggableUtils = { lastInteracted: null, init() { - interact(".draggable-canvas") + interact('.draggable-canvas') .draggable({ listeners: { move: (event) => { const target = event.target; - const x = (parseFloat(target.getAttribute("data-bs-x")) || 0) - + event.dx; - const y = (parseFloat(target.getAttribute("data-bs-y")) || 0) - + event.dy; + const x = (parseFloat(target.getAttribute('data-bs-x')) || 0) + event.dx; + const y = (parseFloat(target.getAttribute('data-bs-y')) || 0) + event.dy; target.style.transform = `translate(${x}px, ${y}px)`; - target.setAttribute("data-bs-x", x); - target.setAttribute("data-bs-y", y); + target.setAttribute('data-bs-x', x); + target.setAttribute('data-bs-y', y); this.onInteraction(target); //update the last interacted element @@ -30,12 +28,12 @@ const DraggableUtils = { }, }) .resizable({ - edges: { left: true, right: true, bottom: true, top: true }, + edges: {left: true, right: true, bottom: true, top: true}, listeners: { move: (event) => { var target = event.target; - var x = parseFloat(target.getAttribute("data-bs-x")) || 0; - var y = parseFloat(target.getAttribute("data-bs-y")) || 0; + var x = parseFloat(target.getAttribute('data-bs-x')) || 0; + var y = parseFloat(target.getAttribute('data-bs-y')) || 0; // check if control key is pressed if (event.ctrlKey) { @@ -44,8 +42,7 @@ const DraggableUtils = { let width = event.rect.width; let height = event.rect.height; - if (Math.abs(event.deltaRect.width) >= Math.abs( - event.deltaRect.height)) { + if (Math.abs(event.deltaRect.width) >= Math.abs(event.deltaRect.height)) { height = width / aspectRatio; } else { width = height * aspectRatio; @@ -55,19 +52,18 @@ const DraggableUtils = { event.rect.height = height; } - target.style.width = event.rect.width + "px"; - target.style.height = event.rect.height + "px"; + target.style.width = event.rect.width + 'px'; + target.style.height = event.rect.height + 'px'; // translate when resizing from top or left edges x += event.deltaRect.left; y += event.deltaRect.top; - target.style.transform = "translate(" + x + "px," + y + "px)"; + target.style.transform = 'translate(' + x + 'px,' + y + 'px)'; - target.setAttribute("data-bs-x", x); - target.setAttribute("data-bs-y", y); - target.textContent = Math.round(event.rect.width) + "\u00D7" - + Math.round(event.rect.height); + target.setAttribute('data-bs-x', x); + target.setAttribute('data-bs-y', y); + target.textContent = Math.round(event.rect.width) + '\u00D7' + Math.round(event.rect.height); this.onInteraction(target); }, @@ -75,7 +71,7 @@ const DraggableUtils = { modifiers: [ interact.modifiers.restrictSize({ - min: { width: 5, height: 5 }, + min: {width: 5, height: 5}, }), ], inertia: true, @@ -95,8 +91,8 @@ const DraggableUtils = { const stepY = target.offsetHeight * 0.05; // Get the current x and y coordinates - let x = (parseFloat(target.getAttribute('data-bs-x')) || 0); - let y = (parseFloat(target.getAttribute('data-bs-y')) || 0); + let x = parseFloat(target.getAttribute('data-bs-x')) || 0; + let y = parseFloat(target.getAttribute('data-bs-y')) || 0; // Check which key was pressed and update the coordinates accordingly switch (event.key) { @@ -135,15 +131,15 @@ const DraggableUtils = { }, createDraggableCanvas() { - const createdCanvas = document.createElement("canvas"); + const createdCanvas = document.createElement('canvas'); createdCanvas.id = `draggable-canvas-${this.nextId++}`; - createdCanvas.classList.add("draggable-canvas"); + createdCanvas.classList.add('draggable-canvas'); const x = 0; const y = 20; createdCanvas.style.transform = `translate(${x}px, ${y}px)`; - createdCanvas.setAttribute("data-bs-x", x); - createdCanvas.setAttribute("data-bs-y", y); + createdCanvas.setAttribute('data-bs-x', x); + createdCanvas.setAttribute('data-bs-y', y); //Click element in order to enable arrow keys createdCanvas.addEventListener('click', () => { @@ -186,29 +182,29 @@ const DraggableUtils = { newHeight = newHeight * scaleMultiplier; } - createdCanvas.style.width = newWidth + "px"; - createdCanvas.style.height = newHeight + "px"; + createdCanvas.style.width = newWidth + 'px'; + createdCanvas.style.height = newHeight + 'px'; - var myContext = createdCanvas.getContext("2d"); + var myContext = createdCanvas.getContext('2d'); myContext.drawImage(myImage, 0, 0); resolve(createdCanvas); }; }); }, deleteAllDraggableCanvases() { - this.boxDragContainer.querySelectorAll(".draggable-canvas").forEach((el) => el.remove()); + this.boxDragContainer.querySelectorAll('.draggable-canvas').forEach((el) => el.remove()); }, async addAllPagesDraggableCanvas(element) { if (element) { - let currentPage = this.pageIndex + let currentPage = this.pageIndex; if (!this.elementAllPages.includes(element)) { - this.elementAllPages.push(element) + this.elementAllPages.push(element); element.style.filter = 'sepia(1) hue-rotate(90deg) brightness(1.2)'; let newElement = { - "element": element, - "offsetWidth": element.width, - "offsetHeight": element.height - } + element: element, + offsetWidth: element.width, + offsetHeight: element.height, + }; let pagesMap = this.documentsMap.get(this.pdfDoc); @@ -216,21 +212,20 @@ const DraggableUtils = { pagesMap = {}; this.documentsMap.set(this.pdfDoc, pagesMap); } - let page = this.pageIndex + let page = this.pageIndex; for (let pageIndex = 0; pageIndex < this.pdfDoc.numPages; pageIndex++) { - if (pagesMap[`${pageIndex}-offsetWidth`]) { if (!pagesMap[pageIndex].includes(newElement)) { pagesMap[pageIndex].push(newElement); } } else { - pagesMap[pageIndex] = [] - pagesMap[pageIndex].push(newElement) + pagesMap[pageIndex] = []; + pagesMap[pageIndex].push(newElement); pagesMap[`${pageIndex}-offsetWidth`] = pagesMap[`${page}-offsetWidth`]; pagesMap[`${pageIndex}-offsetHeight`] = pagesMap[`${page}-offsetHeight`]; } - await this.goToPage(pageIndex) + await this.goToPage(pageIndex); } } else { const index = this.elementAllPages.indexOf(element); @@ -247,17 +242,17 @@ const DraggableUtils = { for (let pageIndex = 0; pageIndex < this.pdfDoc.numPages; pageIndex++) { if (pagesMap[`${pageIndex}-offsetWidth`] && pageIndex != currentPage) { const pageElements = pagesMap[pageIndex]; - pageElements.forEach(elementPage => { - const elementIndex = pageElements.findIndex(elementPage => elementPage['element'].id === element.id); + pageElements.forEach((elementPage) => { + const elementIndex = pageElements.findIndex((elementPage) => elementPage['element'].id === element.id); if (elementIndex !== -1) { pageElements.splice(elementIndex, 1); } }); } - await this.goToPage(pageIndex) + await this.goToPage(pageIndex); } } - await this.goToPage(currentPage) + await this.goToPage(currentPage); } }, deleteDraggableCanvas(element) { @@ -271,7 +266,7 @@ const DraggableUtils = { } }, getLastInteracted() { - return this.boxDragContainer.querySelector(".draggable-canvas:last-of-type"); + return this.boxDragContainer.querySelector('.draggable-canvas:last-of-type'); }, storePageContents() { @@ -280,7 +275,7 @@ const DraggableUtils = { pagesMap = {}; } - const elements = [...this.boxDragContainer.querySelectorAll(".draggable-canvas")]; + const elements = [...this.boxDragContainer.querySelectorAll('.draggable-canvas')]; const draggablesData = elements.map((el) => { return { element: el, @@ -291,8 +286,8 @@ const DraggableUtils = { elements.forEach((el) => this.boxDragContainer.removeChild(el)); pagesMap[this.pageIndex] = draggablesData; - pagesMap[this.pageIndex + "-offsetWidth"] = this.pdfCanvas.offsetWidth; - pagesMap[this.pageIndex + "-offsetHeight"] = this.pdfCanvas.offsetHeight; + pagesMap[this.pageIndex + '-offsetWidth'] = this.pdfCanvas.offsetWidth; + pagesMap[this.pageIndex + '-offsetHeight'] = this.pdfCanvas.offsetHeight; this.documentsMap.set(this.pdfDoc, pagesMap); }, @@ -329,8 +324,8 @@ const DraggableUtils = { // render the page onto the canvas var renderContext = { - canvasContext: this.pdfCanvas.getContext("2d"), - viewport: page.getViewport({ scale: 1 }), + canvasContext: this.pdfCanvas.getContext('2d'), + viewport: page.getViewport({scale: 1}), }; await page.render(renderContext).promise; @@ -358,7 +353,7 @@ const DraggableUtils = { } }, - parseTransform(element) { }, + parseTransform(element) {}, async getOverlayedPdfDocument() { const pdfBytes = await this.pdfDoc.getData(); const pdfDocModified = await PDFLib.PDFDocument.load(pdfBytes, { @@ -369,7 +364,7 @@ const DraggableUtils = { const pagesMap = this.documentsMap.get(this.pdfDoc); for (let pageIdx in pagesMap) { - if (pageIdx.includes("offset")) { + if (pageIdx.includes('offset')) { continue; } console.log(typeof pageIdx); @@ -377,9 +372,8 @@ const DraggableUtils = { const page = pdfDocModified.getPage(parseInt(pageIdx)); let draggablesData = pagesMap[pageIdx]; - const offsetWidth = pagesMap[pageIdx + "-offsetWidth"]; - const offsetHeight = pagesMap[pageIdx + "-offsetHeight"]; - + const offsetWidth = pagesMap[pageIdx + '-offsetWidth']; + const offsetHeight = pagesMap[pageIdx + '-offsetHeight']; for (const draggableData of draggablesData) { // embed the draggable canvas @@ -389,8 +383,8 @@ const DraggableUtils = { const pdfImageObject = await pdfDocModified.embedPng(draggableImgBytes); // calculate the position in the pdf document - const tansform = draggableElement.style.transform.replace(/[^.,-\d]/g, ""); - const transformComponents = tansform.split(","); + const tansform = draggableElement.style.transform.replace(/[^.,-\d]/g, ''); + const transformComponents = tansform.split(','); const draggablePositionPixels = { x: parseFloat(transformComponents[0]), y: parseFloat(transformComponents[1]), @@ -429,9 +423,8 @@ const DraggableUtils = { }; //Defining the image if the page has a 0-degree angle - let x = draggablePositionPdf.x - let y = heightAdjusted - draggablePositionPdf.y - draggablePositionPdf.height - + let x = draggablePositionPdf.x; + let y = heightAdjusted - draggablePositionPdf.y - draggablePositionPdf.height; //Defining the image position if it is at other angles if (normalizedAngle === 90) { @@ -451,7 +444,7 @@ const DraggableUtils = { y: y, width: draggablePositionPdf.width, height: draggablePositionPdf.height, - rotate: rotation + rotate: rotation, }); } } @@ -460,6 +453,6 @@ const DraggableUtils = { }, }; -document.addEventListener("DOMContentLoaded", () => { +document.addEventListener('DOMContentLoaded', () => { DraggableUtils.init(); }); diff --git a/src/main/resources/static/js/fileInput.js b/src/main/resources/static/js/fileInput.js index e288f5b84..63485c606 100644 --- a/src/main/resources/static/js/fileInput.js +++ b/src/main/resources/static/js/fileInput.js @@ -1,20 +1,19 @@ -import FileIconFactory from "./file-icon-factory.js"; -import FileUtils from "./file-utils.js"; +import FileIconFactory from './file-icon-factory.js'; +import FileUtils from './file-utils.js'; import UUID from './uuid.js'; - +import {DecryptFile} from './DecryptFiles.js'; let isScriptExecuted = false; if (!isScriptExecuted) { isScriptExecuted = true; - document.addEventListener("DOMContentLoaded", function () { - document.querySelectorAll(".custom-file-chooser").forEach(setupFileInput); + document.addEventListener('DOMContentLoaded', function () { + document.querySelectorAll('.custom-file-chooser').forEach(setupFileInput); }); } - function setupFileInput(chooser) { - const elementId = chooser.getAttribute("data-bs-element-id"); - const filesSelected = chooser.getAttribute("data-bs-files-selected"); - const pdfPrompt = chooser.getAttribute("data-bs-pdf-prompt"); + const elementId = chooser.getAttribute('data-bs-element-id'); + const filesSelected = chooser.getAttribute('data-bs-files-selected'); + const pdfPrompt = chooser.getAttribute('data-bs-pdf-prompt'); const inputContainerId = chooser.getAttribute('data-bs-element-container-id'); let inputContainer = document.getElementById(inputContainerId); @@ -26,7 +25,7 @@ function setupFileInput(chooser) { inputContainer.addEventListener('click', (e) => { let inputBtn = document.getElementById(elementId); inputBtn.click(); - }) + }); const dragenterListener = function () { dragCounter++; @@ -63,7 +62,7 @@ function setupFileInput(chooser) { const files = dt.files; const fileInput = document.getElementById(elementId); - if (fileInput?.hasAttribute("multiple")) { + if (fileInput?.hasAttribute('multiple')) { pushFileListTo(files, allFiles); } else if (fileInput) { allFiles = [files[0]]; @@ -78,7 +77,7 @@ function setupFileInput(chooser) { dragCounter = 0; - fileInput.dispatchEvent(new CustomEvent("change", { bubbles: true, detail: {source: 'drag-drop'} })); + fileInput.dispatchEvent(new CustomEvent('change', {bubbles: true, detail: {source: 'drag-drop'}})); }; function pushFileListTo(fileList, container) { @@ -87,7 +86,7 @@ function setupFileInput(chooser) { } } - ["dragenter", "dragover", "dragleave", "drop"].forEach((eventName) => { + ['dragenter', 'dragover', 'dragleave', 'drop'].forEach((eventName) => { document.body.addEventListener(eventName, preventDefaults, false); }); @@ -96,37 +95,50 @@ function setupFileInput(chooser) { e.stopPropagation(); } - document.body.addEventListener("dragenter", dragenterListener); - document.body.addEventListener("dragleave", dragleaveListener); - document.body.addEventListener("drop", dropListener); + document.body.addEventListener('dragenter', dragenterListener); + document.body.addEventListener('dragleave', dragleaveListener); + document.body.addEventListener('drop', dropListener); - $("#" + elementId).on("change", function (e) { + $('#' + elementId).on('change', async function (e) { let element = e.target; const isDragAndDrop = e.detail?.source == 'drag-drop'; - if (element instanceof HTMLInputElement && element.hasAttribute("multiple")) { - allFiles = isDragAndDrop ? allFiles : [... allFiles, ... element.files]; + if (element instanceof HTMLInputElement && element.hasAttribute('multiple')) { + allFiles = isDragAndDrop ? allFiles : [...allFiles, ...element.files]; } else { allFiles = Array.from(isDragAndDrop ? allFiles : [element.files[0]]); } - - allFiles = allFiles.map(file => { - if (!file.uniqueId) file.uniqueId = UUID.uuidv4(); - return file; - }); - + allFiles = await Promise.all( + allFiles.map(async (file) => { + let decryptedFile = file; + try { + const decryptFile = new DecryptFile(); + const {isEncrypted, requiresPassword} = await decryptFile.checkFileEncrypted(file); + if (file.type === 'application/pdf' && isEncrypted) { + decryptedFile = await decryptFile.decryptFile(file, requiresPassword); + if (!decryptedFile) throw new Error('File decryption failed.'); + } + decryptedFile.uniqueId = UUID.uuidv4(); + return decryptedFile; + } catch (error) { + console.error(`Error decrypting file: ${file.name}`, error); + if (!file.uniqueId) file.uniqueId = UUID.uuidv4(); + return file; + } + }) + ); if (!isDragAndDrop) { - let dataTransfer = toDataTransfer(allFiles); - element.files = dataTransfer.files; + let dataTransfer = toDataTransfer(allFiles); + element.files = dataTransfer.files; } handleFileInputChange(this); - this.dispatchEvent(new CustomEvent("file-input-change", { bubbles: true })); -}); + this.dispatchEvent(new CustomEvent('file-input-change', {bubbles: true, detail: {elementId, allFiles}})); + }); function toDataTransfer(files) { let dataTransfer = new DataTransfer(); - files.forEach(file => dataTransfer.items.add(file)); + files.forEach((file) => dataTransfer.items.add(file)); return dataTransfer; } @@ -136,7 +148,7 @@ function setupFileInput(chooser) { const filesInfo = files.map((f) => ({name: f.name, size: f.size, uniqueId: f.uniqueId})); - const selectedFilesContainer = $(inputContainer).siblings(".selected-files"); + const selectedFilesContainer = $(inputContainer).siblings('.selected-files'); selectedFilesContainer.empty(); filesInfo.forEach((info) => { let fileContainerClasses = 'small-file-container d-flex flex-column justify-content-center align-items-center'; @@ -167,28 +179,26 @@ function setupFileInput(chooser) { } function showOrHideSelectedFilesContainer(files) { - if (files && files.length > 0) - chooser.style.setProperty('--selected-files-display', 'flex'); - else - chooser.style.setProperty('--selected-files-display', 'none'); + if (files && files.length > 0) chooser.style.setProperty('--selected-files-display', 'flex'); + else chooser.style.setProperty('--selected-files-display', 'none'); } function removeFileListener(e) { - const fileId = (e.target).getAttribute('data-file-id'); + const fileId = e.target.getAttribute('data-file-id'); let inputElement = document.getElementById(elementId); removeFileById(fileId, inputElement); showOrHideSelectedFilesContainer(allFiles); - inputElement.dispatchEvent(new CustomEvent("file-input-change", { bubbles: true })); + inputElement.dispatchEvent(new CustomEvent('file-input-change', {bubbles: true})); } function removeFileById(fileId, inputElement) { let fileContainer = document.getElementById(fileId); fileContainer.remove(); - allFiles = allFiles.filter(v => v.uniqueId != fileId); + allFiles = allFiles.filter((v) => v.uniqueId != fileId); let dataTransfer = toDataTransfer(allFiles); if (inputElement) inputElement.files = dataTransfer.files; @@ -207,23 +217,19 @@ function setupFileInput(chooser) { } function createFileInfoContainer(info) { - let fileInfoContainer = document.createElement("div"); + let fileInfoContainer = document.createElement('div'); let fileInfoContainerClasses = 'file-info d-flex flex-column align-items-center justify-content-center'; $(fileInfoContainer).addClass(fileInfoContainerClasses); - $(fileInfoContainer).append( - `
${info.name}
` - ); + $(fileInfoContainer).append(`
${info.name}
`); let fileSizeWithUnits = FileUtils.transformFileSize(info.size); - $(fileInfoContainer).append( - `
${fileSizeWithUnits}
` - ); + $(fileInfoContainer).append(`
${fileSizeWithUnits}
`); return fileInfoContainer; } //Listen for event of file being removed and the filter it out of the allFiles array - document.addEventListener("fileRemoved", function (e) { + document.addEventListener('fileRemoved', function (e) { const fileId = e.detail; let inputElement = document.getElementById(elementId); removeFileById(fileId, inputElement); diff --git a/src/main/resources/static/js/homecard.js b/src/main/resources/static/js/homecard.js index 6dddfa2bc..9b5297f3c 100644 --- a/src/main/resources/static/js/homecard.js +++ b/src/main/resources/static/js/homecard.js @@ -268,7 +268,7 @@ document.addEventListener("DOMContentLoaded", function () { const parent = header.parentNode; const container = header.parentNode.querySelector(".feature-group-container"); if (parent.id !== "groupFavorites") { - container.style.maxHeight = container.clientHeight + "px"; + container.style.maxHeight = container.scrollHeight + "px"; } header.onclick = () => { expandCollapseToggle(parent); diff --git a/src/main/resources/static/js/multitool/PdfContainer.js b/src/main/resources/static/js/multitool/PdfContainer.js index 4eaf43f14..c060203d1 100644 --- a/src/main/resources/static/js/multitool/PdfContainer.js +++ b/src/main/resources/static/js/multitool/PdfContainer.js @@ -5,6 +5,7 @@ import {SplitAllCommand} from './commands/split.js'; import {UndoManager} from './UndoManager.js'; import {PageBreakCommand} from './commands/page-break.js'; import {AddFilesCommand} from './commands/add-page.js'; +import {DecryptFile} from '../DecryptFiles.js'; class PdfContainer { fileName; @@ -40,6 +41,8 @@ class PdfContainer { this.removeAllElements = this.removeAllElements.bind(this); this.resetPages = this.resetPages.bind(this); + this.decryptFile = new DecryptFile(); + this.undoManager = undoManager || new UndoManager(); this.pdfAdapters = pdfAdapters; @@ -165,7 +168,6 @@ class PdfContainer { input.click(); }); } - async addFilesFromFiles(files, nextSiblingElement, pages) { this.fileName = files[0].name; for (var i = 0; i < files.length; i++) { @@ -173,17 +175,37 @@ class PdfContainer { let processingTime, errorMessage = null, pageCount = 0; + try { - const file = files[i]; - if (file.type === 'application/pdf') { - const {renderer, pdfDocument} = await this.loadFile(file); + let decryptedFile = files[i]; + let isEncrypted = false; + let requiresPassword = false; + await this.decryptFile + .checkFileEncrypted(decryptedFile) + .then((result) => { + isEncrypted = result.isEncrypted; + requiresPassword = result.requiresPassword; + }) + .catch((error) => { + console.error(error); + }); + if (decryptedFile.type === 'application/pdf' && isEncrypted) { + decryptedFile = await this.decryptFile.decryptFile(decryptedFile, requiresPassword); + if (!decryptedFile) { + throw new Error('File decryption failed.'); + } + } + + if (decryptedFile.type === 'application/pdf') { + const {renderer, pdfDocument} = await this.loadFile(decryptedFile); pageCount = renderer.pageCount || 0; pages = await this.addPdfFile(renderer, pdfDocument, nextSiblingElement, pages); - } else if (file.type.startsWith('image/')) { - pages = await this.addImageFile(file, nextSiblingElement, pages); + } else if (decryptedFile.type.startsWith('image/')) { + pages = await this.addImageFile(decryptedFile, nextSiblingElement, pages); } + processingTime = Date.now() - startTime; - this.captureFileProcessingEvent(true, file, processingTime, null, pageCount); + this.captureFileProcessingEvent(true, decryptedFile, processingTime, null, pageCount); } catch (error) { processingTime = Date.now() - startTime; errorMessage = error.message || 'Unknown error'; @@ -194,6 +216,7 @@ class PdfContainer { document.querySelectorAll('.enable-on-file').forEach((element) => { element.disabled = false; }); + return pages; } diff --git a/src/main/resources/static/js/pages/add-image.js b/src/main/resources/static/js/pages/add-image.js new file mode 100644 index 000000000..5899b53f9 --- /dev/null +++ b/src/main/resources/static/js/pages/add-image.js @@ -0,0 +1,47 @@ +document.getElementById('download-pdf').addEventListener('click', async () => { + const modifiedPdf = await DraggableUtils.getOverlayedPdfDocument(); + const modifiedPdfBytes = await modifiedPdf.save(); + const blob = new Blob([modifiedPdfBytes], {type: 'application/pdf'}); + const link = document.createElement('a'); + link.href = URL.createObjectURL(blob); + link.download = originalFileName + '_addedImage.pdf'; + link.click(); +}); +let originalFileName = ''; +document.querySelector('input[name=pdf-upload]').addEventListener('change', async (event) => { + const fileInput = event.target; + fileInput.addEventListener('file-input-change', async (e) => { + const {allFiles} = e.detail; + if (allFiles && allFiles.length > 0) { + const file = allFiles[0]; + originalFileName = file.name.replace(/\.[^/.]+$/, ''); + const pdfData = await file.arrayBuffer(); + pdfjsLib.GlobalWorkerOptions.workerSrc = './pdfjs-legacy/pdf.worker.mjs'; + const pdfDoc = await pdfjsLib.getDocument({data: pdfData}).promise; + await DraggableUtils.renderPage(pdfDoc, 0); + + document.querySelectorAll('.show-on-file-selected').forEach((el) => { + el.style.cssText = ''; + }); + } + }); +}); +document.addEventListener('DOMContentLoaded', () => { + document.querySelectorAll('.show-on-file-selected').forEach((el) => { + el.style.cssText = 'display:none !important'; + }); +}); + +const imageUpload = document.querySelector('input[name=image-upload]'); +imageUpload.addEventListener('change', (e) => { + if (!e.target.files) { + return; + } + for (const imageFile of e.target.files) { + var reader = new FileReader(); + reader.readAsDataURL(imageFile); + reader.onloadend = function (e) { + DraggableUtils.createDraggableCanvasFromUrl(e.target.result); + }; + } +}); diff --git a/src/main/resources/static/js/pages/adjust-contrast.js b/src/main/resources/static/js/pages/adjust-contrast.js new file mode 100644 index 000000000..792c06669 --- /dev/null +++ b/src/main/resources/static/js/pages/adjust-contrast.js @@ -0,0 +1,253 @@ +var canvas = document.getElementById('contrast-pdf-canvas'); +var context = canvas.getContext('2d'); +var originalImageData = null; +var allPages = []; +var pdfDoc = null; +var pdf = null; // This is the current PDF document + +async function renderPDFAndSaveOriginalImageData(file) { + var fileReader = new FileReader(); + fileReader.onload = async function () { + var data = new Uint8Array(this.result); + pdfjsLib.GlobalWorkerOptions.workerSrc = './pdfjs-legacy/pdf.worker.mjs'; + pdf = await pdfjsLib.getDocument({data: data}).promise; + + // Get the number of pages in the PDF + var numPages = pdf.numPages; + allPages = Array.from({length: numPages}, (_, i) => i + 1); + + // Create a new PDF document + pdfDoc = await PDFLib.PDFDocument.create(); + // Render the first page in the viewer + await renderPageAndAdjustImageProperties(1); + document.getElementById('sliders-container').style.display = 'block'; + }; + fileReader.readAsArrayBuffer(file); +} + +// This function is now async and returns a promise +function renderPageAndAdjustImageProperties(pageNum) { + return new Promise(async function (resolve, reject) { + var page = await pdf.getPage(pageNum); + var scale = 1.5; + var viewport = page.getViewport({scale: scale}); + + canvas.height = viewport.height; + canvas.width = viewport.width; + + var renderContext = { + canvasContext: context, + viewport: viewport, + }; + + var renderTask = page.render(renderContext); + renderTask.promise.then(function () { + originalImageData = context.getImageData(0, 0, canvas.width, canvas.height); + adjustImageProperties(); + resolve(); + }); + canvas.classList.add('fixed-shadow-canvas'); + }); +} + +function adjustImageProperties() { + var contrast = parseFloat(document.getElementById('contrast-slider').value); + var brightness = parseFloat(document.getElementById('brightness-slider').value); + var saturation = parseFloat(document.getElementById('saturation-slider').value); + + contrast /= 100; // normalize to range [0, 2] + brightness /= 100; // normalize to range [0, 2] + saturation /= 100; // normalize to range [0, 2] + + if (originalImageData) { + var newImageData = context.createImageData(originalImageData.width, originalImageData.height); + newImageData.data.set(originalImageData.data); + + for (var i = 0; i < newImageData.data.length; i += 4) { + var r = newImageData.data[i]; + var g = newImageData.data[i + 1]; + var b = newImageData.data[i + 2]; + // Adjust contrast + r = adjustContrastForPixel(r, contrast); + g = adjustContrastForPixel(g, contrast); + b = adjustContrastForPixel(b, contrast); + // Adjust brightness + r = adjustBrightnessForPixel(r, brightness); + g = adjustBrightnessForPixel(g, brightness); + b = adjustBrightnessForPixel(b, brightness); + // Adjust saturation + var rgb = adjustSaturationForPixel(r, g, b, saturation); + newImageData.data[i] = rgb[0]; + newImageData.data[i + 1] = rgb[1]; + newImageData.data[i + 2] = rgb[2]; + } + context.putImageData(newImageData, 0, 0); + } +} + +function rgbToHsl(r, g, b) { + (r /= 255), (g /= 255), (b /= 255); + + var max = Math.max(r, g, b), + min = Math.min(r, g, b); + var h, + s, + l = (max + min) / 2; + + if (max === min) { + h = s = 0; // achromatic + } else { + var d = max - min; + s = l > 0.5 ? d / (2 - max - min) : d / (max + min); + + switch (max) { + case r: + h = (g - b) / d + (g < b ? 6 : 0); + break; + case g: + h = (b - r) / d + 2; + break; + case b: + h = (r - g) / d + 4; + break; + } + + h /= 6; + } + + return [h, s, l]; +} + +function hslToRgb(h, s, l) { + var r, g, b; + + if (s === 0) { + r = g = b = l; // achromatic + } else { + var hue2rgb = function hue2rgb(p, q, t) { + if (t < 0) t += 1; + if (t > 1) t -= 1; + if (t < 1 / 6) return p + (q - p) * 6 * t; + if (t < 1 / 2) return q; + if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6; + return p; + }; + + var q = l < 0.5 ? l * (1 + s) : l + s - l * s; + var p = 2 * l - q; + + r = hue2rgb(p, q, h + 1 / 3); + g = hue2rgb(p, q, h); + b = hue2rgb(p, q, h - 1 / 3); + } + + return [r * 255, g * 255, b * 255]; +} + +function adjustContrastForPixel(pixel, contrast) { + // Normalize to range [-0.5, 0.5] + var normalized = pixel / 255 - 0.5; + + // Apply contrast + normalized *= contrast; + + // Denormalize back to [0, 255] + return (normalized + 0.5) * 255; +} + +function clamp(value, min, max) { + return Math.min(Math.max(value, min), max); +} + +function adjustSaturationForPixel(r, g, b, saturation) { + var hsl = rgbToHsl(r, g, b); + + // Adjust saturation + hsl[1] = clamp(hsl[1] * saturation, 0, 1); + + // Convert back to RGB + var rgb = hslToRgb(hsl[0], hsl[1], hsl[2]); + + // Return adjusted RGB values + return rgb; +} + +function adjustBrightnessForPixel(pixel, brightness) { + return Math.max(0, Math.min(255, pixel * brightness)); +} +let inputFileName = ''; +async function downloadPDF() { + for (var i = 0; i < allPages.length; i++) { + await renderPageAndAdjustImageProperties(allPages[i]); + const pngImageBytes = canvas.toDataURL('image/png'); + const pngImage = await pdfDoc.embedPng(pngImageBytes); + const pngDims = pngImage.scale(1); + + // Create a blank page matching the dimensions of the image + const page = pdfDoc.addPage([pngDims.width, pngDims.height]); + + // Draw the PNG image + page.drawImage(pngImage, { + x: 0, + y: 0, + width: pngDims.width, + height: pngDims.height, + }); + } + + // Serialize the PDFDocument to bytes (a Uint8Array) + const pdfBytes = await pdfDoc.save(); + + // Create a Blob + const blob = new Blob([pdfBytes.buffer], {type: 'application/pdf'}); + + // Create download link + const downloadLink = document.createElement('a'); + downloadLink.href = URL.createObjectURL(blob); + let newFileName = inputFileName ? inputFileName.replace('.pdf', '') : 'download'; + newFileName += '_adjusted_color.pdf'; + + downloadLink.download = newFileName; + downloadLink.click(); + + // After download, reset the viewer and clear stored data + allPages = []; // Clear the pages + originalImageData = null; // Clear the image data + + // Go back to page 1 and render it in the viewer + if (pdf !== null) { + renderPageAndAdjustImageProperties(1); + } +} + +// Event listeners +document.getElementById('fileInput-input').addEventListener('change', function (e) { + const fileInput = event.target; + fileInput.addEventListener('file-input-change', async (e) => { + const {allFiles} = e.detail; + if (allFiles && allFiles.length > 0) { + const file = allFiles[0]; + inputFileName = file.name; + renderPDFAndSaveOriginalImageData(file); + } + }); +}); + +document.getElementById('contrast-slider').addEventListener('input', function () { + document.getElementById('contrast-val').textContent = this.value; + adjustImageProperties(); +}); + +document.getElementById('brightness-slider').addEventListener('input', function () { + document.getElementById('brightness-val').textContent = this.value; + adjustImageProperties(); +}); + +document.getElementById('saturation-slider').addEventListener('input', function () { + document.getElementById('saturation-val').textContent = this.value; + adjustImageProperties(); +}); + +document.getElementById('download-button').addEventListener('click', function () { + downloadPDF(); +}); diff --git a/src/main/resources/static/js/pages/change-metadata.js b/src/main/resources/static/js/pages/change-metadata.js new file mode 100644 index 000000000..bdc5426b7 --- /dev/null +++ b/src/main/resources/static/js/pages/change-metadata.js @@ -0,0 +1,150 @@ +const deleteAllCheckbox = document.querySelector('#deleteAll'); +let inputs = document.querySelectorAll('input'); +const customMetadataDiv = document.getElementById('customMetadata'); +const otherMetadataEntriesDiv = document.getElementById('otherMetadataEntries'); + +deleteAllCheckbox.addEventListener('change', function (event) { + inputs.forEach((input) => { + // If it's the deleteAllCheckbox or any file input, skip + if (input === deleteAllCheckbox || input.type === 'file') { + return; + } + // Disable or enable based on the checkbox state + input.disabled = deleteAllCheckbox.checked; + }); +}); + +const customModeCheckbox = document.getElementById('customModeCheckbox'); +const addMetadataBtn = document.getElementById('addMetadataBtn'); +const customMetadataFormContainer = document.getElementById('customMetadataEntries'); +var count = 1; +const fileInput = document.querySelector('#fileInput-input'); +const authorInput = document.querySelector('#author'); +const creationDateInput = document.querySelector('#creationDate'); +const creatorInput = document.querySelector('#creator'); +const keywordsInput = document.querySelector('#keywords'); +const modificationDateInput = document.querySelector('#modificationDate'); +const producerInput = document.querySelector('#producer'); +const subjectInput = document.querySelector('#subject'); +const titleInput = document.querySelector('#title'); +const trappedInput = document.querySelector('#trapped'); +var lastPDFFileMeta = null; +var lastPDFFile = null; + +fileInput.addEventListener('change', async function () { + fileInput.addEventListener('file-input-change', async (e) => { + const {allFiles} = e.detail; + if (allFiles && allFiles.length > 0) { + const file = allFiles[0]; + while (otherMetadataEntriesDiv.firstChild) { + otherMetadataEntriesDiv.removeChild(otherMetadataEntriesDiv.firstChild); + } + while (customMetadataFormContainer.firstChild) { + customMetadataFormContainer.removeChild(customMetadataFormContainer.firstChild); + } + var url = URL.createObjectURL(file); + pdfjsLib.GlobalWorkerOptions.workerSrc = './pdfjs-legacy/pdf.worker.mjs'; + const pdf = await pdfjsLib.getDocument(url).promise; + const pdfMetadata = await pdf.getMetadata(); + lastPDFFile = pdfMetadata?.info; + console.log(pdfMetadata); + if (!pdfMetadata?.info?.Custom || pdfMetadata?.info?.Custom.size == 0) { + customModeCheckbox.disabled = true; + customModeCheckbox.checked = false; + } else { + customModeCheckbox.disabled = false; + } + authorInput.value = pdfMetadata?.info?.Author; + creationDateInput.value = convertDateFormat(pdfMetadata?.info?.CreationDate); + creatorInput.value = pdfMetadata?.info?.Creator; + keywordsInput.value = pdfMetadata?.info?.Keywords; + modificationDateInput.value = convertDateFormat(pdfMetadata?.info?.ModDate); + producerInput.value = pdfMetadata?.info?.Producer; + subjectInput.value = pdfMetadata?.info?.Subject; + titleInput.value = pdfMetadata?.info?.Title; + console.log(pdfMetadata?.info); + const trappedValue = pdfMetadata?.info?.Trapped; + // Get all options in the select element + const options = trappedInput.options; + // Loop through all options to find the one with a matching value + for (let i = 0; i < options.length; i++) { + if (options[i].value === trappedValue) { + options[i].selected = true; + break; + } + } + addExtra(); + } + }); +}); + +addMetadataBtn.addEventListener('click', () => { + const keyInput = document.createElement('input'); + keyInput.type = 'text'; + keyInput.placeholder = 'Key'; + keyInput.className = 'form-control'; + keyInput.name = `allRequestParams[customKey${count}]`; + + const valueInput = document.createElement('input'); + valueInput.type = 'text'; + valueInput.placeholder = 'Value'; + valueInput.className = 'form-control'; + valueInput.name = `allRequestParams[customValue${count}]`; + count = count + 1; + + const formGroup = document.createElement('div'); + formGroup.className = 'mb-3'; + formGroup.appendChild(keyInput); + formGroup.appendChild(valueInput); + + customMetadataFormContainer.appendChild(formGroup); +}); +function convertDateFormat(dateTimeString) { + if (!dateTimeString || dateTimeString.length < 17) { + return dateTimeString; + } + + const year = dateTimeString.substring(2, 6); + const month = dateTimeString.substring(6, 8); + const day = dateTimeString.substring(8, 10); + const hour = dateTimeString.substring(10, 12); + const minute = dateTimeString.substring(12, 14); + const second = dateTimeString.substring(14, 16); + + return year + '/' + month + '/' + day + ' ' + hour + ':' + minute + ':' + second; +} + +function addExtra() { + const event = document.getElementById('customModeCheckbox'); + if (event.checked && lastPDFFile.Custom != null) { + customMetadataDiv.style.display = 'block'; + for (const [key, value] of Object.entries(lastPDFFile.Custom)) { + if ( + key === 'Author' || + key === 'CreationDate' || + key === 'Creator' || + key === 'Keywords' || + key === 'ModDate' || + key === 'Producer' || + key === 'Subject' || + key === 'Title' || + key === 'Trapped' + ) { + continue; + } + const entryDiv = document.createElement('div'); + entryDiv.className = 'mb-3'; + entryDiv.innerHTML = `
`; + otherMetadataEntriesDiv.appendChild(entryDiv); + } + } else { + customMetadataDiv.style.display = 'none'; + while (otherMetadataEntriesDiv.firstChild) { + otherMetadataEntriesDiv.removeChild(otherMetadataEntriesDiv.firstChild); + } + } +} + +customModeCheckbox.addEventListener('change', (event) => { + addExtra(); +}); diff --git a/src/main/resources/static/js/pages/crop.js b/src/main/resources/static/js/pages/crop.js new file mode 100644 index 000000000..1854023a0 --- /dev/null +++ b/src/main/resources/static/js/pages/crop.js @@ -0,0 +1,159 @@ +let pdfCanvas = document.getElementById('cropPdfCanvas'); +let overlayCanvas = document.getElementById('overlayCanvas'); +let canvasesContainer = document.getElementById('canvasesContainer'); +canvasesContainer.style.display = 'none'; +let containerRect = canvasesContainer.getBoundingClientRect(); + +let context = pdfCanvas.getContext('2d'); +let overlayContext = overlayCanvas.getContext('2d'); + +overlayCanvas.width = pdfCanvas.width; +overlayCanvas.height = pdfCanvas.height; + +let isDrawing = false; // New flag to check if drawing is ongoing + +let cropForm = document.getElementById('cropForm'); +let fileInput = document.getElementById('fileInput-input'); +let xInput = document.getElementById('x'); +let yInput = document.getElementById('y'); +let widthInput = document.getElementById('width'); +let heightInput = document.getElementById('height'); + +let pdfDoc = null; +let currentPage = 1; +let totalPages = 0; + +let startX = 0; +let startY = 0; +let rectWidth = 0; +let rectHeight = 0; + +let pageScale = 1; // The scale which the pdf page renders +let timeId = null; // timeout id for resizing canvases event + +function renderPageFromFile(file) { + if (file.type === 'application/pdf') { + let reader = new FileReader(); + reader.onload = function (ev) { + let typedArray = new Uint8Array(reader.result); + pdfjsLib.GlobalWorkerOptions.workerSrc = './pdfjs-legacy/pdf.worker.mjs'; + pdfjsLib.getDocument(typedArray).promise.then(function (pdf) { + pdfDoc = pdf; + totalPages = pdf.numPages; + renderPage(currentPage); + }); + }; + reader.readAsArrayBuffer(file); + } +} + +window.addEventListener('resize', function () { + clearTimeout(timeId); + + timeId = setTimeout(function () { + if (fileInput.files.length == 0) return; + let canvasesContainer = document.getElementById('canvasesContainer'); + let containerRect = canvasesContainer.getBoundingClientRect(); + + context.clearRect(0, 0, pdfCanvas.width, pdfCanvas.height); + + overlayContext.clearRect(0, 0, overlayCanvas.width, overlayCanvas.height); + + pdfCanvas.width = containerRect.width; + pdfCanvas.height = containerRect.height; + + overlayCanvas.width = containerRect.width; + overlayCanvas.height = containerRect.height; + + let file = fileInput.files[0]; + renderPageFromFile(file); + }, 1000); +}); + +fileInput.addEventListener('change', function (e) { + fileInput.addEventListener('file-input-change', async (e) => { + const {allFiles} = e.detail; + if (allFiles && allFiles.length > 0) { + canvasesContainer.style.display = 'block'; // set for visual purposes + let file = allFiles[0]; + renderPageFromFile(file); + } + }); +}); + +cropForm.addEventListener('submit', function (e) { + if (xInput.value == '' && yInput.value == '' && widthInput.value == '' && heightInput.value == '') { + // Ορίστε συντεταγμένες για ολόκληρη την επιφάνεια του PDF + xInput.value = 0; + yInput.value = 0; + widthInput.value = containerRect.width; + heightInput.value = containerRect.height; + } +}); + +overlayCanvas.addEventListener('mousedown', function (e) { + // Clear previously drawn rectangle on the main canvas + context.clearRect(0, 0, pdfCanvas.width, pdfCanvas.height); + renderPage(currentPage); // Re-render the PDF + + // Clear the overlay canvas to ensure old drawings are removed + overlayContext.clearRect(0, 0, overlayCanvas.width, overlayCanvas.height); + + startX = e.offsetX; + startY = e.offsetY; + isDrawing = true; +}); + +overlayCanvas.addEventListener('mousemove', function (e) { + if (!isDrawing) return; + overlayContext.clearRect(0, 0, overlayCanvas.width, overlayCanvas.height); // Clear previous rectangle + + rectWidth = e.offsetX - startX; + rectHeight = e.offsetY - startY; + overlayContext.strokeStyle = 'red'; + overlayContext.strokeRect(startX, startY, rectWidth, rectHeight); +}); + +overlayCanvas.addEventListener('mouseup', function (e) { + isDrawing = false; + + rectWidth = e.offsetX - startX; + rectHeight = e.offsetY - startY; + + let flippedY = pdfCanvas.height - e.offsetY; + + xInput.value = startX / pageScale; + yInput.value = flippedY / pageScale; + widthInput.value = rectWidth / pageScale; + heightInput.value = rectHeight / pageScale; + + // Draw the final rectangle on the main canvas + context.strokeStyle = 'red'; + context.strokeRect(startX, startY, rectWidth, rectHeight); + + overlayContext.clearRect(0, 0, overlayCanvas.width, overlayCanvas.height); // Clear the overlay +}); + +function renderPage(pageNumber) { + pdfDoc.getPage(pageNumber).then(function (page) { + let canvasesContainer = document.getElementById('canvasesContainer'); + let containerRect = canvasesContainer.getBoundingClientRect(); + + pageScale = containerRect.width / page.getViewport({scale: 1}).width; // The new scale + + let viewport = page.getViewport({scale: containerRect.width / page.getViewport({scale: 1}).width}); + + canvasesContainer.width = viewport.width; + canvasesContainer.height = viewport.height; + + pdfCanvas.width = viewport.width; + pdfCanvas.height = viewport.height; + + overlayCanvas.width = viewport.width; // Match overlay canvas size with PDF canvas + overlayCanvas.height = viewport.height; + + let renderContext = {canvasContext: context, viewport: viewport}; + page.render(renderContext); + pdfCanvas.classList.add('shadow-canvas'); + }); +} diff --git a/src/main/resources/static/js/pages/pdf-to-csv.js b/src/main/resources/static/js/pages/pdf-to-csv.js new file mode 100644 index 000000000..6be3c2ed6 --- /dev/null +++ b/src/main/resources/static/js/pages/pdf-to-csv.js @@ -0,0 +1,138 @@ +let pdfCanvas = document.getElementById('cropPdfCanvas'); +let overlayCanvas = document.getElementById('overlayCanvas'); +let canvasesContainer = document.getElementById('canvasesContainer'); +canvasesContainer.style.display = 'none'; +// let paginationBtnContainer = ; + +let context = pdfCanvas.getContext('2d'); +let overlayContext = overlayCanvas.getContext('2d'); + +let btn1Object = document.getElementById('previous-page-btn'); +let btn2Object = document.getElementById('next-page-btn'); +overlayCanvas.width = pdfCanvas.width; +overlayCanvas.height = pdfCanvas.height; + +let fileInput = document.getElementById('fileInput-input'); + +let file; + +let pdfDoc = null; +let pageId = document.getElementById('pageId'); +let currentPage = 1; +let totalPages = 0; + +let startX = 0; +let startY = 0; +let rectWidth = 0; +let rectHeight = 0; + +let timeId = null; // timeout id for resizing canvases event + +btn1Object.addEventListener('click', function (e) { + if (currentPage !== 1) { + currentPage = currentPage - 1; + pageId.value = currentPage; + + if (file.type === 'application/pdf') { + let reader = new FileReader(); + reader.onload = function (ev) { + let typedArray = new Uint8Array(reader.result); + pdfjsLib.GlobalWorkerOptions.workerSrc = './pdfjs-legacy/pdf.worker.mjs'; + pdfjsLib.getDocument(typedArray).promise.then(function (pdf) { + pdfDoc = pdf; + totalPages = pdf.numPages; + renderPage(currentPage); + }); + }; + reader.readAsArrayBuffer(file); + } + } +}); + +btn2Object.addEventListener('click', function (e) { + if (currentPage !== totalPages) { + currentPage = currentPage + 1; + pageId.value = currentPage; + + if (file.type === 'application/pdf') { + let reader = new FileReader(); + reader.onload = function (ev) { + let typedArray = new Uint8Array(reader.result); + pdfjsLib.GlobalWorkerOptions.workerSrc = './pdfjs-legacy/pdf.worker.mjs'; + pdfjsLib.getDocument(typedArray).promise.then(function (pdf) { + pdfDoc = pdf; + totalPages = pdf.numPages; + renderPage(currentPage); + }); + }; + reader.readAsArrayBuffer(file); + } + } +}); + +function renderPageFromFile(file) { + if (file.type === 'application/pdf') { + let reader = new FileReader(); + reader.onload = function (ev) { + let typedArray = new Uint8Array(reader.result); + pdfjsLib.GlobalWorkerOptions.workerSrc = './pdfjs-legacy/pdf.worker.mjs'; + pdfjsLib.getDocument(typedArray).promise.then(function (pdf) { + pdfDoc = pdf; + totalPages = pdf.numPages; + renderPage(currentPage); + }); + pageId.value = currentPage; + }; + reader.readAsArrayBuffer(file); + document.getElementById('pagination-button-container').style.display = 'flex'; + document.getElementById('instruction-text').style.display = 'block'; + } +} + +window.addEventListener('resize', function () { + clearTimeout(timeId); + timeId = setTimeout(function () { + if (fileInput.files.length == 0) return; + let canvasesContainer = document.getElementById('canvasesContainer'); + let containerRect = canvasesContainer.getBoundingClientRect(); + + context.clearRect(0, 0, pdfCanvas.width, pdfCanvas.height); + + overlayContext.clearRect(0, 0, overlayCanvas.width, overlayCanvas.height); + + pdfCanvas.width = containerRect.width; + pdfCanvas.height = containerRect.height; + + overlayCanvas.width = containerRect.width; + overlayCanvas.height = containerRect.height; + + let file = fileInput.files[0]; + renderPageFromFile(file); + }, 1000); +}); + +fileInput.addEventListener('change', function (e) { + fileInput.addEventListener('file-input-change', async (e) => { + const {allFiles} = e.detail; + if (allFiles && allFiles.length > 0) { + canvasesContainer.style.display = 'block'; // set for visual purposes + file = e.target.files[0]; + renderPageFromFile(file); + } + }); +}); + +function renderPage(pageNumber) { + pdfDoc.getPage(pageNumber).then(function (page) { + let viewport = page.getViewport({scale: 1.0}); + pdfCanvas.width = viewport.width; + pdfCanvas.height = viewport.height; + + overlayCanvas.width = viewport.width; // Match overlay canvas size with PDF canvas + overlayCanvas.height = viewport.height; + + let renderContext = {canvasContext: context, viewport: viewport}; + page.render(renderContext); + pdfCanvas.classList.add('shadow-canvas'); + }); +} diff --git a/src/main/resources/static/js/pages/sign.js b/src/main/resources/static/js/pages/sign.js new file mode 100644 index 000000000..8d45c9697 --- /dev/null +++ b/src/main/resources/static/js/pages/sign.js @@ -0,0 +1,213 @@ +window.toggleSignatureView = toggleSignatureView; +window.previewSignature = previewSignature; +window.addSignatureFromPreview = addSignatureFromPreview; +window.addDraggableFromPad = addDraggableFromPad; +window.addDraggableFromText = addDraggableFromText; +window.goToFirstOrLastPage = goToFirstOrLastPage; + +let currentPreviewSrc = null; + +function toggleSignatureView() { + const gridView = document.getElementById('gridView'); + const listView = document.getElementById('listView'); + const gridText = document.querySelector('.grid-view-text'); + const listText = document.querySelector('.list-view-text'); + + if (gridView.style.display !== 'none') { + gridView.style.display = 'none'; + listView.style.display = 'block'; + gridText.style.display = 'none'; + listText.style.display = 'inline'; + } else { + gridView.style.display = 'block'; + listView.style.display = 'none'; + gridText.style.display = 'inline'; + listText.style.display = 'none'; + } +} + +function previewSignature(element) { + const src = element.dataset.src; + currentPreviewSrc = src; + + const filename = element.querySelector('.signature-list-name').textContent; + + const previewImage = document.getElementById('previewImage'); + const previewFileName = document.getElementById('previewFileName'); + + previewImage.src = src; + previewFileName.textContent = filename; + + const modal = new bootstrap.Modal(document.getElementById('signaturePreview')); + modal.show(); +} + +function addSignatureFromPreview() { + if (currentPreviewSrc) { + DraggableUtils.createDraggableCanvasFromUrl(currentPreviewSrc); + bootstrap.Modal.getInstance(document.getElementById('signaturePreview')).hide(); + } +} + +let originalFileName = ''; +document.querySelector('input[name=pdf-upload]').addEventListener('change', async (event) => { + const fileInput = event.target; + fileInput.addEventListener('file-input-change', async (e) => { + const {allFiles} = e.detail; + if (allFiles && allFiles.length > 0) { + const file = allFiles[0]; + originalFileName = file.name.replace(/\.[^/.]+$/, ''); + const pdfData = await file.arrayBuffer(); + pdfjsLib.GlobalWorkerOptions.workerSrc = './pdfjs-legacy/pdf.worker.mjs'; + const pdfDoc = await pdfjsLib.getDocument({data: pdfData}).promise; + await DraggableUtils.renderPage(pdfDoc, 0); + + document.querySelectorAll('.show-on-file-selected').forEach((el) => { + el.style.cssText = ''; + }); + } + }); +}); + +document.addEventListener('DOMContentLoaded', () => { + document.querySelectorAll('.show-on-file-selected').forEach((el) => { + el.style.cssText = 'display:none !important'; + }); +}); + +const imageUpload = document.querySelector('input[name=image-upload]'); +imageUpload.addEventListener('change', (e) => { + if (!e.target.files) return; + for (const imageFile of e.target.files) { + var reader = new FileReader(); + reader.readAsDataURL(imageFile); + reader.onloadend = function (e) { + DraggableUtils.createDraggableCanvasFromUrl(e.target.result); + }; + } +}); + +const signaturePadCanvas = document.getElementById('drawing-pad-canvas'); +const signaturePad = new SignaturePad(signaturePadCanvas, { + minWidth: 1, + maxWidth: 2, + penColor: 'black', +}); + +function addDraggableFromPad() { + if (signaturePad.isEmpty()) return; + const startTime = Date.now(); + const croppedDataUrl = getCroppedCanvasDataUrl(signaturePadCanvas); + console.log(Date.now() - startTime); + DraggableUtils.createDraggableCanvasFromUrl(croppedDataUrl); +} + +function getCroppedCanvasDataUrl(canvas) { + let originalCtx = canvas.getContext('2d'); + let originalWidth = canvas.width; + let originalHeight = canvas.height; + let imageData = originalCtx.getImageData(0, 0, originalWidth, originalHeight); + + let minX = originalWidth + 1, + maxX = -1, + minY = originalHeight + 1, + maxY = -1, + x = 0, + y = 0, + currentPixelColorValueIndex; + + for (y = 0; y < originalHeight; y++) { + for (x = 0; x < originalWidth; x++) { + currentPixelColorValueIndex = (y * originalWidth + x) * 4; + let currentPixelAlphaValue = imageData.data[currentPixelColorValueIndex + 3]; + if (currentPixelAlphaValue > 0) { + if (minX > x) minX = x; + if (maxX < x) maxX = x; + if (minY > y) minY = y; + if (maxY < y) maxY = y; + } + } + } + + let croppedWidth = maxX - minX; + let croppedHeight = maxY - minY; + if (croppedWidth < 0 || croppedHeight < 0) return null; + let cuttedImageData = originalCtx.getImageData(minX, minY, croppedWidth, croppedHeight); + + let croppedCanvas = document.createElement('canvas'), + croppedCtx = croppedCanvas.getContext('2d'); + + croppedCanvas.width = croppedWidth; + croppedCanvas.height = croppedHeight; + croppedCtx.putImageData(cuttedImageData, 0, 0); + + return croppedCanvas.toDataURL(); +} + +function resizeCanvas() { + var ratio = Math.max(window.devicePixelRatio || 1, 1); + var additionalFactor = 10; + + signaturePadCanvas.width = signaturePadCanvas.offsetWidth * ratio * additionalFactor; + signaturePadCanvas.height = signaturePadCanvas.offsetHeight * ratio * additionalFactor; + signaturePadCanvas.getContext('2d').scale(ratio * additionalFactor, ratio * additionalFactor); + + signaturePad.clear(); +} + +new IntersectionObserver((entries, observer) => { + if (entries.some((entry) => entry.intersectionRatio > 0)) { + resizeCanvas(); + } +}).observe(signaturePadCanvas); + +new ResizeObserver(resizeCanvas).observe(signaturePadCanvas); + +function addDraggableFromText() { + const sigText = document.getElementById('sigText').value; + const font = document.querySelector('select[name=font]').value; + const fontSize = 100; + + const canvas = document.createElement('canvas'); + const ctx = canvas.getContext('2d'); + ctx.font = `${fontSize}px ${font}`; + const textWidth = ctx.measureText(sigText).width; + const textHeight = fontSize; + + let paragraphs = sigText.split(/\r?\n/); + + canvas.width = textWidth; + canvas.height = paragraphs.length * textHeight * 1.35; // for tails + ctx.font = `${fontSize}px ${font}`; + + ctx.textBaseline = 'top'; + + let y = 0; + + paragraphs.forEach((paragraph) => { + ctx.fillText(paragraph, 0, y); + y += fontSize; + }); + + const dataURL = canvas.toDataURL(); + DraggableUtils.createDraggableCanvasFromUrl(dataURL); +} + +async function goToFirstOrLastPage(page) { + if (page) { + const lastPage = DraggableUtils.pdfDoc.numPages; + await DraggableUtils.goToPage(lastPage - 1); + } else { + await DraggableUtils.goToPage(0); + } +} + +document.getElementById('download-pdf').addEventListener('click', async () => { + const modifiedPdf = await DraggableUtils.getOverlayedPdfDocument(); + const modifiedPdfBytes = await modifiedPdf.save(); + const blob = new Blob([modifiedPdfBytes], {type: 'application/pdf'}); + const link = document.createElement('a'); + link.href = URL.createObjectURL(blob); + link.download = originalFileName + '_signed.pdf'; + link.click(); +}); diff --git a/src/main/resources/templates/convert/pdf-to-csv.html b/src/main/resources/templates/convert/pdf-to-csv.html index b3dfc09cd..976837340 100644 --- a/src/main/resources/templates/convert/pdf-to-csv.html +++ b/src/main/resources/templates/convert/pdf-to-csv.html @@ -34,140 +34,8 @@ - + diff --git a/src/main/resources/templates/crop.html b/src/main/resources/templates/crop.html index e606fded5..5262f0f59 100644 --- a/src/main/resources/templates/crop.html +++ b/src/main/resources/templates/crop.html @@ -32,163 +32,7 @@ - + diff --git a/src/main/resources/templates/error.html b/src/main/resources/templates/error.html index 314d28b39..00f22c27b 100644 --- a/src/main/resources/templates/error.html +++ b/src/main/resources/templates/error.html @@ -19,7 +19,7 @@

- +
diff --git a/src/main/resources/templates/fragments/common.html b/src/main/resources/templates/fragments/common.html index edbb47ab8..238543a19 100644 --- a/src/main/resources/templates/fragments/common.html +++ b/src/main/resources/templates/fragments/common.html @@ -203,7 +203,17 @@ - +
- +
diff --git a/src/main/resources/templates/misc/add-image.html b/src/main/resources/templates/misc/add-image.html index 947185a73..6bca8ee7a 100644 --- a/src/main/resources/templates/misc/add-image.html +++ b/src/main/resources/templates/misc/add-image.html @@ -22,46 +22,9 @@
- - +
-
@@ -93,17 +56,6 @@
- diff --git a/src/main/resources/templates/misc/adjust-contrast.html b/src/main/resources/templates/misc/adjust-contrast.html index 22ef855d7..4114955ee 100644 --- a/src/main/resources/templates/misc/adjust-contrast.html +++ b/src/main/resources/templates/misc/adjust-contrast.html @@ -55,247 +55,7 @@ - + diff --git a/src/main/resources/templates/misc/change-metadata.html b/src/main/resources/templates/misc/change-metadata.html index 50ba318bf..2aaa47e9a 100644 --- a/src/main/resources/templates/misc/change-metadata.html +++ b/src/main/resources/templates/misc/change-metadata.html @@ -85,140 +85,7 @@
- diff --git a/src/main/resources/templates/misc/extract-images.html b/src/main/resources/templates/misc/extract-images.html index d47a72d7c..1e6268feb 100644 --- a/src/main/resources/templates/misc/extract-images.html +++ b/src/main/resources/templates/misc/extract-images.html @@ -2,6 +2,7 @@ + diff --git a/src/main/resources/templates/misc/replace-color.html b/src/main/resources/templates/misc/replace-color.html index 4defcff72..4ab5460a9 100644 --- a/src/main/resources/templates/misc/replace-color.html +++ b/src/main/resources/templates/misc/replace-color.html @@ -4,6 +4,7 @@ + diff --git a/src/main/resources/templates/multi-tool.html b/src/main/resources/templates/multi-tool.html index 14e5a85ec..17eafedf3 100644 --- a/src/main/resources/templates/multi-tool.html +++ b/src/main/resources/templates/multi-tool.html @@ -162,10 +162,19 @@ insertPageBreak:'[[#{multiTool.insertPageBreak}]]', dragDropMessage:'[[#{multiTool.dragDropMessage}]]', undo: '[[#{multiTool.undo}]]', - redo: '[[#{multiTool.redo}]]' + redo: '[[#{multiTool.redo}]]', }; - + window.decrypt = { + passwordPrompt: '[[#{decrypt.passwordPrompt}]]', + cancelled: '[[#{decrypt.cancelled}]]', + noPassword: '[[#{decrypt.noPassword}]]', + invalidPassword: '[[#{decrypt.invalidPassword}]]', + invalidPasswordHeader: '[[#{decrypt.invalidPasswordHeader}]]', + unexpectedError: '[[#{decrypt.unexpectedError}]]', + serverError: '[[#{decrypt.serverError}]]', + success: '[[#{decrypt.success}]]', + } const csvInput = document.getElementById("csv-input"); csvInput.addEventListener("keydown", function (event) { diff --git a/src/main/resources/templates/overlay-pdf.html b/src/main/resources/templates/overlay-pdf.html index e92e4cb08..616e3343a 100644 --- a/src/main/resources/templates/overlay-pdf.html +++ b/src/main/resources/templates/overlay-pdf.html @@ -2,6 +2,7 @@ + diff --git a/src/main/resources/templates/pipeline.html b/src/main/resources/templates/pipeline.html index eaa874639..dae05df2b 100644 --- a/src/main/resources/templates/pipeline.html +++ b/src/main/resources/templates/pipeline.html @@ -14,6 +14,7 @@ th:href="@{'/css/pipeline.css'}" th:if="${currentPage == 'pipeline'}" /> + + + @@ -42,75 +43,6 @@ th:replace="~{fragments/common :: fileSelector(name='pdf-upload', multipleInputsForSingleRequest=false, disableMultipleFiles=true, accept='application/pdf')}"> -
- - - - -
@@ -410,35 +225,11 @@
-
- - - - @@ -447,6 +238,7 @@ + \ No newline at end of file