Compare commits

...

39 Commits

Author SHA1 Message Date
pixeebot[bot]
b094634799 Hardening suggestions for Stirling-PDF / fix-sig-logo (#2144)
Modernize and secure temp file creation

Co-authored-by: pixeebot[bot] <104101892+pixeebot[bot]@users.noreply.github.com>
2024-10-31 16:17:23 -04:00
sbplat
9e597a4390 fix signature logo not loading and add option to disable it 2024-10-31 16:06:36 -04:00
Anthony Stirling
febc3cf48b Update pull_request_template.md 2024-10-31 17:46:30 +00:00
Philip H.
c5abb47403 navbar.css: prevent overlapping of elements (#2140)
go-pro-link is overlapping the settings button
2024-10-31 17:45:44 +00:00
Anthony Stirling
0e3c9bcc10 Update README.md 2024-10-31 14:52:41 +00:00
github-actions[bot]
384c3ee88f 💾 Update Version (#2139)
💾 Sync Versions
> Made via sync_files.yml

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-10-31 13:06:55 +00:00
Anthony Stirling
5f7a0537f9 Update build.gradle 2024-10-31 13:06:12 +00:00
Anthony Stirling
5aa5628465 [bug fix] Update compress-pdf.html (#2138)
Update compress-pdf.html
2024-10-31 10:59:51 +00:00
albanobattistella
0d91bca932 Update messages_it_IT.properties (#2135) 2024-10-30 19:55:54 +00:00
Ludovic Ortega
8e88591499 chore(helm): bump chart version according to semver (#2109)
Signed-off-by: Ludovic Ortega <ludovic.ortega@adminafk.fr>
2024-10-30 13:49:28 +00:00
github-actions[bot]
3e051d0105 Update 3rd Party Licenses (#2134)
Signed-off-by: GitHub Action <action@github.com>
Co-authored-by: GitHub Action <action@github.com>
2024-10-30 13:00:51 +00:00
dependabot[bot]
4a9b16ff8f Bump org.springframework.security:spring-security-saml2-service-provider from 6.3.3 to 6.3.4 (#2052)
Bump org.springframework.security:spring-security-saml2-service-provider

Bumps [org.springframework.security:spring-security-saml2-service-provider](https://github.com/spring-projects/spring-security) from 6.3.3 to 6.3.4.
- [Release notes](https://github.com/spring-projects/spring-security/releases)
- [Changelog](https://github.com/spring-projects/spring-security/blob/main/RELEASE.adoc)
- [Commits](https://github.com/spring-projects/spring-security/compare/6.3.3...6.3.4)

---
updated-dependencies:
- dependency-name: org.springframework.security:spring-security-saml2-service-provider
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-30 12:58:47 +00:00
github-actions[bot]
a7082ecd85 💾 Update Version (#2132)
💾 Sync Versions
> Made via sync_files.yml

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-10-30 12:48:44 +00:00
github-actions[bot]
966e6a4923 📝 Update README: Translation Progress Table (#2133)
📝 Sync README
> Made via sync_files.yml

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-10-30 12:48:30 +00:00
Anthony Stirling
27d2681a97 Feature/save signs (#2127)
* apply fix

* Fixes empty th:action

* Update build.gradle

* fix

* formatting

* Save signatures

* Fix code scanning alert no. 42: Uncontrolled data used in path expression

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>

* fix UserServiceInterface

* Merge branch 'feature/saveSigns' of
git@github.com:Stirling-Tools/Stirling-PDF.git into feature/saveSigns

* 0.31.0 bump and further csrf

* formatting

* preview name

* add

* sign doc

* Update translation files (#2128)

Signed-off-by: GitHub Action <action@github.com>
Co-authored-by: GitHub Action <action@github.com>

---------

Signed-off-by: GitHub Action <action@github.com>
Co-authored-by: Dimitrios Kaitantzidis <james_k23@hotmail.gr>
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
Co-authored-by: a <a>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: GitHub Action <action@github.com>
2024-10-30 12:46:44 +00:00
github-actions[bot]
ed75fa4e1b 📝 Update README: Translation Progress Table (#2129)
📝 Sync README
> Made via sync_files.yml

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-10-29 19:05:01 +00:00
Rania Amina
9b9752bd7a Update id_ID Translation and fix some grammars (#2108)
* Update id_ID Translation and fix some grammars

* sync lines to fix build warning

* get back new line at end of file

---------

Co-authored-by: Anthony Stirling <77850077+Frooodle@users.noreply.github.com>
2024-10-29 19:03:00 +00:00
Anthony Stirling
903dc7638c Fix csrf (#2126)
* apply fix

* Fixes empty th:action

* Update build.gradle

* fix

* formatting

---------

Co-authored-by: Dimitrios Kaitantzidis <james_k23@hotmail.gr>
2024-10-29 17:56:29 +00:00
github-actions[bot]
c39b111edc 📝 Update README: Translation Progress Table (#2121)
📝 Sync README
> Made via sync_files.yml

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-10-29 16:31:25 +00:00
github-actions[bot]
d910929aa6 Update translation files (#2125)
Signed-off-by: GitHub Action <action@github.com>
Co-authored-by: GitHub Action <action@github.com>
2024-10-29 16:30:44 +00:00
reecebrowne
a9ce0e80ee Feature/298 improve compare performance (#2124)
* Implement Diff.js

* Compare feature - add service worker and improve efficiency for large files

* Compare - messages updated to be compatable with language packs

* Compare - Acknowledge Diff.js usage

* Add message warning there is  no text in uploaded pdf to messages file

---------

Co-authored-by: Anthony Stirling <77850077+Frooodle@users.noreply.github.com>
2024-10-29 15:56:45 +00:00
Florian Fish
4922ab700e Add new french translations (#2120)
Add new french translations and improve simple quote
2024-10-29 10:12:49 +00:00
github-actions[bot]
01f3c138a6 Update 3rd Party Licenses (#2119)
Signed-off-by: GitHub Action <action@github.com>
Co-authored-by: GitHub Action <action@github.com>
2024-10-28 23:22:15 +00:00
github-actions[bot]
4e21f76979 📝 Update README: Translation Progress Table (#2103)
📝 Sync README
> Made via sync_files.yml

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-10-28 23:22:02 +00:00
dependabot[bot]
a9ccd85e75 Bump org.springframework.boot from 3.3.4 to 3.3.5 (#2118)
Bumps [org.springframework.boot](https://github.com/spring-projects/spring-boot) from 3.3.4 to 3.3.5.
- [Release notes](https://github.com/spring-projects/spring-boot/releases)
- [Commits](https://github.com/spring-projects/spring-boot/compare/v3.3.4...v3.3.5)

---
updated-dependencies:
- dependency-name: org.springframework.boot
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-28 23:19:59 +00:00
dependabot[bot]
6f407f1d2f Bump springBootVersion from 3.3.4 to 3.3.5 (#2117)
Bumps `springBootVersion` from 3.3.4 to 3.3.5.

Updates `org.springframework.boot:spring-boot-starter-web` from 3.3.4 to 3.3.5
- [Release notes](https://github.com/spring-projects/spring-boot/releases)
- [Commits](https://github.com/spring-projects/spring-boot/compare/v3.3.4...v3.3.5)

Updates `org.springframework.boot:spring-boot-starter-jetty` from 3.3.4 to 3.3.5
- [Release notes](https://github.com/spring-projects/spring-boot/releases)
- [Commits](https://github.com/spring-projects/spring-boot/compare/v3.3.4...v3.3.5)

Updates `org.springframework.boot:spring-boot-starter-thymeleaf` from 3.3.4 to 3.3.5
- [Release notes](https://github.com/spring-projects/spring-boot/releases)
- [Commits](https://github.com/spring-projects/spring-boot/compare/v3.3.4...v3.3.5)

Updates `org.springframework.boot:spring-boot-starter-security` from 3.3.4 to 3.3.5
- [Release notes](https://github.com/spring-projects/spring-boot/releases)
- [Commits](https://github.com/spring-projects/spring-boot/compare/v3.3.4...v3.3.5)

Updates `org.springframework.boot:spring-boot-starter-data-jpa` from 3.3.4 to 3.3.5
- [Release notes](https://github.com/spring-projects/spring-boot/releases)
- [Commits](https://github.com/spring-projects/spring-boot/compare/v3.3.4...v3.3.5)

Updates `org.springframework.boot:spring-boot-starter-oauth2-client` from 3.3.4 to 3.3.5
- [Release notes](https://github.com/spring-projects/spring-boot/releases)
- [Commits](https://github.com/spring-projects/spring-boot/compare/v3.3.4...v3.3.5)

Updates `org.springframework.boot:spring-boot-starter-test` from 3.3.4 to 3.3.5
- [Release notes](https://github.com/spring-projects/spring-boot/releases)
- [Commits](https://github.com/spring-projects/spring-boot/compare/v3.3.4...v3.3.5)

Updates `org.springframework.boot:spring-boot-starter-actuator` from 3.3.4 to 3.3.5
- [Release notes](https://github.com/spring-projects/spring-boot/releases)
- [Commits](https://github.com/spring-projects/spring-boot/compare/v3.3.4...v3.3.5)

Updates `org.springframework.boot:spring-boot-devtools` from 3.3.4 to 3.3.5
- [Release notes](https://github.com/spring-projects/spring-boot/releases)
- [Commits](https://github.com/spring-projects/spring-boot/compare/v3.3.4...v3.3.5)

---
updated-dependencies:
- dependency-name: org.springframework.boot:spring-boot-starter-web
  dependency-type: direct:production
  update-type: version-update:semver-patch
- dependency-name: org.springframework.boot:spring-boot-starter-jetty
  dependency-type: direct:production
  update-type: version-update:semver-patch
- dependency-name: org.springframework.boot:spring-boot-starter-thymeleaf
  dependency-type: direct:production
  update-type: version-update:semver-patch
- dependency-name: org.springframework.boot:spring-boot-starter-security
  dependency-type: direct:production
  update-type: version-update:semver-patch
- dependency-name: org.springframework.boot:spring-boot-starter-data-jpa
  dependency-type: direct:production
  update-type: version-update:semver-patch
- dependency-name: org.springframework.boot:spring-boot-starter-oauth2-client
  dependency-type: direct:production
  update-type: version-update:semver-patch
- dependency-name: org.springframework.boot:spring-boot-starter-test
  dependency-type: direct:production
  update-type: version-update:semver-patch
- dependency-name: org.springframework.boot:spring-boot-starter-actuator
  dependency-type: direct:production
  update-type: version-update:semver-patch
- dependency-name: org.springframework.boot:spring-boot-devtools
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-28 23:19:36 +00:00
pixeebot[bot]
af5e2b6895 Modernize and secure temp file creation (#2106)
Co-authored-by: pixeebot[bot] <104101892+pixeebot[bot]@users.noreply.github.com>
2024-10-28 23:19:12 +00:00
Ludy
d2046c64d8 Optimierung der SAML2-Integration und Verbesserung der Zertifikats- und Fehlerbehandlung (#2105)
* certificate processing

* Hides dialog when provider list is empty

* removed: unused
2024-10-27 22:17:36 +00:00
Manuel Mora Gordillo
1b88d89191 Spanish translate (#2102)
* Spanish translate

* Added blank line

---------

Co-authored-by: Manu <manuel@fusiontelecom.co>
2024-10-25 13:20:13 +01:00
github-actions[bot]
03bf98265b 📝 Update README: Translation Progress Table (#2072)
📝 Sync README
> Made via sync_files.yml

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-10-24 14:21:17 +01:00
Anthony Stirling
89da2a5c01 Auto detect presence of external dependencies (LibreOffice etc) and disable/enable features dynamically (#2082)
* Create ExternalAppDepConfig.java

* Update EndpointConfiguration.java

* Hardening suggestions for Stirling-PDF / ExternalAppDepConfig (#2083)

Switch order of literals to prevent NullPointerException

Co-authored-by: pixeebot[bot] <104101892+pixeebot[bot]@users.noreply.github.com>

---------

Co-authored-by: pixeebot[bot] <104101892+pixeebot[bot]@users.noreply.github.com>
2024-10-24 13:59:17 +01:00
swanemar
a10d06b693 added some missing translations (#2085) 2024-10-24 10:35:32 +00:00
Eric
a7ed99084f visual certificate signing (#2084)
add visual digital signature
2024-10-24 07:08:09 +01:00
github-actions[bot]
88f3594d80 Update 3rd Party Licenses (#2080)
Signed-off-by: GitHub Action <action@github.com>
Co-authored-by: GitHub Action <action@github.com>
2024-10-23 12:28:58 +01:00
Eric
e0b77ca274 extract and apply the image orientation from exif data in imageToPdf (#2073) 2024-10-23 12:17:40 +01:00
albanobattistella
bac81c930d Update messages_it_IT.properties (#2077) 2024-10-23 12:16:49 +01:00
Corbinian Grimm
2f49626a4c Update messages_de_DE.properties (#2070)
* Update messages_de_DE.properties

Completed translations for German language.

* Update messages_de_DE.properties
2024-10-22 21:53:13 +01:00
Anthony Stirling
83ef003505 Update PostHogService.java 2024-10-22 15:36:54 +01:00
Anthony Stirling
949b87005c Fix metricCollection 2024-10-22 15:36:22 +01:00
94 changed files with 4585 additions and 1066 deletions

View File

@@ -8,6 +8,7 @@ Closes #(issue_number)
- [ ] I have read the [Contribution Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
- [ ] I have performed a self-review of my own code
- [ ] I have attached images of the change if it is UI based
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] My changes generate no new warnings
- [ ] I have read the section [Add New Translation Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/HowToAddNewLanguage.md#add-new-translation-tags) (for new translation tags only)

View File

@@ -8,17 +8,20 @@ gradle_path = "build.gradle"
def get_chart_version(path):
"""
Reads the appVersion from Chart.yaml.
Reads the version and the appVersion from Chart.yaml.
Args:
path (str): The file path to the Chart.yaml.
Returns:
str: The appVersion if found, otherwise an empty string.
dict: The version under "chart" key and the appVersion under "app" key.
"""
with open(path, encoding="utf-8") as file:
chart_yaml = yaml.safe_load(file)
return chart_yaml.get("appVersion", "")
return {
"chart": chart_yaml["version"],
"app": chart_yaml["appVersion"]
}
def get_gradle_version(path):
@@ -39,17 +42,46 @@ def get_gradle_version(path):
return ""
def update_chart_version(path, new_version):
def get_new_chart_version(chart_version, old_app_version, new_app_version):
"""
Get the new chart version from
Args:
str: The current chart version.
str: The current app version.
str: The new app version.
Returns:
str: The new chart version to update to.
"""
chart_major, chart_minor, chart_patch = chart_version.split(".")
old_major, old_minor, old_patch = old_app_version.split(".")
new_major, new_minor, new_patch = new_app_version.split(".")
if old_major != new_major:
new_chart_version = f"{int(chart_major)+1}.0.0"
elif old_minor != new_minor:
new_chart_version = f"{chart_major}.{int(chart_minor)+1}.0"
elif old_patch != new_patch:
new_chart_version = f"{chart_major}.{chart_minor}.{int(chart_patch)+1}"
return new_chart_version
def update_chart_version(path, new_chart_version, new_app_version):
"""
Updates the appVersion in Chart.yaml with a new version.
Updates the version and the appVersion in Chart.yaml with a new version.
Args:
path (str): The file path to the Chart.yaml.
new_version (str): The new version to update to.
new_chart_version (str): The new chart version to update to.
new_app_version (str): The new app version to update to.
"""
with open(path, encoding="utf-8") as file:
chart_yaml = yaml.safe_load(file)
chart_yaml["appVersion"] = new_version
chart_yaml["version"] = new_chart_version
chart_yaml["appVersion"] = new_app_version
with open(path, "w", encoding="utf-8") as file:
yaml.safe_dump(chart_yaml, file)
@@ -58,10 +90,11 @@ def update_chart_version(path, new_version):
chart_version = get_chart_version(chart_yaml_path)
gradle_version = get_gradle_version(gradle_path)
if chart_version != gradle_version:
if chart_version["app"] != gradle_version:
new_chart_version = get_new_chart_version(chart_version["chart"], chart_version["app"], gradle_version, )
print(
f"Versions do not match. Updating Chart.yaml from {chart_version} to {gradle_version}."
f"Versions do not match. Updating Chart.yaml from {chart_version['chart']} to {new_chart_version}."
)
update_chart_version(chart_yaml_path, gradle_version)
update_chart_version(chart_yaml_path, new_chart_version, gradle_version)
else:
print("Versions match. No update required.")

1
.gitignore vendored
View File

@@ -4,6 +4,7 @@ bin/
tmp/
*.tmp
*.bak
*.exe
*.swp
*~.nib
local.properties

108
README.md
View File

@@ -166,48 +166,55 @@ Note: Podman is CLI-compatible with Docker, so simply replace "docker" with "pod
Please view https://github.com/Stirling-Tools/Stirling-PDF/blob/main/HowToUseOCR.md
## Reuse stored files
Certain functionality like ``Sign`` Supports pre-saved files stored at ``/customFiles/signatures/``, image files placed within here will be accesable to be used via webUI
Currently this supports two folder types
- ``/customFiles/signatures/ALL_USERS`` accessible to all users, useful for orginasations were many users use same files or for users not using authentication
- ``/customFiles/signatures/{username}`` such as ``/customFiles/signatures/froodle`` accessible to only the ``froodle`` username, private for all others
## Supported Languages
Stirling PDF currently supports 38!
| Language | Progress |
| ------------------------------------------- | -------------------------------------- |
| Arabic (العربية) (ar_AR) | ![94%](https://geps.dev/progress/94) |
| Basque (Euskara) (eu_ES) | ![57%](https://geps.dev/progress/57) |
| Bulgarian (Български) (bg_BG) | ![99%](https://geps.dev/progress/99) |
| Arabic (العربية) (ar_AR) | ![93%](https://geps.dev/progress/93) |
| Basque (Euskara) (eu_ES) | ![56%](https://geps.dev/progress/56) |
| Bulgarian (Български) (bg_BG) | ![98%](https://geps.dev/progress/98) |
| Catalan (Català) (ca_CA) | ![44%](https://geps.dev/progress/44) |
| Croatian (Hrvatski) (hr_HR) | ![87%](https://geps.dev/progress/87) |
| Czech (Česky) (cs_CZ) | ![83%](https://geps.dev/progress/83) |
| Danish (Dansk) (da_DK) | ![91%](https://geps.dev/progress/91) |
| Dutch (Nederlands) (nl_NL) | ![88%](https://geps.dev/progress/88) |
| Croatian (Hrvatski) (hr_HR) | ![86%](https://geps.dev/progress/86) |
| Czech (Česky) (cs_CZ) | ![82%](https://geps.dev/progress/82) |
| Danish (Dansk) (da_DK) | ![90%](https://geps.dev/progress/90) |
| Dutch (Nederlands) (nl_NL) | ![87%](https://geps.dev/progress/87) |
| 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) | ![88%](https://geps.dev/progress/88) |
| German (Deutsch) (de_DE) | ![94%](https://geps.dev/progress/94) |
| French (Français) (fr_FR) | ![94%](https://geps.dev/progress/94) |
| German (Deutsch) (de_DE) | ![97%](https://geps.dev/progress/97) |
| Greek (Ελληνικά) (el_GR) | ![75%](https://geps.dev/progress/75) |
| Hindi (हिंदी) (hi_IN) | ![72%](https://geps.dev/progress/72) |
| Hindi (हिंदी) (hi_IN) | ![71%](https://geps.dev/progress/71) |
| Hungarian (Magyar) (hu_HU) | ![69%](https://geps.dev/progress/69) |
| Indonesia (Bahasa Indonesia) (id_ID) | ![70%](https://geps.dev/progress/70) |
| Irish (Gaeilge) (ga_IE) | ![90%](https://geps.dev/progress/90) |
| Italian (Italiano) (it_IT) | ![99%](https://geps.dev/progress/99) |
| Japanese (日本語) (ja_JP) | ![87%](https://geps.dev/progress/87) |
| Korean (한국어) (ko_KR) | ![77%](https://geps.dev/progress/77) |
| Norwegian (Norsk) (no_NB) | ![90%](https://geps.dev/progress/90) |
| Polish (Polski) (pl_PL) | ![99%](https://geps.dev/progress/99) |
| Portuguese (Português) (pt_PT) | ![72%](https://geps.dev/progress/72) |
| Portuguese Brazilian (Português) (pt_BR) | ![99%](https://geps.dev/progress/99) |
| Romanian (Română) (ro_RO) | ![92%](https://geps.dev/progress/92) |
| Russian (Русский) (ru_RU) | ![77%](https://geps.dev/progress/77) |
| Serbian Latin alphabet (Srpski) (sr_LATN_RS) | ![72%](https://geps.dev/progress/72) |
| Simplified Chinese (简体中文) (zh_CN) | ![93%](https://geps.dev/progress/93) |
| Slovakian (Slovensky) (sk_SK) | ![84%](https://geps.dev/progress/84) |
| Spanish (Español) (es_ES) | ![93%](https://geps.dev/progress/93) |
| Swedish (Svenska) (sv_SE) | ![92%](https://geps.dev/progress/92) |
| Thai (ไทย) (th_TH) | ![91%](https://geps.dev/progress/91) |
| Traditional Chinese (繁體中文) (zh_TW) | ![99%](https://geps.dev/progress/99) |
| Turkish (Türkçe) (tr_TR) | ![94%](https://geps.dev/progress/94) |
| Ukrainian (Українська) (uk_UA) | ![82%](https://geps.dev/progress/82) |
| Vietnamese (Tiếng Việt) (vi_VN) | ![91%](https://geps.dev/progress/91) |
| Indonesia (Bahasa Indonesia) (id_ID) | ![95%](https://geps.dev/progress/95) |
| Irish (Gaeilge) (ga_IE) | ![89%](https://geps.dev/progress/89) |
| Italian (Italiano) (it_IT) | ![98%](https://geps.dev/progress/98) |
| Japanese (日本語) (ja_JP) | ![86%](https://geps.dev/progress/86) |
| Korean (한국어) (ko_KR) | ![76%](https://geps.dev/progress/76) |
| Norwegian (Norsk) (no_NB) | ![89%](https://geps.dev/progress/89) |
| Polish (Polski) (pl_PL) | ![98%](https://geps.dev/progress/98) |
| Portuguese (Português) (pt_PT) | ![71%](https://geps.dev/progress/71) |
| Portuguese Brazilian (Português) (pt_BR) | ![98%](https://geps.dev/progress/98) |
| Romanian (Română) (ro_RO) | ![91%](https://geps.dev/progress/91) |
| Russian (Русский) (ru_RU) | ![76%](https://geps.dev/progress/76) |
| Serbian Latin alphabet (Srpski) (sr_LATN_RS) | ![71%](https://geps.dev/progress/71) |
| Simplified Chinese (简体中文) (zh_CN) | ![92%](https://geps.dev/progress/92) |
| Slovakian (Slovensky) (sk_SK) | ![83%](https://geps.dev/progress/83) |
| Spanish (Español) (es_ES) | ![97%](https://geps.dev/progress/97) |
| Swedish (Svenska) (sv_SE) | ![93%](https://geps.dev/progress/93) |
| Thai (ไทย) (th_TH) | ![90%](https://geps.dev/progress/90) |
| Traditional Chinese (繁體中文) (zh_TW) | ![98%](https://geps.dev/progress/98) |
| Turkish (Türkçe) (tr_TR) | ![93%](https://geps.dev/progress/93) |
| Ukrainian (Українська) (uk_UA) | ![81%](https://geps.dev/progress/81) |
| Vietnamese (Tiếng Việt) (vi_VN) | ![90%](https://geps.dev/progress/90) |
## Contributing (creating issues, translations, fixing bugs, etc.)
@@ -273,14 +280,44 @@ security:
useAsUsername: email # Default is 'email'; custom fields can be used as the username
scopes: openid, profile, email # Specify the scopes for which the application will request permissions
provider: google # Set this to your OAuth provider's name, e.g., 'google' or 'keycloak'
saml2:
enabled: false # Currently in alpha, not recommended for use yet, enableAlphaFunctionality must be set to true
autoCreateUser: false # set to 'true' to allow auto-creation of non-existing users
blockRegistration: false # set to 'true' to deny login with SSO without prior registration by an admin
registrationId: stirling
idpMetadataUri: https://dev-XXXXXXXX.okta.com/app/externalKey/sso/saml/metadata
idpSingleLogoutUrl: https://dev-XXXXXXXX.okta.com/app/dev-XXXXXXXX_stirlingpdf_1/externalKey/slo/saml
idpSingleLoginUrl: https://dev-XXXXXXXX.okta.com/app/dev-XXXXXXXX_stirlingpdf_1/externalKey/sso/saml
idpIssuer: http://www.okta.com/externalKey
idpCert: classpath:octa.crt
privateKey: classpath:saml-private-key.key
spCert: classpath:saml-public-cert.crt
enterpriseEdition:
enabled: false # set to 'true' to enable enterprise edition
key: 00000000-0000-0000-0000-000000000000
CustomMetadata:
autoUpdateMetadata: false # set to 'true' to automatically update metadata with below values
author: username # Supports text such as 'John Doe' or types such as username to autopopulate with users username
creator: Stirling-PDF # Supports text such as 'Company-PDF'
producer: Stirling-PDF # Supports text such as 'Company-PDF'
legal:
termsAndConditions: https://www.stirlingpdf.com/terms-and-conditions # URL to the terms and conditions of your application (e.g. https://example.com/terms) Empty string to disable or filename to load from local file in static folder
privacyPolicy: https://www.stirlingpdf.com/privacy-policy # URL to the privacy policy of your application (e.g. https://example.com/privacy) Empty string to disable or filename to load from local file in static folder
accessibilityStatement: '' # URL to the accessibility statement of your application (e.g. https://example.com/accessibility) Empty string to disable or filename to load from local file in static folder
cookiePolicy: '' # URL to the cookie policy of your application (e.g. https://example.com/cookie) Empty string to disable or filename to load from local file in static folder
impressum: '' # URL to the impressum of your application (e.g. https://example.com/impressum) Empty string to disable or filename to load from local file in static folder
system:
defaultLocale: 'en-US' # Set the default language (e.g. 'de-DE', 'fr-FR', etc)
defaultLocale: en-US # Set the default language (e.g. 'de-DE', 'fr-FR', etc)
googlevisibility: false # 'true' to allow Google visibility (via robots.txt), 'false' to disallow
enableAlphaFunctionality: false # Set to enable functionality which might need more testing before it fully goes live (This feature might make no changes)
showUpdate: true # see when a new update is available
showUpdate: false # see when a new update is available
showUpdateOnlyAdmin: false # Only admins can see when a new update is available, depending on showUpdate it must be set to 'true'
customHTMLFiles: false # enable to have files placed in /customFiles/templates override the existing template html files
tessdataDir: /usr/share/tessdata # Path to the directory containing the Tessdata files. This setting is relevant for Windows systems. For Windows users, this path should be adjusted to point to the appropriate directory where the Tessdata files are stored.
enableAnalytics: undefined # Set to 'true' to enable analytics, set to 'false' to disable analytics, for enterprise users this is set to true
ui:
appName: '' # Application's visible name
@@ -293,6 +330,11 @@ endpoints:
metrics:
enabled: true # 'true' to enable Info APIs (`/api/*`) endpoints, 'false' to disable
# Automatically Generated Settings (Do Not Edit Directly)
AutomaticallyGenerated:
key: example
UUID: example
```
There is an additional config file ``/configs/custom_settings.yml`` were users familiar with java and spring application.properties can input their own settings on-top of Stirling-PDFs existing ones

View File

@@ -1,6 +1,6 @@
plugins {
id "java"
id "org.springframework.boot" version "3.3.4"
id "org.springframework.boot" version "3.3.5"
id "io.spring.dependency-management" version "1.1.6"
id "org.springdoc.openapi-gradle-plugin" version "1.8.0"
id "io.swagger.swaggerhub" version "1.3.2"
@@ -13,7 +13,7 @@ plugins {
import com.github.jk1.license.render.*
ext {
springBootVersion = "3.3.4"
springBootVersion = "3.3.5"
pdfboxVersion = "3.0.3"
logbackVersion = "1.5.7"
imageioVersion = "3.12.0"
@@ -22,7 +22,7 @@ ext {
}
group = "stirling.software"
version = "0.30.1"
version = "0.31.1"
java {
// 17 is lowest but we support and recommend 21
@@ -137,11 +137,11 @@ dependencies {
if (System.getenv("DOCKER_ENABLE_SECURITY") != "false") {
implementation "org.springframework.boot:spring-boot-starter-security:$springBootVersion"
runtimeOnly "org.thymeleaf.extras:thymeleaf-extras-springsecurity5:3.1.2.RELEASE"
implementation "org.thymeleaf.extras:thymeleaf-extras-springsecurity5:3.1.2.RELEASE"
implementation "org.springframework.boot:spring-boot-starter-data-jpa:$springBootVersion"
implementation "org.springframework.boot:spring-boot-starter-oauth2-client:$springBootVersion"
implementation 'org.springframework.security:spring-security-saml2-service-provider:6.3.3'
implementation 'org.springframework.security:spring-security-saml2-service-provider:6.3.4'
implementation 'com.unboundid.product.scim2:scim2-sdk-client:2.3.5'
//2.2.x requires rebuild of DB file.. need migration path
runtimeOnly "com.h2database:h2:2.1.214"
@@ -154,6 +154,8 @@ dependencies {
implementation "org.springframework.security:spring-security-saml2-service-provider"
implementation 'com.coveo:saml-client:5.0.0'
}
testImplementation "org.springframework.boot:spring-boot-starter-test:$springBootVersion"
@@ -179,6 +181,9 @@ dependencies {
runtimeOnly "com.twelvemonkeys.imageio:imageio-webp:$imageioVersion"
// runtimeOnly "com.twelvemonkeys.imageio:imageio-xwd:$imageioVersion"
// Image metadata extractor
implementation "com.drewnoakes:metadata-extractor:2.19.0"
implementation "commons-io:commons-io:2.17.0"
implementation "org.springdoc:springdoc-openapi-starter-webmvc-ui:2.2.0"
//general PDF

View File

@@ -1,5 +1,5 @@
apiVersion: v2
appVersion: 0.30.1
appVersion: 0.31.1
description: locally hosted web application that allows you to perform various operations
on PDF files
home: https://github.com/Stirling-Tools/Stirling-PDF
@@ -13,4 +13,4 @@ maintainers:
name: stirling-pdf-chart
sources:
- https://github.com/Stirling-Tools/Stirling-PDF
version: 1.0.0
version: 1.0.1

View File

@@ -1,7 +1,5 @@
package stirling.software.SPDF.EE;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -20,6 +18,6 @@ public class EEAppConfig {
@Bean(name = "runningEE")
public boolean runningEnterpriseEdition() {
return licenseKeyChecker.getEnterpriseEnabledResult();
return licenseKeyChecker.getEnterpriseEnabledResult();
}
}
}

View File

@@ -5,6 +5,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -42,7 +43,7 @@ public class EndpointConfiguration {
public void disableEndpoint(String endpoint) {
if (!endpointStatuses.containsKey(endpoint) || endpointStatuses.get(endpoint) != false) {
logger.info("Disabling {}", endpoint);
logger.debug("Disabling {}", endpoint);
endpointStatuses.put(endpoint, false);
}
}
@@ -76,6 +77,23 @@ public class EndpointConfiguration {
}
}
public void logDisabledEndpointsSummary() {
List<String> disabledList =
endpointStatuses.entrySet().stream()
.filter(entry -> !entry.getValue()) // only get disabled endpoints (value
// is false)
.map(Map.Entry::getKey)
.sorted()
.collect(Collectors.toList());
if (!disabledList.isEmpty()) {
logger.info(
"Total disabled endpoints: {}. Disabled endpoints: {}",
disabledList.size(),
String.join(", ", disabledList));
}
}
public void init() {
// Adding endpoints to "PageOps" group
addEndpointToGroup("PageOps", "remove-pages");
@@ -163,14 +181,12 @@ public class EndpointConfiguration {
// python
addEndpointToGroup("Python", "extract-image-scans");
addEndpointToGroup("Python", REMOVE_BLANKS);
addEndpointToGroup("Python", "html-to-pdf");
addEndpointToGroup("Python", "url-to-pdf");
addEndpointToGroup("Python", "pdf-to-img");
// openCV
addEndpointToGroup("OpenCV", "extract-image-scans");
addEndpointToGroup("OpenCV", REMOVE_BLANKS);
// LibreOffice
addEndpointToGroup("LibreOffice", "repair");
@@ -230,6 +246,17 @@ public class EndpointConfiguration {
addEndpointToGroup("Javascript", "sign");
addEndpointToGroup("Javascript", "compare");
addEndpointToGroup("Javascript", "adjust-contrast");
// Ghostscript dependent endpoints
addEndpointToGroup("Ghostscript", "compress-pdf");
addEndpointToGroup("Ghostscript", "pdf-to-pdfa");
// Weasyprint dependent endpoints
addEndpointToGroup("Weasyprint", "html-to-pdf");
addEndpointToGroup("Weasyprint", "url-to-pdf");
// Pdftohtml dependent endpoints
addEndpointToGroup("Pdftohtml", "pdf-to-html");
}
private void processEnvironmentConfigs() {
@@ -251,5 +278,9 @@ public class EndpointConfiguration {
}
}
public Set<String> getEndpointsForGroup(String group) {
return endpointGroups.getOrDefault(group, new HashSet<>());
}
private static final String REMOVE_BLANKS = "remove-blanks";
}

View File

@@ -0,0 +1,146 @@
package stirling.software.SPDF.config;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
@Configuration
@Slf4j
public class ExternalAppDepConfig {
@Autowired private EndpointConfiguration endpointConfiguration;
private boolean isCommandAvailable(String command) {
try {
ProcessBuilder processBuilder = new ProcessBuilder();
if (System.getProperty("os.name").toLowerCase().contains("windows")) {
processBuilder.command("where", command);
} else {
processBuilder.command("which", command);
}
Process process = processBuilder.start();
int exitCode = process.waitFor();
return exitCode == 0;
} catch (Exception e) {
log.debug("Error checking for command {}: {}", command, e.getMessage());
return false;
}
}
private final Map<String, List<String>> commandToGroupMapping =
new HashMap<>() {
{
put("gs", List.of("Ghostscript"));
put("soffice", List.of("LibreOffice"));
put("ocrmypdf", List.of("OCRmyPDF"));
put("weasyprint", List.of("Weasyprint"));
put("pdftohtml", List.of("Pdftohtml"));
}
};
private List<String> getAffectedFeatures(String group) {
return endpointConfiguration.getEndpointsForGroup(group).stream()
.map(endpoint -> formatEndpointAsFeature(endpoint))
.collect(Collectors.toList());
}
private String formatEndpointAsFeature(String endpoint) {
// First replace common terms
String feature = endpoint.replace("-", " ").replace("pdf", "PDF").replace("img", "image");
// Split into words and capitalize each word
return Arrays.stream(feature.split("\\s+"))
.map(word -> capitalizeWord(word))
.collect(Collectors.joining(" "));
}
private String capitalizeWord(String word) {
if (word.isEmpty()) {
return word;
}
if ("pdf".equalsIgnoreCase(word)) {
return "PDF";
}
return word.substring(0, 1).toUpperCase() + word.substring(1).toLowerCase();
}
private void checkDependencyAndDisableGroup(String command) {
boolean isAvailable = isCommandAvailable(command);
if (!isAvailable) {
List<String> affectedGroups = commandToGroupMapping.get(command);
if (affectedGroups != null) {
for (String group : affectedGroups) {
List<String> affectedFeatures = getAffectedFeatures(group);
endpointConfiguration.disableGroup(group);
log.warn(
"Missing dependency: {} - Disabling group: {} (Affected features: {})",
command,
group,
affectedFeatures != null && !affectedFeatures.isEmpty()
? String.join(", ", affectedFeatures)
: "unknown");
}
}
}
}
@PostConstruct
public void checkDependencies() {
// Check core dependencies
checkDependencyAndDisableGroup("gs");
checkDependencyAndDisableGroup("soffice");
checkDependencyAndDisableGroup("ocrmypdf");
checkDependencyAndDisableGroup("weasyprint");
checkDependencyAndDisableGroup("pdftohtml");
// Special handling for Python/OpenCV dependencies
boolean pythonAvailable = isCommandAvailable("python3") || isCommandAvailable("python");
if (!pythonAvailable) {
List<String> pythonFeatures = getAffectedFeatures("Python");
List<String> openCVFeatures = getAffectedFeatures("OpenCV");
endpointConfiguration.disableGroup("Python");
endpointConfiguration.disableGroup("OpenCV");
log.warn(
"Missing dependency: Python - Disabling Python features: {} and OpenCV features: {}",
String.join(", ", pythonFeatures),
String.join(", ", openCVFeatures));
} else {
// If Python is available, check for OpenCV
try {
ProcessBuilder processBuilder = new ProcessBuilder();
if (System.getProperty("os.name").toLowerCase().contains("windows")) {
processBuilder.command("python", "-c", "import cv2");
} else {
processBuilder.command("python3", "-c", "import cv2");
}
Process process = processBuilder.start();
int exitCode = process.waitFor();
if (exitCode != 0) {
List<String> openCVFeatures = getAffectedFeatures("OpenCV");
endpointConfiguration.disableGroup("OpenCV");
log.warn(
"OpenCV not available in Python - Disabling OpenCV features: {}",
String.join(", ", openCVFeatures));
}
} catch (Exception e) {
List<String> openCVFeatures = getAffectedFeatures("OpenCV");
endpointConfiguration.disableGroup("OpenCV");
log.warn(
"Error checking OpenCV: {} - Disabling OpenCV features: {}",
e.getMessage(),
String.join(", ", openCVFeatures));
}
}
endpointConfiguration.logDisabledEndpointsSummary();
}
}

View File

@@ -9,6 +9,7 @@ import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import io.micrometer.common.util.StringUtils;
import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.model.ApplicationProperties;
@@ -40,7 +41,7 @@ public class InitialSetup {
applicationProperties.getAutomaticallyGenerated().setKey(secretKey);
}
}
@PostConstruct
public void initLegalUrls() throws IOException {
// Initialize Terms and Conditions
@@ -59,7 +60,4 @@ public class InitialSetup {
applicationProperties.getLegal().setPrivacyPolicy(defaultPrivacyUrl);
}
}
}

View File

@@ -36,6 +36,8 @@ import org.springframework.security.saml2.provider.service.web.authentication.Sa
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
import org.springframework.security.web.csrf.CookieCsrfTokenRepository;
import org.springframework.security.web.csrf.CsrfTokenRequestAttributeHandler;
import org.springframework.security.web.savedrequest.NullRequestCache;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
@@ -94,6 +96,41 @@ public class SecurityConfiguration {
userAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
if (applicationProperties.getSecurity().getCsrfDisabled()) {
http.csrf(csrf -> csrf.disable());
} else {
CookieCsrfTokenRepository cookieRepo =
CookieCsrfTokenRepository.withHttpOnlyFalse();
CsrfTokenRequestAttributeHandler requestHandler =
new CsrfTokenRequestAttributeHandler();
requestHandler.setCsrfRequestAttributeName(null);
http.csrf(
csrf ->
csrf.ignoringRequestMatchers(
request -> {
String apiKey = request.getHeader("X-API-Key");
// If there's no API key, don't ignore CSRF
// (return false)
if (apiKey == null || apiKey.trim().isEmpty()) {
return false;
}
// Validate API key using existing UserService
try {
Optional<User> user =
userService.getUserByApiKey(apiKey);
// If API key is valid, ignore CSRF (return
// true)
// If API key is invalid, don't ignore CSRF
// (return false)
return user.isPresent();
} catch (Exception e) {
// If there's any error validating the API
// key, don't ignore CSRF
return false;
}
})
.csrfTokenRepository(cookieRepo)
.csrfTokenRequestHandler(requestHandler));
}
http.addFilterBefore(rateLimitingFilter(), UsernamePasswordAuthenticationFilter.class);
http.addFilterAfter(firstLoginFilter, UsernamePasswordAuthenticationFilter.class);
@@ -113,6 +150,7 @@ public class SecurityConfiguration {
logout.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutSuccessHandler(
new CustomLogoutSuccessHandler(applicationProperties))
.clearAuthentication(true)
.invalidateHttpSession(true) // Invalidate session
.deleteCookies("JSESSIONID", "remember-me"));
http.rememberMe(
@@ -203,7 +241,8 @@ public class SecurityConfiguration {
}
// Handle SAML
if (applicationProperties.getSecurity().isSaml2Activ() && applicationProperties.getSystem().getEnableAlphaFunctionality()) {
if (applicationProperties.getSecurity().isSaml2Activ()
&& applicationProperties.getSystem().getEnableAlphaFunctionality()) {
http.authenticationProvider(samlAuthenticationProvider());
http.saml2Login(
saml2 ->
@@ -222,6 +261,16 @@ public class SecurityConfiguration {
} else {
if (applicationProperties.getSecurity().getCsrfDisabled()) {
http.csrf(csrf -> csrf.disable());
} else {
CookieCsrfTokenRepository cookieRepo =
CookieCsrfTokenRepository.withHttpOnlyFalse();
CsrfTokenRequestAttributeHandler requestHandler =
new CsrfTokenRequestAttributeHandler();
requestHandler.setCsrfRequestAttributeName(null);
http.csrf(
csrf ->
csrf.csrfTokenRepository(cookieRepo)
.csrfTokenRequestHandler(requestHandler));
}
http.authorizeHttpRequests(authz -> authz.anyRequest().permitAll());
}

View File

@@ -45,7 +45,6 @@ public class UserService implements UserServiceInterface {
@Autowired DatabaseBackupInterface databaseBackupHelper;
// Handle OAUTH2 login and user auto creation.
public boolean processOAuth2PostLogin(String username, boolean autoCreateUser)
throws IllegalArgumentException, IOException {
@@ -360,8 +359,8 @@ public class UserService implements UserServiceInterface {
}
}
@Override
public long getTotalUsersCount() {
return userRepository.count();
}
@Override
public long getTotalUsersCount() {
return userRepository.count();
}
}

View File

@@ -1,48 +1,42 @@
package stirling.software.SPDF.config.security.saml2;
import java.io.ByteArrayInputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.interfaces.RSAPrivateKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;
import org.bouncycastle.util.io.pem.PemObject;
import org.bouncycastle.util.io.pem.PemReader;
import org.springframework.core.io.Resource;
import org.springframework.util.FileCopyUtils;
public class CertificateUtils {
public static X509Certificate readCertificate(Resource certificateResource) throws Exception {
String certificateString =
new String(
FileCopyUtils.copyToByteArray(certificateResource.getInputStream()),
StandardCharsets.UTF_8);
String certContent =
certificateString
.replace("-----BEGIN CERTIFICATE-----", "")
.replace("-----END CERTIFICATE-----", "")
.replaceAll("\\R", "")
.replaceAll("\\s+", "");
CertificateFactory cf = CertificateFactory.getInstance("X.509");
byte[] decodedCert = Base64.getDecoder().decode(certContent);
return (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(decodedCert));
try (PemReader pemReader =
new PemReader(
new InputStreamReader(
certificateResource.getInputStream(), StandardCharsets.UTF_8))) {
PemObject pemObject = pemReader.readPemObject();
byte[] decodedCert = pemObject.getContent();
CertificateFactory cf = CertificateFactory.getInstance("X.509");
return (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(decodedCert));
}
}
public static RSAPrivateKey readPrivateKey(Resource privateKeyResource) throws Exception {
String privateKeyString =
new String(
FileCopyUtils.copyToByteArray(privateKeyResource.getInputStream()),
StandardCharsets.UTF_8);
String privateKeyContent =
privateKeyString
.replace("-----BEGIN PRIVATE KEY-----", "")
.replace("-----END PRIVATE KEY-----", "")
.replaceAll("\\R", "")
.replaceAll("\\s+", "");
KeyFactory kf = KeyFactory.getInstance("RSA");
byte[] decodedKey = Base64.getDecoder().decode(privateKeyContent);
return (RSAPrivateKey) kf.generatePrivate(new PKCS8EncodedKeySpec(decodedKey));
try (PemReader pemReader =
new PemReader(
new InputStreamReader(
privateKeyResource.getInputStream(), StandardCharsets.UTF_8))) {
PemObject pemObject = pemReader.readPemObject();
byte[] decodedKey = pemObject.getContent();
return (RSAPrivateKey)
KeyFactory.getInstance("RSA")
.generatePrivate(new PKCS8EncodedKeySpec(decodedKey));
}
}
}

View File

@@ -4,6 +4,6 @@ public interface UserServiceInterface {
String getApiKeyForUser(String username);
String getCurrentUsername();
long getTotalUsersCount();
}

View File

@@ -1,10 +1,14 @@
package stirling.software.SPDF.controller.api.security;
import java.awt.Color;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.nio.file.Files;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
@@ -14,12 +18,39 @@ import java.security.UnrecoverableKeyException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Calendar;
import java.util.List;
import org.apache.commons.io.FileUtils;
import org.apache.pdfbox.examples.signature.CreateSignatureBase;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.PDResources;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.common.PDStream;
import org.apache.pdfbox.pdmodel.font.PDFont;
import org.apache.pdfbox.pdmodel.font.PDType1Font;
import org.apache.pdfbox.pdmodel.font.Standard14Fonts.FontName;
import org.apache.pdfbox.pdmodel.graphics.blend.BlendMode;
import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
import org.apache.pdfbox.pdmodel.graphics.state.PDExtendedGraphicsState;
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationWidget;
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAppearanceDictionary;
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAppearanceStream;
import org.apache.pdfbox.pdmodel.interactive.digitalsignature.PDSignature;
import org.apache.pdfbox.pdmodel.interactive.digitalsignature.SignatureOptions;
import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm;
import org.apache.pdfbox.pdmodel.interactive.form.PDField;
import org.apache.pdfbox.pdmodel.interactive.form.PDSignatureField;
import org.apache.pdfbox.util.Matrix;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.asn1.x500.RDN;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x500.style.BCStyle;
import org.bouncycastle.asn1.x500.style.IETFUtils;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openssl.PEMDecryptorProvider;
import org.bouncycastle.openssl.PEMEncryptedKeyPair;
@@ -35,6 +66,7 @@ import org.bouncycastle.pkcs.PKCSException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
@@ -62,6 +94,8 @@ public class CertSignController {
}
class CreateSignature extends CreateSignatureBase {
File logoFile;
public CreateSignature(KeyStore keystore, char[] pin)
throws KeyStoreException,
UnrecoverableKeyException,
@@ -69,6 +103,101 @@ public class CertSignController {
IOException,
CertificateException {
super(keystore, pin);
ClassPathResource resource = new ClassPathResource("static/images/signature.png");
try (InputStream is = resource.getInputStream()) {
logoFile = Files.createTempFile("signature", ".png").toFile();
FileUtils.copyInputStreamToFile(is, logoFile);
} catch (IOException e) {
logger.error("Failed to load image signature file");
throw e;
}
}
public InputStream createVisibleSignature(
PDDocument srcDoc, PDSignature signature, Integer pageNumber, Boolean showLogo)
throws IOException {
// modified from org.apache.pdfbox.examples.signature.CreateVisibleSignature2
try (PDDocument doc = new PDDocument()) {
PDPage page = new PDPage(srcDoc.getPage(pageNumber).getMediaBox());
doc.addPage(page);
PDAcroForm acroForm = new PDAcroForm(doc);
doc.getDocumentCatalog().setAcroForm(acroForm);
PDSignatureField signatureField = new PDSignatureField(acroForm);
PDAnnotationWidget widget = signatureField.getWidgets().get(0);
List<PDField> acroFormFields = acroForm.getFields();
acroForm.setSignaturesExist(true);
acroForm.setAppendOnly(true);
acroForm.getCOSObject().setDirect(true);
acroFormFields.add(signatureField);
PDRectangle rect = new PDRectangle(0, 0, 200, 50);
widget.setRectangle(rect);
// from PDVisualSigBuilder.createHolderForm()
PDStream stream = new PDStream(doc);
PDFormXObject form = new PDFormXObject(stream);
PDResources res = new PDResources();
form.setResources(res);
form.setFormType(1);
PDRectangle bbox = new PDRectangle(rect.getWidth(), rect.getHeight());
float height = bbox.getHeight();
form.setBBox(bbox);
PDFont font = new PDType1Font(FontName.TIMES_BOLD);
// from PDVisualSigBuilder.createAppearanceDictionary()
PDAppearanceDictionary appearance = new PDAppearanceDictionary();
appearance.getCOSObject().setDirect(true);
PDAppearanceStream appearanceStream = new PDAppearanceStream(form.getCOSObject());
appearance.setNormalAppearance(appearanceStream);
widget.setAppearance(appearance);
try (PDPageContentStream cs = new PDPageContentStream(doc, appearanceStream)) {
if (showLogo) {
cs.saveGraphicsState();
PDExtendedGraphicsState extState = new PDExtendedGraphicsState();
extState.setBlendMode(BlendMode.MULTIPLY);
extState.setNonStrokingAlphaConstant(0.5f);
cs.setGraphicsStateParameters(extState);
cs.transform(Matrix.getScaleInstance(0.08f, 0.08f));
PDImageXObject img =
PDImageXObject.createFromFileByExtension(logoFile, doc);
cs.drawImage(img, 100, 0);
cs.restoreGraphicsState();
}
// show text
float fontSize = 10;
float leading = fontSize * 1.5f;
cs.beginText();
cs.setFont(font, fontSize);
cs.setNonStrokingColor(Color.black);
cs.newLineAtOffset(fontSize, height - leading);
cs.setLeading(leading);
X509Certificate cert = (X509Certificate) getCertificateChain()[0];
// https://stackoverflow.com/questions/2914521/
X500Name x500Name = new X500Name(cert.getSubjectX500Principal().getName());
RDN cn = x500Name.getRDNs(BCStyle.CN)[0];
String name = IETFUtils.valueToString(cn.getFirst().getValue());
String date = signature.getSignDate().getTime().toString();
String reason = signature.getReason();
cs.showText("Signed by " + name);
cs.newLine();
cs.showText(date);
cs.newLine();
cs.showText(reason);
cs.endText();
}
ByteArrayOutputStream baos = new ByteArrayOutputStream();
doc.save(baos);
return new ByteArrayInputStream(baos.toByteArray());
}
}
}
@@ -97,7 +226,8 @@ public class CertSignController {
String reason = request.getReason();
String location = request.getLocation();
String name = request.getName();
Integer pageNumber = request.getPageNumber();
Integer pageNumber = request.getPageNumber() - 1;
Boolean showLogo = request.isShowLogo();
if (certType == null) {
throw new IllegalArgumentException("Cert type must be provided");
@@ -126,11 +256,19 @@ public class CertSignController {
throw new IllegalArgumentException("Invalid cert type: " + certType);
}
// TODO: page number
CreateSignature createSignature = new CreateSignature(ks, password.toCharArray());
ByteArrayOutputStream baos = new ByteArrayOutputStream();
sign(pdfDocumentFactory, pdf.getBytes(), baos, createSignature, name, location, reason);
sign(
pdfDocumentFactory,
pdf.getBytes(),
baos,
createSignature,
showSignature,
pageNumber,
name,
location,
reason,
showLogo);
return WebResponseUtils.boasToWebResponse(
baos,
Filenames.toSimpleFileName(pdf.getOriginalFilename()).replaceFirst("[.][^.]+$", "")
@@ -142,9 +280,12 @@ public class CertSignController {
byte[] input,
OutputStream output,
CreateSignature instance,
Boolean showSignature,
Integer pageNumber,
String name,
String location,
String reason) {
String reason,
Boolean showLogo) {
try (PDDocument doc = pdfDocumentFactory.load(input)) {
PDSignature signature = new PDSignature();
signature.setFilter(PDSignature.FILTER_ADOBE_PPKLITE);
@@ -154,7 +295,17 @@ public class CertSignController {
signature.setReason(reason);
signature.setSignDate(Calendar.getInstance());
doc.addSignature(signature, instance);
if (showSignature) {
SignatureOptions signatureOptions = new SignatureOptions();
signatureOptions.setVisualSignature(
instance.createVisibleSignature(doc, signature, pageNumber, showLogo));
signatureOptions.setPage(pageNumber);
doc.addSignature(signature, instance, signatureOptions);
} else {
doc.addSignature(signature, instance);
}
doc.saveIncremental(output);
} catch (Exception e) {
logger.error("exception", e);

View File

@@ -89,10 +89,9 @@ public class AccountWebController {
}
SAML2 saml2 = securityProps.getSaml2();
if (saml2 != null) {
if (saml2.getEnabled()) {
providerList.put("/saml2/authenticate/" + saml2.getRegistrationId(), "SAML 2");
}
if (securityProps.isSaml2Activ()
&& applicationProperties.getSystem().getEnableAlphaFunctionality()) {
providerList.put("/saml2/authenticate/" + saml2.getRegistrationId(), "SAML 2");
}
// Remove any null keys/values from the providerList
providerList
@@ -101,7 +100,8 @@ public class AccountWebController {
model.addAttribute("providerlist", providerList);
model.addAttribute("loginMethod", securityProps.getLoginMethod());
model.addAttribute("altLogin", securityProps.isAltLogin());
boolean altLogin = providerList.size() > 0 ? securityProps.isAltLogin() : false;
model.addAttribute("altLogin", altLogin);
model.addAttribute("currentPage", "login");
@@ -164,6 +164,17 @@ public class AccountWebController {
case "userIsDisabled":
erroroauth = "login.userIsDisabled";
break;
case "invalid_destination":
erroroauth = "login.invalid_destination";
break;
// Valid InResponseTo was not available from the validation context, unable to
// evaluate
case "invalid_in_response_to":
erroroauth = "login.invalid_in_response_to";
break;
case "not_authentication_provider_found":
erroroauth = "login.not_authentication_provider_found";
break;
default:
break;
}

View File

@@ -31,6 +31,10 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import io.swagger.v3.oas.annotations.Hidden;
import io.swagger.v3.oas.annotations.tags.Tag;
import stirling.software.SPDF.controller.api.pipeline.UserServiceInterface;
import stirling.software.SPDF.model.SignatureFile;
import stirling.software.SPDF.service.SignatureService;
@Controller
@Tag(name = "General", description = "General APIs")
public class GeneralWebController {
@@ -171,11 +175,28 @@ public class GeneralWebController {
return "split-pdfs";
}
private static final String SIGNATURE_BASE_PATH = "customFiles/static/signatures/";
private static final String ALL_USERS_FOLDER = "ALL_USERS";
@Autowired private SignatureService signatureService;
@Autowired(required = false)
private UserServiceInterface userService;
@GetMapping("/sign")
@Hidden
public String signForm(Model model) {
String username = "";
if (userService != null) {
username = userService.getCurrentUsername();
}
// Get signatures from both personal and ALL_USERS folders
List<SignatureFile> signatures = signatureService.getAvailableSignatures(username);
model.addAttribute("currentPage", "sign");
model.addAttribute("fonts", getFontNames());
model.addAttribute("signatures", signatures);
return "sign";
}

View File

@@ -0,0 +1,44 @@
package stirling.software.SPDF.controller.web;
import java.io.IOException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import stirling.software.SPDF.controller.api.pipeline.UserServiceInterface;
import stirling.software.SPDF.service.SignatureService;
@Controller
@RequestMapping("/api/v1/general/")
public class SignatureController {
@Autowired private SignatureService signatureService;
@Autowired(required = false)
private UserServiceInterface userService;
@GetMapping("/sign/{fileName}")
public ResponseEntity<byte[]> getSignature(@PathVariable(name = "fileName") String fileName)
throws IOException {
String username = "NON_SECURITY_USER";
if (userService != null) {
username = userService.getCurrentUsername();
}
// Verify access permission
if (!signatureService.hasAccessToFile(username, fileName)) {
return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
}
byte[] imageBytes = signatureService.getSignatureBytes(username, fileName);
return ResponseEntity.ok()
.contentType(MediaType.IMAGE_JPEG) // Adjust based on file type
.body(imageBytes);
}
}

View File

@@ -0,0 +1,11 @@
package stirling.software.SPDF.model;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class SignatureFile {
private String fileName;
private String category; // "Personal" or "Shared"
}

View File

@@ -50,4 +50,7 @@ public class SignPDFWithCertRequest extends PDFFile {
description =
"The page number where the signature should be visible. This is required if showSignature is set to true")
private Integer pageNumber;
@Schema(description = "Whether to visually show a signature logo along with the signature")
private boolean showLogo;
}

View File

@@ -29,12 +29,12 @@ public class PostHogService {
private final ApplicationProperties applicationProperties;
private final UserServiceInterface userService;
@Autowired
public PostHogService(
PostHog postHog,
@Qualifier("UUID") String uuid,
ApplicationProperties applicationProperties, @Autowired(required = false) UserServiceInterface userService) {
ApplicationProperties applicationProperties,
@Autowired(required = false) UserServiceInterface userService) {
this.postHog = postHog;
this.uniqueId = uuid;
this.applicationProperties = applicationProperties;
@@ -43,7 +43,7 @@ public class PostHogService {
}
private void captureSystemInfo() {
if (!Boolean.getBoolean(applicationProperties.getSystem().getEnableAnalytics())) {
if (!Boolean.parseBoolean(applicationProperties.getSystem().getEnableAnalytics())) {
return;
}
try {
@@ -54,7 +54,7 @@ public class PostHogService {
}
public void captureEvent(String eventName, Map<String, Object> properties) {
if (!Boolean.getBoolean(applicationProperties.getSystem().getEnableAnalytics())) {
if (!Boolean.parseBoolean(applicationProperties.getSystem().getEnableAnalytics())) {
return;
}
postHog.capture(uniqueId, eventName, properties);
@@ -137,10 +137,9 @@ public class PostHogService {
metrics.put("docker_metrics", getDockerMetrics());
}
metrics.put("application_properties", captureApplicationProperties());
if(userService != null) {
metrics.put("total_users_created", userService.getTotalUsersCount());
if (userService != null) {
metrics.put("total_users_created", userService.getTotalUsersCount());
}
} catch (Exception e) {

View File

@@ -0,0 +1,100 @@
package stirling.software.SPDF.service;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import org.springframework.stereotype.Service;
import org.thymeleaf.util.StringUtils;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.model.SignatureFile;
@Service
@Slf4j
public class SignatureService {
private static final String SIGNATURE_BASE_PATH = "customFiles/signatures/";
private static final String ALL_USERS_FOLDER = "ALL_USERS";
public boolean hasAccessToFile(String username, String fileName) throws IOException {
validateFileName(fileName);
// Check if file exists in user's personal folder or ALL_USERS folder
Path userPath = Paths.get(SIGNATURE_BASE_PATH, username, fileName);
Path allUsersPath = Paths.get(SIGNATURE_BASE_PATH, ALL_USERS_FOLDER, fileName);
return Files.exists(userPath) || Files.exists(allUsersPath);
}
public List<SignatureFile> getAvailableSignatures(String username) {
List<SignatureFile> signatures = new ArrayList<>();
// Get signatures from user's personal folder
if (!StringUtils.isEmptyOrWhitespace(username)) {
Path userFolder = Paths.get(SIGNATURE_BASE_PATH, username);
if (Files.exists(userFolder)) {
try {
signatures.addAll(getSignaturesFromFolder(userFolder, "Personal"));
} catch (IOException e) {
log.error("Error reading user signatures folder", e);
}
}
}
// Get signatures from ALL_USERS folder
Path allUsersFolder = Paths.get(SIGNATURE_BASE_PATH, ALL_USERS_FOLDER);
if (Files.exists(allUsersFolder)) {
try {
signatures.addAll(getSignaturesFromFolder(allUsersFolder, "Shared"));
} catch (IOException e) {
log.error("Error reading shared signatures folder", e);
}
}
return signatures;
}
private List<SignatureFile> getSignaturesFromFolder(Path folder, String category)
throws IOException {
return Files.list(folder)
.filter(path -> isImageFile(path))
.map(path -> new SignatureFile(path.getFileName().toString(), category))
.collect(Collectors.toList());
}
public byte[] getSignatureBytes(String username, String fileName) throws IOException {
validateFileName(fileName);
// First try user's personal folder
Path userPath = Paths.get(SIGNATURE_BASE_PATH, username, fileName);
if (Files.exists(userPath)) {
return Files.readAllBytes(userPath);
}
// Then try ALL_USERS folder
Path allUsersPath = Paths.get(SIGNATURE_BASE_PATH, ALL_USERS_FOLDER, fileName);
if (Files.exists(allUsersPath)) {
return Files.readAllBytes(allUsersPath);
}
throw new FileNotFoundException("Signature file not found");
}
private boolean isImageFile(Path path) {
String fileName = path.getFileName().toString().toLowerCase();
return fileName.endsWith(".jpg")
|| fileName.endsWith(".jpeg")
|| fileName.endsWith(".png")
|| fileName.endsWith(".gif");
}
private void validateFileName(String fileName) {
if (fileName.contains("..") || fileName.contains("/") || fileName.contains("\\")) {
throw new IllegalArgumentException("Invalid filename");
}
}
}

View File

@@ -1,13 +1,31 @@
package stirling.software.SPDF.utils;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferByte;
import java.awt.image.DataBufferInt;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import javax.imageio.ImageIO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.multipart.MultipartFile;
import com.drew.imaging.ImageMetadataReader;
import com.drew.imaging.ImageProcessingException;
import com.drew.metadata.Metadata;
import com.drew.metadata.MetadataException;
import com.drew.metadata.exif.ExifSubIFDDirectory;
public class ImageProcessingUtils {
private static final Logger logger = LoggerFactory.getLogger(PdfUtils.class);
static BufferedImage convertColorType(BufferedImage sourceImage, String colorType) {
BufferedImage convertedImage;
switch (colorType) {
@@ -59,4 +77,51 @@ public class ImageProcessingUtils {
return data;
}
}
public static double extractImageOrientation(InputStream is) throws IOException {
try {
Metadata metadata = ImageMetadataReader.readMetadata(is);
ExifSubIFDDirectory directory =
metadata.getFirstDirectoryOfType(ExifSubIFDDirectory.class);
if (directory == null) {
return 0;
}
int orientationTag = directory.getInt(ExifSubIFDDirectory.TAG_ORIENTATION);
switch (orientationTag) {
case 1:
return 0;
case 6:
return 90;
case 3:
return 180;
case 8:
return 270;
default:
logger.warn("Unknown orientation tag: {}", orientationTag);
return 0;
}
} catch (ImageProcessingException | MetadataException e) {
return 0;
}
}
public static BufferedImage applyOrientation(BufferedImage image, double orientation) {
if (orientation == 0) {
return image;
}
AffineTransform transform =
AffineTransform.getRotateInstance(
Math.toRadians(orientation),
image.getWidth() / 2.0,
image.getHeight() / 2.0);
AffineTransformOp op = new AffineTransformOp(transform, AffineTransformOp.TYPE_BILINEAR);
return op.filter(image, null);
}
public static BufferedImage loadImageWithExifOrientation(MultipartFile file)
throws IOException {
BufferedImage image = ImageIO.read(file.getInputStream());
double orientation = extractImageOrientation(file.getInputStream());
return applyOrientation(image, orientation);
}
}

View File

@@ -194,7 +194,8 @@ public class PdfUtils {
pdfDocument.close();
// Assumes the expectedPageSize is in the format "widthxheight", e.g. "595x842" for A4
// Assumes the expectedPageSize is in the format "widthxheight", e.g. "595x842"
// for A4
String[] dimensions = expectedPageSize.split("x");
float expectedPageWidth = Float.parseFloat(dimensions[0]);
float expectedPageHeight = Float.parseFloat(dimensions[1]);
@@ -407,7 +408,7 @@ public class PdfUtils {
addImageToDocument(doc, pdImage, fitOption, autoRotate);
}
} else {
BufferedImage image = ImageIO.read(file.getInputStream());
BufferedImage image = ImageProcessingUtils.loadImageWithExifOrientation(file);
BufferedImage convertedImage =
ImageProcessingUtils.convertColorType(image, colorType);
// Use JPEGFactory if it's JPEG since JPEG is lossy

View File

@@ -5,6 +5,7 @@ import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.List;
import java.util.Set;
@@ -53,7 +54,7 @@ public class CustomColorReplaceStrategy extends ReplaceAndInvertColorStrategy {
}
// Create a temporary file, with the original filename from the multipart file
File file = File.createTempFile("temp", getFileInput().getOriginalFilename());
File file = Files.createTempFile("temp", getFileInput().getOriginalFilename()).toFile();
// Transfer the content of the multipart file to the file
getFileInput().transferTo(file);

View File

@@ -6,6 +6,7 @@ import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import javax.imageio.ImageIO;
@@ -30,7 +31,7 @@ public class InvertFullColorStrategy extends ReplaceAndInvertColorStrategy {
public InputStreamResource replace() throws IOException {
// Create a temporary file, with the original filename from the multipart file
File file = File.createTempFile("temp", getFileInput().getOriginalFilename());
File file = Files.createTempFile("temp", getFileInput().getOriginalFilename()).toFile();
// Transfer the content of the multipart file to the file
getFileInput().transferTo(file);

View File

@@ -79,6 +79,8 @@ info=معلومات
pro=Pro
page=Page
pages=Pages
loading=Loading...
addToDoc=Add to Document
legal.privacy=Privacy Policy
legal.terms=Terms and Conditions
@@ -782,6 +784,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.
#BookToPDF
BookToPDF.title=الكتب والكوميكس إلى PDF
@@ -804,6 +809,11 @@ 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
#repair
@@ -1220,5 +1230,3 @@ splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for
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

View File

@@ -79,6 +79,8 @@ info=Информация
pro=Pro
page=Страница
pages=Страници
loading=Loading...
addToDoc=Add to Document
legal.privacy=Политика за поверителност
legal.terms=Правила и условия
@@ -782,6 +784,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.
#BookToPDF
BookToPDF.title=Книги и комикси в PDF
@@ -804,6 +809,11 @@ 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
#repair
@@ -1220,5 +1230,3 @@ splitByChapters.desc.2=Ниво на отметка: Изберете нивот
splitByChapters.desc.3=Включване на метаданни: Ако е отметнато, метаданните на оригиналния PDF ще бъдат включени във всеки разделен PDF.
splitByChapters.desc.4=Разрешаване на дубликати: Ако е отметнато, позволява множество отметки на една и съща страница за създаване на отделни PDF файлове.
splitByChapters.submit=Разделяне на PDF

View File

@@ -79,6 +79,8 @@ info=Info
pro=Pro
page=Page
pages=Pages
loading=Loading...
addToDoc=Add to Document
legal.privacy=Privacy Policy
legal.terms=Terms and Conditions
@@ -782,6 +784,9 @@ compare.highlightColor.2=Highlight Color 2:
compare.document.1=Document 1
compare.document.2=Document 2
compare.submit=Comparar
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.
#BookToPDF
BookToPDF.title=Books and Comics to PDF
@@ -804,6 +809,11 @@ sign.draw=Dibuixa la signatura
sign.text=Entrada de text
sign.clear=Esborrar
sign.add=Afegeix
sign.saved=Saved Signatures
sign.save=Save Signature
sign.personalSigs=Personal Signatures
sign.sharedSigs=Shared Signatures
sign.noSavedSigs=No saved signatures found
#repair
@@ -1220,5 +1230,3 @@ splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for
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

View File

@@ -79,6 +79,8 @@ info=Info
pro=Pro
page=Page
pages=Pages
loading=Loading...
addToDoc=Add to Document
legal.privacy=Privacy Policy
legal.terms=Terms and Conditions
@@ -782,6 +784,9 @@ compare.highlightColor.2=Highlight Color 2:
compare.document.1=Dokument 1
compare.document.2=Dokument 2
compare.submit=Porovnat
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.
#BookToPDF
BookToPDF.title=Knihy a komiksy do PDF
@@ -804,6 +809,11 @@ sign.draw=Nakreslit podpis
sign.text=Vstup textu
sign.clear=Vymazat
sign.add=Přidat
sign.saved=Saved Signatures
sign.save=Save Signature
sign.personalSigs=Personal Signatures
sign.sharedSigs=Shared Signatures
sign.noSavedSigs=No saved signatures found
#repair
@@ -1220,5 +1230,3 @@ splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for
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

View File

@@ -79,6 +79,8 @@ info=Info
pro=Pro
page=Page
pages=Pages
loading=Loading...
addToDoc=Add to Document
legal.privacy=Privacy Policy
legal.terms=Terms and Conditions
@@ -782,6 +784,9 @@ compare.highlightColor.2=Fremhævningsfarve 2:
compare.document.1=Dokument 1
compare.document.2=Dokument 2
compare.submit=Sammenlign
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.
#BookToPDF
BookToPDF.title=Bøger og Tegneserier til PDF
@@ -804,6 +809,11 @@ sign.draw=Tegn Underskrift
sign.text=Tekstinput
sign.clear=Ryd
sign.add=Tilføj
sign.saved=Saved Signatures
sign.save=Save Signature
sign.personalSigs=Personal Signatures
sign.sharedSigs=Shared Signatures
sign.noSavedSigs=No saved signatures found
#repair
@@ -1220,5 +1230,3 @@ splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for
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

View File

@@ -79,6 +79,8 @@ info=Informationen
pro=Pro
page=Page
pages=Pages
loading=Loading...
addToDoc=Add to Document
legal.privacy=Datenschutz
legal.terms=AGB
@@ -114,21 +116,21 @@ pipelineOptions.validateButton=Validieren
########################
# 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=Auf Pro-Version umsteigen
enterpriseEdition.warning=Diese Funktion ist nur für Pro-Nutzer verfügbar.
enterpriseEdition.yamlAdvert=Stirling-PDF Pro unterstützt YAML Konfigurationsdateien, SSO und weitere Funktionen.
enterpriseEdition.ssoAdvert=Suchen Sie weitere Funktionen in der Benutzerverwaltung? Steigen Sie auf die Pro-Version um
#################
# 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=Möchten Sie Stirling-PDF verbessern?
analytics.paragraph1=Stirling-PDF verfügt über Opt-in-Analytics, die uns helfen, das Produkt zu verbessern. Wir zeichnen keine persönlichen Informationen oder Dateiinhalte auf.
analytics.paragraph2=Bitte erwägen Sie die Analytics zu aktivieren, um Stirling-PDF beim Wachsen zu helfen und um unsere User besser zu verstehen.
analytics.enable=Analytics aktivieren
analytics.disable=Analytics deaktivieren
analytics.settings=Sie können die Einstellungen für die Analytics in der config/settings.yml Datei bearbeiten
#############
# NAVBAR #
@@ -392,7 +394,7 @@ certSign.tags=authentifizieren,pem,p12,offiziell,verschlüsseln
home.removeCertSign.title=Zertifikatsignatur entfernen
home.removeCertSign.desc=Zertifikatsignatur aus PDF entfernen
removeCertSign.tags=authentifizieren,PEM,P12,offiziell,entschlüsseln,decrypt
removeCertSign.tags=authentifizieren,PEM,P12,offiziell,entschlüsseln
home.pageLayout.title=Mehrseitiges Layout
home.pageLayout.desc=Mehrere Seiten eines PDF zu einer Seite zusammenführen
@@ -503,28 +505,28 @@ home.removeImagePdf.desc=Bild aus PDF entfernen, um die Dateigröße zu verringe
removeImagePdf.tags=bild entfernen,seitenoperationen,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.
splitPdfByChapters.tags=split,chapters,bookmarks,organize
home.splitPdfByChapters.title=PDF-Datei nach Kapiteln aufteilen
home.splitPdfByChapters.desc=Aufteilung einer PDF-Datei in mehrere Dateien auf Basis der Kapitelstruktur.
splitPdfByChapters.tags=aufteilen,kapitel,lesezeichen,organisieren
#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
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.title=Farbe Ersetzen-Invertieren
replace-color.header=Farb-PDF Ersetzen-Invertieren
home.replaceColorPdf.title=Farbe ersetzen und invertieren
home.replaceColorPdf.desc=Ersetzen Sie die Farbe des Texts und Hintergrund der PDF-Datei und invertieren Sie die komplette Farbe der PDF-Datei, um die Dateigröße zu reduzieren
replaceColorPdf.tags=Farbe ersetzen,Seiteneinstellungen,Backend,Serverseite
replace-color.selectText.1=Ersetzen oder Invertieren von Farboptionen
replace-color.selectText.2=Standard(Standardfarben mit hohem Kontrast)
replace-color.selectText.3=Benutzerdefiniert(Benutzerdefinierte Farben)
replace-color.selectText.4=Vollinvertierung(Invertierung aller Farben)
replace-color.selectText.5=Farboptionen mit hohem Kontrast
replace-color.selectText.6=Weißer Text auf schwarzem Hintergrund
replace-color.selectText.7=Schwarzer Text auf weißem Hintergrund
replace-color.selectText.8=Gelber Text auf schwarzem Hintergrund
replace-color.selectText.9=Grüner Text auf schwarzem Hintergrund
replace-color.selectText.10=Textfarbe auswählen
replace-color.selectText.11=Hintergrundfarbe auswählen
replace-color.submit=Ersetzen
@@ -551,9 +553,9 @@ login.oauth2AccessDenied=Zugriff abgelehnt
login.oauth2InvalidTokenResponse=Ungültige Token-Antwort
login.oauth2InvalidIdToken=Ungültiges ID-Token
login.userIsDisabled=Benutzer ist deaktiviert, die Anmeldung ist mit diesem Benutzernamen derzeit gesperrt. Bitte wenden Sie sich an den Administrator.
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=Sie sind bereits an
login.alreadyLoggedIn2=Geräten angemeldet. Bitte melden Sie sich dort ab und versuchen es dann erneut.
login.toManySessions=Sie haben zu viele aktive Sitzungen
#auto-redact
autoRedact.title=Automatisch zensieren/schwärzen
@@ -703,7 +705,7 @@ autoSplitPDF.header=PDF automatisch teilen
autoSplitPDF.description=Drucken Sie, fügen Sie ein, scannen Sie, laden Sie hoch und lassen Sie uns Ihre Dokumente automatisch trennen. Kein manuelles Sortieren erforderlich.
autoSplitPDF.selectText.1=Drucken Sie einige Trennblätter aus (schwarz/weiß ist ausreichend).
autoSplitPDF.selectText.2=Scannen Sie alle Dokumente auf einmal, indem Sie das Trennblatt zwischen die Dokumente einlegen.
autoSplitPDF.selectText.3=Laden Sie die einzelne große gescannte PDF-Datei hoch und überlassen Sie Stirling PDF den Rest.
autoSplitPDF.selectText.3=Laden Sie die einzelne große gescannte PDF-Datei hoch und überlassen Sie Stirling-PDF den Rest.
autoSplitPDF.selectText.4=Trennseiten werden automatisch erkannt und entfernt, so dass ein sauberes Enddokument garantiert ist.
autoSplitPDF.formPrompt=PDF mit Stirling-PDF Seitentrennern hochladen:
autoSplitPDF.duplexMode=Duplex-Modus (Scannen von Vorder- und Rückseite)
@@ -782,6 +784,9 @@ compare.highlightColor.2=Highlight-Farbe 2:
compare.document.1=Dokument 1
compare.document.2=Dokument 2
compare.submit=Vergleichen
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.
#BookToPDF
BookToPDF.title=Bücher und Comics zu PDF
@@ -804,6 +809,11 @@ sign.draw=Signatur zeichnen
sign.text=Texteingabe
sign.clear=Leeren
sign.add=Signieren
sign.saved=Saved Signatures
sign.save=Save Signature
sign.personalSigs=Personal Signatures
sign.sharedSigs=Shared Signatures
sign.noSavedSigs=No saved signatures found
#repair
@@ -1210,15 +1220,13 @@ removeImage.removeImage=Bild entfernen
removeImage.submit=Bild entfernen
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 nach Kapiteln aufteilen
splitByChapters.header=PDF nach Kapiteln aufteilen
splitByChapters.bookmarkLevel=Lesezeichenebene
splitByChapters.includeMetadata=Metadaten einschließen
splitByChapters.allowDuplicates=Duplikate erlauben
splitByChapters.desc.1=Dieses Werkzeug teilt eine PDF-Datei auf der Grundlage ihrer Kapitelstruktur in mehrere PDF-Dateien auf.
splitByChapters.desc.2=Lesezeichenebene: Wählen Sie die Ebene der Lesezeichen, die für die Aufteilung verwendet werden soll (0 für die erste Ebene, 1 für die zweite Ebene usw.).
splitByChapters.desc.3=Metadaten einschließen: Wenn diese Option aktiviert ist, werden die Metadaten der ursprünglichen PDF-Datei in jede aufgeteilte PDF-Datei übernommen.
splitByChapters.desc.4=Duplikate erlauben: Wenn diese Option aktiviert ist, können mehrere Lesezeichen auf derselben Seite separate PDF Dateien erstellen.
splitByChapters.submit=PDF teilen

View File

@@ -79,6 +79,8 @@ info=Info
pro=Pro
page=Page
pages=Pages
loading=Loading...
addToDoc=Add to Document
legal.privacy=Privacy Policy
legal.terms=Terms and Conditions
@@ -782,6 +784,9 @@ compare.highlightColor.2=Highlight Color 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.
#BookToPDF
BookToPDF.title=Books και Comics σε PDF
@@ -804,6 +809,11 @@ 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
#repair
@@ -1220,5 +1230,3 @@ splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for
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

View File

@@ -79,6 +79,8 @@ info=Info
pro=Pro
page=Page
pages=Pages
loading=Loading...
addToDoc=Add to Document
legal.privacy=Privacy Policy
legal.terms=Terms and Conditions
@@ -748,6 +750,7 @@ certSign.showSig=Show Signature
certSign.reason=Reason
certSign.location=Location
certSign.name=Name
certSign.showLogo=Show Logo
certSign.submit=Sign PDF
@@ -782,6 +785,9 @@ compare.highlightColor.2=Highlight Color 2:
compare.document.1=Document 1
compare.document.2=Document 2
compare.submit=Compare
compare.complex.message=One or both of the provided documents are large files, accuracy of comparison may be reduced
compare.large.file.message=One or Both of the provided documents are too large to process
compare.no.text.message=One or both of the selected PDFs have no text content. Please choose PDFs with text for comparison.
#BookToPDF
BookToPDF.title=Books and Comics to PDF
@@ -804,6 +810,11 @@ sign.draw=Draw Signature
sign.text=Text Input
sign.clear=Clear
sign.add=Add
sign.saved=Saved Signatures
sign.save=Save Signature
sign.personalSigs=Personal Signatures
sign.sharedSigs=Shared Signatures
sign.noSavedSigs=No saved signatures found
#repair
@@ -1220,5 +1231,3 @@ splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for
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

View File

@@ -79,6 +79,8 @@ info=Info
pro=Pro
page=Page
pages=Pages
loading=Loading...
addToDoc=Add to Document
legal.privacy=Privacy Policy
legal.terms=Terms and Conditions
@@ -748,6 +750,7 @@ certSign.showSig=Show Signature
certSign.reason=Reason
certSign.location=Location
certSign.name=Name
certSign.showLogo=Show Logo
certSign.submit=Sign PDF
@@ -782,6 +785,9 @@ compare.highlightColor.2=Highlight Color 2:
compare.document.1=Document 1
compare.document.2=Document 2
compare.submit=Compare
compare.complex.message=One or both of the provided documents are large files, accuracy of comparison may be reduced
compare.large.file.message=One or Both of the provided documents are too large to process
compare.no.text.message=One or both of the selected PDFs have no text content. Please choose PDFs with text for comparison.
#BookToPDF
BookToPDF.title=Books and Comics to PDF
@@ -804,6 +810,11 @@ sign.draw=Draw Signature
sign.text=Text Input
sign.clear=Clear
sign.add=Add
sign.saved=Saved Signatures
sign.save=Save Signature
sign.personalSigs=Personal Signatures
sign.sharedSigs=Shared Signatures
sign.noSavedSigs=No saved signatures found
#repair
@@ -1220,5 +1231,3 @@ splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for
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

View File

@@ -3,8 +3,8 @@
###########
# 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
addPageNumbers.fontSize=Tamaño de Letra
addPageNumbers.fontName=Nombre de Letra
pdfPrompt=Seleccionar PDF(s)
multiPdfPrompt=Seleccionar PDFs (2+)
multiPdfDropPrompt=Seleccione (o arrastre y suelte) todos los PDFs que quiera
@@ -50,7 +50,7 @@ WorkInProgess=Tarea en progreso, puede no funcionar o ralentizarse; ¡por favor,
poweredBy=Desarrollado por
yes=
no=No
changedCredsMessage=Se cambiaron las credenciales!
changedCredsMessage=¡Se cambiaron las credenciales!
notAuthenticatedMessage=Usuario no autentificado.
userNotFoundMessage=Usuario no encontrado.
incorrectPasswordMessage=La contraseña actual no es correcta.
@@ -77,14 +77,16 @@ color=Color
sponsor=Patrocinador
info=Info
pro=Pro
page=Page
pages=Pages
page=Página
pages=Páginas
loading=Loading...
addToDoc=Add to Document
legal.privacy=Privacy Policy
legal.terms=Terms and Conditions
legal.accessibility=Accessibility
legal.cookie=Cookie Policy
legal.impressum=Impressum
legal.privacy=Política de Privacidad
legal.terms=Términos y Condiciones
legal.accessibility=Accesibilidad
legal.cookie=Política de Cookies
legal.impressum=Impresión
###############
# Pipeline #
@@ -114,21 +116,21 @@ pipelineOptions.validateButton=Validar
########################
# 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=Actualiza a Pro
enterpriseEdition.warning=Esta característica está únicamente disponible para usuarios Pro.
enterpriseEdition.yamlAdvert=Stirling PDF Pro soporta configuración de ficheros YAML y otras características SSO.
enterpriseEdition.ssoAdvert=¿Busca más funciones de administración de usuarios? Consulte 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=¿Quieres mejorar Stirling PDF?
analytics.paragraph1=Stirling PDF ha optado por analíticas para ayudarnos a mejorar el producto. No rastreamos ninguna información personal ni contenido de archivos.
analytics.paragraph2=Considere habilitar analíticas para ayudar a Stirling-PDF a crecer y permitirnos comprender mejor a nuestros usuarios.
analytics.enable=Habilitar analíticas
analytics.disable=Deshabilitar analíticas
analytics.settings=Puede cambiar la configuración de analíticas en el archivo config/settings.yml
#############
# NAVBAR #
@@ -243,7 +245,7 @@ database.fileNotFound=Archivo no encontrado
database.fileNullOrEmpty=El archivo no debe ser nulo o vacío.
database.failedImportFile=Archivo de importación fallido
session.expired=Your session has expired. Please refresh the page and try again.
session.expired=Tu sesión ha caducado. Actualice la página e inténtelo de nuevo.
#############
# HOME-PAGE #
@@ -392,7 +394,7 @@ certSign.tags=autentificar,PEM,P12,oficial,encriptar
home.removeCertSign.title=Quitar signo de certificado
home.removeCertSign.desc=Eliminar firma de certificado de PDF
removeCertSign.tags=authenticate,PEM,P12,official,decrypt
removeCertSign.tags=autenticar,PEM,P12,oficial,desencriptar
home.pageLayout.title=Diseño de varias páginas
home.pageLayout.desc=Unir varias páginas de un documento PDF en una sola página
@@ -503,28 +505,28 @@ home.removeImagePdf.desc=Eliminar imagen del PDF> para reducir el tamaño de arc
removeImagePdf.tags=Eliminar imagen,Operaciones de página,Back end,lado del servidor
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=Dividir PDF por capítulos
home.splitPdfByChapters.desc=Divida un PDF en varios archivos según su estructura de capítulos.
splitPdfByChapters.tags=dividir,capítulos,marcadores,organizar
#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
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.title=Reemplazar-Invertir-Color
replace-color.header=Reemplazar-Invertir Color en PDF
home.replaceColorPdf.title=Reemplazar e Invertir Color
home.replaceColorPdf.desc=Reemplaza el color del texto y el fondo en el PDF e invierte el color completo del PDF para reducir el tamaño del archivo
replaceColorPdf.tags=Reemplazar Color,Operaciones de Página,Back end,Lado del servidor
replace-color.selectText.1=Opciones para Reemplazar o Invertir color
replace-color.selectText.2=Predeterminado (Colores de alto contraste predeterminados)
replace-color.selectText.3=Personalizado (Colores personalizados)
replace-color.selectText.4=Invertir Completo (Invertir todos los colores)
replace-color.selectText.5=Opciones de color de alto contraste
replace-color.selectText.6=Texto blanco sobre fondo negro
replace-color.selectText.7=Texto negro sobre fondo blanco
replace-color.selectText.8=Texto amarillo sobre fondo negro
replace-color.selectText.9=Texto verde sobre fondo negro
replace-color.selectText.10=Elegir Color de Texto
replace-color.selectText.11=Elegir Color de Fondo
replace-color.submit=Reemplazar
@@ -551,9 +553,9 @@ login.oauth2AccessDenied=Acceso denegado
login.oauth2InvalidTokenResponse=Respuesta de token no válida
login.oauth2InvalidIdToken=Token de identificación no válido
login.userIsDisabled=El usuario está desactivado, actualmente el acceso está bloqueado para ese nombre de usuario. Por favor, póngase en contacto con el administrador.
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=Ya has iniciado sesión en
login.alreadyLoggedIn2=dispositivos. Cierra sesión en los dispositivos y vuelve a intentarlo.
login.toManySessions=Tienes demasiadas sesiones activas
#auto-redact
autoRedact.title=Auto Redactar
@@ -782,6 +784,9 @@ compare.highlightColor.2=Color resaltado 2:
compare.document.1=Documento 1
compare.document.2=Documento 2
compare.submit=Comparar
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.
#BookToPDF
BookToPDF.title=Libros y Cómics a PDF
@@ -804,6 +809,11 @@ sign.draw=Dibujar firma
sign.text=Entrada de texto
sign.clear=Borrar
sign.add=Agregar
sign.saved=Saved Signatures
sign.save=Save Signature
sign.personalSigs=Personal Signatures
sign.sharedSigs=Shared Signatures
sign.noSavedSigs=No saved signatures found
#repair
@@ -887,7 +897,7 @@ addImage.title=Añadir imagen
addImage.header=Añadir imagen de PDF
addImage.everyPage=¿Todas las páginas?
addImage.upload=Añadir imagen
addImage.submit=Añadir imagen
addImage.submit=Enviar imagen
#merge
@@ -1210,15 +1220,13 @@ removeImage.removeImage=Eliminar imagen
removeImage.submit=Eliminar imagen
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=Dividir PDF por Capítulos
splitByChapters.header=Dividir PDF por Capítulos
splitByChapters.bookmarkLevel=Nivel de Marcador
splitByChapters.includeMetadata=Incluir Metadatos
splitByChapters.allowDuplicates=Permitir Duplicados
splitByChapters.desc.1=Esta herramienta divide un archivo PDF en múltiples archivos PDF según su estructura de capítulos.
splitByChapters.desc.2=Nivel de Marcador: Elige el nivel de marcadores para dividir (0 para el nivel superior, 1 para el segundo nivel, etc.).
splitByChapters.desc.3=Incluir Metadatos: Si está seleccionado, los metadatos del PDF original se incluirán en cada PDF dividido.
splitByChapters.desc.4=Permitir Duplicados: Si está seleccionado, permite que múltiples marcadores en la misma página creen archivos PDF separados.
splitByChapters.submit=Dividir PDF

View File

@@ -79,6 +79,8 @@ info=Info
pro=Pro
page=Page
pages=Pages
loading=Loading...
addToDoc=Add to Document
legal.privacy=Privacy Policy
legal.terms=Terms and Conditions
@@ -782,6 +784,9 @@ compare.highlightColor.2=Highlight Color 2:
compare.document.1=1. dokumentua
compare.document.2=2. dokumentua
compare.submit=Konparatu
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.
#BookToPDF
BookToPDF.title=Books and Comics to PDF
@@ -804,6 +809,11 @@ sign.draw=Marraztu sinadura
sign.text=Testua sartzea
sign.clear=Garbitu
sign.add=Gehitu
sign.saved=Saved Signatures
sign.save=Save Signature
sign.personalSigs=Personal Signatures
sign.sharedSigs=Shared Signatures
sign.noSavedSigs=No saved signatures found
#repair
@@ -1220,5 +1230,3 @@ splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for
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

View File

@@ -3,14 +3,14 @@
###########
# 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
addPageNumbers.fontSize=Taille de Police
addPageNumbers.fontName=Nom de la Police
pdfPrompt=Sélectionnez le(s) PDF
multiPdfPrompt=Sélectionnez les PDF
multiPdfDropPrompt=Sélectionnez (ou glissez-déposez) tous les PDF dont vous avez besoin
imgPrompt=Choisir une image
genericSubmit=Envoyer
processTimeWarning=Attention, ce processus peut prendre jusquà une minute en fonction de la taille du fichier.
processTimeWarning=Attention, ce processus peut prendre jusqu'à une minute en fonction de la taille du fichier.
pageOrderPrompt=Ordre des pages (entrez une liste de numéros de page séparés par des virgules ou des fonctions telles que 2n+1) :
pageSelectionPrompt=Sélection des pages (entrez une liste de numéros de page séparés par des virgules ou des fonctions telles que 2n+1) :
goToPage=Aller
@@ -23,7 +23,7 @@ close=Fermer
filesSelected=fichiers sélectionnés
noFavourites=Aucun favori ajouté
downloadComplete=Téléchargement terminé
bored=Marre dattendre ?
bored=Marre d'attendre ?
alphabet=Alphabet
downloadPdf=Télécharger le PDF
text=Texte
@@ -34,9 +34,9 @@ sizes.small=Petit
sizes.medium=Moyen
sizes.large=Grand
sizes.x-large=Très grand
error.pdfPassword=Le document PDF est protégé par un mot de passe qui na pas été fourni ou était incorrect
error.pdfPassword=Le document PDF est protégé par un mot de passe qui n'a pas été fourni ou était incorrect
delete=Supprimer
username=Nom dutilisateur
username=Nom d'utilisateur
password=Mot de passe
welcome=Bienvenue
property=Propriété
@@ -54,12 +54,12 @@ changedCredsMessage=Les identifiants ont été mis à jour !
notAuthenticatedMessage=Utilisateur non authentifié.
userNotFoundMessage=Utilisateur non trouvé.
incorrectPasswordMessage=Le mot de passe actuel est incorrect.
usernameExistsMessage=Le nouveau nom dutilisateur existe déjà.
invalidUsernameMessage=Nom dutilisateur invalide, le nom dutilisateur ne peut contenir que des lettres, des chiffres et les caractères spéciaux suivants @._+- ou doit être une adresse e-mail valide.
usernameExistsMessage=Le nouveau nom d'utilisateur existe déjà.
invalidUsernameMessage=Nom d'utilisateur invalide, le nom d'utilisateur ne peut contenir que des lettres, des chiffres et les caractères spéciaux suivants @._+- ou doit être une adresse e-mail valide.
invalidPasswordMessage=The password must not be empty and must not have spaces at the beginning or end.
confirmPasswordErrorMessage=New Password and Confirm New Password must match.
deleteCurrentUserMessage=Impossible de supprimer lutilisateur actuellement connecté.
deleteUsernameExistsMessage=Le nom dutilisateur nexiste pas et ne peut pas être supprimé.
deleteCurrentUserMessage=Impossible de supprimer l'utilisateur actuellement connecté.
deleteUsernameExistsMessage=Le nom d'utilisateur n'existe pas et ne peut pas être supprimé.
downgradeCurrentUserMessage=Impossible de rétrograder le rôle de l'utilisateur actuel.
disabledCurrentUserMessage=The current user cannot be disabled
downgradeCurrentUserLongMessage=Impossible de rétrograder le rôle de l'utilisateur actuel. Par conséquent, l'utilisateur actuel ne sera pas affiché.
@@ -68,7 +68,7 @@ userAlreadyExistsWebMessage=L'utilisateur existe déjà en tant qu'utilisateur W
error=Erreur
oops=Oups !
help=Aide
goHomepage=Aller à la page daccueil
goHomepage=Aller à la page d'accueil
joinDiscord=Rejoignez notre serveur Discord
seeDockerHub=Consulter le Docker Hub
visitGithub=Visiter le dépôt Github
@@ -79,12 +79,14 @@ info=Info
pro=Pro
page=Page
pages=Pages
loading=Loading...
addToDoc=Add to Document
legal.privacy=Privacy Policy
legal.terms=Terms and Conditions
legal.accessibility=Accessibility
legal.cookie=Cookie Policy
legal.impressum=Impressum
legal.privacy=Politique de Confidentialité
legal.terms=Conditions Générales
legal.accessibility=Accessibilité
legal.cookie=Politique des Cookies
legal.impressum=Mentions Légales
###############
# Pipeline #
@@ -114,21 +116,21 @@ pipelineOptions.validateButton=Valider
########################
# 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=Passer à Pro
enterpriseEdition.warning=Cette fonctionnalité est uniquement disponible pour les utilisateurs Pro.
enterpriseEdition.yamlAdvert=Stirling PDF Pro prend en charge les fichiers de configuration YAML et d'autres fonctionnalités SSO.
enterpriseEdition.ssoAdvert=Vous cherchez plus de fonctionnalités de gestion des utilisateurs ? Découvrez 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=Souhaitez-vous améliorer Stirling PDF ?
analytics.paragraph1=Stirling PDF utilise des analyses volontaires pour nous aider à améliorer le produit. Nous ne suivons aucune information personnelle ni le contenu des fichiers.
analytics.paragraph2=Veuillez envisager d'activer les analyses pour aider Stirling-PDF à se développer et pour nous permettre de mieux comprendre nos utilisateurs.
analytics.enable=Activer les analyses
analytics.disable=Désactiver les analyses
analytics.settings=Vous pouvez modifier les paramètres des analyses dans le fichier config/settings.yml
#############
# NAVBAR #
@@ -153,8 +155,8 @@ navbar.sections.popular=Populaire
settings.title=Paramètres
settings.update=Mise à jour disponible
settings.updateAvailable={0} est la version actuellement installée. Une nouvelle version ({1}) est disponible.
settings.appVersion=Version de lapplication :
settings.downloadOption.title=Choisissez loption de téléchargement (pour les téléchargements à fichier unique non ZIP) :
settings.appVersion=Version de l'application :
settings.downloadOption.title=Choisissez l'option de téléchargement (pour les téléchargements à fichier unique non ZIP) :
settings.downloadOption.1=Ouvrir dans la même fenêtre
settings.downloadOption.2=Ouvrir dans une nouvelle fenêtre
settings.downloadOption.3=Télécharger le fichier
@@ -168,7 +170,7 @@ settings.cacheInputs.help=Permet de stocker les entrées précédemment utilisé
changeCreds.title=Modifiez vos identifiants
changeCreds.header=Mettez à jour vos identifiants de connexion
changeCreds.changePassword=Vous utilisez les identifiants de connexion par défaut. Veuillez saisir un nouveau mot de passe
changeCreds.newUsername=Nouveau nom dutilisateur
changeCreds.newUsername=Nouveau nom d'utilisateur
changeCreds.oldPassword=Mot de passe actuel
changeCreds.newPassword=Nouveau mot de passe
changeCreds.confirmNewPassword=Confirmer le nouveau mot de passe
@@ -178,10 +180,10 @@ changeCreds.submit=Soumettre les modifications
account.title=Paramètres du compte
account.accountSettings=Paramètres du compte
account.adminSettings=Paramètres dadministration Voir et ajouter des utilisateurs
account.adminSettings=Paramètres d'administration Voir et ajouter des utilisateurs
account.userControlSettings=Contrôle des paramètres des utilisateurs
account.changeUsername=Modifier le nom dutilisateur
account.newUsername=Nouveau nom dutilisateur
account.changeUsername=Modifier le nom d'utilisateur
account.newUsername=Nouveau nom d'utilisateur
account.password=Mot de passe de confirmation
account.oldPassword=Ancien mot de passe
account.newPassword=Nouveau mot de passe
@@ -210,11 +212,11 @@ adminUserSettings.roles=Rôles
adminUserSettings.role=Rôle
adminUserSettings.actions=Actions
adminUserSettings.apiUser=Utilisateur API limité
adminUserSettings.extraApiUser=Utilisateur limité supplémentaire de lAPI
adminUserSettings.extraApiUser=Utilisateur limité supplémentaire de l'API
adminUserSettings.webOnlyUser=Utilisateur Web uniquement
adminUserSettings.demoUser=Demo User (Paramètres par défaut)
adminUserSettings.internalApiUser=Utilisateur de l'API interne
adminUserSettings.forceChange=Forcer lutilisateur à changer son nom dutilisateur/mot de passe lors de la connexion
adminUserSettings.forceChange=Forcer l'utilisateur à changer son nom d'utilisateur/mot de passe lors de la connexion
adminUserSettings.submit=Ajouter
adminUserSettings.changeUserRole=Changer le rôle de l'utilisateur
adminUserSettings.authenticated=Authentifié
@@ -282,7 +284,7 @@ home.pdfToImage.desc=Convertissez un PDF en image (PNG, JPEG, GIF).
pdfToImage.tags=conversion,img,jpg,image,photo
home.pdfOrganiser.title=Organiser
home.pdfOrganiser.desc=Supprimez ou réorganisez les pages dans nimporte quel ordre.
home.pdfOrganiser.desc=Supprimez ou réorganisez les pages dans n'importe quel ordre.
pdfOrganiser.tags=organiser,recto-verso,duplex,even,odd,sort,move
@@ -292,7 +294,7 @@ addImage.tags=img,jpg,image,photo
home.watermark.title=Ajouter un filigrane
home.watermark.desc=Ajoutez un filigrane personnalisé à votre PDF.
watermark.tags=texte,filigrane,label,propriété,droit dauteur,marque déposée,img,jpg,image,photo,copyright,trademark
watermark.tags=texte,filigrane,label,propriété,droit d'auteur,marque déposée,img,jpg,image,photo,copyright,trademark
home.permissions.title=Modifier les permissions
home.permissions.desc=Modifiez les permissions de votre PDF.
@@ -321,16 +323,16 @@ home.changeMetadata.desc=Modifiez, supprimez ou ajoutez des métadonnées à un
changeMetadata.tags=métadonnées,titre,auteur,date,création,heure,éditeur,statistiques,title,author,date,creation,time,publisher,producer,stats,metadata
home.fileToPDF.title=Fichier en PDF
home.fileToPDF.desc=Convertissez presque nimporte quel fichier en PDF (DOCX, PNG, XLS, PPT, TXT, etc.).
home.fileToPDF.desc=Convertissez presque n'importe quel fichier en PDF (DOCX, PNG, XLS, PPT, TXT, etc.).
fileToPDF.tags=convertion,transformation,format,document,image,slide,texte,conversion,office,docs,word,excel,powerpoint
home.ocr.title=OCR / Nettoyage des numérisations
home.ocr.desc=Utilisez lOCR pour analyser et détecter le texte des images dun PDF et le rajouter en tant que tel.
home.ocr.desc=Utilisez l'OCR pour analyser et détecter le texte des images d'un PDF et le rajouter en tant que tel.
ocr.tags=ocr,reconnaissance,texte,image,numérisation,scan,read,identify,detection,editable
home.extractImages.title=Extraire les images
home.extractImages.desc=Extrayez toutes les images dun PDF et enregistrez-les dans un ZIP.
home.extractImages.desc=Extrayez toutes les images d'un PDF et enregistrez-les dans un ZIP.
extractImages.tags=image,photo,save,archive,zip,capture,grab
home.pdfToPDFA.title=PDF en PDF/A
@@ -359,7 +361,7 @@ home.PDFToXML.desc=Convertissez un PDF au format XML.
PDFToXML.tags=xml,extraction de données,contenu structuré,interopérabilité,data-extraction,structured-content,interop,transformation,convert
home.ScannerImageSplit.title=Diviser les photos numérisées
home.ScannerImageSplit.desc=Divisez plusieurs photos à partir dune photo ou dun PDF.
home.ScannerImageSplit.desc=Divisez plusieurs photos à partir d'une photo ou d'un PDF.
ScannerImageSplit.tags=diviser,détecter automatiquement,numériser,separate,auto-detect,scans,multi-photo,organize
home.sign.title=Signer
@@ -367,7 +369,7 @@ home.sign.desc=Ajoutez une signature au PDF avec un dessin, du texte ou une imag
sign.tags=signer,authorize,initials,drawn-signature,text-sign,image-signature
home.flatten.title=Rendre inerte
home.flatten.desc=Supprimez tous les éléments et formulaires interactifs dun PDF.
home.flatten.desc=Supprimez tous les éléments et formulaires interactifs d'un PDF.
flatten.tags=inerte,static,deactivate,non-interactive,streamline
home.repair.title=Réparer
@@ -375,11 +377,11 @@ home.repair.desc=Essayez de réparer un PDF corrompu ou cassé.
repair.tags=réparer,restaurer,corriger,récupérer,fix,restore,correction,recover
home.removeBlanks.title=Supprimer les pages vierges
home.removeBlanks.desc=Détectez et supprimez les pages vierges dun PDF.
home.removeBlanks.desc=Détectez et supprimez les pages vierges d'un PDF.
removeBlanks.tags=pages vierges,supprimer,nettoyer,cleanup,streamline,non-content,organize
home.removeAnnotations.title=Supprimer les annotations
home.removeAnnotations.desc=Supprimer tous les commentaires/annotations dun PDF.
home.removeAnnotations.desc=Supprimer tous les commentaires/annotations d'un PDF.
removeAnnotations.tags=commentaires,supprimer,annotations,highlight,notes,markup,remove
home.compare.title=Comparer
@@ -395,11 +397,11 @@ home.removeCertSign.desc=Supprimez la signature par certificat d'un PDF
removeCertSign.tags=signer,chiffrer,certificat,authenticate,PEM,P12,official,decrypt
home.pageLayout.title=Fusionner des pages
home.pageLayout.desc=Fusionnez plusieurs pages dun PDF en une seule.
home.pageLayout.desc=Fusionnez plusieurs pages d'un PDF en une seule.
pageLayout.tags=fusionner,merge,composite,single-view,organize
home.scalePages.title=Ajuster léchelle ou la taille
home.scalePages.desc=Modifiez la taille ou léchelle dune page et/ou de son contenu.
home.scalePages.title=Ajuster l'échelle ou la taille
home.scalePages.desc=Modifiez la taille ou l'échelle d'une page et/ou de son contenu.
scalePages.tags=ajuster,redimensionner,resize,modify,dimension,adapt
home.pipeline.title=Pipeline
@@ -415,7 +417,7 @@ home.auto-rename.desc=Renommez automatiquement un fichier PDF en fonction de son
auto-rename.tags=renommer,détection automatique,réétiqueter,auto-detect,header-based,organize,relabel
home.adjust-contrast.title=Ajuster les couleurs
home.adjust-contrast.desc=Ajustez le contraste, la saturation et la luminosité dun PDF.
home.adjust-contrast.desc=Ajustez le contraste, la saturation et la luminosité d'un PDF.
adjust-contrast.tags=ajuster,couleurs,amélioration,color-correction,tune,modify,enhance
home.crop.title=Redimensionner
@@ -431,16 +433,16 @@ home.sanitizePdf.desc=Supprimez les scripts et autres éléments des PDF.
sanitizePdf.tags=assainir,sécurisé,clean,secure,safe,remove-threats
home.URLToPDF.title=URL en PDF
home.URLToPDF.desc=Convertissez nimporte quelle URL http(s) en PDF.
home.URLToPDF.desc=Convertissez n'importe quelle URL http(s) en PDF.
URLToPDF.tags=pdf,contenu Web,save-page,web-to-doc,archive
home.HTMLToPDF.title=HTML en PDF
home.HTMLToPDF.desc=Convertissez nimporte quel fichier HTML ou ZIP en PDF.
home.HTMLToPDF.desc=Convertissez n'importe quel fichier HTML ou ZIP en PDF.
HTMLToPDF.tags=html,markup,contenu Web,transformation,convert
home.MarkdownToPDF.title=Markdown en PDF
home.MarkdownToPDF.desc=Convertissez nimporte quel fichier Markdown en PDF.
home.MarkdownToPDF.desc=Convertissez n'importe quel fichier Markdown en PDF.
MarkdownToPDF.tags=markdown,markup,contenu Web,transformation,convert
@@ -464,11 +466,11 @@ home.showJS.desc=Recherche et affiche tout JavaScript injecté dans un PDF.
showJS.tags=JS
home.autoRedact.title=Caviarder automatiquement
home.autoRedact.desc=Caviardez automatiquement les informations sensibles dun PDF.
home.autoRedact.desc=Caviardez automatiquement les informations sensibles d'un PDF.
autoRedact.tags=caviarder,redact,auto
home.tableExtraxt.title=PDF en CSV
home.tableExtraxt.desc=Extrait les tableaux dun PDF et les transforme en CSV.
home.tableExtraxt.desc=Extrait les tableaux d'un PDF et les transforme en CSV.
tableExtraxt.tags=CSV,Table Extraction,extract,convert
@@ -478,15 +480,15 @@ autoSizeSplitPDF.tags=pdf,split,document,organization
home.overlay-pdfs.title=Incrustation de PDF
home.overlay-pdfs.desc=Incrustation dun PDF sur un autre PDF.
home.overlay-pdfs.desc=Incrustation d'un PDF sur un autre PDF.
overlay-pdfs.tags=Overlay,incrustation
home.split-by-sections.title=Séparer un PDF en sections
home.split-by-sections.desc=Diviser chaque page dun PDF en sections horizontales/verticales plus petites.
home.split-by-sections.desc=Diviser chaque page d'un PDF en sections horizontales/verticales plus petites.
split-by-sections.tags=Sections,Diviser,Section Split, Divide, Customize
home.AddStampRequest.title=Ajouter un tampon sur un PDF
home.AddStampRequest.desc=Ajouter un texte ou limage dun tampon à un emplacement défini.
home.AddStampRequest.desc=Ajouter un texte ou l'image d'un tampon à un emplacement défini.
AddStampRequest.tags=Tampon,Ajouter,Stamp,Add image,center image,Watermark,PDF,Embed,Customize
@@ -508,23 +510,23 @@ home.splitPdfByChapters.desc=Séparez un PDF en fichiers multiples en fonction d
splitPdfByChapters.tags=séparer,chapitres,split,chapters,bookmarks,organize
#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
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.title=Remplacer-Inverser-Couleur
replace-color.header=Remplacer-Inverser Couleur PDF
home.replaceColorPdf.title=Remplacer et Inverser Couleur
home.replaceColorPdf.desc=Remplacer la couleur pour le texte et l'arrière-plan dans le PDF et inverser la couleur complète du PDF pour réduire la taille du fichier
replaceColorPdf.tags=Remplacer Couleur,Opérations de Page,Back-end,Côté serveur
replace-color.selectText.1=Options de Remplacement ou d'Inversion de Couleur
replace-color.selectText.2=Par défaut (Couleurs à fort contraste par défaut)
replace-color.selectText.3=Personnalisé (Couleurs personnalisées)
replace-color.selectText.4=Inversion complète (Inverser toutes les couleurs)
replace-color.selectText.5=Options de couleur à fort contraste
replace-color.selectText.6=Texte blanc sur fond noir
replace-color.selectText.7=Texte noir sur fond blanc
replace-color.selectText.8=Texte jaune sur fond noir
replace-color.selectText.9=Texte vert sur fond noir
replace-color.selectText.10=Choisir la couleur du texte
replace-color.selectText.11=Choisir la couleur de l'arrière-plan
replace-color.submit=Remplacer
@@ -538,7 +540,7 @@ login.title=Connexion
login.header=Connexion
login.signin=Connexion
login.rememberme=Se souvenir de moi
login.invalid=Nom dutilisateur ou mot de passe invalide.
login.invalid=Nom d'utilisateur ou mot de passe invalide.
login.locked=Votre compte a été verrouillé.
login.signinTitle=Veuillez vous connecter
login.ssoSignIn=Se connecter via l'authentification unique
@@ -550,10 +552,10 @@ login.oauth2invalidRequest=Requête invalide
login.oauth2AccessDenied=Accès refusé
login.oauth2InvalidTokenResponse=Réponse contenant le jeton est invalide
login.oauth2InvalidIdToken=Jeton d'identification invalide
login.userIsDisabled=User is deactivated, login is currently blocked with this username. Please contact the administrator.
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.userIsDisabled=L'utilisateur est désactivé, la connexion est actuellement bloquée avec ce nom d'utilisateur. Veuillez contacter l'administrateur.
login.alreadyLoggedIn=Vous êtes déjà connecté sur
login.alreadyLoggedIn2=appareils. Veuillez vous déconnecter des appareils et réessayer.
login.toManySessions=Vous avez trop de sessions actives.
#auto-redact
autoRedact.title=Caviarder automatiquement
@@ -617,15 +619,15 @@ HTMLToPDF.header=HTML en PDF
HTMLToPDF.help=Accepte les fichiers HTML et les ZIP contenant du HTML, du CSS, des images, etc. (requis).
HTMLToPDF.submit=Convertir
HTMLToPDF.credit=Utilise WeasyPrint.
HTMLToPDF.zoom=Niveau de zoom pour laffichage du site web.
HTMLToPDF.zoom=Niveau de zoom pour l'affichage du site web.
HTMLToPDF.pageWidth=Largeur de la page en centimètres. (Vide par défaut)
HTMLToPDF.pageHeight=Hauteur de la page en centimètres. (Vide par défaut)
HTMLToPDF.marginTop=Marge supérieure de la page en millimètres. (Vide par défaut)
HTMLToPDF.marginBottom=Marge inférieure de la page en millimètres. (Vide par défaut)
HTMLToPDF.marginLeft=Marge gauche de la page en millimètres. (Vide par défaut)
HTMLToPDF.marginRight=Marge droite de la page en millimètres. (Vide par défaut)
HTMLToPDF.printBackground=Restituer limage de fond des sites web.
HTMLToPDF.defaultHeader=Activer lentête par défaut (Nom et numéro de page)
HTMLToPDF.printBackground=Restituer l'image de fond des sites web.
HTMLToPDF.defaultHeader=Activer l'entête par défaut (Nom et numéro de page)
HTMLToPDF.cssMediaType=Modifier le type de média CSS de la page.
HTMLToPDF.none=Aucun
HTMLToPDF.print=Imprimer
@@ -703,7 +705,7 @@ autoSplitPDF.header=Séparer automatiquement les pages
autoSplitPDF.description=Imprimez, insérez, numérisez, téléchargez et laissez-nous séparer automatiquement vos documents. Aucun travail de tri manuel nécessaire.
autoSplitPDF.selectText.1=Imprimez des feuilles de séparation ci-dessous (le mode noir et blanc convient).
autoSplitPDF.selectText.2=Numérisez tous vos documents en une seule fois en insérant les feuilles intercalaires entre eux.
autoSplitPDF.selectText.3=Téléchargez le fichier PDF numérisé et laissez Stirling PDF soccuper du reste.
autoSplitPDF.selectText.3=Téléchargez le fichier PDF numérisé et laissez Stirling PDF s'occuper du reste.
autoSplitPDF.selectText.4=Les feuilles de séparation sont automatiquement détectées et supprimées, garantissant un document final soigné.
autoSplitPDF.formPrompt=PDF contenant des feuilles de séparation de Stirling PDF :
autoSplitPDF.duplexMode=Mode recto-verso
@@ -725,11 +727,11 @@ pageLayout.submit=Fusionner
#scalePages
scalePages.title=Ajuster la taille ou léchelle
scalePages.header=Ajuster la taille ou léchelle
scalePages.pageSize=Taille dune page du document
scalePages.title=Ajuster la taille ou l'échelle
scalePages.header=Ajuster la taille ou l'échelle
scalePages.pageSize=Taille d'une page du document
scalePages.keepPageSize=Original Size
scalePages.scaleFactor=Niveau de zoom (recadrage) dune page
scalePages.scaleFactor=Niveau de zoom (recadrage) d'une page
scalePages.submit=Ajuster
@@ -737,10 +739,10 @@ scalePages.submit=Ajuster
certSign.title=Signer avec un certificat
certSign.header=Signer avec un certificat (Travail en cours)
certSign.selectPDF=PDF à signer
certSign.jksNote=Note: Si votre type de certificat nest pas listé ci-dessous, merci de le convertir en fichier Java Keystore (.jks) en utilisant loutil en ligne de commande keytool. Puis choisissez loption Fichier .jks ci-dessous.
certSign.jksNote=Note: Si votre type de certificat n'est pas listé ci-dessous, merci de le convertir en fichier Java Keystore (.jks) en utilisant l'outil en ligne de commande keytool. Puis choisissez l'option Fichier .jks ci-dessous.
certSign.selectKey=Fichier de clé privée (format PKCS#8, peut être .pem ou .der)
certSign.selectCert=Fichier de certificat (format X.509, peut être .pem ou .der)
certSign.selectP12=Fichier keystore de clés PKCS#12 (.p12 ou .pfx) (facultatif, sil nest fourni, il doit contenir votre clé privée et votre certificat)
certSign.selectP12=Fichier keystore de clés PKCS#12 (.p12 ou .pfx) (facultatif, s'il n'est fourni, il doit contenir votre clé privée et votre certificat)
certSign.selectJKS=Sélectionner votre fichier Java Keystore File (.jks or .keystore):
certSign.certType=Type de certificat
certSign.password=Mot de passe keystore ou clé privée le cas échéant
@@ -752,10 +754,10 @@ certSign.submit=Signer
#removeCertSign
removeCertSign.title=Remove Certificate Signature
removeCertSign.header=Remove the digital certificate from the PDF
removeCertSign.selectPDF=Select a PDF file:
removeCertSign.submit=Remove Signature
removeCertSign.title=Supprimer la Signature de Certificat
removeCertSign.header=Supprimer le certificat numérique du PDF
removeCertSign.selectPDF=Sélectionnez un fichier PDF :
removeCertSign.submit=Supprimer la Signature
#removeBlanks
@@ -782,6 +784,9 @@ compare.highlightColor.2=Highlight Color 2:
compare.document.1=Document 1
compare.document.2=Document 2
compare.submit=Comparer
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.
#BookToPDF
BookToPDF.title=Livres et BD vers PDF
@@ -804,6 +809,11 @@ sign.draw=Dessiner une signature
sign.text=Saisir de texte
sign.clear=Effacer
sign.add=Ajouter
sign.saved=Saved Signatures
sign.save=Save Signature
sign.personalSigs=Personal Signatures
sign.sharedSigs=Shared Signatures
sign.noSavedSigs=No saved signatures found
#repair
@@ -821,9 +831,9 @@ flatten.submit=Rendre inerte
#ScannerImageSplit
ScannerImageSplit.selectText.1=Seuil de rotation
ScannerImageSplit.selectText.2=Définit langle absolu minimum requis pour la rotation de limage (par défaut : 10).
ScannerImageSplit.selectText.2=Définit l'angle absolu minimum requis pour la rotation de l'image (par défaut : 10).
ScannerImageSplit.selectText.3=Tolérance
ScannerImageSplit.selectText.4=Détermine la plage de variation de couleur autour de la couleur darrière-plan estimée (par défaut : 20).
ScannerImageSplit.selectText.4=Détermine la plage de variation de couleur autour de la couleur d'arrière-plan estimée (par défaut : 20).
ScannerImageSplit.selectText.5=Surface minimale
ScannerImageSplit.selectText.6=Définit la surface minimale pour une photo (par défaut : 8000).
ScannerImageSplit.selectText.7=Surface de contour minimale
@@ -839,24 +849,24 @@ ocr.header=OCR (Reconnaissance optique de caractères) / Nettoyage des numérisa
ocr.selectText.1=Langues à détecter dans le PDF (celles listées sont celles actuellement détectées)
ocr.selectText.2=Produire un fichier texte contenant le texte détecté à côté du PDF
ocr.selectText.3=Corriger les pages qui ont été numérisées à un angle oblique en les remettant en place
ocr.selectText.4=Nettoyer la page afin quil soit moins probable que lOCR trouve du texte dans le bruit de fond, sans modifier la sortie
ocr.selectText.5=Nettoyer la page afin quil soit moins probable que lOCR trouve du texte dans le bruit de fond, en modifiant la sortie
ocr.selectText.6=Ignorer les pages contenant du texte interactif, nanalyser que les pages qui sont des images
ocr.selectText.7=Forcer lOCR, analyser chaque page et supprimer tous les éléments de texte dorigine
ocr.selectText.4=Nettoyer la page afin qu'il soit moins probable que l'OCR trouve du texte dans le bruit de fond, sans modifier la sortie
ocr.selectText.5=Nettoyer la page afin qu'il soit moins probable que l'OCR trouve du texte dans le bruit de fond, en modifiant la sortie
ocr.selectText.6=Ignorer les pages contenant du texte interactif, n'analyser que les pages qui sont des images
ocr.selectText.7=Forcer l'OCR, analyser chaque page et supprimer tous les éléments de texte d'origine
ocr.selectText.8=Normal (génère une erreur si le PDF contient du texte)
ocr.selectText.9=Paramètres additionnels
ocr.selectText.10=Mode OCR
ocr.selectText.11=Supprimer les images après lOCR (Supprime TOUTES les images, utile uniquement si elles font partie de létape de conversion)
ocr.selectText.11=Supprimer les images après l'OCR (Supprime TOUTES les images, utile uniquement si elles font partie de l'étape de conversion)
ocr.selectText.12=Type de rendu (avancé)
ocr.help=Veuillez lire cette documentation pour savoir comment utiliser lOCR pour dautres langues ou une utilisation hors Docker :
ocr.credit=Ce service utilise OCRmyPDF et Tesseract pour lOCR.
ocr.help=Veuillez lire cette documentation pour savoir comment utiliser l'OCR pour d'autres langues ou une utilisation hors Docker :
ocr.credit=Ce service utilise OCRmyPDF et Tesseract pour l'OCR.
ocr.submit=Traiter
#extractImages
extractImages.title=Extraire les images
extractImages.header=Extraire les images
extractImages.selectText=Format dimage dans lequel convertir les images extraites
extractImages.selectText=Format d'image dans lequel convertir les images extraites
extractImages.allowDuplicates=Save duplicate images
extractImages.submit=Extraire
@@ -872,10 +882,10 @@ fileToPDF.submit=Convertir
#compress
compress.title=Compresser un PDF
compress.header=Compresser un PDF (lorsque cest possible!)
compress.credit=Ce service utilise Ghostscript pour la compression et loptimisation des PDF.
compress.header=Compresser un PDF (lorsque c'est possible!)
compress.credit=Ce service utilise Ghostscript pour la compression et l'optimisation des PDF.
compress.selectText.1=Mode manuel de 1 à 4
compress.selectText.2=Niveau doptimisation
compress.selectText.2=Niveau d'optimisation
compress.selectText.3=4 (terrible pour les images textuelles)
compress.selectText.4=Mode automatique ajuste automatiquement la qualité pour obtenir le PDF à la taille exacte
compress.selectText.5=Taille PDF attendue (par exemple, 25MB, 10,8MB, 25KB)
@@ -960,9 +970,9 @@ split.submit=Diviser
imageToPDF.title=Image en PDF
imageToPDF.header=Image en PDF
imageToPDF.submit=Convertir
imageToPDF.selectLabel=Options dajustement de limage
imageToPDF.selectLabel=Options d'ajustement de l'image
imageToPDF.fillPage=Remplir la page
imageToPDF.fitDocumentToImage=Ajuster la page à limage
imageToPDF.fitDocumentToImage=Ajuster la page à l'image
imageToPDF.maintainAspectRatio=Maintenir les proportions
imageToPDF.selectText.2=Rotation automatique du PDF
imageToPDF.selectText.3=Logique multi-fichiers (uniquement activée si vous travaillez avec plusieurs images)
@@ -973,11 +983,11 @@ imageToPDF.selectText.5=Convertir en PDF séparés
#pdfToImage
pdfToImage.title=Image en PDF
pdfToImage.header=Image en PDF
pdfToImage.selectText=Format dimage
pdfToImage.selectText=Format d'image
pdfToImage.singleOrMultiple=Type de résultat
pdfToImage.single=Une seule grande image
pdfToImage.multi=Plusieurs images
pdfToImage.colorType=Type dimpression
pdfToImage.colorType=Type d'impression
pdfToImage.color=Couleur
pdfToImage.grey=Niveaux de gris
pdfToImage.blackwhite=Noir et blanc (peut engendrer une perte de données !)
@@ -989,21 +999,21 @@ pdfToImage.info=Python is not installed. Required for WebP conversion.
addPassword.title=Ajouter un mot de passe
addPassword.header=Ajouter un mot de passe
addPassword.selectText.1=PDF à chiffrer
addPassword.selectText.2=Mot de passe de lutilisateur
addPassword.selectText.2=Mot de passe de l'utilisateur
addPassword.selectText.3=Longueur de la clé de chiffrement
addPassword.selectText.4=Les valeurs plus élevées sont plus fortes, mais les valeurs plus faibles ont une meilleure compatibilité.
addPassword.selectText.5=Autorisations à définir (utilisation recommandée avec le mot de passe du propriétaire)
addPassword.selectText.6=Empêcher lassemblage du document
addPassword.selectText.7=Empêcher lextraction de contenu
addPassword.selectText.8=Empêcher lextraction pour laccessibilité
addPassword.selectText.6=Empêcher l'assemblage du document
addPassword.selectText.7=Empêcher l'extraction de contenu
addPassword.selectText.8=Empêcher l'extraction pour l'accessibilité
addPassword.selectText.9=Empêcher de remplir les formulaires
addPassword.selectText.10=Empêcher la modification
addPassword.selectText.11=Empêcher la modification des annotations
addPassword.selectText.12=Empêcher limpression
addPassword.selectText.13=Empêcher limpression des différents formats
addPassword.selectText.12=Empêcher l'impression
addPassword.selectText.13=Empêcher l'impression des différents formats
addPassword.selectText.14=Mot de passe du propriétaire
addPassword.selectText.15=Restreint ce qui peut être fait avec le document une fois quil est ouvert (non pris en charge par tous les lecteurs).
addPassword.selectText.16=Restreint louverture du document lui-même.
addPassword.selectText.15=Restreint ce qui peut être fait avec le document une fois qu'il est ouvert (non pris en charge par tous les lecteurs).
addPassword.selectText.16=Restreint l'ouverture du document lui-même.
addPassword.submit=Chiffrer
@@ -1031,14 +1041,14 @@ permissions.header=Modifier les permissions
permissions.warning=Attention, pour que ces permissions soient immuables il est recommandé de les paramétrer avec un mot de passe via la page Ajouter un mot de passe.
permissions.selectText.1=Sélectionnez le PDF
permissions.selectText.2=Permissions à définir
permissions.selectText.3=Empêcher lassemblage du document
permissions.selectText.4=Empêcher lextraction de contenu
permissions.selectText.5=Empêcher lextraction pour laccessibilité
permissions.selectText.3=Empêcher l'assemblage du document
permissions.selectText.4=Empêcher l'extraction de contenu
permissions.selectText.5=Empêcher l'extraction pour l'accessibilité
permissions.selectText.6=Empêcher de remplir les formulaires
permissions.selectText.7=Empêcher la modification
permissions.selectText.8=Empêcher la modification des annotations
permissions.selectText.9=Empêcher limpression
permissions.selectText.10=Empêcher limpression des différents formats
permissions.selectText.9=Empêcher l'impression
permissions.selectText.10=Empêcher l'impression des différents formats
permissions.submit=Modifier
@@ -1063,7 +1073,7 @@ changeMetadata.keywords=Mots clés
changeMetadata.modDate=Date de modification (yyyy/MM/dd HH:mm:ss)
changeMetadata.producer=Producteur
changeMetadata.subject=Sujet
changeMetadata.trapped=Recouvrement (technique dimpression)
changeMetadata.trapped=Recouvrement (technique d'impression)
changeMetadata.selectText.4=Autres métadonnées
changeMetadata.selectText.5=Ajouter une entrée de métadonnées personnalisée
changeMetadata.submit=Modifier
@@ -1138,13 +1148,13 @@ split-by-size-or-count.submit=Séparer
overlay-pdfs.header=Incrustation de PDF
overlay-pdfs.baseFile.label=Sélectionner le fichier PDF de base
overlay-pdfs.overlayFiles.label=Sélectionner les fichiers PDF à superposer
overlay-pdfs.mode.label=Sélectionner le mode dincrustation
overlay-pdfs.mode.label=Sélectionner le mode d'incrustation
overlay-pdfs.mode.sequential=Superposition séquentielle
overlay-pdfs.mode.interleaved=Superposition entrelacée
overlay-pdfs.mode.fixedRepeat=Superposition à répétition fixe
overlay-pdfs.counts.label=Nombre de superpositions (pour le mode de répétition fixe)
overlay-pdfs.counts.placeholder=Compteurs (séparés par des virgules, exemple : 2,3,1)
overlay-pdfs.position.label=Définir la position de lincrustation
overlay-pdfs.position.label=Définir la position de l'incrustation
overlay-pdfs.position.foreground=Premier plan
overlay-pdfs.position.background=Arrière-plan
overlay-pdfs.submit=Soumettre
@@ -1178,47 +1188,45 @@ licenses.version=Version
licenses.license=Licence
#survey
survey.nav=Survey
survey.title=Stirling-PDF Survey
survey.description=Stirling-PDF has no tracking so we want to hear from our users to improve 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.please=Please consider taking our survey!
survey.disabled=(Survey popup will be disabled in following updates but available at foot of page)
survey.button=Take Survey
survey.dontShowAgain=Don't show again
survey.nav=Enquête
survey.title=Enquête Stirling-PDF
survey.description=Stirling-PDF n'a pas de suivi, donc nous voulons entendre nos utilisateurs pour améliorer Stirling-PDF !
survey.changes=Stirling-PDF a changé depuis la dernière enquête ! Pour en savoir plus, veuillez consulter notre article de blog ici :
survey.changes2=Avec ces changements, nous obtenons un soutien commercial rémunéré et un financement
survey.please=Veuillez envisager de répondre à notre enquête !
survey.disabled=(La fenêtre contextuelle de l'enquête sera désactivée dans les mises à jour suivantes mais sera disponible en bas de page)
survey.button=Répondre à l'enquête
survey.dontShowAgain=Ne plus afficher
#error
error.sorry=Désolé pour ce problème !
error.needHelp=Besoin daide / Vous avez trouvé un problème ?
error.contactTip=Si vous avez encore des problèmes, nhésitez pas à nous contacter pour obtenir de laide. Vous pouvez soumettre un ticket sur notre page GitHub ou nous contacter via Discord :
error.404.head=404 - Page non trouvée | oups on sest foiré !
error.needHelp=Besoin d'aide / Vous avez trouvé un problème ?
error.contactTip=Si vous avez encore des problèmes, n'hésitez pas à nous contacter pour obtenir de l'aide. Vous pouvez soumettre un ticket sur notre page GitHub ou nous contacter via Discord :
error.404.head=404 - Page non trouvée | oups on s'est foiré !
error.404.1=Nous ne parvenons pas à trouver la page que vous recherchez.
error.404.2=Quelque chose na pas fonctionné
error.404.2=Quelque chose n'a pas fonctionné
error.github=Créer un ticket sur GitHub
error.showStack=Afficher la Stack Trace
error.copyStack=Copier la Stack Trace
error.githubSubmit=GitHub - Créer un ticket
error.discordSubmit=Discord - Poster un message de demande dassistance
error.discordSubmit=Discord - Poster un message de demande d'assistance
#remove-image
removeImage.title=Remove image
removeImage.header=Remove image
removeImage.removeImage=Remove image
removeImage.submit=Remove image
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
removeImage.title=Supprimer l'image
removeImage.header=Supprimer l'image
removeImage.removeImage=Supprimer l'image
removeImage.submit=Supprimer l'image
splitByChapters.title=Diviser un PDF par Chapitres
splitByChapters.header=Diviser un PDF par Chapitres
splitByChapters.bookmarkLevel=Niveau de Signet
splitByChapters.includeMetadata=Inclure les Métadonnées
splitByChapters.allowDuplicates=Autoriser les Doublons
splitByChapters.desc.1=Cet outil divise un fichier PDF en plusieurs PDF en fonction de sa structure de chapitres.
splitByChapters.desc.2=Niveau de Signet : Choisissez le niveau de signets à utiliser pour la division (0 pour le niveau supérieur, 1 pour le deuxième niveau, etc...).
splitByChapters.desc.3=Inclure les Métadonnées : Si coché, les métadonnées du PDF original seront incluses dans chaque PDF divisé.
splitByChapters.desc.4=Autoriser les Doublons : Si coché, permet à plusieurs signets sur la même page de créer des PDF séparés.
splitByChapters.submit=Diviser le PDF

View File

@@ -79,6 +79,8 @@ info=Eolas
pro=Pro
page=Page
pages=Pages
loading=Loading...
addToDoc=Add to Document
legal.privacy=Privacy Policy
legal.terms=Terms and Conditions
@@ -782,6 +784,9 @@ compare.highlightColor.2=Dath Aibhsithe 2:
compare.document.1=Doiciméad 1
compare.document.2=Doiciméad 2
compare.submit=Déan comparáid idir
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.
#BookToPDF
BookToPDF.title=Leabhair agus comics a PDF
@@ -804,6 +809,11 @@ sign.draw=Tarraing Síniú
sign.text=Ionchur Téacs
sign.clear=Glan
sign.add=Cuir
sign.saved=Saved Signatures
sign.save=Save Signature
sign.personalSigs=Personal Signatures
sign.sharedSigs=Shared Signatures
sign.noSavedSigs=No saved signatures found
#repair
@@ -1220,5 +1230,3 @@ splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for
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

View File

@@ -79,6 +79,8 @@ info=Info
pro=Pro
page=पृष्ठ
pages=पृष्ठों
loading=Loading...
addToDoc=Add to Document
legal.privacy=Privacy Policy
legal.terms=Terms and Conditions
@@ -782,6 +784,9 @@ compare.highlightColor.2=Highlight Color 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.
#BookToPDF
BookToPDF.title=Books and Comics to PDF
@@ -804,6 +809,11 @@ 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
#repair
@@ -1220,5 +1230,3 @@ splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for
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

View File

@@ -79,6 +79,8 @@ info=Info
pro=Pro
page=Page
pages=Pages
loading=Loading...
addToDoc=Add to Document
legal.privacy=Privacy Policy
legal.terms=Terms and Conditions
@@ -782,6 +784,9 @@ compare.highlightColor.2=Highlight Color 2:
compare.document.1=Dokument 1
compare.document.2=Dokument 2
compare.submit=Uporedi
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.
#BookToPDF
BookToPDF.title=Knjige i stripovi u PDF
@@ -804,6 +809,11 @@ sign.draw=Nacrtaj potpis
sign.text=Tekstualni unos
sign.clear=Obriši
sign.add=Dodaj
sign.saved=Saved Signatures
sign.save=Save Signature
sign.personalSigs=Personal Signatures
sign.sharedSigs=Shared Signatures
sign.noSavedSigs=No saved signatures found
#repair
@@ -1220,5 +1230,3 @@ splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for
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

View File

@@ -79,6 +79,8 @@ info=Info
pro=Pro
page=Page
pages=Pages
loading=Loading...
addToDoc=Add to Document
legal.privacy=Privacy Policy
legal.terms=Terms and Conditions
@@ -782,6 +784,9 @@ compare.highlightColor.2=Highlight Color 2:
compare.document.1=Dokumentum 1
compare.document.2=Dokumentum 2
compare.submit=Összehasonlítás
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.
#BookToPDF
BookToPDF.title=Books and Comics to PDF
@@ -804,6 +809,11 @@ sign.draw=Aláírás rajzolása
sign.text=Szöveg beírása
sign.clear=Törlés
sign.add=Hozzáadás
sign.saved=Saved Signatures
sign.save=Save Signature
sign.personalSigs=Personal Signatures
sign.sharedSigs=Shared Signatures
sign.noSavedSigs=No saved signatures found
#repair
@@ -1220,5 +1230,3 @@ splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for
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

View File

@@ -3,8 +3,8 @@
###########
# 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
addPageNumbers.fontSize=Ukuran Fonta
addPageNumbers.fontName=Nama Fonta
pdfPrompt=Pilih PDF
multiPdfPrompt=Pilih PDF (2+)
multiPdfDropPrompt=Pilih (atau seret & letakkan)) semua PDF yang Anda butuhkan
@@ -12,17 +12,17 @@ imgPrompt=Pilih Gambar
genericSubmit=Kirim
processTimeWarning=Peringatan: Proses ini dapat memakan waktu hingga satu menit, tergantung pada ukuran berkas
pageOrderPrompt=Urutan Halaman Khusus (Masukkan daftar nomor halaman yang dipisahkan dengan koma atau Fungsi seperti 2n + 1) :
pageSelectionPrompt=Custom Page Selection (Enter a comma-separated list of page numbers 1,5,6 or Functions like 2n+1) :
pageSelectionPrompt=Pemilihan Halaman Kustom (Masukkan daftar nomor halaman dipisahkan dengan koma 1,5,6 atau Fungsi seperti 2n+1) :
goToPage=Ke
true=Benar
false=Salah
unknown=Tidak diketahui
save=Simpan
saveToBrowser=Save to Browser
saveToBrowser=Simpan ke Peramban
close=Tutup
filesSelected=berkas dipilih
noFavourites=Tidak ada favorit yang ditambahkan
downloadComplete=Download Complete
downloadComplete=Unduhan Lengkap
bored=Bosan Menunggu?
alphabet=Abjad
downloadPdf=Unduh PDF
@@ -46,113 +46,115 @@ red=Merah
green=Hijau
blue=Biru
custom=Kustom...
WorkInProgess=Work in progress, May not work or be buggy, Please report any problems!
poweredBy=Powered by
yes=Yes
no=No
WorkInProgess=Pekerjaan sedang diproses, Mungkin tidak berfungsi atau terdapat kutu, Silakan laporkan masalah apa pun!
poweredBy=Ditenagai oleh
yes=Ya
no=Tidak
changedCredsMessage=Kredensial berubah!!
notAuthenticatedMessage=Pengguna tidak ter-autentikasi.
userNotFoundMessage=Pengguna tidak ditemukan.
incorrectPasswordMessage=Kata sandi saat ini salah.
usernameExistsMessage=Nama pengguna baru sudah ada.
invalidUsernameMessage=Invalid username, username can only contain letters, numbers and the following special characters @._+- or must be a valid email address.
invalidPasswordMessage=The password must not be empty and must not have spaces at the beginning or end.
confirmPasswordErrorMessage=New Password and Confirm New Password must match.
deleteCurrentUserMessage=Cannot delete currently logged in user.
deleteUsernameExistsMessage=The username does not exist and cannot be deleted.
invalidUsernameMessage=Nama pengguna tidak valid, nama pengguna hanya boleh mengandung huruf, angka, dan karakter khusus berikut @._+- atau harus berupa alamat email yang valid.
invalidPasswordMessage=Kata sandi tidak boleh kosong dan tidak boleh memiliki spasi di awal atau akhir.
confirmPasswordErrorMessage=Kata Sandi Baru dan Konfirmasi Kata Sandi Baru harus sama.
deleteCurrentUserMessage=Pengguna yang sedang masuk tidak dapat dihapus.
deleteUsernameExistsMessage=Nama pengguna tidak ada dan tidak dapat dihapus.
downgradeCurrentUserMessage=Tidak dapat menurunkan peran pengguna saat ini
disabledCurrentUserMessage=The current user cannot be disabled
disabledCurrentUserMessage=Pengguna saat ini tidak dapat dinonaktifkan
downgradeCurrentUserLongMessage=Tidak dapat menurunkan peran pengguna saat ini. Oleh karena itu, pengguna saat ini tidak akan ditampilkan.
userAlreadyExistsOAuthMessage=The user already exists as an OAuth2 user.
userAlreadyExistsWebMessage=The user already exists as an web user.
error=Error
oops=Oops!
help=Help
goHomepage=Go to Homepage
joinDiscord=Join our Discord server
seeDockerHub=See Docker Hub
visitGithub=Visit Github Repository
donate=Donate
color=Color
userAlreadyExistsOAuthMessage=Pengguna sudah ada sebagai pengguna OAuth2.
userAlreadyExistsWebMessage=Pengguna sudah ada sebagai pengguna web.
error=Kesalahan
oops=Ups!
help=Bantuan
goHomepage=Kembali ke Beranda
joinDiscord=Bergabung dengan server Discord kami
seeDockerHub=Lihat Docker Hub
visitGithub=Kunjungi Repositori Github
donate=Donasi
color=Warna
sponsor=Sponsor
info=Info
pro=Pro
page=Page
pages=Pages
page=Halaman
pages=Halaman-halaman
loading=Loading...
addToDoc=Add to Document
legal.privacy=Privacy Policy
legal.terms=Terms and Conditions
legal.accessibility=Accessibility
legal.cookie=Cookie Policy
legal.impressum=Impressum
legal.privacy=Kebijakan Privasi
legal.terms=Syarat dan Ketentuan
legal.accessibility=Aksesibilitas
legal.cookie=Kebijakan Kuki
legal.impressum=Impresum
###############
# Pipeline #
###############
pipeline.header=Pipeline Menu (Beta)
pipeline.uploadButton=Upload Custom
pipeline.configureButton=Configure
pipeline.defaultOption=Custom
pipeline.submitButton=Submit
pipeline.help=Pipeline Help
pipeline.scanHelp=Folder Scanning Help
pipeline.deletePrompt=Are you sure you want to delete pipeline
pipeline.header=Menu Pipeline (Beta)
pipeline.uploadButton=Unggah Kustom
pipeline.configureButton=Konfigurasi
pipeline.defaultOption=Kustom
pipeline.submitButton=Kirim
pipeline.help=Bantuan Pipeline
pipeline.scanHelp=Bantuan Pemindaian Folder
pipeline.deletePrompt=Apakah Anda yakin ingin menghapus pipeline
######################
# Pipeline Options #
######################
pipelineOptions.header=Pipeline Configuration
pipelineOptions.pipelineNameLabel=Pipeline Name
pipelineOptions.saveSettings=Save Operation Settings
pipelineOptions.pipelineNamePrompt=Enter pipeline name here
pipelineOptions.selectOperation=Select Operation
pipelineOptions.addOperationButton=Add operation
pipelineOptions.header=Konfigurasi Pipeline
pipelineOptions.pipelineNameLabel=Nama Pipeline
pipelineOptions.saveSettings=Simpan Pengaturan Operasi
pipelineOptions.pipelineNamePrompt=Masukkan nama pipeline di sini
pipelineOptions.selectOperation=Pilih Operasi
pipelineOptions.addOperationButton=Tambah operasi
pipelineOptions.pipelineHeader=Pipeline:
pipelineOptions.saveButton=Download
pipelineOptions.validateButton=Validate
pipelineOptions.saveButton=Unduh
pipelineOptions.validateButton=Validasi
########################
# 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=Upgrade ke Pro
enterpriseEdition.warning=Fitur ini hanya tersedia untuk pengguna Pro.
enterpriseEdition.yamlAdvert=Stirling PDF Pro mendukung berkas konfigurasi YAML dan fitur SSO lainnya.
enterpriseEdition.ssoAdvert=Mencari lebih banyak fitur manajemen pengguna? Lihat 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=Apakah Anda ingin membuat Stirling PDF lebih baik?
analytics.paragraph1=Stirling PDF memiliki analitik yang dapat diaktifkan untuk membantu kami meningkatkan produk. Kami tidak melacak informasi pribadi atau konten berkas.
analytics.paragraph2=Silakan pertimbangkan untuk mengaktifkan analitik agar Stirling PDF dapat berkembang dan untuk memungkinkan kami memahami pengguna kami dengan lebih baik.
analytics.enable=Aktifkan analitik
analytics.disable=Nonaktifkan analitik
analytics.settings=Anda dapat mengubah pengaturan untuk analitik di berkas config/settings.yml
#############
# NAVBAR #
#############
navbar.favorite=Favorites
navbar.favorite=Favorit
navbar.darkmode=Mode Gelap
navbar.language=Languages
navbar.language=Bahasa
navbar.settings=Pengaturan
navbar.allTools=Tools
navbar.multiTool=Multi Tools
navbar.sections.organize=Organize
navbar.sections.convertTo=Convert to PDF
navbar.sections.convertFrom=Convert from PDF
navbar.sections.security=Sign & Security
navbar.sections.advance=Advanced
navbar.sections.edit=View & Edit
navbar.sections.popular=Popular
navbar.allTools=Alat
navbar.multiTool=Alat Multi
navbar.sections.organize=Atur
navbar.sections.convertTo=Konversi ke PDF
navbar.sections.convertFrom=Konversi dari PDF
navbar.sections.security=Tanda Tangan & Keamanan
navbar.sections.advance=Langkah Lanjut
navbar.sections.edit=Melihat & Mengedit
navbar.sections.popular=Populer
#############
# SETTINGS #
#############
settings.title=Pengaturan
settings.update=Pembaruan tersedia
settings.updateAvailable={0} is the current installed version. A new version ({1}) is available.
settings.updateAvailable={0} adalah versi yang terpasang saat ini. Versi baru ({1}) tersedia.
settings.appVersion=Versi Aplikasi:
settings.downloadOption.title=Pilih opsi unduhan (Untuk unduhan berkas tunggal non zip):
settings.downloadOption.1=Buka di jendela yang sama
@@ -161,13 +163,13 @@ settings.downloadOption.3=Unduh berkas
settings.zipThreshold=Berkas zip ketika jumlah berkas yang diunduh melebihi
settings.signOut=Keluar
settings.accountSettings=Pengaturan Akun
settings.bored.help=Enables easter egg game
settings.cacheInputs.name=Save form inputs
settings.cacheInputs.help=Enable to store previously used inputs for future runs
settings.bored.help=Mengaktifkan permainan telur paskah
settings.cacheInputs.name=Simpan input formulir
settings.cacheInputs.help=Aktifkan untuk menyimpan input yang pernah digunakan untuk menjalankan di masa depan
changeCreds.title=Ubah Kredensial
changeCreds.header=Perbarui Detail Akun Anda
changeCreds.changePassword=You are using default login credentials. Please enter a new password
changeCreds.changePassword=Anda menggunakan kredensial login default. Silakan masukkan kata sandi baru
changeCreds.newUsername=Nama Pengguna Baru
changeCreds.oldPassword=Kata Sandi Saat Ini
changeCreds.newPassword=Kata Sandi Baru
@@ -202,48 +204,48 @@ adminUserSettings.header=Pengaturan Kontrol Admin
adminUserSettings.admin=Admin
adminUserSettings.user=Pengguna
adminUserSettings.addUser=Tambahkan Pengguna Baru
adminUserSettings.deleteUser=Delete User
adminUserSettings.confirmDeleteUser=Should the user be deleted?
adminUserSettings.confirmChangeUserStatus=Should the user be disabled/enabled?
adminUserSettings.usernameInfo=Username can only contain letters, numbers and the following special characters @._+- or must be a valid email address.
adminUserSettings.deleteUser=Hapus Pengguna
adminUserSettings.confirmDeleteUser=Haruskah pengguna dihapus?
adminUserSettings.confirmChangeUserStatus=Haruskah pengguna dinonaktifkan/diaktifkan?
adminUserSettings.usernameInfo=Nama pengguna hanya boleh mengandung huruf, angka, dan karakter khusus berikut @._+- atau harus berupa alamat email yang valid.
adminUserSettings.roles=Peran
adminUserSettings.role=Peran
adminUserSettings.actions=Tindakan
adminUserSettings.apiUser=Pengguna API Terbatas
adminUserSettings.extraApiUser=Additional Limited API User
adminUserSettings.webOnlyUser=Pengguna Khusus Web
adminUserSettings.demoUser=Demo User (No custom settings)
adminUserSettings.internalApiUser=Internal API User
adminUserSettings.demoUser=Pengguna Demo (Tanpa pengaturan kustom)
adminUserSettings.internalApiUser=Pengguna API Internal
adminUserSettings.forceChange=Memaksa pengguna untuk mengubah nama pengguna/kata sandi saat masuk
adminUserSettings.submit=Simpan Pengguna
adminUserSettings.changeUserRole=Ubah Peran Pengguna
adminUserSettings.authenticated=Authenticated
adminUserSettings.editOwnProfil=Edit own profile
adminUserSettings.enabledUser=enabled user
adminUserSettings.disabledUser=disabled user
adminUserSettings.activeUsers=Active Users:
adminUserSettings.disabledUsers=Disabled Users:
adminUserSettings.totalUsers=Total Users:
adminUserSettings.lastRequest=Last Request
adminUserSettings.authenticated=Terautentikasi
adminUserSettings.editOwnProfil=Edit profil sendiri
adminUserSettings.enabledUser=Pengguna diaktifkan
adminUserSettings.disabledUser=Pengguna dinonaktifkan
adminUserSettings.activeUsers=Pengguna Aktif:
adminUserSettings.disabledUsers=Pengguna Dinonaktifkan:
adminUserSettings.totalUsers=Total Pengguna:
adminUserSettings.lastRequest=Permintaan Terakhir
database.title=Database Import/Export
database.header=Database Import/Export
database.fileName=File Name
database.creationDate=Creation Date
database.fileSize=File Size
database.deleteBackupFile=Delete Backup File
database.importBackupFile=Import Backup File
database.downloadBackupFile=Download Backup File
database.info_1=When importing data, it is crucial to ensure the correct structure. If you are unsure of what you are doing, seek advice and support from a professional. An error in the structure can cause application malfunctions, up to and including the complete inability to run the application.
database.info_2=The file name does not matter when uploading. It will be renamed afterward to follow the format backup_user_yyyyMMddHHmm.sql, ensuring a consistent naming convention.
database.submit=Import Backup
database.importIntoDatabaseSuccessed=Import into database successed
database.fileNotFound=File not Found
database.fileNullOrEmpty=File must not be null or empty
database.failedImportFile=Failed Import File
database.title=Impor/Ekspor Database
database.header=Impor/Ekspor Database
database.fileName=Nama Berkas
database.creationDate=Tanggal Pembuatan
database.fileSize=Ukuran Berkas
database.deleteBackupFile=Hapus Berkas Cadangan
database.importBackupFile=Impor Berkas Cadangan
database.downloadBackupFile=Unduh Berkas Cadangan
database.info_1=Ketika mengimpor data, sangat penting untuk memastikan struktur yang benar. Jika Anda tidak yakin dengan apa yang Anda lakukan, cari nasihat dan dukungan dari seorang profesional. Kesalahan dalam struktur dapat menyebabkan malfungsi aplikasi, bahkan hingga tidak dapat menjalankan aplikasi sama sekali.
database.info_2=Nama berkas tidak menjadi masalah saat mengunggah. Nama berkas akan diubah setelahnya mengikuti format backup_user_yyyyMMddHHmm.sql, memastikan konsistensi dalam penamaan.
database.submit=Impor Cadangan
database.importIntoDatabaseSuccessed=Impor ke database berhasil
database.fileNotFound=Berkas tidak Ditemukan
database.fileNullOrEmpty=Berkas tidak boleh null atau kosong
database.failedImportFile=Impor Berkas Gagal
session.expired=Your session has expired. Please refresh the page and try again.
session.expired=Sesi Anda telah kedaluwarsa. Silakan muat ulang halaman dan coba lagi.
#############
# HOME-PAGE #
@@ -313,7 +315,7 @@ removePassword.tags=aman,Dekripsi,keamanan,buka kata sandi,hapus kata sandi
home.compressPdfs.title=Kompres
home.compressPdfs.desc=Kompres PDF untuk mengurangi ukuran berkas.
compressPdfs.tags=squish, kecil, kecil
compressPdfs.tags=remas, kecil, mini
home.changeMetadata.title=Ubah Metadata
@@ -490,41 +492,41 @@ home.AddStampRequest.desc=Add text or add image stamps at set locations
AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Customize
home.PDFToBook.title=PDF to Book
home.PDFToBook.desc=Converts PDF to Book/Comic formats using calibre
PDFToBook.tags=Book,Comic,Calibre,Convert,manga,amazon,kindle
home.PDFToBook.title=PDF ke Buku
home.PDFToBook.desc=Mengonversi PDF ke format Buku/Komik menggunakan calibre
PDFToBook.tags=Buku,Komik,Calibre,Konversi,manga,amazon,kindle
home.BookToPDF.title=Book to PDF
home.BookToPDF.desc=Converts Books/Comics formats to PDF using calibre
BookToPDF.tags=Book,Comic,Calibre,Convert,manga,amazon,kindle
home.BookToPDF.title=Buku ke PDF
home.BookToPDF.desc=Mengonversi format Buku/Komik ke PDF menggunakan calibre
BookToPDF.tags=Buku,Komik,Calibre,Konversi,manga,amazon,kindle
home.removeImagePdf.title=Remove image
home.removeImagePdf.desc=Remove image from PDF to reduce file size
removeImagePdf.tags=Remove Image,Page operations,Back end,server side
home.removeImagePdf.title=Hapus Gambar
home.removeImagePdf.desc=Hapus gambar dari PDF untuk mengurangi ukuran file
removeImagePdf.tags=Hapus Gambar,Operasi Halaman,Backend,server side
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=Pisahkan PDF berdasarkan Bab
home.splitPdfByChapters.desc=Memisahkan PDF menjadi beberapa file berdasarkan struktur babnya.
splitPdfByChapters.tags=pemisahan,bab,bookmark,atur
#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
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.title=Ganti-Inversi-Warna
replace-color.header=Ganti-Inversi Warna PDF
home.replaceColorPdf.title=Ganti dan Inversi Warna
home.replaceColorPdf.desc=Ganti warna untuk teks dan latar belakang dalam PDF dan inversi seluruh warna PDF untuk mengurangi ukuran file
replaceColorPdf.tags=Ganti Warna,Operasi Halaman,Backend,server side
replace-color.selectText.1=Opsi Ganti atau Inversi warna
replace-color.selectText.2=Default(Warna kontras tinggi default)
replace-color.selectText.3=Kustom(Warna yang disesuaikan)
replace-color.selectText.4=Full-Inversi(Inversi semua warna)
replace-color.selectText.5=Opsi warna kontras tinggi
replace-color.selectText.6=teks putih di latar belakang hitam
replace-color.selectText.7=teks hitam di latar belakang putih
replace-color.selectText.8=teks kuning di latar belakang hitam
replace-color.selectText.9=teks hijau di latar belakang hitam
replace-color.selectText.10=Pilih warna teks
replace-color.selectText.11=Pilih warna latar belakang
replace-color.submit=Ganti
@@ -543,17 +545,17 @@ login.locked=Akun Anda telah dikunci.
login.signinTitle=Silakan masuk
login.ssoSignIn=Masuk melalui Single Sign - on
login.oauth2AutoCreateDisabled=OAUTH2 Buat Otomatis Pengguna Dinonaktifkan
login.oauth2AdminBlockedUser=Registration or logging in of non-registered users is currently blocked. Please contact the administrator.
login.oauth2RequestNotFound=Authorization request not found
login.oauth2InvalidUserInfoResponse=Invalid User Info Response
login.oauth2invalidRequest=Invalid Request
login.oauth2AccessDenied=Access Denied
login.oauth2InvalidTokenResponse=Invalid Token Response
login.oauth2InvalidIdToken=Invalid Id Token
login.userIsDisabled=User is deactivated, login is currently blocked with this username. Please contact the administrator.
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.oauth2AdminBlockedUser=Registrasi atau login pengguna yang tidak terdaftar saat ini diblokir. Silakan hubungi administrator.
login.oauth2RequestNotFound=Permintaan otorisasi tidak ditemukan
login.oauth2InvalidUserInfoResponse=Respons Info Pengguna Tidak Valid
login.oauth2invalidRequest=Permintaan Tidak Valid
login.oauth2AccessDenied=Akses Ditolak
login.oauth2InvalidTokenResponse=Respons Token Tidak Valid
login.oauth2InvalidIdToken=Token ID Tidak Valid
login.userIsDisabled=Pengguna dinonaktifkan, login saat ini diblokir dengan nama pengguna ini. Silakan hubungi administrator.
login.alreadyLoggedIn=Anda sudah login ke
login.alreadyLoggedIn2=perangkat. Silakan keluar dari perangkat dan coba lagi.
login.toManySessions=Anda memiliki terlalu banyak sesi aktif
#auto-redact
autoRedact.title=Redaksional Otomatis
@@ -617,37 +619,37 @@ HTMLToPDF.header=HTML Ke PDF
HTMLToPDF.help=Menerima berkas HTML dan ZIP yang berisi html / css / gambar, dll yang diperlukan
HTMLToPDF.submit=Konversi
HTMLToPDF.credit=Menggunakan WeasyPrint
HTMLToPDF.zoom=Zoom level for displaying the website.
HTMLToPDF.pageWidth=Width of the page in centimeters. (Blank to default)
HTMLToPDF.pageHeight=Height of the page in centimeters. (Blank to default)
HTMLToPDF.marginTop=Top margin of the page in millimeters. (Blank to default)
HTMLToPDF.marginBottom=Bottom margin of the page in millimeters. (Blank to default)
HTMLToPDF.marginLeft=Left margin of the page in millimeters. (Blank to default)
HTMLToPDF.marginRight=Right margin of the page in millimeters. (Blank to default)
HTMLToPDF.printBackground=Render the background of websites.
HTMLToPDF.defaultHeader=Enable Default Header (Name and page number)
HTMLToPDF.cssMediaType=Change the CSS media type of the page.
HTMLToPDF.none=None
HTMLToPDF.print=Print
HTMLToPDF.screen=Screen
HTMLToPDF.zoom=Tingkat perbersan untuk menampilkan situs web.
HTMLToPDF.pageWidth=Lebar halaman dalam sentimeter. (Kosong untuk default)
HTMLToPDF.pageHeight=Tinggi halaman dalam sentimeter. (Kosong untuk default)
HTMLToPDF.marginTop=Margin atas halaman dalam milimeter. (Kosong untuk default)
HTMLToPDF.marginBottom=Margin bawah halaman dalam milimeter. (Kosong untuk default)
HTMLToPDF.marginLeft=Margin kiri halaman dalam milimeter. (Kosong untuk default)
HTMLToPDF.marginRight=Margin kanan halaman dalam milimeter. (Kosong untuk default)
HTMLToPDF.printBackground=Render latar belakang situs web.
HTMLToPDF.defaultHeader=Aktifkan Header Default (Nama dan nomor halaman)
HTMLToPDF.cssMediaType=Ubah jenis media CSS halaman.
HTMLToPDF.none=Tidak ada
HTMLToPDF.print=Cetak
HTMLToPDF.screen=Layar
#AddStampRequest
AddStampRequest.header=Stamp PDF
AddStampRequest.title=Stamp PDF
AddStampRequest.stampType=Stamp Type
AddStampRequest.stampText=Stamp Text
AddStampRequest.stampImage=Stamp Image
AddStampRequest.alphabet=Alphabet
AddStampRequest.fontSize=Font/Image Size
AddStampRequest.rotation=Rotation
AddStampRequest.opacity=Opacity
AddStampRequest.position=Position
AddStampRequest.overrideX=Override X Coordinate
AddStampRequest.overrideY=Override Y Coordinate
AddStampRequest.customMargin=Custom Margin
AddStampRequest.customColor=Custom Text Color
AddStampRequest.submit=Submit
AddStampRequest.header=Stampel PDF
AddStampRequest.title=Stampel PDF
AddStampRequest.stampType=Jenis Stampel
AddStampRequest.stampText=Teks Stampel
AddStampRequest.stampImage=Gambar Stampel
AddStampRequest.alphabet=Alfabet
AddStampRequest.fontSize=Ukuran Font/Gambar
AddStampRequest.rotation=Rotasi
AddStampRequest.opacity=Transparansi
AddStampRequest.position=Posisi
AddStampRequest.overrideX=Timpa Koordinat X
AddStampRequest.overrideY=Timpa Koordinat Y
AddStampRequest.customMargin=Margin Kustom
AddStampRequest.customColor=Warna Teks Kustom
AddStampRequest.submit=Kirim
#sanitizePDF
@@ -737,7 +739,7 @@ scalePages.submit=Kirim
certSign.title=Penandatanganan Sertifikat
certSign.header=Menandatangani PDF dengan sertifikat Anda (Sedang dalam proses)
certSign.selectPDF=Pilih Berkas PDF untuk Penandatanganan:
certSign.jksNote=Note: If your certificate type is not listed below, please convert it to a Java Keystore (.jks) file using the keytool command line tool. Then, choose the .jks file option below.
certSign.jksNote=Catatan: Jika tipe sertifikat Anda tidak terdaftar di bawah, silakan konversi ke file Java Keystore (.jks) menggunakan alat baris perintah keytool. Kemudian, pilih opsi file .jks di bawah.
certSign.selectKey=Pilih Berkas Kunci Pribadi Anda (format PKCS # 8, bisa .pem atau .der):
certSign.selectCert=Pilih Berkas Sertifikat Anda (format X.509, bisa .pem atau .der):
certSign.selectP12=Pilih Berkas Keystore PKCS #12 Anda (.p12 atau .pfx) (Opsional, Jika disediakan, berkas tersebut harus berisi kunci pribadi dan sertifikat Anda):
@@ -752,15 +754,15 @@ certSign.submit=Tanda tangani PDF
#removeCertSign
removeCertSign.title=Remove Certificate Signature
removeCertSign.header=Remove the digital certificate from the PDF
removeCertSign.selectPDF=Select a PDF file:
removeCertSign.submit=Remove Signature
removeCertSign.title=Hapus Tanda Tangan Sertifikat
removeCertSign.header=Hapus sertifikat digital dari PDF
removeCertSign.selectPDF=Pilih file PDF:
removeCertSign.submit=Hapus Tanda Tangan
#removeBlanks
removeBlanks.title=Hapus Halaman Kosong
removeBlanks.header=Remove Blank Pages
removeBlanks.title=Hapus yang Kosong
removeBlanks.header=Hapus Halaman Kosong
removeBlanks.threshold=Ambang Batas Keputihan Piksel:
removeBlanks.thresholdDesc=Ambang batas untuk menentukan seberapa putih piksel putih yang harus diklasifikasikan sebagai 'Putih'. 0=Hitam, 255 putih murni.
removeBlanks.whitePercent=Persen Putih (%):
@@ -777,24 +779,27 @@ removeAnnotations.submit=Hapus
#compare
compare.title=Bandingkan
compare.header=Bandingkan PDF
compare.highlightColor.1=Highlight Color 1:
compare.highlightColor.2=Highlight Color 2:
compare.highlightColor.1=Warna Sorotan 1:
compare.highlightColor.2=Warna Sorotan 2:
compare.document.1=Dokumen 1
compare.document.2=Dokumen 2
compare.submit=Bandingkan
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.
#BookToPDF
BookToPDF.title=Books and Comics to PDF
BookToPDF.header=Book to PDF
BookToPDF.credit=Uses Calibre
BookToPDF.submit=Convert
BookToPDF.title=Buku dan Komik ke PDF
BookToPDF.header=Buku ke PDF
BookToPDF.credit=Menggunakan Calibre
BookToPDF.submit=Konversi
#PDFToBook
PDFToBook.title=PDF to Book
PDFToBook.header=PDF to Book
PDFToBook.title=PDF ke Buku
PDFToBook.header=PDF ke Buku
PDFToBook.selectText.1=Format
PDFToBook.credit=Uses Calibre
PDFToBook.submit=Convert
PDFToBook.credit=Menggunakan Calibre
PDFToBook.submit=Konversi
#sign
sign.title=Tanda
@@ -804,6 +809,11 @@ sign.draw=Gambar Tanda Tangan
sign.text=Masukan Teks
sign.clear=Hapus
sign.add=Tambah
sign.saved=Saved Signatures
sign.save=Save Signature
sign.personalSigs=Personal Signatures
sign.sharedSigs=Shared Signatures
sign.noSavedSigs=No saved signatures found
#repair
@@ -830,7 +840,7 @@ ScannerImageSplit.selectText.7=Area Kontur Minimum:
ScannerImageSplit.selectText.8=Menetapkan ambang batas area kontur minimum untuk foto
ScannerImageSplit.selectText.9=Ukuran Batas:
ScannerImageSplit.selectText.10=Menetapkan ukuran batas yang ditambahkan dan dihapus untuk mencegah batas putih pada output (default: 1).
ScannerImageSplit.info=Python is not installed. It is required to run.
ScannerImageSplit.info=Python tidak terinstal. Ini diperlukan untuk menjalankan.
#OCR
@@ -904,16 +914,16 @@ pdfOrganiser.title=Pengaturan Halaman
pdfOrganiser.header=Pengaturan Halaman PDF
pdfOrganiser.submit=Susun ulang halaman
pdfOrganiser.mode=Mode
pdfOrganiser.mode.1=Custom Page Order
pdfOrganiser.mode.2=Reverse Order
pdfOrganiser.mode.3=Duplex Sort
pdfOrganiser.mode.4=Booklet Sort
pdfOrganiser.mode.5=Side Stitch Booklet Sort
pdfOrganiser.mode.6=Odd-Even Split
pdfOrganiser.mode.7=Remove First
pdfOrganiser.mode.8=Remove Last
pdfOrganiser.mode.9=Remove First and Last
pdfOrganiser.mode.10=Odd-Even Merge
pdfOrganiser.mode.1=Urutan Halaman Kustom
pdfOrganiser.mode.2=Urutan Terbalik
pdfOrganiser.mode.3=Sortir Duplex
pdfOrganiser.mode.4=Sortir Buku
pdfOrganiser.mode.5=Sortir Buku Jahitan Samping
pdfOrganiser.mode.6=Pemisahan Genap-Ganjil
pdfOrganiser.mode.7=Hapus Pertama
pdfOrganiser.mode.8=Hapus Terakhir
pdfOrganiser.mode.9=Hapus Pertama dan Terakhir
pdfOrganiser.mode.10=Penggabungan Genap-Ganjil
pdfOrganiser.placeholder=(e.g. 1,3,2 or 4-8,2,10-12 or 2n-1)
@@ -982,7 +992,7 @@ pdfToImage.color=Warna
pdfToImage.grey=Skala abu-abu
pdfToImage.blackwhite=Black and White (Bisa kehilangan data!)
pdfToImage.submit=Konversi
pdfToImage.info=Python is not installed. Required for WebP conversion.
pdfToImage.info=Python tidak terinstal. Diperlukan untuk konversi WebP.
#addPassword
@@ -1060,7 +1070,7 @@ changeMetadata.author=Penulis:
changeMetadata.creationDate=Tanggal Dibuat (yyyy/MM/dd HH:mm:ss):
changeMetadata.creator=Pencipta:
changeMetadata.keywords=Kata kunci:
changeMetadata.modDate=Tangal Diupdate (yyyy/MM/dd HH:mm:ss):
changeMetadata.modDate=Tangal Diperbarui (yyyy/MM/dd HH:mm:ss):
changeMetadata.producer=Produser:
changeMetadata.subject=Subjek:
changeMetadata.trapped=Terperangkap:
@@ -1074,13 +1084,13 @@ pdfToPDFA.title=PDF Ke PDF/A
pdfToPDFA.header=PDF ke PDF/A
pdfToPDFA.credit=Layanan ini menggunakan ghostscript untuk konversi PDF/A.
pdfToPDFA.submit=Konversi
pdfToPDFA.tip=Currently does not work for multiple inputs at once
pdfToPDFA.outputFormat=Output format
pdfToPDFA.pdfWithDigitalSignature=The PDF contains a digital signature. This will be removed in the next step.
pdfToPDFA.tip=Saat ini tidak dapat digunakan untuk beberapa input sekaligus
pdfToPDFA.outputFormat=Format keluaran
pdfToPDFA.pdfWithDigitalSignature=PDF ini mengandung tanda tangan digital. Ini akan dihapus pada langkah berikutnya.
#PDFToWord
PDFToWord.title=PDF Ke Word
PDFToWord.title=PDF ke Word
PDFToWord.header=PDF ke Word
PDFToWord.selectText.1=Hasil format berkas
PDFToWord.credit=Layanan ini menggunakan LibreOffice untuk konversi berkas.
@@ -1096,7 +1106,7 @@ PDFToPresentation.submit=Konversi
#PDFToText
PDFToText.title=PDF Ke RTF (Text)
PDFToText.title=PDF ke RTF (Text)
PDFToText.header=PDF ke RTF (Text)
PDFToText.selectText.1=Hasil format berkas
PDFToText.credit=Layanan ini menggunakan LibreOffice untuk konversi berkas.
@@ -1104,20 +1114,20 @@ PDFToText.submit=Konversi
#PDFToHTML
PDFToHTML.title=PDF Ke HTML
PDFToHTML.title=PDF ke HTML
PDFToHTML.header=PDF ke HTML
PDFToHTML.credit=Layanan ini menggunakan pdftohtml untuk konversi berkas.
PDFToHTML.submit=Konversi
#PDFToXML
PDFToXML.title=PDF Ke XML
PDFToXML.title=PDF ke XML
PDFToXML.header=PDF ke XML
PDFToXML.credit=Layanan ini menggunakan LibreOffice untuk konversi berkas.
PDFToXML.submit=Konversi
#PDFToCSV
PDFToCSV.title=PDF Ke CSV
PDFToCSV.title=PDF ke CSV
PDFToCSV.header=PDF ke CSV
PDFToCSV.prompt=Pilih halaman untuk mengambil tabel
PDFToCSV.submit=Ektraksi
@@ -1158,67 +1168,65 @@ split-by-sections.vertical.label=Pembagian Vertikal
split-by-sections.horizontal.placeholder=Input angka untuk pembagian horizontal
split-by-sections.vertical.placeholder=Input angka untuk pembagian vertikal
split-by-sections.submit=Pisahkan PDF
split-by-sections.merge=Merge Into One PDF
split-by-sections.merge=Gabung Menjadi Berkas PDF Tunggal
#printFile
printFile.title=Print File
printFile.header=Print File to Printer
printFile.selectText.1=Select File to Print
printFile.selectText.2=Enter Printer Name
printFile.submit=Print
printFile.title=Cetak File
printFile.header=Cetak File ke Printer
printFile.selectText.1=Pilih File untuk Dicetak
printFile.selectText.2=Masukkan Nama Printer
printFile.submit=Cetak
#licenses
licenses.nav=Licenses
licenses.title=3rd Party Licenses
licenses.header=3rd Party Licenses
licenses.module=Module
licenses.version=Version
licenses.license=License
licenses.nav=Lisensi
licenses.title=Lisensi Pihak Ketiga
licenses.header=Lisensi Pihak Ketiga
licenses.module=Modul
licenses.version=Versi
licenses.license=Lisensi
#survey
survey.nav=Survey
survey.title=Stirling-PDF Survey
survey.description=Stirling-PDF has no tracking so we want to hear from our users to improve 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.please=Please consider taking our survey!
survey.disabled=(Survey popup will be disabled in following updates but available at foot of page)
survey.button=Take Survey
survey.dontShowAgain=Don't show again
survey.nav=Survei
survey.title=Survei Stirling-PDF
survey.description=Stirling-PDF tidak memiliki pelacakan, jadi kami ingin mendengar dari pengguna kami untuk meningkatkan Stirling-PDF!
survey.changes=Stirling-PDF telah berubah sejak survei terakhir! Untuk mengetahui lebih lanjut, silakan periksa posting blog kami di sini:
survey.changes2=Dengan perubahan ini, kami mendapatkan dukungan bisnis yang dibayar dan pendanaan
survey.please=Silakan pertimbangkan untuk mengikuti survei kami!
survey.disabled=(Popup survei akan dinonaktifkan dalam pembaruan berikutnya tetapi tersedia di bagian bawah halaman)
survey.button=Ikuti Survei
survey.dontShowAgain=Jangan tampilkan lagi
#error
error.sorry=Sorry for the issue!
error.needHelp=Need help / Found an issue?
error.contactTip=If you're still having trouble, don't hesitate to reach out to us for help. You can submit a ticket on our GitHub page or contact us through Discord:
error.404.head=404 - Page Not Found | Oops, we tripped in the code!
error.404.1=We can't seem to find the page you're looking for.
error.404.2=Something went wrong
error.github=Submit a ticket on GitHub
error.showStack=Show Stack Trace
error.copyStack=Copy Stack Trace
error.githubSubmit=GitHub - Submit a ticket
error.discordSubmit=Discord - Submit Support post
error.sorry=Maaf atas masalah ini!
error.needHelp=Butuh bantuan / Menemukan masalah?
error.contactTip=Jika Anda masih mengalami kesulitan, jangan ragu untuk menghubungi kami untuk bantuan. Anda dapat mengirim tiket di halaman GitHub kami atau menghubungi kami melalui Discord:
error.404.head=404 - Halaman Tidak Ditemukan | Ups, kami tersandung dalam kode!
error.404.1=Kami tidak dapat menemukan halaman yang Anda cari.
error.404.2=Terjadi kesalahan
error.github=Kirim tiket di GitHub
error.showStack=Tampilkan Stack Trace
error.copyStack=Salin Stack Trace
error.githubSubmit=GitHub - Kirim tiket
error.discordSubmit=Discord - Kirim pos dukungan
#remove-image
removeImage.title=Remove image
removeImage.header=Remove image
removeImage.removeImage=Remove image
removeImage.submit=Remove image
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
removeImage.title=Hapus gambar
removeImage.header=Hapus gambar
removeImage.removeImage=Hapus gambar
removeImage.submit=Hapus gambar
splitByChapters.title=Pecah PDF berdasarkan Bab
splitByChapters.header=Pecah PDF berdasarkan Bab
splitByChapters.bookmarkLevel=Tingkatan Markah
splitByChapters.includeMetadata=Termasuk Metadata
splitByChapters.allowDuplicates=Izinkan Duplikat
splitByChapters.desc.1=Alat ini membagi file PDF menjadi beberapa PDF berdasarkan struktur babnya.
splitByChapters.desc.2=Tingkatan Markah: Pilih tingkatan markah yang digunakan untuk membagi (0 untuk tingkat atas, 1 untuk tingkat kedua, dll.).
splitByChapters.desc.3=Termasuk Metadata: Jika dicentang, metadata asli PDF akan disertakan dalam setiap PDF yang dibagi.
splitByChapters.desc.4=Izinkan Duplikat: Jika dicentang, mengizinkan beberapa markah pada halaman yang sama untuk membuat PDF terpisah.
splitByChapters.submit=Pecah PDF

View File

@@ -79,6 +79,8 @@ info=Info
pro=Pro
page=Pagina
pages=Pagine
loading=Caricamento...
addToDoc=Aggiungi al documento
legal.privacy=Informativa sulla privacy
legal.terms=Termini e Condizioni
@@ -145,7 +147,7 @@ navbar.sections.convertFrom=Converti da PDF
navbar.sections.security=Firma & Sicurezza
navbar.sections.advance=Avanzate
navbar.sections.edit=Visualizza & Modifica
navbar.sections.popular=Populare
navbar.sections.popular=Popolare
#############
# SETTINGS #
@@ -782,6 +784,9 @@ compare.highlightColor.2=Evidenzia colore 2:
compare.document.1=Documento 1
compare.document.2=Documento 2
compare.submit=Compara
compare.complex.message=Uno o entrambi i documenti forniti sono file di grandi dimensioni, l'accuratezza del confronto potrebbe risultare ridotta
compare.large.file.message=Uno o entrambi i documenti forniti sono troppo grandi per essere elaborati
compare.no.text.message=Uno o entrambi i PDF selezionati non hanno contenuto di testo. Si prega di scegliere PDF con testo per il confronto.
#BookToPDF
BookToPDF.title=Libri e fumetti in PDF
@@ -804,6 +809,11 @@ sign.draw=Disegna Firma
sign.text=Testo
sign.clear=Cancella
sign.add=Aggiungi
sign.saved=Firme salvate
sign.save=Firma salvata
sign.personalSigs=Firme personali
sign.sharedSigs=Firme condivise
sign.noSavedSigs=Nessuna firma salvata trovata
#repair
@@ -1220,5 +1230,3 @@ splitByChapters.desc.2=Livello segnalibro: seleziona il livello dei segnalibri d
splitByChapters.desc.3=Includi metadati: se selezionato, i metadati del PDF originale verranno inclusi in ogni PDF diviso.
splitByChapters.desc.4=Consenti duplicati: se selezionata, consente più segnalibri sulla stessa pagina per creare PDF separati.
splitByChapters.submit=Dividi PDF

View File

@@ -79,6 +79,8 @@ info=Info
pro=Pro
page=Page
pages=Pages
loading=Loading...
addToDoc=Add to Document
legal.privacy=プライバシーポリシー
legal.terms=利用規約
@@ -782,6 +784,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.
#BookToPDF
BookToPDF.title=書籍やコミックをPDFに変換
@@ -804,6 +809,11 @@ 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
#repair
@@ -1220,5 +1230,3 @@ splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for
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

View File

@@ -79,6 +79,8 @@ info=Info
pro=Pro
page=Page
pages=Pages
loading=Loading...
addToDoc=Add to Document
legal.privacy=Privacy Policy
legal.terms=Terms and Conditions
@@ -782,6 +784,9 @@ compare.highlightColor.2=Highlight Color 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.
#BookToPDF
BookToPDF.title=책과 만화를 PDF로
@@ -804,6 +809,11 @@ 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
#repair
@@ -1220,5 +1230,3 @@ splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for
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

View File

@@ -79,6 +79,8 @@ info=Info
pro=Pro
page=Page
pages=Pages
loading=Loading...
addToDoc=Add to Document
legal.privacy=Privacy Policy
legal.terms=Terms and Conditions
@@ -782,6 +784,9 @@ compare.highlightColor.2=Highlight Color 2:
compare.document.1=Document 1
compare.document.2=Document 2
compare.submit=Vergelijken
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.
#BookToPDF
BookToPDF.title=Boeken en strips naar PDF
@@ -804,6 +809,11 @@ sign.draw=Handtekening tekenen
sign.text=Tekstinvoer
sign.clear=Wissen
sign.add=Toevoegen
sign.saved=Saved Signatures
sign.save=Save Signature
sign.personalSigs=Personal Signatures
sign.sharedSigs=Shared Signatures
sign.noSavedSigs=No saved signatures found
#repair
@@ -1220,5 +1230,3 @@ splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for
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

View File

@@ -79,6 +79,8 @@ info=Info
pro=Pro
page=Page
pages=Pages
loading=Loading...
addToDoc=Add to Document
legal.privacy=Privacy Policy
legal.terms=Terms and Conditions
@@ -782,6 +784,9 @@ compare.highlightColor.2=Uthevingsfarge 2:
compare.document.1=Dokument 1
compare.document.2=Dokument 2
compare.submit=Sammenlign
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.
#BookToPDF
BookToPDF.title=Bøker og Tegneserier til PDF
@@ -804,6 +809,11 @@ sign.draw=Tegn signatur
sign.text=Tekstinput
sign.clear=Slett
sign.add=Legg til
sign.saved=Saved Signatures
sign.save=Save Signature
sign.personalSigs=Personal Signatures
sign.sharedSigs=Shared Signatures
sign.noSavedSigs=No saved signatures found
#repair
@@ -1220,5 +1230,3 @@ splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for
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

View File

@@ -79,6 +79,8 @@ info=informacje
pro=Pro
page=Strona
pages=Strony
loading=Loading...
addToDoc=Add to Document
legal.privacy=Polityka Prywatności
legal.terms=Zasady i Postanowienia
@@ -782,6 +784,9 @@ compare.highlightColor.2=Kolor Podświetlenia 2:
compare.document.1=Dokument 1
compare.document.2=Dokument 2
compare.submit=Porównaj
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.
#BookToPDF
BookToPDF.title=eBooki do PDF
@@ -804,6 +809,11 @@ sign.draw=Narysuj podpis
sign.text=Wprowadź tekst
sign.clear=Wyczyść
sign.add=Dodaj
sign.saved=Saved Signatures
sign.save=Save Signature
sign.personalSigs=Personal Signatures
sign.sharedSigs=Shared Signatures
sign.noSavedSigs=No saved signatures found
#repair
@@ -1220,5 +1230,3 @@ splitByChapters.desc.2=Poziom Zakładek: Wybierz poziom zakładek, który ma zos
splitByChapters.desc.3=Dołącz Metadane: Jeśli opcja ta jest zaznaczona, metadane oryginalnego pliku PDF zostaną uwzględnione w każdym rozdzielonych plików PDF.
splitByChapters.desc.4=Zezwól na Duplikaty: Jeśli ta opcja jest zaznaczona, pozwala na tworzenie oddzielnych plików PDF przez wiele zakładek na tej samej stronie.
splitByChapters.submit=Podziel PDF

View File

@@ -79,6 +79,8 @@ info=Informações
pro=Pro
page=Página
pages=Páginas
loading=Loading...
addToDoc=Add to Document
legal.privacy=Política de Privacidade
legal.terms=Termos e Condições
@@ -782,6 +784,9 @@ compare.highlightColor.2=Cor de destaque 2:
compare.document.1=Documento 1
compare.document.2=Documento 2
compare.submit=Comparar
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.
#BookToPDF
BookToPDF.title=Livros e Quadrinhos para PDF
@@ -804,6 +809,11 @@ sign.draw=Desenhar Assinatura
sign.text=Inserir texto
sign.clear=Limpar
sign.add=Adicionar
sign.saved=Saved Signatures
sign.save=Save Signature
sign.personalSigs=Personal Signatures
sign.sharedSigs=Shared Signatures
sign.noSavedSigs=No saved signatures found
#repair
@@ -1220,5 +1230,3 @@ splitByChapters.desc.2=Nível de Marcador: Escolha o nível de marcador a ser us
splitByChapters.desc.3=Incluir Metadados: Se marcado, os metadados do PDF original serão incluidos em cada 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

View File

@@ -79,6 +79,8 @@ info=Info
pro=Pro
page=Page
pages=Pages
loading=Loading...
addToDoc=Add to Document
legal.privacy=Privacy Policy
legal.terms=Terms and Conditions
@@ -782,6 +784,9 @@ compare.highlightColor.2=Highlight Color 2:
compare.document.1=Documento 1
compare.document.2=Documento 2
compare.submit=Comparar
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.
#BookToPDF
BookToPDF.title=Books and Comics to PDF
@@ -804,6 +809,11 @@ sign.draw=Desenhar Assinatura
sign.text=Inserir Texto
sign.clear=Limpar
sign.add=Adicionar
sign.saved=Saved Signatures
sign.save=Save Signature
sign.personalSigs=Personal Signatures
sign.sharedSigs=Shared Signatures
sign.noSavedSigs=No saved signatures found
#repair
@@ -1220,5 +1230,3 @@ splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for
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

View File

@@ -79,6 +79,8 @@ info=Informații
pro=Pro
page=Page
pages=Pages
loading=Loading...
addToDoc=Add to Document
legal.privacy=Privacy Policy
legal.terms=Terms and Conditions
@@ -782,6 +784,9 @@ compare.highlightColor.2=Culoare Evidențiere 2:
compare.document.1=Documentul 1
compare.document.2=Documentul 2
compare.submit=Compară
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.
#BookToPDF
BookToPDF.title=Cărți și Benzi Desenate în PDF
@@ -804,6 +809,11 @@ sign.draw=Desenează Semnătura
sign.text=Introdu Textul
sign.clear=Curăță
sign.add=Adaugă
sign.saved=Saved Signatures
sign.save=Save Signature
sign.personalSigs=Personal Signatures
sign.sharedSigs=Shared Signatures
sign.noSavedSigs=No saved signatures found
#repair
@@ -1220,5 +1230,3 @@ splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for
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

View File

@@ -79,6 +79,8 @@ info=Info
pro=Pro
page=Page
pages=Pages
loading=Loading...
addToDoc=Add to Document
legal.privacy=Privacy Policy
legal.terms=Terms and Conditions
@@ -782,6 +784,9 @@ compare.highlightColor.2=Highlight Color 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.
#BookToPDF
BookToPDF.title=Книги и комиксы в PDF
@@ -804,6 +809,11 @@ 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
#repair
@@ -1220,5 +1230,3 @@ splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for
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

View File

@@ -79,6 +79,8 @@ info=Info
pro=Pro
page=Page
pages=Pages
loading=Loading...
addToDoc=Add to Document
legal.privacy=Privacy Policy
legal.terms=Terms and Conditions
@@ -782,6 +784,9 @@ compare.highlightColor.2=Highlight Color 2:
compare.document.1=Dokument 1
compare.document.2=Dokument 2
compare.submit=Porovnať
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.
#BookToPDF
BookToPDF.title=Knihy a komiksy do PDF
@@ -804,6 +809,11 @@ sign.draw=Kresliť podpis
sign.text=Textový vstup
sign.clear=Vymazať
sign.add=Pridať
sign.saved=Saved Signatures
sign.save=Save Signature
sign.personalSigs=Personal Signatures
sign.sharedSigs=Shared Signatures
sign.noSavedSigs=No saved signatures found
#repair
@@ -1220,5 +1230,3 @@ splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for
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

View File

@@ -79,6 +79,8 @@ info=Info
pro=Pro
page=Page
pages=Pages
loading=Loading...
addToDoc=Add to Document
legal.privacy=Privacy Policy
legal.terms=Terms and Conditions
@@ -782,6 +784,9 @@ compare.highlightColor.2=Highlight Color 2:
compare.document.1=Dokument 1
compare.document.2=Dokument 2
compare.submit=Uporedi
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.
#BookToPDF
BookToPDF.title=Books and Comics to PDF
@@ -804,6 +809,11 @@ sign.draw=Nacrtaj potpis
sign.text=Tekstualni unos
sign.clear=Obriši
sign.add=Dodaj
sign.saved=Saved Signatures
sign.save=Save Signature
sign.personalSigs=Personal Signatures
sign.sharedSigs=Shared Signatures
sign.noSavedSigs=No saved signatures found
#repair
@@ -1220,5 +1230,3 @@ splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for
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

View File

@@ -79,6 +79,8 @@ info=Info
pro=Pro
page=Page
pages=Pages
loading=Loading...
addToDoc=Add to Document
legal.privacy=Privacy Policy
legal.terms=Terms and Conditions
@@ -114,16 +116,16 @@ pipelineOptions.validateButton=Validera
########################
# 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=Uppgradera till Pro
enterpriseEdition.warning=Den här funktionen är endast tillgänglig för Pro-användare.
enterpriseEdition.yamlAdvert=Stirling PDF Pro stöder YAML-konfigurationsfiler och andra SSO funktioner.
enterpriseEdition.ssoAdvert=Söker du fler funktioner för användarhantering? Spana in Stirling PDF Pro.
#################
# Analytics #
#################
analytics.title=Do you want make Stirling PDF better?
analytics.title=Vill du göra Stirling PDF bättre?
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
@@ -145,7 +147,7 @@ navbar.sections.convertFrom=Konvertera från PDF
navbar.sections.security=Signera & Säkerhet
navbar.sections.advance=Avancerat
navbar.sections.edit=Visa & Redigera
navbar.sections.popular=Popular
navbar.sections.popular=Populära
#############
# SETTINGS #
@@ -243,7 +245,7 @@ database.fileNotFound=Filen hittades inte
database.fileNullOrEmpty=Filen får inte vara null eller tom
database.failedImportFile=Misslyckades med att importera fil
session.expired=Your session has expired. Please refresh the page and try again.
session.expired=Din session har löpt ut. Uppdatera sidan och försök igen.
#############
# HOME-PAGE #
@@ -503,9 +505,9 @@ home.removeImagePdf.desc=Ta bort bild från PDF för att minska filstorlek
removeImagePdf.tags=Ta bort bild,Sidoperationer,Backend,serversida
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=Dela upp PDF efter kapitel
home.splitPdfByChapters.desc=Dela upp en PDF till flera filer baserat på dess kapitelstruktur.
splitPdfByChapters.tags=dela,kapitel,bokmärken,organisera
#replace-invert-color
replace-color.title=Replace-Invert-Color
@@ -551,9 +553,9 @@ login.oauth2AccessDenied=Åtkomst nekad
login.oauth2InvalidTokenResponse=Ogiltigt token-svar
login.oauth2InvalidIdToken=Ogiltigt Id-token
login.userIsDisabled=Användaren är inaktiverad, inloggning är för närvarande blockerad med detta användarnamn. Kontakta administratören.
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=Du är redan inloggad
login.alreadyLoggedIn2=enheter. Logga ut från enheterna och försök igen.
login.toManySessions=Du har för många aktiva sessioner
#auto-redact
autoRedact.title=Auto-redigera
@@ -728,7 +730,7 @@ pageLayout.submit=Skicka
scalePages.title=Justera sidskala
scalePages.header=Justera sidskala
scalePages.pageSize=Storlek på en sida i dokumentet.
scalePages.keepPageSize=Original Size
scalePages.keepPageSize=Originalstorlek
scalePages.scaleFactor=Zoomnivå (beskärning) för en sida.
scalePages.submit=Skicka
@@ -782,6 +784,9 @@ compare.highlightColor.2=Markeringsfärg 2:
compare.document.1=Dokument 1
compare.document.2=Dokument 2
compare.submit=Jämför
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.
#BookToPDF
BookToPDF.title=Böcker och serier till PDF
@@ -804,6 +809,11 @@ sign.draw=Rita signatur
sign.text=Textinmatning
sign.clear=Rensa
sign.add=Lägg till
sign.saved=Saved Signatures
sign.save=Save Signature
sign.personalSigs=Personal Signatures
sign.sharedSigs=Shared Signatures
sign.noSavedSigs=No saved signatures found
#repair
@@ -1181,7 +1191,7 @@ licenses.license=Licens
survey.nav=Undersökning
survey.title=Stirling-PDF-undersökning
survey.description=Stirling-PDF har ingen spårning så vi vill höra från våra användare för att förbättra Stirling-PDF!
survey.changes=Stirling-PDF has changed since the last survey! To find out more please check our blog post here:
survey.changes=Stirling-PDF har ändrats sedan den senaste undersökningen. Lär dig mer på vår blogg här:
survey.changes2=With these changes we are getting paid business support and funding
survey.please=Vänligen överväg att delta i vår undersökning!
survey.disabled=(Undersökningspopup kommer att inaktiveras i kommande uppdateringar men finns tillgänglig längst ner på sidan)
@@ -1210,15 +1220,13 @@ removeImage.removeImage=Ta bort bild
removeImage.submit=Ta bort bild
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.title=Dela upp PDF efter kapitel
splitByChapters.header=Dela upp PDF efter kapitel
splitByChapters.bookmarkLevel=Bokmärkesnivå
splitByChapters.includeMetadata=Inkludera Metadata
splitByChapters.allowDuplicates=Tillåt Dubletter
splitByChapters.desc.1=Detta verktyg delar upp en PDF till flera PDFer baserat på dess kapitelstruktur.
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=Dela upp PDF

View File

@@ -79,6 +79,8 @@ info=ข้อมูล
pro=Pro
page=Page
pages=Pages
loading=Loading...
addToDoc=Add to Document
legal.privacy=Privacy Policy
legal.terms=Terms and Conditions
@@ -782,6 +784,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.
#BookToPDF
BookToPDF.title=หนังสือและการ์ตูนเป็น PDF
@@ -804,6 +809,11 @@ 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
#repair
@@ -1220,5 +1230,3 @@ splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for
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

View File

@@ -79,6 +79,8 @@ info=Bilgi
pro=Pro
page=Page
pages=Pages
loading=Loading...
addToDoc=Add to Document
legal.privacy=Gizlilik Politikası
legal.terms=Şartlar ve koşullar
@@ -782,6 +784,9 @@ compare.highlightColor.2=Vurgu Rengi 2:
compare.document.1=Belge 1
compare.document.2=Belge 2
compare.submit=Karşılaştır
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.
#BookToPDF
BookToPDF.title=Kitapları ve Çizgi Romanları PDF'e Dönüştürme
@@ -804,6 +809,11 @@ sign.draw=İmza Çiz
sign.text=Metin Girişi
sign.clear=Temizle
sign.add=Ekle
sign.saved=Saved Signatures
sign.save=Save Signature
sign.personalSigs=Personal Signatures
sign.sharedSigs=Shared Signatures
sign.noSavedSigs=No saved signatures found
#repair
@@ -1220,5 +1230,3 @@ splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for
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

View File

@@ -79,6 +79,8 @@ info=Інформація
pro=Pro
page=Page
pages=Pages
loading=Loading...
addToDoc=Add to Document
legal.privacy=Privacy Policy
legal.terms=Terms and Conditions
@@ -782,6 +784,9 @@ compare.highlightColor.2=Highlight Color 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.
#BookToPDF
BookToPDF.title=Книги та комікси в PDF
@@ -804,6 +809,11 @@ 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
#repair
@@ -1220,5 +1230,3 @@ splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for
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

View File

@@ -79,6 +79,8 @@ info=Thông tin
pro=Pro
page=Page
pages=Pages
loading=Loading...
addToDoc=Add to Document
legal.privacy=Privacy Policy
legal.terms=Terms and Conditions
@@ -782,6 +784,9 @@ compare.highlightColor.2=Màu đánh dấu 2:
compare.document.1=Tài liệu 1
compare.document.2=Tài liệu 2
compare.submit=So sánh
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.
#BookToPDF
BookToPDF.title=Sách và truyện tranh sang PDF
@@ -804,6 +809,11 @@ sign.draw=Vẽ chữ ký
sign.text=Nhập văn bản
sign.clear=Xóa
sign.add=Thêm
sign.saved=Saved Signatures
sign.save=Save Signature
sign.personalSigs=Personal Signatures
sign.sharedSigs=Shared Signatures
sign.noSavedSigs=No saved signatures found
#repair
@@ -1220,5 +1230,3 @@ splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for
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

View File

@@ -79,6 +79,8 @@ info=信息
pro=Pro
page=Page
pages=Pages
loading=Loading...
addToDoc=Add to Document
legal.privacy=Privacy Policy
legal.terms=Terms and Conditions
@@ -782,6 +784,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.
#BookToPDF
BookToPDF.title=电子书和漫画转换成PDF
@@ -804,6 +809,11 @@ 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
#repair
@@ -1220,5 +1230,3 @@ splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for
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

View File

@@ -79,6 +79,8 @@ info=資訊
pro=專業版
page=頁面
pages=頁面
loading=Loading...
addToDoc=Add to Document
legal.privacy=隱私權政策
legal.terms=使用條款
@@ -782,6 +784,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.
#BookToPDF
BookToPDF.title=電子書和漫畫轉 PDF
@@ -804,6 +809,11 @@ 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
#repair
@@ -1220,5 +1230,3 @@ splitByChapters.desc.2=書籤層級選擇用於分割的書籤層級0 表
splitByChapters.desc.3=包含中繼資料:如果勾選,原始 PDF 的中繼資料將包含在每個分割後的 PDF 中。
splitByChapters.desc.4=允許重複:如果勾選,允許同一頁面上的多個書籤建立獨立的 PDF。
splitByChapters.submit=分割 PDF

View File

@@ -3,17 +3,24 @@
{
"moduleName": "ch.qos.logback:logback-classic",
"moduleUrl": "http://www.qos.ch",
"moduleVersion": "1.5.8",
"moduleVersion": "1.5.11",
"moduleLicense": "GNU Lesser General Public License",
"moduleLicenseUrl": "http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html"
},
{
"moduleName": "ch.qos.logback:logback-core",
"moduleUrl": "http://www.qos.ch",
"moduleVersion": "1.5.8",
"moduleVersion": "1.5.11",
"moduleLicense": "GNU Lesser General Public License",
"moduleLicenseUrl": "http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html"
},
{
"moduleName": "com.adobe.xmp:xmpcore",
"moduleUrl": "https://www.adobe.com/devnet/xmp/library/eula-xmp-library-java.html",
"moduleVersion": "6.1.11",
"moduleLicense": "The BSD 3-Clause License (BSD3)",
"moduleLicenseUrl": "https://opensource.org/licenses/BSD-3-Clause"
},
{
"moduleName": "com.bucket4j:bucket4j_jdk17-core",
"moduleUrl": "http://github.com/bucket4j/bucket4j/bucket4j_jdk17-core",
@@ -28,6 +35,13 @@
"moduleLicense": "MIT",
"moduleLicenseUrl": "https://opensource.org/licenses/MIT"
},
{
"moduleName": "com.drewnoakes:metadata-extractor",
"moduleUrl": "https://drewnoakes.com/code/exif/",
"moduleVersion": "2.19.0",
"moduleLicense": "The Apache Software License, Version 2.0",
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
},
{
"moduleName": "com.fasterxml.jackson.core:jackson-annotations",
"moduleUrl": "https://github.com/FasterXML/jackson",
@@ -400,7 +414,7 @@
{
"moduleName": "io.micrometer:micrometer-commons",
"moduleUrl": "https://github.com/micrometer-metrics/micrometer",
"moduleVersion": "1.13.4",
"moduleVersion": "1.13.6",
"moduleLicense": "The Apache Software License, Version 2.0",
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
},
@@ -414,14 +428,14 @@
{
"moduleName": "io.micrometer:micrometer-jakarta9",
"moduleUrl": "https://github.com/micrometer-metrics/micrometer",
"moduleVersion": "1.13.4",
"moduleVersion": "1.13.6",
"moduleLicense": "The Apache Software License, Version 2.0",
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
},
{
"moduleName": "io.micrometer:micrometer-observation",
"moduleUrl": "https://github.com/micrometer-metrics/micrometer",
"moduleVersion": "1.13.4",
"moduleVersion": "1.13.6",
"moduleLicense": "The Apache Software License, Version 2.0",
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
},
@@ -681,7 +695,7 @@
{
"moduleName": "org.apache.tomcat.embed:tomcat-embed-el",
"moduleUrl": "https://tomcat.apache.org/",
"moduleVersion": "10.1.30",
"moduleVersion": "10.1.31",
"moduleLicense": "Apache License, Version 2.0",
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
},
@@ -776,182 +790,182 @@
{
"moduleName": "org.eclipse.jetty.ee10.websocket:jetty-ee10-websocket-jakarta-client",
"moduleUrl": "https://jetty.org/",
"moduleVersion": "12.0.13",
"moduleVersion": "12.0.14",
"moduleLicense": "Eclipse Public License - Version 2.0",
"moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/"
},
{
"moduleName": "org.eclipse.jetty.ee10.websocket:jetty-ee10-websocket-jakarta-common",
"moduleUrl": "https://jetty.org/",
"moduleVersion": "12.0.13",
"moduleVersion": "12.0.14",
"moduleLicense": "Eclipse Public License - Version 2.0",
"moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/"
},
{
"moduleName": "org.eclipse.jetty.ee10.websocket:jetty-ee10-websocket-jakarta-server",
"moduleUrl": "https://jetty.org/",
"moduleVersion": "12.0.13",
"moduleVersion": "12.0.14",
"moduleLicense": "Eclipse Public License - Version 2.0",
"moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/"
},
{
"moduleName": "org.eclipse.jetty.ee10.websocket:jetty-ee10-websocket-jetty-server",
"moduleUrl": "https://jetty.org/",
"moduleVersion": "12.0.13",
"moduleVersion": "12.0.14",
"moduleLicense": "Eclipse Public License - Version 2.0",
"moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/"
},
{
"moduleName": "org.eclipse.jetty.ee10.websocket:jetty-ee10-websocket-servlet",
"moduleUrl": "https://jetty.org/",
"moduleVersion": "12.0.13",
"moduleVersion": "12.0.14",
"moduleLicense": "Eclipse Public License - Version 2.0",
"moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/"
},
{
"moduleName": "org.eclipse.jetty.ee10:jetty-ee10-annotations",
"moduleUrl": "https://jetty.org/",
"moduleVersion": "12.0.13",
"moduleVersion": "12.0.14",
"moduleLicense": "Eclipse Public License - Version 2.0",
"moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/"
},
{
"moduleName": "org.eclipse.jetty.ee10:jetty-ee10-plus",
"moduleUrl": "https://jetty.org/",
"moduleVersion": "12.0.13",
"moduleVersion": "12.0.14",
"moduleLicense": "Eclipse Public License - Version 2.0",
"moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/"
},
{
"moduleName": "org.eclipse.jetty.ee10:jetty-ee10-servlet",
"moduleUrl": "https://jetty.org/",
"moduleVersion": "12.0.13",
"moduleVersion": "12.0.14",
"moduleLicense": "Eclipse Public License - Version 2.0",
"moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/"
},
{
"moduleName": "org.eclipse.jetty.ee10:jetty-ee10-servlets",
"moduleUrl": "https://jetty.org/",
"moduleVersion": "12.0.13",
"moduleVersion": "12.0.14",
"moduleLicense": "Eclipse Public License - Version 2.0",
"moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/"
},
{
"moduleName": "org.eclipse.jetty.ee10:jetty-ee10-webapp",
"moduleUrl": "https://jetty.org/",
"moduleVersion": "12.0.13",
"moduleVersion": "12.0.14",
"moduleLicense": "Eclipse Public License - Version 2.0",
"moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/"
},
{
"moduleName": "org.eclipse.jetty.websocket:jetty-websocket-core-client",
"moduleUrl": "https://jetty.org/",
"moduleVersion": "12.0.13",
"moduleVersion": "12.0.14",
"moduleLicense": "Eclipse Public License - Version 2.0",
"moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/"
},
{
"moduleName": "org.eclipse.jetty.websocket:jetty-websocket-core-common",
"moduleUrl": "https://jetty.org/",
"moduleVersion": "12.0.13",
"moduleVersion": "12.0.14",
"moduleLicense": "Eclipse Public License - Version 2.0",
"moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/"
},
{
"moduleName": "org.eclipse.jetty.websocket:jetty-websocket-core-server",
"moduleUrl": "https://jetty.org/",
"moduleVersion": "12.0.13",
"moduleVersion": "12.0.14",
"moduleLicense": "Eclipse Public License - Version 2.0",
"moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/"
},
{
"moduleName": "org.eclipse.jetty.websocket:jetty-websocket-jetty-api",
"moduleUrl": "https://jetty.org/",
"moduleVersion": "12.0.13",
"moduleVersion": "12.0.14",
"moduleLicense": "Eclipse Public License - Version 2.0",
"moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/"
},
{
"moduleName": "org.eclipse.jetty.websocket:jetty-websocket-jetty-common",
"moduleUrl": "https://jetty.org/",
"moduleVersion": "12.0.13",
"moduleVersion": "12.0.14",
"moduleLicense": "Eclipse Public License - Version 2.0",
"moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/"
},
{
"moduleName": "org.eclipse.jetty:jetty-alpn-client",
"moduleUrl": "https://jetty.org/",
"moduleVersion": "12.0.13",
"moduleVersion": "12.0.14",
"moduleLicense": "Eclipse Public License - Version 2.0",
"moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/"
},
{
"moduleName": "org.eclipse.jetty:jetty-client",
"moduleUrl": "https://jetty.org/",
"moduleVersion": "12.0.13",
"moduleVersion": "12.0.14",
"moduleLicense": "Eclipse Public License - Version 2.0",
"moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/"
},
{
"moduleName": "org.eclipse.jetty:jetty-ee",
"moduleUrl": "https://jetty.org/",
"moduleVersion": "12.0.13",
"moduleVersion": "12.0.14",
"moduleLicense": "Eclipse Public License - Version 2.0",
"moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/"
},
{
"moduleName": "org.eclipse.jetty:jetty-http",
"moduleUrl": "https://jetty.org/",
"moduleVersion": "12.0.13",
"moduleVersion": "12.0.14",
"moduleLicense": "Eclipse Public License - Version 2.0",
"moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/"
},
{
"moduleName": "org.eclipse.jetty:jetty-io",
"moduleUrl": "https://jetty.org/",
"moduleVersion": "12.0.13",
"moduleVersion": "12.0.14",
"moduleLicense": "Eclipse Public License - Version 2.0",
"moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/"
},
{
"moduleName": "org.eclipse.jetty:jetty-plus",
"moduleUrl": "https://jetty.org/",
"moduleVersion": "12.0.13",
"moduleVersion": "12.0.14",
"moduleLicense": "Eclipse Public License - Version 2.0",
"moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/"
},
{
"moduleName": "org.eclipse.jetty:jetty-security",
"moduleUrl": "https://jetty.org/",
"moduleVersion": "12.0.13",
"moduleVersion": "12.0.14",
"moduleLicense": "Eclipse Public License - Version 2.0",
"moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/"
},
{
"moduleName": "org.eclipse.jetty:jetty-server",
"moduleUrl": "https://jetty.org/",
"moduleVersion": "12.0.13",
"moduleVersion": "12.0.14",
"moduleLicense": "Eclipse Public License - Version 2.0",
"moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/"
},
{
"moduleName": "org.eclipse.jetty:jetty-session",
"moduleUrl": "https://jetty.org/",
"moduleVersion": "12.0.13",
"moduleVersion": "12.0.14",
"moduleLicense": "Eclipse Public License - Version 2.0",
"moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/"
},
{
"moduleName": "org.eclipse.jetty:jetty-util",
"moduleUrl": "https://jetty.org/",
"moduleVersion": "12.0.13",
"moduleVersion": "12.0.14",
"moduleLicense": "Eclipse Public License - Version 2.0",
"moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/"
},
{
"moduleName": "org.eclipse.jetty:jetty-xml",
"moduleUrl": "https://jetty.org/",
"moduleVersion": "12.0.13",
"moduleVersion": "12.0.14",
"moduleLicense": "Eclipse Public License - Version 2.0",
"moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/"
},
@@ -1139,266 +1153,266 @@
{
"moduleName": "org.springframework.boot:spring-boot",
"moduleUrl": "https://spring.io/projects/spring-boot",
"moduleVersion": "3.3.4",
"moduleVersion": "3.3.5",
"moduleLicense": "Apache License, Version 2.0",
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
},
{
"moduleName": "org.springframework.boot:spring-boot-actuator",
"moduleUrl": "https://spring.io/projects/spring-boot",
"moduleVersion": "3.3.4",
"moduleVersion": "3.3.5",
"moduleLicense": "Apache License, Version 2.0",
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
},
{
"moduleName": "org.springframework.boot:spring-boot-actuator-autoconfigure",
"moduleUrl": "https://spring.io/projects/spring-boot",
"moduleVersion": "3.3.4",
"moduleVersion": "3.3.5",
"moduleLicense": "Apache License, Version 2.0",
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
},
{
"moduleName": "org.springframework.boot:spring-boot-autoconfigure",
"moduleUrl": "https://spring.io/projects/spring-boot",
"moduleVersion": "3.3.4",
"moduleVersion": "3.3.5",
"moduleLicense": "Apache License, Version 2.0",
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
},
{
"moduleName": "org.springframework.boot:spring-boot-devtools",
"moduleUrl": "https://spring.io/projects/spring-boot",
"moduleVersion": "3.3.4",
"moduleVersion": "3.3.5",
"moduleLicense": "Apache License, Version 2.0",
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
},
{
"moduleName": "org.springframework.boot:spring-boot-starter",
"moduleUrl": "https://spring.io/projects/spring-boot",
"moduleVersion": "3.3.4",
"moduleVersion": "3.3.5",
"moduleLicense": "Apache License, Version 2.0",
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
},
{
"moduleName": "org.springframework.boot:spring-boot-starter-actuator",
"moduleUrl": "https://spring.io/projects/spring-boot",
"moduleVersion": "3.3.4",
"moduleVersion": "3.3.5",
"moduleLicense": "Apache License, Version 2.0",
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
},
{
"moduleName": "org.springframework.boot:spring-boot-starter-aop",
"moduleUrl": "https://spring.io/projects/spring-boot",
"moduleVersion": "3.3.4",
"moduleVersion": "3.3.5",
"moduleLicense": "Apache License, Version 2.0",
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
},
{
"moduleName": "org.springframework.boot:spring-boot-starter-data-jpa",
"moduleUrl": "https://spring.io/projects/spring-boot",
"moduleVersion": "3.3.4",
"moduleVersion": "3.3.5",
"moduleLicense": "Apache License, Version 2.0",
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
},
{
"moduleName": "org.springframework.boot:spring-boot-starter-jdbc",
"moduleUrl": "https://spring.io/projects/spring-boot",
"moduleVersion": "3.3.4",
"moduleVersion": "3.3.5",
"moduleLicense": "Apache License, Version 2.0",
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
},
{
"moduleName": "org.springframework.boot:spring-boot-starter-jetty",
"moduleUrl": "https://spring.io/projects/spring-boot",
"moduleVersion": "3.3.4",
"moduleVersion": "3.3.5",
"moduleLicense": "Apache License, Version 2.0",
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
},
{
"moduleName": "org.springframework.boot:spring-boot-starter-json",
"moduleUrl": "https://spring.io/projects/spring-boot",
"moduleVersion": "3.3.4",
"moduleVersion": "3.3.5",
"moduleLicense": "Apache License, Version 2.0",
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
},
{
"moduleName": "org.springframework.boot:spring-boot-starter-logging",
"moduleUrl": "https://spring.io/projects/spring-boot",
"moduleVersion": "3.3.4",
"moduleVersion": "3.3.5",
"moduleLicense": "Apache License, Version 2.0",
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
},
{
"moduleName": "org.springframework.boot:spring-boot-starter-oauth2-client",
"moduleUrl": "https://spring.io/projects/spring-boot",
"moduleVersion": "3.3.4",
"moduleVersion": "3.3.5",
"moduleLicense": "Apache License, Version 2.0",
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
},
{
"moduleName": "org.springframework.boot:spring-boot-starter-security",
"moduleUrl": "https://spring.io/projects/spring-boot",
"moduleVersion": "3.3.4",
"moduleVersion": "3.3.5",
"moduleLicense": "Apache License, Version 2.0",
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
},
{
"moduleName": "org.springframework.boot:spring-boot-starter-thymeleaf",
"moduleUrl": "https://spring.io/projects/spring-boot",
"moduleVersion": "3.3.4",
"moduleVersion": "3.3.5",
"moduleLicense": "Apache License, Version 2.0",
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
},
{
"moduleName": "org.springframework.boot:spring-boot-starter-web",
"moduleUrl": "https://spring.io/projects/spring-boot",
"moduleVersion": "3.3.4",
"moduleVersion": "3.3.5",
"moduleLicense": "Apache License, Version 2.0",
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
},
{
"moduleName": "org.springframework.data:spring-data-commons",
"moduleUrl": "https://spring.io/projects/spring-data",
"moduleVersion": "3.3.4",
"moduleVersion": "3.3.5",
"moduleLicense": "Apache License, Version 2.0",
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
},
{
"moduleName": "org.springframework.data:spring-data-jpa",
"moduleUrl": "https://projects.spring.io/spring-data-jpa",
"moduleVersion": "3.3.4",
"moduleVersion": "3.3.5",
"moduleLicense": "Apache License, Version 2.0",
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
},
{
"moduleName": "org.springframework.security:spring-security-config",
"moduleUrl": "https://spring.io/projects/spring-security",
"moduleVersion": "6.3.3",
"moduleVersion": "6.3.4",
"moduleLicense": "Apache License, Version 2.0",
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
},
{
"moduleName": "org.springframework.security:spring-security-core",
"moduleUrl": "https://spring.io/projects/spring-security",
"moduleVersion": "6.3.3",
"moduleVersion": "6.3.4",
"moduleLicense": "Apache License, Version 2.0",
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
},
{
"moduleName": "org.springframework.security:spring-security-crypto",
"moduleUrl": "https://spring.io/projects/spring-security",
"moduleVersion": "6.3.3",
"moduleVersion": "6.3.4",
"moduleLicense": "Apache License, Version 2.0",
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
},
{
"moduleName": "org.springframework.security:spring-security-oauth2-client",
"moduleUrl": "https://spring.io/projects/spring-security",
"moduleVersion": "6.3.3",
"moduleVersion": "6.3.4",
"moduleLicense": "Apache License, Version 2.0",
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
},
{
"moduleName": "org.springframework.security:spring-security-oauth2-core",
"moduleUrl": "https://spring.io/projects/spring-security",
"moduleVersion": "6.3.3",
"moduleVersion": "6.3.4",
"moduleLicense": "Apache License, Version 2.0",
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
},
{
"moduleName": "org.springframework.security:spring-security-oauth2-jose",
"moduleUrl": "https://spring.io/projects/spring-security",
"moduleVersion": "6.3.3",
"moduleVersion": "6.3.4",
"moduleLicense": "Apache License, Version 2.0",
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
},
{
"moduleName": "org.springframework.security:spring-security-saml2-service-provider",
"moduleUrl": "https://spring.io/projects/spring-security",
"moduleVersion": "6.3.3",
"moduleVersion": "6.3.4",
"moduleLicense": "Apache License, Version 2.0",
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
},
{
"moduleName": "org.springframework.security:spring-security-web",
"moduleUrl": "https://spring.io/projects/spring-security",
"moduleVersion": "6.3.3",
"moduleVersion": "6.3.4",
"moduleLicense": "Apache License, Version 2.0",
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
},
{
"moduleName": "org.springframework:spring-aop",
"moduleUrl": "https://github.com/spring-projects/spring-framework",
"moduleVersion": "6.1.13",
"moduleVersion": "6.1.14",
"moduleLicense": "Apache License, Version 2.0",
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
},
{
"moduleName": "org.springframework:spring-aspects",
"moduleUrl": "https://github.com/spring-projects/spring-framework",
"moduleVersion": "6.1.13",
"moduleVersion": "6.1.14",
"moduleLicense": "Apache License, Version 2.0",
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
},
{
"moduleName": "org.springframework:spring-beans",
"moduleUrl": "https://github.com/spring-projects/spring-framework",
"moduleVersion": "6.1.13",
"moduleVersion": "6.1.14",
"moduleLicense": "Apache License, Version 2.0",
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
},
{
"moduleName": "org.springframework:spring-context",
"moduleUrl": "https://github.com/spring-projects/spring-framework",
"moduleVersion": "6.1.13",
"moduleVersion": "6.1.14",
"moduleLicense": "Apache License, Version 2.0",
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
},
{
"moduleName": "org.springframework:spring-core",
"moduleUrl": "https://github.com/spring-projects/spring-framework",
"moduleVersion": "6.1.13",
"moduleVersion": "6.1.14",
"moduleLicense": "Apache License, Version 2.0",
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
},
{
"moduleName": "org.springframework:spring-expression",
"moduleUrl": "https://github.com/spring-projects/spring-framework",
"moduleVersion": "6.1.13",
"moduleVersion": "6.1.14",
"moduleLicense": "Apache License, Version 2.0",
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
},
{
"moduleName": "org.springframework:spring-jcl",
"moduleUrl": "https://github.com/spring-projects/spring-framework",
"moduleVersion": "6.1.13",
"moduleVersion": "6.1.14",
"moduleLicense": "Apache License, Version 2.0",
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
},
{
"moduleName": "org.springframework:spring-jdbc",
"moduleUrl": "https://github.com/spring-projects/spring-framework",
"moduleVersion": "6.1.13",
"moduleVersion": "6.1.14",
"moduleLicense": "Apache License, Version 2.0",
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
},
{
"moduleName": "org.springframework:spring-orm",
"moduleUrl": "https://github.com/spring-projects/spring-framework",
"moduleVersion": "6.1.13",
"moduleVersion": "6.1.14",
"moduleLicense": "Apache License, Version 2.0",
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
},
{
"moduleName": "org.springframework:spring-tx",
"moduleUrl": "https://github.com/spring-projects/spring-framework",
"moduleVersion": "6.1.13",
"moduleVersion": "6.1.14",
"moduleLicense": "Apache License, Version 2.0",
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
},
{
"moduleName": "org.springframework:spring-web",
"moduleUrl": "https://github.com/spring-projects/spring-framework",
"moduleVersion": "6.1.13",
"moduleVersion": "6.1.14",
"moduleLicense": "Apache License, Version 2.0",
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
},

View File

@@ -329,11 +329,14 @@ span.icon-text::after {
}
}
.go-pro-link {
.go-pro-link {
position: relative;
padding: 0.5rem 1rem;
transition: all 0.3s ease;
}
z-index: 1;
display: inline-block;
width: auto;
}
.go-pro-badge {
display: inline-block;
@@ -350,4 +353,4 @@ span.icon-text::after {
.go-pro-link:hover .go-pro-badge {
background-color: #0056b3;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
}
}

View File

@@ -62,3 +62,53 @@ select#font-select option {
background-color: rgba(52, 152, 219, 0.2);
/* Darken background on hover */
}
.signature-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: 1rem;
padding: 1rem;
max-height: 400px;
overflow-y: auto;
}
.signature-list {
max-height: 400px;
overflow-y: auto;
}
.signature-list-item {
padding: 0.75rem;
border: 1px solid #dee2e6;
border-radius: 4px;
margin-bottom: 0.5rem;
cursor: pointer;
transition: background-color 0.2s;
}
.signature-list-item:hover {
background-color: #f8f9fa;
}
.signature-list-info {
display: flex;
justify-content: space-between;
align-items: center;
}
.signature-list-name {
font-weight: 500;
}
.signature-list-details {
color: #6c757d;
font-size: 0.875rem;
}
.signature-list-details small:not(:last-child) {
margin-right: 1rem;
}
.view-toggle {
text-align: right;
padding: 0.5rem 1rem;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,145 @@
importScripts('./diff.js');
self.onmessage = async function (e) {
const { text1, text2, color1, color2 } = e.data;
console.log('Received text for comparison:', { text1, text2 });
const startTime = performance.now();
if (text1.trim() === "" || text2.trim() === "") {
self.postMessage({ status: 'error', message: 'One or both of the texts are empty.' });
return;
}
const words1 = text1.split(' ');
const words2 = text2.split(' ');
const MAX_WORD_COUNT = 150000;
const COMPLEX_WORD_COUNT = 50000;
const BATCH_SIZE = 5000; // Define a suitable batch size for processing
const OVERLAP_SIZE = 200; // Number of words to overlap - bigger increases accuracy but affects performance
const isComplex = words1.length > COMPLEX_WORD_COUNT || words2.length > COMPLEX_WORD_COUNT;
const isTooLarge = words1.length > MAX_WORD_COUNT || words2.length > MAX_WORD_COUNT;
let complexMessage = 'One or both of the provided documents are large files, accuracy of comparison may be reduced';
let tooLargeMessage = 'One or Both of the provided documents are too large to process';
// Listen for messages from the main thread
self.addEventListener('message', (event) => {
if (event.data.type === 'SET_TOO_LARGE_MESSAGE') {
tooLargeMessage = event.data.message;
}
if (event.data.type === 'SET_COMPLEX_MESSAGE') {
complexMessage = event.data.message;
}
});
if (isTooLarge) {
self.postMessage({
status: 'warning',
message: tooLargeMessage,
});
return;
} else {
if (isComplex) {
self.postMessage({
status: 'warning',
message: complexMessage,
});
}
// Perform diff operation depending on document size
const differences = isComplex
? await staggeredBatchDiff(words1, words2, color1, color2, BATCH_SIZE, OVERLAP_SIZE)
: diff(words1, words2, color1, color2);
console.log(`Diff operation took ${performance.now() - startTime} milliseconds`);
self.postMessage({ status: 'success', differences });
}
};
//Splits text into smaller batches to run through diff checking algorithms. overlaps the batches to help ensure
async function staggeredBatchDiff(words1, words2, color1, color2, batchSize, overlapSize) {
const differences = [];
const totalWords1 = words1.length;
const totalWords2 = words2.length;
let previousEnd1 = 0; // Track where the last batch ended in words1
let previousEnd2 = 0; // Track where the last batch ended in words2
// Function to determine if differences are large, differences that are too large indicate potential error in batching
const isLargeDifference = (differences) => {
return differences.length > 50;
};
while (previousEnd1 < totalWords1 || previousEnd2 < totalWords2) {
// Define the next chunk boundaries
const start1 = previousEnd1;
const end1 = Math.min(start1 + batchSize, totalWords1);
const start2 = previousEnd2;
const end2 = Math.min(start2 + batchSize, totalWords2);
//If difference is too high decrease batch size for more granular check
const dynamicBatchSize = isLargeDifference(differences) ? batchSize / 2 : batchSize;
// Adjust the size of the current chunk using dynamic batch size
const batchWords1 = words1.slice(start1, end1 + dynamicBatchSize);
const batchWords2 = words2.slice(start2, end2 + dynamicBatchSize);
// Include overlap from the previous chunk
const overlapWords1 = previousEnd1 > 0 ? words1.slice(Math.max(0, previousEnd1 - overlapSize), previousEnd1) : [];
const overlapWords2 = previousEnd2 > 0 ? words2.slice(Math.max(0, previousEnd2 - overlapSize), previousEnd2) : [];
// Combine overlaps and current batches for comparison
const combinedWords1 = overlapWords1.concat(batchWords1);
const combinedWords2 = overlapWords2.concat(batchWords2);
// Perform the diff on the combined words
const batchDifferences = diff(combinedWords1, combinedWords2, color1, color2);
differences.push(...batchDifferences);
// Update the previous end indices based on the results of this batch
previousEnd1 = end1;
previousEnd2 = end2;
}
return differences;
}
// Standard diff function for small text comparisons
function diff(words1, words2, color1, color2) {
console.log(`Starting diff between ${words1.length} words and ${words2.length} words`);
const matrix = Array.from({ length: words1.length + 1 }, () => Array(words2.length + 1).fill(0));
for (let i = 1; i <= words1.length; i++) {
for (let j = 1; j <= words2.length; j++) {
matrix[i][j] = words1[i - 1] === words2[j - 1]
? matrix[i - 1][j - 1] + 1
: Math.max(matrix[i][j - 1], matrix[i - 1][j]);
}
}
return backtrack(matrix, words1, words2, color1, color2);
}
// Backtrack function to find differences
function backtrack(matrix, words1, words2, color1, color2) {
let i = words1.length, j = words2.length;
const differences = [];
while (i > 0 || j > 0) {
if (i > 0 && j > 0 && words1[i - 1] === words2[j - 1]) {
differences.unshift(['black', words1[i - 1]]);
i--; j--;
} else if (j > 0 && (i === 0 || matrix[i][j] === matrix[i][j - 1])) {
differences.unshift([color2, words2[j - 1]]);
j--;
} else {
differences.unshift([color1, words1[i - 1]]);
i--;
}
}
return differences;
}

View File

@@ -0,0 +1,29 @@
window.fetchWithCsrf = async function(url, options = {}) {
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;
}
// Create a new options object to avoid modifying the passed object
const fetchOptions = { ...options };
// Ensure headers object exists
fetchOptions.headers = { ...options.headers };
// Add CSRF token if available
const csrfToken = getCsrfToken();
if (csrfToken) {
fetchOptions.headers['X-XSRF-TOKEN'] = csrfToken;
}
return fetch(url, fetchOptions);
}

View File

@@ -119,7 +119,7 @@ document.getElementById("submitConfigBtn").addEventListener("click", function ()
formData.append("json", pipelineConfigJson);
console.log("formData", formData);
fetch("api/v1/pipeline/handleData", {
fetchWithCsrf("api/v1/pipeline/handleData", {
method: "POST",
body: formData,
})
@@ -154,7 +154,7 @@ let apiDocs = {};
let apiSchemas = {};
let operationSettings = {};
fetch("v1/api-docs")
fetchWithCsrf("v1/api-docs")
.then((response) => response.json())
.then((data) => {
apiDocs = data.paths;

View File

@@ -283,25 +283,5 @@
</script>
<th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
</div>
<div th:if="${altLogin}" class="modal fade" id="editUserModal" tabindex="-1" role="dialog" aria-labelledby="editUserModalLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="editUserModalLabel" th:text="#{login.ssoSignIn}"></h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close">
<span class="material-symbols-rounded">close</span>
</button>
</div>
<div class="modal-body">
<div class="mb-3" th:each="provider : ${providerlist}">
<a th:href="@{|/oauth2/authorization/${provider.key}|}" th:text="${provider.value}" class="w-100 btn btn-lg btn-primary">OpenID Connect</a>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal" th:text="#{close}"></button>
</div>
</div>
</div>
</div>
</body>
</html>

View File

@@ -27,7 +27,7 @@
<!-- Change Username Form -->
<h4 th:text="#{changeCreds.changePassword}">Change password</h4>
<form action="api/v1/user/change-password-on-login" method="post" id="formsavechangecreds">
<form th:action="@{'api/v1/user/change-password-on-login'}" method="post" id="formsavechangecreds">
<div class="mb-3">
<label for="currentPassword" th:text="#{changeCreds.oldPassword}">Old Password</label>
<input type="password" class="form-control" name="currentPassword" id="currentPassword" th:placeholder="#{changeCreds.oldPassword}">

View File

@@ -351,7 +351,7 @@
</a>
<div class="dropdown-menu dropdown-menu-tp" aria-labelledby="searchDropdown">
<div class="dropdown-menu-wrapper px-xl-2 px-2">
<form class="d-flex p-2 search-form" id="searchForm">
<form th:action="@{''}" class="d-flex p-2 search-form" id="searchForm">
<input class="form-control search-input" type="search" placeholder="Search" aria-label="Search" id="navbarSearchInput">
</form>
<!-- Search Results -->

View File

@@ -384,7 +384,7 @@
<script th:src="@{'/js/fetch-utils.js'}"></script>
<script th:inline="javascript">
/*<![CDATA[*/
@@ -398,7 +398,7 @@
});
/*]]>*/
function setAnalytics(enabled) {
fetch('api/v1/settings/update-enable-analytics', {
fetchWithCsrf('api/v1/settings/update-enable-analytics', {
method: 'POST',
headers: {
'Content-Type': 'application/json'

View File

@@ -19,7 +19,7 @@
<span class="material-symbols-rounded tool-header-icon organize">add_to_photos</span>
<span class="tool-header-text" th:text="#{merge.header}"></span>
</div>
<form action="api/v1/general/merge-pdfs" method="post" enctype="multipart/form-data">
<form th:action="@{'api/v1/general/merge-pdfs'}" method="post" enctype="multipart/form-data">
<div class="mb-3">
<label th:text="#{multiPdfDropPrompt}" for="fileInput-input"></label>
<div

View File

@@ -20,7 +20,7 @@
</div>
<!-- pdf selector -->
<div th:replace="~{fragments/common :: fileSelector(name='pdf-upload', multipleInputsForSingleRequest=false, accept='application/pdf')}"></div>
<div th:replace="~{fragments/common :: fileSelector(name='pdf-upload', disableMultipleFiles=true, multipleInputsForSingleRequest=false, accept='application/pdf')}"></div>
<script type="module" th:src="@{'/pdfjs-legacy/pdf.mjs'}"></script>
<script>
let originalFileName = '';
@@ -46,7 +46,7 @@
</script>
<div class="tab-group show-on-file-selected">
<div th:replace="~{fragments/common :: fileSelector(name='image-upload', multipleInputsForSingleRequest=true, accept='image/*', inputText=#{imgPrompt})}"></div>
<div th:replace="~{fragments/common :: fileSelector(name='image-upload', disableMultipleFiles=true, multipleInputsForSingleRequest=true, accept='image/*', inputText=#{imgPrompt})}"></div>
<script>
const imageUpload = document.querySelector('input[name=image-upload]');
imageUpload.addEventListener('change', e => {

View File

@@ -21,7 +21,7 @@
<div class="container">
<div class="row justify-content-center">
<div class="col-md-12 bg-card">
<form>
<form th:action="@{''}">
<div class="row justify-content-center">
<div class="col-md-3">

View File

@@ -1,236 +1,256 @@
<!DOCTYPE html>
<html th:lang="${#locale.language}" th:dir="#{language.direction}" th:data-language="${#locale.toString()}" xmlns:th="https://www.thymeleaf.org">
<head>
<html th:lang="${#locale.language}" th:dir="#{language.direction}" th:data-language="${#locale.toString()}"
xmlns:th="https://www.thymeleaf.org">
<head>
<th:block th:insert="~{fragments/common :: head(title=#{compare.title}, header=#{compare.header})}"></th:block>
<style>
.result-column {
border: 1px solid #ccc;
padding: 15px;
margin-bottom: 15px;
overflow-y: auto;
height: calc(100vh - 400px);
white-space: pre-wrap;
}
.flex-container {
display: flex;
flex-direction: row;
}
.color-selector {
display: flex;
flex-direction: row;
align-items: center;
width: 50%;
max-height: 100px;
margin-bottom: 2rem;
}
#color-box1, #color-box2 {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
border: none;
background-color: transparent;
}
.spacer1 {
padding-right: calc(var(--bs-gutter-x) * .5);
}
.spacer2 {
padding-left: calc(var(--bs-gutter-x) * .5);
}
</style>
</head>
<style>
.result-column {
border: 1px solid #ccc;
padding: 15px;
margin-bottom: 15px;
overflow-y: auto;
height: calc(100vh - 400px);
white-space: pre-wrap;
}
<body>
<div id="page-container">
<div id="content-wrap">
<th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
<br><br>
<div class="container">
<div class="row justify-content-center">
<div class="col-md-9 bg-card">
<div class="tool-header">
<span class="material-symbols-rounded tool-header-icon other">compare</span>
<span class="tool-header-text" th:text="#{compare.header}"></span>
</div>
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='application/pdf', remoteCall='false')}"></div>
<div th:replace="~{fragments/common :: fileSelector(name='fileInput2', multipleInputsForSingleRequest=false, accept='application/pdf', remoteCall='false')}"></div>
.flex-container {
display: flex;
flex-direction: row;
}
<div class="row">
<div class="flex-container">
<div class="color-selector spacer1">
<label th:text="#{compare.highlightColor.1}"></label>
<label for="color-box1"></label><input type="color" id="color-box1" value="#ff0000">
</div>
<div class="color-selector spacer2">
<label th:text="#{compare.highlightColor.2}"></label>
<label for="color-box2"></label><input type="color" id="color-box2" value="#008000">
</div>
</div>
</div>
.color-selector {
display: flex;
flex-direction: row;
align-items: center;
width: 50%;
max-height: 100px;
margin-bottom: 2rem;
}
<button class="btn btn-primary" onclick="comparePDFs()" th:text="#{compare.submit}"></button>
#color-box1,
#color-box2 {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
border: none;
background-color: transparent;
}
<div class="row">
<div class="col-md-6">
<h3 th:text="#{compare.document.1}"></h3>
<div id="result1" class="result-column"></div>
</div>
<div class="col-md-6">
<h3 th:text="#{compare.document.2}"></h3>
<div id="result2" class="result-column"></div>
</div>
</div>
<script type="module" th:src="@{'/pdfjs-legacy/pdf.mjs'}"></script>
<script>
// get the elements
var result1 = document.getElementById('result1');
var result2 = document.getElementById('result2');
.spacer1 {
padding-right: calc(var(--bs-gutter-x) * .5);
}
// add event listeners
result1.addEventListener('scroll', function() {
result2.scrollTop = result1.scrollTop;
});
.spacer2 {
padding-left: calc(var(--bs-gutter-x) * .5);
}
</style>
</head>
result2.addEventListener('scroll', function() {
result1.scrollTop = result2.scrollTop;
});
async function comparePDFs() {
const file1 = document.getElementById("fileInput-input").files[0];
const file2 = document.getElementById("fileInput2-input").files[0];
var color1 = document.getElementById('color-box1').value;
var color2 = document.getElementById('color-box2').value;
if (!file1 || !file2) {
console.error("Please select two PDF files to compare");
return;
}
pdfjsLib.GlobalWorkerOptions.workerSrc = './pdfjs-legacy/pdf.worker.mjs'
const [pdf1, pdf2] = await Promise.all([
pdfjsLib.getDocument(URL.createObjectURL(file1)).promise,
pdfjsLib.getDocument(URL.createObjectURL(file2)).promise
]);
const extractText = async (pdf) => {
const pages = [];
for (let i = 1; i <= pdf.numPages; i++) {
const page = await pdf.getPage(i);
const content = await page.getTextContent();
const strings = content.items.map(item => item.str);
pages.push(strings.join(" "));
}
return pages.join(" ");
};
const [text1, text2] = await Promise.all([
extractText(pdf1),
extractText(pdf2)
]);
if (text1.trim() === "" || text2.trim() === "") {
alert("One or both of the selected PDFs have no text content. Please choose PDFs with text for comparison.");
return;
}
const diff = (text1, text2) => {
const words1 = text1.split(' ');
const words2 = text2.split(' ');
// Create a 2D array to hold our "matrix"
const matrix = Array(words1.length + 1).fill(null).map(() => Array(words2.length + 1).fill(0));
// Perform standard LCS algorithm
for (let i = 1; i <= words1.length; i++) {
for (let j = 1; j <= words2.length; j++) {
if (words1[i - 1] === words2[j - 1]) {
matrix[i][j] = matrix[i - 1][j - 1] + 1;
} else {
matrix[i][j] = Math.max(matrix[i][j - 1], matrix[i - 1][j]);
}
}
}
let i = words1.length;
let j = words2.length;
const differences = [];
// Backtrack through the matrix to create the diff
while (i > 0 || j > 0) {
if (i > 0 && j > 0 && words1[i - 1] === words2[j - 1]) {
differences.unshift(['black', words1[i - 1]]);
i--;
j--;
} else if (j > 0 && (i === 0 || matrix[i][j - 1] >= matrix[i - 1][j])) {
differences.unshift([color2, words2[j - 1]]);
j--;
} else if (i > 0 && (j === 0 || matrix[i][j - 1] < matrix[i - 1][j])) {
differences.unshift([color1, words1[i - 1]]);
i--;
}
}
console.log(differences);
return differences;
};
const differences = diff(text1, text2);
const displayDifferences = (differences) => {
const resultDiv1 = document.getElementById("result1");
const resultDiv2 = document.getElementById("result2");
resultDiv1.innerHTML = "";
resultDiv2.innerHTML = "";
differences.forEach(([color, word]) => {
const span1 = document.createElement("span");
const span2 = document.createElement("span");
// If it's an addition, show it in color2 in the second document and transparent in the first
if (color === color2) {
span1.style.color = "transparent";
span1.style.userSelect = "none";
span2.style.color = color;
}
// If it's a deletion, show it in color1 in the first document and transparent in the second
else if (color === color1) {
span1.style.color = color;
span2.style.color = "transparent";
span2.style.userSelect = "none";
}
// If it's unchanged, show it in black in both
else {
span1.style.color = color;
span2.style.color = color;
}
span1.textContent = word;
span2.textContent = word;
resultDiv1.appendChild(span1);
resultDiv2.appendChild(span2);
// Add space after each word, or a new line if the word ends with a full stop
const spaceOrNewline1 = document.createElement("span");
const spaceOrNewline2 = document.createElement("span");
if (word.endsWith(".")) {
spaceOrNewline1.innerHTML = "<br>";
spaceOrNewline2.innerHTML = "<br>";
} else {
spaceOrNewline1.textContent = " ";
spaceOrNewline2.textContent = " ";
}
resultDiv1.appendChild(spaceOrNewline1);
resultDiv2.appendChild(spaceOrNewline2);
});
};
console.log('Differences:', differences);
displayDifferences(differences);
}
</script>
<body>
<div id="page-container">
<div id="content-wrap">
<th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
<br><br>
<div class="container">
<div class="row justify-content-center">
<div class="col-md-9 bg-card">
<div class="tool-header">
<span class="material-symbols-rounded tool-header-icon other">compare</span>
<span class="tool-header-text" th:text="#{compare.header}"></span>
</div>
<div
th:replace="~{fragments/common :: fileSelector(name='fileInput', disableMultipleFiles=true, multipleInputsForSingleRequest=false, accept='application/pdf', remoteCall='false')}">
</div>
<div
th:replace="~{fragments/common :: fileSelector(name='fileInput2', disableMultipleFiles=true, multipleInputsForSingleRequest=false, accept='application/pdf', remoteCall='false')}">
</div>
<div class="row">
<div class="flex-container">
<div class="color-selector spacer1">
<label th:text="#{compare.highlightColor.1}"></label>
<label for="color-box1"></label><input type="color" id="color-box1" value="#ff0000">
</div>
<div class="color-selector spacer2">
<label th:text="#{compare.highlightColor.2}"></label>
<label for="color-box2"></label><input type="color" id="color-box2" value="#008000">
</div>
</div>
</div>
<button class="btn btn-primary" onclick="comparePDFs()" th:text="#{compare.submit}"></button>
<div class="row">
<div class="col-md-6">
<h3 th:text="#{compare.document.1}"></h3>
<div id="result1" class="result-column"></div>
</div>
<div class="col-md-6">
<h3 th:text="#{compare.document.2}"></h3>
<div id="result2" class="result-column"></div>
</div>
</div>
<script type="module" th:src="@{'/pdfjs-legacy/pdf.mjs'}"></script>
<script th:inline="javascript">
// get the elements
var result1 = document.getElementById('result1');
var result2 = document.getElementById('result2');
// add event listeners
result1.addEventListener('scroll', function () {
result2.scrollTop = result1.scrollTop;
});
result2.addEventListener('scroll', function () {
result1.scrollTop = result2.scrollTop;
});
async function comparePDFs() {
const file1 = document.getElementById("fileInput-input").files[0];
const file2 = document.getElementById("fileInput2-input").files[0];
var color1 = document.getElementById('color-box1').value;
var color2 = document.getElementById('color-box2').value;
const complexMessage = /*[[#{compare.complex.message}]]*/ 'One or both of the provided documents are large files, accuracy of comparison may be reduced';
const largeFilesMessage = /*[[#{compare.large.file.message}]]*/ 'One or Both of the provided documents are too large to process';
const noTextMessage = /*[[#{compare.no.text.message}]]*/ 'One or both of the selected PDFs have no text content. Please choose PDFs with text for comparison."';
if (!file1 || !file2) {
console.error("Please select two PDF files to compare");
return;
}
pdfjsLib.GlobalWorkerOptions.workerSrc = './pdfjs-legacy/pdf.worker.mjs';
const [pdf1, pdf2] = await Promise.all([
pdfjsLib.getDocument(URL.createObjectURL(file1)).promise,
pdfjsLib.getDocument(URL.createObjectURL(file2)).promise
]);
const extractText = async (pdf) => {
const pages = [];
for (let i = 1; i <= pdf.numPages; i++) {
const page = await pdf.getPage(i);
const content = await page.getTextContent();
const strings = content.items.map(item => item.str);
pages.push(strings.join(" "));
}
return pages.join(" ");
};
const [text1, text2] = await Promise.all([
extractText(pdf1),
extractText(pdf2)
]);
if (text1.trim() === "" || text2.trim() === "") {
alert(noTextMessage);
return;
}
const resultDiv1 = document.getElementById("result1");
const resultDiv2 = document.getElementById("result2");
const loading = /*[[#{loading}]]*/ 'Loading...';
resultDiv1.innerHTML = loading;
resultDiv2.innerHTML = loading;
// Create a new Worker
const worker = new Worker('/js/compare/pdfWorker.js');
// Post messages to the worker
worker.postMessage({
type: 'SET_COMPLEX_MESSAGE',
message: complexMessage
});
worker.postMessage({
type: 'SET_TOO_LARGE_MESSAGE',
message: largeFilesMessage
});
// Error handling for the worker
worker.onerror = function (error) {
console.error('Worker error:', error);
};
worker.onmessage = function (e) {
const { status, differences, message } = e.data;
if (status === 'error') {
resultDiv1.innerHTML = '';
resultDiv2.innerHTML = '';
alert(message);
return;
}
if (status === 'success' && differences) {
console.log('Differences:', differences);
displayDifferences(differences);
}
if (event.data.status === 'warning') {
console.warn(event.data.message);
alert(event.data.message);
}
};
worker.postMessage({ text1, text2, color1, color2 });
const displayDifferences = (differences) => {
const resultDiv1 = document.getElementById("result1");
const resultDiv2 = document.getElementById("result2");
resultDiv1.innerHTML = "";
resultDiv2.innerHTML = "";
differences.forEach(([color, word]) => {
const span1 = document.createElement("span");
const span2 = document.createElement("span");
if (color === color2) {
span1.style.color = "transparent";
span1.style.userSelect = "none";
span2.style.color = color;
}
// If it's a deletion, show it in in the first document and transparent in the second
else if (color === color1) {
span1.style.color = color;
span2.style.color = "transparent";
span2.style.userSelect = "none";
}
// If it's unchanged, show it in black in both
else {
span1.style.color = color;
span2.style.color = color;
}
span1.textContent = word;
span2.textContent = word;
resultDiv1.appendChild(span1);
resultDiv2.appendChild(span2);
// Add space after each word, or a new line if the word ends with a full stop
const spaceOrNewline1 = document.createElement("span");
const spaceOrNewline2 = document.createElement("span");
if (word.endsWith(".")) {
spaceOrNewline1.innerHTML = "<br>";
spaceOrNewline2.innerHTML = "<br>";
} else {
spaceOrNewline1.textContent = " ";
spaceOrNewline2.textContent = " ";
}
resultDiv1.appendChild(spaceOrNewline1);
resultDiv2.appendChild(spaceOrNewline2);
});
};
}
</script>
</div>
</div>
</div>
<th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
</div>
</body>
<th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
</div>
</body>
</html>

View File

@@ -52,4 +52,4 @@
</div>
</body>
</html>
</html>

View File

@@ -16,7 +16,7 @@
<span class="material-symbols-rounded tool-header-icon other">thread_unread</span>
<span class="tool-header-text" th:text="#{removeAnnotations.header}"></span>
</div>
<form id="pdfForm" class="mb-3">
<form id="pdfForm" th:action="@{''}" class="mb-3">
<div class="custom-file">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='application/pdf', remoteCall='false')}"></div>
</div>

View File

@@ -39,6 +39,7 @@
<!-- Button to download the JSON -->
<a href="#" id="downloadJS" class="btn btn-primary mt-3" style="display: none;" th:text="#{showJS.downloadJS}">Download JSON</a>
</div>
<script th:src="@{'/js/fetch-utils.js'}"></script>
<script>
document.querySelector('#pdfInfoForm').addEventListener('submit', function(event){
event.preventDefault();
@@ -46,7 +47,7 @@
// Fetch the formData
const formData = new FormData(event.target);
fetch('api/v1/misc/show-javascript', {
fetchWithCsrf('api/v1/misc/show-javascript', {
method: 'POST',
body: formData
}).then(response => response.text())

View File

@@ -192,6 +192,7 @@
</div>
</div>
</div>
<script th:src="@{'/js/fetch-utils.js'}"></script>
<script th:src="@{'/js/pipeline.js'}"></script>\
</div>
</div>

View File

@@ -20,7 +20,7 @@
<span class="material-symbols-rounded tool-header-icon word">remove_selection</span>
<span class="tool-header-text" th:text="#{removeImage.header}"></span>
</div>
<form action="api/v1/general/remove-image-pdf" method="post" enctype="multipart/form-data">
<form th:action="@{'api/v1/general/remove-image-pdf'}" method="post" enctype="multipart/form-data">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='application/pdf')}"></div>
<br>

View File

@@ -16,7 +16,7 @@
<span class="material-symbols-rounded tool-header-icon security">lock</span>
<span class="tool-header-text" th:text="#{addPassword.header}"></span>
</div>
<form action="api/v1/security/add-password" method="post" enctype="multipart/form-data">
<form th:action="@{'api/v1/security/add-password'}" method="post" enctype="multipart/form-data">
<div class="mb-3">
<label th:text="#{addPassword.selectText.1}"></label>
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='application/pdf')}"></div>

View File

@@ -17,7 +17,7 @@
<span class="tool-header-text" th:text="#{watermark.header}"></span>
</div>
<form method="post" enctype="multipart/form-data" action="api/v1/security/add-watermark">
<form method="post" enctype="multipart/form-data" th:action="@{'api/v1/security/add-watermark'}">
<div class="mb-3">
<label th:text="#{watermark.selectText.1}"></label>
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='application/pdf')}"></div>

View File

@@ -16,7 +16,7 @@
<span class="material-symbols-rounded tool-header-icon security">ink_eraser</span>
<span class="tool-header-text" th:text="#{autoRedact.header}"></span>
</div>
<form action="api/v1/security/auto-redact" method="post" enctype="multipart/form-data">
<form th:action="@{'api/v1/security/auto-redact'}" method="post" enctype="multipart/form-data">
<div class="mb-3">
<input type="file" class="form-control" id="fileInput" name="fileInput" required accept="application/pdf">
</div>

View File

@@ -16,7 +16,7 @@
<span class="material-symbols-rounded tool-header-icon security">workspace_premium</span>
<span class="tool-header-text" th:text="#{certSign.header}"></span>
</div>
<form action="api/v1/security/cert-sign" method="post" enctype="multipart/form-data">
<form th:action="@{'api/v1/security/cert-sign'}" method="post" enctype="multipart/form-data">
<div class="mb-3">
<label th:text="#{certSign.selectPDF}"></label>
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='application/pdf')}"></div>
@@ -71,7 +71,11 @@
<label for="name" th:text="#{certSign.name}"></label> <input type="text" class="form-control" id="name" name="name">
</div>
<div class="mb-3">
<label for="pageNumber" th:text="#{pageNum}"></label> <input type="number" class="form-control" id="pageNumber" name="pageNumber" min="1" disabled>
<label for="pageNumber" th:text="#{pageNum}"></label> <input type="number" class="form-control" id="pageNumber" name="pageNumber" min="1" value="1">
</div>
<div class="form-check mb-3">
<input type="checkbox" id="showLogo" name="showLogo" checked />
<label th:text="#{certSign.showLogo}" for="showLogo"></label>
</div>
</div>
<div class="mb-3 text-left">

View File

@@ -17,7 +17,7 @@
<span class="tool-header-text" th:text="#{permissions.header}"></span>
</div>
<p th:text="#{permissions.warning}"></p>
<form action="api/v1/security/add-password" method="post" enctype="multipart/form-data">
<form th:action="@{'api/v1/security/add-password'}" method="post" enctype="multipart/form-data">
<div class="mb-3">
<label th:text="#{permissions.selectText.1}"></label>
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='application/pdf')}"></div>

View File

@@ -31,12 +31,16 @@
<a href="#" id="downloadJson" class="btn btn-primary mt-3" style="display: none;" th:text="#{getPdfInfo.downloadJson}">Download JSON</a>
</div>
<script>
import { fetchWithCsrf } from 'js/fetch-utils.js';
document.getElementById("pdfInfoForm").addEventListener("submit", function(event) {
event.preventDefault();
const formData = new FormData(event.target);
fetch('api/v1/security/get-info-on-pdf', {
fetchWithCsrf('api/v1/security/get-info-on-pdf', {
method: 'POST',
body: formData
}).then(response => response.json()).then(data => {

View File

@@ -16,7 +16,7 @@
<span class="material-symbols-rounded tool-header-icon security">remove_moderator</span>
<span class="tool-header-text" th:text="#{removeCertSign.header}"></span>
</div>
<form action="api/v1/security/remove-cert-sign" method="post" enctype="multipart/form-data">
<form th:action="@{'api/v1/security/remove-cert-sign'}" method="post" enctype="multipart/form-data">
<div class="mb-3">
<label th:text="#{removeCertSign.selectPDF}"></label>
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='application/pdf')}"></div>

View File

@@ -16,7 +16,7 @@
<span class="material-symbols-rounded tool-header-icon security">lock_open_right</span>
<span class="tool-header-text" th:text="#{removePassword.header}"></span>
</div>
<form action="api/v1/security/remove-password" method="post" enctype="multipart/form-data">
<form th:action="@{'api/v1/security/remove-password'}" method="post" enctype="multipart/form-data">
<div class="mb-3">
<label th:text="#{removePassword.selectText.1}"></label>
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='application/pdf')}"></div>

View File

@@ -16,7 +16,7 @@
<span class="material-symbols-rounded tool-header-icon security">water_drop</span>
<span class="tool-header-text" th:text="#{remove-watermark.header}"></span>
</div>
<form method="post" enctype="multipart/form-data" action="api/v1/security/remove-watermark">
<form method="post" enctype="multipart/form-data" th:action="@{'api/v1/security/remove-watermark'}">
<div class="mb-3">
<label th:text="#{remove-watermark.selectText.1}"></label>
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='application/pdf')}"></div>

View File

@@ -16,7 +16,7 @@
<span class="material-symbols-rounded tool-header-icon security">sanitizer</span>
<span class="tool-header-text" th:text="#{sanitizePDF.header}"></span>
</div>
<form action="api/v1/security/sanitize-pdf" method="post" enctype="multipart/form-data">
<form th:action="@{'api/v1/security/sanitize-pdf'}" method="post" enctype="multipart/form-data">
<div class="mb-3">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='application/pdf')}"></div>
</div>

View File

@@ -43,6 +43,53 @@
</div>
<script type="module" th:src="@{'/pdfjs-legacy/pdf.mjs'}"></script>
<script>
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;
// Extract filename from the data source path
const filename = element.querySelector('.signature-list-name').textContent;
// Update preview modal
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 file = event.target.files[0];
@@ -68,7 +115,7 @@
<div class="tab-group show-on-file-selected">
<div class="tab-container" th:title="#{sign.upload}">
<div
th:replace="~{fragments/common :: fileSelector(name='image-upload', multipleInputsForSingleRequest=true, accept='image/*', inputText=#{imgPrompt})}">
th:replace="~{fragments/common :: fileSelector(name='image-upload', disableMultipleFiles=true, multipleInputsForSingleRequest=true, accept='image/*', inputText=#{imgPrompt})}">
</div>
<script>
const imageUpload = document.querySelector('input[name=image-upload]');
@@ -165,6 +212,126 @@
</script>
</div>
<div class="tab-container" th:title="#{sign.saved}">
<div class="saved-signatures-section" th:if="${not #lists.isEmpty(signatures)}">
<!-- View Toggle Button -->
<div class="view-toggle mb-3">
<button class="btn btn-outline-secondary btn-sm" onclick="toggleSignatureView()">
<span class="material-symbols-rounded grid-view-text">view_list</span>
<span class="material-symbols-rounded list-view-text" style="display: none;">grid_view</span>
</button>
</div>
<!-- Preview Modal -->
<div class="modal fade" id="signaturePreview" tabindex="-1">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title"><span id="previewFileName"></span></h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body text-center">
<img id="previewImage" src="" alt="Signature Preview" style="max-width: 100%;">
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal" th:text="#{close}"></button>
<button type="button" class="btn btn-primary" onclick="addSignatureFromPreview()" th:text="#{addToDoc}">Add to Document</button>
</div>
</div>
</div>
</div>
<!-- Grid View -->
<div id="gridView">
<!-- Personal Signatures -->
<div class="signature-category" th:if="${not #lists.isEmpty(signatures.?[category == 'Personal'])}">
<h5 th:text="#{sign.personalSigs}"></h5>
<div class="signature-grid">
<div th:each="sig : ${signatures}" th:if="${sig.category == 'Personal'}" class="signature-item">
<img th:src="@{'/api/v1/general/sign/' + ${sig.fileName}}"
th:alt="${sig.fileName}"
th:data-filename="${sig.fileName}"
style="max-width: 200px; cursor: pointer;"
onclick="DraggableUtils.createDraggableCanvasFromUrl(this.src)"/>
<div class="signature-name" th:text="${sig.fileName}"></div>
</div>
</div>
</div>
<!-- Shared Signatures -->
<div class="signature-category" th:if="${not #lists.isEmpty(signatures.?[category == 'Shared'])}">
<h5 th:text="#{sign.sharedSigs}"></h5>
<div class="signature-grid">
<div th:each="sig : ${signatures}" th:if="${sig.category == 'Shared'}" class="signature-item">
<img th:src="@{'/api/v1/general/sign/' + ${sig.fileName}}"
th:alt="${sig.fileName}"
th:data-filename="${sig.fileName}"
style="max-width: 200px; cursor: pointer;"
onclick="DraggableUtils.createDraggableCanvasFromUrl(this.src)"/>
<div class="signature-name" th:text="${sig.fileName}"></div>
</div>
</div>
</div>
</div>
<!-- List View (Initially Hidden) -->
<div id="listView" style="display: none;">
<!-- Personal Signatures -->
<div class="signature-category" th:if="${not #lists.isEmpty(signatures.?[category == 'Personal'])}">
<h5 th:text="#{sign.personalSigs}"></h5>
<div class="signature-list">
<div th:each="sig : ${signatures}" th:if="${sig.category == 'Personal'}"
class="signature-list-item"
th:data-src="@{'/api/v1/general/sign/' + ${sig.fileName}}"
onclick="previewSignature(this)">
<div class="signature-list-info">
<span th:text="${sig.fileName}" class="signature-list-name"></span>
</div>
</div>
</div>
</div>
<!-- Shared Signatures -->
<div class="signature-category" th:if="${not #lists.isEmpty(signatures.?[category == 'Shared'])}">
<h5 th:text="#{sign.sharedSigs}"></h5>
<div class="signature-list">
<div th:each="sig : ${signatures}" th:if="${sig.category == 'Shared'}"
class="signature-list-item"
th:data-src="@{'/api/v1/general/sign/' + ${sig.fileName}}"
onclick="previewSignature(this)">
<div class="signature-list-info">
<span th:text="${sig.fileName}" class="signature-list-name"></span>
</div>
</div>
</div>
</div>
</div>
</div>
<div th:if="${#lists.isEmpty(signatures)}" class="text-center p-3">
<p th:text="#{sign.noSavedSigs}">No saved signatures found</p>
</div>
</div>
<div class="tab-container" th:title="#{sign.text}">
<label class="form-check-label" for="sigText" th:text="#{text}"></label>
<textarea class="form-control" id="sigText" name="sigText" rows="3"></textarea>