Compare commits
118 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f1c5384a37 | ||
|
|
5607f7079e | ||
|
|
3b8723975d | ||
|
|
41a3d28c90 | ||
|
|
f7afe73cb4 | ||
|
|
73e5246191 | ||
|
|
1f39481efe | ||
|
|
5ac2260d78 | ||
|
|
bae83a281c | ||
|
|
dd2aae60ad | ||
|
|
30ee33002d | ||
|
|
24717dde19 | ||
|
|
509a305985 | ||
|
|
13572a7f18 | ||
|
|
ebd0ddc6ad | ||
|
|
43c4ec1089 | ||
|
|
1ccdc1697b | ||
|
|
2297c5dc95 | ||
|
|
859c9942e6 | ||
|
|
c723696bd0 | ||
|
|
fe198458ca | ||
|
|
378aca4460 | ||
|
|
9870e6ad7c | ||
|
|
40b5904726 | ||
|
|
de3f59cf44 | ||
|
|
4ae7c83357 | ||
|
|
f127271709 | ||
|
|
f899088c75 | ||
|
|
d55e007f93 | ||
|
|
ccdcb05e65 | ||
|
|
e6c2ad8c9c | ||
|
|
32aa623c8b | ||
|
|
23888c5d2c | ||
|
|
2f23eb69c6 | ||
|
|
446cedf26e | ||
|
|
f950e25dad | ||
|
|
65a86a6e97 | ||
|
|
7f4134f52d | ||
|
|
55969697b8 | ||
|
|
86662d9cf6 | ||
|
|
2437460c73 | ||
|
|
a7960d992c | ||
|
|
c98cd8117f | ||
|
|
50c5efac87 | ||
|
|
0952245b23 | ||
|
|
83ddfdf152 | ||
|
|
08777c78b1 | ||
|
|
c6980e9693 | ||
|
|
fc514ee65b | ||
|
|
44be2b99d2 | ||
|
|
549824c91f | ||
|
|
1c0d1efda6 | ||
|
|
9d8d90bf2f | ||
|
|
a7e7d57b23 | ||
|
|
e014bb023b | ||
|
|
1c5dfc46a0 | ||
|
|
11273b1589 | ||
|
|
dd5af46906 | ||
|
|
c20d37518d | ||
|
|
eb20f51958 | ||
|
|
97d28ac6d2 | ||
|
|
026fe8150d | ||
|
|
c3f88f716c | ||
|
|
67f983f00d | ||
|
|
9167f12296 | ||
|
|
93e190fdeb | ||
|
|
82bebf5c62 | ||
|
|
bb3f076e6d | ||
|
|
64dfa4b841 | ||
|
|
0f6f3f305a | ||
|
|
58c7d7b9a8 | ||
|
|
ef8231de3a | ||
|
|
c1c3eba398 | ||
|
|
52693541d9 | ||
|
|
1639e0fc4c | ||
|
|
0652299bec | ||
|
|
1d6511b043 | ||
|
|
a400fe6015 | ||
|
|
b47df3d252 | ||
|
|
cb6e1cd94e | ||
|
|
6ee6254f5a | ||
|
|
f2c9549ba1 | ||
|
|
58278c07ff | ||
|
|
4d017610b8 | ||
|
|
dcafc0d487 | ||
|
|
2ec8c97737 | ||
|
|
397a07afe8 | ||
|
|
b072c39fd9 | ||
|
|
1bc6b4149c | ||
|
|
5a5a8bb7ba | ||
|
|
b6eca59f23 | ||
|
|
7108424a92 | ||
|
|
400965ffc8 | ||
|
|
1895a04394 | ||
|
|
f8f137a30a | ||
|
|
f6a2d4784b | ||
|
|
526dc9f911 | ||
|
|
cce9f74eb9 | ||
|
|
0e3865618d | ||
|
|
d888ed1ae0 | ||
|
|
99d1b46d97 | ||
|
|
32e46eeb73 | ||
|
|
b7da84d257 | ||
|
|
1c1ead5d62 | ||
|
|
6ff53aa5b3 | ||
|
|
8d60b08cd9 | ||
|
|
64cf5167c0 | ||
|
|
de4637e8d4 | ||
|
|
3c0a8071dc | ||
|
|
04ccdf6f76 | ||
|
|
db02fba31f | ||
|
|
5b6f649e4e | ||
|
|
de23bb702c | ||
|
|
25e564154e | ||
|
|
3633a979d3 | ||
|
|
f4082e3f96 | ||
|
|
c93a48b40d | ||
|
|
75e10efcbd |
2
.github/ISSUE_TEMPLATE/config.yml
vendored
2
.github/ISSUE_TEMPLATE/config.yml
vendored
@@ -1,5 +1,5 @@
|
|||||||
blank_issues_enabled: true
|
blank_issues_enabled: true
|
||||||
contact_links:
|
contact_links:
|
||||||
- name: 💬 Discord Server
|
- name: 💬 Discord Server
|
||||||
url: https://discord.gg/Cn8pWhQRxZ
|
url: https://discord.gg/HYmhKj45pU
|
||||||
about: You can join our Discord server for real time discussion and support
|
about: You can join our Discord server for real time discussion and support
|
||||||
|
|||||||
91
.github/workflows/multiOSReleases.yml
vendored
Normal file
91
.github/workflows/multiOSReleases.yml
vendored
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
name: Test Installers Build
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
release:
|
||||||
|
types: [created]
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
packages: write
|
||||||
|
jobs:
|
||||||
|
build-installers:
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- os: windows-latest
|
||||||
|
platform: win
|
||||||
|
ext: exe
|
||||||
|
#- os: macos-latest
|
||||||
|
# platform: mac
|
||||||
|
# ext: dmg
|
||||||
|
#- os: ubuntu-latest
|
||||||
|
# platform: linux
|
||||||
|
# ext: deb
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set up JDK 21
|
||||||
|
uses: actions/setup-java@v4
|
||||||
|
with:
|
||||||
|
java-version: "21"
|
||||||
|
distribution: "temurin"
|
||||||
|
|
||||||
|
- uses: gradle/actions/setup-gradle@v4
|
||||||
|
with:
|
||||||
|
gradle-version: 8.7
|
||||||
|
|
||||||
|
# Install Windows dependencies
|
||||||
|
- name: Install WiX Toolset
|
||||||
|
if: matrix.os == 'windows-latest'
|
||||||
|
run: |
|
||||||
|
curl -L -o wix.exe https://github.com/wixtoolset/wix3/releases/download/wix3141rtm/wix314.exe
|
||||||
|
.\wix.exe /install /quiet
|
||||||
|
|
||||||
|
# Install Linux dependencies
|
||||||
|
- name: Install Linux Dependencies
|
||||||
|
if: matrix.os == 'ubuntu-latest'
|
||||||
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y fakeroot rpm
|
||||||
|
|
||||||
|
# Get version number
|
||||||
|
- name: Get version number
|
||||||
|
id: versionNumber
|
||||||
|
run: echo "versionNumber=$(./gradlew printVersion --quiet | tail -1)" >> $GITHUB_OUTPUT
|
||||||
|
shell: bash
|
||||||
|
|
||||||
|
- name: Get version number mac
|
||||||
|
id: versionNumberMac
|
||||||
|
run: echo "versionNumberMac=$(./gradlew printMacVersion --quiet | tail -1)" >> $GITHUB_OUTPUT
|
||||||
|
shell: bash
|
||||||
|
|
||||||
|
# Build installer
|
||||||
|
- name: Build Installer
|
||||||
|
run: ./gradlew build jpackage -x test --info
|
||||||
|
env:
|
||||||
|
DOCKER_ENABLE_SECURITY: false
|
||||||
|
STIRLING_PDF_DESKTOP_UI: true
|
||||||
|
|
||||||
|
# Rename and collect artifacts based on OS
|
||||||
|
- name: Prepare artifacts
|
||||||
|
id: prepare
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
if [ "${{ matrix.os }}" = "windows-latest" ]; then
|
||||||
|
mv "build/jpackage/Stirling-PDF-${{ steps.versionNumber.outputs.versionNumber }}.exe" "Stirling-PDF-${{ steps.versionNumber.outputs.versionNumber }}-${{ matrix.platform }}.${{ matrix.ext }}"
|
||||||
|
elif [ "${{ matrix.os }}" = "macos-latest" ]; then
|
||||||
|
mv "build/jpackage/Stirling-PDF-${{ steps.versionNumberMac.outputs.versionNumberMac }}.dmg" "Stirling-PDF-${{ steps.versionNumber.outputs.versionNumber }}-${{ matrix.platform }}.${{ matrix.ext }}"
|
||||||
|
else
|
||||||
|
mv "build/jpackage/stirling-pdf_${{ steps.versionNumber.outputs.versionNumber }}-1_amd64.deb" "Stirling-PDF-${{ steps.versionNumber.outputs.versionNumber }}-${{ matrix.platform }}.${{ matrix.ext }}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Upload installer as artifact for testing
|
||||||
|
- name: Upload Installer Artifact
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: Stirling-PDF-${{ matrix.platform }}-installer.{{ matrix.ext }}
|
||||||
|
path: Stirling-PDF-${{ steps.versionNumber.outputs.versionNumber }}-${{ matrix.platform }}.${{ matrix.ext }}
|
||||||
|
retention-days: 1
|
||||||
|
if-no-files-found: error
|
||||||
59
.github/workflows/releaseArtifacts.yml
vendored
59
.github/workflows/releaseArtifacts.yml
vendored
@@ -35,36 +35,37 @@ jobs:
|
|||||||
run: ./gradlew clean createExe
|
run: ./gradlew clean createExe
|
||||||
env:
|
env:
|
||||||
DOCKER_ENABLE_SECURITY: ${{ matrix.enable_security }}
|
DOCKER_ENABLE_SECURITY: ${{ matrix.enable_security }}
|
||||||
|
STIRLING_PDF_DESKTOP_UI: false
|
||||||
|
|
||||||
- name: Get version number
|
- name: Get version number
|
||||||
id: versionNumber
|
id: versionNumber
|
||||||
run: echo "versionNumber=$(./gradlew printVersion --quiet | tail -1)" >> $GITHUB_OUTPUT
|
run: echo "versionNumber=$(./gradlew printVersion --quiet | tail -1)" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Rename binarie
|
- name: Rename binarie
|
||||||
if: matrix.file_suffix != ''
|
run: cp ./build/launch4j/Stirling-PDF.exe ./build/launch4j/Stirling-PDF-Server${{ matrix.file_suffix }}.exe
|
||||||
run: cp ./build/launch4j/Stirling-PDF.exe ./build/launch4j/Stirling-PDF${{ matrix.file_suffix }}.exe
|
|
||||||
|
|
||||||
- name: Upload Assets binarie
|
- name: Upload Assets binarie
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
path: ./build/launch4j/Stirling-PDF${{ matrix.file_suffix }}.exe
|
path: ./build/launch4j/Stirling-PDF-Server${{ matrix.file_suffix }}.exe
|
||||||
name: Stirling-PDF${{ matrix.file_suffix }}.exe
|
name: Stirling-PDF-Server${{ matrix.file_suffix }}.exe
|
||||||
overwrite: true
|
overwrite: true
|
||||||
retention-days: 1
|
retention-days: 1
|
||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
|
|
||||||
- name: Upload binaries to release
|
- name: Upload binaries to release
|
||||||
uses: softprops/action-gh-release@v2
|
uses: softprops/action-gh-release@v2
|
||||||
with:
|
with:
|
||||||
files: ./build/launch4j/Stirling-PDF${{ matrix.file_suffix }}.exe
|
files: ./build/launch4j/Stirling-PDF-Server${{ matrix.file_suffix }}.exe
|
||||||
|
|
||||||
- name: Rename jar binaries
|
- name: Rename jar binaries
|
||||||
run: cp ./build/libs/Stirling-PDF-${{ steps.versionNumber.outputs.versionNumber }}.jar ./build/libs/Stirling-PDF${{ matrix.file_suffix }}.jar
|
run: cp ./build/libs/Stirling-PDF-${{ steps.versionNumber.outputs.versionNumber }}.jar ./build/libs/Stirling-PDF-Server${{ matrix.file_suffix }}.jar
|
||||||
|
|
||||||
- name: Upload Assets jar binaries
|
- name: Upload Assets jar binaries
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
path: ./build/libs/Stirling-PDF${{ matrix.file_suffix }}.jar
|
path: ./build/libs/Stirling-PDF-Server${{ matrix.file_suffix }}.jar
|
||||||
name: Stirling-PDF${{ matrix.file_suffix }}.jar
|
name: Stirling-PDF-Server${{ matrix.file_suffix }}.jar
|
||||||
overwrite: true
|
overwrite: true
|
||||||
retention-days: 1
|
retention-days: 1
|
||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
@@ -72,4 +73,44 @@ jobs:
|
|||||||
- name: Upload jar binaries to release
|
- name: Upload jar binaries to release
|
||||||
uses: softprops/action-gh-release@v2
|
uses: softprops/action-gh-release@v2
|
||||||
with:
|
with:
|
||||||
files: ./build/libs/Stirling-PDF${{ matrix.file_suffix }}.jar
|
files: ./build/libs/Stirling-PDF-Server${{ matrix.file_suffix }}.jar
|
||||||
|
|
||||||
|
|
||||||
|
push-ui:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set up JDK 17
|
||||||
|
uses: actions/setup-java@v4
|
||||||
|
with:
|
||||||
|
java-version: "17"
|
||||||
|
distribution: "temurin"
|
||||||
|
|
||||||
|
- uses: gradle/actions/setup-gradle@v4
|
||||||
|
with:
|
||||||
|
gradle-version: 8.7
|
||||||
|
|
||||||
|
- name: Generate exe
|
||||||
|
run: ./gradlew clean createExe
|
||||||
|
env:
|
||||||
|
DOCKER_ENABLE_SECURITY: false
|
||||||
|
STIRLING_PDF_DESKTOP_UI: true
|
||||||
|
|
||||||
|
- name: Get version number
|
||||||
|
id: versionNumber
|
||||||
|
run: echo "versionNumber=$(./gradlew printVersion --quiet | tail -1)" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: Upload Assets binarie
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
path: ./build/launch4j/Stirling-PDF.exe
|
||||||
|
name: Stirling-PDF.exe
|
||||||
|
overwrite: true
|
||||||
|
retention-days: 1
|
||||||
|
if-no-files-found: error
|
||||||
|
|
||||||
|
- name: Upload binaries to release
|
||||||
|
uses: softprops/action-gh-release@v2
|
||||||
|
with:
|
||||||
|
files: ./build/launch4j/Stirling-PDF.exe
|
||||||
|
|||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -161,3 +161,4 @@ out/
|
|||||||
.pytest_cache
|
.pytest_cache
|
||||||
.ipynb_checkpoints
|
.ipynb_checkpoints
|
||||||
|
|
||||||
|
**/jcef-bundle/
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
# use alpine
|
# use alpine
|
||||||
FROM alpine:3.20.3
|
FROM alpine:3.21.0
|
||||||
|
|
||||||
ARG VERSION_TAG
|
ARG VERSION_TAG
|
||||||
|
|
||||||
|
|||||||
75
README.md
75
README.md
@@ -2,7 +2,7 @@
|
|||||||
<h1 align="center">Stirling-PDF</h1>
|
<h1 align="center">Stirling-PDF</h1>
|
||||||
|
|
||||||
[](https://hub.docker.com/r/frooodle/s-pdf)
|
[](https://hub.docker.com/r/frooodle/s-pdf)
|
||||||
[](https://discord.gg/Cn8pWhQRxZ)
|
[](https://discord.gg/HYmhKj45pU)
|
||||||
[](https://github.com/Stirling-Tools/Stirling-PDF/)
|
[](https://github.com/Stirling-Tools/Stirling-PDF/)
|
||||||
[](https://github.com/Stirling-Tools/stirling-pdf)
|
[](https://github.com/Stirling-Tools/stirling-pdf)
|
||||||
|
|
||||||
@@ -187,47 +187,48 @@ Certain functionality like `Sign` supports pre-saved files stored at `/customFil
|
|||||||
|
|
||||||
## Supported Languages
|
## Supported Languages
|
||||||
|
|
||||||
Stirling-PDF currently supports 37 languages!
|
Stirling-PDF currently supports 38 languages!
|
||||||
|
|
||||||
| Language | Progress |
|
| Language | Progress |
|
||||||
| -------------------------------------------- | -------------------------------------- |
|
| -------------------------------------------- | -------------------------------------- |
|
||||||
| Arabic (العربية) (ar_AR) |  |
|
| Arabic (العربية) (ar_AR) |  |
|
||||||
| Azerbaijani (Azərbaycan Dili) (az_AZ) |  |
|
| Azerbaijani (Azərbaycan Dili) (az_AZ) |  |
|
||||||
| Basque (Euskara) (eu_ES) |  |
|
| Basque (Euskara) (eu_ES) |  |
|
||||||
| Bulgarian (Български) (bg_BG) |  |
|
| Bulgarian (Български) (bg_BG) |  |
|
||||||
| Catalan (Català) (ca_CA) |  |
|
| Catalan (Català) (ca_CA) |  |
|
||||||
| Croatian (Hrvatski) (hr_HR) |  |
|
| Croatian (Hrvatski) (hr_HR) |  |
|
||||||
| Czech (Česky) (cs_CZ) |  |
|
| Czech (Česky) (cs_CZ) |  |
|
||||||
| Danish (Dansk) (da_DK) |  |
|
| Danish (Dansk) (da_DK) |  |
|
||||||
| Dutch (Nederlands) (nl_NL) |  |
|
| Dutch (Nederlands) (nl_NL) |  |
|
||||||
| English (English) (en_GB) |  |
|
| English (English) (en_GB) |  |
|
||||||
| English (US) (en_US) |  |
|
| English (US) (en_US) |  |
|
||||||
| French (Français) (fr_FR) |  |
|
| French (Français) (fr_FR) |  |
|
||||||
| German (Deutsch) (de_DE) |  |
|
| German (Deutsch) (de_DE) |  |
|
||||||
| Greek (Ελληνικά) (el_GR) |  |
|
| Greek (Ελληνικά) (el_GR) |  |
|
||||||
| Hindi (हिंदी) (hi_IN) |  |
|
| Hindi (हिंदी) (hi_IN) |  |
|
||||||
| Hungarian (Magyar) (hu_HU) |  |
|
| Hungarian (Magyar) (hu_HU) |  |
|
||||||
| Indonesian (Bahasa Indonesia) (id_ID) |  |
|
| Indonesian (Bahasa Indonesia) (id_ID) |  |
|
||||||
| Irish (Gaeilge) (ga_IE) |  |
|
| Irish (Gaeilge) (ga_IE) |  |
|
||||||
| Italian (Italiano) (it_IT) |  |
|
| Italian (Italiano) (it_IT) |  |
|
||||||
| Japanese (日本語) (ja_JP) |  |
|
| Japanese (日本語) (ja_JP) |  |
|
||||||
| Korean (한국어) (ko_KR) |  |
|
| Korean (한국어) (ko_KR) |  |
|
||||||
| Norwegian (Norsk) (no_NB) |  |
|
| Norwegian (Norsk) (no_NB) |  |
|
||||||
| Polish (Polski) (pl_PL) |  |
|
| Persian (فارسی) (fa_IR) |  |
|
||||||
| Portuguese (Português) (pt_PT) |  |
|
| Polish (Polski) (pl_PL) |  |
|
||||||
| Portuguese Brazilian (Português) (pt_BR) |  |
|
| Portuguese (Português) (pt_PT) |  |
|
||||||
| Romanian (Română) (ro_RO) |  |
|
| Portuguese Brazilian (Português) (pt_BR) |  |
|
||||||
| Russian (Русский) (ru_RU) |  |
|
| Romanian (Română) (ro_RO) |  |
|
||||||
| Serbian Latin alphabet (Srpski) (sr_LATN_RS) |  |
|
| Russian (Русский) (ru_RU) |  |
|
||||||
| Simplified Chinese (简体中文) (zh_CN) |  |
|
| Serbian Latin alphabet (Srpski) (sr_LATN_RS) |  |
|
||||||
| Slovakian (Slovensky) (sk_SK) |  |
|
| Simplified Chinese (简体中文) (zh_CN) |  |
|
||||||
| Spanish (Español) (es_ES) |  |
|
| Slovakian (Slovensky) (sk_SK) |  |
|
||||||
| Swedish (Svenska) (sv_SE) |  |
|
| Spanish (Español) (es_ES) |  |
|
||||||
| Thai (ไทย) (th_TH) |  |
|
| Swedish (Svenska) (sv_SE) |  |
|
||||||
| Traditional Chinese (繁體中文) (zh_TW) |  |
|
| Thai (ไทย) (th_TH) |  |
|
||||||
| Turkish (Türkçe) (tr_TR) |  |
|
| Traditional Chinese (繁體中文) (zh_TW) |  |
|
||||||
| Ukrainian (Українська) (uk_UA) |  |
|
| Turkish (Türkçe) (tr_TR) |  |
|
||||||
| Vietnamese (Tiếng Việt) (vi_VN) |  |
|
| Ukrainian (Українська) (uk_UA) |  |
|
||||||
|
| Vietnamese (Tiếng Việt) (vi_VN) |  |
|
||||||
|
|
||||||
## Contributing (Creating Issues, Translations, Fixing Bugs, etc.)
|
## Contributing (Creating Issues, Translations, Fixing Bugs, etc.)
|
||||||
|
|
||||||
@@ -404,7 +405,7 @@ To access your account settings, go to Account Settings in the settings cog menu
|
|||||||
|
|
||||||
To add new users, go to the bottom of Account Settings and hit 'Admin Settings'. Here you can add new users. The different roles mentioned within this are for rate limiting. This is a work in progress and will be expanded on more in the future.
|
To add new users, go to the bottom of Account Settings and hit 'Admin Settings'. Here you can add new users. The different roles mentioned within this are for rate limiting. This is a work in progress and will be expanded on more in the future.
|
||||||
|
|
||||||
For API usage, you must provide a header with `X-API-Key` and the associated API key for that user.
|
For API usage, you must provide a header with `X-API-KEY` and the associated API key for that user.
|
||||||
|
|
||||||
## FAQ
|
## FAQ
|
||||||
|
|
||||||
|
|||||||
184
build.gradle
184
build.gradle
@@ -8,6 +8,7 @@ plugins {
|
|||||||
id "com.diffplug.spotless" version "6.25.0"
|
id "com.diffplug.spotless" version "6.25.0"
|
||||||
id "com.github.jk1.dependency-license-report" version "2.9"
|
id "com.github.jk1.dependency-license-report" version "2.9"
|
||||||
//id "nebula.lint" version "19.0.3"
|
//id "nebula.lint" version "19.0.3"
|
||||||
|
id("org.panteleyev.jpackageplugin") version "1.6.0"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -21,10 +22,12 @@ ext {
|
|||||||
imageioVersion = "3.12.0"
|
imageioVersion = "3.12.0"
|
||||||
lombokVersion = "1.18.36"
|
lombokVersion = "1.18.36"
|
||||||
bouncycastleVersion = "1.79"
|
bouncycastleVersion = "1.79"
|
||||||
|
springSecuritySamlVersion = "6.4.1"
|
||||||
|
openSamlVersion = "4.3.2"
|
||||||
}
|
}
|
||||||
|
|
||||||
group = "stirling.software"
|
group = "stirling.software"
|
||||||
version = "0.35.0"
|
version = "0.36.1"
|
||||||
|
|
||||||
|
|
||||||
java {
|
java {
|
||||||
@@ -39,6 +42,9 @@ repositories {
|
|||||||
maven {
|
maven {
|
||||||
url 'https://build.shibboleth.net/maven/releases'
|
url 'https://build.shibboleth.net/maven/releases'
|
||||||
}
|
}
|
||||||
|
maven { url "https://build.shibboleth.net/maven/releases" }
|
||||||
|
maven { url "https://maven.pkg.github.com/jcefmaven/jcefmaven" }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
licenseReport {
|
licenseReport {
|
||||||
@@ -62,6 +68,12 @@ sourceSets {
|
|||||||
exclude "stirling/software/SPDF/model/User.java"
|
exclude "stirling/software/SPDF/model/User.java"
|
||||||
exclude "stirling/software/SPDF/repository/**"
|
exclude "stirling/software/SPDF/repository/**"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (System.getenv("STIRLING_PDF_DESKTOP_UI") == "false") {
|
||||||
|
exclude "stirling/software/SPDF/UI/impl/**"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -72,16 +84,153 @@ openApi {
|
|||||||
outputFileName = "SwaggerDoc.json"
|
outputFileName = "SwaggerDoc.json"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//0.11.5 to 2024.11.5
|
||||||
|
def getMacVersion(String version) {
|
||||||
|
def currentYear = java.time.Year.now().getValue()
|
||||||
|
def versionParts = version.split("\\.", 2)
|
||||||
|
return "${currentYear}.${versionParts.length > 1 ? versionParts[1] : versionParts[0]}"
|
||||||
|
}
|
||||||
|
|
||||||
|
jpackage {
|
||||||
|
input = "build/libs"
|
||||||
|
|
||||||
|
appName = "Stirling-PDF"
|
||||||
|
appVersion = project.version
|
||||||
|
vendor = "Stirling-Software"
|
||||||
|
appDescription = "Stirling PDF - Your Local PDF Editor"
|
||||||
|
|
||||||
|
mainJar = "Stirling-PDF-${project.version}.jar"
|
||||||
|
mainClass = "org.springframework.boot.loader.launch.JarLauncher"
|
||||||
|
|
||||||
|
icon = "src/main/resources/static/favicon.ico"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// JVM Options
|
||||||
|
javaOptions = [
|
||||||
|
"-DBROWSER_OPEN=true",
|
||||||
|
"-DSTIRLING_PDF_DESKTOP_UI=true",
|
||||||
|
"-Djava.awt.headless=false",
|
||||||
|
"-Dapple.awt.UIElement=true",
|
||||||
|
"--add-opens", "java.base/java.lang=ALL-UNNAMED",
|
||||||
|
"--add-opens", "java.desktop/java.awt.event=ALL-UNNAMED",
|
||||||
|
"--add-opens", "java.desktop/sun.awt=ALL-UNNAMED"
|
||||||
|
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
verbose = true
|
||||||
|
|
||||||
|
destination = "${projectDir}/build/jpackage"
|
||||||
|
|
||||||
|
// Windows-specific configuration
|
||||||
|
windows {
|
||||||
|
launcherAsService = false
|
||||||
|
appVersion = project.version
|
||||||
|
winConsole = false
|
||||||
|
winDirChooser = true
|
||||||
|
winMenu = true
|
||||||
|
winShortcut = true
|
||||||
|
winPerUserInstall = true
|
||||||
|
winMenuGroup = "Stirling Software"
|
||||||
|
winUpgradeUuid = "2a43ed0c-b8c2-40cf-89e1-751129b87641" // Unique identifier for updates
|
||||||
|
winHelpUrl = "https://github.com/Stirling-Tools/Stirling-PDF"
|
||||||
|
winUpdateUrl = "https://github.com/Stirling-Tools/Stirling-PDF/releases"
|
||||||
|
type = "exe"
|
||||||
|
installDir = "C:/Program Files/Stirling-PDF"
|
||||||
|
}
|
||||||
|
|
||||||
|
// macOS-specific configuration
|
||||||
|
mac {
|
||||||
|
appVersion = getMacVersion(project.version.toString())
|
||||||
|
icon = "src/main/resources/static/favicon.icns"
|
||||||
|
type = "dmg"
|
||||||
|
macPackageIdentifier = "com.stirling.software.pdf"
|
||||||
|
macPackageName = "Stirling-PDF"
|
||||||
|
macAppCategory = "public.app-category.productivity"
|
||||||
|
macSign = false // Enable signing
|
||||||
|
macAppStore = false // Not targeting App Store initially
|
||||||
|
|
||||||
|
//installDir = "Applications"
|
||||||
|
|
||||||
|
// Add license and other documentation to DMG
|
||||||
|
/*macDmgContent = [
|
||||||
|
"README.md",
|
||||||
|
"LICENSE",
|
||||||
|
"CHANGELOG.md"
|
||||||
|
]*/
|
||||||
|
|
||||||
|
// Enable Mac-specific entitlements
|
||||||
|
//macEntitlements = "entitlements.plist" // You'll need to create this file
|
||||||
|
}
|
||||||
|
|
||||||
|
// Linux-specific configuration
|
||||||
|
linux {
|
||||||
|
appVersion = project.version
|
||||||
|
icon = "src/main/resources/static/favicon.png"
|
||||||
|
type = "deb" // Can also use "rpm" for Red Hat-based systems
|
||||||
|
|
||||||
|
// Debian package configuration
|
||||||
|
//linuxPackageName = "stirlingpdf"
|
||||||
|
linuxDebMaintainer = "support@stirlingpdf.com"
|
||||||
|
linuxMenuGroup = "Office;PDF;Productivity"
|
||||||
|
linuxAppCategory = "Office"
|
||||||
|
linuxAppRelease = "1"
|
||||||
|
linuxPackageDeps = true
|
||||||
|
|
||||||
|
installDir = "/opt/Stirling-PDF"
|
||||||
|
|
||||||
|
// RPM-specific settings
|
||||||
|
//linuxRpmLicenseType = "MIT"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Common additional options
|
||||||
|
//jLinkOptions = [
|
||||||
|
// "--strip-debug",
|
||||||
|
// "--compress=2",
|
||||||
|
// "--no-header-files",
|
||||||
|
// "--no-man-pages"
|
||||||
|
//]
|
||||||
|
|
||||||
|
// Add any additional modules required
|
||||||
|
/*addModules = [
|
||||||
|
"java.base",
|
||||||
|
"java.desktop",
|
||||||
|
"java.logging",
|
||||||
|
"java.sql",
|
||||||
|
"java.xml",
|
||||||
|
"jdk.crypto.ec"
|
||||||
|
]*/
|
||||||
|
|
||||||
|
// Add copyright and license information
|
||||||
|
copyright = "Copyright © 2024 Stirling Software"
|
||||||
|
licenseFile = "LICENSE"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
launch4j {
|
launch4j {
|
||||||
icon = "${projectDir}/src/main/resources/static/favicon.ico"
|
icon = "${projectDir}/src/main/resources/static/favicon.ico"
|
||||||
|
|
||||||
outfile="Stirling-PDF.exe"
|
outfile="Stirling-PDF.exe"
|
||||||
headerType="console"
|
|
||||||
|
if(System.getenv("STIRLING_PDF_DESKTOP_UI") == 'true') {
|
||||||
|
headerType = "gui"
|
||||||
|
} else {
|
||||||
|
headerType = "console"
|
||||||
|
}
|
||||||
jarTask = tasks.bootJar
|
jarTask = tasks.bootJar
|
||||||
|
|
||||||
errTitle="Encountered error, Do you have Java 21?"
|
errTitle="Encountered error, Do you have Java 21?"
|
||||||
downloadUrl="https://download.oracle.com/java/21/latest/jdk-21_windows-x64_bin.exe"
|
downloadUrl="https://download.oracle.com/java/21/latest/jdk-21_windows-x64_bin.exe"
|
||||||
|
|
||||||
|
if(System.getenv("STIRLING_PDF_DESKTOP_UI") == 'true') {
|
||||||
|
variables=["BROWSER_OPEN=true", "STIRLING_PDF_DESKTOP_UI=true"]
|
||||||
|
} else {
|
||||||
variables=["BROWSER_OPEN=true"]
|
variables=["BROWSER_OPEN=true"]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
jreMinVersion="17"
|
jreMinVersion="17"
|
||||||
|
|
||||||
mutexName="Stirling-PDF"
|
mutexName="Stirling-PDF"
|
||||||
@@ -121,6 +270,13 @@ configurations.all {
|
|||||||
exclude group: "org.springframework.boot", module: "spring-boot-starter-tomcat"
|
exclude group: "org.springframework.boot", module: "spring-boot-starter-tomcat"
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
|
|
||||||
|
if (System.getenv("STIRLING_PDF_DESKTOP_UI") != "false") {
|
||||||
|
implementation "me.friwi:jcefmaven:127.3.1"
|
||||||
|
implementation "org.openjfx:javafx-controls:21"
|
||||||
|
implementation "org.openjfx:javafx-swing:21"
|
||||||
|
}
|
||||||
|
|
||||||
//security updates
|
//security updates
|
||||||
implementation "org.springframework:spring-webmvc:6.2.0"
|
implementation "org.springframework:spring-webmvc:6.2.0"
|
||||||
|
|
||||||
@@ -140,21 +296,22 @@ dependencies {
|
|||||||
|
|
||||||
if (System.getenv("DOCKER_ENABLE_SECURITY") != "false") {
|
if (System.getenv("DOCKER_ENABLE_SECURITY") != "false") {
|
||||||
implementation "org.springframework.boot:spring-boot-starter-security:$springBootVersion"
|
implementation "org.springframework.boot:spring-boot-starter-security:$springBootVersion"
|
||||||
implementation "org.thymeleaf.extras:thymeleaf-extras-springsecurity5:3.1.2.RELEASE"
|
implementation "org.thymeleaf.extras:thymeleaf-extras-springsecurity5:3.1.3.RELEASE"
|
||||||
implementation "org.springframework.boot:spring-boot-starter-data-jpa:$springBootVersion"
|
implementation "org.springframework.boot:spring-boot-starter-data-jpa:$springBootVersion"
|
||||||
implementation "org.springframework.boot:spring-boot-starter-oauth2-client:$springBootVersion"
|
implementation "org.springframework.boot:spring-boot-starter-oauth2-client:$springBootVersion"
|
||||||
|
|
||||||
implementation 'org.springframework.security:spring-security-saml2-service-provider:6.4.1'
|
implementation "org.springframework.session:spring-session-core:$springBootVersion"
|
||||||
|
|
||||||
implementation 'com.unboundid.product.scim2:scim2-sdk-client:2.3.5'
|
implementation 'com.unboundid.product.scim2:scim2-sdk-client:2.3.5'
|
||||||
// Don't upgrade h2database
|
// Don't upgrade h2database
|
||||||
runtimeOnly "com.h2database:h2:2.3.232"
|
runtimeOnly "com.h2database:h2:2.3.232"
|
||||||
constraints {
|
constraints {
|
||||||
implementation "org.opensaml:opensaml-core"
|
implementation "org.opensaml:opensaml-core:$openSamlVersion"
|
||||||
implementation "org.opensaml:opensaml-saml-api"
|
implementation "org.opensaml:opensaml-saml-api:$openSamlVersion"
|
||||||
implementation "org.opensaml:opensaml-saml-impl"
|
implementation "org.opensaml:opensaml-saml-impl:$openSamlVersion"
|
||||||
}
|
}
|
||||||
implementation "org.springframework.security:spring-security-saml2-service-provider"
|
implementation "org.springframework.security:spring-security-saml2-service-provider:$springSecuritySamlVersion"
|
||||||
|
// implementation 'org.springframework.security:spring-security-core:$springSecuritySamlVersion'
|
||||||
implementation 'com.coveo:saml-client:5.0.0'
|
implementation 'com.coveo:saml-client:5.0.0'
|
||||||
|
|
||||||
|
|
||||||
@@ -268,7 +425,14 @@ jar {
|
|||||||
tasks.named("test") {
|
tasks.named("test") {
|
||||||
useJUnitPlatform()
|
useJUnitPlatform()
|
||||||
}
|
}
|
||||||
|
|
||||||
task printVersion {
|
task printVersion {
|
||||||
|
doLast {
|
||||||
println project.version
|
println project.version
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
task printMacVersion {
|
||||||
|
doLast {
|
||||||
|
println getMacVersion(project.version.toString())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,24 +48,6 @@ Feature: API Validation
|
|||||||
And the response status code should be 200
|
And the response status code should be 200
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ocr @negative
|
|
||||||
Scenario: Process PDF with text and OCR with type normal
|
|
||||||
Given I generate a PDF file as "fileInput"
|
|
||||||
And the pdf contains 3 pages with random text
|
|
||||||
And the request data includes
|
|
||||||
| parameter | value |
|
|
||||||
| languages | eng |
|
|
||||||
| sidecar | false |
|
|
||||||
| deskew | true |
|
|
||||||
| clean | true |
|
|
||||||
| cleanFinal | true |
|
|
||||||
| ocrType | Normal |
|
|
||||||
| ocrRenderType | hocr |
|
|
||||||
| removeImagesAfter| false |
|
|
||||||
When I send the API request to the endpoint "/api/v1/misc/ocr-pdf"
|
|
||||||
Then the response status code should be 500
|
|
||||||
|
|
||||||
@ocr @positive
|
@ocr @positive
|
||||||
Scenario: Process PDF with OCR
|
Scenario: Process PDF with OCR
|
||||||
Given I generate a PDF file as "fileInput"
|
Given I generate a PDF file as "fileInput"
|
||||||
@@ -84,26 +66,6 @@ Feature: API Validation
|
|||||||
And the response file should have size greater than 0
|
And the response file should have size greater than 0
|
||||||
And the response status code should be 200
|
And the response status code should be 200
|
||||||
|
|
||||||
@ocr @positive
|
|
||||||
Scenario: Process PDF with OCR with sidecar
|
|
||||||
Given I generate a PDF file as "fileInput"
|
|
||||||
And the request data includes
|
|
||||||
| parameter | value |
|
|
||||||
| languages | eng |
|
|
||||||
| sidecar | true |
|
|
||||||
| deskew | true |
|
|
||||||
| clean | true |
|
|
||||||
| cleanFinal | true |
|
|
||||||
| ocrType | Force |
|
|
||||||
| ocrRenderType | hocr |
|
|
||||||
| removeImagesAfter| false |
|
|
||||||
When I send the API request to the endpoint "/api/v1/misc/ocr-pdf"
|
|
||||||
Then the response content type should be "application/octet-stream"
|
|
||||||
And the response file should have extension ".zip"
|
|
||||||
And the response ZIP should contain 2 files
|
|
||||||
And the response file should have size greater than 0
|
|
||||||
And the response status code should be 200
|
|
||||||
|
|
||||||
|
|
||||||
@libre @positive
|
@libre @positive
|
||||||
Scenario Outline: Convert PDF to various word formats
|
Scenario Outline: Convert PDF to various word formats
|
||||||
|
|||||||
@@ -15,6 +15,10 @@ import shutil
|
|||||||
import re
|
import re
|
||||||
from PIL import Image, ImageDraw
|
from PIL import Image, ImageDraw
|
||||||
|
|
||||||
|
API_HEADERS = {
|
||||||
|
'X-API-KEY': '123456789'
|
||||||
|
}
|
||||||
|
|
||||||
#########
|
#########
|
||||||
# GIVEN #
|
# GIVEN #
|
||||||
#########
|
#########
|
||||||
@@ -227,7 +231,7 @@ def save_generated_pdf(context, filename):
|
|||||||
def step_send_get_request(context, endpoint):
|
def step_send_get_request(context, endpoint):
|
||||||
base_url = "http://localhost:8080"
|
base_url = "http://localhost:8080"
|
||||||
full_url = f"{base_url}{endpoint}"
|
full_url = f"{base_url}{endpoint}"
|
||||||
response = requests.get(full_url)
|
response = requests.get(full_url, headers=API_HEADERS)
|
||||||
context.response = response
|
context.response = response
|
||||||
|
|
||||||
@when('I send a GET request to "{endpoint}" with parameters')
|
@when('I send a GET request to "{endpoint}" with parameters')
|
||||||
@@ -235,7 +239,7 @@ def step_send_get_request_with_params(context, endpoint):
|
|||||||
base_url = "http://localhost:8080"
|
base_url = "http://localhost:8080"
|
||||||
params = {row['parameter']: row['value'] for row in context.table}
|
params = {row['parameter']: row['value'] for row in context.table}
|
||||||
full_url = f"{base_url}{endpoint}"
|
full_url = f"{base_url}{endpoint}"
|
||||||
response = requests.get(full_url, params=params)
|
response = requests.get(full_url, params=params, headers=API_HEADERS)
|
||||||
context.response = response
|
context.response = response
|
||||||
|
|
||||||
@when('I send the API request to the endpoint "{endpoint}"')
|
@when('I send the API request to the endpoint "{endpoint}"')
|
||||||
@@ -256,7 +260,7 @@ def step_send_api_request(context, endpoint):
|
|||||||
print(f"form_data {file.name} with {mime_type}")
|
print(f"form_data {file.name} with {mime_type}")
|
||||||
form_data.append((key, (file.name, file, mime_type)))
|
form_data.append((key, (file.name, file, mime_type)))
|
||||||
|
|
||||||
response = requests.post(url, files=form_data)
|
response = requests.post(url, files=form_data, headers=API_HEADERS)
|
||||||
context.response = response
|
context.response = response
|
||||||
|
|
||||||
########
|
########
|
||||||
|
|||||||
34
exampleYmlFiles/test_cicd.yml
Normal file
34
exampleYmlFiles/test_cicd.yml
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
services:
|
||||||
|
stirling-pdf:
|
||||||
|
container_name: Stirling-PDF-Security-Fat
|
||||||
|
image: stirlingtools/stirling-pdf:latest-fat
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 4G
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "curl -f -H 'X-API-KEY: 123456789' http://localhost:8080/api/v1/info/status | grep -q 'UP'"]
|
||||||
|
interval: 5s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 16
|
||||||
|
ports:
|
||||||
|
- 8080:8080
|
||||||
|
volumes:
|
||||||
|
- /stirling/latest/data:/usr/share/tessdata:rw
|
||||||
|
- /stirling/latest/config:/configs:rw
|
||||||
|
- /stirling/latest/logs:/logs:rw
|
||||||
|
environment:
|
||||||
|
DOCKER_ENABLE_SECURITY: "true"
|
||||||
|
SECURITY_ENABLELOGIN: "true"
|
||||||
|
PUID: 1002
|
||||||
|
PGID: 1002
|
||||||
|
UMASK: "022"
|
||||||
|
SYSTEM_DEFAULTLOCALE: en-US
|
||||||
|
UI_APPNAME: Stirling-PDF
|
||||||
|
UI_HOMEDESCRIPTION: Demo site for Stirling-PDF Latest-fat with Security
|
||||||
|
UI_APPNAMENAVBAR: Stirling-PDF Latest-fat
|
||||||
|
SYSTEM_MAXFILESIZE: "100"
|
||||||
|
METRICS_ENABLED: "true"
|
||||||
|
SYSTEM_GOOGLEVISIBILITY: "true"
|
||||||
|
SECURITY_CUSTOMGLOBALAPIKEY: "123456789"
|
||||||
|
restart: on-failure:5
|
||||||
@@ -42,14 +42,19 @@ ignore = [
|
|||||||
'addPageNumbers.selectText.3',
|
'addPageNumbers.selectText.3',
|
||||||
'alphabet',
|
'alphabet',
|
||||||
'certSign.name',
|
'certSign.name',
|
||||||
|
'fileChooser.dragAndDrop',
|
||||||
'home.pipeline.title',
|
'home.pipeline.title',
|
||||||
'language.direction',
|
'language.direction',
|
||||||
|
'legal.impressum',
|
||||||
'licenses.version',
|
'licenses.version',
|
||||||
'pipeline.title',
|
'pipeline.title',
|
||||||
'pipelineOptions.pipelineHeader',
|
'pipelineOptions.pipelineHeader',
|
||||||
'pro',
|
'pro',
|
||||||
'sponsor',
|
'sponsor',
|
||||||
'text',
|
'text',
|
||||||
|
'validateSignature.cert.bits',
|
||||||
|
'validateSignature.cert.version',
|
||||||
|
'validateSignature.status',
|
||||||
'watermark.type.1',
|
'watermark.type.1',
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -61,7 +66,6 @@ ignore = [
|
|||||||
[es_ES]
|
[es_ES]
|
||||||
ignore = [
|
ignore = [
|
||||||
'adminUserSettings.roles',
|
'adminUserSettings.roles',
|
||||||
'color',
|
|
||||||
'error',
|
'error',
|
||||||
'language.direction',
|
'language.direction',
|
||||||
'no',
|
'no',
|
||||||
@@ -73,6 +77,11 @@ ignore = [
|
|||||||
'language.direction',
|
'language.direction',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[fa_IR]
|
||||||
|
ignore = [
|
||||||
|
'language.direction',
|
||||||
|
]
|
||||||
|
|
||||||
[fr_FR]
|
[fr_FR]
|
||||||
ignore = [
|
ignore = [
|
||||||
'AddStampRequest.alphabet',
|
'AddStampRequest.alphabet',
|
||||||
|
|||||||
@@ -3,13 +3,14 @@ package stirling.software.SPDF.EE;
|
|||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.context.annotation.Lazy;
|
import org.springframework.core.Ordered;
|
||||||
|
import org.springframework.core.annotation.Order;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import stirling.software.SPDF.model.ApplicationProperties;
|
import stirling.software.SPDF.model.ApplicationProperties;
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@Lazy
|
@Order(Ordered.HIGHEST_PRECEDENCE)
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class EEAppConfig {
|
public class EEAppConfig {
|
||||||
|
|
||||||
|
|||||||
@@ -25,9 +25,10 @@ public class LicenseKeyChecker {
|
|||||||
KeygenLicenseVerifier licenseService, ApplicationProperties applicationProperties) {
|
KeygenLicenseVerifier licenseService, ApplicationProperties applicationProperties) {
|
||||||
this.licenseService = licenseService;
|
this.licenseService = licenseService;
|
||||||
this.applicationProperties = applicationProperties;
|
this.applicationProperties = applicationProperties;
|
||||||
|
this.checkLicense();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Scheduled(fixedRate = 604800000, initialDelay = 1000) // 7 days in milliseconds
|
@Scheduled(initialDelay = 604800000, fixedRate = 604800000) // 7 days in milliseconds
|
||||||
public void checkLicensePeriodically() {
|
public void checkLicensePeriodically() {
|
||||||
checkLicense();
|
checkLicense();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package stirling.software.SPDF;
|
package stirling.software.SPDF;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.ServerSocket;
|
import java.net.ServerSocket;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
@@ -8,6 +9,9 @@ import java.nio.file.Paths;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
@@ -19,13 +23,16 @@ import org.springframework.core.env.Environment;
|
|||||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||||
|
|
||||||
import io.github.pixee.security.SystemCommand;
|
import io.github.pixee.security.SystemCommand;
|
||||||
|
|
||||||
import jakarta.annotation.PostConstruct;
|
import jakarta.annotation.PostConstruct;
|
||||||
|
import jakarta.annotation.PreDestroy;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import stirling.software.SPDF.UI.WebBrowser;
|
||||||
import stirling.software.SPDF.config.ConfigInitializer;
|
import stirling.software.SPDF.config.ConfigInitializer;
|
||||||
import stirling.software.SPDF.model.ApplicationProperties;
|
import stirling.software.SPDF.model.ApplicationProperties;
|
||||||
|
|
||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
@EnableScheduling
|
@EnableScheduling
|
||||||
|
@Slf4j
|
||||||
public class SPdfApplication {
|
public class SPdfApplication {
|
||||||
|
|
||||||
private static final Logger logger = LoggerFactory.getLogger(SPdfApplication.class);
|
private static final Logger logger = LoggerFactory.getLogger(SPdfApplication.class);
|
||||||
@@ -67,36 +74,19 @@ public class SPdfApplication {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostConstruct
|
|
||||||
public void init() {
|
|
||||||
baseUrlStatic = this.baseUrl;
|
|
||||||
// Check if the BROWSER_OPEN environment variable is set to true
|
|
||||||
String browserOpenEnv = env.getProperty("BROWSER_OPEN");
|
|
||||||
boolean browserOpen = browserOpenEnv != null && "true".equalsIgnoreCase(browserOpenEnv);
|
|
||||||
if (browserOpen) {
|
|
||||||
try {
|
|
||||||
String url = baseUrl + ":" + getStaticPort();
|
|
||||||
|
|
||||||
String os = System.getProperty("os.name").toLowerCase();
|
|
||||||
Runtime rt = Runtime.getRuntime();
|
|
||||||
if (os.contains("win")) {
|
|
||||||
// For Windows
|
|
||||||
SystemCommand.runCommand(rt, "rundll32 url.dll,FileProtocolHandler " + url);
|
|
||||||
} else if (os.contains("mac")) {
|
|
||||||
SystemCommand.runCommand(rt, "open " + url);
|
|
||||||
} else if (os.contains("nix") || os.contains("nux")) {
|
|
||||||
SystemCommand.runCommand(rt, "xdg-open " + url);
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
logger.error("Error opening browser: {}", e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
logger.info("Running configs {}", applicationProperties.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void main(String[] args) throws IOException, InterruptedException {
|
public static void main(String[] args) throws IOException, InterruptedException {
|
||||||
|
|
||||||
SpringApplication app = new SpringApplication(SPdfApplication.class);
|
SpringApplication app = new SpringApplication(SPdfApplication.class);
|
||||||
|
|
||||||
|
Properties props = new Properties();
|
||||||
|
|
||||||
|
if (Boolean.parseBoolean(System.getProperty("STIRLING_PDF_DESKTOP_UI", "false"))) {
|
||||||
|
System.setProperty("java.awt.headless", "false");
|
||||||
|
app.setHeadless(false);
|
||||||
|
props.put("java.awt.headless", "false");
|
||||||
|
props.put("spring.main.web-application-type", "servlet");
|
||||||
|
}
|
||||||
|
|
||||||
app.setAdditionalProfiles("default");
|
app.setAdditionalProfiles("default");
|
||||||
app.addInitializers(new ConfigInitializer());
|
app.addInitializers(new ConfigInitializer());
|
||||||
Map<String, String> propertyFiles = new HashMap<>();
|
Map<String, String> propertyFiles = new HashMap<>();
|
||||||
@@ -120,14 +110,20 @@ public class SPdfApplication {
|
|||||||
} else {
|
} else {
|
||||||
logger.warn("Custom configuration file 'configs/custom_settings.yml' does not exist.");
|
logger.warn("Custom configuration file 'configs/custom_settings.yml' does not exist.");
|
||||||
}
|
}
|
||||||
|
Properties finalProps = new Properties();
|
||||||
|
|
||||||
if (!propertyFiles.isEmpty()) {
|
if (!propertyFiles.isEmpty()) {
|
||||||
app.setDefaultProperties(
|
finalProps.putAll(
|
||||||
Collections.singletonMap(
|
Collections.singletonMap(
|
||||||
"spring.config.additional-location",
|
"spring.config.additional-location",
|
||||||
propertyFiles.get("spring.config.additional-location")));
|
propertyFiles.get("spring.config.additional-location")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!props.isEmpty()) {
|
||||||
|
finalProps.putAll(props);
|
||||||
|
}
|
||||||
|
app.setDefaultProperties(finalProps);
|
||||||
|
|
||||||
app.run(args);
|
app.run(args);
|
||||||
|
|
||||||
// Ensure directories are created
|
// Ensure directories are created
|
||||||
@@ -147,6 +143,46 @@ public class SPdfApplication {
|
|||||||
logger.info("Navigate to {}", url);
|
logger.info("Navigate to {}", url);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Autowired(required = false)
|
||||||
|
private WebBrowser webBrowser;
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
public void init() {
|
||||||
|
baseUrlStatic = this.baseUrl;
|
||||||
|
String url = baseUrl + ":" + getStaticPort();
|
||||||
|
if (webBrowser != null
|
||||||
|
&& Boolean.parseBoolean(System.getProperty("STIRLING_PDF_DESKTOP_UI", "false"))) {
|
||||||
|
webBrowser.initWebUI(url);
|
||||||
|
} else {
|
||||||
|
String browserOpenEnv = env.getProperty("BROWSER_OPEN");
|
||||||
|
boolean browserOpen = browserOpenEnv != null && "true".equalsIgnoreCase(browserOpenEnv);
|
||||||
|
if (browserOpen) {
|
||||||
|
try {
|
||||||
|
String os = System.getProperty("os.name").toLowerCase();
|
||||||
|
Runtime rt = Runtime.getRuntime();
|
||||||
|
if (os.contains("win")) {
|
||||||
|
// For Windows
|
||||||
|
SystemCommand.runCommand(rt, "rundll32 url.dll,FileProtocolHandler " + url);
|
||||||
|
} else if (os.contains("mac")) {
|
||||||
|
SystemCommand.runCommand(rt, "open " + url);
|
||||||
|
} else if (os.contains("nix") || os.contains("nux")) {
|
||||||
|
SystemCommand.runCommand(rt, "xdg-open " + url);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("Error opening browser: {}", e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logger.info("Running configs {}", applicationProperties.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@PreDestroy
|
||||||
|
public void cleanup() {
|
||||||
|
if (webBrowser != null) {
|
||||||
|
webBrowser.cleanup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static String getStaticBaseUrl() {
|
public static String getStaticBaseUrl() {
|
||||||
return baseUrlStatic;
|
return baseUrlStatic;
|
||||||
}
|
}
|
||||||
|
|||||||
7
src/main/java/stirling/software/SPDF/UI/WebBrowser.java
Normal file
7
src/main/java/stirling/software/SPDF/UI/WebBrowser.java
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
package stirling.software.SPDF.UI;
|
||||||
|
|
||||||
|
public interface WebBrowser {
|
||||||
|
void initWebUI(String url);
|
||||||
|
|
||||||
|
void cleanup();
|
||||||
|
}
|
||||||
354
src/main/java/stirling/software/SPDF/UI/impl/DesktopBrowser.java
Normal file
354
src/main/java/stirling/software/SPDF/UI/impl/DesktopBrowser.java
Normal file
@@ -0,0 +1,354 @@
|
|||||||
|
package stirling.software.SPDF.UI.impl;
|
||||||
|
|
||||||
|
import java.awt.AWTException;
|
||||||
|
import java.awt.BorderLayout;
|
||||||
|
import java.awt.Frame;
|
||||||
|
import java.awt.Image;
|
||||||
|
import java.awt.MenuItem;
|
||||||
|
import java.awt.PopupMenu;
|
||||||
|
import java.awt.SystemTray;
|
||||||
|
import java.awt.TrayIcon;
|
||||||
|
import java.awt.event.WindowEvent;
|
||||||
|
import java.awt.event.WindowStateListener;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
|
import javax.swing.JFrame;
|
||||||
|
import javax.swing.JPanel;
|
||||||
|
import javax.swing.SwingUtilities;
|
||||||
|
import javax.swing.Timer;
|
||||||
|
|
||||||
|
import org.cef.CefApp;
|
||||||
|
import org.cef.CefClient;
|
||||||
|
import org.cef.CefSettings;
|
||||||
|
import org.cef.browser.CefBrowser;
|
||||||
|
import org.cef.callback.CefBeforeDownloadCallback;
|
||||||
|
import org.cef.callback.CefDownloadItem;
|
||||||
|
import org.cef.callback.CefDownloadItemCallback;
|
||||||
|
import org.cef.handler.CefDownloadHandlerAdapter;
|
||||||
|
import org.cef.handler.CefLoadHandlerAdapter;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import jakarta.annotation.PreDestroy;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import me.friwi.jcefmaven.CefAppBuilder;
|
||||||
|
import me.friwi.jcefmaven.EnumProgress;
|
||||||
|
import me.friwi.jcefmaven.MavenCefAppHandlerAdapter;
|
||||||
|
import me.friwi.jcefmaven.impl.progress.ConsoleProgressHandler;
|
||||||
|
import stirling.software.SPDF.UI.WebBrowser;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@Slf4j
|
||||||
|
@ConditionalOnProperty(
|
||||||
|
name = "STIRLING_PDF_DESKTOP_UI",
|
||||||
|
havingValue = "true",
|
||||||
|
matchIfMissing = false)
|
||||||
|
public class DesktopBrowser implements WebBrowser {
|
||||||
|
private static CefApp cefApp;
|
||||||
|
private static CefClient client;
|
||||||
|
private static CefBrowser browser;
|
||||||
|
private static JFrame frame;
|
||||||
|
private static LoadingWindow loadingWindow;
|
||||||
|
private static volatile boolean browserInitialized = false;
|
||||||
|
private static TrayIcon trayIcon;
|
||||||
|
private static SystemTray systemTray;
|
||||||
|
|
||||||
|
public DesktopBrowser() {
|
||||||
|
SwingUtilities.invokeLater(
|
||||||
|
() -> {
|
||||||
|
loadingWindow = new LoadingWindow(null, "Initializing...");
|
||||||
|
loadingWindow.setVisible(true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void initWebUI(String url) {
|
||||||
|
CompletableFuture.runAsync(
|
||||||
|
() -> {
|
||||||
|
try {
|
||||||
|
CefAppBuilder builder = new CefAppBuilder();
|
||||||
|
configureCefSettings(builder);
|
||||||
|
builder.setProgressHandler(createProgressHandler());
|
||||||
|
|
||||||
|
// Build and initialize CEF
|
||||||
|
cefApp = builder.build();
|
||||||
|
client = cefApp.createClient();
|
||||||
|
|
||||||
|
// Set up download handler
|
||||||
|
setupDownloadHandler();
|
||||||
|
|
||||||
|
// Create browser and frame on EDT
|
||||||
|
SwingUtilities.invokeAndWait(
|
||||||
|
() -> {
|
||||||
|
browser = client.createBrowser(url, false, false);
|
||||||
|
setupMainFrame();
|
||||||
|
setupLoadHandler();
|
||||||
|
|
||||||
|
// Show the frame immediately but transparent
|
||||||
|
frame.setVisible(true);
|
||||||
|
});
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Error initializing JCEF browser: ", e);
|
||||||
|
cleanup();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void configureCefSettings(CefAppBuilder builder) {
|
||||||
|
CefSettings settings = builder.getCefSettings();
|
||||||
|
settings.cache_path = new File("jcef-bundle").getAbsolutePath();
|
||||||
|
settings.root_cache_path = new File("jcef-bundle").getAbsolutePath();
|
||||||
|
settings.persist_session_cookies = true;
|
||||||
|
settings.windowless_rendering_enabled = false;
|
||||||
|
settings.log_severity = CefSettings.LogSeverity.LOGSEVERITY_INFO;
|
||||||
|
|
||||||
|
builder.setAppHandler(
|
||||||
|
new MavenCefAppHandlerAdapter() {
|
||||||
|
@Override
|
||||||
|
public void stateHasChanged(org.cef.CefApp.CefAppState state) {
|
||||||
|
log.info("CEF state changed: " + state);
|
||||||
|
if (state == CefApp.CefAppState.TERMINATED) {
|
||||||
|
System.exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupDownloadHandler() {
|
||||||
|
client.addDownloadHandler(
|
||||||
|
new CefDownloadHandlerAdapter() {
|
||||||
|
@Override
|
||||||
|
public boolean onBeforeDownload(
|
||||||
|
CefBrowser browser,
|
||||||
|
CefDownloadItem downloadItem,
|
||||||
|
String suggestedName,
|
||||||
|
CefBeforeDownloadCallback callback) {
|
||||||
|
callback.Continue("", true);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDownloadUpdated(
|
||||||
|
CefBrowser browser,
|
||||||
|
CefDownloadItem downloadItem,
|
||||||
|
CefDownloadItemCallback callback) {
|
||||||
|
if (downloadItem.isComplete()) {
|
||||||
|
log.info("Download completed: " + downloadItem.getFullPath());
|
||||||
|
} else if (downloadItem.isCanceled()) {
|
||||||
|
log.info("Download canceled: " + downloadItem.getFullPath());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private ConsoleProgressHandler createProgressHandler() {
|
||||||
|
return new ConsoleProgressHandler() {
|
||||||
|
@Override
|
||||||
|
public void handleProgress(EnumProgress state, float percent) {
|
||||||
|
Objects.requireNonNull(state, "state cannot be null");
|
||||||
|
SwingUtilities.invokeLater(
|
||||||
|
() -> {
|
||||||
|
if (loadingWindow != null) {
|
||||||
|
switch (state) {
|
||||||
|
case LOCATING:
|
||||||
|
loadingWindow.setStatus("Locating Files...");
|
||||||
|
loadingWindow.setProgress(0);
|
||||||
|
break;
|
||||||
|
case DOWNLOADING:
|
||||||
|
if (percent >= 0) {
|
||||||
|
loadingWindow.setStatus(
|
||||||
|
String.format(
|
||||||
|
"Downloading additional files: %.0f%%",
|
||||||
|
percent));
|
||||||
|
loadingWindow.setProgress((int) percent);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case EXTRACTING:
|
||||||
|
loadingWindow.setStatus("Extracting files...");
|
||||||
|
loadingWindow.setProgress(60);
|
||||||
|
break;
|
||||||
|
case INITIALIZING:
|
||||||
|
loadingWindow.setStatus("Initializing UI...");
|
||||||
|
loadingWindow.setProgress(80);
|
||||||
|
break;
|
||||||
|
case INITIALIZED:
|
||||||
|
loadingWindow.setStatus("Finalising startup...");
|
||||||
|
loadingWindow.setProgress(90);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupMainFrame() {
|
||||||
|
frame = new JFrame("Stirling-PDF");
|
||||||
|
frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
|
||||||
|
frame.setUndecorated(true);
|
||||||
|
frame.setOpacity(0.0f);
|
||||||
|
|
||||||
|
JPanel contentPane = new JPanel(new BorderLayout());
|
||||||
|
contentPane.setDoubleBuffered(true);
|
||||||
|
contentPane.add(browser.getUIComponent(), BorderLayout.CENTER);
|
||||||
|
frame.setContentPane(contentPane);
|
||||||
|
|
||||||
|
frame.addWindowListener(
|
||||||
|
new java.awt.event.WindowAdapter() {
|
||||||
|
@Override
|
||||||
|
public void windowClosing(java.awt.event.WindowEvent windowEvent) {
|
||||||
|
cleanup();
|
||||||
|
System.exit(0);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
frame.setSize(1280, 768);
|
||||||
|
frame.setLocationRelativeTo(null);
|
||||||
|
|
||||||
|
loadIcon();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupLoadHandler() {
|
||||||
|
client.addLoadHandler(
|
||||||
|
new CefLoadHandlerAdapter() {
|
||||||
|
@Override
|
||||||
|
public void onLoadingStateChange(
|
||||||
|
CefBrowser browser,
|
||||||
|
boolean isLoading,
|
||||||
|
boolean canGoBack,
|
||||||
|
boolean canGoForward) {
|
||||||
|
if (!isLoading && !browserInitialized) {
|
||||||
|
browserInitialized = true;
|
||||||
|
SwingUtilities.invokeLater(
|
||||||
|
() -> {
|
||||||
|
if (loadingWindow != null) {
|
||||||
|
Timer timer =
|
||||||
|
new Timer(
|
||||||
|
500,
|
||||||
|
e -> {
|
||||||
|
loadingWindow.dispose();
|
||||||
|
loadingWindow = null;
|
||||||
|
|
||||||
|
frame.dispose();
|
||||||
|
frame.setOpacity(1.0f);
|
||||||
|
frame.setUndecorated(false);
|
||||||
|
frame.pack();
|
||||||
|
frame.setSize(1280, 800);
|
||||||
|
frame.setLocationRelativeTo(null);
|
||||||
|
frame.setVisible(true);
|
||||||
|
frame.requestFocus();
|
||||||
|
frame.toFront();
|
||||||
|
browser.getUIComponent()
|
||||||
|
.requestFocus();
|
||||||
|
});
|
||||||
|
timer.setRepeats(false);
|
||||||
|
timer.start();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupTrayIcon(Image icon) {
|
||||||
|
if (!SystemTray.isSupported()) {
|
||||||
|
log.warn("System tray is not supported");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
systemTray = SystemTray.getSystemTray();
|
||||||
|
|
||||||
|
// Create popup menu
|
||||||
|
PopupMenu popup = new PopupMenu();
|
||||||
|
|
||||||
|
// Create menu items
|
||||||
|
MenuItem showItem = new MenuItem("Show");
|
||||||
|
showItem.addActionListener(
|
||||||
|
e -> {
|
||||||
|
frame.setVisible(true);
|
||||||
|
frame.setState(Frame.NORMAL);
|
||||||
|
});
|
||||||
|
|
||||||
|
MenuItem exitItem = new MenuItem("Exit");
|
||||||
|
exitItem.addActionListener(
|
||||||
|
e -> {
|
||||||
|
cleanup();
|
||||||
|
System.exit(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add menu items to popup menu
|
||||||
|
popup.add(showItem);
|
||||||
|
popup.addSeparator();
|
||||||
|
popup.add(exitItem);
|
||||||
|
|
||||||
|
// Create tray icon
|
||||||
|
trayIcon = new TrayIcon(icon, "Stirling-PDF", popup);
|
||||||
|
trayIcon.setImageAutoSize(true);
|
||||||
|
|
||||||
|
// Add double-click behavior
|
||||||
|
trayIcon.addActionListener(
|
||||||
|
e -> {
|
||||||
|
frame.setVisible(true);
|
||||||
|
frame.setState(Frame.NORMAL);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add tray icon to system tray
|
||||||
|
systemTray.add(trayIcon);
|
||||||
|
|
||||||
|
// Modify frame behavior to minimize to tray
|
||||||
|
frame.addWindowStateListener(
|
||||||
|
new WindowStateListener() {
|
||||||
|
public void windowStateChanged(WindowEvent e) {
|
||||||
|
if (e.getNewState() == Frame.ICONIFIED) {
|
||||||
|
frame.setVisible(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
} catch (AWTException e) {
|
||||||
|
log.error("Error setting up system tray icon", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadIcon() {
|
||||||
|
try {
|
||||||
|
Image icon = null;
|
||||||
|
String[] iconPaths = {"/static/favicon.ico"};
|
||||||
|
|
||||||
|
for (String path : iconPaths) {
|
||||||
|
if (icon != null) break;
|
||||||
|
try {
|
||||||
|
try (InputStream is = getClass().getResourceAsStream(path)) {
|
||||||
|
if (is != null) {
|
||||||
|
icon = ImageIO.read(is);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.debug("Could not load icon from " + path, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (icon != null) {
|
||||||
|
frame.setIconImage(icon);
|
||||||
|
setupTrayIcon(icon);
|
||||||
|
} else {
|
||||||
|
log.warn("Could not load icon from any source");
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Error loading icon", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@PreDestroy
|
||||||
|
public void cleanup() {
|
||||||
|
if (browser != null) browser.close(true);
|
||||||
|
if (client != null) client.dispose();
|
||||||
|
if (cefApp != null) cefApp.dispose();
|
||||||
|
if (loadingWindow != null) loadingWindow.dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
114
src/main/java/stirling/software/SPDF/UI/impl/LoadingWindow.java
Normal file
114
src/main/java/stirling/software/SPDF/UI/impl/LoadingWindow.java
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
package stirling.software.SPDF.UI.impl;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
|
import javax.swing.*;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
public class LoadingWindow extends JDialog {
|
||||||
|
private final JProgressBar progressBar;
|
||||||
|
private final JLabel statusLabel;
|
||||||
|
private final JPanel mainPanel;
|
||||||
|
private final JLabel brandLabel;
|
||||||
|
|
||||||
|
public LoadingWindow(Frame parent, String initialUrl) {
|
||||||
|
super(parent, "Initializing Stirling-PDF", true);
|
||||||
|
|
||||||
|
// Initialize components
|
||||||
|
mainPanel = new JPanel();
|
||||||
|
mainPanel.setBackground(Color.WHITE);
|
||||||
|
mainPanel.setBorder(BorderFactory.createEmptyBorder(20, 30, 20, 30));
|
||||||
|
mainPanel.setLayout(new GridBagLayout());
|
||||||
|
GridBagConstraints gbc = new GridBagConstraints();
|
||||||
|
|
||||||
|
// Configure GridBagConstraints
|
||||||
|
gbc.gridwidth = GridBagConstraints.REMAINDER;
|
||||||
|
gbc.fill = GridBagConstraints.HORIZONTAL;
|
||||||
|
gbc.insets = new Insets(5, 5, 5, 5);
|
||||||
|
gbc.weightx = 1.0; // Add horizontal weight
|
||||||
|
gbc.weighty = 0.0; // Add vertical weight
|
||||||
|
|
||||||
|
// Add icon
|
||||||
|
try {
|
||||||
|
try (InputStream is = getClass().getResourceAsStream("/static/favicon.ico")) {
|
||||||
|
if (is != null) {
|
||||||
|
Image img = ImageIO.read(is);
|
||||||
|
if (img != null) {
|
||||||
|
Image scaledImg = img.getScaledInstance(48, 48, Image.SCALE_SMOOTH);
|
||||||
|
JLabel iconLabel = new JLabel(new ImageIcon(scaledImg));
|
||||||
|
iconLabel.setHorizontalAlignment(SwingConstants.CENTER);
|
||||||
|
gbc.gridy = 0;
|
||||||
|
mainPanel.add(iconLabel, gbc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Failed to load icon", e);
|
||||||
|
}
|
||||||
|
// URL Label with explicit size
|
||||||
|
brandLabel = new JLabel(initialUrl);
|
||||||
|
brandLabel.setHorizontalAlignment(SwingConstants.CENTER);
|
||||||
|
brandLabel.setPreferredSize(new Dimension(300, 25));
|
||||||
|
brandLabel.setText("Stirling-PDF");
|
||||||
|
gbc.gridy = 1;
|
||||||
|
mainPanel.add(brandLabel, gbc);
|
||||||
|
|
||||||
|
// Status label with explicit size
|
||||||
|
statusLabel = new JLabel("Initializing...");
|
||||||
|
statusLabel.setHorizontalAlignment(SwingConstants.CENTER);
|
||||||
|
statusLabel.setPreferredSize(new Dimension(300, 25));
|
||||||
|
gbc.gridy = 2;
|
||||||
|
mainPanel.add(statusLabel, gbc);
|
||||||
|
// Progress bar with explicit size
|
||||||
|
progressBar = new JProgressBar(0, 100);
|
||||||
|
progressBar.setStringPainted(true);
|
||||||
|
progressBar.setPreferredSize(new Dimension(300, 25));
|
||||||
|
gbc.gridy = 3;
|
||||||
|
mainPanel.add(progressBar, gbc);
|
||||||
|
|
||||||
|
// Set dialog properties
|
||||||
|
setContentPane(mainPanel);
|
||||||
|
setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
|
||||||
|
setResizable(false);
|
||||||
|
setUndecorated(false);
|
||||||
|
|
||||||
|
// Set size and position
|
||||||
|
setSize(400, 200);
|
||||||
|
setLocationRelativeTo(parent);
|
||||||
|
setAlwaysOnTop(true);
|
||||||
|
setProgress(0);
|
||||||
|
setStatus("Starting...");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setProgress(final int progress) {
|
||||||
|
SwingUtilities.invokeLater(
|
||||||
|
() -> {
|
||||||
|
try {
|
||||||
|
progressBar.setValue(Math.min(Math.max(progress, 0), 100));
|
||||||
|
progressBar.setString(progress + "%");
|
||||||
|
mainPanel.revalidate();
|
||||||
|
mainPanel.repaint();
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Error updating progress", e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStatus(final String status) {
|
||||||
|
log.info(status);
|
||||||
|
SwingUtilities.invokeLater(
|
||||||
|
() -> {
|
||||||
|
try {
|
||||||
|
statusLabel.setText(status != null ? status : "");
|
||||||
|
mainPanel.revalidate();
|
||||||
|
mainPanel.repaint();
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Error updating status", e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -260,6 +260,9 @@ public class EndpointConfiguration {
|
|||||||
|
|
||||||
// Pdftohtml dependent endpoints
|
// Pdftohtml dependent endpoints
|
||||||
addEndpointToGroup("Pdftohtml", "pdf-to-html");
|
addEndpointToGroup("Pdftohtml", "pdf-to-html");
|
||||||
|
|
||||||
|
// disabled for now while we resolve issues
|
||||||
|
disableEndpoint("pdf-to-pdfa");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processEnvironmentConfigs() {
|
private void processEnvironmentConfigs() {
|
||||||
|
|||||||
@@ -43,7 +43,6 @@ public class ExternalAppDepConfig {
|
|||||||
put("unoconv", List.of("Unoconv"));
|
put("unoconv", List.of("Unoconv"));
|
||||||
put("qpdf", List.of("qpdf"));
|
put("qpdf", List.of("qpdf"));
|
||||||
put("tesseract", List.of("tesseract"));
|
put("tesseract", List.of("tesseract"));
|
||||||
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
package stirling.software.SPDF.config;
|
package stirling.software.SPDF.config;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Properties;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.core.Ordered;
|
import org.springframework.core.Ordered;
|
||||||
import org.springframework.core.annotation.Order;
|
import org.springframework.core.annotation.Order;
|
||||||
|
import org.springframework.core.io.ClassPathResource;
|
||||||
|
import org.springframework.core.io.Resource;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import io.micrometer.common.util.StringUtils;
|
import io.micrometer.common.util.StringUtils;
|
||||||
@@ -23,6 +26,18 @@ public class InitialSetup {
|
|||||||
@Autowired private ApplicationProperties applicationProperties;
|
@Autowired private ApplicationProperties applicationProperties;
|
||||||
|
|
||||||
@PostConstruct
|
@PostConstruct
|
||||||
|
public void init() throws IOException {
|
||||||
|
initUUIDKey();
|
||||||
|
|
||||||
|
initSecretKey();
|
||||||
|
|
||||||
|
initEnableCSRFSecurity();
|
||||||
|
|
||||||
|
initLegalUrls();
|
||||||
|
|
||||||
|
initSetAppVersion();
|
||||||
|
}
|
||||||
|
|
||||||
public void initUUIDKey() throws IOException {
|
public void initUUIDKey() throws IOException {
|
||||||
String uuid = applicationProperties.getAutomaticallyGenerated().getUUID();
|
String uuid = applicationProperties.getAutomaticallyGenerated().getUUID();
|
||||||
if (!GeneralUtils.isValidUUID(uuid)) {
|
if (!GeneralUtils.isValidUUID(uuid)) {
|
||||||
@@ -32,7 +47,6 @@ public class InitialSetup {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostConstruct
|
|
||||||
public void initSecretKey() throws IOException {
|
public void initSecretKey() throws IOException {
|
||||||
String secretKey = applicationProperties.getAutomaticallyGenerated().getKey();
|
String secretKey = applicationProperties.getAutomaticallyGenerated().getKey();
|
||||||
if (!GeneralUtils.isValidUUID(secretKey)) {
|
if (!GeneralUtils.isValidUUID(secretKey)) {
|
||||||
@@ -42,13 +56,24 @@ public class InitialSetup {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostConstruct
|
public void initEnableCSRFSecurity() throws IOException {
|
||||||
|
if (GeneralUtils.isVersionHigher(
|
||||||
|
"0.36.0", applicationProperties.getAutomaticallyGenerated().getAppVersion())) {
|
||||||
|
Boolean csrf = applicationProperties.getSecurity().getCsrfDisabled();
|
||||||
|
if (!csrf) {
|
||||||
|
GeneralUtils.saveKeyToConfig("security.csrfDisabled", false, false);
|
||||||
|
GeneralUtils.saveKeyToConfig("system.enableAnalytics", "true", false);
|
||||||
|
applicationProperties.getSecurity().setCsrfDisabled(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void initLegalUrls() throws IOException {
|
public void initLegalUrls() throws IOException {
|
||||||
// Initialize Terms and Conditions
|
// Initialize Terms and Conditions
|
||||||
String termsUrl = applicationProperties.getLegal().getTermsAndConditions();
|
String termsUrl = applicationProperties.getLegal().getTermsAndConditions();
|
||||||
if (StringUtils.isEmpty(termsUrl)) {
|
if (StringUtils.isEmpty(termsUrl)) {
|
||||||
String defaultTermsUrl = "https://www.stirlingpdf.com/terms-and-conditions";
|
String defaultTermsUrl = "https://www.stirlingpdf.com/terms-and-conditions";
|
||||||
GeneralUtils.saveKeyToConfig("legal.termsAndConditions", defaultTermsUrl);
|
GeneralUtils.saveKeyToConfig("legal.termsAndConditions", defaultTermsUrl, false);
|
||||||
applicationProperties.getLegal().setTermsAndConditions(defaultTermsUrl);
|
applicationProperties.getLegal().setTermsAndConditions(defaultTermsUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,8 +81,23 @@ public class InitialSetup {
|
|||||||
String privacyUrl = applicationProperties.getLegal().getPrivacyPolicy();
|
String privacyUrl = applicationProperties.getLegal().getPrivacyPolicy();
|
||||||
if (StringUtils.isEmpty(privacyUrl)) {
|
if (StringUtils.isEmpty(privacyUrl)) {
|
||||||
String defaultPrivacyUrl = "https://www.stirlingpdf.com/privacy-policy";
|
String defaultPrivacyUrl = "https://www.stirlingpdf.com/privacy-policy";
|
||||||
GeneralUtils.saveKeyToConfig("legal.privacyPolicy", defaultPrivacyUrl);
|
GeneralUtils.saveKeyToConfig("legal.privacyPolicy", defaultPrivacyUrl, false);
|
||||||
applicationProperties.getLegal().setPrivacyPolicy(defaultPrivacyUrl);
|
applicationProperties.getLegal().setPrivacyPolicy(defaultPrivacyUrl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void initSetAppVersion() throws IOException {
|
||||||
|
|
||||||
|
String appVersion = "0.0.0";
|
||||||
|
Resource resource = new ClassPathResource("version.properties");
|
||||||
|
Properties props = new Properties();
|
||||||
|
try {
|
||||||
|
props.load(resource.getInputStream());
|
||||||
|
appVersion = props.getProperty("version");
|
||||||
|
} catch (Exception e) {
|
||||||
|
|
||||||
|
}
|
||||||
|
applicationProperties.getAutomaticallyGenerated().setAppVersion(appVersion);
|
||||||
|
GeneralUtils.saveKeyToConfig("AutomaticallyGenerated.appVersion", appVersion, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ public class InitialSecuritySetup {
|
|||||||
initializeAdminUser();
|
initializeAdminUser();
|
||||||
} else {
|
} else {
|
||||||
databaseBackupHelper.exportDatabase();
|
databaseBackupHelper.exportDatabase();
|
||||||
|
userService.migrateOauth2ToSSO();
|
||||||
}
|
}
|
||||||
initializeInternalApiUser();
|
initializeInternalApiUser();
|
||||||
}
|
}
|
||||||
@@ -74,5 +75,6 @@ public class InitialSecuritySetup {
|
|||||||
userService.addApiKeyToUser(Role.INTERNAL_API_USER.getRoleId());
|
userService.addApiKeyToUser(Role.INTERNAL_API_USER.getRoleId());
|
||||||
log.info("Internal API user created: " + Role.INTERNAL_API_USER.getRoleId());
|
log.info("Internal API user created: " + Role.INTERNAL_API_USER.getRoleId());
|
||||||
}
|
}
|
||||||
|
userService.syncCustomApiUser(applicationProperties.getSecurity().getCustomGlobalAPIKey());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,14 +3,16 @@ package stirling.software.SPDF.config.security;
|
|||||||
import java.security.cert.X509Certificate;
|
import java.security.cert.X509Certificate;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
|
import org.opensaml.saml.saml2.core.AuthnRequest;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.beans.factory.annotation.Qualifier;
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.DependsOn;
|
||||||
import org.springframework.context.annotation.Lazy;
|
import org.springframework.context.annotation.Lazy;
|
||||||
import org.springframework.core.io.Resource;
|
import org.springframework.core.io.Resource;
|
||||||
import org.springframework.security.authentication.AuthenticationProvider;
|
import org.springframework.security.authentication.ProviderManager;
|
||||||
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
|
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
|
||||||
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
|
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||||
@@ -32,7 +34,8 @@ import org.springframework.security.saml2.provider.service.authentication.OpenSa
|
|||||||
import org.springframework.security.saml2.provider.service.registration.InMemoryRelyingPartyRegistrationRepository;
|
import org.springframework.security.saml2.provider.service.registration.InMemoryRelyingPartyRegistrationRepository;
|
||||||
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration;
|
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration;
|
||||||
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository;
|
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository;
|
||||||
import org.springframework.security.saml2.provider.service.web.authentication.Saml2WebSsoAuthenticationFilter;
|
import org.springframework.security.saml2.provider.service.registration.Saml2MessageBinding;
|
||||||
|
import org.springframework.security.saml2.provider.service.web.authentication.OpenSaml4AuthenticationRequestResolver;
|
||||||
import org.springframework.security.web.SecurityFilterChain;
|
import org.springframework.security.web.SecurityFilterChain;
|
||||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||||
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
|
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
|
||||||
@@ -41,6 +44,7 @@ import org.springframework.security.web.csrf.CsrfTokenRequestAttributeHandler;
|
|||||||
import org.springframework.security.web.savedrequest.NullRequestCache;
|
import org.springframework.security.web.savedrequest.NullRequestCache;
|
||||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||||
|
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import stirling.software.SPDF.config.security.oauth2.CustomOAuth2AuthenticationFailureHandler;
|
import stirling.software.SPDF.config.security.oauth2.CustomOAuth2AuthenticationFailureHandler;
|
||||||
import stirling.software.SPDF.config.security.oauth2.CustomOAuth2AuthenticationSuccessHandler;
|
import stirling.software.SPDF.config.security.oauth2.CustomOAuth2AuthenticationSuccessHandler;
|
||||||
@@ -64,6 +68,7 @@ import stirling.software.SPDF.repository.JPATokenRepositoryImpl;
|
|||||||
@EnableWebSecurity
|
@EnableWebSecurity
|
||||||
@EnableMethodSecurity
|
@EnableMethodSecurity
|
||||||
@Slf4j
|
@Slf4j
|
||||||
|
@DependsOn("runningEE")
|
||||||
public class SecurityConfiguration {
|
public class SecurityConfiguration {
|
||||||
|
|
||||||
@Autowired private CustomUserDetailsService userDetailsService;
|
@Autowired private CustomUserDetailsService userDetailsService;
|
||||||
@@ -79,6 +84,10 @@ public class SecurityConfiguration {
|
|||||||
@Qualifier("loginEnabled")
|
@Qualifier("loginEnabled")
|
||||||
public boolean loginEnabledValue;
|
public boolean loginEnabledValue;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
@Qualifier("runningEE")
|
||||||
|
public boolean runningEE;
|
||||||
|
|
||||||
@Autowired ApplicationProperties applicationProperties;
|
@Autowired ApplicationProperties applicationProperties;
|
||||||
|
|
||||||
@Autowired private UserAuthenticationFilter userAuthenticationFilter;
|
@Autowired private UserAuthenticationFilter userAuthenticationFilter;
|
||||||
@@ -90,13 +99,14 @@ public class SecurityConfiguration {
|
|||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||||
|
if (applicationProperties.getSecurity().getCsrfDisabled() || !loginEnabledValue) {
|
||||||
|
http.csrf(csrf -> csrf.disable());
|
||||||
|
}
|
||||||
|
|
||||||
if (loginEnabledValue) {
|
if (loginEnabledValue) {
|
||||||
http.addFilterBefore(
|
http.addFilterBefore(
|
||||||
userAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
|
userAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
|
||||||
if (applicationProperties.getSecurity().getCsrfDisabled()) {
|
if (!applicationProperties.getSecurity().getCsrfDisabled()) {
|
||||||
http.csrf(csrf -> csrf.disable());
|
|
||||||
} else {
|
|
||||||
CookieCsrfTokenRepository cookieRepo =
|
CookieCsrfTokenRepository cookieRepo =
|
||||||
CookieCsrfTokenRepository.withHttpOnlyFalse();
|
CookieCsrfTokenRepository.withHttpOnlyFalse();
|
||||||
CsrfTokenRequestAttributeHandler requestHandler =
|
CsrfTokenRequestAttributeHandler requestHandler =
|
||||||
@@ -106,7 +116,7 @@ public class SecurityConfiguration {
|
|||||||
csrf ->
|
csrf ->
|
||||||
csrf.ignoringRequestMatchers(
|
csrf.ignoringRequestMatchers(
|
||||||
request -> {
|
request -> {
|
||||||
String apiKey = request.getHeader("X-API-Key");
|
String apiKey = request.getHeader("X-API-KEY");
|
||||||
|
|
||||||
// If there's no API key, don't ignore CSRF
|
// If there's no API key, don't ignore CSRF
|
||||||
// (return false)
|
// (return false)
|
||||||
@@ -245,12 +255,22 @@ public class SecurityConfiguration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Handle SAML
|
// Handle SAML
|
||||||
if (applicationProperties.getSecurity().isSaml2Activ()
|
if (applicationProperties.getSecurity().isSaml2Activ()) { // && runningEE
|
||||||
&& applicationProperties.getSystem().getEnableAlphaFunctionality()) {
|
// Configure the authentication provider
|
||||||
http.authenticationProvider(samlAuthenticationProvider());
|
OpenSaml4AuthenticationProvider authenticationProvider =
|
||||||
http.saml2Login(
|
new OpenSaml4AuthenticationProvider();
|
||||||
saml2 ->
|
authenticationProvider.setResponseAuthenticationConverter(
|
||||||
|
new CustomSaml2ResponseAuthenticationConverter(userService));
|
||||||
|
|
||||||
|
http.authenticationProvider(authenticationProvider)
|
||||||
|
.saml2Login(
|
||||||
|
saml2 -> {
|
||||||
|
try {
|
||||||
saml2.loginPage("/saml2")
|
saml2.loginPage("/saml2")
|
||||||
|
.relyingPartyRegistrationRepository(
|
||||||
|
relyingPartyRegistrations())
|
||||||
|
.authenticationManager(
|
||||||
|
new ProviderManager(authenticationProvider))
|
||||||
.successHandler(
|
.successHandler(
|
||||||
new CustomSaml2AuthenticationSuccessHandler(
|
new CustomSaml2AuthenticationSuccessHandler(
|
||||||
loginAttemptService,
|
loginAttemptService,
|
||||||
@@ -258,44 +278,34 @@ public class SecurityConfiguration {
|
|||||||
userService))
|
userService))
|
||||||
.failureHandler(
|
.failureHandler(
|
||||||
new CustomSaml2AuthenticationFailureHandler())
|
new CustomSaml2AuthenticationFailureHandler())
|
||||||
.permitAll())
|
.authenticationRequestResolver(
|
||||||
.addFilterBefore(
|
authenticationRequestResolver(
|
||||||
userAuthenticationFilter, Saml2WebSsoAuthenticationFilter.class);
|
relyingPartyRegistrations()));
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Error configuring SAML2 login", e);
|
||||||
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
} 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));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// if (!applicationProperties.getSecurity().getCsrfDisabled()) {
|
||||||
|
// 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());
|
http.authorizeHttpRequests(authz -> authz.anyRequest().permitAll());
|
||||||
}
|
}
|
||||||
|
|
||||||
return http.build();
|
return http.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
|
||||||
@ConditionalOnProperty(
|
|
||||||
name = "security.saml2.enabled",
|
|
||||||
havingValue = "true",
|
|
||||||
matchIfMissing = false)
|
|
||||||
public AuthenticationProvider samlAuthenticationProvider() {
|
|
||||||
OpenSaml4AuthenticationProvider authenticationProvider =
|
|
||||||
new OpenSaml4AuthenticationProvider();
|
|
||||||
authenticationProvider.setResponseAuthenticationConverter(
|
|
||||||
new CustomSaml2ResponseAuthenticationConverter(userService));
|
|
||||||
return authenticationProvider;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Client Registration Repository for OAUTH2 OIDC Login
|
|
||||||
@Bean
|
@Bean
|
||||||
@ConditionalOnProperty(
|
@ConditionalOnProperty(
|
||||||
value = "security.oauth2.enabled",
|
value = "security.oauth2.enabled",
|
||||||
@@ -432,11 +442,12 @@ public class SecurityConfiguration {
|
|||||||
havingValue = "true",
|
havingValue = "true",
|
||||||
matchIfMissing = false)
|
matchIfMissing = false)
|
||||||
public RelyingPartyRegistrationRepository relyingPartyRegistrations() throws Exception {
|
public RelyingPartyRegistrationRepository relyingPartyRegistrations() throws Exception {
|
||||||
|
|
||||||
SAML2 samlConf = applicationProperties.getSecurity().getSaml2();
|
SAML2 samlConf = applicationProperties.getSecurity().getSaml2();
|
||||||
|
|
||||||
Resource privateKeyResource = samlConf.getPrivateKey();
|
X509Certificate idpCert = CertificateUtils.readCertificate(samlConf.getidpCert());
|
||||||
|
Saml2X509Credential verificationCredential = Saml2X509Credential.verification(idpCert);
|
||||||
|
|
||||||
|
Resource privateKeyResource = samlConf.getPrivateKey();
|
||||||
Resource certificateResource = samlConf.getSpCert();
|
Resource certificateResource = samlConf.getSpCert();
|
||||||
|
|
||||||
Saml2X509Credential signingCredential =
|
Saml2X509Credential signingCredential =
|
||||||
@@ -445,26 +456,97 @@ public class SecurityConfiguration {
|
|||||||
CertificateUtils.readCertificate(certificateResource),
|
CertificateUtils.readCertificate(certificateResource),
|
||||||
Saml2X509CredentialType.SIGNING);
|
Saml2X509CredentialType.SIGNING);
|
||||||
|
|
||||||
X509Certificate idpCert = CertificateUtils.readCertificate(samlConf.getidpCert());
|
|
||||||
|
|
||||||
Saml2X509Credential verificationCredential = Saml2X509Credential.verification(idpCert);
|
|
||||||
|
|
||||||
RelyingPartyRegistration rp =
|
RelyingPartyRegistration rp =
|
||||||
RelyingPartyRegistration.withRegistrationId(samlConf.getRegistrationId())
|
RelyingPartyRegistration.withRegistrationId(samlConf.getRegistrationId())
|
||||||
.signingX509Credentials((c) -> c.add(signingCredential))
|
.signingX509Credentials(c -> c.add(signingCredential))
|
||||||
.assertingPartyMetadata(
|
.assertingPartyMetadata(
|
||||||
(details) ->
|
metadata ->
|
||||||
details.entityId(samlConf.getIdpIssuer())
|
metadata.entityId(samlConf.getIdpIssuer())
|
||||||
.singleSignOnServiceLocation(
|
.singleSignOnServiceLocation(
|
||||||
samlConf.getIdpSingleLoginUrl())
|
samlConf.getIdpSingleLoginUrl())
|
||||||
.verificationX509Credentials(
|
.verificationX509Credentials(
|
||||||
(c) -> c.add(verificationCredential))
|
c -> c.add(verificationCredential))
|
||||||
|
.singleSignOnServiceBinding(
|
||||||
|
Saml2MessageBinding.POST)
|
||||||
.wantAuthnRequestsSigned(true))
|
.wantAuthnRequestsSigned(true))
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
return new InMemoryRelyingPartyRegistrationRepository(rp);
|
return new InMemoryRelyingPartyRegistrationRepository(rp);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
|
@ConditionalOnProperty(
|
||||||
|
name = "security.saml2.enabled",
|
||||||
|
havingValue = "true",
|
||||||
|
matchIfMissing = false)
|
||||||
|
public OpenSaml4AuthenticationRequestResolver authenticationRequestResolver(
|
||||||
|
RelyingPartyRegistrationRepository relyingPartyRegistrationRepository) {
|
||||||
|
OpenSaml4AuthenticationRequestResolver resolver =
|
||||||
|
new OpenSaml4AuthenticationRequestResolver(relyingPartyRegistrationRepository);
|
||||||
|
resolver.setAuthnRequestCustomizer(
|
||||||
|
customizer -> {
|
||||||
|
log.debug("Customizing SAML Authentication request");
|
||||||
|
|
||||||
|
AuthnRequest authnRequest = customizer.getAuthnRequest();
|
||||||
|
log.debug("AuthnRequest ID: {}", authnRequest.getID());
|
||||||
|
|
||||||
|
if (authnRequest.getID() == null) {
|
||||||
|
authnRequest.setID("ARQ" + UUID.randomUUID().toString());
|
||||||
|
}
|
||||||
|
log.debug("AuthnRequest new ID after set: {}", authnRequest.getID());
|
||||||
|
log.debug("AuthnRequest IssueInstant: {}", authnRequest.getIssueInstant());
|
||||||
|
log.debug(
|
||||||
|
"AuthnRequest Issuer: {}",
|
||||||
|
authnRequest.getIssuer() != null
|
||||||
|
? authnRequest.getIssuer().getValue()
|
||||||
|
: "null");
|
||||||
|
|
||||||
|
HttpServletRequest request = customizer.getRequest();
|
||||||
|
|
||||||
|
// Log HTTP request details
|
||||||
|
log.debug("HTTP Request Method: {}", request.getMethod());
|
||||||
|
log.debug("Request URI: {}", request.getRequestURI());
|
||||||
|
log.debug("Request URL: {}", request.getRequestURL().toString());
|
||||||
|
log.debug("Query String: {}", request.getQueryString());
|
||||||
|
log.debug("Remote Address: {}", request.getRemoteAddr());
|
||||||
|
|
||||||
|
// Log headers
|
||||||
|
Collections.list(request.getHeaderNames())
|
||||||
|
.forEach(
|
||||||
|
headerName -> {
|
||||||
|
log.debug(
|
||||||
|
"Header - {}: {}",
|
||||||
|
headerName,
|
||||||
|
request.getHeader(headerName));
|
||||||
|
});
|
||||||
|
|
||||||
|
// Log SAML specific parameters
|
||||||
|
log.debug("SAML Request Parameters:");
|
||||||
|
log.debug("SAMLRequest: {}", request.getParameter("SAMLRequest"));
|
||||||
|
log.debug("RelayState: {}", request.getParameter("RelayState"));
|
||||||
|
|
||||||
|
// Log session debugrmation if exists
|
||||||
|
if (request.getSession(false) != null) {
|
||||||
|
log.debug("Session ID: {}", request.getSession().getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Log any assertions consumer service details if present
|
||||||
|
if (authnRequest.getAssertionConsumerServiceURL() != null) {
|
||||||
|
log.debug(
|
||||||
|
"AssertionConsumerServiceURL: {}",
|
||||||
|
authnRequest.getAssertionConsumerServiceURL());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Log NameID policy if present
|
||||||
|
if (authnRequest.getNameIDPolicy() != null) {
|
||||||
|
log.debug(
|
||||||
|
"NameIDPolicy Format: {}",
|
||||||
|
authnRequest.getNameIDPolicy().getFormat());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return resolver;
|
||||||
|
}
|
||||||
|
|
||||||
public DaoAuthenticationProvider daoAuthenticationProvider() {
|
public DaoAuthenticationProvider daoAuthenticationProvider() {
|
||||||
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
|
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
|
||||||
provider.setUserDetailsService(userDetailsService);
|
provider.setUserDetailsService(userDetailsService);
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ public class UserAuthenticationFilter extends OncePerRequestFilter {
|
|||||||
|
|
||||||
// Check for API key in the request headers if no authentication exists
|
// Check for API key in the request headers if no authentication exists
|
||||||
if (authentication == null || !authentication.isAuthenticated()) {
|
if (authentication == null || !authentication.isAuthenticated()) {
|
||||||
String apiKey = request.getHeader("X-API-Key");
|
String apiKey = request.getHeader("X-API-KEY");
|
||||||
if (apiKey != null && !apiKey.trim().isEmpty()) {
|
if (apiKey != null && !apiKey.trim().isEmpty()) {
|
||||||
try {
|
try {
|
||||||
// Use API key to authenticate. This requires you to have an authentication
|
// Use API key to authenticate. This requires you to have an authentication
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ public class UserBasedRateLimitingFilter extends OncePerRequestFilter {
|
|||||||
String identifier = null;
|
String identifier = null;
|
||||||
|
|
||||||
// Check for API key in the request headers
|
// Check for API key in the request headers
|
||||||
String apiKey = request.getHeader("X-API-Key");
|
String apiKey = request.getHeader("X-API-KEY");
|
||||||
if (apiKey != null && !apiKey.trim().isEmpty()) {
|
if (apiKey != null && !apiKey.trim().isEmpty()) {
|
||||||
identifier =
|
identifier =
|
||||||
"API_KEY_" + apiKey; // Prefix to distinguish between API keys and usernames
|
"API_KEY_" + apiKey; // Prefix to distinguish between API keys and usernames
|
||||||
@@ -79,7 +79,7 @@ public class UserBasedRateLimitingFilter extends OncePerRequestFilter {
|
|||||||
Role userRole =
|
Role userRole =
|
||||||
getRoleFromAuthentication(SecurityContextHolder.getContext().getAuthentication());
|
getRoleFromAuthentication(SecurityContextHolder.getContext().getAuthentication());
|
||||||
|
|
||||||
if (request.getHeader("X-API-Key") != null) {
|
if (request.getHeader("X-API-KEY") != null) {
|
||||||
// It's an API call
|
// It's an API call
|
||||||
processRequest(
|
processRequest(
|
||||||
userRole.getApiCallsPerDay(),
|
userRole.getApiCallsPerDay(),
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
|||||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
import org.springframework.security.oauth2.core.user.OAuth2User;
|
import org.springframework.security.oauth2.core.user.OAuth2User;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import stirling.software.SPDF.config.interfaces.DatabaseBackupInterface;
|
import stirling.software.SPDF.config.interfaces.DatabaseBackupInterface;
|
||||||
@@ -50,8 +51,19 @@ public class UserService implements UserServiceInterface {
|
|||||||
|
|
||||||
@Autowired ApplicationProperties applicationProperties;
|
@Autowired ApplicationProperties applicationProperties;
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public void migrateOauth2ToSSO() {
|
||||||
|
userRepository
|
||||||
|
.findByAuthenticationTypeIgnoreCase("OAUTH2")
|
||||||
|
.forEach(
|
||||||
|
user -> {
|
||||||
|
user.setAuthenticationType(AuthenticationType.SSO);
|
||||||
|
userRepository.save(user);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Handle OAUTH2 login and user auto creation.
|
// Handle OAUTH2 login and user auto creation.
|
||||||
public boolean processOAuth2PostLogin(String username, boolean autoCreateUser)
|
public boolean processSSOPostLogin(String username, boolean autoCreateUser)
|
||||||
throws IllegalArgumentException, IOException {
|
throws IllegalArgumentException, IOException {
|
||||||
if (!isUsernameValid(username)) {
|
if (!isUsernameValid(username)) {
|
||||||
return false;
|
return false;
|
||||||
@@ -61,7 +73,7 @@ public class UserService implements UserServiceInterface {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (autoCreateUser) {
|
if (autoCreateUser) {
|
||||||
saveUser(username, AuthenticationType.OAUTH2);
|
saveUser(username, AuthenticationType.SSO);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -378,6 +390,37 @@ public class UserService implements UserServiceInterface {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public void syncCustomApiUser(String customApiKey) throws IOException {
|
||||||
|
if (customApiKey == null || customApiKey.trim().length() == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String username = "CUSTOM_API_USER";
|
||||||
|
Optional<User> existingUser = findByUsernameIgnoreCase(username);
|
||||||
|
|
||||||
|
if (!existingUser.isPresent()) {
|
||||||
|
// Create new user with API role
|
||||||
|
User user = new User();
|
||||||
|
user.setUsername(username);
|
||||||
|
user.setPassword(UUID.randomUUID().toString());
|
||||||
|
user.setEnabled(true);
|
||||||
|
user.setFirstLogin(false);
|
||||||
|
user.setAuthenticationType(AuthenticationType.WEB);
|
||||||
|
user.setApiKey(customApiKey);
|
||||||
|
user.addAuthority(new Authority(Role.INTERNAL_API_USER.getRoleId(), user));
|
||||||
|
userRepository.save(user);
|
||||||
|
databaseBackupHelper.exportDatabase();
|
||||||
|
} else {
|
||||||
|
// Update API key if it has changed
|
||||||
|
User user = existingUser.get();
|
||||||
|
if (!customApiKey.equals(user.getApiKey())) {
|
||||||
|
user.setApiKey(customApiKey);
|
||||||
|
userRepository.save(user);
|
||||||
|
databaseBackupHelper.exportDatabase();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getTotalUsersCount() {
|
public long getTotalUsersCount() {
|
||||||
return userRepository.count();
|
return userRepository.count();
|
||||||
|
|||||||
@@ -82,8 +82,7 @@ public class CustomOAuth2AuthenticationSuccessHandler
|
|||||||
}
|
}
|
||||||
if (userService.usernameExistsIgnoreCase(username)
|
if (userService.usernameExistsIgnoreCase(username)
|
||||||
&& userService.hasPassword(username)
|
&& userService.hasPassword(username)
|
||||||
&& !userService.isAuthenticationTypeByUsername(
|
&& !userService.isAuthenticationTypeByUsername(username, AuthenticationType.SSO)
|
||||||
username, AuthenticationType.OAUTH2)
|
|
||||||
&& oAuth.getAutoCreateUser()) {
|
&& oAuth.getAutoCreateUser()) {
|
||||||
response.sendRedirect(contextPath + "/logout?oauth2AuthenticationErrorWeb=true");
|
response.sendRedirect(contextPath + "/logout?oauth2AuthenticationErrorWeb=true");
|
||||||
return;
|
return;
|
||||||
@@ -95,7 +94,7 @@ public class CustomOAuth2AuthenticationSuccessHandler
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (principal instanceof OAuth2User) {
|
if (principal instanceof OAuth2User) {
|
||||||
userService.processOAuth2PostLogin(username, oAuth.getAutoCreateUser());
|
userService.processSSOPostLogin(username, oAuth.getAutoCreateUser());
|
||||||
}
|
}
|
||||||
response.sendRedirect(contextPath + "/");
|
response.sendRedirect(contextPath + "/");
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -3,12 +3,14 @@ package stirling.software.SPDF.config.security.saml2;
|
|||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.security.KeyFactory;
|
|
||||||
import java.security.cert.CertificateFactory;
|
import java.security.cert.CertificateFactory;
|
||||||
import java.security.cert.X509Certificate;
|
import java.security.cert.X509Certificate;
|
||||||
import java.security.interfaces.RSAPrivateKey;
|
import java.security.interfaces.RSAPrivateKey;
|
||||||
import java.security.spec.PKCS8EncodedKeySpec;
|
|
||||||
|
|
||||||
|
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
|
||||||
|
import org.bouncycastle.openssl.PEMKeyPair;
|
||||||
|
import org.bouncycastle.openssl.PEMParser;
|
||||||
|
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
|
||||||
import org.bouncycastle.util.io.pem.PemObject;
|
import org.bouncycastle.util.io.pem.PemObject;
|
||||||
import org.bouncycastle.util.io.pem.PemReader;
|
import org.bouncycastle.util.io.pem.PemReader;
|
||||||
import org.springframework.core.io.Resource;
|
import org.springframework.core.io.Resource;
|
||||||
@@ -28,15 +30,26 @@ public class CertificateUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static RSAPrivateKey readPrivateKey(Resource privateKeyResource) throws Exception {
|
public static RSAPrivateKey readPrivateKey(Resource privateKeyResource) throws Exception {
|
||||||
try (PemReader pemReader =
|
try (PEMParser pemParser =
|
||||||
new PemReader(
|
new PEMParser(
|
||||||
new InputStreamReader(
|
new InputStreamReader(
|
||||||
privateKeyResource.getInputStream(), StandardCharsets.UTF_8))) {
|
privateKeyResource.getInputStream(), StandardCharsets.UTF_8))) {
|
||||||
PemObject pemObject = pemReader.readPemObject();
|
|
||||||
byte[] decodedKey = pemObject.getContent();
|
Object object = pemParser.readObject();
|
||||||
return (RSAPrivateKey)
|
JcaPEMKeyConverter converter = new JcaPEMKeyConverter();
|
||||||
KeyFactory.getInstance("RSA")
|
|
||||||
.generatePrivate(new PKCS8EncodedKeySpec(decodedKey));
|
if (object instanceof PEMKeyPair) {
|
||||||
|
// Handle traditional RSA private key format
|
||||||
|
PEMKeyPair keypair = (PEMKeyPair) object;
|
||||||
|
return (RSAPrivateKey) converter.getPrivateKey(keypair.getPrivateKeyInfo());
|
||||||
|
} else if (object instanceof PrivateKeyInfo) {
|
||||||
|
// Handle PKCS#8 format
|
||||||
|
return (RSAPrivateKey) converter.getPrivateKey((PrivateKeyInfo) object);
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"Unsupported key format: "
|
||||||
|
+ (object != null ? object.getClass().getName() : "null"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import jakarta.servlet.http.HttpServletRequest;
|
|||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import jakarta.servlet.http.HttpSession;
|
import jakarta.servlet.http.HttpSession;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import stirling.software.SPDF.config.security.LoginAttemptService;
|
import stirling.software.SPDF.config.security.LoginAttemptService;
|
||||||
import stirling.software.SPDF.config.security.UserService;
|
import stirling.software.SPDF.config.security.UserService;
|
||||||
import stirling.software.SPDF.model.ApplicationProperties;
|
import stirling.software.SPDF.model.ApplicationProperties;
|
||||||
@@ -20,11 +21,11 @@ import stirling.software.SPDF.model.AuthenticationType;
|
|||||||
import stirling.software.SPDF.utils.RequestUriUtils;
|
import stirling.software.SPDF.utils.RequestUriUtils;
|
||||||
|
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
|
@Slf4j
|
||||||
public class CustomSaml2AuthenticationSuccessHandler
|
public class CustomSaml2AuthenticationSuccessHandler
|
||||||
extends SavedRequestAwareAuthenticationSuccessHandler {
|
extends SavedRequestAwareAuthenticationSuccessHandler {
|
||||||
|
|
||||||
private LoginAttemptService loginAttemptService;
|
private LoginAttemptService loginAttemptService;
|
||||||
|
|
||||||
private ApplicationProperties applicationProperties;
|
private ApplicationProperties applicationProperties;
|
||||||
private UserService userService;
|
private UserService userService;
|
||||||
|
|
||||||
@@ -34,10 +35,12 @@ public class CustomSaml2AuthenticationSuccessHandler
|
|||||||
throws ServletException, IOException {
|
throws ServletException, IOException {
|
||||||
|
|
||||||
Object principal = authentication.getPrincipal();
|
Object principal = authentication.getPrincipal();
|
||||||
|
log.debug("Starting SAML2 authentication success handling");
|
||||||
|
|
||||||
if (principal instanceof CustomSaml2AuthenticatedPrincipal) {
|
if (principal instanceof CustomSaml2AuthenticatedPrincipal) {
|
||||||
String username = ((CustomSaml2AuthenticatedPrincipal) principal).getName();
|
String username = ((CustomSaml2AuthenticatedPrincipal) principal).getName();
|
||||||
// Get the saved request
|
log.debug("Authenticated principal found for user: {}", username);
|
||||||
|
|
||||||
HttpSession session = request.getSession(false);
|
HttpSession session = request.getSession(false);
|
||||||
String contextPath = request.getContextPath();
|
String contextPath = request.getContextPath();
|
||||||
SavedRequest savedRequest =
|
SavedRequest savedRequest =
|
||||||
@@ -45,46 +48,77 @@ public class CustomSaml2AuthenticationSuccessHandler
|
|||||||
? (SavedRequest) session.getAttribute("SPRING_SECURITY_SAVED_REQUEST")
|
? (SavedRequest) session.getAttribute("SPRING_SECURITY_SAVED_REQUEST")
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
|
log.debug(
|
||||||
|
"Session exists: {}, Saved request exists: {}",
|
||||||
|
session != null,
|
||||||
|
savedRequest != null);
|
||||||
|
|
||||||
if (savedRequest != null
|
if (savedRequest != null
|
||||||
&& !RequestUriUtils.isStaticResource(
|
&& !RequestUriUtils.isStaticResource(
|
||||||
contextPath, savedRequest.getRedirectUrl())) {
|
contextPath, savedRequest.getRedirectUrl())) {
|
||||||
// Redirect to the original destination
|
log.debug(
|
||||||
|
"Valid saved request found, redirecting to original destination: {}",
|
||||||
|
savedRequest.getRedirectUrl());
|
||||||
super.onAuthenticationSuccess(request, response, authentication);
|
super.onAuthenticationSuccess(request, response, authentication);
|
||||||
} else {
|
} else {
|
||||||
SAML2 saml2 = applicationProperties.getSecurity().getSaml2();
|
SAML2 saml2 = applicationProperties.getSecurity().getSaml2();
|
||||||
|
log.debug(
|
||||||
|
"Processing SAML2 authentication with autoCreateUser: {}",
|
||||||
|
saml2.getAutoCreateUser());
|
||||||
|
|
||||||
if (loginAttemptService.isBlocked(username)) {
|
if (loginAttemptService.isBlocked(username)) {
|
||||||
|
log.debug("User {} is blocked due to too many login attempts", username);
|
||||||
if (session != null) {
|
if (session != null) {
|
||||||
session.removeAttribute("SPRING_SECURITY_SAVED_REQUEST");
|
session.removeAttribute("SPRING_SECURITY_SAVED_REQUEST");
|
||||||
}
|
}
|
||||||
throw new LockedException(
|
throw new LockedException(
|
||||||
"Your account has been locked due to too many failed login attempts.");
|
"Your account has been locked due to too many failed login attempts.");
|
||||||
}
|
}
|
||||||
if (userService.usernameExistsIgnoreCase(username)
|
|
||||||
&& userService.hasPassword(username)
|
boolean userExists = userService.usernameExistsIgnoreCase(username);
|
||||||
&& !userService.isAuthenticationTypeByUsername(
|
boolean hasPassword = userExists && userService.hasPassword(username);
|
||||||
username, AuthenticationType.OAUTH2)
|
boolean isSSOUser =
|
||||||
&& saml2.getAutoCreateUser()) {
|
userExists
|
||||||
|
&& userService.isAuthenticationTypeByUsername(
|
||||||
|
username, AuthenticationType.SSO);
|
||||||
|
|
||||||
|
log.debug(
|
||||||
|
"User status - Exists: {}, Has password: {}, Is SSO user: {}",
|
||||||
|
userExists,
|
||||||
|
hasPassword,
|
||||||
|
isSSOUser);
|
||||||
|
|
||||||
|
if (userExists && hasPassword && !isSSOUser && saml2.getAutoCreateUser()) {
|
||||||
|
log.debug(
|
||||||
|
"User {} exists with password but is not SSO user, redirecting to logout",
|
||||||
|
username);
|
||||||
response.sendRedirect(
|
response.sendRedirect(
|
||||||
contextPath + "/logout?oauth2AuthenticationErrorWeb=true");
|
contextPath + "/logout?oauth2AuthenticationErrorWeb=true");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (saml2.getBlockRegistration()
|
if (saml2.getBlockRegistration() && !userExists) {
|
||||||
&& !userService.usernameExistsIgnoreCase(username)) {
|
log.debug("Registration blocked for new user: {}", username);
|
||||||
response.sendRedirect(
|
response.sendRedirect(
|
||||||
contextPath + "/login?erroroauth=oauth2_admin_blocked_user");
|
contextPath + "/login?erroroauth=oauth2_admin_blocked_user");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
userService.processOAuth2PostLogin(username, saml2.getAutoCreateUser());
|
log.debug("Processing SSO post-login for user: {}", username);
|
||||||
|
userService.processSSOPostLogin(username, saml2.getAutoCreateUser());
|
||||||
|
log.debug("Successfully processed authentication for user: {}", username);
|
||||||
response.sendRedirect(contextPath + "/");
|
response.sendRedirect(contextPath + "/");
|
||||||
return;
|
return;
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
|
log.debug(
|
||||||
|
"Invalid username detected for user: {}, redirecting to logout",
|
||||||
|
username);
|
||||||
response.sendRedirect(contextPath + "/logout?invalidUsername=true");
|
response.sendRedirect(contextPath + "/logout?invalidUsername=true");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
log.debug("Non-SAML2 principal detected, delegating to parent handler");
|
||||||
super.onAuthenticationSuccess(request, response, authentication);
|
super.onAuthenticationSuccess(request, response, authentication);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,8 +3,6 @@ package stirling.software.SPDF.config.security.saml2;
|
|||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import org.opensaml.core.xml.XMLObject;
|
import org.opensaml.core.xml.XMLObject;
|
||||||
import org.opensaml.core.xml.schema.XSBoolean;
|
|
||||||
import org.opensaml.core.xml.schema.XSString;
|
|
||||||
import org.opensaml.saml.saml2.core.Assertion;
|
import org.opensaml.saml.saml2.core.Assertion;
|
||||||
import org.opensaml.saml.saml2.core.Attribute;
|
import org.opensaml.saml.saml2.core.Attribute;
|
||||||
import org.opensaml.saml.saml2.core.AttributeStatement;
|
import org.opensaml.saml.saml2.core.AttributeStatement;
|
||||||
@@ -30,15 +28,60 @@ public class CustomSaml2ResponseAuthenticationConverter
|
|||||||
this.userService = userService;
|
this.userService = userService;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Map<String, List<Object>> extractAttributes(Assertion assertion) {
|
||||||
|
Map<String, List<Object>> attributes = new HashMap<>();
|
||||||
|
|
||||||
|
for (AttributeStatement attributeStatement : assertion.getAttributeStatements()) {
|
||||||
|
for (Attribute attribute : attributeStatement.getAttributes()) {
|
||||||
|
String attributeName = attribute.getName();
|
||||||
|
List<Object> values = new ArrayList<>();
|
||||||
|
|
||||||
|
for (XMLObject xmlObject : attribute.getAttributeValues()) {
|
||||||
|
// Get the text content directly
|
||||||
|
String value = xmlObject.getDOM().getTextContent();
|
||||||
|
if (value != null && !value.trim().isEmpty()) {
|
||||||
|
values.add(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!values.isEmpty()) {
|
||||||
|
// Store with both full URI and last part of the URI
|
||||||
|
attributes.put(attributeName, values);
|
||||||
|
String shortName = attributeName.substring(attributeName.lastIndexOf('/') + 1);
|
||||||
|
attributes.put(shortName, values);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return attributes;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Saml2Authentication convert(ResponseToken responseToken) {
|
public Saml2Authentication convert(ResponseToken responseToken) {
|
||||||
// Extract the assertion from the response
|
|
||||||
Assertion assertion = responseToken.getResponse().getAssertions().get(0);
|
Assertion assertion = responseToken.getResponse().getAssertions().get(0);
|
||||||
|
Map<String, List<Object>> attributes = extractAttributes(assertion);
|
||||||
|
|
||||||
// Extract the NameID
|
// Debug log with actual values
|
||||||
String nameId = assertion.getSubject().getNameID().getValue();
|
log.debug("Extracted SAML Attributes: " + attributes);
|
||||||
|
|
||||||
Optional<User> userOpt = userService.findByUsernameIgnoreCase(nameId);
|
// Try to get username/identifier in order of preference
|
||||||
|
String userIdentifier = null;
|
||||||
|
if (hasAttribute(attributes, "username")) {
|
||||||
|
userIdentifier = getFirstAttributeValue(attributes, "username");
|
||||||
|
} else if (hasAttribute(attributes, "emailaddress")) {
|
||||||
|
userIdentifier = getFirstAttributeValue(attributes, "emailaddress");
|
||||||
|
} else if (hasAttribute(attributes, "name")) {
|
||||||
|
userIdentifier = getFirstAttributeValue(attributes, "name");
|
||||||
|
} else if (hasAttribute(attributes, "upn")) {
|
||||||
|
userIdentifier = getFirstAttributeValue(attributes, "upn");
|
||||||
|
} else if (hasAttribute(attributes, "uid")) {
|
||||||
|
userIdentifier = getFirstAttributeValue(attributes, "uid");
|
||||||
|
} else {
|
||||||
|
userIdentifier = assertion.getSubject().getNameID().getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rest of your existing code...
|
||||||
|
Optional<User> userOpt = userService.findByUsernameIgnoreCase(userIdentifier);
|
||||||
SimpleGrantedAuthority simpleGrantedAuthority = new SimpleGrantedAuthority("ROLE_USER");
|
SimpleGrantedAuthority simpleGrantedAuthority = new SimpleGrantedAuthority("ROLE_USER");
|
||||||
if (userOpt.isPresent()) {
|
if (userOpt.isPresent()) {
|
||||||
User user = userOpt.get();
|
User user = userOpt.get();
|
||||||
@@ -48,39 +91,27 @@ public class CustomSaml2ResponseAuthenticationConverter
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract the SessionIndexes
|
|
||||||
List<String> sessionIndexes = new ArrayList<>();
|
List<String> sessionIndexes = new ArrayList<>();
|
||||||
for (AuthnStatement authnStatement : assertion.getAuthnStatements()) {
|
for (AuthnStatement authnStatement : assertion.getAuthnStatements()) {
|
||||||
sessionIndexes.add(authnStatement.getSessionIndex());
|
sessionIndexes.add(authnStatement.getSessionIndex());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract the Attributes
|
|
||||||
Map<String, List<Object>> attributes = extractAttributes(assertion);
|
|
||||||
|
|
||||||
// Create the custom principal
|
|
||||||
CustomSaml2AuthenticatedPrincipal principal =
|
CustomSaml2AuthenticatedPrincipal principal =
|
||||||
new CustomSaml2AuthenticatedPrincipal(nameId, attributes, nameId, sessionIndexes);
|
new CustomSaml2AuthenticatedPrincipal(
|
||||||
|
userIdentifier, attributes, userIdentifier, sessionIndexes);
|
||||||
|
|
||||||
// Create the Saml2Authentication
|
|
||||||
return new Saml2Authentication(
|
return new Saml2Authentication(
|
||||||
principal,
|
principal,
|
||||||
responseToken.getToken().getSaml2Response(),
|
responseToken.getToken().getSaml2Response(),
|
||||||
Collections.singletonList(simpleGrantedAuthority));
|
Collections.singletonList(simpleGrantedAuthority));
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<String, List<Object>> extractAttributes(Assertion assertion) {
|
private boolean hasAttribute(Map<String, List<Object>> attributes, String name) {
|
||||||
Map<String, List<Object>> attributes = new HashMap<>();
|
return attributes.containsKey(name) && !attributes.get(name).isEmpty();
|
||||||
for (AttributeStatement attributeStatement : assertion.getAttributeStatements()) {
|
|
||||||
for (Attribute attribute : attributeStatement.getAttributes()) {
|
|
||||||
String attributeName = attribute.getName();
|
|
||||||
List<Object> values = new ArrayList<>();
|
|
||||||
for (XMLObject xmlObject : attribute.getAttributeValues()) {
|
|
||||||
log.info("BOOL: " + ((XSBoolean) xmlObject).getValue());
|
|
||||||
values.add(((XSString) xmlObject).getValue());
|
|
||||||
}
|
}
|
||||||
attributes.put(attributeName, values);
|
|
||||||
}
|
private String getFirstAttributeValue(Map<String, List<Object>> attributes, String name) {
|
||||||
}
|
List<Object> values = attributes.get(name);
|
||||||
return attributes;
|
return values != null && !values.isEmpty() ? values.get(0).toString() : null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,11 +52,18 @@ public class SplitPDFController {
|
|||||||
"This endpoint splits a given PDF file into separate documents based on the specified page numbers or ranges. Users can specify pages using individual numbers, ranges, or 'all' for every page. Input:PDF Output:PDF Type:SIMO")
|
"This endpoint splits a given PDF file into separate documents based on the specified page numbers or ranges. Users can specify pages using individual numbers, ranges, or 'all' for every page. Input:PDF Output:PDF Type:SIMO")
|
||||||
public ResponseEntity<byte[]> splitPdf(@ModelAttribute PDFWithPageNums request)
|
public ResponseEntity<byte[]> splitPdf(@ModelAttribute PDFWithPageNums request)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
|
|
||||||
|
PDDocument document = null;
|
||||||
|
Path zipFile = null;
|
||||||
|
List<ByteArrayOutputStream> splitDocumentsBoas = new ArrayList<>();
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
MultipartFile file = request.getFileInput();
|
MultipartFile file = request.getFileInput();
|
||||||
String pages = request.getPageNumbers();
|
String pages = request.getPageNumbers();
|
||||||
// open the pdf document
|
// open the pdf document
|
||||||
|
|
||||||
PDDocument document = Loader.loadPDF(file.getBytes());
|
document = Loader.loadPDF(file.getBytes());
|
||||||
// PdfMetadata metadata = PdfMetadataService.extractMetadataFromPdf(document);
|
// PdfMetadata metadata = PdfMetadataService.extractMetadataFromPdf(document);
|
||||||
int totalPages = document.getNumberOfPages();
|
int totalPages = document.getNumberOfPages();
|
||||||
List<Integer> pageNumbers = request.getPageNumbersList(document, false);
|
List<Integer> pageNumbers = request.getPageNumbersList(document, false);
|
||||||
@@ -71,7 +78,7 @@ public class SplitPDFController {
|
|||||||
pageNumbers.stream().map(String::valueOf).collect(Collectors.joining(",")));
|
pageNumbers.stream().map(String::valueOf).collect(Collectors.joining(",")));
|
||||||
|
|
||||||
// split the document
|
// split the document
|
||||||
List<ByteArrayOutputStream> splitDocumentsBoas = new ArrayList<>();
|
splitDocumentsBoas = new ArrayList<>();
|
||||||
int previousPageNumber = 0;
|
int previousPageNumber = 0;
|
||||||
for (int splitPoint : pageNumbers) {
|
for (int splitPoint : pageNumbers) {
|
||||||
try (PDDocument splitDocument =
|
try (PDDocument splitDocument =
|
||||||
@@ -99,7 +106,7 @@ public class SplitPDFController {
|
|||||||
// closing the original document
|
// closing the original document
|
||||||
document.close();
|
document.close();
|
||||||
|
|
||||||
Path zipFile = Files.createTempFile("split_documents", ".zip");
|
zipFile = Files.createTempFile("split_documents", ".zip");
|
||||||
|
|
||||||
String filename =
|
String filename =
|
||||||
Filenames.toSimpleFileName(file.getOriginalFilename())
|
Filenames.toSimpleFileName(file.getOriginalFilename())
|
||||||
@@ -124,12 +131,36 @@ public class SplitPDFController {
|
|||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.info("Successfully created zip file with split documents: {}", zipFile.toString());
|
logger.info(
|
||||||
|
"Successfully created zip file with split documents: {}", zipFile.toString());
|
||||||
byte[] data = Files.readAllBytes(zipFile);
|
byte[] data = Files.readAllBytes(zipFile);
|
||||||
Files.deleteIfExists(zipFile);
|
Files.deleteIfExists(zipFile);
|
||||||
|
|
||||||
// return the Resource in the response
|
// return the Resource in the response
|
||||||
return WebResponseUtils.bytesToWebResponse(
|
return WebResponseUtils.bytesToWebResponse(
|
||||||
data, filename + ".zip", MediaType.APPLICATION_OCTET_STREAM);
|
data, filename + ".zip", MediaType.APPLICATION_OCTET_STREAM);
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
// Close the main document
|
||||||
|
if (document != null) {
|
||||||
|
document.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close all ByteArrayOutputStreams
|
||||||
|
for (ByteArrayOutputStream baos : splitDocumentsBoas) {
|
||||||
|
if (baos != null) {
|
||||||
|
baos.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete temporary zip file
|
||||||
|
if (zipFile != null) {
|
||||||
|
Files.deleteIfExists(zipFile);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("Error while cleaning up resources", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,13 +59,17 @@ public class SplitPdfByChaptersController {
|
|||||||
public ResponseEntity<byte[]> splitPdf(@ModelAttribute SplitPdfByChaptersRequest request)
|
public ResponseEntity<byte[]> splitPdf(@ModelAttribute SplitPdfByChaptersRequest request)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
MultipartFile file = request.getFileInput();
|
MultipartFile file = request.getFileInput();
|
||||||
|
PDDocument sourceDocument = null;
|
||||||
|
Path zipFile = null;
|
||||||
|
|
||||||
|
try {
|
||||||
boolean includeMetadata = request.getIncludeMetadata();
|
boolean includeMetadata = request.getIncludeMetadata();
|
||||||
Integer bookmarkLevel =
|
Integer bookmarkLevel =
|
||||||
request.getBookmarkLevel(); // levels start from 0 (top most bookmarks)
|
request.getBookmarkLevel(); // levels start from 0 (top most bookmarks)
|
||||||
if (bookmarkLevel < 0) {
|
if (bookmarkLevel < 0) {
|
||||||
return ResponseEntity.badRequest().body("Invalid bookmark level".getBytes());
|
return ResponseEntity.badRequest().body("Invalid bookmark level".getBytes());
|
||||||
}
|
}
|
||||||
PDDocument sourceDocument = Loader.loadPDF(file.getBytes());
|
sourceDocument = Loader.loadPDF(file.getBytes());
|
||||||
|
|
||||||
PDDocumentOutline outline = sourceDocument.getDocumentCatalog().getDocumentOutline();
|
PDDocumentOutline outline = sourceDocument.getDocumentCatalog().getDocumentOutline();
|
||||||
|
|
||||||
@@ -112,7 +116,7 @@ public class SplitPdfByChaptersController {
|
|||||||
List<ByteArrayOutputStream> splitDocumentsBoas =
|
List<ByteArrayOutputStream> splitDocumentsBoas =
|
||||||
getSplitDocumentsBoas(sourceDocument, bookmarks, includeMetadata);
|
getSplitDocumentsBoas(sourceDocument, bookmarks, includeMetadata);
|
||||||
|
|
||||||
Path zipFile = createZipFile(bookmarks, splitDocumentsBoas);
|
zipFile = createZipFile(bookmarks, splitDocumentsBoas);
|
||||||
|
|
||||||
byte[] data = Files.readAllBytes(zipFile);
|
byte[] data = Files.readAllBytes(zipFile);
|
||||||
Files.deleteIfExists(zipFile);
|
Files.deleteIfExists(zipFile);
|
||||||
@@ -123,6 +127,18 @@ public class SplitPdfByChaptersController {
|
|||||||
sourceDocument.close();
|
sourceDocument.close();
|
||||||
return WebResponseUtils.bytesToWebResponse(
|
return WebResponseUtils.bytesToWebResponse(
|
||||||
data, filename + ".zip", MediaType.APPLICATION_OCTET_STREAM);
|
data, filename + ".zip", MediaType.APPLICATION_OCTET_STREAM);
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
if (sourceDocument != null) {
|
||||||
|
sourceDocument.close();
|
||||||
|
}
|
||||||
|
if (zipFile != null) {
|
||||||
|
Files.deleteIfExists(zipFile);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("Error while cleaning up resources", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Bookmark> mergeBookmarksThatCorrespondToSamePage(List<Bookmark> bookmarks) {
|
private List<Bookmark> mergeBookmarksThatCorrespondToSamePage(List<Bookmark> bookmarks) {
|
||||||
|
|||||||
@@ -105,15 +105,13 @@ public class SplitPdfBySectionsController {
|
|||||||
|
|
||||||
if (sectionNum == horiz * verti) pageNum++;
|
if (sectionNum == horiz * verti) pageNum++;
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
|
||||||
logger.error("exception", e);
|
|
||||||
} finally {
|
|
||||||
data = Files.readAllBytes(zipFile);
|
data = Files.readAllBytes(zipFile);
|
||||||
Files.deleteIfExists(zipFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
return WebResponseUtils.bytesToWebResponse(
|
return WebResponseUtils.bytesToWebResponse(
|
||||||
data, filename + "_split.zip", MediaType.APPLICATION_OCTET_STREAM);
|
data, filename + "_split.zip", MediaType.APPLICATION_OCTET_STREAM);
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
Files.deleteIfExists(zipFile);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<PDDocument> splitPdfPages(
|
public List<PDDocument> splitPdfPages(
|
||||||
|
|||||||
@@ -244,8 +244,8 @@ public class UserController {
|
|||||||
return new RedirectView("/addUsers?messageType=invalidRole", true);
|
return new RedirectView("/addUsers?messageType=invalidRole", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (authType.equalsIgnoreCase(AuthenticationType.OAUTH2.toString())) {
|
if (authType.equalsIgnoreCase(AuthenticationType.SSO.toString())) {
|
||||||
userService.saveUser(username, AuthenticationType.OAUTH2, role);
|
userService.saveUser(username, AuthenticationType.SSO, role);
|
||||||
} else {
|
} else {
|
||||||
if (password.isBlank()) {
|
if (password.isBlank()) {
|
||||||
return new RedirectView("/addUsers?messageType=invalidPassword", true);
|
return new RedirectView("/addUsers?messageType=invalidPassword", true);
|
||||||
|
|||||||
@@ -65,6 +65,12 @@ public class ConvertImgPDFController {
|
|||||||
String colorType = request.getColorType();
|
String colorType = request.getColorType();
|
||||||
String dpi = request.getDpi();
|
String dpi = request.getDpi();
|
||||||
|
|
||||||
|
Path tempFile = null;
|
||||||
|
Path tempOutputDir = null;
|
||||||
|
Path tempPdfPath = null;
|
||||||
|
byte[] result = null;
|
||||||
|
|
||||||
|
try {
|
||||||
byte[] pdfBytes = file.getBytes();
|
byte[] pdfBytes = file.getBytes();
|
||||||
ImageType colorTypeResult = ImageType.RGB;
|
ImageType colorTypeResult = ImageType.RGB;
|
||||||
if ("greyscale".equals(colorType)) {
|
if ("greyscale".equals(colorType)) {
|
||||||
@@ -74,7 +80,6 @@ public class ConvertImgPDFController {
|
|||||||
}
|
}
|
||||||
// returns bytes for image
|
// returns bytes for image
|
||||||
boolean singleImage = "single".equals(singleOrMultiple);
|
boolean singleImage = "single".equals(singleOrMultiple);
|
||||||
byte[] result = null;
|
|
||||||
String filename =
|
String filename =
|
||||||
Filenames.toSimpleFileName(file.getOriginalFilename())
|
Filenames.toSimpleFileName(file.getOriginalFilename())
|
||||||
.replaceFirst("[.][^.]+$", "");
|
.replaceFirst("[.][^.]+$", "");
|
||||||
@@ -82,7 +87,9 @@ public class ConvertImgPDFController {
|
|||||||
result =
|
result =
|
||||||
PdfUtils.convertFromPdf(
|
PdfUtils.convertFromPdf(
|
||||||
pdfBytes,
|
pdfBytes,
|
||||||
"webp".equalsIgnoreCase(imageFormat) ? "png" : imageFormat.toUpperCase(),
|
"webp".equalsIgnoreCase(imageFormat)
|
||||||
|
? "png"
|
||||||
|
: imageFormat.toUpperCase(),
|
||||||
colorTypeResult,
|
colorTypeResult,
|
||||||
singleImage,
|
singleImage,
|
||||||
Integer.valueOf(dpi),
|
Integer.valueOf(dpi),
|
||||||
@@ -95,7 +102,7 @@ public class ConvertImgPDFController {
|
|||||||
} else if ("webp".equalsIgnoreCase(imageFormat)
|
} else if ("webp".equalsIgnoreCase(imageFormat)
|
||||||
&& CheckProgramInstall.isPythonAvailable()) {
|
&& CheckProgramInstall.isPythonAvailable()) {
|
||||||
// Write the output stream to a temp file
|
// Write the output stream to a temp file
|
||||||
Path tempFile = Files.createTempFile("temp_png", ".png");
|
tempFile = Files.createTempFile("temp_png", ".png");
|
||||||
try (FileOutputStream fos = new FileOutputStream(tempFile.toFile())) {
|
try (FileOutputStream fos = new FileOutputStream(tempFile.toFile())) {
|
||||||
fos.write(result);
|
fos.write(result);
|
||||||
fos.flush();
|
fos.flush();
|
||||||
@@ -108,7 +115,7 @@ public class ConvertImgPDFController {
|
|||||||
command.add("./scripts/png_to_webp.py"); // Python script to handle the conversion
|
command.add("./scripts/png_to_webp.py"); // Python script to handle the conversion
|
||||||
|
|
||||||
// Create a temporary directory for the output WebP files
|
// Create a temporary directory for the output WebP files
|
||||||
Path tempOutputDir = Files.createTempDirectory("webp_output");
|
tempOutputDir = Files.createTempDirectory("webp_output");
|
||||||
if (singleImage) {
|
if (singleImage) {
|
||||||
// Run the Python script to convert PNG to WebP
|
// Run the Python script to convert PNG to WebP
|
||||||
command.add(tempFile.toString());
|
command.add(tempFile.toString());
|
||||||
@@ -116,7 +123,7 @@ public class ConvertImgPDFController {
|
|||||||
command.add("--single");
|
command.add("--single");
|
||||||
} else {
|
} else {
|
||||||
// Save the uploaded PDF to a temporary file
|
// Save the uploaded PDF to a temporary file
|
||||||
Path tempPdfPath = Files.createTempFile("temp_pdf", ".pdf");
|
tempPdfPath = Files.createTempFile("temp_pdf", ".pdf");
|
||||||
file.transferTo(tempPdfPath.toFile());
|
file.transferTo(tempPdfPath.toFile());
|
||||||
// Run the Python script to convert PDF to WebP
|
// Run the Python script to convert PDF to WebP
|
||||||
command.add(tempPdfPath.toString());
|
command.add(tempPdfPath.toString());
|
||||||
@@ -136,7 +143,8 @@ public class ConvertImgPDFController {
|
|||||||
|
|
||||||
if (webpFiles.isEmpty()) {
|
if (webpFiles.isEmpty()) {
|
||||||
logger.error("No WebP files were created in: {}", tempOutputDir.toString());
|
logger.error("No WebP files were created in: {}", tempOutputDir.toString());
|
||||||
throw new IOException("No WebP files were created. " + resultProcess.getMessages());
|
throw new IOException(
|
||||||
|
"No WebP files were created. " + resultProcess.getMessages());
|
||||||
}
|
}
|
||||||
|
|
||||||
byte[] bodyBytes = new byte[0];
|
byte[] bodyBytes = new byte[0];
|
||||||
@@ -172,6 +180,23 @@ public class ConvertImgPDFController {
|
|||||||
return WebResponseUtils.bytesToWebResponse(
|
return WebResponseUtils.bytesToWebResponse(
|
||||||
result, zipFilename, MediaType.APPLICATION_OCTET_STREAM);
|
result, zipFilename, MediaType.APPLICATION_OCTET_STREAM);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
// Clean up temporary files
|
||||||
|
if (tempFile != null) {
|
||||||
|
Files.deleteIfExists(tempFile);
|
||||||
|
}
|
||||||
|
if (tempPdfPath != null) {
|
||||||
|
Files.deleteIfExists(tempPdfPath);
|
||||||
|
}
|
||||||
|
if (tempOutputDir != null) {
|
||||||
|
FileUtils.deleteDirectory(tempOutputDir.toFile());
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("Error cleaning up temporary files", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping(consumes = "multipart/form-data", value = "/img/pdf")
|
@PostMapping(consumes = "multipart/form-data", value = "/img/pdf")
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ import org.apache.pdfbox.pdmodel.PDDocumentInformation;
|
|||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.WebDataBinder;
|
||||||
|
import org.springframework.web.bind.annotation.InitBinder;
|
||||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
@@ -26,6 +28,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
|
|||||||
|
|
||||||
import stirling.software.SPDF.model.api.misc.MetadataRequest;
|
import stirling.software.SPDF.model.api.misc.MetadataRequest;
|
||||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
import stirling.software.SPDF.utils.propertyeditor.StringToMapPropertyEditor;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/v1/misc")
|
@RequestMapping("/api/v1/misc")
|
||||||
@@ -44,6 +47,11 @@ public class MetadataController {
|
|||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@InitBinder
|
||||||
|
public void initBinder(WebDataBinder binder) {
|
||||||
|
binder.registerCustomEditor(Map.class, "allRequestParams", new StringToMapPropertyEditor());
|
||||||
|
}
|
||||||
|
|
||||||
@PostMapping(consumes = "multipart/form-data", value = "/update-metadata")
|
@PostMapping(consumes = "multipart/form-data", value = "/update-metadata")
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Update metadata of a PDF file",
|
summary = "Update metadata of a PDF file",
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
package stirling.software.SPDF.controller.api.misc;
|
package stirling.software.SPDF.controller.api.misc;
|
||||||
|
|
||||||
import io.github.pixee.security.BoundedLineReader;
|
|
||||||
import io.github.pixee.security.Filenames;
|
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@@ -35,6 +33,8 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
|||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import io.github.pixee.security.BoundedLineReader;
|
||||||
|
import io.github.pixee.security.Filenames;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
@@ -87,7 +87,7 @@ public class OCRController {
|
|||||||
|
|
||||||
Files.createDirectories(tempOutputDir);
|
Files.createDirectories(tempOutputDir);
|
||||||
Files.createDirectories(tempImagesDir);
|
Files.createDirectories(tempImagesDir);
|
||||||
|
Process process = null;
|
||||||
try {
|
try {
|
||||||
// Save input file
|
// Save input file
|
||||||
inputFile.transferTo(tempInputFile.toFile());
|
inputFile.transferTo(tempInputFile.toFile());
|
||||||
@@ -139,7 +139,7 @@ public class OCRController {
|
|||||||
command.add("pdf"); // Always output PDF
|
command.add("pdf"); // Always output PDF
|
||||||
|
|
||||||
ProcessBuilder pb = new ProcessBuilder(command);
|
ProcessBuilder pb = new ProcessBuilder(command);
|
||||||
Process process = pb.start();
|
process = pb.start();
|
||||||
|
|
||||||
// Capture any error output
|
// Capture any error output
|
||||||
try (BufferedReader reader =
|
try (BufferedReader reader =
|
||||||
@@ -176,7 +176,9 @@ public class OCRController {
|
|||||||
// Read the final PDF file
|
// Read the final PDF file
|
||||||
byte[] pdfContent = Files.readAllBytes(finalOutputFile);
|
byte[] pdfContent = Files.readAllBytes(finalOutputFile);
|
||||||
String outputFilename =
|
String outputFilename =
|
||||||
Filenames.toSimpleFileName(inputFile.getOriginalFilename()).replaceFirst("[.][^.]+$", "") + "_OCR.pdf";
|
Filenames.toSimpleFileName(inputFile.getOriginalFilename())
|
||||||
|
.replaceFirst("[.][^.]+$", "")
|
||||||
|
+ "_OCR.pdf";
|
||||||
|
|
||||||
return ResponseEntity.ok()
|
return ResponseEntity.ok()
|
||||||
.header(
|
.header(
|
||||||
@@ -186,6 +188,10 @@ public class OCRController {
|
|||||||
.body(pdfContent);
|
.body(pdfContent);
|
||||||
|
|
||||||
} finally {
|
} finally {
|
||||||
|
if (process != null) {
|
||||||
|
process.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
// Clean up temporary files
|
// Clean up temporary files
|
||||||
deleteDirectory(tempDir);
|
deleteDirectory(tempDir);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,7 +50,6 @@ public class RepairController {
|
|||||||
MultipartFile inputFile = request.getFileInput();
|
MultipartFile inputFile = request.getFileInput();
|
||||||
// Save the uploaded file to a temporary location
|
// Save the uploaded file to a temporary location
|
||||||
Path tempInputFile = Files.createTempFile("input_", ".pdf");
|
Path tempInputFile = Files.createTempFile("input_", ".pdf");
|
||||||
Path tempOutputFile = Files.createTempFile("output_", ".pdf");
|
|
||||||
byte[] pdfBytes = null;
|
byte[] pdfBytes = null;
|
||||||
inputFile.transferTo(tempInputFile.toFile());
|
inputFile.transferTo(tempInputFile.toFile());
|
||||||
try {
|
try {
|
||||||
@@ -61,14 +60,13 @@ public class RepairController {
|
|||||||
command.add("--qdf"); // Linearizes and normalizes PDF structure
|
command.add("--qdf"); // Linearizes and normalizes PDF structure
|
||||||
command.add("--object-streams=disable"); // Can help with some corruptions
|
command.add("--object-streams=disable"); // Can help with some corruptions
|
||||||
command.add(tempInputFile.toString());
|
command.add(tempInputFile.toString());
|
||||||
command.add(tempOutputFile.toString());
|
|
||||||
|
|
||||||
ProcessExecutorResult returnCode =
|
ProcessExecutorResult returnCode =
|
||||||
ProcessExecutor.getInstance(ProcessExecutor.Processes.QPDF)
|
ProcessExecutor.getInstance(ProcessExecutor.Processes.QPDF)
|
||||||
.runCommandWithOutputHandling(command);
|
.runCommandWithOutputHandling(command);
|
||||||
|
|
||||||
// Read the optimized PDF file
|
// Read the optimized PDF file
|
||||||
pdfBytes = pdfDocumentFactory.loadToBytes(tempOutputFile.toFile());
|
pdfBytes = pdfDocumentFactory.loadToBytes(tempInputFile.toFile());
|
||||||
|
|
||||||
// Return the optimized PDF as a response
|
// Return the optimized PDF as a response
|
||||||
String outputFilename =
|
String outputFilename =
|
||||||
@@ -79,7 +77,6 @@ public class RepairController {
|
|||||||
} finally {
|
} finally {
|
||||||
// Clean up the temporary files
|
// Clean up the temporary files
|
||||||
Files.deleteIfExists(tempInputFile);
|
Files.deleteIfExists(tempInputFile);
|
||||||
Files.deleteIfExists(tempOutputFile);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -229,10 +229,22 @@ public class StampController {
|
|||||||
calculatePositionY(
|
calculatePositionY(
|
||||||
pageSize, position, calculateTextCapHeight(font, fontSize), margin);
|
pageSize, position, calculateTextCapHeight(font, fontSize), margin);
|
||||||
}
|
}
|
||||||
|
// Split the stampText into multiple lines
|
||||||
|
String[] lines = stampText.split("\\\\n");
|
||||||
|
|
||||||
|
// Calculate dynamic line height based on font ascent and descent
|
||||||
|
float ascent = font.getFontDescriptor().getAscent();
|
||||||
|
float descent = font.getFontDescriptor().getDescent();
|
||||||
|
float lineHeight = ((ascent - descent) / 1000) * fontSize;
|
||||||
|
|
||||||
contentStream.beginText();
|
contentStream.beginText();
|
||||||
contentStream.setTextMatrix(Matrix.getRotateInstance(Math.toRadians(rotation), x, y));
|
for (int i = 0; i < lines.length; i++) {
|
||||||
contentStream.showText(stampText);
|
String line = lines[i];
|
||||||
|
// Set the text matrix for each line with rotation
|
||||||
|
contentStream.setTextMatrix(
|
||||||
|
Matrix.getRotateInstance(Math.toRadians(rotation), x, y - (i * lineHeight)));
|
||||||
|
contentStream.showText(line);
|
||||||
|
}
|
||||||
contentStream.endText();
|
contentStream.endText();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -221,7 +221,7 @@ public class PipelineProcessor {
|
|||||||
|
|
||||||
HttpHeaders headers = new HttpHeaders();
|
HttpHeaders headers = new HttpHeaders();
|
||||||
String apiKey = getApiKeyForUser();
|
String apiKey = getApiKeyForUser();
|
||||||
headers.add("X-API-Key", apiKey);
|
headers.add("X-API-KEY", apiKey);
|
||||||
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
|
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
|
||||||
|
|
||||||
// Create HttpEntity with the body and headers
|
// Create HttpEntity with the body and headers
|
||||||
|
|||||||
@@ -322,27 +322,14 @@ public class GetInfoOnPDF {
|
|||||||
PDEncryption pdfEncryption = pdfBoxDoc.getEncryption();
|
PDEncryption pdfEncryption = pdfBoxDoc.getEncryption();
|
||||||
encryption.put("EncryptionAlgorithm", pdfEncryption.getFilter());
|
encryption.put("EncryptionAlgorithm", pdfEncryption.getFilter());
|
||||||
encryption.put("KeyLength", pdfEncryption.getLength());
|
encryption.put("KeyLength", pdfEncryption.getLength());
|
||||||
AccessPermission ap = pdfBoxDoc.getCurrentAccessPermission();
|
|
||||||
if (ap != null) {
|
|
||||||
ObjectNode permissionsNode = objectMapper.createObjectNode();
|
|
||||||
|
|
||||||
permissionsNode.put("CanAssembleDocument", ap.canAssembleDocument());
|
|
||||||
permissionsNode.put("CanExtractContent", ap.canExtractContent());
|
|
||||||
permissionsNode.put(
|
|
||||||
"CanExtractForAccessibility", ap.canExtractForAccessibility());
|
|
||||||
permissionsNode.put("CanFillInForm", ap.canFillInForm());
|
|
||||||
permissionsNode.put("CanModify", ap.canModify());
|
|
||||||
permissionsNode.put("CanModifyAnnotations", ap.canModifyAnnotations());
|
|
||||||
permissionsNode.put("CanPrint", ap.canPrint());
|
|
||||||
|
|
||||||
encryption.set(
|
|
||||||
"Permissions", permissionsNode); // set the node under "Permissions"
|
|
||||||
}
|
|
||||||
// Add other encryption-related properties as needed
|
// Add other encryption-related properties as needed
|
||||||
} else {
|
} else {
|
||||||
encryption.put("IsEncrypted", false);
|
encryption.put("IsEncrypted", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ObjectNode permissionsNode = objectMapper.createObjectNode();
|
||||||
|
setNodePermissions(pdfBoxDoc, permissionsNode);
|
||||||
|
|
||||||
ObjectNode pageInfoParent = objectMapper.createObjectNode();
|
ObjectNode pageInfoParent = objectMapper.createObjectNode();
|
||||||
for (int pageNum = 0; pageNum < pdfBoxDoc.getNumberOfPages(); pageNum++) {
|
for (int pageNum = 0; pageNum < pdfBoxDoc.getNumberOfPages(); pageNum++) {
|
||||||
ObjectNode pageInfo = objectMapper.createObjectNode();
|
ObjectNode pageInfo = objectMapper.createObjectNode();
|
||||||
@@ -584,6 +571,7 @@ public class GetInfoOnPDF {
|
|||||||
jsonOutput.set("DocumentInfo", docInfoNode);
|
jsonOutput.set("DocumentInfo", docInfoNode);
|
||||||
jsonOutput.set("Compliancy", compliancy);
|
jsonOutput.set("Compliancy", compliancy);
|
||||||
jsonOutput.set("Encryption", encryption);
|
jsonOutput.set("Encryption", encryption);
|
||||||
|
jsonOutput.set("Permissions", permissionsNode); // set the node under "Permissions"
|
||||||
jsonOutput.set("Other", other);
|
jsonOutput.set("Other", other);
|
||||||
jsonOutput.set("PerPageInfo", pageInfoParent);
|
jsonOutput.set("PerPageInfo", pageInfoParent);
|
||||||
|
|
||||||
@@ -602,6 +590,24 @@ public class GetInfoOnPDF {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setNodePermissions(PDDocument pdfBoxDoc, ObjectNode permissionsNode) {
|
||||||
|
AccessPermission ap = pdfBoxDoc.getCurrentAccessPermission();
|
||||||
|
|
||||||
|
permissionsNode.put("Document Assembly", getPermissionState(ap.canAssembleDocument()));
|
||||||
|
permissionsNode.put("Extracting Content", getPermissionState(ap.canExtractContent()));
|
||||||
|
permissionsNode.put(
|
||||||
|
"Extracting for accessibility",
|
||||||
|
getPermissionState(ap.canExtractForAccessibility()));
|
||||||
|
permissionsNode.put("Form Filling", getPermissionState(ap.canFillInForm()));
|
||||||
|
permissionsNode.put("Modifying", getPermissionState(ap.canModify()));
|
||||||
|
permissionsNode.put("Modifying annotations", getPermissionState(ap.canModifyAnnotations()));
|
||||||
|
permissionsNode.put("Printing", getPermissionState(ap.canPrint()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getPermissionState(boolean state) {
|
||||||
|
return state ? "Allowed" : "Not Allowed";
|
||||||
|
}
|
||||||
|
|
||||||
private static void addOutlinesToArray(PDOutlineItem outline, ArrayNode arrayNode) {
|
private static void addOutlinesToArray(PDOutlineItem outline, ArrayNode arrayNode) {
|
||||||
if (outline == null) return;
|
if (outline == null) return;
|
||||||
|
|
||||||
|
|||||||
@@ -39,10 +39,7 @@ public class PasswordController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping(consumes = "multipart/form-data", value = "/remove-password")
|
@PostMapping(consumes = "multipart/form-data", value = "/remove-password")
|
||||||
@Operation(
|
@Operation(summary = "Remove password from a PDF file", description = "This endpoint removes the password from a protected PDF file. Users need to provide the existing password. Input:PDF Output:PDF Type:SISO")
|
||||||
summary = "Remove password from a PDF file",
|
|
||||||
description =
|
|
||||||
"This endpoint removes the password from a protected PDF file. Users need to provide the existing password. Input:PDF Output:PDF Type:SISO")
|
|
||||||
public ResponseEntity<byte[]> removePassword(@ModelAttribute PDFPasswordRequest request)
|
public ResponseEntity<byte[]> removePassword(@ModelAttribute PDFPasswordRequest request)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
MultipartFile fileInput = request.getFileInput();
|
MultipartFile fileInput = request.getFileInput();
|
||||||
@@ -57,10 +54,7 @@ public class PasswordController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping(consumes = "multipart/form-data", value = "/add-password")
|
@PostMapping(consumes = "multipart/form-data", value = "/add-password")
|
||||||
@Operation(
|
@Operation(summary = "Add password to a PDF file", description = "This endpoint adds password protection to a PDF file. Users can specify a set of permissions that should be applied to the file. Input:PDF Output:PDF")
|
||||||
summary = "Add password to a PDF file",
|
|
||||||
description =
|
|
||||||
"This endpoint adds password protection to a PDF file. Users can specify a set of permissions that should be applied to the file. Input:PDF Output:PDF")
|
|
||||||
public ResponseEntity<byte[]> addPassword(@ModelAttribute AddPasswordRequest request)
|
public ResponseEntity<byte[]> addPassword(@ModelAttribute AddPasswordRequest request)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
MultipartFile fileInput = request.getFileInput();
|
MultipartFile fileInput = request.getFileInput();
|
||||||
|
|||||||
@@ -0,0 +1,180 @@
|
|||||||
|
package stirling.software.SPDF.controller.api.security;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.security.cert.CertificateException;
|
||||||
|
import java.security.cert.CertificateFactory;
|
||||||
|
import java.security.cert.X509Certificate;
|
||||||
|
import java.security.interfaces.RSAPublicKey;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
|
import org.apache.pdfbox.pdmodel.interactive.digitalsignature.PDSignature;
|
||||||
|
import org.bouncycastle.cert.X509CertificateHolder;
|
||||||
|
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
|
||||||
|
import org.bouncycastle.cms.CMSProcessable;
|
||||||
|
import org.bouncycastle.cms.CMSProcessableByteArray;
|
||||||
|
import org.bouncycastle.cms.CMSSignedData;
|
||||||
|
import org.bouncycastle.cms.SignerInformation;
|
||||||
|
import org.bouncycastle.cms.SignerInformationStore;
|
||||||
|
import org.bouncycastle.cms.jcajce.JcaSimpleSignerInfoVerifierBuilder;
|
||||||
|
import org.bouncycastle.util.Store;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
|
||||||
|
import stirling.software.SPDF.model.api.security.SignatureValidationRequest;
|
||||||
|
import stirling.software.SPDF.model.api.security.SignatureValidationResult;
|
||||||
|
import stirling.software.SPDF.service.CertificateValidationService;
|
||||||
|
import stirling.software.SPDF.service.CustomPDDocumentFactory;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/v1/security")
|
||||||
|
@Tag(name = "Security", description = "Security APIs")
|
||||||
|
public class ValidateSignatureController {
|
||||||
|
|
||||||
|
private final CustomPDDocumentFactory pdfDocumentFactory;
|
||||||
|
private final CertificateValidationService certValidationService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public ValidateSignatureController(
|
||||||
|
CustomPDDocumentFactory pdfDocumentFactory,
|
||||||
|
CertificateValidationService certValidationService) {
|
||||||
|
this.pdfDocumentFactory = pdfDocumentFactory;
|
||||||
|
this.certValidationService = certValidationService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(
|
||||||
|
summary = "Validate PDF Digital Signature",
|
||||||
|
description =
|
||||||
|
"Validates the digital signatures in a PDF file against default or custom certificates. Input:PDF Output:JSON Type:SISO")
|
||||||
|
@PostMapping(value = "/validate-signature")
|
||||||
|
public ResponseEntity<List<SignatureValidationResult>> validateSignature(
|
||||||
|
@ModelAttribute SignatureValidationRequest request) throws IOException {
|
||||||
|
List<SignatureValidationResult> results = new ArrayList<>();
|
||||||
|
MultipartFile file = request.getFileInput();
|
||||||
|
|
||||||
|
// Load custom certificate if provided
|
||||||
|
X509Certificate customCert = null;
|
||||||
|
if (request.getCertFile() != null && !request.getCertFile().isEmpty()) {
|
||||||
|
try (ByteArrayInputStream certStream =
|
||||||
|
new ByteArrayInputStream(request.getCertFile().getBytes())) {
|
||||||
|
CertificateFactory cf = CertificateFactory.getInstance("X.509");
|
||||||
|
customCert = (X509Certificate) cf.generateCertificate(certStream);
|
||||||
|
} catch (CertificateException e) {
|
||||||
|
throw new RuntimeException("Invalid certificate file: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try (PDDocument document = pdfDocumentFactory.load(file.getInputStream())) {
|
||||||
|
List<PDSignature> signatures = document.getSignatureDictionaries();
|
||||||
|
|
||||||
|
for (PDSignature sig : signatures) {
|
||||||
|
SignatureValidationResult result = new SignatureValidationResult();
|
||||||
|
|
||||||
|
try {
|
||||||
|
byte[] signedContent = sig.getSignedContent(file.getInputStream());
|
||||||
|
byte[] signatureBytes = sig.getContents(file.getInputStream());
|
||||||
|
|
||||||
|
CMSProcessable content = new CMSProcessableByteArray(signedContent);
|
||||||
|
CMSSignedData signedData = new CMSSignedData(content, signatureBytes);
|
||||||
|
|
||||||
|
Store<X509CertificateHolder> certStore = signedData.getCertificates();
|
||||||
|
SignerInformationStore signerStore = signedData.getSignerInfos();
|
||||||
|
|
||||||
|
for (SignerInformation signer : signerStore.getSigners()) {
|
||||||
|
X509CertificateHolder certHolder =
|
||||||
|
(X509CertificateHolder)
|
||||||
|
certStore.getMatches(signer.getSID()).iterator().next();
|
||||||
|
X509Certificate cert =
|
||||||
|
new JcaX509CertificateConverter().getCertificate(certHolder);
|
||||||
|
|
||||||
|
boolean isValid =
|
||||||
|
signer.verify(new JcaSimpleSignerInfoVerifierBuilder().build(cert));
|
||||||
|
result.setValid(isValid);
|
||||||
|
|
||||||
|
// Additional validations
|
||||||
|
result.setChainValid(
|
||||||
|
customCert != null
|
||||||
|
? certValidationService
|
||||||
|
.validateCertificateChainWithCustomCert(
|
||||||
|
cert, customCert)
|
||||||
|
: certValidationService.validateCertificateChain(cert));
|
||||||
|
|
||||||
|
result.setTrustValid(
|
||||||
|
customCert != null
|
||||||
|
? certValidationService.validateTrustWithCustomCert(
|
||||||
|
cert, customCert)
|
||||||
|
: certValidationService.validateTrustStore(cert));
|
||||||
|
|
||||||
|
result.setNotRevoked(!certValidationService.isRevoked(cert));
|
||||||
|
result.setNotExpired(!cert.getNotAfter().before(new Date()));
|
||||||
|
|
||||||
|
// Set basic signature info
|
||||||
|
result.setSignerName(sig.getName());
|
||||||
|
result.setSignatureDate(sig.getSignDate().getTime().toString());
|
||||||
|
result.setReason(sig.getReason());
|
||||||
|
result.setLocation(sig.getLocation());
|
||||||
|
|
||||||
|
// Set new certificate details
|
||||||
|
result.setIssuerDN(cert.getIssuerX500Principal().getName());
|
||||||
|
result.setSubjectDN(cert.getSubjectX500Principal().getName());
|
||||||
|
result.setSerialNumber(cert.getSerialNumber().toString(16)); // Hex format
|
||||||
|
result.setValidFrom(cert.getNotBefore().toString());
|
||||||
|
result.setValidUntil(cert.getNotAfter().toString());
|
||||||
|
result.setSignatureAlgorithm(cert.getSigAlgName());
|
||||||
|
|
||||||
|
// Get key size (if possible)
|
||||||
|
try {
|
||||||
|
result.setKeySize(
|
||||||
|
((RSAPublicKey) cert.getPublicKey()).getModulus().bitLength());
|
||||||
|
} catch (Exception e) {
|
||||||
|
// If not RSA or error, set to 0
|
||||||
|
result.setKeySize(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
result.setVersion(String.valueOf(cert.getVersion()));
|
||||||
|
|
||||||
|
// Set key usage
|
||||||
|
List<String> keyUsages = new ArrayList<>();
|
||||||
|
boolean[] keyUsageFlags = cert.getKeyUsage();
|
||||||
|
if (keyUsageFlags != null) {
|
||||||
|
String[] keyUsageLabels = {
|
||||||
|
"Digital Signature", "Non-Repudiation", "Key Encipherment",
|
||||||
|
"Data Encipherment", "Key Agreement", "Certificate Signing",
|
||||||
|
"CRL Signing", "Encipher Only", "Decipher Only"
|
||||||
|
};
|
||||||
|
for (int i = 0; i < keyUsageFlags.length; i++) {
|
||||||
|
if (keyUsageFlags[i]) {
|
||||||
|
keyUsages.add(keyUsageLabels[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result.setKeyUsages(keyUsages);
|
||||||
|
|
||||||
|
// Check if self-signed
|
||||||
|
result.setSelfSigned(
|
||||||
|
cert.getSubjectX500Principal()
|
||||||
|
.equals(cert.getIssuerX500Principal()));
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
result.setValid(false);
|
||||||
|
result.setErrorMessage("Signature validation failed: " + e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
results.add(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResponseEntity.ok(results);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -69,6 +69,7 @@ public class WatermarkController {
|
|||||||
float opacity = request.getOpacity();
|
float opacity = request.getOpacity();
|
||||||
int widthSpacer = request.getWidthSpacer();
|
int widthSpacer = request.getWidthSpacer();
|
||||||
int heightSpacer = request.getHeightSpacer();
|
int heightSpacer = request.getHeightSpacer();
|
||||||
|
String customColor = request.getCustomColor();
|
||||||
boolean convertPdfToImage = request.isConvertPDFToImage();
|
boolean convertPdfToImage = request.isConvertPDFToImage();
|
||||||
|
|
||||||
// Load the input PDF
|
// Load the input PDF
|
||||||
@@ -97,7 +98,8 @@ public class WatermarkController {
|
|||||||
widthSpacer,
|
widthSpacer,
|
||||||
heightSpacer,
|
heightSpacer,
|
||||||
fontSize,
|
fontSize,
|
||||||
alphabet);
|
alphabet,
|
||||||
|
customColor);
|
||||||
} else if ("image".equalsIgnoreCase(watermarkType)) {
|
} else if ("image".equalsIgnoreCase(watermarkType)) {
|
||||||
addImageWatermark(
|
addImageWatermark(
|
||||||
contentStream,
|
contentStream,
|
||||||
@@ -136,7 +138,8 @@ public class WatermarkController {
|
|||||||
int widthSpacer,
|
int widthSpacer,
|
||||||
int heightSpacer,
|
int heightSpacer,
|
||||||
float fontSize,
|
float fontSize,
|
||||||
String alphabet)
|
String alphabet,
|
||||||
|
String colorString)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
String resourceDir = "";
|
String resourceDir = "";
|
||||||
PDFont font = new PDType1Font(Standard14Fonts.FontName.HELVETICA);
|
PDFont font = new PDType1Font(Standard14Fonts.FontName.HELVETICA);
|
||||||
@@ -173,7 +176,18 @@ public class WatermarkController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
contentStream.setFont(font, fontSize);
|
contentStream.setFont(font, fontSize);
|
||||||
contentStream.setNonStrokingColor(Color.LIGHT_GRAY);
|
|
||||||
|
Color redactColor;
|
||||||
|
try {
|
||||||
|
if (!colorString.startsWith("#")) {
|
||||||
|
colorString = "#" + colorString;
|
||||||
|
}
|
||||||
|
redactColor = Color.decode(colorString);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
|
||||||
|
redactColor = Color.LIGHT_GRAY;
|
||||||
|
}
|
||||||
|
contentStream.setNonStrokingColor(redactColor);
|
||||||
|
|
||||||
String[] textLines = watermarkText.split("\\\\n");
|
String[] textLines = watermarkText.split("\\\\n");
|
||||||
float maxLineWidth = 0;
|
float maxLineWidth = 0;
|
||||||
|
|||||||
@@ -53,6 +53,13 @@ public class SecurityWebController {
|
|||||||
return "security/cert-sign";
|
return "security/cert-sign";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("/validate-signature")
|
||||||
|
@Hidden
|
||||||
|
public String certSignVerifyForm(Model model) {
|
||||||
|
model.addAttribute("currentPage", "validate-signature");
|
||||||
|
return "security/validate-signature";
|
||||||
|
}
|
||||||
|
|
||||||
@GetMapping("/remove-cert-sign")
|
@GetMapping("/remove-cert-sign")
|
||||||
@Hidden
|
@Hidden
|
||||||
public String certUnSignForm(Model model) {
|
public String certUnSignForm(Model model) {
|
||||||
|
|||||||
@@ -73,6 +73,7 @@ public class ApplicationProperties {
|
|||||||
private int loginAttemptCount;
|
private int loginAttemptCount;
|
||||||
private long loginResetTimeMinutes;
|
private long loginResetTimeMinutes;
|
||||||
private String loginMethod = "all";
|
private String loginMethod = "all";
|
||||||
|
private String customGlobalAPIKey;
|
||||||
|
|
||||||
public Boolean isAltLogin() {
|
public Boolean isAltLogin() {
|
||||||
return saml2.getEnabled() || oauth2.getEnabled();
|
return saml2.getEnabled() || oauth2.getEnabled();
|
||||||
@@ -285,6 +286,7 @@ public class ApplicationProperties {
|
|||||||
public static class AutomaticallyGenerated {
|
public static class AutomaticallyGenerated {
|
||||||
@ToString.Exclude private String key;
|
@ToString.Exclude private String key;
|
||||||
private String UUID;
|
private String UUID;
|
||||||
|
private String appVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
|
|||||||
@@ -2,5 +2,5 @@ package stirling.software.SPDF.model;
|
|||||||
|
|
||||||
public enum AuthenticationType {
|
public enum AuthenticationType {
|
||||||
WEB,
|
WEB,
|
||||||
OAUTH2
|
SSO
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,6 +45,9 @@ public class AddWatermarkRequest extends PDFFile {
|
|||||||
@Schema(description = "The height spacer between watermark elements", example = "50")
|
@Schema(description = "The height spacer between watermark elements", example = "50")
|
||||||
private int heightSpacer;
|
private int heightSpacer;
|
||||||
|
|
||||||
|
@Schema(description = "The color for watermark", defaultValue = "#d3d3d3")
|
||||||
|
private String customColor = "#d3d3d3";
|
||||||
|
|
||||||
@Schema(description = "Convert the redacted PDF to an image", defaultValue = "false")
|
@Schema(description = "Convert the redacted PDF to an image", defaultValue = "false")
|
||||||
private boolean convertPDFToImage;
|
private boolean convertPDFToImage;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package stirling.software.SPDF.model.api.security;
|
||||||
|
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import stirling.software.SPDF.model.api.PDFFile;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class SignatureValidationRequest extends PDFFile {
|
||||||
|
|
||||||
|
@Schema(description = "(Optional) file to compare PDF cert signatures against x.509 format")
|
||||||
|
private MultipartFile certFile;
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package stirling.software.SPDF.model.api.security;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class SignatureValidationResult {
|
||||||
|
private boolean valid;
|
||||||
|
private String signerName;
|
||||||
|
private String signatureDate;
|
||||||
|
private String reason;
|
||||||
|
private String location;
|
||||||
|
private String errorMessage;
|
||||||
|
private boolean chainValid;
|
||||||
|
private boolean trustValid;
|
||||||
|
private boolean notExpired;
|
||||||
|
private boolean notRevoked;
|
||||||
|
|
||||||
|
private String issuerDN; // Certificate issuer's Distinguished Name
|
||||||
|
private String subjectDN; // Certificate subject's Distinguished Name
|
||||||
|
private String serialNumber; // Certificate serial number
|
||||||
|
private String validFrom; // Certificate validity start date
|
||||||
|
private String validUntil; // Certificate validity end date
|
||||||
|
private String signatureAlgorithm; // Algorithm used for signing
|
||||||
|
private int keySize; // Key size in bits
|
||||||
|
private String version; // Certificate version
|
||||||
|
private List<String> keyUsages; // List of key usage purposes
|
||||||
|
private boolean isSelfSigned; // Whether the certificate is self-signed
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
package stirling.software.SPDF.repository;
|
package stirling.software.SPDF.repository;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
import org.springframework.data.jpa.repository.JpaRepository;
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
@@ -19,4 +20,6 @@ public interface UserRepository extends JpaRepository<User, Long> {
|
|||||||
Optional<User> findByUsername(String username);
|
Optional<User> findByUsername(String username);
|
||||||
|
|
||||||
Optional<User> findByApiKey(String apiKey);
|
Optional<User> findByApiKey(String apiKey);
|
||||||
|
|
||||||
|
List<User> findByAuthenticationTypeIgnoreCase(String authenticationType);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,158 @@
|
|||||||
|
package stirling.software.SPDF.service;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.security.KeyStore;
|
||||||
|
import java.security.KeyStoreException;
|
||||||
|
import java.security.cert.CertPath;
|
||||||
|
import java.security.cert.CertPathValidator;
|
||||||
|
import java.security.cert.CertificateExpiredException;
|
||||||
|
import java.security.cert.CertificateFactory;
|
||||||
|
import java.security.cert.CertificateNotYetValidException;
|
||||||
|
import java.security.cert.PKIXParameters;
|
||||||
|
import java.security.cert.TrustAnchor;
|
||||||
|
import java.security.cert.X509Certificate;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Enumeration;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import io.github.pixee.security.BoundedLineReader;
|
||||||
|
|
||||||
|
import jakarta.annotation.PostConstruct;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class CertificateValidationService {
|
||||||
|
private KeyStore trustStore;
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
private void initializeTrustStore() throws Exception {
|
||||||
|
trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
|
||||||
|
trustStore.load(null, null);
|
||||||
|
loadMozillaCertificates();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadMozillaCertificates() throws Exception {
|
||||||
|
try (InputStream is = getClass().getResourceAsStream("/certdata.txt")) {
|
||||||
|
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
|
||||||
|
String line;
|
||||||
|
StringBuilder certData = new StringBuilder();
|
||||||
|
boolean inCert = false;
|
||||||
|
int certCount = 0;
|
||||||
|
|
||||||
|
while ((line = BoundedLineReader.readLine(reader, 5_000_000)) != null) {
|
||||||
|
if (line.startsWith("CKA_VALUE MULTILINE_OCTAL")) {
|
||||||
|
inCert = true;
|
||||||
|
certData = new StringBuilder();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (inCert) {
|
||||||
|
if ("END".equals(line)) {
|
||||||
|
inCert = false;
|
||||||
|
byte[] certBytes = parseOctalData(certData.toString());
|
||||||
|
if (certBytes != null) {
|
||||||
|
CertificateFactory cf = CertificateFactory.getInstance("X.509");
|
||||||
|
X509Certificate cert =
|
||||||
|
(X509Certificate)
|
||||||
|
cf.generateCertificate(
|
||||||
|
new ByteArrayInputStream(certBytes));
|
||||||
|
trustStore.setCertificateEntry("mozilla-cert-" + certCount++, cert);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
certData.append(line).append("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte[] parseOctalData(String data) {
|
||||||
|
try {
|
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
String[] tokens = data.split("\\\\");
|
||||||
|
for (String token : tokens) {
|
||||||
|
token = token.trim();
|
||||||
|
if (!token.isEmpty()) {
|
||||||
|
baos.write(Integer.parseInt(token, 8));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return baos.toByteArray();
|
||||||
|
} catch (Exception e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean validateCertificateChain(X509Certificate cert) {
|
||||||
|
try {
|
||||||
|
CertPathValidator validator = CertPathValidator.getInstance("PKIX");
|
||||||
|
CertificateFactory cf = CertificateFactory.getInstance("X.509");
|
||||||
|
List<X509Certificate> certList = Arrays.asList(cert);
|
||||||
|
CertPath certPath = cf.generateCertPath(certList);
|
||||||
|
|
||||||
|
Set<TrustAnchor> anchors = new HashSet<>();
|
||||||
|
Enumeration<String> aliases = trustStore.aliases();
|
||||||
|
while (aliases.hasMoreElements()) {
|
||||||
|
Object trustCert = trustStore.getCertificate(aliases.nextElement());
|
||||||
|
if (trustCert instanceof X509Certificate) {
|
||||||
|
anchors.add(new TrustAnchor((X509Certificate) trustCert, null));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PKIXParameters params = new PKIXParameters(anchors);
|
||||||
|
params.setRevocationEnabled(false);
|
||||||
|
validator.validate(certPath, params);
|
||||||
|
return true;
|
||||||
|
} catch (Exception e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean validateTrustStore(X509Certificate cert) {
|
||||||
|
try {
|
||||||
|
Enumeration<String> aliases = trustStore.aliases();
|
||||||
|
while (aliases.hasMoreElements()) {
|
||||||
|
Object trustCert = trustStore.getCertificate(aliases.nextElement());
|
||||||
|
if (trustCert instanceof X509Certificate && cert.equals(trustCert)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
} catch (KeyStoreException e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isRevoked(X509Certificate cert) {
|
||||||
|
try {
|
||||||
|
cert.checkValidity();
|
||||||
|
return false;
|
||||||
|
} catch (CertificateExpiredException | CertificateNotYetValidException e) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean validateCertificateChainWithCustomCert(
|
||||||
|
X509Certificate cert, X509Certificate customCert) {
|
||||||
|
try {
|
||||||
|
cert.verify(customCert.getPublicKey());
|
||||||
|
return true;
|
||||||
|
} catch (Exception e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean validateTrustWithCustomCert(X509Certificate cert, X509Certificate customCert) {
|
||||||
|
try {
|
||||||
|
// Compare the issuer of the signature certificate with the custom certificate
|
||||||
|
return cert.getIssuerX500Principal().equals(customCert.getSubjectX500Principal());
|
||||||
|
} catch (Exception e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -24,7 +24,7 @@ public class MetricsAggregatorService {
|
|||||||
this.postHogService = postHogService;
|
this.postHogService = postHogService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Scheduled(fixedRate = 1800000) // Run every 30 minutes
|
@Scheduled(fixedRate = 7200000) // Run every 2 hours
|
||||||
public void aggregateAndSendMetrics() {
|
public void aggregateAndSendMetrics() {
|
||||||
Map<String, Object> metrics = new HashMap<>();
|
Map<String, Object> metrics = new HashMap<>();
|
||||||
Search.in(meterRegistry)
|
Search.in(meterRegistry)
|
||||||
|
|||||||
@@ -17,15 +17,18 @@ public class PdfMetadataService {
|
|||||||
private final ApplicationProperties applicationProperties;
|
private final ApplicationProperties applicationProperties;
|
||||||
private final String stirlingPDFLabel;
|
private final String stirlingPDFLabel;
|
||||||
private final UserServiceInterface userService;
|
private final UserServiceInterface userService;
|
||||||
|
private final boolean runningEE;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public PdfMetadataService(
|
public PdfMetadataService(
|
||||||
ApplicationProperties applicationProperties,
|
ApplicationProperties applicationProperties,
|
||||||
@Qualifier("StirlingPDFLabel") String stirlingPDFLabel,
|
@Qualifier("StirlingPDFLabel") String stirlingPDFLabel,
|
||||||
|
@Qualifier("runningEE") boolean runningEE,
|
||||||
@Autowired(required = false) UserServiceInterface userService) {
|
@Autowired(required = false) UserServiceInterface userService) {
|
||||||
this.applicationProperties = applicationProperties;
|
this.applicationProperties = applicationProperties;
|
||||||
this.stirlingPDFLabel = stirlingPDFLabel;
|
this.stirlingPDFLabel = stirlingPDFLabel;
|
||||||
this.userService = userService;
|
this.userService = userService;
|
||||||
|
this.runningEE = runningEE;
|
||||||
}
|
}
|
||||||
|
|
||||||
public PdfMetadata extractMetadataFromPdf(PDDocument pdf) {
|
public PdfMetadata extractMetadataFromPdf(PDDocument pdf) {
|
||||||
@@ -61,10 +64,8 @@ public class PdfMetadataService {
|
|||||||
|
|
||||||
String creator = stirlingPDFLabel;
|
String creator = stirlingPDFLabel;
|
||||||
|
|
||||||
if (applicationProperties
|
if (applicationProperties.getEnterpriseEdition().getCustomMetadata().isAutoUpdateMetadata()
|
||||||
.getEnterpriseEdition()
|
&& runningEE) {
|
||||||
.getCustomMetadata()
|
|
||||||
.isAutoUpdateMetadata()) {
|
|
||||||
|
|
||||||
creator = applicationProperties.getEnterpriseEdition().getCustomMetadata().getCreator();
|
creator = applicationProperties.getEnterpriseEdition().getCustomMetadata().getCreator();
|
||||||
pdf.getDocumentInformation().setProducer(stirlingPDFLabel);
|
pdf.getDocumentInformation().setProducer(stirlingPDFLabel);
|
||||||
@@ -83,10 +84,8 @@ public class PdfMetadataService {
|
|||||||
pdf.getDocumentInformation().setModificationDate(Calendar.getInstance());
|
pdf.getDocumentInformation().setModificationDate(Calendar.getInstance());
|
||||||
|
|
||||||
String author = pdfMetadata.getAuthor();
|
String author = pdfMetadata.getAuthor();
|
||||||
if (applicationProperties
|
if (applicationProperties.getEnterpriseEdition().getCustomMetadata().isAutoUpdateMetadata()
|
||||||
.getEnterpriseEdition()
|
&& runningEE) {
|
||||||
.getCustomMetadata()
|
|
||||||
.isAutoUpdateMetadata()) {
|
|
||||||
author = applicationProperties.getEnterpriseEdition().getCustomMetadata().getAuthor();
|
author = applicationProperties.getEnterpriseEdition().getCustomMetadata().getAuthor();
|
||||||
|
|
||||||
if (userService != null) {
|
if (userService != null) {
|
||||||
|
|||||||
@@ -88,15 +88,45 @@ public class GeneralUtils {
|
|||||||
|
|
||||||
public static boolean isURLReachable(String urlStr) {
|
public static boolean isURLReachable(String urlStr) {
|
||||||
try {
|
try {
|
||||||
|
// Parse the URL
|
||||||
URL url = URI.create(urlStr).toURL();
|
URL url = URI.create(urlStr).toURL();
|
||||||
|
|
||||||
|
// Allow only http and https protocols
|
||||||
|
String protocol = url.getProtocol();
|
||||||
|
if (!protocol.equals("http") && !protocol.equals("https")) {
|
||||||
|
return false; // Disallow other protocols
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the host is a local address
|
||||||
|
String host = url.getHost();
|
||||||
|
if (isLocalAddress(host)) {
|
||||||
|
return false; // Exclude local addresses
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the URL is reachable
|
||||||
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
||||||
connection.setRequestMethod("HEAD");
|
connection.setRequestMethod("HEAD");
|
||||||
|
// connection.setConnectTimeout(5000); // Set connection timeout
|
||||||
|
// connection.setReadTimeout(5000); // Set read timeout
|
||||||
int responseCode = connection.getResponseCode();
|
int responseCode = connection.getResponseCode();
|
||||||
return (200 <= responseCode && responseCode <= 399);
|
return (200 <= responseCode && responseCode <= 399);
|
||||||
} catch (MalformedURLException e) {
|
} catch (Exception e) {
|
||||||
return false;
|
return false; // Return false in case of any exception
|
||||||
} catch (IOException e) {
|
}
|
||||||
return false;
|
}
|
||||||
|
|
||||||
|
private static boolean isLocalAddress(String host) {
|
||||||
|
try {
|
||||||
|
// Resolve DNS to IP address
|
||||||
|
InetAddress address = InetAddress.getByName(host);
|
||||||
|
|
||||||
|
// Check for local addresses
|
||||||
|
return address.isAnyLocalAddress() || // Matches 0.0.0.0 or similar
|
||||||
|
address.isLoopbackAddress() || // Matches 127.0.0.1 or ::1
|
||||||
|
address.isSiteLocalAddress() || // Matches private IPv4 ranges: 192.168.x.x, 10.x.x.x, 172.16.x.x to 172.31.x.x
|
||||||
|
address.getHostAddress().startsWith("fe80:"); // Matches link-local IPv6 addresses
|
||||||
|
} catch (Exception e) {
|
||||||
|
return false; // Return false for invalid or unresolved addresses
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -289,6 +319,10 @@ public class GeneralUtils {
|
|||||||
saveKeyToConfig(id, key, true);
|
saveKeyToConfig(id, key, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void saveKeyToConfig(String id, boolean key) throws IOException {
|
||||||
|
saveKeyToConfig(id, key, true);
|
||||||
|
}
|
||||||
|
|
||||||
public static void saveKeyToConfig(String id, String key, boolean autoGenerated)
|
public static void saveKeyToConfig(String id, String key, boolean autoGenerated)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
Path path = Paths.get("configs", "settings.yml"); // Target the configs/settings.yml
|
Path path = Paths.get("configs", "settings.yml"); // Target the configs/settings.yml
|
||||||
@@ -307,6 +341,24 @@ public class GeneralUtils {
|
|||||||
settingsYml.save();
|
settingsYml.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void saveKeyToConfig(String id, boolean key, boolean autoGenerated)
|
||||||
|
throws IOException {
|
||||||
|
Path path = Paths.get("configs", "settings.yml");
|
||||||
|
|
||||||
|
final YamlFile settingsYml = new YamlFile(path.toFile());
|
||||||
|
DumperOptions yamlOptionssettingsYml =
|
||||||
|
((SimpleYamlImplementation) settingsYml.getImplementation()).getDumperOptions();
|
||||||
|
yamlOptionssettingsYml.setSplitLines(false);
|
||||||
|
|
||||||
|
settingsYml.loadWithComments();
|
||||||
|
|
||||||
|
YamlFileWrapper writer = settingsYml.path(id).set(key);
|
||||||
|
if (autoGenerated) {
|
||||||
|
writer.comment("# Automatically Generated Settings (Do Not Edit Directly)");
|
||||||
|
}
|
||||||
|
settingsYml.save();
|
||||||
|
}
|
||||||
|
|
||||||
public static String generateMachineFingerprint() {
|
public static String generateMachineFingerprint() {
|
||||||
try {
|
try {
|
||||||
// Get the MAC address
|
// Get the MAC address
|
||||||
@@ -349,4 +401,33 @@ public class GeneralUtils {
|
|||||||
return "GenericID";
|
return "GenericID";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean isVersionHigher(String currentVersion, String compareVersion) {
|
||||||
|
if (currentVersion == null || compareVersion == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Split versions into components
|
||||||
|
String[] current = currentVersion.split("\\.");
|
||||||
|
String[] compare = compareVersion.split("\\.");
|
||||||
|
|
||||||
|
// Get the length of the shorter version array
|
||||||
|
int length = Math.min(current.length, compare.length);
|
||||||
|
|
||||||
|
// Compare each component
|
||||||
|
for (int i = 0; i < length; i++) {
|
||||||
|
int currentPart = Integer.parseInt(current[i]);
|
||||||
|
int comparePart = Integer.parseInt(compare[i]);
|
||||||
|
|
||||||
|
if (currentPart > comparePart) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (currentPart < comparePart) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If all components so far are equal, the longer version is considered higher
|
||||||
|
return current.length > compare.length;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package stirling.software.SPDF.utils.propertyeditor;
|
||||||
|
|
||||||
|
import java.beans.PropertyEditorSupport;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.type.TypeReference;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
|
||||||
|
public class StringToMapPropertyEditor extends PropertyEditorSupport {
|
||||||
|
|
||||||
|
private final ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setAsText(String text) throws IllegalArgumentException {
|
||||||
|
try {
|
||||||
|
TypeReference<HashMap<String, String>> typeRef =
|
||||||
|
new TypeReference<HashMap<String, String>>() {};
|
||||||
|
Map<String, String> map = objectMapper.readValue(text, typeRef);
|
||||||
|
setValue(map);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"Failed to convert java.lang.String to java.util.Map");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,6 +3,10 @@ multipart.enabled=true
|
|||||||
logging.level.org.springframework=WARN
|
logging.level.org.springframework=WARN
|
||||||
logging.level.org.hibernate=WARN
|
logging.level.org.hibernate=WARN
|
||||||
logging.level.org.eclipse.jetty=WARN
|
logging.level.org.eclipse.jetty=WARN
|
||||||
|
#logging.level.org.springframework.security.saml2=TRACE
|
||||||
|
#logging.level.org.springframework.security=DEBUG
|
||||||
|
#logging.level.org.opensaml=DEBUG
|
||||||
|
#logging.level.stirling.software.SPDF.config.security: DEBUG
|
||||||
logging.level.com.zaxxer.hikari=WARN
|
logging.level.com.zaxxer.hikari=WARN
|
||||||
|
|
||||||
spring.jpa.open-in-view=false
|
spring.jpa.open-in-view=false
|
||||||
@@ -27,6 +31,8 @@ server.servlet.context-path=${SYSTEM_ROOTURIPATH:/}
|
|||||||
|
|
||||||
spring.devtools.restart.enabled=true
|
spring.devtools.restart.enabled=true
|
||||||
spring.devtools.livereload.enabled=true
|
spring.devtools.livereload.enabled=true
|
||||||
|
spring.devtools.restart.exclude=stirling.software.SPDF.config.security/**
|
||||||
|
|
||||||
spring.thymeleaf.encoding=UTF-8
|
spring.thymeleaf.encoding=UTF-8
|
||||||
|
|
||||||
spring.web.resources.mime-mappings.webmanifest=application/manifest+json
|
spring.web.resources.mime-mappings.webmanifest=application/manifest+json
|
||||||
|
|||||||
25972
src/main/resources/certdata.txt
Normal file
25972
src/main/resources/certdata.txt
Normal file
File diff suppressed because it is too large
Load Diff
@@ -512,6 +512,10 @@ home.splitPdfByChapters.title=تجزئة المستندات PDF حسب الفص
|
|||||||
home.splitPdfByChapters.desc=قسم مستند PDF إلى ملفات متعددة بناءً على هيكل فصوله.
|
home.splitPdfByChapters.desc=قسم مستند PDF إلى ملفات متعددة بناءً على هيكل فصوله.
|
||||||
splitPdfByChapters.tags=تجزئة، فصول، علامات تبويب، تنظيم
|
splitPdfByChapters.tags=تجزئة، فصول، علامات تبويب، تنظيم
|
||||||
|
|
||||||
|
home.validateSignature.title=Validate PDF Signature
|
||||||
|
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
|
||||||
|
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
|
||||||
|
|
||||||
#replace-invert-color
|
#replace-invert-color
|
||||||
replace-color.title=إستبدال-عكس اللون
|
replace-color.title=إستبدال-عكس اللون
|
||||||
replace-color.header=استبدال-عكس لون PDF
|
replace-color.header=استبدال-عكس لون PDF
|
||||||
@@ -961,6 +965,16 @@ multiTool.dragDropMessage=الصفحات المحددة
|
|||||||
multiTool.undo=تراجع
|
multiTool.undo=تراجع
|
||||||
multiTool.redo=إعادة إجراء
|
multiTool.redo=إعادة إجراء
|
||||||
|
|
||||||
|
#decrypt
|
||||||
|
decrypt.passwordPrompt=This file is password-protected. Please enter the password:
|
||||||
|
decrypt.cancelled=Operation cancelled for PDF: {0}
|
||||||
|
decrypt.noPassword=No password provided for encrypted PDF: {0}
|
||||||
|
decrypt.invalidPassword=Please try again with the correct password.
|
||||||
|
decrypt.invalidPasswordHeader=Incorrect password or unsupported encryption for PDF: {0}
|
||||||
|
decrypt.unexpectedError=There was an error processing the file. Please try again.
|
||||||
|
decrypt.serverError=Server error while decrypting: {0}
|
||||||
|
decrypt.success=File decrypted successfully.
|
||||||
|
|
||||||
#multiTool-advert
|
#multiTool-advert
|
||||||
multiTool-advert.message=هذه الميزة متوفرة في <a href="{0}">صفحة الأدوات المتعددة</a> لدينا. اطلع عليها للحصول على واجهة مستخدم محسّنة لكل صفحة وميزات إضافية!
|
multiTool-advert.message=هذه الميزة متوفرة في <a href="{0}">صفحة الأدوات المتعددة</a> لدينا. اطلع عليها للحصول على واجهة مستخدم محسّنة لكل صفحة وميزات إضافية!
|
||||||
|
|
||||||
@@ -1052,6 +1066,7 @@ addPassword.submit=تشفير
|
|||||||
#watermark
|
#watermark
|
||||||
watermark.title=إضافة علامة مائية
|
watermark.title=إضافة علامة مائية
|
||||||
watermark.header=إضافة علامة مائية
|
watermark.header=إضافة علامة مائية
|
||||||
|
watermark.customColor=لون نص مخصص
|
||||||
watermark.selectText.1=حدد PDF لإضافة العلامة المائية إليه:
|
watermark.selectText.1=حدد PDF لإضافة العلامة المائية إليه:
|
||||||
watermark.selectText.2=نص العلامة المائية:
|
watermark.selectText.2=نص العلامة المائية:
|
||||||
watermark.selectText.3=حجم الخط:
|
watermark.selectText.3=حجم الخط:
|
||||||
@@ -1263,6 +1278,11 @@ splitByChapters.desc.3=تمثيل البيانات الأصلية: إذا تم
|
|||||||
splitByChapters.desc.4=سماح بالتكرار: إذا تم اختياره، يسمح بوجود معاينات متعددة في الصفحة نفسها لخلق ملفات PDF منفصلة.
|
splitByChapters.desc.4=سماح بالتكرار: إذا تم اختياره، يسمح بوجود معاينات متعددة في الصفحة نفسها لخلق ملفات PDF منفصلة.
|
||||||
splitByChapters.submit=تقطيع ملف PDF
|
splitByChapters.submit=تقطيع ملف PDF
|
||||||
|
|
||||||
|
#File Chooser
|
||||||
|
fileChooser.click=انقر هنا
|
||||||
|
fileChooser.or=أو
|
||||||
|
fileChooser.dragAndDrop=قم بسحب الملفات وإفلاتها
|
||||||
|
fileChooser.hoveredDragAndDrop=قم بسحب المفات وإفلاتها هنا
|
||||||
|
|
||||||
#release notes
|
#release notes
|
||||||
releases.footer=Releases
|
releases.footer=Releases
|
||||||
@@ -1270,3 +1290,38 @@ releases.title=Release Notes
|
|||||||
releases.header=Release Notes
|
releases.header=Release Notes
|
||||||
releases.current.version=Current Release
|
releases.current.version=Current Release
|
||||||
releases.note=Release notes are only available in English
|
releases.note=Release notes are only available in English
|
||||||
|
|
||||||
|
#Validate Signature
|
||||||
|
validateSignature.title=Validate PDF Signatures
|
||||||
|
validateSignature.header=Validate Digital Signatures
|
||||||
|
validateSignature.selectPDF=Select signed PDF file
|
||||||
|
validateSignature.submit=Validate Signatures
|
||||||
|
validateSignature.results=Validation Results
|
||||||
|
validateSignature.status=Status
|
||||||
|
validateSignature.signer=Signer
|
||||||
|
validateSignature.date=Date
|
||||||
|
validateSignature.reason=Reason
|
||||||
|
validateSignature.location=Location
|
||||||
|
validateSignature.noSignatures=No digital signatures found in this document
|
||||||
|
validateSignature.status.valid=Valid
|
||||||
|
validateSignature.status.invalid=Invalid
|
||||||
|
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
|
||||||
|
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
|
||||||
|
validateSignature.cert.expired=Certificate has expired
|
||||||
|
validateSignature.cert.revoked=Certificate has been revoked
|
||||||
|
validateSignature.signature.info=Signature Information
|
||||||
|
validateSignature.signature=Signature
|
||||||
|
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
|
||||||
|
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
|
||||||
|
validateSignature.cert.info=Certificate Details
|
||||||
|
validateSignature.cert.issuer=Issuer
|
||||||
|
validateSignature.cert.subject=Subject
|
||||||
|
validateSignature.cert.serialNumber=Serial Number
|
||||||
|
validateSignature.cert.validFrom=Valid From
|
||||||
|
validateSignature.cert.validUntil=Valid Until
|
||||||
|
validateSignature.cert.algorithm=Algorithm
|
||||||
|
validateSignature.cert.keySize=Key Size
|
||||||
|
validateSignature.cert.version=Version
|
||||||
|
validateSignature.cert.keyUsage=Key Usage
|
||||||
|
validateSignature.cert.selfSigned=Self-Signed
|
||||||
|
validateSignature.cert.bits=bits
|
||||||
|
|||||||
@@ -512,6 +512,10 @@ home.splitPdfByChapters.title=PDF-i Fəsillərə Əsasən Böl
|
|||||||
home.splitPdfByChapters.desc=Fəsil strukturuna əsasən PDF-i bir neçə fayla böl.
|
home.splitPdfByChapters.desc=Fəsil strukturuna əsasən PDF-i bir neçə fayla böl.
|
||||||
splitPdfByChapters.tags=böl,fəsillər,əlfəcinlər,nizamla
|
splitPdfByChapters.tags=böl,fəsillər,əlfəcinlər,nizamla
|
||||||
|
|
||||||
|
home.validateSignature.title=Validate PDF Signature
|
||||||
|
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
|
||||||
|
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
|
||||||
|
|
||||||
#replace-invert-color
|
#replace-invert-color
|
||||||
replace-color.title=Qabaqcıl Rəng Seçimləri
|
replace-color.title=Qabaqcıl Rəng Seçimləri
|
||||||
replace-color.header=PDF-də Rəngləri Dəyiş-Tərsinə Çevir
|
replace-color.header=PDF-də Rəngləri Dəyiş-Tərsinə Çevir
|
||||||
@@ -961,6 +965,16 @@ multiTool.dragDropMessage=Seçilmiş Səhifə(lər)
|
|||||||
multiTool.undo=Undo
|
multiTool.undo=Undo
|
||||||
multiTool.redo=Redo
|
multiTool.redo=Redo
|
||||||
|
|
||||||
|
#decrypt
|
||||||
|
decrypt.passwordPrompt=This file is password-protected. Please enter the password:
|
||||||
|
decrypt.cancelled=Operation cancelled for PDF: {0}
|
||||||
|
decrypt.noPassword=No password provided for encrypted PDF: {0}
|
||||||
|
decrypt.invalidPassword=Please try again with the correct password.
|
||||||
|
decrypt.invalidPasswordHeader=Incorrect password or unsupported encryption for PDF: {0}
|
||||||
|
decrypt.unexpectedError=There was an error processing the file. Please try again.
|
||||||
|
decrypt.serverError=Server error while decrypting: {0}
|
||||||
|
decrypt.success=File decrypted successfully.
|
||||||
|
|
||||||
#multiTool-advert
|
#multiTool-advert
|
||||||
multiTool-advert.message=Bu xüsusiyyət bizim <a href="{0}">multi-alət səhifə</a>mizdə də mövcuddur. Əlavə xüsusiyyətlər və səhifə-səhifə interfeys üçün sınaqdan keçirin!
|
multiTool-advert.message=Bu xüsusiyyət bizim <a href="{0}">multi-alət səhifə</a>mizdə də mövcuddur. Əlavə xüsusiyyətlər və səhifə-səhifə interfeys üçün sınaqdan keçirin!
|
||||||
|
|
||||||
@@ -1052,6 +1066,7 @@ addPassword.submit=Şifrlə
|
|||||||
#watermark
|
#watermark
|
||||||
watermark.title=Watermark Əlavə Et
|
watermark.title=Watermark Əlavə Et
|
||||||
watermark.header=Watermark Əlavə Et
|
watermark.header=Watermark Əlavə Et
|
||||||
|
watermark.customColor=Fərdi Mətn Rəngi
|
||||||
watermark.selectText.1=Watermark əlavə olunacaq PDF-i seç
|
watermark.selectText.1=Watermark əlavə olunacaq PDF-i seç
|
||||||
watermark.selectText.2=Watermark Mətni:
|
watermark.selectText.2=Watermark Mətni:
|
||||||
watermark.selectText.3=Şrift Ölçüsü:
|
watermark.selectText.3=Şrift Ölçüsü:
|
||||||
@@ -1263,6 +1278,11 @@ splitByChapters.desc.3=Metadatanı daxil edin: Əgər yoxlanılıbsa, orijinal P
|
|||||||
splitByChapters.desc.4=Allow Duplicates: Dublikatlara icazə verin: Əgər işarələnərsə, eyni səhifədə birdən çox bookmarka ayrı-ayrı PDF sənədləri yaratmağa icazə verin.
|
splitByChapters.desc.4=Allow Duplicates: Dublikatlara icazə verin: Əgər işarələnərsə, eyni səhifədə birdən çox bookmarka ayrı-ayrı PDF sənədləri yaratmağa icazə verin.
|
||||||
splitByChapters.submit=PDF-i Ayır
|
splitByChapters.submit=PDF-i Ayır
|
||||||
|
|
||||||
|
#File Chooser
|
||||||
|
fileChooser.click=Click
|
||||||
|
fileChooser.or=or
|
||||||
|
fileChooser.dragAndDrop=Drag & Drop
|
||||||
|
fileChooser.hoveredDragAndDrop=Drag & Drop file(s) here
|
||||||
|
|
||||||
#release notes
|
#release notes
|
||||||
releases.footer=Buraxılışlar
|
releases.footer=Buraxılışlar
|
||||||
@@ -1270,3 +1290,38 @@ releases.title=Buraxılış Qeydləri
|
|||||||
releases.header=Buraxılış Qeydləri
|
releases.header=Buraxılış Qeydləri
|
||||||
releases.current.version=Hazırki Buraxılış
|
releases.current.version=Hazırki Buraxılış
|
||||||
releases.note=Buraxılış Qeydləri yalnız ingiliscə mövcuddur
|
releases.note=Buraxılış Qeydləri yalnız ingiliscə mövcuddur
|
||||||
|
|
||||||
|
#Validate Signature
|
||||||
|
validateSignature.title=Validate PDF Signatures
|
||||||
|
validateSignature.header=Validate Digital Signatures
|
||||||
|
validateSignature.selectPDF=Select signed PDF file
|
||||||
|
validateSignature.submit=Validate Signatures
|
||||||
|
validateSignature.results=Validation Results
|
||||||
|
validateSignature.status=Status
|
||||||
|
validateSignature.signer=Signer
|
||||||
|
validateSignature.date=Date
|
||||||
|
validateSignature.reason=Reason
|
||||||
|
validateSignature.location=Location
|
||||||
|
validateSignature.noSignatures=No digital signatures found in this document
|
||||||
|
validateSignature.status.valid=Valid
|
||||||
|
validateSignature.status.invalid=Invalid
|
||||||
|
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
|
||||||
|
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
|
||||||
|
validateSignature.cert.expired=Certificate has expired
|
||||||
|
validateSignature.cert.revoked=Certificate has been revoked
|
||||||
|
validateSignature.signature.info=Signature Information
|
||||||
|
validateSignature.signature=Signature
|
||||||
|
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
|
||||||
|
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
|
||||||
|
validateSignature.cert.info=Certificate Details
|
||||||
|
validateSignature.cert.issuer=Issuer
|
||||||
|
validateSignature.cert.subject=Subject
|
||||||
|
validateSignature.cert.serialNumber=Serial Number
|
||||||
|
validateSignature.cert.validFrom=Valid From
|
||||||
|
validateSignature.cert.validUntil=Valid Until
|
||||||
|
validateSignature.cert.algorithm=Algorithm
|
||||||
|
validateSignature.cert.keySize=Key Size
|
||||||
|
validateSignature.cert.version=Version
|
||||||
|
validateSignature.cert.keyUsage=Key Usage
|
||||||
|
validateSignature.cert.selfSigned=Self-Signed
|
||||||
|
validateSignature.cert.bits=bits
|
||||||
|
|||||||
@@ -512,6 +512,10 @@ home.splitPdfByChapters.title=Разделете PDF по глави
|
|||||||
home.splitPdfByChapters.desc=Разделете PDF на множество файлове въз основа на неговата структура на глави.
|
home.splitPdfByChapters.desc=Разделете PDF на множество файлове въз основа на неговата структура на глави.
|
||||||
splitPdfByChapters.tags=разделяне, глави, отметки, организиране
|
splitPdfByChapters.tags=разделяне, глави, отметки, организиране
|
||||||
|
|
||||||
|
home.validateSignature.title=Validate PDF Signature
|
||||||
|
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
|
||||||
|
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
|
||||||
|
|
||||||
#replace-invert-color
|
#replace-invert-color
|
||||||
replace-color.title=Замени-инвертиране-на-цвят
|
replace-color.title=Замени-инвертиране-на-цвят
|
||||||
replace-color.header=Замяна-инвертиране на цвят PDF
|
replace-color.header=Замяна-инвертиране на цвят PDF
|
||||||
@@ -961,6 +965,16 @@ multiTool.dragDropMessage=Page(s) Selected
|
|||||||
multiTool.undo=Undo
|
multiTool.undo=Undo
|
||||||
multiTool.redo=Redo
|
multiTool.redo=Redo
|
||||||
|
|
||||||
|
#decrypt
|
||||||
|
decrypt.passwordPrompt=This file is password-protected. Please enter the password:
|
||||||
|
decrypt.cancelled=Operation cancelled for PDF: {0}
|
||||||
|
decrypt.noPassword=No password provided for encrypted PDF: {0}
|
||||||
|
decrypt.invalidPassword=Please try again with the correct password.
|
||||||
|
decrypt.invalidPasswordHeader=Incorrect password or unsupported encryption for PDF: {0}
|
||||||
|
decrypt.unexpectedError=There was an error processing the file. Please try again.
|
||||||
|
decrypt.serverError=Server error while decrypting: {0}
|
||||||
|
decrypt.success=File decrypted successfully.
|
||||||
|
|
||||||
#multiTool-advert
|
#multiTool-advert
|
||||||
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
||||||
|
|
||||||
@@ -1052,6 +1066,7 @@ addPassword.submit=Шифроване
|
|||||||
#watermark
|
#watermark
|
||||||
watermark.title=Добавяне на воден знак
|
watermark.title=Добавяне на воден знак
|
||||||
watermark.header=Добавяне на воден знак
|
watermark.header=Добавяне на воден знак
|
||||||
|
watermark.customColor=Персонализиран цвят на текста
|
||||||
watermark.selectText.1=Изберете PDF, към който да добавите воден знак:
|
watermark.selectText.1=Изберете PDF, към който да добавите воден знак:
|
||||||
watermark.selectText.2=Текст на воден знак:
|
watermark.selectText.2=Текст на воден знак:
|
||||||
watermark.selectText.3=Размер на шрифта:
|
watermark.selectText.3=Размер на шрифта:
|
||||||
@@ -1263,6 +1278,11 @@ splitByChapters.desc.3=Включване на метаданни: Ако е о
|
|||||||
splitByChapters.desc.4=Разрешаване на дубликати: Ако е отметнато, позволява множество отметки на една и съща страница за създаване на отделни PDF файлове.
|
splitByChapters.desc.4=Разрешаване на дубликати: Ако е отметнато, позволява множество отметки на една и съща страница за създаване на отделни PDF файлове.
|
||||||
splitByChapters.submit=Разделяне на PDF
|
splitByChapters.submit=Разделяне на PDF
|
||||||
|
|
||||||
|
#File Chooser
|
||||||
|
fileChooser.click=Click
|
||||||
|
fileChooser.or=or
|
||||||
|
fileChooser.dragAndDrop=Drag & Drop
|
||||||
|
fileChooser.hoveredDragAndDrop=Drag & Drop file(s) here
|
||||||
|
|
||||||
#release notes
|
#release notes
|
||||||
releases.footer=Releases
|
releases.footer=Releases
|
||||||
@@ -1270,3 +1290,38 @@ releases.title=Release Notes
|
|||||||
releases.header=Release Notes
|
releases.header=Release Notes
|
||||||
releases.current.version=Current Release
|
releases.current.version=Current Release
|
||||||
releases.note=Release notes are only available in English
|
releases.note=Release notes are only available in English
|
||||||
|
|
||||||
|
#Validate Signature
|
||||||
|
validateSignature.title=Validate PDF Signatures
|
||||||
|
validateSignature.header=Validate Digital Signatures
|
||||||
|
validateSignature.selectPDF=Select signed PDF file
|
||||||
|
validateSignature.submit=Validate Signatures
|
||||||
|
validateSignature.results=Validation Results
|
||||||
|
validateSignature.status=Status
|
||||||
|
validateSignature.signer=Signer
|
||||||
|
validateSignature.date=Date
|
||||||
|
validateSignature.reason=Reason
|
||||||
|
validateSignature.location=Location
|
||||||
|
validateSignature.noSignatures=No digital signatures found in this document
|
||||||
|
validateSignature.status.valid=Valid
|
||||||
|
validateSignature.status.invalid=Invalid
|
||||||
|
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
|
||||||
|
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
|
||||||
|
validateSignature.cert.expired=Certificate has expired
|
||||||
|
validateSignature.cert.revoked=Certificate has been revoked
|
||||||
|
validateSignature.signature.info=Signature Information
|
||||||
|
validateSignature.signature=Signature
|
||||||
|
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
|
||||||
|
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
|
||||||
|
validateSignature.cert.info=Certificate Details
|
||||||
|
validateSignature.cert.issuer=Issuer
|
||||||
|
validateSignature.cert.subject=Subject
|
||||||
|
validateSignature.cert.serialNumber=Serial Number
|
||||||
|
validateSignature.cert.validFrom=Valid From
|
||||||
|
validateSignature.cert.validUntil=Valid Until
|
||||||
|
validateSignature.cert.algorithm=Algorithm
|
||||||
|
validateSignature.cert.keySize=Key Size
|
||||||
|
validateSignature.cert.version=Version
|
||||||
|
validateSignature.cert.keyUsage=Key Usage
|
||||||
|
validateSignature.cert.selfSigned=Self-Signed
|
||||||
|
validateSignature.cert.bits=bits
|
||||||
|
|||||||
@@ -512,6 +512,10 @@ home.splitPdfByChapters.title=Divideix PDF per Capítols
|
|||||||
home.splitPdfByChapters.desc=Divideix un PDF en múltiples fitxers segons la seva estructura de capítols.
|
home.splitPdfByChapters.desc=Divideix un PDF en múltiples fitxers segons la seva estructura de capítols.
|
||||||
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
||||||
|
|
||||||
|
home.validateSignature.title=Validate PDF Signature
|
||||||
|
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
|
||||||
|
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
|
||||||
|
|
||||||
#replace-invert-color
|
#replace-invert-color
|
||||||
replace-color.title=Reemplaça-Inverteix-Color
|
replace-color.title=Reemplaça-Inverteix-Color
|
||||||
replace-color.header=Reemplaça-Inverteix Color en PDF
|
replace-color.header=Reemplaça-Inverteix Color en PDF
|
||||||
@@ -961,6 +965,16 @@ multiTool.dragDropMessage=Page(s) Selected
|
|||||||
multiTool.undo=Undo
|
multiTool.undo=Undo
|
||||||
multiTool.redo=Redo
|
multiTool.redo=Redo
|
||||||
|
|
||||||
|
#decrypt
|
||||||
|
decrypt.passwordPrompt=This file is password-protected. Please enter the password:
|
||||||
|
decrypt.cancelled=Operation cancelled for PDF: {0}
|
||||||
|
decrypt.noPassword=No password provided for encrypted PDF: {0}
|
||||||
|
decrypt.invalidPassword=Please try again with the correct password.
|
||||||
|
decrypt.invalidPasswordHeader=Incorrect password or unsupported encryption for PDF: {0}
|
||||||
|
decrypt.unexpectedError=There was an error processing the file. Please try again.
|
||||||
|
decrypt.serverError=Server error while decrypting: {0}
|
||||||
|
decrypt.success=File decrypted successfully.
|
||||||
|
|
||||||
#multiTool-advert
|
#multiTool-advert
|
||||||
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
||||||
|
|
||||||
@@ -1052,6 +1066,7 @@ addPassword.submit=Encripta
|
|||||||
#watermark
|
#watermark
|
||||||
watermark.title=Afegir Marca d'Aigua
|
watermark.title=Afegir Marca d'Aigua
|
||||||
watermark.header=Afegir Marca d'Aigua
|
watermark.header=Afegir Marca d'Aigua
|
||||||
|
watermark.customColor=Color de Text Personalitzat
|
||||||
watermark.selectText.1=Selecciona el PDF per afegir la Marca d'Aigua:
|
watermark.selectText.1=Selecciona el PDF per afegir la Marca d'Aigua:
|
||||||
watermark.selectText.2=Text de la Marca d'Aigua
|
watermark.selectText.2=Text de la Marca d'Aigua
|
||||||
watermark.selectText.3=Mida de la Font:
|
watermark.selectText.3=Mida de la Font:
|
||||||
@@ -1263,6 +1278,11 @@ splitByChapters.desc.3=Incloure Metadades: Si està marcat, les metadades del PD
|
|||||||
splitByChapters.desc.4=Permetre Duplicats: Si està marcat, permet diversos marcadors a la mateixa pàgina per crear PDFs separats.
|
splitByChapters.desc.4=Permetre Duplicats: Si està marcat, permet diversos marcadors a la mateixa pàgina per crear PDFs separats.
|
||||||
splitByChapters.submit=Divideix PDF
|
splitByChapters.submit=Divideix PDF
|
||||||
|
|
||||||
|
#File Chooser
|
||||||
|
fileChooser.click=Click
|
||||||
|
fileChooser.or=or
|
||||||
|
fileChooser.dragAndDrop=Drag & Drop
|
||||||
|
fileChooser.hoveredDragAndDrop=Drag & Drop file(s) here
|
||||||
|
|
||||||
#release notes
|
#release notes
|
||||||
releases.footer=Releases
|
releases.footer=Releases
|
||||||
@@ -1270,3 +1290,38 @@ releases.title=Release Notes
|
|||||||
releases.header=Release Notes
|
releases.header=Release Notes
|
||||||
releases.current.version=Current Release
|
releases.current.version=Current Release
|
||||||
releases.note=Release notes are only available in English
|
releases.note=Release notes are only available in English
|
||||||
|
|
||||||
|
#Validate Signature
|
||||||
|
validateSignature.title=Validate PDF Signatures
|
||||||
|
validateSignature.header=Validate Digital Signatures
|
||||||
|
validateSignature.selectPDF=Select signed PDF file
|
||||||
|
validateSignature.submit=Validate Signatures
|
||||||
|
validateSignature.results=Validation Results
|
||||||
|
validateSignature.status=Status
|
||||||
|
validateSignature.signer=Signer
|
||||||
|
validateSignature.date=Date
|
||||||
|
validateSignature.reason=Reason
|
||||||
|
validateSignature.location=Location
|
||||||
|
validateSignature.noSignatures=No digital signatures found in this document
|
||||||
|
validateSignature.status.valid=Valid
|
||||||
|
validateSignature.status.invalid=Invalid
|
||||||
|
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
|
||||||
|
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
|
||||||
|
validateSignature.cert.expired=Certificate has expired
|
||||||
|
validateSignature.cert.revoked=Certificate has been revoked
|
||||||
|
validateSignature.signature.info=Signature Information
|
||||||
|
validateSignature.signature=Signature
|
||||||
|
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
|
||||||
|
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
|
||||||
|
validateSignature.cert.info=Certificate Details
|
||||||
|
validateSignature.cert.issuer=Issuer
|
||||||
|
validateSignature.cert.subject=Subject
|
||||||
|
validateSignature.cert.serialNumber=Serial Number
|
||||||
|
validateSignature.cert.validFrom=Valid From
|
||||||
|
validateSignature.cert.validUntil=Valid Until
|
||||||
|
validateSignature.cert.algorithm=Algorithm
|
||||||
|
validateSignature.cert.keySize=Key Size
|
||||||
|
validateSignature.cert.version=Version
|
||||||
|
validateSignature.cert.keyUsage=Key Usage
|
||||||
|
validateSignature.cert.selfSigned=Self-Signed
|
||||||
|
validateSignature.cert.bits=bits
|
||||||
|
|||||||
@@ -512,6 +512,10 @@ home.splitPdfByChapters.title=Rozdělit PDF podle kapitol
|
|||||||
home.splitPdfByChapters.desc=Rozdělit PDF do více souborů na základě jeho struktury kapitol.
|
home.splitPdfByChapters.desc=Rozdělit PDF do více souborů na základě jeho struktury kapitol.
|
||||||
splitPdfByChapters.tags=rozdělení, kapitoly, zápisky, organizace
|
splitPdfByChapters.tags=rozdělení, kapitoly, zápisky, organizace
|
||||||
|
|
||||||
|
home.validateSignature.title=Validate PDF Signature
|
||||||
|
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
|
||||||
|
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
|
||||||
|
|
||||||
#replace-invert-color
|
#replace-invert-color
|
||||||
replace-color.title=Replace-Invert-Color
|
replace-color.title=Replace-Invert-Color
|
||||||
replace-color.header=Nahradit inverzní barvu PDF
|
replace-color.header=Nahradit inverzní barvu PDF
|
||||||
@@ -961,6 +965,16 @@ multiTool.dragDropMessage=Page(s) Selected
|
|||||||
multiTool.undo=Undo
|
multiTool.undo=Undo
|
||||||
multiTool.redo=Redo
|
multiTool.redo=Redo
|
||||||
|
|
||||||
|
#decrypt
|
||||||
|
decrypt.passwordPrompt=This file is password-protected. Please enter the password:
|
||||||
|
decrypt.cancelled=Operation cancelled for PDF: {0}
|
||||||
|
decrypt.noPassword=No password provided for encrypted PDF: {0}
|
||||||
|
decrypt.invalidPassword=Please try again with the correct password.
|
||||||
|
decrypt.invalidPasswordHeader=Incorrect password or unsupported encryption for PDF: {0}
|
||||||
|
decrypt.unexpectedError=There was an error processing the file. Please try again.
|
||||||
|
decrypt.serverError=Server error while decrypting: {0}
|
||||||
|
decrypt.success=File decrypted successfully.
|
||||||
|
|
||||||
#multiTool-advert
|
#multiTool-advert
|
||||||
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
||||||
|
|
||||||
@@ -1052,6 +1066,7 @@ addPassword.submit=Šifrovat
|
|||||||
#watermark
|
#watermark
|
||||||
watermark.title=Přidat vodoznak
|
watermark.title=Přidat vodoznak
|
||||||
watermark.header=Přidat vodoznak
|
watermark.header=Přidat vodoznak
|
||||||
|
watermark.customColor=Vlastní barva textu
|
||||||
watermark.selectText.1=Vyberte PDF, ke kterému chcete přidat vodoznak:
|
watermark.selectText.1=Vyberte PDF, ke kterému chcete přidat vodoznak:
|
||||||
watermark.selectText.2=Text vodoznaku:
|
watermark.selectText.2=Text vodoznaku:
|
||||||
watermark.selectText.3=Velikost písma:
|
watermark.selectText.3=Velikost písma:
|
||||||
@@ -1263,6 +1278,11 @@ splitByChapters.desc.3=Zahrnout metadatů: Pokud je zaškrtnuto, původní metad
|
|||||||
splitByChapters.desc.4=Povolit duplicitní záznamy: Pokud je zaškrtnuto, návštěvníci mohou vytvořit samostatné PDF soubory z více záhlaví na stejné straně.
|
splitByChapters.desc.4=Povolit duplicitní záznamy: Pokud je zaškrtnuto, návštěvníci mohou vytvořit samostatné PDF soubory z více záhlaví na stejné straně.
|
||||||
splitByChapters.submit=Podělit se PDF
|
splitByChapters.submit=Podělit se PDF
|
||||||
|
|
||||||
|
#File Chooser
|
||||||
|
fileChooser.click=Click
|
||||||
|
fileChooser.or=or
|
||||||
|
fileChooser.dragAndDrop=Drag & Drop
|
||||||
|
fileChooser.hoveredDragAndDrop=Drag & Drop file(s) here
|
||||||
|
|
||||||
#release notes
|
#release notes
|
||||||
releases.footer=Releases
|
releases.footer=Releases
|
||||||
@@ -1270,3 +1290,38 @@ releases.title=Release Notes
|
|||||||
releases.header=Release Notes
|
releases.header=Release Notes
|
||||||
releases.current.version=Current Release
|
releases.current.version=Current Release
|
||||||
releases.note=Release notes are only available in English
|
releases.note=Release notes are only available in English
|
||||||
|
|
||||||
|
#Validate Signature
|
||||||
|
validateSignature.title=Validate PDF Signatures
|
||||||
|
validateSignature.header=Validate Digital Signatures
|
||||||
|
validateSignature.selectPDF=Select signed PDF file
|
||||||
|
validateSignature.submit=Validate Signatures
|
||||||
|
validateSignature.results=Validation Results
|
||||||
|
validateSignature.status=Status
|
||||||
|
validateSignature.signer=Signer
|
||||||
|
validateSignature.date=Date
|
||||||
|
validateSignature.reason=Reason
|
||||||
|
validateSignature.location=Location
|
||||||
|
validateSignature.noSignatures=No digital signatures found in this document
|
||||||
|
validateSignature.status.valid=Valid
|
||||||
|
validateSignature.status.invalid=Invalid
|
||||||
|
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
|
||||||
|
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
|
||||||
|
validateSignature.cert.expired=Certificate has expired
|
||||||
|
validateSignature.cert.revoked=Certificate has been revoked
|
||||||
|
validateSignature.signature.info=Signature Information
|
||||||
|
validateSignature.signature=Signature
|
||||||
|
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
|
||||||
|
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
|
||||||
|
validateSignature.cert.info=Certificate Details
|
||||||
|
validateSignature.cert.issuer=Issuer
|
||||||
|
validateSignature.cert.subject=Subject
|
||||||
|
validateSignature.cert.serialNumber=Serial Number
|
||||||
|
validateSignature.cert.validFrom=Valid From
|
||||||
|
validateSignature.cert.validUntil=Valid Until
|
||||||
|
validateSignature.cert.algorithm=Algorithm
|
||||||
|
validateSignature.cert.keySize=Key Size
|
||||||
|
validateSignature.cert.version=Version
|
||||||
|
validateSignature.cert.keyUsage=Key Usage
|
||||||
|
validateSignature.cert.selfSigned=Self-Signed
|
||||||
|
validateSignature.cert.bits=bits
|
||||||
|
|||||||
@@ -512,6 +512,10 @@ home.splitPdfByChapters.title=Partitioner PDF efter kapitler
|
|||||||
home.splitPdfByChapters.desc=Partitioner en PDF i flere filer baseret på dens kapitelstruktur.
|
home.splitPdfByChapters.desc=Partitioner en PDF i flere filer baseret på dens kapitelstruktur.
|
||||||
splitPdfByChapters.tags=partitionering,kapitler,merker,organisering
|
splitPdfByChapters.tags=partitionering,kapitler,merker,organisering
|
||||||
|
|
||||||
|
home.validateSignature.title=Validate PDF Signature
|
||||||
|
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
|
||||||
|
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
|
||||||
|
|
||||||
#replace-invert-color
|
#replace-invert-color
|
||||||
replace-color.title=Replace-Invert-Color
|
replace-color.title=Replace-Invert-Color
|
||||||
replace-color.header=Erstat-omgivende Farve PDF
|
replace-color.header=Erstat-omgivende Farve PDF
|
||||||
@@ -961,6 +965,16 @@ multiTool.dragDropMessage=Page(s) Selected
|
|||||||
multiTool.undo=Undo
|
multiTool.undo=Undo
|
||||||
multiTool.redo=Redo
|
multiTool.redo=Redo
|
||||||
|
|
||||||
|
#decrypt
|
||||||
|
decrypt.passwordPrompt=This file is password-protected. Please enter the password:
|
||||||
|
decrypt.cancelled=Operation cancelled for PDF: {0}
|
||||||
|
decrypt.noPassword=No password provided for encrypted PDF: {0}
|
||||||
|
decrypt.invalidPassword=Please try again with the correct password.
|
||||||
|
decrypt.invalidPasswordHeader=Incorrect password or unsupported encryption for PDF: {0}
|
||||||
|
decrypt.unexpectedError=There was an error processing the file. Please try again.
|
||||||
|
decrypt.serverError=Server error while decrypting: {0}
|
||||||
|
decrypt.success=File decrypted successfully.
|
||||||
|
|
||||||
#multiTool-advert
|
#multiTool-advert
|
||||||
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
||||||
|
|
||||||
@@ -1052,6 +1066,7 @@ addPassword.submit=Kryptér
|
|||||||
#watermark
|
#watermark
|
||||||
watermark.title=Tilføj Vandmærke
|
watermark.title=Tilføj Vandmærke
|
||||||
watermark.header=Tilføj Vandmærke
|
watermark.header=Tilføj Vandmærke
|
||||||
|
watermark.customColor=Brugerdefineret Tekstfarve
|
||||||
watermark.selectText.1=Vælg PDF til at tilføje vandmærke:
|
watermark.selectText.1=Vælg PDF til at tilføje vandmærke:
|
||||||
watermark.selectText.2=Vandmærketekst:
|
watermark.selectText.2=Vandmærketekst:
|
||||||
watermark.selectText.3=Skriftstørrelse:
|
watermark.selectText.3=Skriftstørrelse:
|
||||||
@@ -1263,6 +1278,11 @@ splitByChapters.desc.3=Inkluder metadata: Hvis markeret, vil den originale PDF's
|
|||||||
splitByChapters.desc.4=Tillad duplikater: Hvis markeret, tillader det flere bogmærker på samme side til at oprette separate PDF'er.
|
splitByChapters.desc.4=Tillad duplikater: Hvis markeret, tillader det flere bogmærker på samme side til at oprette separate PDF'er.
|
||||||
splitByChapters.submit=Splitter PDF
|
splitByChapters.submit=Splitter PDF
|
||||||
|
|
||||||
|
#File Chooser
|
||||||
|
fileChooser.click=Click
|
||||||
|
fileChooser.or=or
|
||||||
|
fileChooser.dragAndDrop=Drag & Drop
|
||||||
|
fileChooser.hoveredDragAndDrop=Drag & Drop file(s) here
|
||||||
|
|
||||||
#release notes
|
#release notes
|
||||||
releases.footer=Releases
|
releases.footer=Releases
|
||||||
@@ -1270,3 +1290,38 @@ releases.title=Release Notes
|
|||||||
releases.header=Release Notes
|
releases.header=Release Notes
|
||||||
releases.current.version=Current Release
|
releases.current.version=Current Release
|
||||||
releases.note=Release notes are only available in English
|
releases.note=Release notes are only available in English
|
||||||
|
|
||||||
|
#Validate Signature
|
||||||
|
validateSignature.title=Validate PDF Signatures
|
||||||
|
validateSignature.header=Validate Digital Signatures
|
||||||
|
validateSignature.selectPDF=Select signed PDF file
|
||||||
|
validateSignature.submit=Validate Signatures
|
||||||
|
validateSignature.results=Validation Results
|
||||||
|
validateSignature.status=Status
|
||||||
|
validateSignature.signer=Signer
|
||||||
|
validateSignature.date=Date
|
||||||
|
validateSignature.reason=Reason
|
||||||
|
validateSignature.location=Location
|
||||||
|
validateSignature.noSignatures=No digital signatures found in this document
|
||||||
|
validateSignature.status.valid=Valid
|
||||||
|
validateSignature.status.invalid=Invalid
|
||||||
|
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
|
||||||
|
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
|
||||||
|
validateSignature.cert.expired=Certificate has expired
|
||||||
|
validateSignature.cert.revoked=Certificate has been revoked
|
||||||
|
validateSignature.signature.info=Signature Information
|
||||||
|
validateSignature.signature=Signature
|
||||||
|
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
|
||||||
|
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
|
||||||
|
validateSignature.cert.info=Certificate Details
|
||||||
|
validateSignature.cert.issuer=Issuer
|
||||||
|
validateSignature.cert.subject=Subject
|
||||||
|
validateSignature.cert.serialNumber=Serial Number
|
||||||
|
validateSignature.cert.validFrom=Valid From
|
||||||
|
validateSignature.cert.validUntil=Valid Until
|
||||||
|
validateSignature.cert.algorithm=Algorithm
|
||||||
|
validateSignature.cert.keySize=Key Size
|
||||||
|
validateSignature.cert.version=Version
|
||||||
|
validateSignature.cert.keyUsage=Key Usage
|
||||||
|
validateSignature.cert.selfSigned=Self-Signed
|
||||||
|
validateSignature.cert.bits=bits
|
||||||
|
|||||||
@@ -146,8 +146,8 @@ navbar.search=Suche
|
|||||||
navbar.sections.organize=Organisieren
|
navbar.sections.organize=Organisieren
|
||||||
navbar.sections.convertTo=In PDF konvertieren
|
navbar.sections.convertTo=In PDF konvertieren
|
||||||
navbar.sections.convertFrom=Konvertieren von PDF
|
navbar.sections.convertFrom=Konvertieren von PDF
|
||||||
navbar.sections.security=Zeichen und Sicherheit
|
navbar.sections.security=Signieren und Sicherheit
|
||||||
navbar.sections.advance=Fortschrittlich
|
navbar.sections.advance=Erweiterte Funktionen
|
||||||
navbar.sections.edit=Anzeigen und Bearbeiten
|
navbar.sections.edit=Anzeigen und Bearbeiten
|
||||||
navbar.sections.popular=Beliebt
|
navbar.sections.popular=Beliebt
|
||||||
|
|
||||||
@@ -248,7 +248,7 @@ database.fileNullOrEmpty=Datei darf nicht null oder leer sein
|
|||||||
database.failedImportFile=Dateiimport fehlgeschlagen
|
database.failedImportFile=Dateiimport fehlgeschlagen
|
||||||
|
|
||||||
session.expired=Ihre Sitzung ist abgelaufen. Bitte laden Sie die Seite neu und versuchen Sie es erneut.
|
session.expired=Ihre Sitzung ist abgelaufen. Bitte laden Sie die Seite neu und versuchen Sie es erneut.
|
||||||
session.refreshPage=Refresh Page
|
session.refreshPage=Seite aktualisieren
|
||||||
|
|
||||||
#############
|
#############
|
||||||
# HOME-PAGE #
|
# HOME-PAGE #
|
||||||
@@ -512,6 +512,10 @@ home.splitPdfByChapters.title=PDF-Datei nach Kapiteln aufteilen
|
|||||||
home.splitPdfByChapters.desc=Aufteilung einer PDF-Datei in mehrere Dateien auf Basis der Kapitelstruktur.
|
home.splitPdfByChapters.desc=Aufteilung einer PDF-Datei in mehrere Dateien auf Basis der Kapitelstruktur.
|
||||||
splitPdfByChapters.tags=aufteilen,kapitel,lesezeichen,organisieren
|
splitPdfByChapters.tags=aufteilen,kapitel,lesezeichen,organisieren
|
||||||
|
|
||||||
|
home.validateSignature.title=PDF-Signatur überprüfen
|
||||||
|
home.validateSignature.desc=Digitale Signaturen und Zertifikate in PDF-Dokumenten überprüfen
|
||||||
|
validateSignature.tags=signature,verify,validate,pdf,digitale signatur,signatur validieren,überprüfen,Zertifikat,cert
|
||||||
|
|
||||||
#replace-invert-color
|
#replace-invert-color
|
||||||
replace-color.title=Farbe Ersetzen-Invertieren
|
replace-color.title=Farbe Ersetzen-Invertieren
|
||||||
replace-color.header=Farb-PDF Ersetzen-Invertieren
|
replace-color.header=Farb-PDF Ersetzen-Invertieren
|
||||||
@@ -818,12 +822,12 @@ sign.save=Signature speichern
|
|||||||
sign.personalSigs=Persönliche Signaturen
|
sign.personalSigs=Persönliche Signaturen
|
||||||
sign.sharedSigs=Geteilte Signaturen
|
sign.sharedSigs=Geteilte Signaturen
|
||||||
sign.noSavedSigs=Es wurden keine gespeicherten Signaturen gefunden
|
sign.noSavedSigs=Es wurden keine gespeicherten Signaturen gefunden
|
||||||
sign.addToAll=Add to all pages
|
sign.addToAll=Zu allen Seiten hinzufügen
|
||||||
sign.delete=Delete
|
sign.delete=Löschen
|
||||||
sign.first=First page
|
sign.first=Erste Seite
|
||||||
sign.last=Last page
|
sign.last=Letzte Seite
|
||||||
sign.next=Next page
|
sign.next=Nächste Seite
|
||||||
sign.previous=Previous page
|
sign.previous=Vorherige Seite
|
||||||
|
|
||||||
#repair
|
#repair
|
||||||
repair.title=Reparieren
|
repair.title=Reparieren
|
||||||
@@ -949,17 +953,27 @@ multiTool.deleteSelected=Auswahl löschen
|
|||||||
multiTool.downloadAll=Downloaden
|
multiTool.downloadAll=Downloaden
|
||||||
multiTool.downloadSelected=Auswahl downloaden
|
multiTool.downloadSelected=Auswahl downloaden
|
||||||
|
|
||||||
multiTool.insertPageBreak=Insert Page Break
|
multiTool.insertPageBreak=Seitenumbruch einfügen
|
||||||
multiTool.addFile=Add File
|
multiTool.addFile=Datei hinzufügen
|
||||||
multiTool.rotateLeft=Rotate Left
|
multiTool.rotateLeft=Nach links drehen
|
||||||
multiTool.rotateRight=Rotate Right
|
multiTool.rotateRight=Nach rechts drehen
|
||||||
multiTool.split=Split
|
multiTool.split=Teilen
|
||||||
multiTool.moveLeft=Move Left
|
multiTool.moveLeft=Nach links verschieben
|
||||||
multiTool.moveRight=Move Right
|
multiTool.moveRight=Nach rechts verschieben
|
||||||
multiTool.delete=Delete
|
multiTool.delete=Löschen
|
||||||
multiTool.dragDropMessage=Page(s) Selected
|
multiTool.dragDropMessage=Ausgewählte Seite(n)
|
||||||
multiTool.undo=Undo
|
multiTool.undo=Rückgängig machen
|
||||||
multiTool.redo=Redo
|
multiTool.redo=Wiederherstellen
|
||||||
|
|
||||||
|
#decrypt
|
||||||
|
decrypt.passwordPrompt=This file is password-protected. Please enter the password:
|
||||||
|
decrypt.cancelled=Operation cancelled for PDF: {0}
|
||||||
|
decrypt.noPassword=No password provided for encrypted PDF: {0}
|
||||||
|
decrypt.invalidPassword=Please try again with the correct password.
|
||||||
|
decrypt.invalidPasswordHeader=Incorrect password or unsupported encryption for PDF: {0}
|
||||||
|
decrypt.unexpectedError=There was an error processing the file. Please try again.
|
||||||
|
decrypt.serverError=Server error while decrypting: {0}
|
||||||
|
decrypt.success=File decrypted successfully.
|
||||||
|
|
||||||
#multiTool-advert
|
#multiTool-advert
|
||||||
multiTool-advert.message=Diese Funktion ist auch auf unserer <a href="{0}">PDF-Multitool-Seite</a> verfügbar. Probieren Sie sie aus, denn sie bietet eine verbesserte Benutzeroberfläche und zusätzliche Funktionen!
|
multiTool-advert.message=Diese Funktion ist auch auf unserer <a href="{0}">PDF-Multitool-Seite</a> verfügbar. Probieren Sie sie aus, denn sie bietet eine verbesserte Benutzeroberfläche und zusätzliche Funktionen!
|
||||||
@@ -1052,6 +1066,7 @@ addPassword.submit=Verschlüsseln
|
|||||||
#watermark
|
#watermark
|
||||||
watermark.title=Wasserzeichen hinzufügen
|
watermark.title=Wasserzeichen hinzufügen
|
||||||
watermark.header=Wasserzeichen hinzufügen
|
watermark.header=Wasserzeichen hinzufügen
|
||||||
|
watermark.customColor=Benutzerdefinierte Textfarbe
|
||||||
watermark.selectText.1=PDF auswählen, dem ein Wasserzeichen hinzugefügt werden soll:
|
watermark.selectText.1=PDF auswählen, dem ein Wasserzeichen hinzugefügt werden soll:
|
||||||
watermark.selectText.2=Wasserzeichen Text:
|
watermark.selectText.2=Wasserzeichen Text:
|
||||||
watermark.selectText.3=Schriftgröße:
|
watermark.selectText.3=Schriftgröße:
|
||||||
@@ -1263,10 +1278,50 @@ splitByChapters.desc.3=Metadaten einschließen: Wenn diese Option aktiviert ist,
|
|||||||
splitByChapters.desc.4=Duplikate erlauben: Wenn diese Option aktiviert ist, können mehrere Lesezeichen auf derselben Seite separate PDF Dateien erstellen.
|
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
|
splitByChapters.submit=PDF teilen
|
||||||
|
|
||||||
|
#File Chooser
|
||||||
|
fileChooser.click=Klicken
|
||||||
|
fileChooser.or=oder
|
||||||
|
fileChooser.dragAndDrop=Drag & Drop
|
||||||
|
fileChooser.hoveredDragAndDrop=Datei(en) hierhin Ziehen & Fallenlassen
|
||||||
|
|
||||||
#release notes
|
#release notes
|
||||||
releases.footer=Releases
|
releases.footer=Veröffentlichungen
|
||||||
releases.title=Release Notes
|
releases.title=Versionshinweise
|
||||||
releases.header=Release Notes
|
releases.header=Versionshinweise
|
||||||
releases.current.version=Current Release
|
releases.current.version=Aktuelle Version
|
||||||
releases.note=Release notes are only available in English
|
releases.note=Versionshinweise sind nur auf Englisch verfügbar
|
||||||
|
|
||||||
|
#Validate Signature
|
||||||
|
validateSignature.title=PDF-Signaturen überprüfen
|
||||||
|
validateSignature.header=Digitale Signaturen überprüfen
|
||||||
|
validateSignature.selectPDF=Signierte PDF-Datei auswählen
|
||||||
|
validateSignature.submit=Signaturen überprüfen
|
||||||
|
validateSignature.results=Gültigkeitsprüfungsergebnisse
|
||||||
|
validateSignature.status=Status
|
||||||
|
validateSignature.signer=Unterzeichner
|
||||||
|
validateSignature.date=Datum
|
||||||
|
validateSignature.reason=Grund
|
||||||
|
validateSignature.location=Ort
|
||||||
|
validateSignature.noSignatures=Keine digitalen Signaturen in diesem Dokument gefunden
|
||||||
|
validateSignature.status.valid=Gültig
|
||||||
|
validateSignature.status.invalid=Ungültig
|
||||||
|
validateSignature.chain.invalid=Zertifikatskettenprüfung fehlgeschlagen - kann die Identität des Unterzeichners nicht verifizieren
|
||||||
|
validateSignature.trust.invalid=Zertifikat nicht im Truststore - Quelle kann nicht verifiziert werden
|
||||||
|
validateSignature.cert.expired=Zertifikat ist abgelaufen
|
||||||
|
validateSignature.cert.revoked=Zertifikat wurde widerrufen
|
||||||
|
validateSignature.signature.info=Signaturinformationen
|
||||||
|
validateSignature.signature=Signatur
|
||||||
|
validateSignature.signature.mathValid=Signatur ist mathematisch gültig ABER:
|
||||||
|
validateSignature.selectCustomCert=Benutzerdefinierte Zertifikatsdatei X.509 (Optional)
|
||||||
|
validateSignature.cert.info=Zertifikat Details
|
||||||
|
validateSignature.cert.issuer=Aussteller
|
||||||
|
validateSignature.cert.subject=Betreff
|
||||||
|
validateSignature.cert.serialNumber=Seriennummer
|
||||||
|
validateSignature.cert.validFrom=Gültig von
|
||||||
|
validateSignature.cert.validUntil=Gültig bis
|
||||||
|
validateSignature.cert.algorithm=Algorithmus
|
||||||
|
validateSignature.cert.keySize=Schlüsselgröße
|
||||||
|
validateSignature.cert.version=Version
|
||||||
|
validateSignature.cert.keyUsage=Schlüsselverwendung
|
||||||
|
validateSignature.cert.selfSigned=Selbstsigniert
|
||||||
|
validateSignature.cert.bits=bits
|
||||||
|
|||||||
@@ -512,6 +512,10 @@ home.splitPdfByChapters.title=Διχοτομία PDF ανά Περιγραφές
|
|||||||
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
||||||
splitPdfByChapters.tags=διχοτομία,περιγραφές,κεφάλαια,συνορία
|
splitPdfByChapters.tags=διχοτομία,περιγραφές,κεφάλαια,συνορία
|
||||||
|
|
||||||
|
home.validateSignature.title=Validate PDF Signature
|
||||||
|
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
|
||||||
|
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
|
||||||
|
|
||||||
#replace-invert-color
|
#replace-invert-color
|
||||||
replace-color.title=Replace-Invert-Color
|
replace-color.title=Replace-Invert-Color
|
||||||
replace-color.header=Αντικατάσταση-Αντίστροφη Παθωμένη Πίντσουρ
|
replace-color.header=Αντικατάσταση-Αντίστροφη Παθωμένη Πίντσουρ
|
||||||
@@ -961,6 +965,16 @@ multiTool.dragDropMessage=Page(s) Selected
|
|||||||
multiTool.undo=Undo
|
multiTool.undo=Undo
|
||||||
multiTool.redo=Redo
|
multiTool.redo=Redo
|
||||||
|
|
||||||
|
#decrypt
|
||||||
|
decrypt.passwordPrompt=This file is password-protected. Please enter the password:
|
||||||
|
decrypt.cancelled=Operation cancelled for PDF: {0}
|
||||||
|
decrypt.noPassword=No password provided for encrypted PDF: {0}
|
||||||
|
decrypt.invalidPassword=Please try again with the correct password.
|
||||||
|
decrypt.invalidPasswordHeader=Incorrect password or unsupported encryption for PDF: {0}
|
||||||
|
decrypt.unexpectedError=There was an error processing the file. Please try again.
|
||||||
|
decrypt.serverError=Server error while decrypting: {0}
|
||||||
|
decrypt.success=File decrypted successfully.
|
||||||
|
|
||||||
#multiTool-advert
|
#multiTool-advert
|
||||||
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
||||||
|
|
||||||
@@ -1052,12 +1066,13 @@ addPassword.submit=Κρυπτογράφηση
|
|||||||
#watermark
|
#watermark
|
||||||
watermark.title=Προσθήκη Υδατογραφήματος
|
watermark.title=Προσθήκη Υδατογραφήματος
|
||||||
watermark.header=Προσθήκη Υδατογραφήματος
|
watermark.header=Προσθήκη Υδατογραφήματος
|
||||||
|
watermark.customColor=Προσαρμοσμένο χρώμα κειμένου
|
||||||
watermark.selectText.1=Επιλέξτε PDF για την προσθήκη του υδατογραφήματος:
|
watermark.selectText.1=Επιλέξτε PDF για την προσθήκη του υδατογραφήματος:
|
||||||
watermark.selectText.2=Κείμενο Υδατογραφήματος:
|
watermark.selectText.2=Κείμενο Υδατογραφήματος:
|
||||||
watermark.selectText.3=Μέγεθος Κειμένου:
|
watermark.selectText.3=Μέγεθος Κειμένου:
|
||||||
watermark.selectText.4=Περιστροφή (0-360):
|
watermark.selectText.4=Περιστροφή (0-360):
|
||||||
watermark.selectText.5=widthSpacer (Κενό μεταξύ κάθε υδατογραφήματος οριζόντια):
|
watermark.selectText.5=Width Spacer (Κενό μεταξύ κάθε υδατογραφήματος οριζόντια):
|
||||||
watermark.selectText.6=heightSpacer (Κενό μεταξύ κάθε υδατογραφήματος κάθετα):
|
watermark.selectText.6=Height Spacer (Κενό μεταξύ κάθε υδατογραφήματος κάθετα):
|
||||||
watermark.selectText.7=Αδιαφάνεια (Opacity) (0% - 100%):
|
watermark.selectText.7=Αδιαφάνεια (Opacity) (0% - 100%):
|
||||||
watermark.selectText.8=Τύπος Υδατογραφήματος:
|
watermark.selectText.8=Τύπος Υδατογραφήματος:
|
||||||
watermark.selectText.9=Εικόνα Υδατογραφήματος:
|
watermark.selectText.9=Εικόνα Υδατογραφήματος:
|
||||||
@@ -1263,6 +1278,11 @@ splitByChapters.desc.3=Πρόσθεση Metadata: Αν επεξεργαστεί
|
|||||||
splitByChapters.desc.4=Διάλυση Παρόντων Τίτλων Επιπέδου: Αν επεξεργαστείται, επιτρέπει τη δημιουργία αποκοπών PDF με βάση πλήρως καθορισμένους σήμαντες έδρας.
|
splitByChapters.desc.4=Διάλυση Παρόντων Τίτλων Επιπέδου: Αν επεξεργαστείται, επιτρέπει τη δημιουργία αποκοπών PDF με βάση πλήρως καθορισμένους σήμαντες έδρας.
|
||||||
splitByChapters.submit=Διαλύστε το PDF
|
splitByChapters.submit=Διαλύστε το PDF
|
||||||
|
|
||||||
|
#File Chooser
|
||||||
|
fileChooser.click=Click
|
||||||
|
fileChooser.or=or
|
||||||
|
fileChooser.dragAndDrop=Drag & Drop
|
||||||
|
fileChooser.hoveredDragAndDrop=Drag & Drop file(s) here
|
||||||
|
|
||||||
#release notes
|
#release notes
|
||||||
releases.footer=Releases
|
releases.footer=Releases
|
||||||
@@ -1270,3 +1290,38 @@ releases.title=Release Notes
|
|||||||
releases.header=Release Notes
|
releases.header=Release Notes
|
||||||
releases.current.version=Current Release
|
releases.current.version=Current Release
|
||||||
releases.note=Release notes are only available in English
|
releases.note=Release notes are only available in English
|
||||||
|
|
||||||
|
#Validate Signature
|
||||||
|
validateSignature.title=Validate PDF Signatures
|
||||||
|
validateSignature.header=Validate Digital Signatures
|
||||||
|
validateSignature.selectPDF=Select signed PDF file
|
||||||
|
validateSignature.submit=Validate Signatures
|
||||||
|
validateSignature.results=Validation Results
|
||||||
|
validateSignature.status=Status
|
||||||
|
validateSignature.signer=Signer
|
||||||
|
validateSignature.date=Date
|
||||||
|
validateSignature.reason=Reason
|
||||||
|
validateSignature.location=Location
|
||||||
|
validateSignature.noSignatures=No digital signatures found in this document
|
||||||
|
validateSignature.status.valid=Valid
|
||||||
|
validateSignature.status.invalid=Invalid
|
||||||
|
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
|
||||||
|
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
|
||||||
|
validateSignature.cert.expired=Certificate has expired
|
||||||
|
validateSignature.cert.revoked=Certificate has been revoked
|
||||||
|
validateSignature.signature.info=Signature Information
|
||||||
|
validateSignature.signature=Signature
|
||||||
|
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
|
||||||
|
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
|
||||||
|
validateSignature.cert.info=Certificate Details
|
||||||
|
validateSignature.cert.issuer=Issuer
|
||||||
|
validateSignature.cert.subject=Subject
|
||||||
|
validateSignature.cert.serialNumber=Serial Number
|
||||||
|
validateSignature.cert.validFrom=Valid From
|
||||||
|
validateSignature.cert.validUntil=Valid Until
|
||||||
|
validateSignature.cert.algorithm=Algorithm
|
||||||
|
validateSignature.cert.keySize=Key Size
|
||||||
|
validateSignature.cert.version=Version
|
||||||
|
validateSignature.cert.keyUsage=Key Usage
|
||||||
|
validateSignature.cert.selfSigned=Self-Signed
|
||||||
|
validateSignature.cert.bits=bits
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ joinDiscord=Join our Discord server
|
|||||||
seeDockerHub=See Docker Hub
|
seeDockerHub=See Docker Hub
|
||||||
visitGithub=Visit Github Repository
|
visitGithub=Visit Github Repository
|
||||||
donate=Donate
|
donate=Donate
|
||||||
color=Color
|
color=Colour
|
||||||
sponsor=Sponsor
|
sponsor=Sponsor
|
||||||
info=Info
|
info=Info
|
||||||
pro=Pro
|
pro=Pro
|
||||||
@@ -419,9 +419,9 @@ home.auto-rename.title=Auto Rename PDF File
|
|||||||
home.auto-rename.desc=Auto renames a PDF file based on its detected header
|
home.auto-rename.desc=Auto renames a PDF file based on its detected header
|
||||||
auto-rename.tags=auto-detect,header-based,organize,relabel
|
auto-rename.tags=auto-detect,header-based,organize,relabel
|
||||||
|
|
||||||
home.adjust-contrast.title=Adjust Colors/Contrast
|
home.adjust-contrast.title=Adjust Colours/Contrast
|
||||||
home.adjust-contrast.desc=Adjust Contrast, Saturation and Brightness of a PDF
|
home.adjust-contrast.desc=Adjust Contrast, Saturation and Brightness of a PDF
|
||||||
adjust-contrast.tags=color-correction,tune,modify,enhance
|
adjust-contrast.tags=color-correction,tune,modify,enhance,colour-correction
|
||||||
|
|
||||||
home.crop.title=Crop PDF
|
home.crop.title=Crop PDF
|
||||||
home.crop.desc=Crop a PDF to reduce its size (maintains text!)
|
home.crop.desc=Crop a PDF to reduce its size (maintains text!)
|
||||||
@@ -488,11 +488,11 @@ overlay-pdfs.tags=Overlay
|
|||||||
|
|
||||||
home.split-by-sections.title=Split PDF by Sections
|
home.split-by-sections.title=Split PDF by Sections
|
||||||
home.split-by-sections.desc=Divide each page of a PDF into smaller horizontal and vertical sections
|
home.split-by-sections.desc=Divide each page of a PDF into smaller horizontal and vertical sections
|
||||||
split-by-sections.tags=Section Split, Divide, Customize
|
split-by-sections.tags=Section Split, Divide, Customize,Customise
|
||||||
|
|
||||||
home.AddStampRequest.title=Add Stamp to PDF
|
home.AddStampRequest.title=Add Stamp to PDF
|
||||||
home.AddStampRequest.desc=Add text or add image stamps at set locations
|
home.AddStampRequest.desc=Add text or add image stamps at set locations
|
||||||
AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Customize
|
AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Customize,Customise
|
||||||
|
|
||||||
|
|
||||||
home.PDFToBook.title=PDF to Book
|
home.PDFToBook.title=PDF to Book
|
||||||
@@ -512,23 +512,27 @@ home.splitPdfByChapters.title=Split PDF by Chapters
|
|||||||
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
||||||
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
||||||
|
|
||||||
|
home.validateSignature.title=Validate PDF Signature
|
||||||
|
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
|
||||||
|
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
|
||||||
|
|
||||||
#replace-invert-color
|
#replace-invert-color
|
||||||
replace-color.title=Advanced Colour options
|
replace-color.title=Advanced Colour options
|
||||||
replace-color.header=Replace-Invert Color PDF
|
replace-color.header=Replace-Invert Colour PDF
|
||||||
home.replaceColorPdf.title=Advanced Colour options
|
home.replaceColorPdf.title=Advanced Colour options
|
||||||
home.replaceColorPdf.desc=Replace color for text and background in PDF and invert full color of pdf to reduce file size
|
home.replaceColorPdf.desc=Replace colour for text and background in PDF and invert full colour of pdf to reduce file size
|
||||||
replaceColorPdf.tags=Replace Color,Page operations,Back end,server side
|
replaceColorPdf.tags=Replace Colour,Page operations,Back end,server side
|
||||||
replace-color.selectText.1=Replace or Invert color Options
|
replace-color.selectText.1=Replace or Invert colour Options
|
||||||
replace-color.selectText.2=Default(Default high contrast colors)
|
replace-color.selectText.2=Default(Default high contrast colours)
|
||||||
replace-color.selectText.3=Custom(Customized colors)
|
replace-color.selectText.3=Custom(Customised colours)
|
||||||
replace-color.selectText.4=Full-Invert(Invert all colors)
|
replace-color.selectText.4=Full-Invert(Invert all colours)
|
||||||
replace-color.selectText.5=High contrast color options
|
replace-color.selectText.5=High contrast colour options
|
||||||
replace-color.selectText.6=white text on black background
|
replace-color.selectText.6=white text on black background
|
||||||
replace-color.selectText.7=Black text on white background
|
replace-color.selectText.7=Black text on white background
|
||||||
replace-color.selectText.8=Yellow text on black background
|
replace-color.selectText.8=Yellow text on black background
|
||||||
replace-color.selectText.9=Green text on black background
|
replace-color.selectText.9=Green text on black background
|
||||||
replace-color.selectText.10=Choose text Color
|
replace-color.selectText.10=Choose text Colour
|
||||||
replace-color.selectText.11=Choose background Color
|
replace-color.selectText.11=Choose background Colour
|
||||||
replace-color.submit=Replace
|
replace-color.submit=Replace
|
||||||
|
|
||||||
|
|
||||||
@@ -651,7 +655,7 @@ AddStampRequest.position=Position
|
|||||||
AddStampRequest.overrideX=Override X Coordinate
|
AddStampRequest.overrideX=Override X Coordinate
|
||||||
AddStampRequest.overrideY=Override Y Coordinate
|
AddStampRequest.overrideY=Override Y Coordinate
|
||||||
AddStampRequest.customMargin=Custom Margin
|
AddStampRequest.customMargin=Custom Margin
|
||||||
AddStampRequest.customColor=Custom Text Color
|
AddStampRequest.customColor=Custom Text Colour
|
||||||
AddStampRequest.submit=Submit
|
AddStampRequest.submit=Submit
|
||||||
|
|
||||||
|
|
||||||
@@ -783,8 +787,8 @@ removeAnnotations.submit=Remove
|
|||||||
#compare
|
#compare
|
||||||
compare.title=Compare
|
compare.title=Compare
|
||||||
compare.header=Compare PDFs
|
compare.header=Compare PDFs
|
||||||
compare.highlightColor.1=Highlight Color 1:
|
compare.highlightColor.1=Highlight Colour 1:
|
||||||
compare.highlightColor.2=Highlight Color 2:
|
compare.highlightColor.2=Highlight Colour 2:
|
||||||
compare.document.1=Document 1
|
compare.document.1=Document 1
|
||||||
compare.document.2=Document 2
|
compare.document.2=Document 2
|
||||||
compare.submit=Compare
|
compare.submit=Compare
|
||||||
@@ -842,7 +846,7 @@ flatten.submit=Flatten
|
|||||||
ScannerImageSplit.selectText.1=Angle Threshold:
|
ScannerImageSplit.selectText.1=Angle Threshold:
|
||||||
ScannerImageSplit.selectText.2=Sets the minimum absolute angle required for the image to be rotated (default: 10).
|
ScannerImageSplit.selectText.2=Sets the minimum absolute angle required for the image to be rotated (default: 10).
|
||||||
ScannerImageSplit.selectText.3=Tolerance:
|
ScannerImageSplit.selectText.3=Tolerance:
|
||||||
ScannerImageSplit.selectText.4=Determines the range of color variation around the estimated background color (default: 30).
|
ScannerImageSplit.selectText.4=Determines the range of colour variation around the estimated background colour (default: 30).
|
||||||
ScannerImageSplit.selectText.5=Minimum Area:
|
ScannerImageSplit.selectText.5=Minimum Area:
|
||||||
ScannerImageSplit.selectText.6=Sets the minimum area threshold for a photo (default: 10000).
|
ScannerImageSplit.selectText.6=Sets the minimum area threshold for a photo (default: 10000).
|
||||||
ScannerImageSplit.selectText.7=Minimum Contour Area:
|
ScannerImageSplit.selectText.7=Minimum Contour Area:
|
||||||
@@ -894,7 +898,7 @@ compress.title=Compress
|
|||||||
compress.header=Compress PDF
|
compress.header=Compress PDF
|
||||||
compress.credit=This service uses qpdf for PDF Compress/Optimisation.
|
compress.credit=This service uses qpdf for PDF Compress/Optimisation.
|
||||||
compress.selectText.1=Manual Mode - From 1 to 4
|
compress.selectText.1=Manual Mode - From 1 to 4
|
||||||
compress.selectText.2=Optimization level:
|
compress.selectText.2=Optimisation level:
|
||||||
compress.selectText.3=4 (Terrible for text images)
|
compress.selectText.3=4 (Terrible for text images)
|
||||||
compress.selectText.4=Auto mode - Auto adjusts quality to get PDF to exact size
|
compress.selectText.4=Auto mode - Auto adjusts quality to get PDF to exact size
|
||||||
compress.selectText.5=Expected PDF Size (e.g. 25MB, 10.8MB, 25KB)
|
compress.selectText.5=Expected PDF Size (e.g. 25MB, 10.8MB, 25KB)
|
||||||
@@ -961,6 +965,16 @@ multiTool.dragDropMessage=Page(s) Selected
|
|||||||
multiTool.undo=Undo
|
multiTool.undo=Undo
|
||||||
multiTool.redo=Redo
|
multiTool.redo=Redo
|
||||||
|
|
||||||
|
#decrypt
|
||||||
|
decrypt.passwordPrompt=This file is password-protected. Please enter the password:
|
||||||
|
decrypt.cancelled=Operation cancelled for PDF: {0}
|
||||||
|
decrypt.noPassword=No password provided for encrypted PDF: {0}
|
||||||
|
decrypt.invalidPassword=Please try again with the correct password.
|
||||||
|
decrypt.invalidPasswordHeader=Incorrect password or unsupported encryption for PDF: {0}
|
||||||
|
decrypt.unexpectedError=There was an error processing the file. Please try again.
|
||||||
|
decrypt.serverError=Server error while decrypting: {0}
|
||||||
|
decrypt.success=File decrypted successfully.
|
||||||
|
|
||||||
#multiTool-advert
|
#multiTool-advert
|
||||||
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
||||||
|
|
||||||
@@ -1052,12 +1066,13 @@ addPassword.submit=Encrypt
|
|||||||
#watermark
|
#watermark
|
||||||
watermark.title=Add Watermark
|
watermark.title=Add Watermark
|
||||||
watermark.header=Add Watermark
|
watermark.header=Add Watermark
|
||||||
|
watermark.customColor=Custom Text Colour
|
||||||
watermark.selectText.1=Select PDF to add watermark to:
|
watermark.selectText.1=Select PDF to add watermark to:
|
||||||
watermark.selectText.2=Watermark Text:
|
watermark.selectText.2=Watermark Text:
|
||||||
watermark.selectText.3=Font Size:
|
watermark.selectText.3=Font Size:
|
||||||
watermark.selectText.4=Rotation (0-360):
|
watermark.selectText.4=Rotation (0-360):
|
||||||
watermark.selectText.5=widthSpacer (Space between each watermark horizontally):
|
watermark.selectText.5=Width Spacer (Space between each watermark horizontally):
|
||||||
watermark.selectText.6=heightSpacer (Space between each watermark vertically):
|
watermark.selectText.6=Height Spacer (Space between each watermark vertically):
|
||||||
watermark.selectText.7=Opacity (0% - 100%):
|
watermark.selectText.7=Opacity (0% - 100%):
|
||||||
watermark.selectText.8=Watermark Type:
|
watermark.selectText.8=Watermark Type:
|
||||||
watermark.selectText.9=Watermark Image:
|
watermark.selectText.9=Watermark Image:
|
||||||
@@ -1263,6 +1278,11 @@ splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata
|
|||||||
splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs.
|
splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs.
|
||||||
splitByChapters.submit=Split PDF
|
splitByChapters.submit=Split PDF
|
||||||
|
|
||||||
|
#File Chooser
|
||||||
|
fileChooser.click=Click
|
||||||
|
fileChooser.or=or
|
||||||
|
fileChooser.dragAndDrop=Drag & Drop
|
||||||
|
fileChooser.hoveredDragAndDrop=Drag & Drop file(s) here
|
||||||
|
|
||||||
#release notes
|
#release notes
|
||||||
releases.footer=Releases
|
releases.footer=Releases
|
||||||
@@ -1270,3 +1290,38 @@ releases.title=Release Notes
|
|||||||
releases.header=Release Notes
|
releases.header=Release Notes
|
||||||
releases.current.version=Current Release
|
releases.current.version=Current Release
|
||||||
releases.note=Release notes are only available in English
|
releases.note=Release notes are only available in English
|
||||||
|
|
||||||
|
#Validate Signature
|
||||||
|
validateSignature.title=Validate PDF Signatures
|
||||||
|
validateSignature.header=Validate Digital Signatures
|
||||||
|
validateSignature.selectPDF=Select signed PDF file
|
||||||
|
validateSignature.submit=Validate Signatures
|
||||||
|
validateSignature.results=Validation Results
|
||||||
|
validateSignature.status=Status
|
||||||
|
validateSignature.signer=Signer
|
||||||
|
validateSignature.date=Date
|
||||||
|
validateSignature.reason=Reason
|
||||||
|
validateSignature.location=Location
|
||||||
|
validateSignature.noSignatures=No digital signatures found in this document
|
||||||
|
validateSignature.status.valid=Valid
|
||||||
|
validateSignature.status.invalid=Invalid
|
||||||
|
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
|
||||||
|
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
|
||||||
|
validateSignature.cert.expired=Certificate has expired
|
||||||
|
validateSignature.cert.revoked=Certificate has been revoked
|
||||||
|
validateSignature.signature.info=Signature Information
|
||||||
|
validateSignature.signature=Signature
|
||||||
|
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
|
||||||
|
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
|
||||||
|
validateSignature.cert.info=Certificate Details
|
||||||
|
validateSignature.cert.issuer=Issuer
|
||||||
|
validateSignature.cert.subject=Subject
|
||||||
|
validateSignature.cert.serialNumber=Serial Number
|
||||||
|
validateSignature.cert.validFrom=Valid From
|
||||||
|
validateSignature.cert.validUntil=Valid Until
|
||||||
|
validateSignature.cert.algorithm=Algorithm
|
||||||
|
validateSignature.cert.keySize=Key Size
|
||||||
|
validateSignature.cert.version=Version
|
||||||
|
validateSignature.cert.keyUsage=Key Usage
|
||||||
|
validateSignature.cert.selfSigned=Self-Signed
|
||||||
|
validateSignature.cert.bits=bits
|
||||||
|
|||||||
@@ -512,6 +512,10 @@ home.splitPdfByChapters.title=Split PDF by Chapters
|
|||||||
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
||||||
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
||||||
|
|
||||||
|
home.validateSignature.title=Validate PDF Signature
|
||||||
|
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
|
||||||
|
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
|
||||||
|
|
||||||
#replace-invert-color
|
#replace-invert-color
|
||||||
replace-color.title=Replace-Invert-Color
|
replace-color.title=Replace-Invert-Color
|
||||||
replace-color.header=Replace-Invert Color PDF
|
replace-color.header=Replace-Invert Color PDF
|
||||||
@@ -961,6 +965,16 @@ multiTool.dragDropMessage=Page(s) Selected
|
|||||||
multiTool.undo=Undo
|
multiTool.undo=Undo
|
||||||
multiTool.redo=Redo
|
multiTool.redo=Redo
|
||||||
|
|
||||||
|
#decrypt
|
||||||
|
decrypt.passwordPrompt=This file is password-protected. Please enter the password:
|
||||||
|
decrypt.cancelled=Operation cancelled for PDF: {0}
|
||||||
|
decrypt.noPassword=No password provided for encrypted PDF: {0}
|
||||||
|
decrypt.invalidPassword=Please try again with the correct password.
|
||||||
|
decrypt.invalidPasswordHeader=Incorrect password or unsupported encryption for PDF: {0}
|
||||||
|
decrypt.unexpectedError=There was an error processing the file. Please try again.
|
||||||
|
decrypt.serverError=Server error while decrypting: {0}
|
||||||
|
decrypt.success=File decrypted successfully.
|
||||||
|
|
||||||
#multiTool-advert
|
#multiTool-advert
|
||||||
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
||||||
|
|
||||||
@@ -1052,12 +1066,13 @@ addPassword.submit=Encrypt
|
|||||||
#watermark
|
#watermark
|
||||||
watermark.title=Add Watermark
|
watermark.title=Add Watermark
|
||||||
watermark.header=Add Watermark
|
watermark.header=Add Watermark
|
||||||
|
watermark.customColor=Custom Text Color
|
||||||
watermark.selectText.1=Select PDF to add watermark to:
|
watermark.selectText.1=Select PDF to add watermark to:
|
||||||
watermark.selectText.2=Watermark Text:
|
watermark.selectText.2=Watermark Text:
|
||||||
watermark.selectText.3=Font Size:
|
watermark.selectText.3=Font Size:
|
||||||
watermark.selectText.4=Rotation (0-360):
|
watermark.selectText.4=Rotation (0-360):
|
||||||
watermark.selectText.5=widthSpacer (Space between each watermark horizontally):
|
watermark.selectText.5=Width Spacer (Space between each watermark horizontally):
|
||||||
watermark.selectText.6=heightSpacer (Space between each watermark vertically):
|
watermark.selectText.6=Height Spacer (Space between each watermark vertically):
|
||||||
watermark.selectText.7=Opacity (0% - 100%):
|
watermark.selectText.7=Opacity (0% - 100%):
|
||||||
watermark.selectText.8=Watermark Type:
|
watermark.selectText.8=Watermark Type:
|
||||||
watermark.selectText.9=Watermark Image:
|
watermark.selectText.9=Watermark Image:
|
||||||
@@ -1263,6 +1278,11 @@ splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata
|
|||||||
splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs.
|
splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs.
|
||||||
splitByChapters.submit=Split PDF
|
splitByChapters.submit=Split PDF
|
||||||
|
|
||||||
|
#File Chooser
|
||||||
|
fileChooser.click=Click
|
||||||
|
fileChooser.or=or
|
||||||
|
fileChooser.dragAndDrop=Drag & Drop
|
||||||
|
fileChooser.hoveredDragAndDrop=Drag & Drop file(s) here
|
||||||
|
|
||||||
#release notes
|
#release notes
|
||||||
releases.footer=Releases
|
releases.footer=Releases
|
||||||
@@ -1270,3 +1290,38 @@ releases.title=Release Notes
|
|||||||
releases.header=Release Notes
|
releases.header=Release Notes
|
||||||
releases.current.version=Current Release
|
releases.current.version=Current Release
|
||||||
releases.note=Release notes are only available in English
|
releases.note=Release notes are only available in English
|
||||||
|
|
||||||
|
#Validate Signature
|
||||||
|
validateSignature.title=Validate PDF Signatures
|
||||||
|
validateSignature.header=Validate Digital Signatures
|
||||||
|
validateSignature.selectPDF=Select signed PDF file
|
||||||
|
validateSignature.submit=Validate Signatures
|
||||||
|
validateSignature.results=Validation Results
|
||||||
|
validateSignature.status=Status
|
||||||
|
validateSignature.signer=Signer
|
||||||
|
validateSignature.date=Date
|
||||||
|
validateSignature.reason=Reason
|
||||||
|
validateSignature.location=Location
|
||||||
|
validateSignature.noSignatures=No digital signatures found in this document
|
||||||
|
validateSignature.status.valid=Valid
|
||||||
|
validateSignature.status.invalid=Invalid
|
||||||
|
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
|
||||||
|
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
|
||||||
|
validateSignature.cert.expired=Certificate has expired
|
||||||
|
validateSignature.cert.revoked=Certificate has been revoked
|
||||||
|
validateSignature.signature.info=Signature Information
|
||||||
|
validateSignature.signature=Signature
|
||||||
|
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
|
||||||
|
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
|
||||||
|
validateSignature.cert.info=Certificate Details
|
||||||
|
validateSignature.cert.issuer=Issuer
|
||||||
|
validateSignature.cert.subject=Subject
|
||||||
|
validateSignature.cert.serialNumber=Serial Number
|
||||||
|
validateSignature.cert.validFrom=Valid From
|
||||||
|
validateSignature.cert.validUntil=Valid Until
|
||||||
|
validateSignature.cert.algorithm=Algorithm
|
||||||
|
validateSignature.cert.keySize=Key Size
|
||||||
|
validateSignature.cert.version=Version
|
||||||
|
validateSignature.cert.keyUsage=Key Usage
|
||||||
|
validateSignature.cert.selfSigned=Self-Signed
|
||||||
|
validateSignature.cert.bits=bits
|
||||||
|
|||||||
@@ -512,6 +512,10 @@ home.splitPdfByChapters.title=Dividir PDF por capítulos
|
|||||||
home.splitPdfByChapters.desc=Divida un PDF en varios archivos según su estructura de 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
|
splitPdfByChapters.tags=dividir,capítulos,marcadores,organizar
|
||||||
|
|
||||||
|
home.validateSignature.title=Validate PDF Signature
|
||||||
|
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
|
||||||
|
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
|
||||||
|
|
||||||
#replace-invert-color
|
#replace-invert-color
|
||||||
replace-color.title=Reemplazar-Invertir-Color
|
replace-color.title=Reemplazar-Invertir-Color
|
||||||
replace-color.header=Reemplazar-Invertir Color en PDF
|
replace-color.header=Reemplazar-Invertir Color en PDF
|
||||||
@@ -961,6 +965,16 @@ multiTool.dragDropMessage=Page(s) Selected
|
|||||||
multiTool.undo=Undo
|
multiTool.undo=Undo
|
||||||
multiTool.redo=Redo
|
multiTool.redo=Redo
|
||||||
|
|
||||||
|
#decrypt
|
||||||
|
decrypt.passwordPrompt=This file is password-protected. Please enter the password:
|
||||||
|
decrypt.cancelled=Operation cancelled for PDF: {0}
|
||||||
|
decrypt.noPassword=No password provided for encrypted PDF: {0}
|
||||||
|
decrypt.invalidPassword=Please try again with the correct password.
|
||||||
|
decrypt.invalidPasswordHeader=Incorrect password or unsupported encryption for PDF: {0}
|
||||||
|
decrypt.unexpectedError=There was an error processing the file. Please try again.
|
||||||
|
decrypt.serverError=Server error while decrypting: {0}
|
||||||
|
decrypt.success=File decrypted successfully.
|
||||||
|
|
||||||
#multiTool-advert
|
#multiTool-advert
|
||||||
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
||||||
|
|
||||||
@@ -1052,6 +1066,7 @@ addPassword.submit=Encriptar
|
|||||||
#watermark
|
#watermark
|
||||||
watermark.title=Añadir marca de agua
|
watermark.title=Añadir marca de agua
|
||||||
watermark.header=Añadir marca de agua
|
watermark.header=Añadir marca de agua
|
||||||
|
watermark.customColor=Personalizar color de texto
|
||||||
watermark.selectText.1=Seleccionar PDF para añadir marca de agua:
|
watermark.selectText.1=Seleccionar PDF para añadir marca de agua:
|
||||||
watermark.selectText.2=Texto de la marca de agua:
|
watermark.selectText.2=Texto de la marca de agua:
|
||||||
watermark.selectText.3=Tamaño de la Fuente:
|
watermark.selectText.3=Tamaño de la Fuente:
|
||||||
@@ -1263,6 +1278,11 @@ splitByChapters.desc.3=Incluir Metadatos: Si está seleccionado, los metadatos d
|
|||||||
splitByChapters.desc.4=Permitir Duplicados: Si está seleccionado, permite que múltiples marcadores en la misma página creen archivos PDF separados.
|
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
|
splitByChapters.submit=Dividir PDF
|
||||||
|
|
||||||
|
#File Chooser
|
||||||
|
fileChooser.click=Click
|
||||||
|
fileChooser.or=or
|
||||||
|
fileChooser.dragAndDrop=Drag & Drop
|
||||||
|
fileChooser.hoveredDragAndDrop=Drag & Drop file(s) here
|
||||||
|
|
||||||
#release notes
|
#release notes
|
||||||
releases.footer=Releases
|
releases.footer=Releases
|
||||||
@@ -1270,3 +1290,38 @@ releases.title=Release Notes
|
|||||||
releases.header=Release Notes
|
releases.header=Release Notes
|
||||||
releases.current.version=Current Release
|
releases.current.version=Current Release
|
||||||
releases.note=Release notes are only available in English
|
releases.note=Release notes are only available in English
|
||||||
|
|
||||||
|
#Validate Signature
|
||||||
|
validateSignature.title=Validate PDF Signatures
|
||||||
|
validateSignature.header=Validate Digital Signatures
|
||||||
|
validateSignature.selectPDF=Select signed PDF file
|
||||||
|
validateSignature.submit=Validate Signatures
|
||||||
|
validateSignature.results=Validation Results
|
||||||
|
validateSignature.status=Status
|
||||||
|
validateSignature.signer=Signer
|
||||||
|
validateSignature.date=Date
|
||||||
|
validateSignature.reason=Reason
|
||||||
|
validateSignature.location=Location
|
||||||
|
validateSignature.noSignatures=No digital signatures found in this document
|
||||||
|
validateSignature.status.valid=Valid
|
||||||
|
validateSignature.status.invalid=Invalid
|
||||||
|
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
|
||||||
|
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
|
||||||
|
validateSignature.cert.expired=Certificate has expired
|
||||||
|
validateSignature.cert.revoked=Certificate has been revoked
|
||||||
|
validateSignature.signature.info=Signature Information
|
||||||
|
validateSignature.signature=Signature
|
||||||
|
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
|
||||||
|
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
|
||||||
|
validateSignature.cert.info=Certificate Details
|
||||||
|
validateSignature.cert.issuer=Issuer
|
||||||
|
validateSignature.cert.subject=Subject
|
||||||
|
validateSignature.cert.serialNumber=Serial Number
|
||||||
|
validateSignature.cert.validFrom=Valid From
|
||||||
|
validateSignature.cert.validUntil=Valid Until
|
||||||
|
validateSignature.cert.algorithm=Algorithm
|
||||||
|
validateSignature.cert.keySize=Key Size
|
||||||
|
validateSignature.cert.version=Version
|
||||||
|
validateSignature.cert.keyUsage=Key Usage
|
||||||
|
validateSignature.cert.selfSigned=Self-Signed
|
||||||
|
validateSignature.cert.bits=bits
|
||||||
|
|||||||
@@ -512,6 +512,10 @@ home.splitPdfByChapters.title=Split PDF by Chapters
|
|||||||
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
||||||
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
||||||
|
|
||||||
|
home.validateSignature.title=Validate PDF Signature
|
||||||
|
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
|
||||||
|
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
|
||||||
|
|
||||||
#replace-invert-color
|
#replace-invert-color
|
||||||
replace-color.title=Replace-Invert-Color
|
replace-color.title=Replace-Invert-Color
|
||||||
replace-color.header=Replace-Invert Color PDF
|
replace-color.header=Replace-Invert Color PDF
|
||||||
@@ -961,6 +965,16 @@ multiTool.dragDropMessage=Page(s) Selected
|
|||||||
multiTool.undo=Undo
|
multiTool.undo=Undo
|
||||||
multiTool.redo=Redo
|
multiTool.redo=Redo
|
||||||
|
|
||||||
|
#decrypt
|
||||||
|
decrypt.passwordPrompt=This file is password-protected. Please enter the password:
|
||||||
|
decrypt.cancelled=Operation cancelled for PDF: {0}
|
||||||
|
decrypt.noPassword=No password provided for encrypted PDF: {0}
|
||||||
|
decrypt.invalidPassword=Please try again with the correct password.
|
||||||
|
decrypt.invalidPasswordHeader=Incorrect password or unsupported encryption for PDF: {0}
|
||||||
|
decrypt.unexpectedError=There was an error processing the file. Please try again.
|
||||||
|
decrypt.serverError=Server error while decrypting: {0}
|
||||||
|
decrypt.success=File decrypted successfully.
|
||||||
|
|
||||||
#multiTool-advert
|
#multiTool-advert
|
||||||
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
||||||
|
|
||||||
@@ -1052,6 +1066,7 @@ addPassword.submit=Enkriptatu
|
|||||||
#watermark
|
#watermark
|
||||||
watermark.title=Gehitu ur-marka
|
watermark.title=Gehitu ur-marka
|
||||||
watermark.header=Gehitu ur-marka
|
watermark.header=Gehitu ur-marka
|
||||||
|
watermark.customColor=Custom Text Color
|
||||||
watermark.selectText.1=Hautatu PDFa ur-marka gehitzeko:
|
watermark.selectText.1=Hautatu PDFa ur-marka gehitzeko:
|
||||||
watermark.selectText.2=Ur-markaren testua:
|
watermark.selectText.2=Ur-markaren testua:
|
||||||
watermark.selectText.3=Letra-tipoaren tamaina:
|
watermark.selectText.3=Letra-tipoaren tamaina:
|
||||||
@@ -1263,6 +1278,11 @@ splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata
|
|||||||
splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs.
|
splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs.
|
||||||
splitByChapters.submit=Split PDF
|
splitByChapters.submit=Split PDF
|
||||||
|
|
||||||
|
#File Chooser
|
||||||
|
fileChooser.click=Click
|
||||||
|
fileChooser.or=or
|
||||||
|
fileChooser.dragAndDrop=Drag & Drop
|
||||||
|
fileChooser.hoveredDragAndDrop=Drag & Drop file(s) here
|
||||||
|
|
||||||
#release notes
|
#release notes
|
||||||
releases.footer=Releases
|
releases.footer=Releases
|
||||||
@@ -1270,3 +1290,38 @@ releases.title=Release Notes
|
|||||||
releases.header=Release Notes
|
releases.header=Release Notes
|
||||||
releases.current.version=Current Release
|
releases.current.version=Current Release
|
||||||
releases.note=Release notes are only available in English
|
releases.note=Release notes are only available in English
|
||||||
|
|
||||||
|
#Validate Signature
|
||||||
|
validateSignature.title=Validate PDF Signatures
|
||||||
|
validateSignature.header=Validate Digital Signatures
|
||||||
|
validateSignature.selectPDF=Select signed PDF file
|
||||||
|
validateSignature.submit=Validate Signatures
|
||||||
|
validateSignature.results=Validation Results
|
||||||
|
validateSignature.status=Status
|
||||||
|
validateSignature.signer=Signer
|
||||||
|
validateSignature.date=Date
|
||||||
|
validateSignature.reason=Reason
|
||||||
|
validateSignature.location=Location
|
||||||
|
validateSignature.noSignatures=No digital signatures found in this document
|
||||||
|
validateSignature.status.valid=Valid
|
||||||
|
validateSignature.status.invalid=Invalid
|
||||||
|
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
|
||||||
|
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
|
||||||
|
validateSignature.cert.expired=Certificate has expired
|
||||||
|
validateSignature.cert.revoked=Certificate has been revoked
|
||||||
|
validateSignature.signature.info=Signature Information
|
||||||
|
validateSignature.signature=Signature
|
||||||
|
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
|
||||||
|
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
|
||||||
|
validateSignature.cert.info=Certificate Details
|
||||||
|
validateSignature.cert.issuer=Issuer
|
||||||
|
validateSignature.cert.subject=Subject
|
||||||
|
validateSignature.cert.serialNumber=Serial Number
|
||||||
|
validateSignature.cert.validFrom=Valid From
|
||||||
|
validateSignature.cert.validUntil=Valid Until
|
||||||
|
validateSignature.cert.algorithm=Algorithm
|
||||||
|
validateSignature.cert.keySize=Key Size
|
||||||
|
validateSignature.cert.version=Version
|
||||||
|
validateSignature.cert.keyUsage=Key Usage
|
||||||
|
validateSignature.cert.selfSigned=Self-Signed
|
||||||
|
validateSignature.cert.bits=bits
|
||||||
|
|||||||
1327
src/main/resources/messages_fa_IR.properties
Normal file
1327
src/main/resources/messages_fa_IR.properties
Normal file
File diff suppressed because it is too large
Load Diff
@@ -512,6 +512,10 @@ home.splitPdfByChapters.title=Séparer un PDF par chapitres
|
|||||||
home.splitPdfByChapters.desc=Séparez un PDF en fichiers multiples en fonction de sa structure par chapitres.
|
home.splitPdfByChapters.desc=Séparez un PDF en fichiers multiples en fonction de sa structure par chapitres.
|
||||||
splitPdfByChapters.tags=séparer,chapitres,split,chapters,bookmarks,organize
|
splitPdfByChapters.tags=séparer,chapitres,split,chapters,bookmarks,organize
|
||||||
|
|
||||||
|
home.validateSignature.title=Validate PDF Signature
|
||||||
|
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
|
||||||
|
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
|
||||||
|
|
||||||
#replace-invert-color
|
#replace-invert-color
|
||||||
replace-color.title=Remplacer-Inverser-Couleur
|
replace-color.title=Remplacer-Inverser-Couleur
|
||||||
replace-color.header=Remplacer-Inverser Couleur PDF
|
replace-color.header=Remplacer-Inverser Couleur PDF
|
||||||
@@ -961,6 +965,16 @@ multiTool.dragDropMessage=Page(s) sélectionnées
|
|||||||
multiTool.undo=Undo
|
multiTool.undo=Undo
|
||||||
multiTool.redo=Redo
|
multiTool.redo=Redo
|
||||||
|
|
||||||
|
#decrypt
|
||||||
|
decrypt.passwordPrompt=This file is password-protected. Please enter the password:
|
||||||
|
decrypt.cancelled=Operation cancelled for PDF: {0}
|
||||||
|
decrypt.noPassword=No password provided for encrypted PDF: {0}
|
||||||
|
decrypt.invalidPassword=Please try again with the correct password.
|
||||||
|
decrypt.invalidPasswordHeader=Incorrect password or unsupported encryption for PDF: {0}
|
||||||
|
decrypt.unexpectedError=There was an error processing the file. Please try again.
|
||||||
|
decrypt.serverError=Server error while decrypting: {0}
|
||||||
|
decrypt.success=File decrypted successfully.
|
||||||
|
|
||||||
#multiTool-advert
|
#multiTool-advert
|
||||||
multiTool-advert.message=Cette fonctionnalité est aussi disponible dans la <a href="{0}">page de l'outil multifonction</a>. Allez-y pour une interface page par page améliorée et des fonctionnalités additionnelles !
|
multiTool-advert.message=Cette fonctionnalité est aussi disponible dans la <a href="{0}">page de l'outil multifonction</a>. Allez-y pour une interface page par page améliorée et des fonctionnalités additionnelles !
|
||||||
|
|
||||||
@@ -1052,12 +1066,13 @@ addPassword.submit=Chiffrer
|
|||||||
#watermark
|
#watermark
|
||||||
watermark.title=Ajouter un filigrane
|
watermark.title=Ajouter un filigrane
|
||||||
watermark.header=Ajouter un filigrane
|
watermark.header=Ajouter un filigrane
|
||||||
|
watermark.customColor=Couleur de texte personnalisée
|
||||||
watermark.selectText.1=PDF auquel ajouter un filigrane
|
watermark.selectText.1=PDF auquel ajouter un filigrane
|
||||||
watermark.selectText.2=Texte du filigrane
|
watermark.selectText.2=Texte du filigrane
|
||||||
watermark.selectText.3=Taille de police
|
watermark.selectText.3=Taille de police
|
||||||
watermark.selectText.4=Rotation (de 0 à 360 degrés)
|
watermark.selectText.4=Rotation (de 0 à 360 degrés)
|
||||||
watermark.selectText.5=widthSpacer (espace entre chaque filigrane horizontalement)
|
watermark.selectText.5=Width Spacer (espace entre chaque filigrane horizontalement)
|
||||||
watermark.selectText.6=heightSpacer (espace entre chaque filigrane verticalement)
|
watermark.selectText.6=Height Spacer (espace entre chaque filigrane verticalement)
|
||||||
watermark.selectText.7=Opacité (de 0% à 100%)
|
watermark.selectText.7=Opacité (de 0% à 100%)
|
||||||
watermark.selectText.8=Type de filigrane
|
watermark.selectText.8=Type de filigrane
|
||||||
watermark.selectText.9=Image du filigrane
|
watermark.selectText.9=Image du filigrane
|
||||||
@@ -1263,6 +1278,11 @@ splitByChapters.desc.3=Inclure les Métadonnées : Si coché, les métadonnées
|
|||||||
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.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
|
splitByChapters.submit=Diviser le PDF
|
||||||
|
|
||||||
|
#File Chooser
|
||||||
|
fileChooser.click=Click
|
||||||
|
fileChooser.or=or
|
||||||
|
fileChooser.dragAndDrop=Drag & Drop
|
||||||
|
fileChooser.hoveredDragAndDrop=Drag & Drop file(s) here
|
||||||
|
|
||||||
#release notes
|
#release notes
|
||||||
releases.footer=Releases
|
releases.footer=Releases
|
||||||
@@ -1270,3 +1290,38 @@ releases.title=Release Notes
|
|||||||
releases.header=Release Notes
|
releases.header=Release Notes
|
||||||
releases.current.version=Current Release
|
releases.current.version=Current Release
|
||||||
releases.note=Release notes are only available in English
|
releases.note=Release notes are only available in English
|
||||||
|
|
||||||
|
#Validate Signature
|
||||||
|
validateSignature.title=Validate PDF Signatures
|
||||||
|
validateSignature.header=Validate Digital Signatures
|
||||||
|
validateSignature.selectPDF=Select signed PDF file
|
||||||
|
validateSignature.submit=Validate Signatures
|
||||||
|
validateSignature.results=Validation Results
|
||||||
|
validateSignature.status=Status
|
||||||
|
validateSignature.signer=Signer
|
||||||
|
validateSignature.date=Date
|
||||||
|
validateSignature.reason=Reason
|
||||||
|
validateSignature.location=Location
|
||||||
|
validateSignature.noSignatures=No digital signatures found in this document
|
||||||
|
validateSignature.status.valid=Valid
|
||||||
|
validateSignature.status.invalid=Invalid
|
||||||
|
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
|
||||||
|
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
|
||||||
|
validateSignature.cert.expired=Certificate has expired
|
||||||
|
validateSignature.cert.revoked=Certificate has been revoked
|
||||||
|
validateSignature.signature.info=Signature Information
|
||||||
|
validateSignature.signature=Signature
|
||||||
|
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
|
||||||
|
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
|
||||||
|
validateSignature.cert.info=Certificate Details
|
||||||
|
validateSignature.cert.issuer=Issuer
|
||||||
|
validateSignature.cert.subject=Subject
|
||||||
|
validateSignature.cert.serialNumber=Serial Number
|
||||||
|
validateSignature.cert.validFrom=Valid From
|
||||||
|
validateSignature.cert.validUntil=Valid Until
|
||||||
|
validateSignature.cert.algorithm=Algorithm
|
||||||
|
validateSignature.cert.keySize=Key Size
|
||||||
|
validateSignature.cert.version=Version
|
||||||
|
validateSignature.cert.keyUsage=Key Usage
|
||||||
|
validateSignature.cert.selfSigned=Self-Signed
|
||||||
|
validateSignature.cert.bits=bits
|
||||||
|
|||||||
@@ -512,6 +512,10 @@ home.splitPdfByChapters.title=Split PDF by Chapters
|
|||||||
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
||||||
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
||||||
|
|
||||||
|
home.validateSignature.title=Validate PDF Signature
|
||||||
|
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
|
||||||
|
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
|
||||||
|
|
||||||
#replace-invert-color
|
#replace-invert-color
|
||||||
replace-color.title=Replace-Invert-Color
|
replace-color.title=Replace-Invert-Color
|
||||||
replace-color.header=Replace-Invert Color PDF
|
replace-color.header=Replace-Invert Color PDF
|
||||||
@@ -961,6 +965,16 @@ multiTool.dragDropMessage=Page(s) Selected
|
|||||||
multiTool.undo=Undo
|
multiTool.undo=Undo
|
||||||
multiTool.redo=Redo
|
multiTool.redo=Redo
|
||||||
|
|
||||||
|
#decrypt
|
||||||
|
decrypt.passwordPrompt=This file is password-protected. Please enter the password:
|
||||||
|
decrypt.cancelled=Operation cancelled for PDF: {0}
|
||||||
|
decrypt.noPassword=No password provided for encrypted PDF: {0}
|
||||||
|
decrypt.invalidPassword=Please try again with the correct password.
|
||||||
|
decrypt.invalidPasswordHeader=Incorrect password or unsupported encryption for PDF: {0}
|
||||||
|
decrypt.unexpectedError=There was an error processing the file. Please try again.
|
||||||
|
decrypt.serverError=Server error while decrypting: {0}
|
||||||
|
decrypt.success=File decrypted successfully.
|
||||||
|
|
||||||
#multiTool-advert
|
#multiTool-advert
|
||||||
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
||||||
|
|
||||||
@@ -1052,11 +1066,12 @@ addPassword.submit=Criptigh
|
|||||||
#watermark
|
#watermark
|
||||||
watermark.title=Cuir Uisce leis
|
watermark.title=Cuir Uisce leis
|
||||||
watermark.header=Cuir Uisce leis
|
watermark.header=Cuir Uisce leis
|
||||||
|
watermark.customColor=Dath Téacs Saincheaptha
|
||||||
watermark.selectText.1=Roghnaigh PDF chun comhartha uisce a chur leis:
|
watermark.selectText.1=Roghnaigh PDF chun comhartha uisce a chur leis:
|
||||||
watermark.selectText.2=Téacs Comhartha Uisce:
|
watermark.selectText.2=Téacs Comhartha Uisce:
|
||||||
watermark.selectText.3=Méid cló:
|
watermark.selectText.3=Méid cló:
|
||||||
watermark.selectText.4=Rothlú (0-360):
|
watermark.selectText.4=Rothlú (0-360):
|
||||||
watermark.selectText.5=widthSpacer (Spás idir gach comhartha uisce go cothrománach):
|
watermark.selectText.5=Width Spacer (Spás idir gach comhartha uisce go cothrománach):
|
||||||
watermark.selectText.6=spásaire airde (Spás idir gach comhartha uisce go hingearach):
|
watermark.selectText.6=spásaire airde (Spás idir gach comhartha uisce go hingearach):
|
||||||
watermark.selectText.7=Teimhneacht (0% - 100%):
|
watermark.selectText.7=Teimhneacht (0% - 100%):
|
||||||
watermark.selectText.8=Cineál Comhartha Uisce:
|
watermark.selectText.8=Cineál Comhartha Uisce:
|
||||||
@@ -1263,6 +1278,11 @@ splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata
|
|||||||
splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs.
|
splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs.
|
||||||
splitByChapters.submit=Split PDF
|
splitByChapters.submit=Split PDF
|
||||||
|
|
||||||
|
#File Chooser
|
||||||
|
fileChooser.click=Click
|
||||||
|
fileChooser.or=or
|
||||||
|
fileChooser.dragAndDrop=Drag & Drop
|
||||||
|
fileChooser.hoveredDragAndDrop=Drag & Drop file(s) here
|
||||||
|
|
||||||
#release notes
|
#release notes
|
||||||
releases.footer=Releases
|
releases.footer=Releases
|
||||||
@@ -1270,3 +1290,38 @@ releases.title=Release Notes
|
|||||||
releases.header=Release Notes
|
releases.header=Release Notes
|
||||||
releases.current.version=Current Release
|
releases.current.version=Current Release
|
||||||
releases.note=Release notes are only available in English
|
releases.note=Release notes are only available in English
|
||||||
|
|
||||||
|
#Validate Signature
|
||||||
|
validateSignature.title=Validate PDF Signatures
|
||||||
|
validateSignature.header=Validate Digital Signatures
|
||||||
|
validateSignature.selectPDF=Select signed PDF file
|
||||||
|
validateSignature.submit=Validate Signatures
|
||||||
|
validateSignature.results=Validation Results
|
||||||
|
validateSignature.status=Status
|
||||||
|
validateSignature.signer=Signer
|
||||||
|
validateSignature.date=Date
|
||||||
|
validateSignature.reason=Reason
|
||||||
|
validateSignature.location=Location
|
||||||
|
validateSignature.noSignatures=No digital signatures found in this document
|
||||||
|
validateSignature.status.valid=Valid
|
||||||
|
validateSignature.status.invalid=Invalid
|
||||||
|
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
|
||||||
|
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
|
||||||
|
validateSignature.cert.expired=Certificate has expired
|
||||||
|
validateSignature.cert.revoked=Certificate has been revoked
|
||||||
|
validateSignature.signature.info=Signature Information
|
||||||
|
validateSignature.signature=Signature
|
||||||
|
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
|
||||||
|
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
|
||||||
|
validateSignature.cert.info=Certificate Details
|
||||||
|
validateSignature.cert.issuer=Issuer
|
||||||
|
validateSignature.cert.subject=Subject
|
||||||
|
validateSignature.cert.serialNumber=Serial Number
|
||||||
|
validateSignature.cert.validFrom=Valid From
|
||||||
|
validateSignature.cert.validUntil=Valid Until
|
||||||
|
validateSignature.cert.algorithm=Algorithm
|
||||||
|
validateSignature.cert.keySize=Key Size
|
||||||
|
validateSignature.cert.version=Version
|
||||||
|
validateSignature.cert.keyUsage=Key Usage
|
||||||
|
validateSignature.cert.selfSigned=Self-Signed
|
||||||
|
validateSignature.cert.bits=bits
|
||||||
|
|||||||
@@ -512,6 +512,10 @@ home.splitPdfByChapters.title=अध्यायों पर अलग-कर
|
|||||||
home.splitPdfByChapters.desc=पुस्तक के अध्याय की संरचना पर आधारित एक PDF को बहिन-भागों में विभाजित करें
|
home.splitPdfByChapters.desc=पुस्तक के अध्याय की संरचना पर आधारित एक PDF को बहिन-भागों में विभाजित करें
|
||||||
splitPdfByChapters.tags=विभाजन,अध्याय,पसंदीदा,रजैत
|
splitPdfByChapters.tags=विभाजन,अध्याय,पसंदीदा,रजैत
|
||||||
|
|
||||||
|
home.validateSignature.title=Validate PDF Signature
|
||||||
|
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
|
||||||
|
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
|
||||||
|
|
||||||
#replace-invert-color
|
#replace-invert-color
|
||||||
replace-color.title=Replace-Invert-Color
|
replace-color.title=Replace-Invert-Color
|
||||||
replace-color.header=चित्र रंग परिवर्तन/उलटकर परिवर्तन PDF
|
replace-color.header=चित्र रंग परिवर्तन/उलटकर परिवर्तन PDF
|
||||||
@@ -961,6 +965,16 @@ multiTool.dragDropMessage=Page(s) Selected
|
|||||||
multiTool.undo=Undo
|
multiTool.undo=Undo
|
||||||
multiTool.redo=Redo
|
multiTool.redo=Redo
|
||||||
|
|
||||||
|
#decrypt
|
||||||
|
decrypt.passwordPrompt=This file is password-protected. Please enter the password:
|
||||||
|
decrypt.cancelled=Operation cancelled for PDF: {0}
|
||||||
|
decrypt.noPassword=No password provided for encrypted PDF: {0}
|
||||||
|
decrypt.invalidPassword=Please try again with the correct password.
|
||||||
|
decrypt.invalidPasswordHeader=Incorrect password or unsupported encryption for PDF: {0}
|
||||||
|
decrypt.unexpectedError=There was an error processing the file. Please try again.
|
||||||
|
decrypt.serverError=Server error while decrypting: {0}
|
||||||
|
decrypt.success=File decrypted successfully.
|
||||||
|
|
||||||
#multiTool-advert
|
#multiTool-advert
|
||||||
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
||||||
|
|
||||||
@@ -1052,6 +1066,7 @@ addPassword.submit=एन्क्रिप्ट करें
|
|||||||
#watermark
|
#watermark
|
||||||
watermark.title=वॉटरमार्क जोड़ें
|
watermark.title=वॉटरमार्क जोड़ें
|
||||||
watermark.header=वॉटरमार्क जोड़ें
|
watermark.header=वॉटरमार्क जोड़ें
|
||||||
|
watermark.customColor=संवैधित टेक्स्ट रंग
|
||||||
watermark.selectText.1=वॉटरमार्क जोड़ने के लिए पीडीएफ चुनें:
|
watermark.selectText.1=वॉटरमार्क जोड़ने के लिए पीडीएफ चुनें:
|
||||||
watermark.selectText.2=वॉटरमार्क टेक्स्ट:
|
watermark.selectText.2=वॉटरमार्क टेक्स्ट:
|
||||||
watermark.selectText.3=फ़ॉन्ट साइज़:
|
watermark.selectText.3=फ़ॉन्ट साइज़:
|
||||||
@@ -1263,6 +1278,11 @@ splitByChapters.desc.3=मॉडेटरेट का शामिल करे
|
|||||||
splitByChapters.desc.4=यादृच्छिक पुनरावृत्ति अनुमोदित: यदि सत्यापित किया जाता है, एक ही पेज पर दोहरे मूल्यांकन पब्लिक पीड़एफ बनाने की संभावना देता है।
|
splitByChapters.desc.4=यादृच्छिक पुनरावृत्ति अनुमोदित: यदि सत्यापित किया जाता है, एक ही पेज पर दोहरे मूल्यांकन पब्लिक पीड़एफ बनाने की संभावना देता है।
|
||||||
splitByChapters.submit=PDF विभाजित
|
splitByChapters.submit=PDF विभाजित
|
||||||
|
|
||||||
|
#File Chooser
|
||||||
|
fileChooser.click=Click
|
||||||
|
fileChooser.or=or
|
||||||
|
fileChooser.dragAndDrop=Drag & Drop
|
||||||
|
fileChooser.hoveredDragAndDrop=Drag & Drop file(s) here
|
||||||
|
|
||||||
#release notes
|
#release notes
|
||||||
releases.footer=Releases
|
releases.footer=Releases
|
||||||
@@ -1270,3 +1290,38 @@ releases.title=Release Notes
|
|||||||
releases.header=Release Notes
|
releases.header=Release Notes
|
||||||
releases.current.version=Current Release
|
releases.current.version=Current Release
|
||||||
releases.note=Release notes are only available in English
|
releases.note=Release notes are only available in English
|
||||||
|
|
||||||
|
#Validate Signature
|
||||||
|
validateSignature.title=Validate PDF Signatures
|
||||||
|
validateSignature.header=Validate Digital Signatures
|
||||||
|
validateSignature.selectPDF=Select signed PDF file
|
||||||
|
validateSignature.submit=Validate Signatures
|
||||||
|
validateSignature.results=Validation Results
|
||||||
|
validateSignature.status=Status
|
||||||
|
validateSignature.signer=Signer
|
||||||
|
validateSignature.date=Date
|
||||||
|
validateSignature.reason=Reason
|
||||||
|
validateSignature.location=Location
|
||||||
|
validateSignature.noSignatures=No digital signatures found in this document
|
||||||
|
validateSignature.status.valid=Valid
|
||||||
|
validateSignature.status.invalid=Invalid
|
||||||
|
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
|
||||||
|
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
|
||||||
|
validateSignature.cert.expired=Certificate has expired
|
||||||
|
validateSignature.cert.revoked=Certificate has been revoked
|
||||||
|
validateSignature.signature.info=Signature Information
|
||||||
|
validateSignature.signature=Signature
|
||||||
|
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
|
||||||
|
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
|
||||||
|
validateSignature.cert.info=Certificate Details
|
||||||
|
validateSignature.cert.issuer=Issuer
|
||||||
|
validateSignature.cert.subject=Subject
|
||||||
|
validateSignature.cert.serialNumber=Serial Number
|
||||||
|
validateSignature.cert.validFrom=Valid From
|
||||||
|
validateSignature.cert.validUntil=Valid Until
|
||||||
|
validateSignature.cert.algorithm=Algorithm
|
||||||
|
validateSignature.cert.keySize=Key Size
|
||||||
|
validateSignature.cert.version=Version
|
||||||
|
validateSignature.cert.keyUsage=Key Usage
|
||||||
|
validateSignature.cert.selfSigned=Self-Signed
|
||||||
|
validateSignature.cert.bits=bits
|
||||||
|
|||||||
@@ -512,6 +512,10 @@ home.splitPdfByChapters.title=Podijeli PDF prema glavama
|
|||||||
home.splitPdfByChapters.desc=Podijeli PDF na više datoteka prema njegovom strukturnom obliku glava.
|
home.splitPdfByChapters.desc=Podijeli PDF na više datoteka prema njegovom strukturnom obliku glava.
|
||||||
splitPdfByChapters.tags=podjela, glave, markere, organizacija
|
splitPdfByChapters.tags=podjela, glave, markere, organizacija
|
||||||
|
|
||||||
|
home.validateSignature.title=Validate PDF Signature
|
||||||
|
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
|
||||||
|
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
|
||||||
|
|
||||||
#replace-invert-color
|
#replace-invert-color
|
||||||
replace-color.title=Replace-Invert-Color
|
replace-color.title=Replace-Invert-Color
|
||||||
replace-color.header=Zameni-inverziranje boja u PDF-u
|
replace-color.header=Zameni-inverziranje boja u PDF-u
|
||||||
@@ -961,6 +965,16 @@ multiTool.dragDropMessage=Page(s) Selected
|
|||||||
multiTool.undo=Undo
|
multiTool.undo=Undo
|
||||||
multiTool.redo=Redo
|
multiTool.redo=Redo
|
||||||
|
|
||||||
|
#decrypt
|
||||||
|
decrypt.passwordPrompt=This file is password-protected. Please enter the password:
|
||||||
|
decrypt.cancelled=Operation cancelled for PDF: {0}
|
||||||
|
decrypt.noPassword=No password provided for encrypted PDF: {0}
|
||||||
|
decrypt.invalidPassword=Please try again with the correct password.
|
||||||
|
decrypt.invalidPasswordHeader=Incorrect password or unsupported encryption for PDF: {0}
|
||||||
|
decrypt.unexpectedError=There was an error processing the file. Please try again.
|
||||||
|
decrypt.serverError=Server error while decrypting: {0}
|
||||||
|
decrypt.success=File decrypted successfully.
|
||||||
|
|
||||||
#multiTool-advert
|
#multiTool-advert
|
||||||
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
||||||
|
|
||||||
@@ -1052,6 +1066,7 @@ addPassword.submit=Šifriraj
|
|||||||
#watermark
|
#watermark
|
||||||
watermark.title=Dodaj vodeni žig
|
watermark.title=Dodaj vodeni žig
|
||||||
watermark.header=Dodaj vodeni žig
|
watermark.header=Dodaj vodeni žig
|
||||||
|
watermark.customColor=Prilagođena boja teksta
|
||||||
watermark.selectText.1=Izaberite PDF za dodavanje vodenog žiga:
|
watermark.selectText.1=Izaberite PDF za dodavanje vodenog žiga:
|
||||||
watermark.selectText.2=Tekst vodenog žiga:
|
watermark.selectText.2=Tekst vodenog žiga:
|
||||||
watermark.selectText.3=Veličina fonta:
|
watermark.selectText.3=Veličina fonta:
|
||||||
@@ -1263,6 +1278,11 @@ splitByChapters.desc.3=Uključi metapodatke: Ako je pokušano, metapodaci iz ori
|
|||||||
splitByChapters.desc.4=Dopuštaj duplikate: Ako je ova opcija zaštićena, dozvoljava se da se na istoj strani mogu stvoriti posebne PDF datoteke s više oznaka.
|
splitByChapters.desc.4=Dopuštaj duplikate: Ako je ova opcija zaštićena, dozvoljava se da se na istoj strani mogu stvoriti posebne PDF datoteke s više oznaka.
|
||||||
splitByChapters.submit=Podijeli PDF
|
splitByChapters.submit=Podijeli PDF
|
||||||
|
|
||||||
|
#File Chooser
|
||||||
|
fileChooser.click=Click
|
||||||
|
fileChooser.or=or
|
||||||
|
fileChooser.dragAndDrop=Drag & Drop
|
||||||
|
fileChooser.hoveredDragAndDrop=Drag & Drop file(s) here
|
||||||
|
|
||||||
#release notes
|
#release notes
|
||||||
releases.footer=Releases
|
releases.footer=Releases
|
||||||
@@ -1270,3 +1290,38 @@ releases.title=Release Notes
|
|||||||
releases.header=Release Notes
|
releases.header=Release Notes
|
||||||
releases.current.version=Current Release
|
releases.current.version=Current Release
|
||||||
releases.note=Release notes are only available in English
|
releases.note=Release notes are only available in English
|
||||||
|
|
||||||
|
#Validate Signature
|
||||||
|
validateSignature.title=Validate PDF Signatures
|
||||||
|
validateSignature.header=Validate Digital Signatures
|
||||||
|
validateSignature.selectPDF=Select signed PDF file
|
||||||
|
validateSignature.submit=Validate Signatures
|
||||||
|
validateSignature.results=Validation Results
|
||||||
|
validateSignature.status=Status
|
||||||
|
validateSignature.signer=Signer
|
||||||
|
validateSignature.date=Date
|
||||||
|
validateSignature.reason=Reason
|
||||||
|
validateSignature.location=Location
|
||||||
|
validateSignature.noSignatures=No digital signatures found in this document
|
||||||
|
validateSignature.status.valid=Valid
|
||||||
|
validateSignature.status.invalid=Invalid
|
||||||
|
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
|
||||||
|
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
|
||||||
|
validateSignature.cert.expired=Certificate has expired
|
||||||
|
validateSignature.cert.revoked=Certificate has been revoked
|
||||||
|
validateSignature.signature.info=Signature Information
|
||||||
|
validateSignature.signature=Signature
|
||||||
|
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
|
||||||
|
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
|
||||||
|
validateSignature.cert.info=Certificate Details
|
||||||
|
validateSignature.cert.issuer=Issuer
|
||||||
|
validateSignature.cert.subject=Subject
|
||||||
|
validateSignature.cert.serialNumber=Serial Number
|
||||||
|
validateSignature.cert.validFrom=Valid From
|
||||||
|
validateSignature.cert.validUntil=Valid Until
|
||||||
|
validateSignature.cert.algorithm=Algorithm
|
||||||
|
validateSignature.cert.keySize=Key Size
|
||||||
|
validateSignature.cert.version=Version
|
||||||
|
validateSignature.cert.keyUsage=Key Usage
|
||||||
|
validateSignature.cert.selfSigned=Self-Signed
|
||||||
|
validateSignature.cert.bits=bits
|
||||||
|
|||||||
@@ -512,6 +512,10 @@ home.splitPdfByChapters.title=PDF felosztása fejezetek szerint
|
|||||||
home.splitPdfByChapters.desc=Fejezetei alapján egy PDF fájl több dokumentumba osztás.
|
home.splitPdfByChapters.desc=Fejezetei alapján egy PDF fájl több dokumentumba osztás.
|
||||||
splitPdfByChapters.tags=Osztás, fejezetek, jelezes, organizálás
|
splitPdfByChapters.tags=Osztás, fejezetek, jelezes, organizálás
|
||||||
|
|
||||||
|
home.validateSignature.title=Validate PDF Signature
|
||||||
|
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
|
||||||
|
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
|
||||||
|
|
||||||
#replace-invert-color
|
#replace-invert-color
|
||||||
replace-color.title=Replace-Invert-Color
|
replace-color.title=Replace-Invert-Color
|
||||||
replace-color.header=Visszaalakítás-összevétel a színekkel PDF-ben
|
replace-color.header=Visszaalakítás-összevétel a színekkel PDF-ben
|
||||||
@@ -961,6 +965,16 @@ multiTool.dragDropMessage=Page(s) Selected
|
|||||||
multiTool.undo=Undo
|
multiTool.undo=Undo
|
||||||
multiTool.redo=Redo
|
multiTool.redo=Redo
|
||||||
|
|
||||||
|
#decrypt
|
||||||
|
decrypt.passwordPrompt=This file is password-protected. Please enter the password:
|
||||||
|
decrypt.cancelled=Operation cancelled for PDF: {0}
|
||||||
|
decrypt.noPassword=No password provided for encrypted PDF: {0}
|
||||||
|
decrypt.invalidPassword=Please try again with the correct password.
|
||||||
|
decrypt.invalidPasswordHeader=Incorrect password or unsupported encryption for PDF: {0}
|
||||||
|
decrypt.unexpectedError=There was an error processing the file. Please try again.
|
||||||
|
decrypt.serverError=Server error while decrypting: {0}
|
||||||
|
decrypt.success=File decrypted successfully.
|
||||||
|
|
||||||
#multiTool-advert
|
#multiTool-advert
|
||||||
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
||||||
|
|
||||||
@@ -1052,12 +1066,13 @@ addPassword.submit=Titkosítás
|
|||||||
#watermark
|
#watermark
|
||||||
watermark.title=Vízjel hozzáadása
|
watermark.title=Vízjel hozzáadása
|
||||||
watermark.header=Vízjel hozzáadása
|
watermark.header=Vízjel hozzáadása
|
||||||
|
watermark.customColor=Egyéni szövegszín
|
||||||
watermark.selectText.1=Válassza ki a PDF-t, amelyhez vízjelet kíván hozzáadni:
|
watermark.selectText.1=Válassza ki a PDF-t, amelyhez vízjelet kíván hozzáadni:
|
||||||
watermark.selectText.2=Vízjel szövege:
|
watermark.selectText.2=Vízjel szövege:
|
||||||
watermark.selectText.3=Betűméret:
|
watermark.selectText.3=Betűméret:
|
||||||
watermark.selectText.4=Forgatás (0-360):
|
watermark.selectText.4=Forgatás (0-360):
|
||||||
watermark.selectText.5=widthSpacer (Hely a vízjelek között vízszintesen):
|
watermark.selectText.5=Width Spacer (Hely a vízjelek között vízszintesen):
|
||||||
watermark.selectText.6=heightSpacer (Hely a vízjelek között függőlegesen):
|
watermark.selectText.6=Height Spacer (Hely a vízjelek között függőlegesen):
|
||||||
watermark.selectText.7=Átlátszóság (0% - 100%):
|
watermark.selectText.7=Átlátszóság (0% - 100%):
|
||||||
watermark.selectText.8=Vízjel típusa:
|
watermark.selectText.8=Vízjel típusa:
|
||||||
watermark.selectText.9=Vízjel képe:
|
watermark.selectText.9=Vízjel képe:
|
||||||
@@ -1263,6 +1278,11 @@ splitByChapters.desc.3=Metaadatok belefoglalása: Ha bevanítva van, az eredeti
|
|||||||
splitByChapters.desc.4=Duplikációk engedélyezése: Ha bevanítva van, lehetővé teszi a megadott oldalon lévő több kijelzőszint alapján új PDF-ek létrehozása.
|
splitByChapters.desc.4=Duplikációk engedélyezése: Ha bevanítva van, lehetővé teszi a megadott oldalon lévő több kijelzőszint alapján új PDF-ek létrehozása.
|
||||||
splitByChapters.submit=PDF osztás
|
splitByChapters.submit=PDF osztás
|
||||||
|
|
||||||
|
#File Chooser
|
||||||
|
fileChooser.click=Click
|
||||||
|
fileChooser.or=or
|
||||||
|
fileChooser.dragAndDrop=Drag & Drop
|
||||||
|
fileChooser.hoveredDragAndDrop=Drag & Drop file(s) here
|
||||||
|
|
||||||
#release notes
|
#release notes
|
||||||
releases.footer=Releases
|
releases.footer=Releases
|
||||||
@@ -1270,3 +1290,38 @@ releases.title=Release Notes
|
|||||||
releases.header=Release Notes
|
releases.header=Release Notes
|
||||||
releases.current.version=Current Release
|
releases.current.version=Current Release
|
||||||
releases.note=Release notes are only available in English
|
releases.note=Release notes are only available in English
|
||||||
|
|
||||||
|
#Validate Signature
|
||||||
|
validateSignature.title=Validate PDF Signatures
|
||||||
|
validateSignature.header=Validate Digital Signatures
|
||||||
|
validateSignature.selectPDF=Select signed PDF file
|
||||||
|
validateSignature.submit=Validate Signatures
|
||||||
|
validateSignature.results=Validation Results
|
||||||
|
validateSignature.status=Status
|
||||||
|
validateSignature.signer=Signer
|
||||||
|
validateSignature.date=Date
|
||||||
|
validateSignature.reason=Reason
|
||||||
|
validateSignature.location=Location
|
||||||
|
validateSignature.noSignatures=No digital signatures found in this document
|
||||||
|
validateSignature.status.valid=Valid
|
||||||
|
validateSignature.status.invalid=Invalid
|
||||||
|
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
|
||||||
|
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
|
||||||
|
validateSignature.cert.expired=Certificate has expired
|
||||||
|
validateSignature.cert.revoked=Certificate has been revoked
|
||||||
|
validateSignature.signature.info=Signature Information
|
||||||
|
validateSignature.signature=Signature
|
||||||
|
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
|
||||||
|
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
|
||||||
|
validateSignature.cert.info=Certificate Details
|
||||||
|
validateSignature.cert.issuer=Issuer
|
||||||
|
validateSignature.cert.subject=Subject
|
||||||
|
validateSignature.cert.serialNumber=Serial Number
|
||||||
|
validateSignature.cert.validFrom=Valid From
|
||||||
|
validateSignature.cert.validUntil=Valid Until
|
||||||
|
validateSignature.cert.algorithm=Algorithm
|
||||||
|
validateSignature.cert.keySize=Key Size
|
||||||
|
validateSignature.cert.version=Version
|
||||||
|
validateSignature.cert.keyUsage=Key Usage
|
||||||
|
validateSignature.cert.selfSigned=Self-Signed
|
||||||
|
validateSignature.cert.bits=bits
|
||||||
|
|||||||
@@ -512,6 +512,10 @@ home.splitPdfByChapters.title=Pisahkan PDF berdasarkan Bab
|
|||||||
home.splitPdfByChapters.desc=Memisahkan PDF menjadi beberapa file berdasarkan struktur babnya.
|
home.splitPdfByChapters.desc=Memisahkan PDF menjadi beberapa file berdasarkan struktur babnya.
|
||||||
splitPdfByChapters.tags=pemisahan,bab,bookmark,atur
|
splitPdfByChapters.tags=pemisahan,bab,bookmark,atur
|
||||||
|
|
||||||
|
home.validateSignature.title=Validate PDF Signature
|
||||||
|
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
|
||||||
|
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
|
||||||
|
|
||||||
#replace-invert-color
|
#replace-invert-color
|
||||||
replace-color.title=Ganti-Inversi-Warna
|
replace-color.title=Ganti-Inversi-Warna
|
||||||
replace-color.header=Ganti-Inversi Warna PDF
|
replace-color.header=Ganti-Inversi Warna PDF
|
||||||
@@ -961,6 +965,16 @@ multiTool.dragDropMessage=Page(s) Selected
|
|||||||
multiTool.undo=Undo
|
multiTool.undo=Undo
|
||||||
multiTool.redo=Redo
|
multiTool.redo=Redo
|
||||||
|
|
||||||
|
#decrypt
|
||||||
|
decrypt.passwordPrompt=This file is password-protected. Please enter the password:
|
||||||
|
decrypt.cancelled=Operation cancelled for PDF: {0}
|
||||||
|
decrypt.noPassword=No password provided for encrypted PDF: {0}
|
||||||
|
decrypt.invalidPassword=Please try again with the correct password.
|
||||||
|
decrypt.invalidPasswordHeader=Incorrect password or unsupported encryption for PDF: {0}
|
||||||
|
decrypt.unexpectedError=There was an error processing the file. Please try again.
|
||||||
|
decrypt.serverError=Server error while decrypting: {0}
|
||||||
|
decrypt.success=File decrypted successfully.
|
||||||
|
|
||||||
#multiTool-advert
|
#multiTool-advert
|
||||||
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
||||||
|
|
||||||
@@ -1052,12 +1066,13 @@ addPassword.submit=Enkripsi
|
|||||||
#watermark
|
#watermark
|
||||||
watermark.title=Tambahkan Watermark
|
watermark.title=Tambahkan Watermark
|
||||||
watermark.header=Tambahkan Watermark
|
watermark.header=Tambahkan Watermark
|
||||||
|
watermark.customColor=Warna Teks Kustom
|
||||||
watermark.selectText.1=Pilih PDF untuk menambahkan watermark:
|
watermark.selectText.1=Pilih PDF untuk menambahkan watermark:
|
||||||
watermark.selectText.2=Text Watermark:
|
watermark.selectText.2=Text Watermark:
|
||||||
watermark.selectText.3=Ukuran Huruf:
|
watermark.selectText.3=Ukuran Huruf:
|
||||||
watermark.selectText.4=Rotasi (0-360):
|
watermark.selectText.4=Rotasi (0-360):
|
||||||
watermark.selectText.5=widthSpacer (Spasi diantara setiap watermark horisontal):
|
watermark.selectText.5=Width Spacer (Spasi diantara setiap watermark horisontal):
|
||||||
watermark.selectText.6=heightSpacer (Spasi diantara setiap watermark vertikal):
|
watermark.selectText.6=Height Spacer (Spasi diantara setiap watermark vertikal):
|
||||||
watermark.selectText.7=Kejernihan (0% - 100%):
|
watermark.selectText.7=Kejernihan (0% - 100%):
|
||||||
watermark.selectText.8=Tipe Watermark:
|
watermark.selectText.8=Tipe Watermark:
|
||||||
watermark.selectText.9=Gambar Watermark:
|
watermark.selectText.9=Gambar Watermark:
|
||||||
@@ -1263,6 +1278,11 @@ splitByChapters.desc.3=Termasuk Metadata: Jika dicentang, metadata asli PDF akan
|
|||||||
splitByChapters.desc.4=Izinkan Duplikat: Jika dicentang, mengizinkan beberapa markah pada halaman yang sama untuk membuat PDF terpisah.
|
splitByChapters.desc.4=Izinkan Duplikat: Jika dicentang, mengizinkan beberapa markah pada halaman yang sama untuk membuat PDF terpisah.
|
||||||
splitByChapters.submit=Pecah PDF
|
splitByChapters.submit=Pecah PDF
|
||||||
|
|
||||||
|
#File Chooser
|
||||||
|
fileChooser.click=Click
|
||||||
|
fileChooser.or=or
|
||||||
|
fileChooser.dragAndDrop=Drag & Drop
|
||||||
|
fileChooser.hoveredDragAndDrop=Drag & Drop file(s) here
|
||||||
|
|
||||||
#release notes
|
#release notes
|
||||||
releases.footer=Releases
|
releases.footer=Releases
|
||||||
@@ -1270,3 +1290,38 @@ releases.title=Release Notes
|
|||||||
releases.header=Release Notes
|
releases.header=Release Notes
|
||||||
releases.current.version=Current Release
|
releases.current.version=Current Release
|
||||||
releases.note=Release notes are only available in English
|
releases.note=Release notes are only available in English
|
||||||
|
|
||||||
|
#Validate Signature
|
||||||
|
validateSignature.title=Validate PDF Signatures
|
||||||
|
validateSignature.header=Validate Digital Signatures
|
||||||
|
validateSignature.selectPDF=Select signed PDF file
|
||||||
|
validateSignature.submit=Validate Signatures
|
||||||
|
validateSignature.results=Validation Results
|
||||||
|
validateSignature.status=Status
|
||||||
|
validateSignature.signer=Signer
|
||||||
|
validateSignature.date=Date
|
||||||
|
validateSignature.reason=Reason
|
||||||
|
validateSignature.location=Location
|
||||||
|
validateSignature.noSignatures=No digital signatures found in this document
|
||||||
|
validateSignature.status.valid=Valid
|
||||||
|
validateSignature.status.invalid=Invalid
|
||||||
|
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
|
||||||
|
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
|
||||||
|
validateSignature.cert.expired=Certificate has expired
|
||||||
|
validateSignature.cert.revoked=Certificate has been revoked
|
||||||
|
validateSignature.signature.info=Signature Information
|
||||||
|
validateSignature.signature=Signature
|
||||||
|
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
|
||||||
|
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
|
||||||
|
validateSignature.cert.info=Certificate Details
|
||||||
|
validateSignature.cert.issuer=Issuer
|
||||||
|
validateSignature.cert.subject=Subject
|
||||||
|
validateSignature.cert.serialNumber=Serial Number
|
||||||
|
validateSignature.cert.validFrom=Valid From
|
||||||
|
validateSignature.cert.validUntil=Valid Until
|
||||||
|
validateSignature.cert.algorithm=Algorithm
|
||||||
|
validateSignature.cert.keySize=Key Size
|
||||||
|
validateSignature.cert.version=Version
|
||||||
|
validateSignature.cert.keyUsage=Key Usage
|
||||||
|
validateSignature.cert.selfSigned=Self-Signed
|
||||||
|
validateSignature.cert.bits=bits
|
||||||
|
|||||||
@@ -512,6 +512,10 @@ home.splitPdfByChapters.title=Dividi PDF per capitoli
|
|||||||
home.splitPdfByChapters.desc=Dividi un PDF in più file in base alla struttura dei capitoli.
|
home.splitPdfByChapters.desc=Dividi un PDF in più file in base alla struttura dei capitoli.
|
||||||
splitPdfByChapters.tags=dividi, capitoli, segnalibri, organizza
|
splitPdfByChapters.tags=dividi, capitoli, segnalibri, organizza
|
||||||
|
|
||||||
|
home.validateSignature.title=Convalida la firma PDF
|
||||||
|
home.validateSignature.desc=Verificare le firme digitali e i certificati nei documenti PDF
|
||||||
|
validateSignature.tags=firma,verifica,convalida,pdf,certificato,firma digitale,convalida firma,convalida certificato
|
||||||
|
|
||||||
#replace-invert-color
|
#replace-invert-color
|
||||||
replace-color.title=Sostituisci-Inverti-Colore
|
replace-color.title=Sostituisci-Inverti-Colore
|
||||||
replace-color.header=Sostituisci-Inverti colore PDF
|
replace-color.header=Sostituisci-Inverti colore PDF
|
||||||
@@ -958,8 +962,18 @@ multiTool.moveLeft=Sposta a sinistra
|
|||||||
multiTool.moveRight=Sposta a destra
|
multiTool.moveRight=Sposta a destra
|
||||||
multiTool.delete=Elimina
|
multiTool.delete=Elimina
|
||||||
multiTool.dragDropMessage=Pagina(e) selezionata(e)
|
multiTool.dragDropMessage=Pagina(e) selezionata(e)
|
||||||
multiTool.undo=Undo
|
multiTool.undo=Annulla
|
||||||
multiTool.redo=Redo
|
multiTool.redo=Rifai
|
||||||
|
|
||||||
|
#decrypt
|
||||||
|
decrypt.passwordPrompt=Questo file è protetto da password. Inserisci la password:
|
||||||
|
decrypt.cancelled=Operazione annullata per il PDF: {0}
|
||||||
|
decrypt.noPassword=Nessuna password fornita per il PDF crittografato: {0}
|
||||||
|
decrypt.invalidPassword=Riprova con la password corretta.
|
||||||
|
decrypt.invalidPasswordHeader=Password errata o crittografia non supportata per il PDF: {0}
|
||||||
|
decrypt.unexpectedError=Si è verificato un errore durante l'elaborazione del file. Riprova..
|
||||||
|
decrypt.serverError=Errore del server durante la decrittazione: {0}
|
||||||
|
decrypt.success=File decrittografato con successo.
|
||||||
|
|
||||||
#multiTool-advert
|
#multiTool-advert
|
||||||
multiTool-advert.message=Questa funzione è disponibile anche nella nostra <a href="{0}">pagina multi-strumento</a>. Scoprila per un'interfaccia utente pagina per pagina migliorata e funzionalità aggiuntive!
|
multiTool-advert.message=Questa funzione è disponibile anche nella nostra <a href="{0}">pagina multi-strumento</a>. Scoprila per un'interfaccia utente pagina per pagina migliorata e funzionalità aggiuntive!
|
||||||
@@ -1052,6 +1066,7 @@ addPassword.submit=Crittografa
|
|||||||
#watermark
|
#watermark
|
||||||
watermark.title=Aggiungi Filigrana
|
watermark.title=Aggiungi Filigrana
|
||||||
watermark.header=Aggiungi filigrana
|
watermark.header=Aggiungi filigrana
|
||||||
|
watermark.customColor=Colore testo personalizzato
|
||||||
watermark.selectText.1=Seleziona PDF a cui aggiungere la filigrana:
|
watermark.selectText.1=Seleziona PDF a cui aggiungere la filigrana:
|
||||||
watermark.selectText.2=Testo:
|
watermark.selectText.2=Testo:
|
||||||
watermark.selectText.3=Dimensione carattere:
|
watermark.selectText.3=Dimensione carattere:
|
||||||
@@ -1263,6 +1278,11 @@ splitByChapters.desc.3=Includi metadati: se selezionato, i metadati del PDF orig
|
|||||||
splitByChapters.desc.4=Consenti duplicati: se selezionata, consente più segnalibri sulla stessa pagina per creare PDF separati.
|
splitByChapters.desc.4=Consenti duplicati: se selezionata, consente più segnalibri sulla stessa pagina per creare PDF separati.
|
||||||
splitByChapters.submit=Dividi PDF
|
splitByChapters.submit=Dividi PDF
|
||||||
|
|
||||||
|
#File Chooser
|
||||||
|
fileChooser.click=Clicca
|
||||||
|
fileChooser.or=o
|
||||||
|
fileChooser.dragAndDrop=Trascina & Rilascia
|
||||||
|
fileChooser.hoveredDragAndDrop=Trascina & rilascia i file qui
|
||||||
|
|
||||||
#release notes
|
#release notes
|
||||||
releases.footer=Rilasci
|
releases.footer=Rilasci
|
||||||
@@ -1270,3 +1290,38 @@ releases.title=Note di rilascio
|
|||||||
releases.header=Note di rilascio
|
releases.header=Note di rilascio
|
||||||
releases.current.version=Rilascio corrente
|
releases.current.version=Rilascio corrente
|
||||||
releases.note=Le note di rilascio sono disponibili solo in inglese
|
releases.note=Le note di rilascio sono disponibili solo in inglese
|
||||||
|
|
||||||
|
#Validate Signature
|
||||||
|
validateSignature.title=Validare le firme PDF
|
||||||
|
validateSignature.header=Convalidare le firme digitali
|
||||||
|
validateSignature.selectPDF=Seleziona il file PDF firmato
|
||||||
|
validateSignature.submit=Convalida firme
|
||||||
|
validateSignature.results=Risultati di convalida
|
||||||
|
validateSignature.status=Stato
|
||||||
|
validateSignature.signer=Firmatario
|
||||||
|
validateSignature.date=Data
|
||||||
|
validateSignature.reason=Ragione
|
||||||
|
validateSignature.location=Posizione
|
||||||
|
validateSignature.noSignatures=Nessuna firma digitale trovata in questo documento
|
||||||
|
validateSignature.status.valid=Valida
|
||||||
|
validateSignature.status.invalid=Invalida
|
||||||
|
validateSignature.chain.invalid=Convalida della catena di certificati non riuscita: impossibile verificare l'identità del firmatario
|
||||||
|
validateSignature.trust.invalid=Certificato non presente nell'archivio attendibile: la fonte non può essere verificata
|
||||||
|
validateSignature.cert.expired=Il certificato è scaduto
|
||||||
|
validateSignature.cert.revoked=Il certificato è stato revocato
|
||||||
|
validateSignature.signature.info=Informazioni sulla firma
|
||||||
|
validateSignature.signature=Firma
|
||||||
|
validateSignature.signature.mathValid=La firma è matematicamente valida MA:
|
||||||
|
validateSignature.selectCustomCert=File di certificato personalizzato X.509 (opzionale)
|
||||||
|
validateSignature.cert.info=Dettagli del certificato
|
||||||
|
validateSignature.cert.issuer=Emittente
|
||||||
|
validateSignature.cert.subject=Soggetto
|
||||||
|
validateSignature.cert.serialNumber=Numero di serie
|
||||||
|
validateSignature.cert.validFrom=Valido da
|
||||||
|
validateSignature.cert.validUntil=Valido fino a
|
||||||
|
validateSignature.cert.algorithm=Algoritmo
|
||||||
|
validateSignature.cert.keySize=Dimensione chiave
|
||||||
|
validateSignature.cert.version=Versione
|
||||||
|
validateSignature.cert.keyUsage=Utilizzo della chiave
|
||||||
|
validateSignature.cert.selfSigned=Autofirmato
|
||||||
|
validateSignature.cert.bits=bit
|
||||||
|
|||||||
@@ -56,12 +56,12 @@ userNotFoundMessage=ユーザーが見つかりません。
|
|||||||
incorrectPasswordMessage=現在のパスワードが正しくありません。
|
incorrectPasswordMessage=現在のパスワードが正しくありません。
|
||||||
usernameExistsMessage=新しいユーザー名はすでに存在します。
|
usernameExistsMessage=新しいユーザー名はすでに存在します。
|
||||||
invalidUsernameMessage=ユーザー名が無効です。ユーザー名には文字、数字、およびそれに続く特殊文字 @._+- のみを含めることができます。または、有効な電子メール アドレスである必要があります。
|
invalidUsernameMessage=ユーザー名が無効です。ユーザー名には文字、数字、およびそれに続く特殊文字 @._+- のみを含めることができます。または、有効な電子メール アドレスである必要があります。
|
||||||
invalidPasswordMessage=The password must not be empty and must not have spaces at the beginning or end.
|
invalidPasswordMessage=パスワードは空にすることはできません。また、先頭・末尾にスペースを含めることもできません。
|
||||||
confirmPasswordErrorMessage=新しいパスワードと新しいパスワードの確認は一致する必要があります。
|
confirmPasswordErrorMessage=新しいパスワードと新しいパスワードの確認は一致する必要があります。
|
||||||
deleteCurrentUserMessage=現在ログインしているユーザーは削除できません。
|
deleteCurrentUserMessage=現在ログインしているユーザーは削除できません。
|
||||||
deleteUsernameExistsMessage=そのユーザー名は存在しないため削除できません。
|
deleteUsernameExistsMessage=そのユーザー名は存在しないため削除できません。
|
||||||
downgradeCurrentUserMessage=現在のユーザーの役割をダウングレードできません
|
downgradeCurrentUserMessage=現在のユーザーの役割をダウングレードできません
|
||||||
disabledCurrentUserMessage=The current user cannot be disabled
|
disabledCurrentUserMessage=現在のユーザーを無効にすることはできません
|
||||||
downgradeCurrentUserLongMessage=現在のユーザーの役割をダウングレードできません。したがって、現在のユーザーは表示されません。
|
downgradeCurrentUserLongMessage=現在のユーザーの役割をダウングレードできません。したがって、現在のユーザーは表示されません。
|
||||||
userAlreadyExistsOAuthMessage=ユーザーは既にOAuth2ユーザーとして存在します。
|
userAlreadyExistsOAuthMessage=ユーザーは既にOAuth2ユーザーとして存在します。
|
||||||
userAlreadyExistsWebMessage=ユーザーは既にWebユーザーとして存在します。
|
userAlreadyExistsWebMessage=ユーザーは既にWebユーザーとして存在します。
|
||||||
@@ -76,12 +76,12 @@ donate=寄付する
|
|||||||
color=色
|
color=色
|
||||||
sponsor=スポンサー
|
sponsor=スポンサー
|
||||||
info=Info
|
info=Info
|
||||||
pro=Pro
|
pro=pro
|
||||||
page=Page
|
page=ページ
|
||||||
pages=Pages
|
pages=ページ
|
||||||
loading=Loading...
|
loading=読込中...
|
||||||
addToDoc=Add to Document
|
addToDoc=ドキュメントに追加
|
||||||
reset=Reset
|
reset=リセット
|
||||||
|
|
||||||
legal.privacy=プライバシーポリシー
|
legal.privacy=プライバシーポリシー
|
||||||
legal.terms=利用規約
|
legal.terms=利用規約
|
||||||
@@ -92,7 +92,7 @@ legal.impressum=著作権利者情報
|
|||||||
###############
|
###############
|
||||||
# Pipeline #
|
# Pipeline #
|
||||||
###############
|
###############
|
||||||
pipeline.header=パイプラインメニュー (Alpha)
|
pipeline.header=パイプラインメニュー (Beta)
|
||||||
pipeline.uploadButton=カスタムのアップロード
|
pipeline.uploadButton=カスタムのアップロード
|
||||||
pipeline.configureButton=設定
|
pipeline.configureButton=設定
|
||||||
pipeline.defaultOption=カスタム
|
pipeline.defaultOption=カスタム
|
||||||
@@ -117,21 +117,21 @@ pipelineOptions.validateButton=検証
|
|||||||
########################
|
########################
|
||||||
# ENTERPRISE EDITION #
|
# ENTERPRISE EDITION #
|
||||||
########################
|
########################
|
||||||
enterpriseEdition.button=Upgrade to Pro
|
enterpriseEdition.button=Proにアップグレード
|
||||||
enterpriseEdition.warning=This feature is only available to Pro users.
|
enterpriseEdition.warning=この機能はProユーザーのみが利用できます。
|
||||||
enterpriseEdition.yamlAdvert=Stirling PDF Pro supports YAML configuration files and other SSO features.
|
enterpriseEdition.yamlAdvert=Stirling PDF Proは、YAML構成ファイルやその他のSSO機能をサポートしています。
|
||||||
enterpriseEdition.ssoAdvert=Looking for more user management features? Check out Stirling PDF Pro
|
enterpriseEdition.ssoAdvert=より多くのユーザー管理機能をお探しですか? Stirling PDF Proをご覧ください
|
||||||
|
|
||||||
|
|
||||||
#################
|
#################
|
||||||
# Analytics #
|
# Analytics #
|
||||||
#################
|
#################
|
||||||
analytics.title=Do you want make Stirling PDF better?
|
analytics.title=Stirling PDFをもっと良くしたいですか?
|
||||||
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.paragraph1=Stirling PDFでは、製品の改善に役立つ分析機能をオプトインしています。個人情報やファイルの内容を追跡することはありません。
|
||||||
analytics.paragraph2=Please consider enabling analytics to help Stirling-PDF grow and to allow us to understand our users better.
|
analytics.paragraph2=Stirling-PDFの成長を支援しユーザーをより深く理解できるように分析を有効にすることを検討してください。
|
||||||
analytics.enable=Enable analytics
|
analytics.enable=分析を有効にする
|
||||||
analytics.disable=Disable analytics
|
analytics.disable=分析を無効にする
|
||||||
analytics.settings=You can change the settings for analytics in the config/settings.yml file
|
analytics.settings=config/settings.ymlファイルでアナリティクスの設定を変更できます。
|
||||||
|
|
||||||
#############
|
#############
|
||||||
# NAVBAR #
|
# NAVBAR #
|
||||||
@@ -142,14 +142,14 @@ navbar.language=言語
|
|||||||
navbar.settings=設定
|
navbar.settings=設定
|
||||||
navbar.allTools=ツール
|
navbar.allTools=ツール
|
||||||
navbar.multiTool=マルチツール
|
navbar.multiTool=マルチツール
|
||||||
navbar.search=Search
|
navbar.search=検索
|
||||||
navbar.sections.organize=整理
|
navbar.sections.organize=整理
|
||||||
navbar.sections.convertTo=PDFへ変換
|
navbar.sections.convertTo=PDFへ変換
|
||||||
navbar.sections.convertFrom=PDFから変換
|
navbar.sections.convertFrom=PDFから変換
|
||||||
navbar.sections.security=署名とセキュリティ
|
navbar.sections.security=署名とセキュリティ
|
||||||
navbar.sections.advance=アドバンスド
|
navbar.sections.advance=アドバンスド
|
||||||
navbar.sections.edit=閲覧と編集
|
navbar.sections.edit=閲覧と編集
|
||||||
navbar.sections.popular=Popular
|
navbar.sections.popular=人気
|
||||||
|
|
||||||
#############
|
#############
|
||||||
# SETTINGS #
|
# SETTINGS #
|
||||||
@@ -208,7 +208,7 @@ adminUserSettings.user=ユーザー
|
|||||||
adminUserSettings.addUser=新しいユーザを追加
|
adminUserSettings.addUser=新しいユーザを追加
|
||||||
adminUserSettings.deleteUser=ユーザの削除
|
adminUserSettings.deleteUser=ユーザの削除
|
||||||
adminUserSettings.confirmDeleteUser=ユーザを本当に削除しますか?
|
adminUserSettings.confirmDeleteUser=ユーザを本当に削除しますか?
|
||||||
adminUserSettings.confirmChangeUserStatus=Should the user be disabled/enabled?
|
adminUserSettings.confirmChangeUserStatus=ユーザーを無効/有効にする必要がありますか?
|
||||||
adminUserSettings.usernameInfo=ユーザー名には、文字、数字、および次の特殊文字 @._+- のみを含めることができます。または、有効な電子メール アドレスである必要があります。
|
adminUserSettings.usernameInfo=ユーザー名には、文字、数字、および次の特殊文字 @._+- のみを含めることができます。または、有効な電子メール アドレスである必要があります。
|
||||||
adminUserSettings.roles=役割
|
adminUserSettings.roles=役割
|
||||||
adminUserSettings.role=役割
|
adminUserSettings.role=役割
|
||||||
@@ -247,8 +247,8 @@ database.fileNotFound=ファイルが見つかりません
|
|||||||
database.fileNullOrEmpty=ファイルは null または空であってはなりません
|
database.fileNullOrEmpty=ファイルは null または空であってはなりません
|
||||||
database.failedImportFile=ファイルのインポートに失敗
|
database.failedImportFile=ファイルのインポートに失敗
|
||||||
|
|
||||||
session.expired=Your session has expired. Please refresh the page and try again.
|
session.expired=セッションが期限切れです。ページを更新してもう一度お試しください。
|
||||||
session.refreshPage=Refresh Page
|
session.refreshPage=ページを更新
|
||||||
|
|
||||||
#############
|
#############
|
||||||
# HOME-PAGE #
|
# HOME-PAGE #
|
||||||
@@ -488,48 +488,52 @@ overlay-pdfs.tags=Overlay
|
|||||||
|
|
||||||
home.split-by-sections.title=PDFをセクションで分割
|
home.split-by-sections.title=PDFをセクションで分割
|
||||||
home.split-by-sections.desc=PDFの各ページを縦横に分割します。
|
home.split-by-sections.desc=PDFの各ページを縦横に分割します。
|
||||||
split-by-sections.tags=Section Split, Divide, Customize
|
split-by-sections.tags=Section Split, Divide, Customize,Customise
|
||||||
|
|
||||||
home.AddStampRequest.title=PDFにスタンプを追加
|
home.AddStampRequest.title=PDFにスタンプを追加
|
||||||
home.AddStampRequest.desc=設定した位置にテキストや画像のスタンプを追加できます
|
home.AddStampRequest.desc=設定した位置にテキストや画像のスタンプを追加できます
|
||||||
AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Customize
|
AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Customize,Customise
|
||||||
|
|
||||||
|
|
||||||
home.PDFToBook.title=PDFを書籍に変換
|
home.PDFToBook.title=PDFを書籍に変換
|
||||||
home.PDFToBook.desc=calibreを使用してPDFを書籍/コミック形式に変換します
|
home.PDFToBook.desc=calibreを使用してPDFを書籍/コミック形式に変換します
|
||||||
PDFToBook.tags=Book,Comic,Calibre,Convert,manga,amazon,kindle
|
PDFToBook.tags=Book,Comic,Calibre,Convert,manga,amazon,kindle,epub,mobi,azw3,docx,rtf,txt,html,lit,fb2,pdb,lrf
|
||||||
|
|
||||||
home.BookToPDF.title=PDFを書籍に変換
|
home.BookToPDF.title=PDFを書籍に変換
|
||||||
home.BookToPDF.desc=calibreを使用してPDFを書籍/コミック形式に変換します
|
home.BookToPDF.desc=calibreを使用してPDFを書籍/コミック形式に変換します
|
||||||
BookToPDF.tags=Book,Comic,Calibre,Convert,manga,amazon,kindle
|
BookToPDF.tags=Book,Comic,Calibre,Convert,manga,amazon,kindle,epub,mobi,azw3,docx,rtf,txt,html,lit,fb2,pdb,lrf
|
||||||
|
|
||||||
home.removeImagePdf.title=画像の削除
|
home.removeImagePdf.title=画像の削除
|
||||||
home.removeImagePdf.desc=PDFから画像を削除してファイルサイズを小さくします
|
home.removeImagePdf.desc=PDFから画像を削除してファイルサイズを小さくします
|
||||||
removeImagePdf.tags=Remove Image,Page operations,Back end,server side
|
removeImagePdf.tags=Remove Image,Page operations,Back end,server side
|
||||||
|
|
||||||
|
|
||||||
home.splitPdfByChapters.title=Split PDF by Chapters
|
home.splitPdfByChapters.title=PDFをチャプターごとに分割
|
||||||
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
home.splitPdfByChapters.desc=チャプターの構造に基づいてPDFを複数のファイルに分割します
|
||||||
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
||||||
|
|
||||||
|
home.validateSignature.title=PDF署名の検証
|
||||||
|
home.validateSignature.desc=PDF文書のデジタル署名と証明書を検証します
|
||||||
|
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
|
||||||
|
|
||||||
#replace-invert-color
|
#replace-invert-color
|
||||||
replace-color.title=Replace-Invert-Color
|
replace-color.title=色の置換・反転
|
||||||
replace-color.header=Replace-Invert Color PDF
|
replace-color.header=PDFの色の置換・反転
|
||||||
home.replaceColorPdf.title=Replace and Invert Color
|
home.replaceColorPdf.title=色の置換と反転
|
||||||
home.replaceColorPdf.desc=Replace color for text and background in PDF and invert full color of pdf to reduce file size
|
home.replaceColorPdf.desc=PDF内のテキストと背景の色を置き換え、PDFのフルカラーを反転してファイルサイズを縮小します。
|
||||||
replaceColorPdf.tags=Replace Color,Page operations,Back end,server side
|
replaceColorPdf.tags=Replace Color,Page operations,Back end,server side
|
||||||
replace-color.selectText.1=Replace or Invert color Options
|
replace-color.selectText.1=色の置換または反転オプション
|
||||||
replace-color.selectText.2=Default(Default high contrast colors)
|
replace-color.selectText.2=デフォルト(デフォルトの高コントラスト色)
|
||||||
replace-color.selectText.3=Custom(Customized colors)
|
replace-color.selectText.3=カスタム(カスタマイズされた色)
|
||||||
replace-color.selectText.4=Full-Invert(Invert all colors)
|
replace-color.selectText.4=フル反転(すべての色を反転)
|
||||||
replace-color.selectText.5=High contrast color options
|
replace-color.selectText.5=高コントラストカラーオプション
|
||||||
replace-color.selectText.6=white text on black background
|
replace-color.selectText.6=黒背景に白文字
|
||||||
replace-color.selectText.7=Black text on white background
|
replace-color.selectText.7=白背景に黒文字
|
||||||
replace-color.selectText.8=Yellow text on black background
|
replace-color.selectText.8=黒背景に黄色文字
|
||||||
replace-color.selectText.9=Green text on black background
|
replace-color.selectText.9=黒背景に緑文字
|
||||||
replace-color.selectText.10=Choose text Color
|
replace-color.selectText.10=テキストの色を選択
|
||||||
replace-color.selectText.11=Choose background Color
|
replace-color.selectText.11=背景色を選択
|
||||||
replace-color.submit=Replace
|
replace-color.submit=置換
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -556,9 +560,9 @@ login.oauth2AccessDenied=アクセス拒否
|
|||||||
login.oauth2InvalidTokenResponse=無効なトークン応答
|
login.oauth2InvalidTokenResponse=無効なトークン応答
|
||||||
login.oauth2InvalidIdToken=無効なIDトークン
|
login.oauth2InvalidIdToken=無効なIDトークン
|
||||||
login.userIsDisabled=ユーザーは非アクティブ化されており、現在このユーザー名でのログインはブロックされています。管理者に連絡してください。
|
login.userIsDisabled=ユーザーは非アクティブ化されており、現在このユーザー名でのログインはブロックされています。管理者に連絡してください。
|
||||||
login.alreadyLoggedIn=You are already logged in to
|
login.alreadyLoggedIn=すでにログインしています
|
||||||
login.alreadyLoggedIn2=devices. Please log out of the devices and try again.
|
login.alreadyLoggedIn2=デバイスからログアウトしてもう一度お試しください。
|
||||||
login.toManySessions=You have too many active sessions
|
login.toManySessions=アクティブなセッションが多すぎます
|
||||||
|
|
||||||
#auto-redact
|
#auto-redact
|
||||||
autoRedact.title=自動塗りつぶし
|
autoRedact.title=自動塗りつぶし
|
||||||
@@ -574,8 +578,8 @@ autoRedact.submitButton=送信
|
|||||||
|
|
||||||
|
|
||||||
#showJS
|
#showJS
|
||||||
showJS.title=JavaScriptを表示
|
showJS.title=Javascriptを表示
|
||||||
showJS.header=JavaScriptを表示
|
showJS.header=Javascriptを表示
|
||||||
showJS.downloadJS=Javascriptをダウンロード
|
showJS.downloadJS=Javascriptをダウンロード
|
||||||
showJS.submit=表示
|
showJS.submit=表示
|
||||||
|
|
||||||
@@ -753,7 +757,7 @@ certSign.showSig=署名を表示
|
|||||||
certSign.reason=理由
|
certSign.reason=理由
|
||||||
certSign.location=場所
|
certSign.location=場所
|
||||||
certSign.name=名前
|
certSign.name=名前
|
||||||
certSign.showLogo=Show Logo
|
certSign.showLogo=ロゴを表示
|
||||||
certSign.submit=PDFに署名
|
certSign.submit=PDFに署名
|
||||||
|
|
||||||
|
|
||||||
@@ -788,9 +792,9 @@ compare.highlightColor.2=ハイライトカラー 2:
|
|||||||
compare.document.1=ドキュメント 1
|
compare.document.1=ドキュメント 1
|
||||||
compare.document.2=ドキュメント 2
|
compare.document.2=ドキュメント 2
|
||||||
compare.submit=比較
|
compare.submit=比較
|
||||||
compare.complex.message=One or both of the provided documents are large files, accuracy of comparison may be reduced
|
compare.complex.message=提供された文書の一方または両方が大きなファイルであるため、比較の精度が低下する可能性があります。
|
||||||
compare.large.file.message=One or Both of the provided documents are too large to process
|
compare.large.file.message=提供された文書の1つまたは両方が大きすぎて処理できません
|
||||||
compare.no.text.message=One or both of the selected PDFs have no text content. Please choose PDFs with text for comparison.
|
compare.no.text.message=選択したPDFの1つまたは両方にテキストコンテンツがありません。比較するには、テキストを含むPDFを選択してください。
|
||||||
|
|
||||||
#BookToPDF
|
#BookToPDF
|
||||||
BookToPDF.title=書籍やコミックをPDFに変換
|
BookToPDF.title=書籍やコミックをPDFに変換
|
||||||
@@ -799,8 +803,8 @@ BookToPDF.credit=calibreを使用
|
|||||||
BookToPDF.submit=変換
|
BookToPDF.submit=変換
|
||||||
|
|
||||||
#PDFToBook
|
#PDFToBook
|
||||||
PDFToBook.title=書籍をPDFに変換
|
PDFToBook.title=PDFを書籍に変換
|
||||||
PDFToBook.header=書籍をPDFに変換
|
PDFToBook.header=PDFを書籍に変換
|
||||||
PDFToBook.selectText.1=フォーマット
|
PDFToBook.selectText.1=フォーマット
|
||||||
PDFToBook.credit=calibreを使用
|
PDFToBook.credit=calibreを使用
|
||||||
PDFToBook.submit=変換
|
PDFToBook.submit=変換
|
||||||
@@ -813,17 +817,17 @@ sign.draw=署名を書く
|
|||||||
sign.text=テキスト入力
|
sign.text=テキスト入力
|
||||||
sign.clear=クリア
|
sign.clear=クリア
|
||||||
sign.add=追加
|
sign.add=追加
|
||||||
sign.saved=Saved Signatures
|
sign.saved=保存された署名
|
||||||
sign.save=Save Signature
|
sign.save=署名を保存
|
||||||
sign.personalSigs=Personal Signatures
|
sign.personalSigs=個人署名
|
||||||
sign.sharedSigs=Shared Signatures
|
sign.sharedSigs=共有署名
|
||||||
sign.noSavedSigs=No saved signatures found
|
sign.noSavedSigs=保存された署名が見つかりません
|
||||||
sign.addToAll=Add to all pages
|
sign.addToAll=すべてのページに追加
|
||||||
sign.delete=Delete
|
sign.delete=削除
|
||||||
sign.first=First page
|
sign.first=最初のページ
|
||||||
sign.last=Last page
|
sign.last=最後のページ
|
||||||
sign.next=Next page
|
sign.next=次のページ
|
||||||
sign.previous=Previous page
|
sign.previous=前のページ
|
||||||
|
|
||||||
#repair
|
#repair
|
||||||
repair.title=修復
|
repair.title=修復
|
||||||
@@ -940,29 +944,39 @@ pdfOrganiser.placeholder=(例:1,3,2または4-8,2,10-12または2n-1)
|
|||||||
multiTool.title=PDFマルチツール
|
multiTool.title=PDFマルチツール
|
||||||
multiTool.header=PDFマルチツール
|
multiTool.header=PDFマルチツール
|
||||||
multiTool.uploadPrompts=ファイル名
|
multiTool.uploadPrompts=ファイル名
|
||||||
multiTool.selectAll=Select All
|
multiTool.selectAll=すべて選択
|
||||||
multiTool.deselectAll=Deselect All
|
multiTool.deselectAll=選択を解除
|
||||||
multiTool.selectPages=Page Select
|
multiTool.selectPages=ページ選択
|
||||||
multiTool.selectedPages=Selected Pages
|
multiTool.selectedPages=選択したページ
|
||||||
multiTool.page=Page
|
multiTool.page=ページ
|
||||||
multiTool.deleteSelected=Delete Selected
|
multiTool.deleteSelected=選択項目を削除
|
||||||
multiTool.downloadAll=Export
|
multiTool.downloadAll=エクスポート
|
||||||
multiTool.downloadSelected=Export Selected
|
multiTool.downloadSelected=選択項目をエクスポート
|
||||||
|
|
||||||
multiTool.insertPageBreak=Insert Page Break
|
multiTool.insertPageBreak=改ページを挿入
|
||||||
multiTool.addFile=Add File
|
multiTool.addFile=ファイルを追加
|
||||||
multiTool.rotateLeft=Rotate Left
|
multiTool.rotateLeft=左回転
|
||||||
multiTool.rotateRight=Rotate Right
|
multiTool.rotateRight=右回転
|
||||||
multiTool.split=Split
|
multiTool.split=分割
|
||||||
multiTool.moveLeft=Move Left
|
multiTool.moveLeft=左に移動
|
||||||
multiTool.moveRight=Move Right
|
multiTool.moveRight=右に移動
|
||||||
multiTool.delete=Delete
|
multiTool.delete=削除
|
||||||
multiTool.dragDropMessage=Page(s) Selected
|
multiTool.dragDropMessage=選択されたページ
|
||||||
multiTool.undo=Undo
|
multiTool.undo=元に戻す
|
||||||
multiTool.redo=Redo
|
multiTool.redo=やり直す
|
||||||
|
|
||||||
|
#decrypt
|
||||||
|
decrypt.passwordPrompt=このファイルはパスワードで保護されています。パスワードを入力してください:
|
||||||
|
decrypt.cancelled=PDFの操作がキャンセルされました: {0}
|
||||||
|
decrypt.noPassword=暗号化されたPDFにパスワードが指定されていません: {0}
|
||||||
|
decrypt.invalidPassword=正しいパスワードでもう一度お試しください。
|
||||||
|
decrypt.invalidPasswordHeader=PDFのパスワードが正しくないか、暗号化がサポートされていません: {0}
|
||||||
|
decrypt.unexpectedError=ファイルの処理中にエラーが発生しました。もう一度お試しください。
|
||||||
|
decrypt.serverError=復号化中にサーバーエラーが発生しました: {0}
|
||||||
|
decrypt.success=ファイルの暗号化が正常に完了しました。
|
||||||
|
|
||||||
#multiTool-advert
|
#multiTool-advert
|
||||||
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
multiTool-advert.message=この機能は、<a href="{0}">マルチツール</a>でもご利用いただけます。強化されたページごとのUIと追加機能についてはこちらをご覧ください。
|
||||||
|
|
||||||
#view pdf
|
#view pdf
|
||||||
viewPdf.title=PDFを表示
|
viewPdf.title=PDFを表示
|
||||||
@@ -1052,6 +1066,7 @@ addPassword.submit=暗号化
|
|||||||
#watermark
|
#watermark
|
||||||
watermark.title=透かしの追加
|
watermark.title=透かしの追加
|
||||||
watermark.header=透かしの追加
|
watermark.header=透かしの追加
|
||||||
|
watermark.customColor=文字色のカスタム
|
||||||
watermark.selectText.1=透かしを追加するPDFを選択:
|
watermark.selectText.1=透かしを追加するPDFを選択:
|
||||||
watermark.selectText.2=透かしのテキスト:
|
watermark.selectText.2=透かしのテキスト:
|
||||||
watermark.selectText.3=文字サイズ:
|
watermark.selectText.3=文字サイズ:
|
||||||
@@ -1117,8 +1132,8 @@ pdfToPDFA.header=PDFをPDF/Aに変換
|
|||||||
pdfToPDFA.credit=本サービスはPDF/Aの変換にqpdfを使用しています。
|
pdfToPDFA.credit=本サービスはPDF/Aの変換にqpdfを使用しています。
|
||||||
pdfToPDFA.submit=変換
|
pdfToPDFA.submit=変換
|
||||||
pdfToPDFA.tip=現在、一度に複数の入力に対して機能しません
|
pdfToPDFA.tip=現在、一度に複数の入力に対して機能しません
|
||||||
pdfToPDFA.outputFormat=Output format
|
pdfToPDFA.outputFormat=出力形式
|
||||||
pdfToPDFA.pdfWithDigitalSignature=PDF にはデジタル署名が含まれています。これは次の手順で削除されます。
|
pdfToPDFA.pdfWithDigitalSignature=PDFにはデジタル署名が含まれています。これは次の手順で削除されます。
|
||||||
|
|
||||||
|
|
||||||
#PDFToWord
|
#PDFToWord
|
||||||
@@ -1223,8 +1238,8 @@ licenses.license=ライセンス
|
|||||||
survey.nav=アンケート
|
survey.nav=アンケート
|
||||||
survey.title=Stirling-PDFのアンケート
|
survey.title=Stirling-PDFのアンケート
|
||||||
survey.description=Stirling-PDFには追跡機能がないため、Stirling-PDFをより良くするために皆様の意見を聞かせてください!
|
survey.description=Stirling-PDFには追跡機能がないため、Stirling-PDFをより良くするために皆様の意見を聞かせてください!
|
||||||
survey.changes=Stirling-PDF has changed since the last survey! To find out more please check our blog post here:
|
survey.changes=Stirling-PDFは前回の調査から変更されました。詳細についてはこちらのブログ投稿をご覧ください。
|
||||||
survey.changes2=With these changes we are getting paid business support and funding
|
survey.changes2=これらの変更により私たちは有償のビジネスサポートと資金援助を受けています
|
||||||
survey.please=アンケートにご協力ください!
|
survey.please=アンケートにご協力ください!
|
||||||
survey.disabled=(アンケートのポップアップは、次の更新では無効になりますが、ページの下部に表示されます。)
|
survey.disabled=(アンケートのポップアップは、次の更新では無効になりますが、ページの下部に表示されます。)
|
||||||
survey.button=アンケートに答える
|
survey.button=アンケートに答える
|
||||||
@@ -1252,21 +1267,61 @@ removeImage.removeImage=画像の削除
|
|||||||
removeImage.submit=画像を削除
|
removeImage.submit=画像を削除
|
||||||
|
|
||||||
|
|
||||||
splitByChapters.title=Split PDF by Chapters
|
splitByChapters.title=PDFをチャプターごとに分割
|
||||||
splitByChapters.header=Split PDF by Chapters
|
splitByChapters.header=PDFをチャプターごとに分割
|
||||||
splitByChapters.bookmarkLevel=Bookmark Level
|
splitByChapters.bookmarkLevel=ブックマークレベル
|
||||||
splitByChapters.includeMetadata=Include Metadata
|
splitByChapters.includeMetadata=メタデータを含める
|
||||||
splitByChapters.allowDuplicates=Allow Duplicates
|
splitByChapters.allowDuplicates=重複を許可する
|
||||||
splitByChapters.desc.1=This tool splits a PDF file into multiple PDFs based on its chapter structure.
|
splitByChapters.desc.1=このツールは、チャプター構造に基づいてPDFファイルを複数のPDFに分割します。
|
||||||
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.2=ブックマークレベル:分割に使用するブックマークのレベルを選択します(最上位レベルの場合は0、第2レベルの場合は1など)。
|
||||||
splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF.
|
splitByChapters.desc.3=メタデータを含める:チェックすると、元のPDFのメタデータが各分割PDFに含まれます。
|
||||||
splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs.
|
splitByChapters.desc.4=重複を許可:チェックすると同じページ上の複数のブックマークから個別のPDFを作成できます。
|
||||||
splitByChapters.submit=Split PDF
|
splitByChapters.submit=PDFを分割
|
||||||
|
|
||||||
|
#File Chooser
|
||||||
|
fileChooser.click=クリック
|
||||||
|
fileChooser.or=または
|
||||||
|
fileChooser.dragAndDrop=ドラッグ&ドロップ
|
||||||
|
fileChooser.hoveredDragAndDrop=ファイルをここにドラッグ&ドロップ
|
||||||
|
|
||||||
#release notes
|
#release notes
|
||||||
releases.footer=Releases
|
releases.footer=リリース
|
||||||
releases.title=Release Notes
|
releases.title=リリースノート
|
||||||
releases.header=Release Notes
|
releases.header=リリースノート
|
||||||
releases.current.version=Current Release
|
releases.current.version=現在のリリース
|
||||||
releases.note=Release notes are only available in English
|
releases.note=リリースノートは英語でのみで提供されています
|
||||||
|
|
||||||
|
#Validate Signature
|
||||||
|
validateSignature.title=PDF署名の検証
|
||||||
|
validateSignature.header=デジタル署名の検証
|
||||||
|
validateSignature.selectPDF=署名済みPDFファイルを選択
|
||||||
|
validateSignature.submit=署名の検証
|
||||||
|
validateSignature.results=検証結果
|
||||||
|
validateSignature.status=状態
|
||||||
|
validateSignature.signer=署名者
|
||||||
|
validateSignature.date=日付
|
||||||
|
validateSignature.reason=理由
|
||||||
|
validateSignature.location=場所
|
||||||
|
validateSignature.noSignatures=この文書にはデジタル署名が見つかりません
|
||||||
|
validateSignature.status.valid=有効
|
||||||
|
validateSignature.status.invalid=無効
|
||||||
|
validateSignature.chain.invalid=証明書チェーンの検証に失敗しました - 署名者の身元を確認できません
|
||||||
|
validateSignature.trust.invalid=証明書が信頼ストアにありません - ソースを検証できません
|
||||||
|
validateSignature.cert.expired=証明書の有効期限が切れています
|
||||||
|
validateSignature.cert.revoked=証明書は取り消されました
|
||||||
|
validateSignature.signature.info=署名情報
|
||||||
|
validateSignature.signature=署名
|
||||||
|
validateSignature.signature.mathValid=署名は数学的には有効ですが:
|
||||||
|
validateSignature.selectCustomCert=カスタム証明書ファイル X.509 (オプション)
|
||||||
|
validateSignature.cert.info=証明書の詳細
|
||||||
|
validateSignature.cert.issuer=発行者
|
||||||
|
validateSignature.cert.subject=主題
|
||||||
|
validateSignature.cert.serialNumber=シリアルナンバー
|
||||||
|
validateSignature.cert.validFrom=有効開始日
|
||||||
|
validateSignature.cert.validUntil=有効期限
|
||||||
|
validateSignature.cert.algorithm=アルゴリズム
|
||||||
|
validateSignature.cert.keySize=キーサイズ
|
||||||
|
validateSignature.cert.version=バージョン
|
||||||
|
validateSignature.cert.keyUsage=キーの使用法
|
||||||
|
validateSignature.cert.selfSigned=自己署名
|
||||||
|
validateSignature.cert.bits=ビット
|
||||||
|
|||||||
@@ -512,6 +512,10 @@ home.splitPdfByChapters.title=챕터별로 PDF 분할
|
|||||||
home.splitPdfByChapters.desc=PDF를 여러 파일로 나눕니다. 각 장의 구조에 따라.
|
home.splitPdfByChapters.desc=PDF를 여러 파일로 나눕니다. 각 장의 구조에 따라.
|
||||||
splitPdfByChapters.tags=분할, 챕터, 북마크, 조직화
|
splitPdfByChapters.tags=분할, 챕터, 북마크, 조직화
|
||||||
|
|
||||||
|
home.validateSignature.title=Validate PDF Signature
|
||||||
|
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
|
||||||
|
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
|
||||||
|
|
||||||
#replace-invert-color
|
#replace-invert-color
|
||||||
replace-color.title=Replace-Invert-Color
|
replace-color.title=Replace-Invert-Color
|
||||||
replace-color.header=색상 교체/반전 PDF
|
replace-color.header=색상 교체/반전 PDF
|
||||||
@@ -961,6 +965,16 @@ multiTool.dragDropMessage=Page(s) Selected
|
|||||||
multiTool.undo=Undo
|
multiTool.undo=Undo
|
||||||
multiTool.redo=Redo
|
multiTool.redo=Redo
|
||||||
|
|
||||||
|
#decrypt
|
||||||
|
decrypt.passwordPrompt=This file is password-protected. Please enter the password:
|
||||||
|
decrypt.cancelled=Operation cancelled for PDF: {0}
|
||||||
|
decrypt.noPassword=No password provided for encrypted PDF: {0}
|
||||||
|
decrypt.invalidPassword=Please try again with the correct password.
|
||||||
|
decrypt.invalidPasswordHeader=Incorrect password or unsupported encryption for PDF: {0}
|
||||||
|
decrypt.unexpectedError=There was an error processing the file. Please try again.
|
||||||
|
decrypt.serverError=Server error while decrypting: {0}
|
||||||
|
decrypt.success=File decrypted successfully.
|
||||||
|
|
||||||
#multiTool-advert
|
#multiTool-advert
|
||||||
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
||||||
|
|
||||||
@@ -1052,6 +1066,7 @@ addPassword.submit=암호화
|
|||||||
#watermark
|
#watermark
|
||||||
watermark.title=워터마크 추가
|
watermark.title=워터마크 추가
|
||||||
watermark.header=워터마크 추가
|
watermark.header=워터마크 추가
|
||||||
|
watermark.customColor=사용자 정의 텍스트 색상
|
||||||
watermark.selectText.1=워터마크를 추가할 PDF 선택:
|
watermark.selectText.1=워터마크를 추가할 PDF 선택:
|
||||||
watermark.selectText.2=워터마크 텍스트:
|
watermark.selectText.2=워터마크 텍스트:
|
||||||
watermark.selectText.3=폰트 크기:
|
watermark.selectText.3=폰트 크기:
|
||||||
@@ -1263,6 +1278,11 @@ splitByChapters.desc.3=메타데이터 포함: 체크하면 각 분할된 PDF에
|
|||||||
splitByChapters.desc.4=중복 허용: 중복 북마크가 있는 같은 페이지에 여러 번 분할 PDF를 생성합니다.
|
splitByChapters.desc.4=중복 허용: 중복 북마크가 있는 같은 페이지에 여러 번 분할 PDF를 생성합니다.
|
||||||
splitByChapters.submit=PDF 분할
|
splitByChapters.submit=PDF 분할
|
||||||
|
|
||||||
|
#File Chooser
|
||||||
|
fileChooser.click=Click
|
||||||
|
fileChooser.or=or
|
||||||
|
fileChooser.dragAndDrop=Drag & Drop
|
||||||
|
fileChooser.hoveredDragAndDrop=Drag & Drop file(s) here
|
||||||
|
|
||||||
#release notes
|
#release notes
|
||||||
releases.footer=Releases
|
releases.footer=Releases
|
||||||
@@ -1270,3 +1290,38 @@ releases.title=Release Notes
|
|||||||
releases.header=Release Notes
|
releases.header=Release Notes
|
||||||
releases.current.version=Current Release
|
releases.current.version=Current Release
|
||||||
releases.note=Release notes are only available in English
|
releases.note=Release notes are only available in English
|
||||||
|
|
||||||
|
#Validate Signature
|
||||||
|
validateSignature.title=Validate PDF Signatures
|
||||||
|
validateSignature.header=Validate Digital Signatures
|
||||||
|
validateSignature.selectPDF=Select signed PDF file
|
||||||
|
validateSignature.submit=Validate Signatures
|
||||||
|
validateSignature.results=Validation Results
|
||||||
|
validateSignature.status=Status
|
||||||
|
validateSignature.signer=Signer
|
||||||
|
validateSignature.date=Date
|
||||||
|
validateSignature.reason=Reason
|
||||||
|
validateSignature.location=Location
|
||||||
|
validateSignature.noSignatures=No digital signatures found in this document
|
||||||
|
validateSignature.status.valid=Valid
|
||||||
|
validateSignature.status.invalid=Invalid
|
||||||
|
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
|
||||||
|
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
|
||||||
|
validateSignature.cert.expired=Certificate has expired
|
||||||
|
validateSignature.cert.revoked=Certificate has been revoked
|
||||||
|
validateSignature.signature.info=Signature Information
|
||||||
|
validateSignature.signature=Signature
|
||||||
|
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
|
||||||
|
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
|
||||||
|
validateSignature.cert.info=Certificate Details
|
||||||
|
validateSignature.cert.issuer=Issuer
|
||||||
|
validateSignature.cert.subject=Subject
|
||||||
|
validateSignature.cert.serialNumber=Serial Number
|
||||||
|
validateSignature.cert.validFrom=Valid From
|
||||||
|
validateSignature.cert.validUntil=Valid Until
|
||||||
|
validateSignature.cert.algorithm=Algorithm
|
||||||
|
validateSignature.cert.keySize=Key Size
|
||||||
|
validateSignature.cert.version=Version
|
||||||
|
validateSignature.cert.keyUsage=Key Usage
|
||||||
|
validateSignature.cert.selfSigned=Self-Signed
|
||||||
|
validateSignature.cert.bits=bits
|
||||||
|
|||||||
@@ -512,6 +512,10 @@ home.splitPdfByChapters.title=PDF op hoofdstukken splitsen
|
|||||||
home.splitPdfByChapters.desc=Splits een PDF op basis van zijn hoofdstukstructuur in meerdere bestanden.
|
home.splitPdfByChapters.desc=Splits een PDF op basis van zijn hoofdstukstructuur in meerdere bestanden.
|
||||||
splitPdfByChapters.tags=splitsen, hoofdstukken, bookmarks, organiseren
|
splitPdfByChapters.tags=splitsen, hoofdstukken, bookmarks, organiseren
|
||||||
|
|
||||||
|
home.validateSignature.title=Validate PDF Signature
|
||||||
|
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
|
||||||
|
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
|
||||||
|
|
||||||
#replace-invert-color
|
#replace-invert-color
|
||||||
replace-color.title=Replace-Invert-Color
|
replace-color.title=Replace-Invert-Color
|
||||||
replace-color.header=Kleur-instellingen voor PDF's
|
replace-color.header=Kleur-instellingen voor PDF's
|
||||||
@@ -961,6 +965,16 @@ multiTool.dragDropMessage=Page(s) Selected
|
|||||||
multiTool.undo=Undo
|
multiTool.undo=Undo
|
||||||
multiTool.redo=Redo
|
multiTool.redo=Redo
|
||||||
|
|
||||||
|
#decrypt
|
||||||
|
decrypt.passwordPrompt=This file is password-protected. Please enter the password:
|
||||||
|
decrypt.cancelled=Operation cancelled for PDF: {0}
|
||||||
|
decrypt.noPassword=No password provided for encrypted PDF: {0}
|
||||||
|
decrypt.invalidPassword=Please try again with the correct password.
|
||||||
|
decrypt.invalidPasswordHeader=Incorrect password or unsupported encryption for PDF: {0}
|
||||||
|
decrypt.unexpectedError=There was an error processing the file. Please try again.
|
||||||
|
decrypt.serverError=Server error while decrypting: {0}
|
||||||
|
decrypt.success=File decrypted successfully.
|
||||||
|
|
||||||
#multiTool-advert
|
#multiTool-advert
|
||||||
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
||||||
|
|
||||||
@@ -1052,6 +1066,7 @@ addPassword.submit=Versleutelen
|
|||||||
#watermark
|
#watermark
|
||||||
watermark.title=Watermerk toevoegen
|
watermark.title=Watermerk toevoegen
|
||||||
watermark.header=Watermerk toevoegen
|
watermark.header=Watermerk toevoegen
|
||||||
|
watermark.customColor=Aangepaste tekstkleur
|
||||||
watermark.selectText.1=Selecteer PDF om watermerk toe te voegen:
|
watermark.selectText.1=Selecteer PDF om watermerk toe te voegen:
|
||||||
watermark.selectText.2=Watermerk tekst:
|
watermark.selectText.2=Watermerk tekst:
|
||||||
watermark.selectText.3=Tekengrootte:
|
watermark.selectText.3=Tekengrootte:
|
||||||
@@ -1263,6 +1278,11 @@ splitByChapters.desc.3=Metadata inclusief: Als gecijfeld, de originele PDF's met
|
|||||||
splitByChapters.desc.4=Dubbele items toestaan: Als gecijfeld, zorgen multiple boekmarkeersymboolen op dezelfde pagina voor het maken van aparte PDF-bestanden.
|
splitByChapters.desc.4=Dubbele items toestaan: Als gecijfeld, zorgen multiple boekmarkeersymboolen op dezelfde pagina voor het maken van aparte PDF-bestanden.
|
||||||
splitByChapters.submit=PDF splitsen
|
splitByChapters.submit=PDF splitsen
|
||||||
|
|
||||||
|
#File Chooser
|
||||||
|
fileChooser.click=Click
|
||||||
|
fileChooser.or=or
|
||||||
|
fileChooser.dragAndDrop=Drag & Drop
|
||||||
|
fileChooser.hoveredDragAndDrop=Drag & Drop file(s) here
|
||||||
|
|
||||||
#release notes
|
#release notes
|
||||||
releases.footer=Releases
|
releases.footer=Releases
|
||||||
@@ -1270,3 +1290,38 @@ releases.title=Release Notes
|
|||||||
releases.header=Release Notes
|
releases.header=Release Notes
|
||||||
releases.current.version=Current Release
|
releases.current.version=Current Release
|
||||||
releases.note=Release notes are only available in English
|
releases.note=Release notes are only available in English
|
||||||
|
|
||||||
|
#Validate Signature
|
||||||
|
validateSignature.title=Validate PDF Signatures
|
||||||
|
validateSignature.header=Validate Digital Signatures
|
||||||
|
validateSignature.selectPDF=Select signed PDF file
|
||||||
|
validateSignature.submit=Validate Signatures
|
||||||
|
validateSignature.results=Validation Results
|
||||||
|
validateSignature.status=Status
|
||||||
|
validateSignature.signer=Signer
|
||||||
|
validateSignature.date=Date
|
||||||
|
validateSignature.reason=Reason
|
||||||
|
validateSignature.location=Location
|
||||||
|
validateSignature.noSignatures=No digital signatures found in this document
|
||||||
|
validateSignature.status.valid=Valid
|
||||||
|
validateSignature.status.invalid=Invalid
|
||||||
|
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
|
||||||
|
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
|
||||||
|
validateSignature.cert.expired=Certificate has expired
|
||||||
|
validateSignature.cert.revoked=Certificate has been revoked
|
||||||
|
validateSignature.signature.info=Signature Information
|
||||||
|
validateSignature.signature=Signature
|
||||||
|
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
|
||||||
|
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
|
||||||
|
validateSignature.cert.info=Certificate Details
|
||||||
|
validateSignature.cert.issuer=Issuer
|
||||||
|
validateSignature.cert.subject=Subject
|
||||||
|
validateSignature.cert.serialNumber=Serial Number
|
||||||
|
validateSignature.cert.validFrom=Valid From
|
||||||
|
validateSignature.cert.validUntil=Valid Until
|
||||||
|
validateSignature.cert.algorithm=Algorithm
|
||||||
|
validateSignature.cert.keySize=Key Size
|
||||||
|
validateSignature.cert.version=Version
|
||||||
|
validateSignature.cert.keyUsage=Key Usage
|
||||||
|
validateSignature.cert.selfSigned=Self-Signed
|
||||||
|
validateSignature.cert.bits=bits
|
||||||
|
|||||||
@@ -512,6 +512,10 @@ home.splitPdfByChapters.title=Split PDF by Chapters
|
|||||||
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
||||||
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
||||||
|
|
||||||
|
home.validateSignature.title=Validate PDF Signature
|
||||||
|
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
|
||||||
|
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
|
||||||
|
|
||||||
#replace-invert-color
|
#replace-invert-color
|
||||||
replace-color.title=Replace-Invert-Color
|
replace-color.title=Replace-Invert-Color
|
||||||
replace-color.header=Replace-Invert Color PDF
|
replace-color.header=Replace-Invert Color PDF
|
||||||
@@ -961,6 +965,16 @@ multiTool.dragDropMessage=Page(s) Selected
|
|||||||
multiTool.undo=Undo
|
multiTool.undo=Undo
|
||||||
multiTool.redo=Redo
|
multiTool.redo=Redo
|
||||||
|
|
||||||
|
#decrypt
|
||||||
|
decrypt.passwordPrompt=This file is password-protected. Please enter the password:
|
||||||
|
decrypt.cancelled=Operation cancelled for PDF: {0}
|
||||||
|
decrypt.noPassword=No password provided for encrypted PDF: {0}
|
||||||
|
decrypt.invalidPassword=Please try again with the correct password.
|
||||||
|
decrypt.invalidPasswordHeader=Incorrect password or unsupported encryption for PDF: {0}
|
||||||
|
decrypt.unexpectedError=There was an error processing the file. Please try again.
|
||||||
|
decrypt.serverError=Server error while decrypting: {0}
|
||||||
|
decrypt.success=File decrypted successfully.
|
||||||
|
|
||||||
#multiTool-advert
|
#multiTool-advert
|
||||||
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
||||||
|
|
||||||
@@ -1052,6 +1066,7 @@ addPassword.submit=Krypter
|
|||||||
#watermark
|
#watermark
|
||||||
watermark.title=Legg til vannmerke
|
watermark.title=Legg til vannmerke
|
||||||
watermark.header=Legg til vannmerke
|
watermark.header=Legg til vannmerke
|
||||||
|
watermark.customColor=Tilpasset Tekstfarge
|
||||||
watermark.selectText.1=Velg PDF-fil å legge til vannmerke på:
|
watermark.selectText.1=Velg PDF-fil å legge til vannmerke på:
|
||||||
watermark.selectText.2=Vannmerketekst:
|
watermark.selectText.2=Vannmerketekst:
|
||||||
watermark.selectText.3=Skriftstørrelse:
|
watermark.selectText.3=Skriftstørrelse:
|
||||||
@@ -1263,6 +1278,11 @@ splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata
|
|||||||
splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs.
|
splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs.
|
||||||
splitByChapters.submit=Split PDF
|
splitByChapters.submit=Split PDF
|
||||||
|
|
||||||
|
#File Chooser
|
||||||
|
fileChooser.click=Click
|
||||||
|
fileChooser.or=or
|
||||||
|
fileChooser.dragAndDrop=Drag & Drop
|
||||||
|
fileChooser.hoveredDragAndDrop=Drag & Drop file(s) here
|
||||||
|
|
||||||
#release notes
|
#release notes
|
||||||
releases.footer=Releases
|
releases.footer=Releases
|
||||||
@@ -1270,3 +1290,38 @@ releases.title=Release Notes
|
|||||||
releases.header=Release Notes
|
releases.header=Release Notes
|
||||||
releases.current.version=Current Release
|
releases.current.version=Current Release
|
||||||
releases.note=Release notes are only available in English
|
releases.note=Release notes are only available in English
|
||||||
|
|
||||||
|
#Validate Signature
|
||||||
|
validateSignature.title=Validate PDF Signatures
|
||||||
|
validateSignature.header=Validate Digital Signatures
|
||||||
|
validateSignature.selectPDF=Select signed PDF file
|
||||||
|
validateSignature.submit=Validate Signatures
|
||||||
|
validateSignature.results=Validation Results
|
||||||
|
validateSignature.status=Status
|
||||||
|
validateSignature.signer=Signer
|
||||||
|
validateSignature.date=Date
|
||||||
|
validateSignature.reason=Reason
|
||||||
|
validateSignature.location=Location
|
||||||
|
validateSignature.noSignatures=No digital signatures found in this document
|
||||||
|
validateSignature.status.valid=Valid
|
||||||
|
validateSignature.status.invalid=Invalid
|
||||||
|
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
|
||||||
|
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
|
||||||
|
validateSignature.cert.expired=Certificate has expired
|
||||||
|
validateSignature.cert.revoked=Certificate has been revoked
|
||||||
|
validateSignature.signature.info=Signature Information
|
||||||
|
validateSignature.signature=Signature
|
||||||
|
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
|
||||||
|
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
|
||||||
|
validateSignature.cert.info=Certificate Details
|
||||||
|
validateSignature.cert.issuer=Issuer
|
||||||
|
validateSignature.cert.subject=Subject
|
||||||
|
validateSignature.cert.serialNumber=Serial Number
|
||||||
|
validateSignature.cert.validFrom=Valid From
|
||||||
|
validateSignature.cert.validUntil=Valid Until
|
||||||
|
validateSignature.cert.algorithm=Algorithm
|
||||||
|
validateSignature.cert.keySize=Key Size
|
||||||
|
validateSignature.cert.version=Version
|
||||||
|
validateSignature.cert.keyUsage=Key Usage
|
||||||
|
validateSignature.cert.selfSigned=Self-Signed
|
||||||
|
validateSignature.cert.bits=bits
|
||||||
|
|||||||
55
src/main/resources/messages_pl_PL.properties
Executable file → Normal file
55
src/main/resources/messages_pl_PL.properties
Executable file → Normal file
@@ -512,6 +512,10 @@ home.splitPdfByChapters.title=Podziel PDF według rozdziałów
|
|||||||
home.splitPdfByChapters.desc=Podział pliku PDF na wiele plików na podstawie struktury rozdziałów.
|
home.splitPdfByChapters.desc=Podział pliku PDF na wiele plików na podstawie struktury rozdziałów.
|
||||||
splitPdfByChapters.tags=podział, rozdziały, zakładki, porządkowanie, organizacja
|
splitPdfByChapters.tags=podział, rozdziały, zakładki, porządkowanie, organizacja
|
||||||
|
|
||||||
|
home.validateSignature.title=Validate PDF Signature
|
||||||
|
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
|
||||||
|
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
|
||||||
|
|
||||||
#replace-invert-color
|
#replace-invert-color
|
||||||
replace-color.title=Zamień-Odwróć-Kolor
|
replace-color.title=Zamień-Odwróć-Kolor
|
||||||
replace-color.header=Zamień-Odwróć kolor PDF
|
replace-color.header=Zamień-Odwróć kolor PDF
|
||||||
@@ -961,6 +965,16 @@ multiTool.dragDropMessage=Page(s) Selected
|
|||||||
multiTool.undo=Undo
|
multiTool.undo=Undo
|
||||||
multiTool.redo=Redo
|
multiTool.redo=Redo
|
||||||
|
|
||||||
|
#decrypt
|
||||||
|
decrypt.passwordPrompt=This file is password-protected. Please enter the password:
|
||||||
|
decrypt.cancelled=Operation cancelled for PDF: {0}
|
||||||
|
decrypt.noPassword=No password provided for encrypted PDF: {0}
|
||||||
|
decrypt.invalidPassword=Please try again with the correct password.
|
||||||
|
decrypt.invalidPasswordHeader=Incorrect password or unsupported encryption for PDF: {0}
|
||||||
|
decrypt.unexpectedError=There was an error processing the file. Please try again.
|
||||||
|
decrypt.serverError=Server error while decrypting: {0}
|
||||||
|
decrypt.success=File decrypted successfully.
|
||||||
|
|
||||||
#multiTool-advert
|
#multiTool-advert
|
||||||
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
||||||
|
|
||||||
@@ -1052,6 +1066,7 @@ addPassword.submit=Zablokuj
|
|||||||
#watermark
|
#watermark
|
||||||
watermark.title=Dodaj znak wodny
|
watermark.title=Dodaj znak wodny
|
||||||
watermark.header=Dodaj znak wodny
|
watermark.header=Dodaj znak wodny
|
||||||
|
watermark.customColor=Własny kolor tekstu
|
||||||
watermark.selectText.1=Wybierz dokument PDF, do którego chcesz dodać znak wodny:
|
watermark.selectText.1=Wybierz dokument PDF, do którego chcesz dodać znak wodny:
|
||||||
watermark.selectText.2=Treść znaku wodnego:
|
watermark.selectText.2=Treść znaku wodnego:
|
||||||
watermark.selectText.3=Rozmiar czcionki:
|
watermark.selectText.3=Rozmiar czcionki:
|
||||||
@@ -1263,6 +1278,11 @@ splitByChapters.desc.3=Dołącz Metadane: Jeśli opcja ta jest zaznaczona, metad
|
|||||||
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.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
|
splitByChapters.submit=Podziel PDF
|
||||||
|
|
||||||
|
#File Chooser
|
||||||
|
fileChooser.click=Click
|
||||||
|
fileChooser.or=or
|
||||||
|
fileChooser.dragAndDrop=Drag & Drop
|
||||||
|
fileChooser.hoveredDragAndDrop=Drag & Drop file(s) here
|
||||||
|
|
||||||
#release notes
|
#release notes
|
||||||
releases.footer=Releases
|
releases.footer=Releases
|
||||||
@@ -1270,3 +1290,38 @@ releases.title=Release Notes
|
|||||||
releases.header=Release Notes
|
releases.header=Release Notes
|
||||||
releases.current.version=Current Release
|
releases.current.version=Current Release
|
||||||
releases.note=Release notes are only available in English
|
releases.note=Release notes are only available in English
|
||||||
|
|
||||||
|
#Validate Signature
|
||||||
|
validateSignature.title=Validate PDF Signatures
|
||||||
|
validateSignature.header=Validate Digital Signatures
|
||||||
|
validateSignature.selectPDF=Select signed PDF file
|
||||||
|
validateSignature.submit=Validate Signatures
|
||||||
|
validateSignature.results=Validation Results
|
||||||
|
validateSignature.status=Status
|
||||||
|
validateSignature.signer=Signer
|
||||||
|
validateSignature.date=Date
|
||||||
|
validateSignature.reason=Reason
|
||||||
|
validateSignature.location=Location
|
||||||
|
validateSignature.noSignatures=No digital signatures found in this document
|
||||||
|
validateSignature.status.valid=Valid
|
||||||
|
validateSignature.status.invalid=Invalid
|
||||||
|
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
|
||||||
|
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
|
||||||
|
validateSignature.cert.expired=Certificate has expired
|
||||||
|
validateSignature.cert.revoked=Certificate has been revoked
|
||||||
|
validateSignature.signature.info=Signature Information
|
||||||
|
validateSignature.signature=Signature
|
||||||
|
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
|
||||||
|
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
|
||||||
|
validateSignature.cert.info=Certificate Details
|
||||||
|
validateSignature.cert.issuer=Issuer
|
||||||
|
validateSignature.cert.subject=Subject
|
||||||
|
validateSignature.cert.serialNumber=Serial Number
|
||||||
|
validateSignature.cert.validFrom=Valid From
|
||||||
|
validateSignature.cert.validUntil=Valid Until
|
||||||
|
validateSignature.cert.algorithm=Algorithm
|
||||||
|
validateSignature.cert.keySize=Key Size
|
||||||
|
validateSignature.cert.version=Version
|
||||||
|
validateSignature.cert.keyUsage=Key Usage
|
||||||
|
validateSignature.cert.selfSigned=Self-Signed
|
||||||
|
validateSignature.cert.bits=bits
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -512,6 +512,10 @@ home.splitPdfByChapters.title=Dividir PDF por Capítulos
|
|||||||
home.splitPdfByChapters.desc=Divida um PDF em vários arquivos com base na estrutura dos capítulos.
|
home.splitPdfByChapters.desc=Divida um PDF em vários arquivos com base na estrutura dos capítulos.
|
||||||
splitPdfByChapters.tags=dividir,capítulos,marcadores,organizar
|
splitPdfByChapters.tags=dividir,capítulos,marcadores,organizar
|
||||||
|
|
||||||
|
home.validateSignature.title=Validate PDF Signature
|
||||||
|
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
|
||||||
|
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
|
||||||
|
|
||||||
#replace-invert-color
|
#replace-invert-color
|
||||||
replace-color.title=Replace-Invert-Color
|
replace-color.title=Replace-Invert-Color
|
||||||
replace-color.header=Substituir-Inverter Cor do PDF
|
replace-color.header=Substituir-Inverter Cor do PDF
|
||||||
@@ -961,6 +965,16 @@ multiTool.dragDropMessage=Page(s) Selected
|
|||||||
multiTool.undo=Undo
|
multiTool.undo=Undo
|
||||||
multiTool.redo=Redo
|
multiTool.redo=Redo
|
||||||
|
|
||||||
|
#decrypt
|
||||||
|
decrypt.passwordPrompt=This file is password-protected. Please enter the password:
|
||||||
|
decrypt.cancelled=Operation cancelled for PDF: {0}
|
||||||
|
decrypt.noPassword=No password provided for encrypted PDF: {0}
|
||||||
|
decrypt.invalidPassword=Please try again with the correct password.
|
||||||
|
decrypt.invalidPasswordHeader=Incorrect password or unsupported encryption for PDF: {0}
|
||||||
|
decrypt.unexpectedError=There was an error processing the file. Please try again.
|
||||||
|
decrypt.serverError=Server error while decrypting: {0}
|
||||||
|
decrypt.success=File decrypted successfully.
|
||||||
|
|
||||||
#multiTool-advert
|
#multiTool-advert
|
||||||
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
||||||
|
|
||||||
@@ -1052,12 +1066,13 @@ addPassword.submit=Proteger
|
|||||||
#watermark
|
#watermark
|
||||||
watermark.title=Adicionar Marca d'Água
|
watermark.title=Adicionar Marca d'Água
|
||||||
watermark.header=Adicionar Marca d'Água
|
watermark.header=Adicionar Marca d'Água
|
||||||
|
watermark.customColor=Personalizar a cor do texto
|
||||||
watermark.selectText.1=Seleccione o PDF para Adicionar a Marca d'Água
|
watermark.selectText.1=Seleccione o PDF para Adicionar a Marca d'Água
|
||||||
watermark.selectText.2=Texto da Marca d'Água
|
watermark.selectText.2=Texto da Marca d'Água
|
||||||
watermark.selectText.3=Tamanho da Fonte
|
watermark.selectText.3=Tamanho da Fonte
|
||||||
watermark.selectText.4=Rotação (0-360)
|
watermark.selectText.4=Rotação (0-360)
|
||||||
watermark.selectText.5=Espaçamento Horizontal (widthSpacer)
|
watermark.selectText.5=Espaçamento Horizontal (Width Spacer)
|
||||||
watermark.selectText.6=Espaçamento Vertical (heightSpacer)
|
watermark.selectText.6=Espaçamento Vertical (Height Spacer)
|
||||||
watermark.selectText.7=Opacidade (0% - 100%)
|
watermark.selectText.7=Opacidade (0% - 100%)
|
||||||
watermark.selectText.8=Tipo de Marca d'Água
|
watermark.selectText.8=Tipo de Marca d'Água
|
||||||
watermark.selectText.9=Imagem da Marca d'Água
|
watermark.selectText.9=Imagem da Marca d'Água
|
||||||
@@ -1263,6 +1278,11 @@ splitByChapters.desc.3=Inclua Metadados: Se marcado, os metadados originais do P
|
|||||||
splitByChapters.desc.4=Permitir Duplicatas: Se marcado, permite a criação de vários bookmarks na mesma página para criar separadamente vários PDFs.
|
splitByChapters.desc.4=Permitir Duplicatas: Se marcado, permite a criação de vários bookmarks na mesma página para criar separadamente vários PDFs.
|
||||||
splitByChapters.submit=Dividir o PDF
|
splitByChapters.submit=Dividir o PDF
|
||||||
|
|
||||||
|
#File Chooser
|
||||||
|
fileChooser.click=Click
|
||||||
|
fileChooser.or=or
|
||||||
|
fileChooser.dragAndDrop=Drag & Drop
|
||||||
|
fileChooser.hoveredDragAndDrop=Drag & Drop file(s) here
|
||||||
|
|
||||||
#release notes
|
#release notes
|
||||||
releases.footer=Releases
|
releases.footer=Releases
|
||||||
@@ -1270,3 +1290,38 @@ releases.title=Release Notes
|
|||||||
releases.header=Release Notes
|
releases.header=Release Notes
|
||||||
releases.current.version=Current Release
|
releases.current.version=Current Release
|
||||||
releases.note=Release notes are only available in English
|
releases.note=Release notes are only available in English
|
||||||
|
|
||||||
|
#Validate Signature
|
||||||
|
validateSignature.title=Validate PDF Signatures
|
||||||
|
validateSignature.header=Validate Digital Signatures
|
||||||
|
validateSignature.selectPDF=Select signed PDF file
|
||||||
|
validateSignature.submit=Validate Signatures
|
||||||
|
validateSignature.results=Validation Results
|
||||||
|
validateSignature.status=Status
|
||||||
|
validateSignature.signer=Signer
|
||||||
|
validateSignature.date=Date
|
||||||
|
validateSignature.reason=Reason
|
||||||
|
validateSignature.location=Location
|
||||||
|
validateSignature.noSignatures=No digital signatures found in this document
|
||||||
|
validateSignature.status.valid=Valid
|
||||||
|
validateSignature.status.invalid=Invalid
|
||||||
|
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
|
||||||
|
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
|
||||||
|
validateSignature.cert.expired=Certificate has expired
|
||||||
|
validateSignature.cert.revoked=Certificate has been revoked
|
||||||
|
validateSignature.signature.info=Signature Information
|
||||||
|
validateSignature.signature=Signature
|
||||||
|
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
|
||||||
|
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
|
||||||
|
validateSignature.cert.info=Certificate Details
|
||||||
|
validateSignature.cert.issuer=Issuer
|
||||||
|
validateSignature.cert.subject=Subject
|
||||||
|
validateSignature.cert.serialNumber=Serial Number
|
||||||
|
validateSignature.cert.validFrom=Valid From
|
||||||
|
validateSignature.cert.validUntil=Valid Until
|
||||||
|
validateSignature.cert.algorithm=Algorithm
|
||||||
|
validateSignature.cert.keySize=Key Size
|
||||||
|
validateSignature.cert.version=Version
|
||||||
|
validateSignature.cert.keyUsage=Key Usage
|
||||||
|
validateSignature.cert.selfSigned=Self-Signed
|
||||||
|
validateSignature.cert.bits=bits
|
||||||
|
|||||||
@@ -512,6 +512,10 @@ home.splitPdfByChapters.title=Split PDF by Chapters
|
|||||||
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
||||||
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
||||||
|
|
||||||
|
home.validateSignature.title=Validate PDF Signature
|
||||||
|
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
|
||||||
|
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
|
||||||
|
|
||||||
#replace-invert-color
|
#replace-invert-color
|
||||||
replace-color.title=Replace-Invert-Color
|
replace-color.title=Replace-Invert-Color
|
||||||
replace-color.header=Replace-Invert Color PDF
|
replace-color.header=Replace-Invert Color PDF
|
||||||
@@ -961,6 +965,16 @@ multiTool.dragDropMessage=Page(s) Selected
|
|||||||
multiTool.undo=Undo
|
multiTool.undo=Undo
|
||||||
multiTool.redo=Redo
|
multiTool.redo=Redo
|
||||||
|
|
||||||
|
#decrypt
|
||||||
|
decrypt.passwordPrompt=This file is password-protected. Please enter the password:
|
||||||
|
decrypt.cancelled=Operation cancelled for PDF: {0}
|
||||||
|
decrypt.noPassword=No password provided for encrypted PDF: {0}
|
||||||
|
decrypt.invalidPassword=Please try again with the correct password.
|
||||||
|
decrypt.invalidPasswordHeader=Incorrect password or unsupported encryption for PDF: {0}
|
||||||
|
decrypt.unexpectedError=There was an error processing the file. Please try again.
|
||||||
|
decrypt.serverError=Server error while decrypting: {0}
|
||||||
|
decrypt.success=File decrypted successfully.
|
||||||
|
|
||||||
#multiTool-advert
|
#multiTool-advert
|
||||||
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
||||||
|
|
||||||
@@ -1052,6 +1066,7 @@ addPassword.submit=Criptează
|
|||||||
#watermark
|
#watermark
|
||||||
watermark.title=Adaugă Filigran
|
watermark.title=Adaugă Filigran
|
||||||
watermark.header=Adaugă Filigran
|
watermark.header=Adaugă Filigran
|
||||||
|
watermark.customColor=Culoare Text Personalizată
|
||||||
watermark.selectText.1=Selectează PDF-ul la care să adaugi filigranul:
|
watermark.selectText.1=Selectează PDF-ul la care să adaugi filigranul:
|
||||||
watermark.selectText.2=Textul Filigranului:
|
watermark.selectText.2=Textul Filigranului:
|
||||||
watermark.selectText.3=Mărimea fontului:
|
watermark.selectText.3=Mărimea fontului:
|
||||||
@@ -1263,6 +1278,11 @@ splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata
|
|||||||
splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs.
|
splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs.
|
||||||
splitByChapters.submit=Split PDF
|
splitByChapters.submit=Split PDF
|
||||||
|
|
||||||
|
#File Chooser
|
||||||
|
fileChooser.click=Click
|
||||||
|
fileChooser.or=or
|
||||||
|
fileChooser.dragAndDrop=Drag & Drop
|
||||||
|
fileChooser.hoveredDragAndDrop=Drag & Drop file(s) here
|
||||||
|
|
||||||
#release notes
|
#release notes
|
||||||
releases.footer=Releases
|
releases.footer=Releases
|
||||||
@@ -1270,3 +1290,38 @@ releases.title=Release Notes
|
|||||||
releases.header=Release Notes
|
releases.header=Release Notes
|
||||||
releases.current.version=Current Release
|
releases.current.version=Current Release
|
||||||
releases.note=Release notes are only available in English
|
releases.note=Release notes are only available in English
|
||||||
|
|
||||||
|
#Validate Signature
|
||||||
|
validateSignature.title=Validate PDF Signatures
|
||||||
|
validateSignature.header=Validate Digital Signatures
|
||||||
|
validateSignature.selectPDF=Select signed PDF file
|
||||||
|
validateSignature.submit=Validate Signatures
|
||||||
|
validateSignature.results=Validation Results
|
||||||
|
validateSignature.status=Status
|
||||||
|
validateSignature.signer=Signer
|
||||||
|
validateSignature.date=Date
|
||||||
|
validateSignature.reason=Reason
|
||||||
|
validateSignature.location=Location
|
||||||
|
validateSignature.noSignatures=No digital signatures found in this document
|
||||||
|
validateSignature.status.valid=Valid
|
||||||
|
validateSignature.status.invalid=Invalid
|
||||||
|
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
|
||||||
|
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
|
||||||
|
validateSignature.cert.expired=Certificate has expired
|
||||||
|
validateSignature.cert.revoked=Certificate has been revoked
|
||||||
|
validateSignature.signature.info=Signature Information
|
||||||
|
validateSignature.signature=Signature
|
||||||
|
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
|
||||||
|
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
|
||||||
|
validateSignature.cert.info=Certificate Details
|
||||||
|
validateSignature.cert.issuer=Issuer
|
||||||
|
validateSignature.cert.subject=Subject
|
||||||
|
validateSignature.cert.serialNumber=Serial Number
|
||||||
|
validateSignature.cert.validFrom=Valid From
|
||||||
|
validateSignature.cert.validUntil=Valid Until
|
||||||
|
validateSignature.cert.algorithm=Algorithm
|
||||||
|
validateSignature.cert.keySize=Key Size
|
||||||
|
validateSignature.cert.version=Version
|
||||||
|
validateSignature.cert.keyUsage=Key Usage
|
||||||
|
validateSignature.cert.selfSigned=Self-Signed
|
||||||
|
validateSignature.cert.bits=bits
|
||||||
|
|||||||
@@ -512,6 +512,10 @@ home.splitPdfByChapters.title=Разделить PDF по разделам
|
|||||||
home.splitPdfByChapters.desc=Разделите PDF на несколько файлов на основе структуры его разделов
|
home.splitPdfByChapters.desc=Разделите PDF на несколько файлов на основе структуры его разделов
|
||||||
splitPdfByChapters.tags=разделение, разделы, закладки, организация
|
splitPdfByChapters.tags=разделение, разделы, закладки, организация
|
||||||
|
|
||||||
|
home.validateSignature.title=Validate PDF Signature
|
||||||
|
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
|
||||||
|
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
|
||||||
|
|
||||||
#replace-invert-color
|
#replace-invert-color
|
||||||
replace-color.title=Replace-Invert-Color
|
replace-color.title=Replace-Invert-Color
|
||||||
replace-color.header=Заменить-Обратное изменение цвета PDF
|
replace-color.header=Заменить-Обратное изменение цвета PDF
|
||||||
@@ -961,6 +965,16 @@ multiTool.dragDropMessage=Page(s) Selected
|
|||||||
multiTool.undo=Undo
|
multiTool.undo=Undo
|
||||||
multiTool.redo=Redo
|
multiTool.redo=Redo
|
||||||
|
|
||||||
|
#decrypt
|
||||||
|
decrypt.passwordPrompt=This file is password-protected. Please enter the password:
|
||||||
|
decrypt.cancelled=Operation cancelled for PDF: {0}
|
||||||
|
decrypt.noPassword=No password provided for encrypted PDF: {0}
|
||||||
|
decrypt.invalidPassword=Please try again with the correct password.
|
||||||
|
decrypt.invalidPasswordHeader=Incorrect password or unsupported encryption for PDF: {0}
|
||||||
|
decrypt.unexpectedError=There was an error processing the file. Please try again.
|
||||||
|
decrypt.serverError=Server error while decrypting: {0}
|
||||||
|
decrypt.success=File decrypted successfully.
|
||||||
|
|
||||||
#multiTool-advert
|
#multiTool-advert
|
||||||
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
||||||
|
|
||||||
@@ -1052,12 +1066,13 @@ addPassword.submit=Шифровать
|
|||||||
#watermark
|
#watermark
|
||||||
watermark.title=Добавить водяной знак
|
watermark.title=Добавить водяной знак
|
||||||
watermark.header=Добавить водяной знак
|
watermark.header=Добавить водяной знак
|
||||||
|
watermark.customColor=Настроенный цвет текста
|
||||||
watermark.selectText.1=Выберите PDF, чтобы добавить водяной знак:
|
watermark.selectText.1=Выберите PDF, чтобы добавить водяной знак:
|
||||||
watermark.selectText.2=Текст водяного знака:
|
watermark.selectText.2=Текст водяного знака:
|
||||||
watermark.selectText.3=Размер шрифта:
|
watermark.selectText.3=Размер шрифта:
|
||||||
watermark.selectText.4=Поворот (0-360):
|
watermark.selectText.4=Поворот (0-360):
|
||||||
watermark.selectText.5=widthSpacer (пробел между каждым водяным знаком по горизонтали):
|
watermark.selectText.5=Width Spacer (пробел между каждым водяным знаком по горизонтали):
|
||||||
watermark.selectText.6=heightSpacer (пробел между каждым водяным знаком по вертикали):
|
watermark.selectText.6=Height Spacer (пробел между каждым водяным знаком по вертикали):
|
||||||
watermark.selectText.7=Непрозрачность (0% - 100%):
|
watermark.selectText.7=Непрозрачность (0% - 100%):
|
||||||
watermark.selectText.8=Тип водяного знака:
|
watermark.selectText.8=Тип водяного знака:
|
||||||
watermark.selectText.9=Изображение водяного знака:
|
watermark.selectText.9=Изображение водяного знака:
|
||||||
@@ -1263,6 +1278,11 @@ splitByChapters.desc.3=Включить метаданные: если эта о
|
|||||||
splitByChapters.desc.4=Позволять дубликаты: если эта опция отмечена, на одной странице могут быть созданы несколько PDF из-за нескольких одинаковых закладок.
|
splitByChapters.desc.4=Позволять дубликаты: если эта опция отмечена, на одной странице могут быть созданы несколько PDF из-за нескольких одинаковых закладок.
|
||||||
splitByChapters.submit=Разделить PDF
|
splitByChapters.submit=Разделить PDF
|
||||||
|
|
||||||
|
#File Chooser
|
||||||
|
fileChooser.click=Click
|
||||||
|
fileChooser.or=or
|
||||||
|
fileChooser.dragAndDrop=Drag & Drop
|
||||||
|
fileChooser.hoveredDragAndDrop=Drag & Drop file(s) here
|
||||||
|
|
||||||
#release notes
|
#release notes
|
||||||
releases.footer=Releases
|
releases.footer=Releases
|
||||||
@@ -1270,3 +1290,38 @@ releases.title=Release Notes
|
|||||||
releases.header=Release Notes
|
releases.header=Release Notes
|
||||||
releases.current.version=Current Release
|
releases.current.version=Current Release
|
||||||
releases.note=Release notes are only available in English
|
releases.note=Release notes are only available in English
|
||||||
|
|
||||||
|
#Validate Signature
|
||||||
|
validateSignature.title=Validate PDF Signatures
|
||||||
|
validateSignature.header=Validate Digital Signatures
|
||||||
|
validateSignature.selectPDF=Select signed PDF file
|
||||||
|
validateSignature.submit=Validate Signatures
|
||||||
|
validateSignature.results=Validation Results
|
||||||
|
validateSignature.status=Status
|
||||||
|
validateSignature.signer=Signer
|
||||||
|
validateSignature.date=Date
|
||||||
|
validateSignature.reason=Reason
|
||||||
|
validateSignature.location=Location
|
||||||
|
validateSignature.noSignatures=No digital signatures found in this document
|
||||||
|
validateSignature.status.valid=Valid
|
||||||
|
validateSignature.status.invalid=Invalid
|
||||||
|
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
|
||||||
|
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
|
||||||
|
validateSignature.cert.expired=Certificate has expired
|
||||||
|
validateSignature.cert.revoked=Certificate has been revoked
|
||||||
|
validateSignature.signature.info=Signature Information
|
||||||
|
validateSignature.signature=Signature
|
||||||
|
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
|
||||||
|
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
|
||||||
|
validateSignature.cert.info=Certificate Details
|
||||||
|
validateSignature.cert.issuer=Issuer
|
||||||
|
validateSignature.cert.subject=Subject
|
||||||
|
validateSignature.cert.serialNumber=Serial Number
|
||||||
|
validateSignature.cert.validFrom=Valid From
|
||||||
|
validateSignature.cert.validUntil=Valid Until
|
||||||
|
validateSignature.cert.algorithm=Algorithm
|
||||||
|
validateSignature.cert.keySize=Key Size
|
||||||
|
validateSignature.cert.version=Version
|
||||||
|
validateSignature.cert.keyUsage=Key Usage
|
||||||
|
validateSignature.cert.selfSigned=Self-Signed
|
||||||
|
validateSignature.cert.bits=bits
|
||||||
|
|||||||
@@ -512,6 +512,10 @@ home.splitPdfByChapters.title=Split PDF by Chapters
|
|||||||
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
||||||
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
||||||
|
|
||||||
|
home.validateSignature.title=Validate PDF Signature
|
||||||
|
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
|
||||||
|
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
|
||||||
|
|
||||||
#replace-invert-color
|
#replace-invert-color
|
||||||
replace-color.title=Replace-Invert-Color
|
replace-color.title=Replace-Invert-Color
|
||||||
replace-color.header=Replace-Invert Color PDF
|
replace-color.header=Replace-Invert Color PDF
|
||||||
@@ -961,6 +965,16 @@ multiTool.dragDropMessage=Page(s) Selected
|
|||||||
multiTool.undo=Undo
|
multiTool.undo=Undo
|
||||||
multiTool.redo=Redo
|
multiTool.redo=Redo
|
||||||
|
|
||||||
|
#decrypt
|
||||||
|
decrypt.passwordPrompt=This file is password-protected. Please enter the password:
|
||||||
|
decrypt.cancelled=Operation cancelled for PDF: {0}
|
||||||
|
decrypt.noPassword=No password provided for encrypted PDF: {0}
|
||||||
|
decrypt.invalidPassword=Please try again with the correct password.
|
||||||
|
decrypt.invalidPasswordHeader=Incorrect password or unsupported encryption for PDF: {0}
|
||||||
|
decrypt.unexpectedError=There was an error processing the file. Please try again.
|
||||||
|
decrypt.serverError=Server error while decrypting: {0}
|
||||||
|
decrypt.success=File decrypted successfully.
|
||||||
|
|
||||||
#multiTool-advert
|
#multiTool-advert
|
||||||
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
||||||
|
|
||||||
@@ -1052,6 +1066,7 @@ addPassword.submit=Zašifrovať
|
|||||||
#watermark
|
#watermark
|
||||||
watermark.title=Pridať vodotlač
|
watermark.title=Pridať vodotlač
|
||||||
watermark.header=Pridať vodotlač
|
watermark.header=Pridať vodotlač
|
||||||
|
watermark.customColor=Vlastná farba textu
|
||||||
watermark.selectText.1=Vyberte PDF, do ktorého chcete pridať vodotlač:
|
watermark.selectText.1=Vyberte PDF, do ktorého chcete pridať vodotlač:
|
||||||
watermark.selectText.2=Text vodotlače:
|
watermark.selectText.2=Text vodotlače:
|
||||||
watermark.selectText.3=Veľkosť písma:
|
watermark.selectText.3=Veľkosť písma:
|
||||||
@@ -1263,6 +1278,11 @@ splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata
|
|||||||
splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs.
|
splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs.
|
||||||
splitByChapters.submit=Split PDF
|
splitByChapters.submit=Split PDF
|
||||||
|
|
||||||
|
#File Chooser
|
||||||
|
fileChooser.click=Click
|
||||||
|
fileChooser.or=or
|
||||||
|
fileChooser.dragAndDrop=Drag & Drop
|
||||||
|
fileChooser.hoveredDragAndDrop=Drag & Drop file(s) here
|
||||||
|
|
||||||
#release notes
|
#release notes
|
||||||
releases.footer=Releases
|
releases.footer=Releases
|
||||||
@@ -1270,3 +1290,38 @@ releases.title=Release Notes
|
|||||||
releases.header=Release Notes
|
releases.header=Release Notes
|
||||||
releases.current.version=Current Release
|
releases.current.version=Current Release
|
||||||
releases.note=Release notes are only available in English
|
releases.note=Release notes are only available in English
|
||||||
|
|
||||||
|
#Validate Signature
|
||||||
|
validateSignature.title=Validate PDF Signatures
|
||||||
|
validateSignature.header=Validate Digital Signatures
|
||||||
|
validateSignature.selectPDF=Select signed PDF file
|
||||||
|
validateSignature.submit=Validate Signatures
|
||||||
|
validateSignature.results=Validation Results
|
||||||
|
validateSignature.status=Status
|
||||||
|
validateSignature.signer=Signer
|
||||||
|
validateSignature.date=Date
|
||||||
|
validateSignature.reason=Reason
|
||||||
|
validateSignature.location=Location
|
||||||
|
validateSignature.noSignatures=No digital signatures found in this document
|
||||||
|
validateSignature.status.valid=Valid
|
||||||
|
validateSignature.status.invalid=Invalid
|
||||||
|
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
|
||||||
|
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
|
||||||
|
validateSignature.cert.expired=Certificate has expired
|
||||||
|
validateSignature.cert.revoked=Certificate has been revoked
|
||||||
|
validateSignature.signature.info=Signature Information
|
||||||
|
validateSignature.signature=Signature
|
||||||
|
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
|
||||||
|
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
|
||||||
|
validateSignature.cert.info=Certificate Details
|
||||||
|
validateSignature.cert.issuer=Issuer
|
||||||
|
validateSignature.cert.subject=Subject
|
||||||
|
validateSignature.cert.serialNumber=Serial Number
|
||||||
|
validateSignature.cert.validFrom=Valid From
|
||||||
|
validateSignature.cert.validUntil=Valid Until
|
||||||
|
validateSignature.cert.algorithm=Algorithm
|
||||||
|
validateSignature.cert.keySize=Key Size
|
||||||
|
validateSignature.cert.version=Version
|
||||||
|
validateSignature.cert.keyUsage=Key Usage
|
||||||
|
validateSignature.cert.selfSigned=Self-Signed
|
||||||
|
validateSignature.cert.bits=bits
|
||||||
|
|||||||
@@ -512,6 +512,10 @@ home.splitPdfByChapters.title=Split PDF by Chapters
|
|||||||
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
||||||
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
||||||
|
|
||||||
|
home.validateSignature.title=Validate PDF Signature
|
||||||
|
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
|
||||||
|
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
|
||||||
|
|
||||||
#replace-invert-color
|
#replace-invert-color
|
||||||
replace-color.title=Replace-Invert-Color
|
replace-color.title=Replace-Invert-Color
|
||||||
replace-color.header=Replace-Invert Color PDF
|
replace-color.header=Replace-Invert Color PDF
|
||||||
@@ -961,6 +965,16 @@ multiTool.dragDropMessage=Page(s) Selected
|
|||||||
multiTool.undo=Undo
|
multiTool.undo=Undo
|
||||||
multiTool.redo=Redo
|
multiTool.redo=Redo
|
||||||
|
|
||||||
|
#decrypt
|
||||||
|
decrypt.passwordPrompt=This file is password-protected. Please enter the password:
|
||||||
|
decrypt.cancelled=Operation cancelled for PDF: {0}
|
||||||
|
decrypt.noPassword=No password provided for encrypted PDF: {0}
|
||||||
|
decrypt.invalidPassword=Please try again with the correct password.
|
||||||
|
decrypt.invalidPasswordHeader=Incorrect password or unsupported encryption for PDF: {0}
|
||||||
|
decrypt.unexpectedError=There was an error processing the file. Please try again.
|
||||||
|
decrypt.serverError=Server error while decrypting: {0}
|
||||||
|
decrypt.success=File decrypted successfully.
|
||||||
|
|
||||||
#multiTool-advert
|
#multiTool-advert
|
||||||
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
||||||
|
|
||||||
@@ -1052,6 +1066,7 @@ addPassword.submit=Enkriptuj
|
|||||||
#watermark
|
#watermark
|
||||||
watermark.title=Dodaj vodeni žig
|
watermark.title=Dodaj vodeni žig
|
||||||
watermark.header=Dodaj vodeni žig
|
watermark.header=Dodaj vodeni žig
|
||||||
|
watermark.customColor=Custom Text Color
|
||||||
watermark.selectText.1=Izaberite PDF za dodavanje vodenog žiga:
|
watermark.selectText.1=Izaberite PDF za dodavanje vodenog žiga:
|
||||||
watermark.selectText.2=Tekst vodenog žiga:
|
watermark.selectText.2=Tekst vodenog žiga:
|
||||||
watermark.selectText.3=Veličina fonta:
|
watermark.selectText.3=Veličina fonta:
|
||||||
@@ -1263,6 +1278,11 @@ splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata
|
|||||||
splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs.
|
splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs.
|
||||||
splitByChapters.submit=Split PDF
|
splitByChapters.submit=Split PDF
|
||||||
|
|
||||||
|
#File Chooser
|
||||||
|
fileChooser.click=Click
|
||||||
|
fileChooser.or=or
|
||||||
|
fileChooser.dragAndDrop=Drag & Drop
|
||||||
|
fileChooser.hoveredDragAndDrop=Drag & Drop file(s) here
|
||||||
|
|
||||||
#release notes
|
#release notes
|
||||||
releases.footer=Releases
|
releases.footer=Releases
|
||||||
@@ -1270,3 +1290,38 @@ releases.title=Release Notes
|
|||||||
releases.header=Release Notes
|
releases.header=Release Notes
|
||||||
releases.current.version=Current Release
|
releases.current.version=Current Release
|
||||||
releases.note=Release notes are only available in English
|
releases.note=Release notes are only available in English
|
||||||
|
|
||||||
|
#Validate Signature
|
||||||
|
validateSignature.title=Validate PDF Signatures
|
||||||
|
validateSignature.header=Validate Digital Signatures
|
||||||
|
validateSignature.selectPDF=Select signed PDF file
|
||||||
|
validateSignature.submit=Validate Signatures
|
||||||
|
validateSignature.results=Validation Results
|
||||||
|
validateSignature.status=Status
|
||||||
|
validateSignature.signer=Signer
|
||||||
|
validateSignature.date=Date
|
||||||
|
validateSignature.reason=Reason
|
||||||
|
validateSignature.location=Location
|
||||||
|
validateSignature.noSignatures=No digital signatures found in this document
|
||||||
|
validateSignature.status.valid=Valid
|
||||||
|
validateSignature.status.invalid=Invalid
|
||||||
|
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
|
||||||
|
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
|
||||||
|
validateSignature.cert.expired=Certificate has expired
|
||||||
|
validateSignature.cert.revoked=Certificate has been revoked
|
||||||
|
validateSignature.signature.info=Signature Information
|
||||||
|
validateSignature.signature=Signature
|
||||||
|
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
|
||||||
|
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
|
||||||
|
validateSignature.cert.info=Certificate Details
|
||||||
|
validateSignature.cert.issuer=Issuer
|
||||||
|
validateSignature.cert.subject=Subject
|
||||||
|
validateSignature.cert.serialNumber=Serial Number
|
||||||
|
validateSignature.cert.validFrom=Valid From
|
||||||
|
validateSignature.cert.validUntil=Valid Until
|
||||||
|
validateSignature.cert.algorithm=Algorithm
|
||||||
|
validateSignature.cert.keySize=Key Size
|
||||||
|
validateSignature.cert.version=Version
|
||||||
|
validateSignature.cert.keyUsage=Key Usage
|
||||||
|
validateSignature.cert.selfSigned=Self-Signed
|
||||||
|
validateSignature.cert.bits=bits
|
||||||
|
|||||||
@@ -512,6 +512,10 @@ home.splitPdfByChapters.title=Dela upp PDF efter kapitel
|
|||||||
home.splitPdfByChapters.desc=Dela upp en PDF till flera filer baserat på dess kapitelstruktur.
|
home.splitPdfByChapters.desc=Dela upp en PDF till flera filer baserat på dess kapitelstruktur.
|
||||||
splitPdfByChapters.tags=dela,kapitel,bokmärken,organisera
|
splitPdfByChapters.tags=dela,kapitel,bokmärken,organisera
|
||||||
|
|
||||||
|
home.validateSignature.title=Validate PDF Signature
|
||||||
|
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
|
||||||
|
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
|
||||||
|
|
||||||
#replace-invert-color
|
#replace-invert-color
|
||||||
replace-color.title=Replace-Invert-Color
|
replace-color.title=Replace-Invert-Color
|
||||||
replace-color.header=Ersätt-Invertera färg på PDF
|
replace-color.header=Ersätt-Invertera färg på PDF
|
||||||
@@ -961,6 +965,16 @@ multiTool.dragDropMessage=Page(s) Selected
|
|||||||
multiTool.undo=Undo
|
multiTool.undo=Undo
|
||||||
multiTool.redo=Redo
|
multiTool.redo=Redo
|
||||||
|
|
||||||
|
#decrypt
|
||||||
|
decrypt.passwordPrompt=This file is password-protected. Please enter the password:
|
||||||
|
decrypt.cancelled=Operation cancelled for PDF: {0}
|
||||||
|
decrypt.noPassword=No password provided for encrypted PDF: {0}
|
||||||
|
decrypt.invalidPassword=Please try again with the correct password.
|
||||||
|
decrypt.invalidPasswordHeader=Incorrect password or unsupported encryption for PDF: {0}
|
||||||
|
decrypt.unexpectedError=There was an error processing the file. Please try again.
|
||||||
|
decrypt.serverError=Server error while decrypting: {0}
|
||||||
|
decrypt.success=File decrypted successfully.
|
||||||
|
|
||||||
#multiTool-advert
|
#multiTool-advert
|
||||||
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
||||||
|
|
||||||
@@ -1052,12 +1066,13 @@ addPassword.submit=Kryptera
|
|||||||
#watermark
|
#watermark
|
||||||
watermark.title=Lägg till vattenstämpel
|
watermark.title=Lägg till vattenstämpel
|
||||||
watermark.header=Lägg till vattenstämpel
|
watermark.header=Lägg till vattenstämpel
|
||||||
|
watermark.customColor=Anpassad textfärg
|
||||||
watermark.selectText.1=Välj PDF för att lägga till vattenstämpel till:
|
watermark.selectText.1=Välj PDF för att lägga till vattenstämpel till:
|
||||||
watermark.selectText.2=Vattenmärkestext:
|
watermark.selectText.2=Vattenmärkestext:
|
||||||
watermark.selectText.3=Teckenstorlek:
|
watermark.selectText.3=Teckenstorlek:
|
||||||
watermark.selectText.4=Vändning (0-360):
|
watermark.selectText.4=Vändning (0-360):
|
||||||
watermark.selectText.5=widthSpacer (mellanrum mellan varje vattenstämpel horisontellt):
|
watermark.selectText.5=Width Spacer (mellanrum mellan varje vattenstämpel horisontellt):
|
||||||
watermark.selectText.6=heightSpacer (mellanrum mellan varje vattenstämpel vertikalt):
|
watermark.selectText.6=Height Spacer (mellanrum mellan varje vattenstämpel vertikalt):
|
||||||
watermark.selectText.7=Opacitet (0% - 100%):
|
watermark.selectText.7=Opacitet (0% - 100%):
|
||||||
watermark.selectText.8=Vattenstämpeltyp:
|
watermark.selectText.8=Vattenstämpeltyp:
|
||||||
watermark.selectText.9=Vattenstämpelbild:
|
watermark.selectText.9=Vattenstämpelbild:
|
||||||
@@ -1263,6 +1278,11 @@ splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata
|
|||||||
splitByChapters.desc.4=Tillåt duplicieringar: Om kryssrutan är markerad tillåts flera bokmärken på samma sida skapa individuella PDF:er.
|
splitByChapters.desc.4=Tillåt duplicieringar: Om kryssrutan är markerad tillåts flera bokmärken på samma sida skapa individuella PDF:er.
|
||||||
splitByChapters.submit=Dela upp PDF
|
splitByChapters.submit=Dela upp PDF
|
||||||
|
|
||||||
|
#File Chooser
|
||||||
|
fileChooser.click=Click
|
||||||
|
fileChooser.or=or
|
||||||
|
fileChooser.dragAndDrop=Drag & Drop
|
||||||
|
fileChooser.hoveredDragAndDrop=Drag & Drop file(s) here
|
||||||
|
|
||||||
#release notes
|
#release notes
|
||||||
releases.footer=Releases
|
releases.footer=Releases
|
||||||
@@ -1270,3 +1290,38 @@ releases.title=Release Notes
|
|||||||
releases.header=Release Notes
|
releases.header=Release Notes
|
||||||
releases.current.version=Current Release
|
releases.current.version=Current Release
|
||||||
releases.note=Release notes are only available in English
|
releases.note=Release notes are only available in English
|
||||||
|
|
||||||
|
#Validate Signature
|
||||||
|
validateSignature.title=Validate PDF Signatures
|
||||||
|
validateSignature.header=Validate Digital Signatures
|
||||||
|
validateSignature.selectPDF=Select signed PDF file
|
||||||
|
validateSignature.submit=Validate Signatures
|
||||||
|
validateSignature.results=Validation Results
|
||||||
|
validateSignature.status=Status
|
||||||
|
validateSignature.signer=Signer
|
||||||
|
validateSignature.date=Date
|
||||||
|
validateSignature.reason=Reason
|
||||||
|
validateSignature.location=Location
|
||||||
|
validateSignature.noSignatures=No digital signatures found in this document
|
||||||
|
validateSignature.status.valid=Valid
|
||||||
|
validateSignature.status.invalid=Invalid
|
||||||
|
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
|
||||||
|
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
|
||||||
|
validateSignature.cert.expired=Certificate has expired
|
||||||
|
validateSignature.cert.revoked=Certificate has been revoked
|
||||||
|
validateSignature.signature.info=Signature Information
|
||||||
|
validateSignature.signature=Signature
|
||||||
|
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
|
||||||
|
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
|
||||||
|
validateSignature.cert.info=Certificate Details
|
||||||
|
validateSignature.cert.issuer=Issuer
|
||||||
|
validateSignature.cert.subject=Subject
|
||||||
|
validateSignature.cert.serialNumber=Serial Number
|
||||||
|
validateSignature.cert.validFrom=Valid From
|
||||||
|
validateSignature.cert.validUntil=Valid Until
|
||||||
|
validateSignature.cert.algorithm=Algorithm
|
||||||
|
validateSignature.cert.keySize=Key Size
|
||||||
|
validateSignature.cert.version=Version
|
||||||
|
validateSignature.cert.keyUsage=Key Usage
|
||||||
|
validateSignature.cert.selfSigned=Self-Signed
|
||||||
|
validateSignature.cert.bits=bits
|
||||||
|
|||||||
@@ -512,6 +512,10 @@ home.splitPdfByChapters.title=Split PDF by Chapters
|
|||||||
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
||||||
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
||||||
|
|
||||||
|
home.validateSignature.title=Validate PDF Signature
|
||||||
|
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
|
||||||
|
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
|
||||||
|
|
||||||
#replace-invert-color
|
#replace-invert-color
|
||||||
replace-color.title=Replace-Invert-Color
|
replace-color.title=Replace-Invert-Color
|
||||||
replace-color.header=Replace-Invert Color PDF
|
replace-color.header=Replace-Invert Color PDF
|
||||||
@@ -961,6 +965,16 @@ multiTool.dragDropMessage=Page(s) Selected
|
|||||||
multiTool.undo=Undo
|
multiTool.undo=Undo
|
||||||
multiTool.redo=Redo
|
multiTool.redo=Redo
|
||||||
|
|
||||||
|
#decrypt
|
||||||
|
decrypt.passwordPrompt=This file is password-protected. Please enter the password:
|
||||||
|
decrypt.cancelled=Operation cancelled for PDF: {0}
|
||||||
|
decrypt.noPassword=No password provided for encrypted PDF: {0}
|
||||||
|
decrypt.invalidPassword=Please try again with the correct password.
|
||||||
|
decrypt.invalidPasswordHeader=Incorrect password or unsupported encryption for PDF: {0}
|
||||||
|
decrypt.unexpectedError=There was an error processing the file. Please try again.
|
||||||
|
decrypt.serverError=Server error while decrypting: {0}
|
||||||
|
decrypt.success=File decrypted successfully.
|
||||||
|
|
||||||
#multiTool-advert
|
#multiTool-advert
|
||||||
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
||||||
|
|
||||||
@@ -1052,6 +1066,7 @@ addPassword.submit=เข้ารหัส
|
|||||||
#watermark
|
#watermark
|
||||||
watermark.title=เพิ่มลายน้ำ
|
watermark.title=เพิ่มลายน้ำ
|
||||||
watermark.header=เพิ่มลายน้ำ
|
watermark.header=เพิ่มลายน้ำ
|
||||||
|
watermark.customColor=สีข้อความที่กำหนดเอง
|
||||||
watermark.selectText.1=เลือก PDF เพื่อเพิ่มลายน้ำ:
|
watermark.selectText.1=เลือก PDF เพื่อเพิ่มลายน้ำ:
|
||||||
watermark.selectText.2=ข้อความลายน้ำ:
|
watermark.selectText.2=ข้อความลายน้ำ:
|
||||||
watermark.selectText.3=ขนาดฟอนต์:
|
watermark.selectText.3=ขนาดฟอนต์:
|
||||||
@@ -1263,6 +1278,11 @@ splitByChapters.desc.3=รวมข้อมูลเสริม: หากถ
|
|||||||
splitByChapters.desc.4=อนุญาตให้มีการซ้ำ: หากถูกเลือก จะทำให้สามารถสร้างไฟล์ PDF แยกออกมาจากหน้าเดียวกันได้หลายรายการ
|
splitByChapters.desc.4=อนุญาตให้มีการซ้ำ: หากถูกเลือก จะทำให้สามารถสร้างไฟล์ PDF แยกออกมาจากหน้าเดียวกันได้หลายรายการ
|
||||||
splitByChapters.submit=แบ่งไฟล์ PDF
|
splitByChapters.submit=แบ่งไฟล์ PDF
|
||||||
|
|
||||||
|
#File Chooser
|
||||||
|
fileChooser.click=Click
|
||||||
|
fileChooser.or=or
|
||||||
|
fileChooser.dragAndDrop=Drag & Drop
|
||||||
|
fileChooser.hoveredDragAndDrop=Drag & Drop file(s) here
|
||||||
|
|
||||||
#release notes
|
#release notes
|
||||||
releases.footer=Releases
|
releases.footer=Releases
|
||||||
@@ -1270,3 +1290,38 @@ releases.title=Release Notes
|
|||||||
releases.header=Release Notes
|
releases.header=Release Notes
|
||||||
releases.current.version=Current Release
|
releases.current.version=Current Release
|
||||||
releases.note=Release notes are only available in English
|
releases.note=Release notes are only available in English
|
||||||
|
|
||||||
|
#Validate Signature
|
||||||
|
validateSignature.title=Validate PDF Signatures
|
||||||
|
validateSignature.header=Validate Digital Signatures
|
||||||
|
validateSignature.selectPDF=Select signed PDF file
|
||||||
|
validateSignature.submit=Validate Signatures
|
||||||
|
validateSignature.results=Validation Results
|
||||||
|
validateSignature.status=Status
|
||||||
|
validateSignature.signer=Signer
|
||||||
|
validateSignature.date=Date
|
||||||
|
validateSignature.reason=Reason
|
||||||
|
validateSignature.location=Location
|
||||||
|
validateSignature.noSignatures=No digital signatures found in this document
|
||||||
|
validateSignature.status.valid=Valid
|
||||||
|
validateSignature.status.invalid=Invalid
|
||||||
|
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
|
||||||
|
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
|
||||||
|
validateSignature.cert.expired=Certificate has expired
|
||||||
|
validateSignature.cert.revoked=Certificate has been revoked
|
||||||
|
validateSignature.signature.info=Signature Information
|
||||||
|
validateSignature.signature=Signature
|
||||||
|
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
|
||||||
|
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
|
||||||
|
validateSignature.cert.info=Certificate Details
|
||||||
|
validateSignature.cert.issuer=Issuer
|
||||||
|
validateSignature.cert.subject=Subject
|
||||||
|
validateSignature.cert.serialNumber=Serial Number
|
||||||
|
validateSignature.cert.validFrom=Valid From
|
||||||
|
validateSignature.cert.validUntil=Valid Until
|
||||||
|
validateSignature.cert.algorithm=Algorithm
|
||||||
|
validateSignature.cert.keySize=Key Size
|
||||||
|
validateSignature.cert.version=Version
|
||||||
|
validateSignature.cert.keyUsage=Key Usage
|
||||||
|
validateSignature.cert.selfSigned=Self-Signed
|
||||||
|
validateSignature.cert.bits=bits
|
||||||
|
|||||||
@@ -512,6 +512,10 @@ home.splitPdfByChapters.title=Split PDF by Chapters
|
|||||||
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
||||||
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
||||||
|
|
||||||
|
home.validateSignature.title=Validate PDF Signature
|
||||||
|
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
|
||||||
|
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
|
||||||
|
|
||||||
#replace-invert-color
|
#replace-invert-color
|
||||||
replace-color.title=Replace-Invert-Color
|
replace-color.title=Replace-Invert-Color
|
||||||
replace-color.header=Replace-Invert Color PDF
|
replace-color.header=Replace-Invert Color PDF
|
||||||
@@ -961,6 +965,16 @@ multiTool.dragDropMessage=Page(s) Selected
|
|||||||
multiTool.undo=Undo
|
multiTool.undo=Undo
|
||||||
multiTool.redo=Redo
|
multiTool.redo=Redo
|
||||||
|
|
||||||
|
#decrypt
|
||||||
|
decrypt.passwordPrompt=This file is password-protected. Please enter the password:
|
||||||
|
decrypt.cancelled=Operation cancelled for PDF: {0}
|
||||||
|
decrypt.noPassword=No password provided for encrypted PDF: {0}
|
||||||
|
decrypt.invalidPassword=Please try again with the correct password.
|
||||||
|
decrypt.invalidPasswordHeader=Incorrect password or unsupported encryption for PDF: {0}
|
||||||
|
decrypt.unexpectedError=There was an error processing the file. Please try again.
|
||||||
|
decrypt.serverError=Server error while decrypting: {0}
|
||||||
|
decrypt.success=File decrypted successfully.
|
||||||
|
|
||||||
#multiTool-advert
|
#multiTool-advert
|
||||||
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
||||||
|
|
||||||
@@ -1052,6 +1066,7 @@ addPassword.submit=Şifrele
|
|||||||
#watermark
|
#watermark
|
||||||
watermark.title=Filigran Ekle
|
watermark.title=Filigran Ekle
|
||||||
watermark.header=Filigran Ekle
|
watermark.header=Filigran Ekle
|
||||||
|
watermark.customColor=Özel Metin Rengi
|
||||||
watermark.selectText.1=Filigran eklemek için PDF seçin:
|
watermark.selectText.1=Filigran eklemek için PDF seçin:
|
||||||
watermark.selectText.2=Filigran Metni:
|
watermark.selectText.2=Filigran Metni:
|
||||||
watermark.selectText.3=Yazı Boyutu:
|
watermark.selectText.3=Yazı Boyutu:
|
||||||
@@ -1263,6 +1278,11 @@ splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata
|
|||||||
splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs.
|
splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs.
|
||||||
splitByChapters.submit=Split PDF
|
splitByChapters.submit=Split PDF
|
||||||
|
|
||||||
|
#File Chooser
|
||||||
|
fileChooser.click=Click
|
||||||
|
fileChooser.or=or
|
||||||
|
fileChooser.dragAndDrop=Drag & Drop
|
||||||
|
fileChooser.hoveredDragAndDrop=Drag & Drop file(s) here
|
||||||
|
|
||||||
#release notes
|
#release notes
|
||||||
releases.footer=Releases
|
releases.footer=Releases
|
||||||
@@ -1270,3 +1290,38 @@ releases.title=Release Notes
|
|||||||
releases.header=Release Notes
|
releases.header=Release Notes
|
||||||
releases.current.version=Current Release
|
releases.current.version=Current Release
|
||||||
releases.note=Release notes are only available in English
|
releases.note=Release notes are only available in English
|
||||||
|
|
||||||
|
#Validate Signature
|
||||||
|
validateSignature.title=Validate PDF Signatures
|
||||||
|
validateSignature.header=Validate Digital Signatures
|
||||||
|
validateSignature.selectPDF=Select signed PDF file
|
||||||
|
validateSignature.submit=Validate Signatures
|
||||||
|
validateSignature.results=Validation Results
|
||||||
|
validateSignature.status=Status
|
||||||
|
validateSignature.signer=Signer
|
||||||
|
validateSignature.date=Date
|
||||||
|
validateSignature.reason=Reason
|
||||||
|
validateSignature.location=Location
|
||||||
|
validateSignature.noSignatures=No digital signatures found in this document
|
||||||
|
validateSignature.status.valid=Valid
|
||||||
|
validateSignature.status.invalid=Invalid
|
||||||
|
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
|
||||||
|
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
|
||||||
|
validateSignature.cert.expired=Certificate has expired
|
||||||
|
validateSignature.cert.revoked=Certificate has been revoked
|
||||||
|
validateSignature.signature.info=Signature Information
|
||||||
|
validateSignature.signature=Signature
|
||||||
|
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
|
||||||
|
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
|
||||||
|
validateSignature.cert.info=Certificate Details
|
||||||
|
validateSignature.cert.issuer=Issuer
|
||||||
|
validateSignature.cert.subject=Subject
|
||||||
|
validateSignature.cert.serialNumber=Serial Number
|
||||||
|
validateSignature.cert.validFrom=Valid From
|
||||||
|
validateSignature.cert.validUntil=Valid Until
|
||||||
|
validateSignature.cert.algorithm=Algorithm
|
||||||
|
validateSignature.cert.keySize=Key Size
|
||||||
|
validateSignature.cert.version=Version
|
||||||
|
validateSignature.cert.keyUsage=Key Usage
|
||||||
|
validateSignature.cert.selfSigned=Self-Signed
|
||||||
|
validateSignature.cert.bits=bits
|
||||||
|
|||||||
@@ -512,6 +512,10 @@ home.splitPdfByChapters.title=Split PDF by Chapters
|
|||||||
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
||||||
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
||||||
|
|
||||||
|
home.validateSignature.title=Validate PDF Signature
|
||||||
|
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
|
||||||
|
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
|
||||||
|
|
||||||
#replace-invert-color
|
#replace-invert-color
|
||||||
replace-color.title=Replace-Invert-Color
|
replace-color.title=Replace-Invert-Color
|
||||||
replace-color.header=Replace-Invert Color PDF
|
replace-color.header=Replace-Invert Color PDF
|
||||||
@@ -961,6 +965,16 @@ multiTool.dragDropMessage=Page(s) Selected
|
|||||||
multiTool.undo=Undo
|
multiTool.undo=Undo
|
||||||
multiTool.redo=Redo
|
multiTool.redo=Redo
|
||||||
|
|
||||||
|
#decrypt
|
||||||
|
decrypt.passwordPrompt=This file is password-protected. Please enter the password:
|
||||||
|
decrypt.cancelled=Operation cancelled for PDF: {0}
|
||||||
|
decrypt.noPassword=No password provided for encrypted PDF: {0}
|
||||||
|
decrypt.invalidPassword=Please try again with the correct password.
|
||||||
|
decrypt.invalidPasswordHeader=Incorrect password or unsupported encryption for PDF: {0}
|
||||||
|
decrypt.unexpectedError=There was an error processing the file. Please try again.
|
||||||
|
decrypt.serverError=Server error while decrypting: {0}
|
||||||
|
decrypt.success=File decrypted successfully.
|
||||||
|
|
||||||
#multiTool-advert
|
#multiTool-advert
|
||||||
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
||||||
|
|
||||||
@@ -1052,12 +1066,13 @@ addPassword.submit=Шифрувати
|
|||||||
#watermark
|
#watermark
|
||||||
watermark.title=Додати водяний знак
|
watermark.title=Додати водяний знак
|
||||||
watermark.header=Додати водяний знак
|
watermark.header=Додати водяний знак
|
||||||
|
watermark.customColor=Користувацький колір тексту
|
||||||
watermark.selectText.1=Виберіть PDF, щоб додати водяний знак:
|
watermark.selectText.1=Виберіть PDF, щоб додати водяний знак:
|
||||||
watermark.selectText.2=Текст водяного знаку:
|
watermark.selectText.2=Текст водяного знаку:
|
||||||
watermark.selectText.3=Розмір шрифту:
|
watermark.selectText.3=Розмір шрифту:
|
||||||
watermark.selectText.4=Обертання (0-360):
|
watermark.selectText.4=Обертання (0-360):
|
||||||
watermark.selectText.5=widthSpacer (проміжок між кожним водяним знаком по горизонталі):
|
watermark.selectText.5=Width Spacer (проміжок між кожним водяним знаком по горизонталі):
|
||||||
watermark.selectText.6=heightSpacer (проміжок між кожним водяним знаком по вертикалі):
|
watermark.selectText.6=Height Spacer (проміжок між кожним водяним знаком по вертикалі):
|
||||||
watermark.selectText.7=Непрозорість (0% - 100%):
|
watermark.selectText.7=Непрозорість (0% - 100%):
|
||||||
watermark.selectText.8=Тип водяного знаку:
|
watermark.selectText.8=Тип водяного знаку:
|
||||||
watermark.selectText.9=Зображення водяного знаку:
|
watermark.selectText.9=Зображення водяного знаку:
|
||||||
@@ -1263,6 +1278,11 @@ splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata
|
|||||||
splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs.
|
splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs.
|
||||||
splitByChapters.submit=Split PDF
|
splitByChapters.submit=Split PDF
|
||||||
|
|
||||||
|
#File Chooser
|
||||||
|
fileChooser.click=Click
|
||||||
|
fileChooser.or=or
|
||||||
|
fileChooser.dragAndDrop=Drag & Drop
|
||||||
|
fileChooser.hoveredDragAndDrop=Drag & Drop file(s) here
|
||||||
|
|
||||||
#release notes
|
#release notes
|
||||||
releases.footer=Releases
|
releases.footer=Releases
|
||||||
@@ -1270,3 +1290,38 @@ releases.title=Release Notes
|
|||||||
releases.header=Release Notes
|
releases.header=Release Notes
|
||||||
releases.current.version=Current Release
|
releases.current.version=Current Release
|
||||||
releases.note=Release notes are only available in English
|
releases.note=Release notes are only available in English
|
||||||
|
|
||||||
|
#Validate Signature
|
||||||
|
validateSignature.title=Validate PDF Signatures
|
||||||
|
validateSignature.header=Validate Digital Signatures
|
||||||
|
validateSignature.selectPDF=Select signed PDF file
|
||||||
|
validateSignature.submit=Validate Signatures
|
||||||
|
validateSignature.results=Validation Results
|
||||||
|
validateSignature.status=Status
|
||||||
|
validateSignature.signer=Signer
|
||||||
|
validateSignature.date=Date
|
||||||
|
validateSignature.reason=Reason
|
||||||
|
validateSignature.location=Location
|
||||||
|
validateSignature.noSignatures=No digital signatures found in this document
|
||||||
|
validateSignature.status.valid=Valid
|
||||||
|
validateSignature.status.invalid=Invalid
|
||||||
|
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
|
||||||
|
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
|
||||||
|
validateSignature.cert.expired=Certificate has expired
|
||||||
|
validateSignature.cert.revoked=Certificate has been revoked
|
||||||
|
validateSignature.signature.info=Signature Information
|
||||||
|
validateSignature.signature=Signature
|
||||||
|
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
|
||||||
|
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
|
||||||
|
validateSignature.cert.info=Certificate Details
|
||||||
|
validateSignature.cert.issuer=Issuer
|
||||||
|
validateSignature.cert.subject=Subject
|
||||||
|
validateSignature.cert.serialNumber=Serial Number
|
||||||
|
validateSignature.cert.validFrom=Valid From
|
||||||
|
validateSignature.cert.validUntil=Valid Until
|
||||||
|
validateSignature.cert.algorithm=Algorithm
|
||||||
|
validateSignature.cert.keySize=Key Size
|
||||||
|
validateSignature.cert.version=Version
|
||||||
|
validateSignature.cert.keyUsage=Key Usage
|
||||||
|
validateSignature.cert.selfSigned=Self-Signed
|
||||||
|
validateSignature.cert.bits=bits
|
||||||
|
|||||||
@@ -512,6 +512,10 @@ home.splitPdfByChapters.title=Split PDF by Chapters
|
|||||||
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
||||||
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
||||||
|
|
||||||
|
home.validateSignature.title=Validate PDF Signature
|
||||||
|
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
|
||||||
|
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
|
||||||
|
|
||||||
#replace-invert-color
|
#replace-invert-color
|
||||||
replace-color.title=Replace-Invert-Color
|
replace-color.title=Replace-Invert-Color
|
||||||
replace-color.header=Replace-Invert Color PDF
|
replace-color.header=Replace-Invert Color PDF
|
||||||
@@ -961,6 +965,16 @@ multiTool.dragDropMessage=Page(s) Selected
|
|||||||
multiTool.undo=Undo
|
multiTool.undo=Undo
|
||||||
multiTool.redo=Redo
|
multiTool.redo=Redo
|
||||||
|
|
||||||
|
#decrypt
|
||||||
|
decrypt.passwordPrompt=This file is password-protected. Please enter the password:
|
||||||
|
decrypt.cancelled=Operation cancelled for PDF: {0}
|
||||||
|
decrypt.noPassword=No password provided for encrypted PDF: {0}
|
||||||
|
decrypt.invalidPassword=Please try again with the correct password.
|
||||||
|
decrypt.invalidPasswordHeader=Incorrect password or unsupported encryption for PDF: {0}
|
||||||
|
decrypt.unexpectedError=There was an error processing the file. Please try again.
|
||||||
|
decrypt.serverError=Server error while decrypting: {0}
|
||||||
|
decrypt.success=File decrypted successfully.
|
||||||
|
|
||||||
#multiTool-advert
|
#multiTool-advert
|
||||||
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
||||||
|
|
||||||
@@ -1052,6 +1066,7 @@ addPassword.submit=Mã hóa
|
|||||||
#watermark
|
#watermark
|
||||||
watermark.title=Thêm hình mờ
|
watermark.title=Thêm hình mờ
|
||||||
watermark.header=Thêm hình mờ
|
watermark.header=Thêm hình mờ
|
||||||
|
watermark.customColor=Màu văn bản tùy chỉnh
|
||||||
watermark.selectText.1=Chọn PDF để thêm hình mờ:
|
watermark.selectText.1=Chọn PDF để thêm hình mờ:
|
||||||
watermark.selectText.2=Văn bản hình mờ:
|
watermark.selectText.2=Văn bản hình mờ:
|
||||||
watermark.selectText.3=Cỡ chữ:
|
watermark.selectText.3=Cỡ chữ:
|
||||||
@@ -1263,6 +1278,11 @@ splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata
|
|||||||
splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs.
|
splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs.
|
||||||
splitByChapters.submit=Split PDF
|
splitByChapters.submit=Split PDF
|
||||||
|
|
||||||
|
#File Chooser
|
||||||
|
fileChooser.click=Click
|
||||||
|
fileChooser.or=or
|
||||||
|
fileChooser.dragAndDrop=Drag & Drop
|
||||||
|
fileChooser.hoveredDragAndDrop=Drag & Drop file(s) here
|
||||||
|
|
||||||
#release notes
|
#release notes
|
||||||
releases.footer=Releases
|
releases.footer=Releases
|
||||||
@@ -1270,3 +1290,38 @@ releases.title=Release Notes
|
|||||||
releases.header=Release Notes
|
releases.header=Release Notes
|
||||||
releases.current.version=Current Release
|
releases.current.version=Current Release
|
||||||
releases.note=Release notes are only available in English
|
releases.note=Release notes are only available in English
|
||||||
|
|
||||||
|
#Validate Signature
|
||||||
|
validateSignature.title=Validate PDF Signatures
|
||||||
|
validateSignature.header=Validate Digital Signatures
|
||||||
|
validateSignature.selectPDF=Select signed PDF file
|
||||||
|
validateSignature.submit=Validate Signatures
|
||||||
|
validateSignature.results=Validation Results
|
||||||
|
validateSignature.status=Status
|
||||||
|
validateSignature.signer=Signer
|
||||||
|
validateSignature.date=Date
|
||||||
|
validateSignature.reason=Reason
|
||||||
|
validateSignature.location=Location
|
||||||
|
validateSignature.noSignatures=No digital signatures found in this document
|
||||||
|
validateSignature.status.valid=Valid
|
||||||
|
validateSignature.status.invalid=Invalid
|
||||||
|
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
|
||||||
|
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
|
||||||
|
validateSignature.cert.expired=Certificate has expired
|
||||||
|
validateSignature.cert.revoked=Certificate has been revoked
|
||||||
|
validateSignature.signature.info=Signature Information
|
||||||
|
validateSignature.signature=Signature
|
||||||
|
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
|
||||||
|
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
|
||||||
|
validateSignature.cert.info=Certificate Details
|
||||||
|
validateSignature.cert.issuer=Issuer
|
||||||
|
validateSignature.cert.subject=Subject
|
||||||
|
validateSignature.cert.serialNumber=Serial Number
|
||||||
|
validateSignature.cert.validFrom=Valid From
|
||||||
|
validateSignature.cert.validUntil=Valid Until
|
||||||
|
validateSignature.cert.algorithm=Algorithm
|
||||||
|
validateSignature.cert.keySize=Key Size
|
||||||
|
validateSignature.cert.version=Version
|
||||||
|
validateSignature.cert.keyUsage=Key Usage
|
||||||
|
validateSignature.cert.selfSigned=Self-Signed
|
||||||
|
validateSignature.cert.bits=bits
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -512,6 +512,10 @@ home.splitPdfByChapters.title=依章節分割 PDF
|
|||||||
home.splitPdfByChapters.desc=根據 PDF 的章節結構將其分割成多個檔案。
|
home.splitPdfByChapters.desc=根據 PDF 的章節結構將其分割成多個檔案。
|
||||||
splitPdfByChapters.tags=分割,章節,書籤,整理
|
splitPdfByChapters.tags=分割,章節,書籤,整理
|
||||||
|
|
||||||
|
home.validateSignature.title=Validate PDF Signature
|
||||||
|
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
|
||||||
|
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
|
||||||
|
|
||||||
#replace-invert-color
|
#replace-invert-color
|
||||||
replace-color.title=取代-反轉顏色
|
replace-color.title=取代-反轉顏色
|
||||||
replace-color.header=取代-反轉 PDF 顏色
|
replace-color.header=取代-反轉 PDF 顏色
|
||||||
@@ -961,6 +965,16 @@ multiTool.dragDropMessage=Page(s) Selected
|
|||||||
multiTool.undo=Undo
|
multiTool.undo=Undo
|
||||||
multiTool.redo=Redo
|
multiTool.redo=Redo
|
||||||
|
|
||||||
|
#decrypt
|
||||||
|
decrypt.passwordPrompt=This file is password-protected. Please enter the password:
|
||||||
|
decrypt.cancelled=Operation cancelled for PDF: {0}
|
||||||
|
decrypt.noPassword=No password provided for encrypted PDF: {0}
|
||||||
|
decrypt.invalidPassword=Please try again with the correct password.
|
||||||
|
decrypt.invalidPasswordHeader=Incorrect password or unsupported encryption for PDF: {0}
|
||||||
|
decrypt.unexpectedError=There was an error processing the file. Please try again.
|
||||||
|
decrypt.serverError=Server error while decrypting: {0}
|
||||||
|
decrypt.success=File decrypted successfully.
|
||||||
|
|
||||||
#multiTool-advert
|
#multiTool-advert
|
||||||
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
||||||
|
|
||||||
@@ -1052,12 +1066,13 @@ addPassword.submit=加密
|
|||||||
#watermark
|
#watermark
|
||||||
watermark.title=新增浮水印
|
watermark.title=新增浮水印
|
||||||
watermark.header=新增浮水印
|
watermark.header=新增浮水印
|
||||||
|
watermark.customColor=自訂文字顏色
|
||||||
watermark.selectText.1=選擇要新增浮水印的 PDF:
|
watermark.selectText.1=選擇要新增浮水印的 PDF:
|
||||||
watermark.selectText.2=浮水印文字:
|
watermark.selectText.2=浮水印文字:
|
||||||
watermark.selectText.3=字型大小:
|
watermark.selectText.3=字型大小:
|
||||||
watermark.selectText.4=旋轉(0-360):
|
watermark.selectText.4=旋轉(0-360):
|
||||||
watermark.selectText.5=widthSpacer(每個浮水印之間的水平間距):
|
watermark.selectText.5=Width Spacer(每個浮水印之間的水平間距):
|
||||||
watermark.selectText.6=heightSpacer(每個浮水印之間的垂直間距):
|
watermark.selectText.6=Height Spacer(每個浮水印之間的垂直間距):
|
||||||
watermark.selectText.7=不透明度(0% - 100%):
|
watermark.selectText.7=不透明度(0% - 100%):
|
||||||
watermark.selectText.8=浮水印類型:
|
watermark.selectText.8=浮水印類型:
|
||||||
watermark.selectText.9=浮水印影像:
|
watermark.selectText.9=浮水印影像:
|
||||||
@@ -1263,6 +1278,11 @@ splitByChapters.desc.3=包含中繼資料:如果勾選,原始 PDF 的中繼
|
|||||||
splitByChapters.desc.4=允許重複:如果勾選,允許同一頁面上的多個書籤建立獨立的 PDF。
|
splitByChapters.desc.4=允許重複:如果勾選,允許同一頁面上的多個書籤建立獨立的 PDF。
|
||||||
splitByChapters.submit=分割 PDF
|
splitByChapters.submit=分割 PDF
|
||||||
|
|
||||||
|
#File Chooser
|
||||||
|
fileChooser.click=Click
|
||||||
|
fileChooser.or=or
|
||||||
|
fileChooser.dragAndDrop=Drag & Drop
|
||||||
|
fileChooser.hoveredDragAndDrop=Drag & Drop file(s) here
|
||||||
|
|
||||||
#release notes
|
#release notes
|
||||||
releases.footer=Releases
|
releases.footer=Releases
|
||||||
@@ -1270,3 +1290,38 @@ releases.title=Release Notes
|
|||||||
releases.header=Release Notes
|
releases.header=Release Notes
|
||||||
releases.current.version=Current Release
|
releases.current.version=Current Release
|
||||||
releases.note=Release notes are only available in English
|
releases.note=Release notes are only available in English
|
||||||
|
|
||||||
|
#Validate Signature
|
||||||
|
validateSignature.title=Validate PDF Signatures
|
||||||
|
validateSignature.header=Validate Digital Signatures
|
||||||
|
validateSignature.selectPDF=Select signed PDF file
|
||||||
|
validateSignature.submit=Validate Signatures
|
||||||
|
validateSignature.results=Validation Results
|
||||||
|
validateSignature.status=Status
|
||||||
|
validateSignature.signer=Signer
|
||||||
|
validateSignature.date=Date
|
||||||
|
validateSignature.reason=Reason
|
||||||
|
validateSignature.location=Location
|
||||||
|
validateSignature.noSignatures=No digital signatures found in this document
|
||||||
|
validateSignature.status.valid=Valid
|
||||||
|
validateSignature.status.invalid=Invalid
|
||||||
|
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
|
||||||
|
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
|
||||||
|
validateSignature.cert.expired=Certificate has expired
|
||||||
|
validateSignature.cert.revoked=Certificate has been revoked
|
||||||
|
validateSignature.signature.info=Signature Information
|
||||||
|
validateSignature.signature=Signature
|
||||||
|
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
|
||||||
|
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
|
||||||
|
validateSignature.cert.info=Certificate Details
|
||||||
|
validateSignature.cert.issuer=Issuer
|
||||||
|
validateSignature.cert.subject=Subject
|
||||||
|
validateSignature.cert.serialNumber=Serial Number
|
||||||
|
validateSignature.cert.validFrom=Valid From
|
||||||
|
validateSignature.cert.validUntil=Valid Until
|
||||||
|
validateSignature.cert.algorithm=Algorithm
|
||||||
|
validateSignature.cert.keySize=Key Size
|
||||||
|
validateSignature.cert.version=Version
|
||||||
|
validateSignature.cert.keyUsage=Key Usage
|
||||||
|
validateSignature.cert.selfSigned=Self-Signed
|
||||||
|
validateSignature.cert.bits=bits
|
||||||
|
|||||||
@@ -13,10 +13,10 @@
|
|||||||
|
|
||||||
security:
|
security:
|
||||||
enableLogin: false # set to 'true' to enable login
|
enableLogin: false # set to 'true' to enable login
|
||||||
csrfDisabled: true # set to 'true' to disable CSRF protection (not recommended for production)
|
csrfDisabled: false # set to 'true' to disable CSRF protection (not recommended for production)
|
||||||
loginAttemptCount: 5 # lock user account after 5 tries; when using e.g. Fail2Ban you can deactivate the function with -1
|
loginAttemptCount: 5 # lock user account after 5 tries; when using e.g. Fail2Ban you can deactivate the function with -1
|
||||||
loginResetTimeMinutes: 120 # lock account for 2 hours after x attempts
|
loginResetTimeMinutes: 120 # lock account for 2 hours after x attempts
|
||||||
loginMethod: all # 'all' (Login Username/Password and OAuth2[must be enabled and configured]), 'normal'(only Login with Username/Password) or 'oauth2'(only Login with OAuth2)
|
loginMethod: all # Accepts values like 'all' and 'normal'(only Login with Username/Password), 'oauth2'(only Login with OAuth2) or 'saml2'(only Login with SAML2)
|
||||||
initialLogin:
|
initialLogin:
|
||||||
username: '' # initial username for the first login
|
username: '' # initial username for the first login
|
||||||
password: '' # initial password for the first login
|
password: '' # initial password for the first login
|
||||||
@@ -42,14 +42,14 @@ security:
|
|||||||
issuer: '' # set to any provider that supports OpenID Connect Discovery (/.well-known/openid-configuration) endpoint
|
issuer: '' # set to any provider that supports OpenID Connect Discovery (/.well-known/openid-configuration) endpoint
|
||||||
clientId: '' # client ID from your provider
|
clientId: '' # client ID from your provider
|
||||||
clientSecret: '' # client secret from your provider
|
clientSecret: '' # client secret from your provider
|
||||||
autoCreateUser: false # set to 'true' to allow auto-creation of non-existing users
|
autoCreateUser: true # 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
|
blockRegistration: false # set to 'true' to deny login with SSO without prior registration by an admin
|
||||||
useAsUsername: email # default is 'email'; custom fields can be used as the username
|
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
|
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'
|
provider: google # set this to your OAuth provider's name, e.g., 'google' or 'keycloak'
|
||||||
saml2:
|
saml2:
|
||||||
enabled: false # currently in alpha, not recommended for use yet, enableAlphaFunctionality must be set to true
|
enabled: false # Only enabled for paid enterprise clients (enterpriseEdition.enabled must be true)
|
||||||
autoCreateUser: false # set to 'true' to allow auto-creation of non-existing users
|
autoCreateUser: true # 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
|
blockRegistration: false # set to 'true' to deny login with SSO without prior registration by an admin
|
||||||
registrationId: stirling
|
registrationId: stirling
|
||||||
idpMetadataUri: https://dev-XXXXXXXX.okta.com/app/externalKey/sso/saml/metadata
|
idpMetadataUri: https://dev-XXXXXXXX.okta.com/app/externalKey/sso/saml/metadata
|
||||||
@@ -102,6 +102,7 @@ metrics:
|
|||||||
AutomaticallyGenerated:
|
AutomaticallyGenerated:
|
||||||
key: example
|
key: example
|
||||||
UUID: example
|
UUID: example
|
||||||
|
appVersion: 0.35.0
|
||||||
|
|
||||||
processExecutor:
|
processExecutor:
|
||||||
sessionLimit: # Process executor instances limits
|
sessionLimit: # Process executor instances limits
|
||||||
|
|||||||
@@ -172,6 +172,13 @@
|
|||||||
"moduleLicense": "The Apache Software License, Version 2.0",
|
"moduleLicense": "The Apache Software License, Version 2.0",
|
||||||
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"moduleName": "com.google.code.gson:gson",
|
||||||
|
"moduleUrl": "https://github.com/google/gson",
|
||||||
|
"moduleVersion": "2.11.0",
|
||||||
|
"moduleLicense": "Apache-2.0",
|
||||||
|
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "com.google.errorprone:error_prone_annotations",
|
"moduleName": "com.google.errorprone:error_prone_annotations",
|
||||||
"moduleUrl": "https://errorprone.info/error_prone_annotations",
|
"moduleUrl": "https://errorprone.info/error_prone_annotations",
|
||||||
@@ -591,6 +598,34 @@
|
|||||||
"moduleLicense": "GPL2 w/ CPE",
|
"moduleLicense": "GPL2 w/ CPE",
|
||||||
"moduleLicenseUrl": "https://oss.oracle.com/licenses/CDDL+GPL-1.1"
|
"moduleLicenseUrl": "https://oss.oracle.com/licenses/CDDL+GPL-1.1"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"moduleName": "me.friwi:gluegen-rt",
|
||||||
|
"moduleUrl": "http://jogamp.org/gluegen/www/",
|
||||||
|
"moduleVersion": "v2.4.0-rc-20210111",
|
||||||
|
"moduleLicense": "BSD-4 License",
|
||||||
|
"moduleLicenseUrl": "http://www.spdx.org/licenses/BSD-4-Clause"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"moduleName": "me.friwi:jcef-api",
|
||||||
|
"moduleUrl": "https://bitbucket.org/chromiumembedded/java-cef/",
|
||||||
|
"moduleVersion": "jcef-99c2f7a+cef-127.3.1+g6cbb30e+chromium-127.0.6533.100",
|
||||||
|
"moduleLicense": "BSD License",
|
||||||
|
"moduleLicenseUrl": "https://bitbucket.org/chromiumembedded/java-cef/src/master/LICENSE.txt"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"moduleName": "me.friwi:jcefmaven",
|
||||||
|
"moduleUrl": "https://github.com/jcefmaven/jcefmaven/",
|
||||||
|
"moduleVersion": "127.3.1",
|
||||||
|
"moduleLicense": "Apache-2.0 License",
|
||||||
|
"moduleLicenseUrl": "https://github.com/jcefmaven/jcefmaven/blob/master/LICENSE"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"moduleName": "me.friwi:jogl-all",
|
||||||
|
"moduleUrl": "http://jogamp.org/jogl/www/",
|
||||||
|
"moduleVersion": "v2.4.0-rc-20210111",
|
||||||
|
"moduleLicense": "Ubuntu Font Licence 1.0",
|
||||||
|
"moduleLicenseUrl": "http://font.ubuntu.com/ufl/ubuntu-font-licence-1.0.txt"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "net.bytebuddy:byte-buddy",
|
"moduleName": "net.bytebuddy:byte-buddy",
|
||||||
"moduleVersion": "1.15.10",
|
"moduleVersion": "1.15.10",
|
||||||
@@ -631,6 +666,13 @@
|
|||||||
"moduleLicense": "Apache License, Version 2.0",
|
"moduleLicense": "Apache License, Version 2.0",
|
||||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt"
|
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"moduleName": "org.apache.commons:commons-compress",
|
||||||
|
"moduleUrl": "https://commons.apache.org/proper/commons-compress/",
|
||||||
|
"moduleVersion": "1.21",
|
||||||
|
"moduleLicense": "Apache License, Version 2.0",
|
||||||
|
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "org.apache.commons:commons-csv",
|
"moduleName": "org.apache.commons:commons-csv",
|
||||||
"moduleUrl": "https://commons.apache.org/proper/commons-csv/",
|
"moduleUrl": "https://commons.apache.org/proper/commons-csv/",
|
||||||
@@ -1079,6 +1121,30 @@
|
|||||||
"moduleLicense": "Eclipse Public License, Version 2.0",
|
"moduleLicense": "Eclipse Public License, Version 2.0",
|
||||||
"moduleLicenseUrl": "https://github.com/locationtech/jts/blob/master/LICENSE_EPLv2.txt"
|
"moduleLicenseUrl": "https://github.com/locationtech/jts/blob/master/LICENSE_EPLv2.txt"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"moduleName": "org.openjfx:javafx-base",
|
||||||
|
"moduleVersion": "21",
|
||||||
|
"moduleLicense": "GPLv2+CE",
|
||||||
|
"moduleLicenseUrl": "https://openjdk.java.net/legal/gplv2+ce.html"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"moduleName": "org.openjfx:javafx-controls",
|
||||||
|
"moduleVersion": "21",
|
||||||
|
"moduleLicense": "GPLv2+CE",
|
||||||
|
"moduleLicenseUrl": "https://openjdk.java.net/legal/gplv2+ce.html"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"moduleName": "org.openjfx:javafx-graphics",
|
||||||
|
"moduleVersion": "21",
|
||||||
|
"moduleLicense": "GPLv2+CE",
|
||||||
|
"moduleLicenseUrl": "https://openjdk.java.net/legal/gplv2+ce.html"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"moduleName": "org.openjfx:javafx-swing",
|
||||||
|
"moduleVersion": "21",
|
||||||
|
"moduleLicense": "GPLv2+CE",
|
||||||
|
"moduleLicenseUrl": "https://openjdk.java.net/legal/gplv2+ce.html"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "org.opensaml:opensaml-core",
|
"moduleName": "org.opensaml:opensaml-core",
|
||||||
"moduleVersion": "4.3.2",
|
"moduleVersion": "4.3.2",
|
||||||
@@ -1386,6 +1452,13 @@
|
|||||||
"moduleLicense": "Apache License, Version 2.0",
|
"moduleLicense": "Apache License, Version 2.0",
|
||||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"moduleName": "org.springframework.session:spring-session-core",
|
||||||
|
"moduleUrl": "https://spring.io/projects/spring-session",
|
||||||
|
"moduleVersion": "3.4.0",
|
||||||
|
"moduleLicense": "Apache License, Version 2.0",
|
||||||
|
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "org.springframework:spring-aop",
|
"moduleName": "org.springframework:spring-aop",
|
||||||
"moduleUrl": "https://github.com/spring-projects/spring-framework",
|
"moduleUrl": "https://github.com/spring-projects/spring-framework",
|
||||||
@@ -1472,7 +1545,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "org.thymeleaf.extras:thymeleaf-extras-springsecurity5",
|
"moduleName": "org.thymeleaf.extras:thymeleaf-extras-springsecurity5",
|
||||||
"moduleVersion": "3.1.2.RELEASE",
|
"moduleVersion": "3.1.3.RELEASE",
|
||||||
"moduleLicense": "The Apache Software License, Version 2.0",
|
"moduleLicense": "The Apache Software License, Version 2.0",
|
||||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt"
|
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||||
},
|
},
|
||||||
@@ -1484,7 +1557,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "org.thymeleaf:thymeleaf-spring5",
|
"moduleName": "org.thymeleaf:thymeleaf-spring5",
|
||||||
"moduleVersion": "3.1.2.RELEASE",
|
"moduleVersion": "3.1.3.RELEASE",
|
||||||
"moduleLicense": "The Apache Software License, Version 2.0",
|
"moduleLicense": "The Apache Software License, Version 2.0",
|
||||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt"
|
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,10 +1,221 @@
|
|||||||
|
.custom-file-chooser {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
min-height: 55px;
|
||||||
|
border-radius: 1rem;
|
||||||
|
--selected-files-display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-container {
|
||||||
|
position: relative;
|
||||||
|
border-radius: 1rem;
|
||||||
|
border: 1px dashed rgb(105, 116, 134);
|
||||||
|
|
||||||
|
column-gap: 7px;
|
||||||
|
row-gap: 7px;
|
||||||
|
height: 150px;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
--overlay-display: none;
|
||||||
|
transition: background-color 0.5s linear;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-container:hover {
|
||||||
|
outline: none;
|
||||||
|
border: none;
|
||||||
|
background-color: var(--md-sys-color-surface-container-low);
|
||||||
|
|
||||||
|
-webkit-transition: box-shadow 1s ease, background-color 2s linear;
|
||||||
|
-moz-transition: box-shadow 1s ease, background-color 2s linear;
|
||||||
|
-o-transition: box-shadow 1s ease, background-color 2s linear;
|
||||||
|
-ms-transition: box-shadow 1s ease, background-color 2s linear;
|
||||||
|
transition: box-shadow 1s ease, background-color 2s linear;
|
||||||
|
|
||||||
|
box-shadow: 0 0 10px rgb(105, 116, 134);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-container * {
|
||||||
|
user-select: none;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.input-container::before {
|
||||||
|
display: var(--overlay-display);
|
||||||
|
position: absolute;
|
||||||
|
|
||||||
|
content: '';
|
||||||
|
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
background-color: var(--md-sys-color-surface);
|
||||||
|
z-index: 1;
|
||||||
|
|
||||||
|
white-space: pre;
|
||||||
|
border-radius: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-container::after {
|
||||||
|
display: var(--overlay-display);
|
||||||
|
position: absolute;
|
||||||
|
|
||||||
|
content: attr(data-text);
|
||||||
|
font-size: 0.9rem;
|
||||||
|
font-weight: 550;
|
||||||
|
color: var(--md-sys-color-on-surface);
|
||||||
|
|
||||||
|
background-color: transparent;
|
||||||
|
|
||||||
|
min-width: 150px;
|
||||||
|
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
|
||||||
|
transform: translateX(-50%) translateY(-50%);
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-container input[type="file"] {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-container div:nth-of-type(2) {
|
||||||
|
color: var(--md-sys-color-on-surface);
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-container div:nth-of-type(1), .input-container div:nth-of-type(3) {
|
||||||
|
color: var(--md-sys-color-on-surface);
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-input-btn {
|
||||||
|
display: inline-block;
|
||||||
|
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
padding: 6px 12px;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
color: #212529;
|
||||||
|
font-size: 1rem;
|
||||||
|
border-radius: 3rem;
|
||||||
|
|
||||||
|
background-color: #DDE0E3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.small-file-container {
|
||||||
|
padding-top: 1px;
|
||||||
|
position: relative;
|
||||||
|
row-gap: 1px;
|
||||||
|
height: 60px;
|
||||||
|
width: 60px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-icon {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
height: 30px;
|
||||||
|
width: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-icon * {
|
||||||
|
height: inherit;
|
||||||
|
width: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-info {
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-info > div:nth-child(1) {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
color: var(--md-sys-color-on-surface);
|
||||||
|
|
||||||
|
max-width: 60px;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-info > div:nth-child(2) {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
color: grey;
|
||||||
|
|
||||||
|
max-width: 60px;
|
||||||
|
font-size: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.remove-selected-file {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
position: absolute;
|
||||||
|
height: 15px;
|
||||||
|
width: 15px;
|
||||||
|
|
||||||
|
right: 10px;
|
||||||
|
top: -5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.remove-selected-file * {
|
||||||
|
overflow: hidden;
|
||||||
|
height: inherit;
|
||||||
|
width: inherit;
|
||||||
|
z-index: 3;
|
||||||
|
pointer-events: none;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.remove-selected-file:after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
|
||||||
|
left: 1;
|
||||||
|
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
border-radius: 50%;
|
||||||
|
|
||||||
|
background-color: white;
|
||||||
|
z-index: 2;
|
||||||
|
|
||||||
|
user-select: none;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.remove-selected-file:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
.custom-file-label {
|
.custom-file-label {
|
||||||
padding-right: 90px;
|
padding-right: 90px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.selected-files {
|
.selected-files {
|
||||||
margin-top: 10px;
|
display: var(--selected-files-display);
|
||||||
max-height: 150px;
|
padding-left: 5px;
|
||||||
overflow-y: auto;
|
padding-right: 3px;
|
||||||
|
padding-top: 15px;
|
||||||
|
padding-bottom: 15px;
|
||||||
|
|
||||||
|
flex: 1;
|
||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
|
|
||||||
|
row-gap: 12px;
|
||||||
|
column-gap: 5px;
|
||||||
|
|
||||||
|
border-radius: 1rem;
|
||||||
|
border: 1px solid rgb(105, 116, 134, 0.5);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,6 +65,7 @@
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
margin: -20px;
|
margin: -20px;
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
|
box-sizing:content-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
.feature-group-container.animated-group {
|
.feature-group-container.animated-group {
|
||||||
|
|||||||
BIN
src/main/resources/static/favicon.icns
Normal file
BIN
src/main/resources/static/favicon.icns
Normal file
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user