Merge branch 'Stirling-Tools:main' into main
This commit is contained in:
commit
caa5525ddd
89 changed files with 2622 additions and 740 deletions
14
.github/workflows/build.yml
vendored
14
.github/workflows/build.yml
vendored
|
@ -26,15 +26,17 @@ jobs:
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Set up JDK 17
|
- name: Set up JDK 17
|
||||||
uses: actions/setup-java@v3
|
uses: actions/setup-java@v4
|
||||||
with:
|
with:
|
||||||
java-version: '17'
|
java-version: "17"
|
||||||
distribution: 'temurin'
|
distribution: "temurin"
|
||||||
|
|
||||||
- uses: gradle/gradle-build-action@v2.4.2
|
- uses: gradle/actions/setup-gradle@v3
|
||||||
with:
|
with:
|
||||||
gradle-version: 7.6
|
gradle-version: 7.6
|
||||||
arguments: build --no-build-cache
|
|
||||||
|
- name: Build with Gradle
|
||||||
|
run: ./gradlew build --no-build-cache
|
||||||
|
|
15
.github/workflows/licenses-update.yml
vendored
15
.github/workflows/licenses-update.yml
vendored
|
@ -5,7 +5,7 @@ on:
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
paths:
|
paths:
|
||||||
- 'build.gradle'
|
- "build.gradle"
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: write
|
||||||
|
@ -17,13 +17,15 @@ jobs:
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Check out code
|
- name: Check out code
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Set up JDK 17
|
- name: Set up JDK 17
|
||||||
uses: actions/setup-java@v3
|
uses: actions/setup-java@v4
|
||||||
with:
|
with:
|
||||||
java-version: '17'
|
java-version: "17"
|
||||||
distribution: 'adopt'
|
distribution: "adopt"
|
||||||
|
|
||||||
|
- uses: gradle/actions/setup-gradle@v3
|
||||||
|
|
||||||
- name: Run Gradle Command
|
- name: Run Gradle Command
|
||||||
run: ./gradlew clean generateLicenseReport
|
run: ./gradlew clean generateLicenseReport
|
||||||
|
@ -44,7 +46,7 @@ jobs:
|
||||||
|
|
||||||
- name: Create Pull Request
|
- name: Create Pull Request
|
||||||
if: env.CHANGES_DETECTED == 'true'
|
if: env.CHANGES_DETECTED == 'true'
|
||||||
uses: peter-evans/create-pull-request@v3
|
uses: peter-evans/create-pull-request@v6
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
commit-message: "Update 3rd Party Licenses"
|
commit-message: "Update 3rd Party Licenses"
|
||||||
|
@ -58,4 +60,3 @@ jobs:
|
||||||
[1]: https://github.com/peter-evans/create-pull-request
|
[1]: https://github.com/peter-evans/create-pull-request
|
||||||
draft: false
|
draft: false
|
||||||
delete-branch: true
|
delete-branch: true
|
||||||
|
|
||||||
|
|
62
.github/workflows/push-docker.yml
vendored
62
.github/workflows/push-docker.yml
vendored
|
@ -14,50 +14,54 @@ jobs:
|
||||||
push:
|
push:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/checkout@v3.5.2
|
|
||||||
|
|
||||||
- name: Set up JDK 17
|
- name: Set up JDK 17
|
||||||
uses: actions/setup-java@v3.11.0
|
uses: actions/setup-java@v4
|
||||||
with:
|
with:
|
||||||
java-version: '17'
|
java-version: "17"
|
||||||
distribution: 'temurin'
|
distribution: "temurin"
|
||||||
|
|
||||||
|
- uses: gradle/actions/setup-gradle@v3
|
||||||
- uses: gradle/gradle-build-action@v2.4.2
|
|
||||||
env:
|
|
||||||
DOCKER_ENABLE_SECURITY: false
|
|
||||||
with:
|
with:
|
||||||
gradle-version: 7.6
|
gradle-version: 7.6
|
||||||
arguments: clean build
|
|
||||||
|
|
||||||
- name: Make Gradle wrapper executable
|
- name: Run Gradle Command
|
||||||
run: chmod +x gradlew
|
run: ./gradlew clean build
|
||||||
|
env:
|
||||||
|
DOCKER_ENABLE_SECURITY: false
|
||||||
|
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
id: buildx
|
||||||
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
- name: Get version number
|
- name: Get version number
|
||||||
id: versionNumber
|
id: versionNumber
|
||||||
run: echo "::set-output name=versionNumber::$(./gradlew printVersion --quiet | tail -1)"
|
run: echo "versionNumber=$(./gradlew printVersion --quiet | tail -1)" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Login to Docker Hub
|
- name: Login to Docker Hub
|
||||||
uses: docker/login-action@v2.1.0
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
username: ${{ secrets.DOCKER_HUB_USERNAME }}
|
username: ${{ secrets.DOCKER_HUB_USERNAME }}
|
||||||
password: ${{ secrets.DOCKER_HUB_API }}
|
password: ${{ secrets.DOCKER_HUB_API }}
|
||||||
|
|
||||||
- name: Login to GitHub Container Registry
|
- name: Login to GitHub Container Registry
|
||||||
uses: docker/login-action@v2.1.0
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
registry: ghcr.io
|
registry: ghcr.io
|
||||||
username: ${{ github.actor }}
|
username: ${{ github.actor }}
|
||||||
password: ${{ github.token }}
|
password: ${{ github.token }}
|
||||||
|
|
||||||
|
- name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@v3
|
||||||
|
|
||||||
- name: Convert repository owner to lowercase
|
- name: Convert repository owner to lowercase
|
||||||
id: repoowner
|
id: repoowner
|
||||||
run: echo "::set-output name=lowercase::$(echo ${{ github.repository_owner }} | awk '{print tolower($0)}')"
|
run: echo "lowercase=$(echo ${{ github.repository_owner }} | awk '{print tolower($0)}')" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Generate tags
|
- name: Generate tags
|
||||||
id: meta
|
id: meta
|
||||||
uses: docker/metadata-action@v4.4.0
|
uses: docker/metadata-action@v5
|
||||||
with:
|
with:
|
||||||
images: |
|
images: |
|
||||||
${{ secrets.DOCKER_HUB_USERNAME }}/s-pdf
|
${{ secrets.DOCKER_HUB_USERNAME }}/s-pdf
|
||||||
|
@ -67,31 +71,23 @@ jobs:
|
||||||
type=raw,value=latest,enable=${{ github.ref == 'refs/heads/master' }}
|
type=raw,value=latest,enable=${{ github.ref == 'refs/heads/master' }}
|
||||||
type=raw,value=alpha,enable=${{ github.ref == 'refs/heads/main' }}
|
type=raw,value=alpha,enable=${{ github.ref == 'refs/heads/main' }}
|
||||||
|
|
||||||
- name: Set up QEMU
|
|
||||||
uses: docker/setup-qemu-action@v2.1.0
|
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v2.5.0
|
|
||||||
|
|
||||||
- name: Build and push main Dockerfile
|
- name: Build and push main Dockerfile
|
||||||
uses: docker/build-push-action@v4.0.0
|
uses: docker/build-push-action@v5
|
||||||
with:
|
with:
|
||||||
|
builder: ${{ steps.buildx.outputs.name }}
|
||||||
context: .
|
context: .
|
||||||
dockerfile: ./Dockerfile
|
file: ./Dockerfile
|
||||||
push: true
|
push: true
|
||||||
cache-from: type=gha
|
cache-from: type=gha
|
||||||
cache-to: type=gha,mode=max
|
cache-to: type=gha,mode=max
|
||||||
tags: ${{ steps.meta.outputs.tags }}
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
labels: ${{ steps.meta.outputs.labels }}
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
build-args:
|
build-args: VERSION_TAG=${{ steps.versionNumber.outputs.versionNumber }}
|
||||||
VERSION_TAG=${{ steps.versionNumber.outputs.versionNumber }}
|
|
||||||
platforms: linux/amd64,linux/arm64/v8
|
platforms: linux/amd64,linux/arm64/v8
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
- name: Generate tags ultra-lite
|
- name: Generate tags ultra-lite
|
||||||
id: meta2
|
id: meta2
|
||||||
uses: docker/metadata-action@v4.4.0
|
uses: docker/metadata-action@v5
|
||||||
if: github.ref != 'refs/heads/main'
|
if: github.ref != 'refs/heads/main'
|
||||||
with:
|
with:
|
||||||
images: |
|
images: |
|
||||||
|
@ -101,9 +97,8 @@ jobs:
|
||||||
type=raw,value=${{ steps.versionNumber.outputs.versionNumber }}-ultra-lite,enable=${{ github.ref == 'refs/heads/master' }}
|
type=raw,value=${{ steps.versionNumber.outputs.versionNumber }}-ultra-lite,enable=${{ github.ref == 'refs/heads/master' }}
|
||||||
type=raw,value=latest-ultra-lite,enable=${{ github.ref == 'refs/heads/master' }}
|
type=raw,value=latest-ultra-lite,enable=${{ github.ref == 'refs/heads/master' }}
|
||||||
|
|
||||||
|
|
||||||
- name: Build and push Dockerfile-ultra-lite
|
- name: Build and push Dockerfile-ultra-lite
|
||||||
uses: docker/build-push-action@v4.0.0
|
uses: docker/build-push-action@v5
|
||||||
if: github.ref != 'refs/heads/main'
|
if: github.ref != 'refs/heads/main'
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
|
@ -113,6 +108,5 @@ jobs:
|
||||||
cache-to: type=gha,mode=max
|
cache-to: type=gha,mode=max
|
||||||
tags: ${{ steps.meta2.outputs.tags }}
|
tags: ${{ steps.meta2.outputs.tags }}
|
||||||
labels: ${{ steps.meta2.outputs.labels }}
|
labels: ${{ steps.meta2.outputs.labels }}
|
||||||
build-args:
|
build-args: VERSION_TAG=${{ steps.versionNumber.outputs.versionNumber }}
|
||||||
VERSION_TAG=${{ steps.versionNumber.outputs.versionNumber }}
|
|
||||||
platforms: linux/amd64,linux/arm64/v8
|
platforms: linux/amd64,linux/arm64/v8
|
66
.github/workflows/releaseArtifacts.yml
vendored
66
.github/workflows/releaseArtifacts.yml
vendored
|
@ -1,6 +1,7 @@
|
||||||
name: Release Artifacts
|
name: Release Artifacts
|
||||||
|
|
||||||
on:
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
release:
|
release:
|
||||||
types: [created]
|
types: [created]
|
||||||
permissions:
|
permissions:
|
||||||
|
@ -14,44 +15,61 @@ jobs:
|
||||||
enable_security: [true, false]
|
enable_security: [true, false]
|
||||||
include:
|
include:
|
||||||
- enable_security: true
|
- enable_security: true
|
||||||
file_suffix: '-with-login'
|
file_suffix: "-with-login"
|
||||||
- enable_security: false
|
- enable_security: false
|
||||||
file_suffix: ''
|
file_suffix: ""
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3.5.2
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Set up JDK 17
|
- name: Set up JDK 17
|
||||||
uses: actions/setup-java@v3.11.0
|
uses: actions/setup-java@v4
|
||||||
with:
|
with:
|
||||||
java-version: '17'
|
java-version: "17"
|
||||||
distribution: 'temurin'
|
distribution: "temurin"
|
||||||
|
|
||||||
- name: Grant execute permission for gradlew
|
- uses: gradle/actions/setup-gradle@v3
|
||||||
run: chmod +x gradlew
|
with:
|
||||||
|
gradle-version: 7.6
|
||||||
|
|
||||||
- name: Generate jar (With Security=${{ matrix.enable_security }})
|
- name: Generate jar (With Security=${{ matrix.enable_security }})
|
||||||
run: ./gradlew clean createExe
|
run: ./gradlew clean createExe
|
||||||
env:
|
env:
|
||||||
DOCKER_ENABLE_SECURITY: ${{ matrix.enable_security }}
|
DOCKER_ENABLE_SECURITY: ${{ matrix.enable_security }}
|
||||||
|
|
||||||
- name: Upload binaries to release
|
|
||||||
uses: svenstaro/upload-release-action@v2
|
|
||||||
with:
|
|
||||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
file: ./build/launch4j/Stirling-PDF.exe
|
|
||||||
asset_name: Stirling-PDF${{ matrix.file_suffix }}.exe
|
|
||||||
tag: ${{ github.ref }}
|
|
||||||
overwrite: true
|
|
||||||
|
|
||||||
- name: Get version number
|
- name: Get version number
|
||||||
id: versionNumber
|
id: versionNumber
|
||||||
run: echo "::set-output name=versionNumber::$(./gradlew printVersion --quiet | tail -1)"
|
run: echo "versionNumber=$(./gradlew printVersion --quiet | tail -1)" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: Rename binarie
|
||||||
|
if: matrix.file_suffix != ''
|
||||||
|
run: cp ./build/launch4j/Stirling-PDF.exe ./build/launch4j/Stirling-PDF${{ matrix.file_suffix }}.exe
|
||||||
|
|
||||||
|
- name: Upload Assets binarie
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
path: ./build/launch4j/Stirling-PDF${{ matrix.file_suffix }}.exe
|
||||||
|
name: Stirling-PDF${{ matrix.file_suffix }}.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${{ matrix.file_suffix }}.exe
|
||||||
|
|
||||||
|
- name: Rename jar binaries
|
||||||
|
run: cp ./build/libs/Stirling-PDF-${{ steps.versionNumber.outputs.versionNumber }}.jar ./build/libs/Stirling-PDF${{ matrix.file_suffix }}.jar
|
||||||
|
|
||||||
|
- name: Upload Assets jar binaries
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
path: ./build/libs/Stirling-PDF${{ matrix.file_suffix }}.jar
|
||||||
|
name: Stirling-PDF${{ matrix.file_suffix }}.jar
|
||||||
|
overwrite: true
|
||||||
|
retention-days: 1
|
||||||
|
if-no-files-found: error
|
||||||
|
|
||||||
- name: Upload jar binaries to release
|
- name: Upload jar binaries to release
|
||||||
uses: svenstaro/upload-release-action@v2
|
uses: softprops/action-gh-release@v2
|
||||||
with:
|
with:
|
||||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
files: ./build/libs/Stirling-PDF${{ matrix.file_suffix }}.jar
|
||||||
file: ./build/libs/Stirling-PDF-${{ steps.versionNumber.outputs.versionNumber }}.jar
|
|
||||||
asset_name: Stirling-PDF${{ matrix.file_suffix }}.jar
|
|
||||||
tag: ${{ github.ref }}
|
|
||||||
overwrite: true
|
|
||||||
|
|
17
.github/workflows/swagger.yml
vendored
17
.github/workflows/swagger.yml
vendored
|
@ -8,20 +8,17 @@ on:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
push:
|
push:
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/checkout@v3.5.2
|
|
||||||
|
|
||||||
- name: Set up JDK 17
|
- name: Set up JDK 17
|
||||||
uses: actions/setup-java@v3.11.0
|
uses: actions/setup-java@v4
|
||||||
with:
|
with:
|
||||||
java-version: '17'
|
java-version: "17"
|
||||||
distribution: 'temurin'
|
distribution: "temurin"
|
||||||
|
|
||||||
- name: Grant execute permission for gradlew
|
- uses: gradle/actions/setup-gradle@v3
|
||||||
run: chmod +x gradlew
|
|
||||||
|
|
||||||
- name: Generate Swagger documentation
|
- name: Generate Swagger documentation
|
||||||
run: ./gradlew generateOpenApiDocs
|
run: ./gradlew generateOpenApiDocs
|
||||||
|
@ -31,6 +28,10 @@ jobs:
|
||||||
env:
|
env:
|
||||||
SWAGGERHUB_API_KEY: ${{ secrets.SWAGGERHUB_API_KEY }}
|
SWAGGERHUB_API_KEY: ${{ secrets.SWAGGERHUB_API_KEY }}
|
||||||
|
|
||||||
|
- name: Get version number
|
||||||
|
id: versionNumber
|
||||||
|
run: echo "versionNumber=$(./gradlew printVersion --quiet | tail -1)" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Set API version as published and default on SwaggerHub
|
- name: Set API version as published and default on SwaggerHub
|
||||||
run: |
|
run: |
|
||||||
curl -X PUT -H "Authorization: ${SWAGGERHUB_API_KEY}" "https://api.swaggerhub.com/apis/Frooodle/Stirling-PDF/${{ steps.versionNumber.outputs.versionNumber }}/settings/lifecycle" -H "accept: application/json" -H "Content-Type: application/json" -d "{\"published\":true,\"default\":true}"
|
curl -X PUT -H "Authorization: ${SWAGGERHUB_API_KEY}" "https://api.swaggerhub.com/apis/Frooodle/Stirling-PDF/${{ steps.versionNumber.outputs.versionNumber }}/settings/lifecycle" -H "accept: application/json" -H "Content-Type: application/json" -d "{\"published\":true,\"default\":true}"
|
||||||
|
|
3
.github/workflows/sync_files.yml
vendored
3
.github/workflows/sync_files.yml
vendored
|
@ -7,6 +7,7 @@ on:
|
||||||
paths:
|
paths:
|
||||||
- "build.gradle"
|
- "build.gradle"
|
||||||
- "src/main/resources/messages_*.properties"
|
- "src/main/resources/messages_*.properties"
|
||||||
|
- "scripts/translation_status.toml"
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: write
|
||||||
|
@ -58,6 +59,8 @@ jobs:
|
||||||
uses: actions/setup-python@v5.1.0
|
uses: actions/setup-python@v5.1.0
|
||||||
with:
|
with:
|
||||||
python-version: "3.x"
|
python-version: "3.x"
|
||||||
|
- name: Install dependencies
|
||||||
|
run: pip install tomlkit
|
||||||
- name: Sync README
|
- name: Sync README
|
||||||
run: python scripts/counter_translation.py
|
run: python scripts/counter_translation.py
|
||||||
- name: Set up git config
|
- name: Set up git config
|
||||||
|
|
44
.github/workflows/test.yml
vendored
44
.github/workflows/test.yml
vendored
|
@ -3,12 +3,12 @@ name: Docker Compose Tests
|
||||||
on:
|
on:
|
||||||
pull_request:
|
pull_request:
|
||||||
paths:
|
paths:
|
||||||
- 'src/**'
|
- "src/**"
|
||||||
- '**.gradle'
|
- "**.gradle"
|
||||||
- '!src/main/java/resources/messages*'
|
- "!src/main/java/resources/messages*"
|
||||||
- 'exampleYmlFiles/**'
|
- "exampleYmlFiles/**"
|
||||||
- 'Dockerfile'
|
- "Dockerfile"
|
||||||
- 'Dockerfile**'
|
- "Dockerfile**"
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
test:
|
||||||
|
@ -16,39 +16,21 @@ jobs:
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout Repository
|
- name: Checkout Repository
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Set up Java 17
|
- name: Set up Java 17
|
||||||
uses: actions/setup-java@v2
|
uses: actions/setup-java@v4
|
||||||
with:
|
with:
|
||||||
java-version: '17'
|
java-version: "17"
|
||||||
distribution: 'adopt'
|
distribution: "adopt"
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v1
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
- name: Run Docker Compose Tests
|
|
||||||
run: |
|
|
||||||
chmod +x ./gradlew
|
|
||||||
|
|
||||||
- name: Get version number
|
|
||||||
id: versionNumber
|
|
||||||
run: echo "::set-output name=versionNumber::$(./gradlew printVersion --quiet | tail -1)"
|
|
||||||
|
|
||||||
|
|
||||||
- name: Cache Docker layers
|
|
||||||
uses: actions/cache@v2
|
|
||||||
with:
|
|
||||||
path: /tmp/.buildx-cache
|
|
||||||
key: ${{ runner.os }}-buildx-${{ steps.versionNumber.outputs.versionNumber }}
|
|
||||||
restore-keys: |
|
|
||||||
${{ runner.os }}-buildx-
|
|
||||||
|
|
||||||
- name: Install Docker Compose
|
- name: Install Docker Compose
|
||||||
run: |
|
run: |
|
||||||
sudo curl -L "https://github.com/docker/compose/releases/download/v2.6.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
|
sudo curl -SL "https://github.com/docker/compose/releases/download/v2.26.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
|
||||||
sudo chmod +x /usr/local/bin/docker-compose
|
# sudo chmod +x /usr/local/bin/docker-compose
|
||||||
|
|
||||||
|
|
||||||
- name: Run Docker Compose Tests
|
- name: Run Docker Compose Tests
|
||||||
run: |
|
run: |
|
||||||
|
|
|
@ -27,6 +27,10 @@ Please make sure your Pull Request adheres to the following guidelines:
|
||||||
|
|
||||||
If you would like to add or modify a translation, please see [How to add new languages to Stirling-PDF](HowToAddNewLanguage.md). Also, please create a Pull Request so others can use it!
|
If you would like to add or modify a translation, please see [How to add new languages to Stirling-PDF](HowToAddNewLanguage.md). Also, please create a Pull Request so others can use it!
|
||||||
|
|
||||||
|
## Docs
|
||||||
|
|
||||||
|
Documentation for Stirling-PDF is handled in a seperate repository. Please see [Docs repository](https://github.com/Stirling-Tools/Stirling-Tools.github.io) or use "edit this page"-button at the bottom of each page at [https://stirlingtools.com/docs/](https://stirlingtools.com/docs/).
|
||||||
|
|
||||||
## Fixing Bugs or Adding a New Feature
|
## Fixing Bugs or Adding a New Feature
|
||||||
|
|
||||||
First, make sure you've read the section [Pull Requests](#pull-requests).
|
First, make sure you've read the section [Pull Requests](#pull-requests).
|
||||||
|
|
11
Dockerfile
11
Dockerfile
|
@ -4,8 +4,8 @@ FROM alpine:20240329
|
||||||
# Copy necessary files
|
# Copy necessary files
|
||||||
COPY scripts /scripts
|
COPY scripts /scripts
|
||||||
COPY pipeline /pipeline
|
COPY pipeline /pipeline
|
||||||
COPY src/main/resources/static/fonts/*.ttf /usr/share/fonts/opentype/noto
|
COPY src/main/resources/static/fonts/*.ttf /usr/share/fonts/opentype/noto/
|
||||||
COPY src/main/resources/static/fonts/*.otf /usr/share/fonts/opentype/noto
|
COPY src/main/resources/static/fonts/*.otf /usr/share/fonts/opentype/noto/
|
||||||
COPY build/libs/*.jar app.jar
|
COPY build/libs/*.jar app.jar
|
||||||
|
|
||||||
ARG VERSION_TAG
|
ARG VERSION_TAG
|
||||||
|
@ -25,15 +25,17 @@ ENV DOCKER_ENABLE_SECURITY=false \
|
||||||
RUN echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/main" | tee -a /etc/apk/repositories && \
|
RUN echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/main" | tee -a /etc/apk/repositories && \
|
||||||
echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/community" | tee -a /etc/apk/repositories && \
|
echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/community" | tee -a /etc/apk/repositories && \
|
||||||
echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/testing" | tee -a /etc/apk/repositories && \
|
echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/testing" | tee -a /etc/apk/repositories && \
|
||||||
|
apk update && \
|
||||||
apk add --no-cache \
|
apk add --no-cache \
|
||||||
ca-certificates \
|
ca-certificates \
|
||||||
tzdata \
|
tzdata \
|
||||||
tini \
|
tini \
|
||||||
|
openssl \
|
||||||
|
openssl-dev \
|
||||||
bash \
|
bash \
|
||||||
curl \
|
curl \
|
||||||
openjdk17-jre \
|
openjdk17-jre \
|
||||||
su-exec \
|
su-exec \
|
||||||
font-noto-cjk \
|
|
||||||
shadow \
|
shadow \
|
||||||
# Doc conversion
|
# Doc conversion
|
||||||
libreoffice@testing \
|
libreoffice@testing \
|
||||||
|
@ -58,7 +60,8 @@ RUN echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/main" | tee -a /et
|
||||||
addgroup -S stirlingpdfgroup && adduser -S stirlingpdfuser -G stirlingpdfgroup && \
|
addgroup -S stirlingpdfgroup && adduser -S stirlingpdfuser -G stirlingpdfgroup && \
|
||||||
chown -R stirlingpdfuser:stirlingpdfgroup $HOME /scripts /usr/share/fonts/opentype/noto /configs /customFiles /pipeline && \
|
chown -R stirlingpdfuser:stirlingpdfgroup $HOME /scripts /usr/share/fonts/opentype/noto /configs /customFiles /pipeline && \
|
||||||
chown stirlingpdfuser:stirlingpdfgroup /app.jar && \
|
chown stirlingpdfuser:stirlingpdfgroup /app.jar && \
|
||||||
tesseract --list-langs
|
tesseract --list-langs && \
|
||||||
|
rm -rf /var/cache/apk/*
|
||||||
|
|
||||||
EXPOSE 8080
|
EXPOSE 8080
|
||||||
|
|
||||||
|
|
|
@ -34,5 +34,18 @@ Then simply translate all property entries within that file and make a PR into m
|
||||||
|
|
||||||
If you do not have a java IDE i am happy to verify the changes worked once you raise PR (but won't be able to verify the translations themselves)
|
If you do not have a java IDE i am happy to verify the changes worked once you raise PR (but won't be able to verify the translations themselves)
|
||||||
|
|
||||||
|
## Handling Untranslatable Strings
|
||||||
|
|
||||||
|
Sometimes, certain strings in the properties file may not require translation because they are the same in the target language or are universal (like names of protocols, certain terminologies, etc.). To ensure accurate statistics for language progress, these strings should be added to the `ignore_translation.toml` file located in the `scripts` directory. This will exclude them from the translation progress calculations.
|
||||||
|
|
||||||
|
For example, if the English string error=Error does not need translation in Polish, add it to the ignore_translation.toml under the Polish section:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[pl_PL]
|
||||||
|
ignore = [
|
||||||
|
"language.direction", # Existing entries
|
||||||
|
"error" # Add new entries here
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
Make sure to place the entry under the correct language section. This helps maintain the accuracy of translation progress statistics and ensures that the translation tool or scripts do not misinterpret the completion rate.
|
||||||
|
|
57
README.md
57
README.md
|
@ -121,6 +121,7 @@ docker run -d \
|
||||||
-v /location/of/logs:/logs \
|
-v /location/of/logs:/logs \
|
||||||
-e DOCKER_ENABLE_SECURITY=false \
|
-e DOCKER_ENABLE_SECURITY=false \
|
||||||
-e INSTALL_BOOK_AND_ADVANCED_HTML_OPS=false \
|
-e INSTALL_BOOK_AND_ADVANCED_HTML_OPS=false \
|
||||||
|
-e LANGS=en_GB \
|
||||||
--name stirling-pdf \
|
--name stirling-pdf \
|
||||||
frooodle/s-pdf:latest
|
frooodle/s-pdf:latest
|
||||||
|
|
||||||
|
@ -147,6 +148,7 @@ services:
|
||||||
environment:
|
environment:
|
||||||
- DOCKER_ENABLE_SECURITY=false
|
- DOCKER_ENABLE_SECURITY=false
|
||||||
- INSTALL_BOOK_AND_ADVANCED_HTML_OPS=false
|
- INSTALL_BOOK_AND_ADVANCED_HTML_OPS=false
|
||||||
|
- LANGS=en_GB
|
||||||
```
|
```
|
||||||
|
|
||||||
Note: Podman is CLI-compatible with Docker, so simply replace "docker" with "podman".
|
Note: Podman is CLI-compatible with Docker, so simply replace "docker" with "podman".
|
||||||
|
@ -163,31 +165,31 @@ Stirling PDF currently supports 27!
|
||||||
| ------------------------------------------- | -------------------------------------- |
|
| ------------------------------------------- | -------------------------------------- |
|
||||||
| English (English) (en_GB) | ![100%](https://geps.dev/progress/100) |
|
| English (English) (en_GB) | ![100%](https://geps.dev/progress/100) |
|
||||||
| English (US) (en_US) | ![100%](https://geps.dev/progress/100) |
|
| English (US) (en_US) | ![100%](https://geps.dev/progress/100) |
|
||||||
| Arabic (العربية) (ar_AR) | ![58%](https://geps.dev/progress/58) |
|
| Arabic (العربية) (ar_AR) | ![42%](https://geps.dev/progress/42) |
|
||||||
| German (Deutsch) (de_DE) | ![98%](https://geps.dev/progress/98) |
|
| German (Deutsch) (de_DE) | ![100%](https://geps.dev/progress/100) |
|
||||||
| French (Français) (fr_FR) | ![94%](https://geps.dev/progress/94) |
|
| French (Français) (fr_FR) | ![91%](https://geps.dev/progress/91) |
|
||||||
| Spanish (Español) (es_ES) | ![95%](https://geps.dev/progress/95) |
|
| Spanish (Español) (es_ES) | ![99%](https://geps.dev/progress/99) |
|
||||||
| Simplified Chinese (简体中文) (zh_CN) | ![99%](https://geps.dev/progress/99) |
|
| Simplified Chinese (简体中文) (zh_CN) | ![98%](https://geps.dev/progress/98) |
|
||||||
| Traditional Chinese (繁體中文) (zh_TW) | ![99%](https://geps.dev/progress/99) |
|
| Traditional Chinese (繁體中文) (zh_TW) | ![98%](https://geps.dev/progress/98) |
|
||||||
| Catalan (Català) (ca_CA) | ![65%](https://geps.dev/progress/65) |
|
| Catalan (Català) (ca_CA) | ![51%](https://geps.dev/progress/51) |
|
||||||
| Italian (Italiano) (it_IT) | ![98%](https://geps.dev/progress/98) |
|
| Italian (Italiano) (it_IT) | ![99%](https://geps.dev/progress/99) |
|
||||||
| Swedish (Svenska) (sv_SE) | ![58%](https://geps.dev/progress/58) |
|
| Swedish (Svenska) (sv_SE) | ![42%](https://geps.dev/progress/42) |
|
||||||
| Polish (Polski) (pl_PL) | ![60%](https://geps.dev/progress/60) |
|
| Polish (Polski) (pl_PL) | ![44%](https://geps.dev/progress/44) |
|
||||||
| Romanian (Română) (ro_RO) | ![58%](https://geps.dev/progress/58) |
|
| Romanian (Română) (ro_RO) | ![41%](https://geps.dev/progress/41) |
|
||||||
| Korean (한국어) (ko_KR) | ![94%](https://geps.dev/progress/94) |
|
| Korean (한국어) (ko_KR) | ![91%](https://geps.dev/progress/91) |
|
||||||
| Portuguese Brazilian (Português) (pt_BR) | ![74%](https://geps.dev/progress/74) |
|
| Portuguese Brazilian (Português) (pt_BR) | ![63%](https://geps.dev/progress/63) |
|
||||||
| Russian (Русский) (ru_RU) | ![94%](https://geps.dev/progress/94) |
|
| Russian (Русский) (ru_RU) | ![91%](https://geps.dev/progress/91) |
|
||||||
| Basque (Euskara) (eu_ES) | ![76%](https://geps.dev/progress/76) |
|
| Basque (Euskara) (eu_ES) | ![66%](https://geps.dev/progress/66) |
|
||||||
| Japanese (日本語) (ja_JP) | ![94%](https://geps.dev/progress/94) |
|
| Japanese (日本語) (ja_JP) | ![91%](https://geps.dev/progress/91) |
|
||||||
| Dutch (Nederlands) (nl_NL) | ![92%](https://geps.dev/progress/92) |
|
| Dutch (Nederlands) (nl_NL) | ![88%](https://geps.dev/progress/88) |
|
||||||
| Greek (Ελληνικά) (el_GR) | ![92%](https://geps.dev/progress/92) |
|
| Greek (Ελληνικά) (el_GR) | ![88%](https://geps.dev/progress/88) |
|
||||||
| Turkish (Türkçe) (tr_TR) | ![99%](https://geps.dev/progress/99) |
|
| Turkish (Türkçe) (tr_TR) | ![99%](https://geps.dev/progress/99) |
|
||||||
| Indonesia (Bahasa Indonesia) (id_ID) | ![87%](https://geps.dev/progress/87) |
|
| Indonesia (Bahasa Indonesia) (id_ID) | ![82%](https://geps.dev/progress/82) |
|
||||||
| Hindi (हिंदी) (hi_IN) | ![88%](https://geps.dev/progress/88) |
|
| Hindi (हिंदी) (hi_IN) | ![82%](https://geps.dev/progress/82) |
|
||||||
| Hungarian (Magyar) (hu_HU) | ![87%](https://geps.dev/progress/87) |
|
| Hungarian (Magyar) (hu_HU) | ![81%](https://geps.dev/progress/81) |
|
||||||
| Bulgarian (Български) (bg_BG) | ![82%](https://geps.dev/progress/82) |
|
| Bulgarian (Български) (bg_BG) | ![75%](https://geps.dev/progress/75) |
|
||||||
| Sebian Latin alphabet (Srpski) (sr_LATN_RS) | ![89%](https://geps.dev/progress/89) |
|
| Sebian Latin alphabet (Srpski) (sr_LATN_RS) | ![84%](https://geps.dev/progress/84) |
|
||||||
| Ukrainian (Українська) (uk_UA) | ![98%](https://geps.dev/progress/98) |
|
| Ukrainian (Українська) (uk_UA) | ![90%](https://geps.dev/progress/90) |
|
||||||
|
|
||||||
## Contributing (creating issues, translations, fixing bugs, etc.)
|
## Contributing (creating issues, translations, fixing bugs, etc.)
|
||||||
|
|
||||||
|
@ -199,7 +201,7 @@ Stirling PDF allows easy customization of the app.
|
||||||
Includes things like
|
Includes things like
|
||||||
|
|
||||||
- Custom application name
|
- Custom application name
|
||||||
- Custom slogans, icons, images, and even custom HTML (via file overrides)
|
- Custom slogans, icons, HTML, images CSS etc (via file overrides)
|
||||||
|
|
||||||
There are two options for this, either using the generated settings file ``settings.yml``
|
There are two options for this, either using the generated settings file ``settings.yml``
|
||||||
This file is located in the ``/configs`` directory and follows standard YAML formatting
|
This file is located in the ``/configs`` directory and follows standard YAML formatting
|
||||||
|
@ -225,6 +227,9 @@ system:
|
||||||
defaultLocale: 'en-US' # Set the default language (e.g. 'de-DE', 'fr-FR', etc)
|
defaultLocale: 'en-US' # Set the default language (e.g. 'de-DE', 'fr-FR', etc)
|
||||||
googlevisibility: false # 'true' to allow Google visibility (via robots.txt), 'false' to disallow
|
googlevisibility: false # 'true' to allow Google visibility (via robots.txt), 'false' to disallow
|
||||||
customStaticFilePath: '/customFiles/static/' # Directory path for custom static files
|
customStaticFilePath: '/customFiles/static/' # Directory path for custom static files
|
||||||
|
showUpdate: true # see when a new update is available
|
||||||
|
showUpdateOnlyAdmin: false # Only admins can see when a new update is available, depending on showUpdate it must be set to 'true'
|
||||||
|
customHTMLFiles: false # enable to have files placed in /customFiles/templates override the existing template html files
|
||||||
|
|
||||||
#ui:
|
#ui:
|
||||||
# appName: exampleAppName # Application's visible name
|
# appName: exampleAppName # Application's visible name
|
||||||
|
@ -250,13 +255,13 @@ metrics:
|
||||||
- ``SYSTEM_CONNECTIONTIMEOUTMINUTES`` to set custom connection timeout values
|
- ``SYSTEM_CONNECTIONTIMEOUTMINUTES`` to set custom connection timeout values
|
||||||
- ``DOCKER_ENABLE_SECURITY`` to tell docker to download security jar (required as true for auth login)
|
- ``DOCKER_ENABLE_SECURITY`` to tell docker to download security jar (required as true for auth login)
|
||||||
- ``INSTALL_BOOK_AND_ADVANCED_HTML_OPS`` to download calibre onto stirling-pdf enabling pdf to/from book and advanced html conversion
|
- ``INSTALL_BOOK_AND_ADVANCED_HTML_OPS`` to download calibre onto stirling-pdf enabling pdf to/from book and advanced html conversion
|
||||||
|
- ``LANGS`` to define custom font libraries to install for use for document conversions
|
||||||
|
|
||||||
## API
|
## API
|
||||||
|
|
||||||
For those wanting to use Stirling-PDFs backend API to link with their own custom scripting to edit PDFs you can view all existing API documentation
|
For those wanting to use Stirling-PDFs backend API to link with their own custom scripting to edit PDFs you can view all existing API documentation
|
||||||
[here](https://app.swaggerhub.com/apis-docs/Stirling-Tools/Stirling-PDF/) or navigate to /swagger-ui/index.html of your stirling-pdf instance for your versions documentation (Or by following the API button in your settings of Stirling-PDF)
|
[here](https://app.swaggerhub.com/apis-docs/Stirling-Tools/Stirling-PDF/) or navigate to /swagger-ui/index.html of your stirling-pdf instance for your versions documentation (Or by following the API button in your settings of Stirling-PDF)
|
||||||
|
|
||||||
|
|
||||||
## Login authentication
|
## Login authentication
|
||||||
|
|
||||||
![stirling-login](images/login-light.png)
|
![stirling-login](images/login-light.png)
|
||||||
|
|
|
@ -12,7 +12,7 @@ plugins {
|
||||||
import com.github.jk1.license.render.*
|
import com.github.jk1.license.render.*
|
||||||
|
|
||||||
group = 'stirling.software'
|
group = 'stirling.software'
|
||||||
version = '0.22.8'
|
version = '0.23.1'
|
||||||
sourceCompatibility = '17'
|
sourceCompatibility = '17'
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
|
@ -99,6 +99,7 @@ dependencies {
|
||||||
implementation 'org.springframework.boot:spring-boot-starter-security:3.2.4'
|
implementation 'org.springframework.boot:spring-boot-starter-security:3.2.4'
|
||||||
implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity5:3.1.2.RELEASE'
|
implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity5:3.1.2.RELEASE'
|
||||||
implementation "org.springframework.boot:spring-boot-starter-data-jpa:3.2.4"
|
implementation "org.springframework.boot:spring-boot-starter-data-jpa:3.2.4"
|
||||||
|
implementation 'org.springframework.boot:spring-boot-starter-oauth2-client:3.2.4'
|
||||||
|
|
||||||
//2.2.x requires rebuild of DB file.. need migration path
|
//2.2.x requires rebuild of DB file.. need migration path
|
||||||
implementation "com.h2database:h2:2.1.214"
|
implementation "com.h2database:h2:2.1.214"
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
apiVersion: v2
|
apiVersion: v2
|
||||||
appVersion: 0.22.8
|
appVersion: 0.23.1
|
||||||
description: locally hosted web application that allows you to perform various operations
|
description: locally hosted web application that allows you to perform various operations
|
||||||
on PDF files
|
on PDF files
|
||||||
home: https://github.com/Stirling-Tools/Stirling-PDF
|
home: https://github.com/Stirling-Tools/Stirling-PDF
|
||||||
|
|
39
exampleYmlFiles/docker-compose-latest-security-with-sso.yml
Normal file
39
exampleYmlFiles/docker-compose-latest-security-with-sso.yml
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
version: '3.3'
|
||||||
|
services:
|
||||||
|
stirling-pdf:
|
||||||
|
container_name: Stirling-PDF-Security
|
||||||
|
image: frooodle/s-pdf:latest
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 4G
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "curl -f http://localhost:8080/api/v1/info/status | grep -q 'UP' && curl -fL http://localhost:8080/ | grep -q 'Please sign in'"]
|
||||||
|
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"
|
||||||
|
SECURITY_OAUTH2_ENABLED: "true"
|
||||||
|
SECURITY_OAUTH2_AUTOCREATEUSER: "true" # This is set to true to allow auto-creation of non-existing users in Striling-PDF
|
||||||
|
SECURITY_OAUTH2_ISSUER: "https://accounts.google.com" # Change with any other provider that supports OpenID Connect Discovery (/.well-known/openid-configuration) end-point
|
||||||
|
SECURITY_OAUTH2_CLIENTID: "<YOUR CLIENT ID>.apps.googleusercontent.com" # Client ID from your provider
|
||||||
|
SECURITY_OAUTH2_CLIENTSECRET: "<YOUR CLIENT SECRET>" # Client Secret from your provider
|
||||||
|
PUID: 1002
|
||||||
|
PGID: 1002
|
||||||
|
UMASK: "022"
|
||||||
|
SYSTEM_DEFAULTLOCALE: en-US
|
||||||
|
UI_APPNAME: Stirling-PDF
|
||||||
|
UI_HOMEDESCRIPTION: Demo site for Stirling-PDF Latest with Security
|
||||||
|
UI_APPNAMENAVBAR: Stirling-PDF Latest
|
||||||
|
SYSTEM_MAXFILESIZE: "100"
|
||||||
|
METRICS_ENABLED: "true"
|
||||||
|
SYSTEM_GOOGLEVISIBILITY: "true"
|
||||||
|
restart: on-failure:5
|
|
@ -21,6 +21,8 @@ services:
|
||||||
environment:
|
environment:
|
||||||
DOCKER_ENABLE_SECURITY: "false"
|
DOCKER_ENABLE_SECURITY: "false"
|
||||||
SECURITY_ENABLELOGIN: "false"
|
SECURITY_ENABLELOGIN: "false"
|
||||||
|
LANGS: "en_GB,en_US,ar_AR,de_DE,fr_FR,es_ES,zh_CN,zh_TW,ca_CA,it_IT,sv_SE,pl_PL,ro_RO,ko_KR,pt_BR,ru_RU,el_GR,hi_IN,hu_HU,tr_TR,id_ID"
|
||||||
|
INSTALL_BOOK_AND_ADVANCED_HTML_OPS: "true"
|
||||||
SYSTEM_DEFAULTLOCALE: en-US
|
SYSTEM_DEFAULTLOCALE: en-US
|
||||||
UI_APPNAME: Stirling-PDF
|
UI_APPNAME: Stirling-PDF
|
||||||
UI_HOMEDESCRIPTION: Demo site for Stirling-PDF Latest
|
UI_HOMEDESCRIPTION: Demo site for Stirling-PDF Latest
|
||||||
|
|
|
@ -10,49 +10,77 @@ Author: Ludy87
|
||||||
Example:
|
Example:
|
||||||
To use this script, simply run it from command line:
|
To use this script, simply run it from command line:
|
||||||
$ python counter_translation.py
|
$ python counter_translation.py
|
||||||
"""
|
""" # noqa: D205
|
||||||
import os
|
|
||||||
import glob
|
import glob
|
||||||
|
import os
|
||||||
import re
|
import re
|
||||||
from typing import List, Tuple
|
|
||||||
|
import tomlkit
|
||||||
|
import tomlkit.toml_file
|
||||||
|
|
||||||
|
|
||||||
def write_readme(progress_list: List[Tuple[str, int]]) -> None:
|
def convert_to_multiline(data: tomlkit.TOMLDocument) -> tomlkit.TOMLDocument:
|
||||||
"""
|
"""Converts 'ignore' and 'missing' arrays to multiline arrays and sorts the first-level keys of the TOML document.
|
||||||
Updates the progress status in the README.md file based
|
Enhances readability and consistency in the TOML file by ensuring arrays contain unique and sorted entries.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
data (tomlkit.TOMLDocument): The original TOML document containing the data.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
tomlkit.TOMLDocument: A new TOML document with sorted keys and properly formatted arrays.
|
||||||
|
""" # noqa: D205
|
||||||
|
sorted_data = tomlkit.document()
|
||||||
|
for key in sorted(data.keys()):
|
||||||
|
value = data[key]
|
||||||
|
if isinstance(value, dict):
|
||||||
|
new_table = tomlkit.table()
|
||||||
|
for subkey in ("ignore", "missing"):
|
||||||
|
if subkey in value:
|
||||||
|
# Convert the list to a set to remove duplicates, sort it, and convert to multiline for readability
|
||||||
|
unique_sorted_array = sorted(set(value[subkey]))
|
||||||
|
array = tomlkit.array()
|
||||||
|
array.multiline(True)
|
||||||
|
for item in unique_sorted_array:
|
||||||
|
array.append(item)
|
||||||
|
new_table[subkey] = array
|
||||||
|
sorted_data[key] = new_table
|
||||||
|
else:
|
||||||
|
# Add other types of data unchanged
|
||||||
|
sorted_data[key] = value
|
||||||
|
return sorted_data
|
||||||
|
|
||||||
|
|
||||||
|
def write_readme(progress_list: list[tuple[str, int]]) -> None:
|
||||||
|
"""Updates the progress status in the README.md file based
|
||||||
on the provided progress list.
|
on the provided progress list.
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
progress_list (List[Tuple[str, int]]): A list of tuples containing
|
progress_list (list[tuple[str, int]]): A list of tuples containing
|
||||||
language and progress percentage.
|
language and progress percentage.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
None
|
None
|
||||||
"""
|
""" # noqa: D205
|
||||||
with open("README.md", "r", encoding="utf-8") as file:
|
with open("README.md", encoding="utf-8") as file:
|
||||||
content = file.read()
|
content = file.readlines()
|
||||||
|
|
||||||
lines = content.split("\n")
|
for i, line in enumerate(content[2:], start=2):
|
||||||
for i, line in enumerate(lines[2:], start=2):
|
|
||||||
for progress in progress_list:
|
for progress in progress_list:
|
||||||
language, value = progress
|
language, value = progress
|
||||||
if language in line:
|
if language in line:
|
||||||
match = re.search(r"\!\[(\d+(\.\d+)?)%\]\(.*\)", line)
|
if match := re.search(r"\!\[(\d+(\.\d+)?)%\]\(.*\)", line):
|
||||||
if match:
|
content[i] = line.replace(
|
||||||
lines[i] = line.replace(
|
|
||||||
match.group(0),
|
match.group(0),
|
||||||
f"![{value}%](https://geps.dev/progress/{value})",
|
f"![{value}%](https://geps.dev/progress/{value})",
|
||||||
)
|
)
|
||||||
|
|
||||||
new_content = "\n".join(lines)
|
|
||||||
|
|
||||||
with open("README.md", "w", encoding="utf-8") as file:
|
with open("README.md", "w", encoding="utf-8") as file:
|
||||||
file.write(new_content)
|
file.writelines(content)
|
||||||
|
|
||||||
|
|
||||||
def compare_files(default_file_path, files_directory) -> List[Tuple[str, int]]:
|
def compare_files(default_file_path, file_paths, translation_status_file) -> list[tuple[str, int]]:
|
||||||
"""
|
"""Compares the default properties file with other
|
||||||
Compares the default properties file with other
|
|
||||||
properties files in the directory.
|
properties files in the directory.
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
|
@ -60,20 +88,22 @@ def compare_files(default_file_path, files_directory) -> List[Tuple[str, int]]:
|
||||||
files_directory (str): The directory containing other properties files.
|
files_directory (str): The directory containing other properties files.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
List[Tuple[str, int]]: A list of tuples containing
|
list[tuple[str, int]]: A list of tuples containing
|
||||||
language and progress percentage.
|
language and progress percentage.
|
||||||
"""
|
""" # noqa: D205
|
||||||
file_paths = glob.glob(os.path.join(files_directory, "messages_*.properties"))
|
num_lines = sum(
|
||||||
num_lines = sum(1 for _ in open(default_file_path, encoding="utf-8"))
|
1 for line in open(default_file_path, encoding="utf-8") if line.strip() and not line.strip().startswith("#")
|
||||||
|
)
|
||||||
|
|
||||||
result_list = []
|
result_list = []
|
||||||
|
sort_translation_status: tomlkit.TOMLDocument
|
||||||
|
|
||||||
|
# read toml
|
||||||
|
with open(translation_status_file, encoding="utf-8") as f:
|
||||||
|
sort_translation_status = tomlkit.parse(f.read())
|
||||||
|
|
||||||
for file_path in file_paths:
|
for file_path in file_paths:
|
||||||
language = (
|
language = os.path.basename(file_path).split("messages_", 1)[1].split(".properties", 1)[0]
|
||||||
os.path.basename(file_path)
|
|
||||||
.split("messages_", 1)[1]
|
|
||||||
.split(".properties", 1)[0]
|
|
||||||
)
|
|
||||||
|
|
||||||
fails = 0
|
fails = 0
|
||||||
if "en_GB" in language or "en_US" in language:
|
if "en_GB" in language or "en_US" in language:
|
||||||
|
@ -81,9 +111,21 @@ def compare_files(default_file_path, files_directory) -> List[Tuple[str, int]]:
|
||||||
result_list.append(("en_US", 100))
|
result_list.append(("en_US", 100))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
with open(default_file_path, "r", encoding="utf-8") as default_file, open(
|
if language not in sort_translation_status:
|
||||||
file_path, "r", encoding="utf-8"
|
sort_translation_status[language] = tomlkit.table()
|
||||||
) as file:
|
|
||||||
|
if (
|
||||||
|
"ignore" not in sort_translation_status[language]
|
||||||
|
or len(sort_translation_status[language].get("ignore", [])) < 1
|
||||||
|
):
|
||||||
|
sort_translation_status[language]["ignore"] = tomlkit.array(["language.direction"])
|
||||||
|
|
||||||
|
# if "missing" not in sort_translation_status[language]:
|
||||||
|
# sort_translation_status[language]["missing"] = tomlkit.array()
|
||||||
|
# elif "language.direction" in sort_translation_status[language]["missing"]:
|
||||||
|
# sort_translation_status[language]["missing"].remove("language.direction")
|
||||||
|
|
||||||
|
with open(default_file_path, encoding="utf-8") as default_file, open(file_path, encoding="utf-8") as file:
|
||||||
for _ in range(5):
|
for _ in range(5):
|
||||||
next(default_file)
|
next(default_file)
|
||||||
try:
|
try:
|
||||||
|
@ -91,24 +133,47 @@ def compare_files(default_file_path, files_directory) -> List[Tuple[str, int]]:
|
||||||
except StopIteration:
|
except StopIteration:
|
||||||
fails = num_lines
|
fails = num_lines
|
||||||
|
|
||||||
for _, (line_default, line_file) in enumerate(
|
for line_num, (line_default, line_file) in enumerate(zip(default_file, file), start=6):
|
||||||
zip(default_file, file), start=6
|
|
||||||
):
|
|
||||||
try:
|
try:
|
||||||
|
# Ignoring empty lines and lines start with #
|
||||||
|
if line_default.strip() == "" or line_default.startswith("#"):
|
||||||
|
continue
|
||||||
|
|
||||||
|
default_key, default_value = line_default.split("=", 1)
|
||||||
|
file_key, file_value = line_file.split("=", 1)
|
||||||
if (
|
if (
|
||||||
line_default.split("=", 1)[1].strip()
|
default_value.strip() == file_value.strip()
|
||||||
== line_file.split("=", 1)[1].strip()
|
and default_key.strip() not in sort_translation_status[language]["ignore"]
|
||||||
):
|
):
|
||||||
|
print(f"{language}: Line {line_num} is missing the translation.")
|
||||||
|
# if default_key.strip() not in sort_translation_status[language]["missing"]:
|
||||||
|
# missing_array = tomlkit.array()
|
||||||
|
# missing_array.append(default_key.strip())
|
||||||
|
# missing_array.multiline(True)
|
||||||
|
# sort_translation_status[language]["missing"].extend(missing_array)
|
||||||
fails += 1
|
fails += 1
|
||||||
|
# elif default_key.strip() in sort_translation_status[language]["ignore"]:
|
||||||
|
# if default_key.strip() in sort_translation_status[language]["missing"]:
|
||||||
|
# sort_translation_status[language]["missing"].remove(default_key.strip())
|
||||||
|
if default_value.strip() != file_value.strip():
|
||||||
|
# if default_key.strip() in sort_translation_status[language]["missing"]:
|
||||||
|
# sort_translation_status[language]["missing"].remove(default_key.strip())
|
||||||
|
if default_key.strip() in sort_translation_status[language]["ignore"]:
|
||||||
|
sort_translation_status[language]["ignore"].remove(default_key.strip())
|
||||||
|
|
||||||
except IndexError:
|
except IndexError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
print(f"{language}: {fails} out of {num_lines} lines are not translated.")
|
||||||
result_list.append(
|
result_list.append(
|
||||||
(
|
(
|
||||||
language,
|
language,
|
||||||
int((num_lines - fails) * 100 / num_lines),
|
int((num_lines - fails) * 100 / num_lines),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
translation_status = convert_to_multiline(sort_translation_status)
|
||||||
|
with open(translation_status_file, "w", encoding="utf-8") as file:
|
||||||
|
file.write(tomlkit.dumps(translation_status))
|
||||||
|
|
||||||
unique_data = list(set(result_list))
|
unique_data = list(set(result_list))
|
||||||
unique_data.sort(key=lambda x: x[1], reverse=True)
|
unique_data.sort(key=lambda x: x[1], reverse=True)
|
||||||
|
@ -118,5 +183,10 @@ def compare_files(default_file_path, files_directory) -> List[Tuple[str, int]]:
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
directory = os.path.join(os.getcwd(), "src", "main", "resources")
|
directory = os.path.join(os.getcwd(), "src", "main", "resources")
|
||||||
|
messages_file_paths = glob.glob(os.path.join(directory, "messages_*.properties"))
|
||||||
reference_file = os.path.join(directory, "messages_en_GB.properties")
|
reference_file = os.path.join(directory, "messages_en_GB.properties")
|
||||||
write_readme(compare_files(reference_file, directory))
|
|
||||||
|
scripts_directory = os.path.join(os.getcwd(), "scripts")
|
||||||
|
translation_state_file = os.path.join(scripts_directory, "translation_status.toml")
|
||||||
|
|
||||||
|
write_readme(compare_files(reference_file, messages_file_paths, translation_state_file))
|
||||||
|
|
|
@ -1,25 +1,30 @@
|
||||||
#!/bin/sh
|
#!/bin/bash
|
||||||
|
|
||||||
# Update the user and group IDs as per environment variables
|
# Update the user and group IDs as per environment variables
|
||||||
if [ ! -z "$PUID" ] && [ "$PUID" != "$(id -u stirlingpdfuser)" ]; then
|
if [ ! -z "$PUID" ] && [ "$PUID" != "$(id -u stirlingpdfuser)" ]; then
|
||||||
usermod -o -u "$PUID" stirlingpdfuser || true
|
usermod -o -u "$PUID" stirlingpdfuser || true
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
if [ ! -z "$PGID" ] && [ "$PGID" != "$(getent group stirlingpdfgroup | cut -d: -f3)" ]; then
|
if [ ! -z "$PGID" ] && [ "$PGID" != "$(getent group stirlingpdfgroup | cut -d: -f3)" ]; then
|
||||||
groupmod -o -g "$PGID" stirlingpdfgroup || true
|
groupmod -o -g "$PGID" stirlingpdfgroup || true
|
||||||
fi
|
fi
|
||||||
umask "$UMASK" || true
|
umask "$UMASK" || true
|
||||||
|
|
||||||
|
|
||||||
if [[ "$INSTALL_BOOK_AND_ADVANCED_HTML_OPS" == "true" ]]; then
|
if [[ "$INSTALL_BOOK_AND_ADVANCED_HTML_OPS" == "true" ]]; then
|
||||||
apk add --no-cache calibre@testing
|
apk add --no-cache calibre@testing
|
||||||
fi
|
fi
|
||||||
|
|
||||||
/scripts/download-security-jar.sh
|
/scripts/download-security-jar.sh
|
||||||
|
|
||||||
|
if [[ -n "$LANGS" ]]; then
|
||||||
|
/scripts/installFonts.sh $LANGS
|
||||||
|
fi
|
||||||
|
|
||||||
echo "Setting permissions and ownership for necessary directories..."
|
echo "Setting permissions and ownership for necessary directories..."
|
||||||
if chown -R stirlingpdfuser:stirlingpdfgroup $HOME /logs /scripts /usr/share/fonts/opentype/noto /usr/share/tessdata /configs /customFiles /pipeline /app.jar; then
|
# Attempt to change ownership of directories and files
|
||||||
chmod -R 755 /logs /scripts /usr/share/fonts/opentype/noto /usr/share/tessdata /configs /customFiles /pipeline /app.jar || true
|
if chown -R stirlingpdfuser:stirlingpdfgroup $HOME /logs /scripts /usr/share/fonts/opentype/noto /configs /customFiles /pipeline /app.jar; then
|
||||||
|
chmod -R 755 /logs /scripts /usr/share/fonts/opentype/noto /configs /customFiles /pipeline /app.jar || true
|
||||||
# If chown succeeds, execute the command as stirlingpdfuser
|
# If chown succeeds, execute the command as stirlingpdfuser
|
||||||
exec su-exec stirlingpdfuser "$@"
|
exec su-exec stirlingpdfuser "$@"
|
||||||
else
|
else
|
||||||
|
|
|
@ -13,18 +13,6 @@ if [ -d /usr/share/tesseract-ocr/5/tessdata ]; then
|
||||||
cp -r /usr/share/tesseract-ocr/5/tessdata/* /usr/share/tessdata || true;
|
cp -r /usr/share/tesseract-ocr/5/tessdata/* /usr/share/tessdata || true;
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Update the user and group IDs as per environment variables
|
|
||||||
if [ ! -z "$PUID" ] && [ "$PUID" != "$(id -u stirlingpdfuser)" ]; then
|
|
||||||
usermod -o -u "$PUID" stirlingpdfuser || true
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
if [ ! -z "$PGID" ] && [ "$PGID" != "$(getent group stirlingpdfgroup | cut -d: -f3)" ]; then
|
|
||||||
groupmod -o -g "$PGID" stirlingpdfgroup || true
|
|
||||||
fi
|
|
||||||
umask "$UMASK" || true
|
|
||||||
|
|
||||||
|
|
||||||
# Check if TESSERACT_LANGS environment variable is set and is not empty
|
# Check if TESSERACT_LANGS environment variable is set and is not empty
|
||||||
if [[ -n "$TESSERACT_LANGS" ]]; then
|
if [[ -n "$TESSERACT_LANGS" ]]; then
|
||||||
# Convert comma-separated values to a space-separated list
|
# Convert comma-separated values to a space-separated list
|
||||||
|
@ -40,20 +28,4 @@ if [[ -n "$TESSERACT_LANGS" ]]; then
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "$INSTALL_BOOK_AND_ADVANCED_HTML_OPS" == "true" ]]; then
|
/scripts/init-without-ocr.sh "$@"
|
||||||
apk add --no-cache calibre@testing
|
|
||||||
fi
|
|
||||||
|
|
||||||
/scripts/download-security-jar.sh
|
|
||||||
|
|
||||||
echo "Setting permissions and ownership for necessary directories..."
|
|
||||||
# Attempt to change ownership of directories and files
|
|
||||||
if chown -R stirlingpdfuser:stirlingpdfgroup $HOME /logs /scripts /usr/share/fonts/opentype/noto /usr/share/tessdata /configs /customFiles /pipeline /app.jar; then
|
|
||||||
chmod -R 755 /logs /scripts /usr/share/fonts/opentype/noto /usr/share/tessdata /configs /customFiles /pipeline /app.jar || true
|
|
||||||
# If chown succeeds, execute the command as stirlingpdfuser
|
|
||||||
exec su-exec stirlingpdfuser "$@"
|
|
||||||
else
|
|
||||||
# If chown fails, execute the command without changing the user context
|
|
||||||
echo "[WARN] Chown failed, running as host user"
|
|
||||||
exec "$@"
|
|
||||||
fi
|
|
67
scripts/installFonts.sh
Normal file
67
scripts/installFonts.sh
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
LANGS=$1
|
||||||
|
|
||||||
|
# Function to install a font package
|
||||||
|
install_font() {
|
||||||
|
echo "Installing font package: $1"
|
||||||
|
if ! apk add "$1" --no-cache; then
|
||||||
|
echo "Failed to install $1"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Install common fonts used across many languages
|
||||||
|
#common_fonts=(
|
||||||
|
# font-terminus
|
||||||
|
# font-dejavu
|
||||||
|
# font-noto
|
||||||
|
# font-noto-cjk
|
||||||
|
# font-awesome
|
||||||
|
# font-noto-extra
|
||||||
|
#)
|
||||||
|
#
|
||||||
|
#for font in "${common_fonts[@]}"; do
|
||||||
|
# install_font $font
|
||||||
|
#done
|
||||||
|
|
||||||
|
# Map languages to specific font packages
|
||||||
|
declare -A language_fonts=(
|
||||||
|
["ar_AR"]="font-noto-arabic"
|
||||||
|
["zh_CN"]="font-isas-misc"
|
||||||
|
["zh_TW"]="font-isas-misc"
|
||||||
|
["ja_JP"]="font-noto font-noto-thai font-noto-tibetan font-ipa font-sony-misc font-jis-misc"
|
||||||
|
["ru_RU"]="font-vollkorn font-misc-cyrillic font-mutt-misc font-screen-cyrillic font-winitzki-cyrillic font-cronyx-cyrillic"
|
||||||
|
["sr_LATN_RS"]="font-vollkorn font-misc-cyrillic font-mutt-misc font-screen-cyrillic font-winitzki-cyrillic font-cronyx-cyrillic"
|
||||||
|
["uk_UA"]="font-vollkorn font-misc-cyrillic font-mutt-misc font-screen-cyrillic font-winitzki-cyrillic font-cronyx-cyrillic"
|
||||||
|
["ko_KR"]="font-noto font-noto-thai font-noto-tibetan"
|
||||||
|
["el_GR"]="font-noto"
|
||||||
|
["hi_IN"]="font-noto-devanagari"
|
||||||
|
["bg_BG"]="font-vollkorn font-misc-cyrillic"
|
||||||
|
["GENERAL"]="font-terminus font-dejavu font-noto font-noto-cjk font-awesome font-noto-extra"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Install fonts for other languages which generally do not need special packages beyond 'font-noto'
|
||||||
|
other_langs=("en_GB" "en_US" "de_DE" "fr_FR" "es_ES" "ca_CA" "it_IT" "pt_BR" "nl_NL" "sv_SE" "pl_PL" "ro_RO" "hu_HU" "tr_TR" "id_ID" "eu_ES")
|
||||||
|
if [[ $LANGS == "ALL" ]]; then
|
||||||
|
# Install all fonts from the language_fonts map
|
||||||
|
for fonts in "${language_fonts[@]}"; do
|
||||||
|
for font in $fonts; do
|
||||||
|
install_font $font
|
||||||
|
done
|
||||||
|
done
|
||||||
|
else
|
||||||
|
# Split comma-separated languages and install necessary fonts
|
||||||
|
IFS=',' read -ra LANG_CODES <<< "$LANGS"
|
||||||
|
for code in "${LANG_CODES[@]}"; do
|
||||||
|
if [[ " ${other_langs[@]} " =~ " ${code} " ]]; then
|
||||||
|
install_font font-noto
|
||||||
|
else
|
||||||
|
fonts_to_install=${language_fonts[$code]}
|
||||||
|
if [ ! -z "$fonts_to_install" ]; then
|
||||||
|
for font in $fonts_to_install; do
|
||||||
|
install_font $font
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
154
scripts/translation_status.toml
Normal file
154
scripts/translation_status.toml
Normal file
|
@ -0,0 +1,154 @@
|
||||||
|
[ar_AR]
|
||||||
|
ignore = [
|
||||||
|
'language.direction',
|
||||||
|
]
|
||||||
|
|
||||||
|
[bg_BG]
|
||||||
|
ignore = [
|
||||||
|
'language.direction',
|
||||||
|
]
|
||||||
|
|
||||||
|
[ca_CA]
|
||||||
|
ignore = [
|
||||||
|
'language.direction',
|
||||||
|
]
|
||||||
|
|
||||||
|
[de_DE]
|
||||||
|
ignore = [
|
||||||
|
'AddStampRequest.alphabet',
|
||||||
|
'AddStampRequest.position',
|
||||||
|
'PDFToBook.selectText.1',
|
||||||
|
'PDFToText.tags',
|
||||||
|
'addPageNumbers.selectText.3',
|
||||||
|
'alphabet',
|
||||||
|
'certSign.name',
|
||||||
|
'language.direction',
|
||||||
|
'licenses.version',
|
||||||
|
'pipeline.title',
|
||||||
|
'pipelineOptions.pipelineHeader',
|
||||||
|
'sponsor',
|
||||||
|
'text',
|
||||||
|
'watermark.type.1',
|
||||||
|
]
|
||||||
|
|
||||||
|
[el_GR]
|
||||||
|
ignore = [
|
||||||
|
'language.direction',
|
||||||
|
]
|
||||||
|
|
||||||
|
[es_ES]
|
||||||
|
ignore = [
|
||||||
|
'adminUserSettings.roles',
|
||||||
|
'color',
|
||||||
|
'language.direction',
|
||||||
|
'no',
|
||||||
|
'showJS.tags',
|
||||||
|
]
|
||||||
|
|
||||||
|
[eu_ES]
|
||||||
|
ignore = [
|
||||||
|
'language.direction',
|
||||||
|
]
|
||||||
|
|
||||||
|
[fr_FR]
|
||||||
|
ignore = [
|
||||||
|
'language.direction',
|
||||||
|
]
|
||||||
|
|
||||||
|
[hi_IN]
|
||||||
|
ignore = [
|
||||||
|
'language.direction',
|
||||||
|
]
|
||||||
|
|
||||||
|
[hu_HU]
|
||||||
|
ignore = [
|
||||||
|
'language.direction',
|
||||||
|
]
|
||||||
|
|
||||||
|
[id_ID]
|
||||||
|
ignore = [
|
||||||
|
'language.direction',
|
||||||
|
]
|
||||||
|
|
||||||
|
[it_IT]
|
||||||
|
ignore = [
|
||||||
|
'font',
|
||||||
|
'language.direction',
|
||||||
|
'no',
|
||||||
|
'password',
|
||||||
|
'pipeline.title',
|
||||||
|
'pipelineOptions.pipelineHeader',
|
||||||
|
'removePassword.selectText.2',
|
||||||
|
'showJS.tags',
|
||||||
|
'sponsor',
|
||||||
|
]
|
||||||
|
|
||||||
|
[ja_JP]
|
||||||
|
ignore = [
|
||||||
|
'language.direction',
|
||||||
|
]
|
||||||
|
|
||||||
|
[ko_KR]
|
||||||
|
ignore = [
|
||||||
|
'language.direction',
|
||||||
|
]
|
||||||
|
|
||||||
|
[nl_NL]
|
||||||
|
ignore = [
|
||||||
|
'language.direction',
|
||||||
|
]
|
||||||
|
|
||||||
|
[pl_PL]
|
||||||
|
ignore = [
|
||||||
|
'language.direction',
|
||||||
|
]
|
||||||
|
|
||||||
|
[pt_BR]
|
||||||
|
ignore = [
|
||||||
|
'language.direction',
|
||||||
|
]
|
||||||
|
|
||||||
|
[pt_PT]
|
||||||
|
ignore = [
|
||||||
|
'language.direction',
|
||||||
|
]
|
||||||
|
|
||||||
|
[ro_RO]
|
||||||
|
ignore = [
|
||||||
|
'language.direction',
|
||||||
|
]
|
||||||
|
|
||||||
|
[ru_RU]
|
||||||
|
ignore = [
|
||||||
|
'language.direction',
|
||||||
|
]
|
||||||
|
|
||||||
|
[sr_LATN_RS]
|
||||||
|
ignore = [
|
||||||
|
'language.direction',
|
||||||
|
]
|
||||||
|
|
||||||
|
[sv_SE]
|
||||||
|
ignore = [
|
||||||
|
'language.direction',
|
||||||
|
]
|
||||||
|
|
||||||
|
[tr_TR]
|
||||||
|
ignore = [
|
||||||
|
'language.direction',
|
||||||
|
]
|
||||||
|
|
||||||
|
[uk_UA]
|
||||||
|
ignore = [
|
||||||
|
'language.direction',
|
||||||
|
]
|
||||||
|
|
||||||
|
[zh_CN]
|
||||||
|
ignore = [
|
||||||
|
'language.direction',
|
||||||
|
]
|
||||||
|
|
||||||
|
[zh_TW]
|
||||||
|
ignore = [
|
||||||
|
'language.direction',
|
||||||
|
]
|
|
@ -62,6 +62,7 @@ public class SPdfApplication {
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
||||||
app.addInitializers(new ConfigInitializer());
|
app.addInitializers(new ConfigInitializer());
|
||||||
if (Files.exists(Paths.get("configs/settings.yml"))) {
|
if (Files.exists(Paths.get("configs/settings.yml"))) {
|
||||||
|
|
|
@ -6,18 +6,35 @@ import java.nio.file.Paths;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
|
||||||
|
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.Lazy;
|
||||||
import org.springframework.core.io.ClassPathResource;
|
import org.springframework.core.io.ClassPathResource;
|
||||||
import org.springframework.core.io.Resource;
|
import org.springframework.core.io.Resource;
|
||||||
|
import org.springframework.core.io.ResourceLoader;
|
||||||
|
import org.thymeleaf.spring6.SpringTemplateEngine;
|
||||||
|
|
||||||
import stirling.software.SPDF.model.ApplicationProperties;
|
import stirling.software.SPDF.model.ApplicationProperties;
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
|
@Lazy
|
||||||
public class AppConfig {
|
public class AppConfig {
|
||||||
|
|
||||||
@Autowired ApplicationProperties applicationProperties;
|
@Autowired ApplicationProperties applicationProperties;
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@ConditionalOnProperty(
|
||||||
|
name = "system.customHTMLFiles",
|
||||||
|
havingValue = "true",
|
||||||
|
matchIfMissing = false)
|
||||||
|
public SpringTemplateEngine templateEngine(ResourceLoader resourceLoader) {
|
||||||
|
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
|
||||||
|
templateEngine.addTemplateResolver(new FileFallbackTemplateResolver(resourceLoader));
|
||||||
|
return templateEngine;
|
||||||
|
}
|
||||||
|
|
||||||
@Bean(name = "loginEnabled")
|
@Bean(name = "loginEnabled")
|
||||||
public boolean loginEnabled() {
|
public boolean loginEnabled() {
|
||||||
return applicationProperties.getSecurity().getEnableLogin();
|
return applicationProperties.getSecurity().getEnableLogin();
|
||||||
|
@ -85,4 +102,10 @@ public class AppConfig {
|
||||||
}
|
}
|
||||||
return "true".equalsIgnoreCase(installOps);
|
return "true".equalsIgnoreCase(installOps);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ConditionalOnMissingClass("stirling.software.SPDF.config.security.SecurityConfiguration")
|
||||||
|
@Bean(name = "activSecurity")
|
||||||
|
public boolean missingActivSecurity() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
package stirling.software.SPDF.config;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Scope;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import stirling.software.SPDF.model.ApplicationProperties;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
class AppUpdateService {
|
||||||
|
|
||||||
|
@Autowired private ApplicationProperties applicationProperties;
|
||||||
|
|
||||||
|
@Autowired(required = false)
|
||||||
|
ShowAdminInterface showAdmin;
|
||||||
|
|
||||||
|
@Bean(name = "shouldShow")
|
||||||
|
@Scope("request")
|
||||||
|
public boolean shouldShow() {
|
||||||
|
boolean showUpdate = applicationProperties.getSystem().getShowUpdate();
|
||||||
|
boolean showAdminResult = (showAdmin != null) ? showAdmin.getShowUpdateOnlyAdmins() : true;
|
||||||
|
return showUpdate && showAdminResult;
|
||||||
|
}
|
||||||
|
}
|
|
@ -146,7 +146,6 @@ public class EndpointConfiguration {
|
||||||
addEndpointToGroup("CLI", "xlsx-to-pdf");
|
addEndpointToGroup("CLI", "xlsx-to-pdf");
|
||||||
addEndpointToGroup("CLI", "pdf-to-word");
|
addEndpointToGroup("CLI", "pdf-to-word");
|
||||||
addEndpointToGroup("CLI", "pdf-to-presentation");
|
addEndpointToGroup("CLI", "pdf-to-presentation");
|
||||||
addEndpointToGroup("CLI", "pdf-to-text");
|
|
||||||
addEndpointToGroup("CLI", "pdf-to-html");
|
addEndpointToGroup("CLI", "pdf-to-html");
|
||||||
addEndpointToGroup("CLI", "pdf-to-xml");
|
addEndpointToGroup("CLI", "pdf-to-xml");
|
||||||
addEndpointToGroup("CLI", "ocr-pdf");
|
addEndpointToGroup("CLI", "ocr-pdf");
|
||||||
|
@ -154,6 +153,7 @@ public class EndpointConfiguration {
|
||||||
addEndpointToGroup("CLI", "url-to-pdf");
|
addEndpointToGroup("CLI", "url-to-pdf");
|
||||||
addEndpointToGroup("CLI", "book-to-pdf");
|
addEndpointToGroup("CLI", "book-to-pdf");
|
||||||
addEndpointToGroup("CLI", "pdf-to-book");
|
addEndpointToGroup("CLI", "pdf-to-book");
|
||||||
|
addEndpointToGroup("CLI", "pdf-to-rtf");
|
||||||
|
|
||||||
// Calibre
|
// Calibre
|
||||||
addEndpointToGroup("Calibre", "book-to-pdf");
|
addEndpointToGroup("Calibre", "book-to-pdf");
|
||||||
|
@ -175,7 +175,7 @@ public class EndpointConfiguration {
|
||||||
addEndpointToGroup("LibreOffice", "xlsx-to-pdf");
|
addEndpointToGroup("LibreOffice", "xlsx-to-pdf");
|
||||||
addEndpointToGroup("LibreOffice", "pdf-to-word");
|
addEndpointToGroup("LibreOffice", "pdf-to-word");
|
||||||
addEndpointToGroup("LibreOffice", "pdf-to-presentation");
|
addEndpointToGroup("LibreOffice", "pdf-to-presentation");
|
||||||
addEndpointToGroup("LibreOffice", "pdf-to-text");
|
addEndpointToGroup("LibreOffice", "pdf-to-rtf");
|
||||||
addEndpointToGroup("LibreOffice", "pdf-to-html");
|
addEndpointToGroup("LibreOffice", "pdf-to-html");
|
||||||
addEndpointToGroup("LibreOffice", "pdf-to-xml");
|
addEndpointToGroup("LibreOffice", "pdf-to-xml");
|
||||||
|
|
||||||
|
@ -218,6 +218,7 @@ public class EndpointConfiguration {
|
||||||
addEndpointToGroup("Java", "overlay-pdf");
|
addEndpointToGroup("Java", "overlay-pdf");
|
||||||
addEndpointToGroup("Java", "split-pdf-by-sections");
|
addEndpointToGroup("Java", "split-pdf-by-sections");
|
||||||
addEndpointToGroup("Java", REMOVE_BLANKS);
|
addEndpointToGroup("Java", REMOVE_BLANKS);
|
||||||
|
addEndpointToGroup("Java", "pdf-to-text");
|
||||||
|
|
||||||
// Javascript
|
// Javascript
|
||||||
addEndpointToGroup("Javascript", "pdf-organizer");
|
addEndpointToGroup("Javascript", "pdf-organizer");
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
package stirling.software.SPDF.config;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.springframework.core.io.Resource;
|
||||||
|
import org.springframework.core.io.ResourceLoader;
|
||||||
|
import org.thymeleaf.IEngineConfiguration;
|
||||||
|
import org.thymeleaf.templateresolver.AbstractConfigurableTemplateResolver;
|
||||||
|
import org.thymeleaf.templateresource.ClassLoaderTemplateResource;
|
||||||
|
import org.thymeleaf.templateresource.FileTemplateResource;
|
||||||
|
import org.thymeleaf.templateresource.ITemplateResource;
|
||||||
|
|
||||||
|
public class FileFallbackTemplateResolver extends AbstractConfigurableTemplateResolver {
|
||||||
|
|
||||||
|
private final ResourceLoader resourceLoader;
|
||||||
|
|
||||||
|
public FileFallbackTemplateResolver(ResourceLoader resourceLoader) {
|
||||||
|
super();
|
||||||
|
this.resourceLoader = resourceLoader;
|
||||||
|
setSuffix(".html");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note this does not work in local IDE, Prod jar only.
|
||||||
|
@Override
|
||||||
|
protected ITemplateResource computeTemplateResource(
|
||||||
|
IEngineConfiguration configuration,
|
||||||
|
String ownerTemplate,
|
||||||
|
String template,
|
||||||
|
String resourceName,
|
||||||
|
String characterEncoding,
|
||||||
|
Map<String, Object> templateResolutionAttributes) {
|
||||||
|
Resource resource =
|
||||||
|
resourceLoader.getResource("file:./customFiles/templates/" + resourceName);
|
||||||
|
try {
|
||||||
|
if (resource.exists() && resource.isReadable()) {
|
||||||
|
return new FileTemplateResource(resource.getFile().getPath(), characterEncoding);
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ClassLoaderTemplateResource(
|
||||||
|
Thread.currentThread().getContextClassLoader(),
|
||||||
|
"classpath:/templates/" + resourceName,
|
||||||
|
characterEncoding);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
package stirling.software.SPDF.config;
|
||||||
|
|
||||||
|
public interface ShowAdminInterface {
|
||||||
|
default boolean getShowUpdateOnlyAdmins() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
package stirling.software.SPDF.config.security;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import stirling.software.SPDF.config.ShowAdminInterface;
|
||||||
|
import stirling.software.SPDF.model.ApplicationProperties;
|
||||||
|
import stirling.software.SPDF.model.User;
|
||||||
|
import stirling.software.SPDF.repository.UserRepository;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
class AppUpdateAuthService implements ShowAdminInterface {
|
||||||
|
|
||||||
|
@Autowired private UserRepository userRepository;
|
||||||
|
@Autowired private ApplicationProperties applicationProperties;
|
||||||
|
|
||||||
|
public boolean getShowUpdateOnlyAdmins() {
|
||||||
|
boolean showUpdate = applicationProperties.getSystem().getShowUpdate();
|
||||||
|
if (!showUpdate) {
|
||||||
|
return showUpdate;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean showUpdateOnlyAdmin = applicationProperties.getSystem().getShowUpdateOnlyAdmin();
|
||||||
|
|
||||||
|
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||||
|
|
||||||
|
if (authentication == null || !authentication.isAuthenticated()) {
|
||||||
|
return !showUpdateOnlyAdmin;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (authentication.getName().equalsIgnoreCase("anonymousUser")) {
|
||||||
|
return !showUpdateOnlyAdmin;
|
||||||
|
}
|
||||||
|
|
||||||
|
Optional<User> user = userRepository.findByUsername(authentication.getName());
|
||||||
|
if (user.isPresent() && showUpdateOnlyAdmin) {
|
||||||
|
return "ROLE_ADMIN".equals(user.get().getRolesAsString());
|
||||||
|
}
|
||||||
|
|
||||||
|
return showUpdate;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
package stirling.software.SPDF.config.security;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import jakarta.servlet.http.HttpSession;
|
||||||
|
import jakarta.servlet.ServletException;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.core.session.SessionRegistry;
|
||||||
|
import org.springframework.security.core.session.SessionRegistryImpl;
|
||||||
|
import org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler;
|
||||||
|
|
||||||
|
public class CustomLogoutSuccessHandler extends SimpleUrlLogoutSuccessHandler
|
||||||
|
{
|
||||||
|
@Bean
|
||||||
|
public SessionRegistry sessionRegistry() {
|
||||||
|
return new SessionRegistryImpl();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException
|
||||||
|
{
|
||||||
|
HttpSession session = request.getSession(false);
|
||||||
|
if (session != null) {
|
||||||
|
String sessionId = session.getId();
|
||||||
|
sessionRegistry()
|
||||||
|
.removeSessionInformation(
|
||||||
|
sessionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(request.getParameter("oauth2AutoCreateDisabled") != null)
|
||||||
|
{
|
||||||
|
response.sendRedirect(request.getContextPath()+"/login?error=oauth2AutoCreateDisabled");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
response.sendRedirect(request.getContextPath() + "/login?logout=true");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,11 @@
|
||||||
package stirling.software.SPDF.config.security;
|
package stirling.software.SPDF.config.security;
|
||||||
|
|
||||||
|
import jakarta.servlet.ServletException;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
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.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.context.annotation.Lazy;
|
||||||
|
@ -10,20 +14,30 @@ import org.springframework.security.config.annotation.method.configuration.Enabl
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||||
import org.springframework.security.config.http.SessionCreationPolicy;
|
import org.springframework.security.config.http.SessionCreationPolicy;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.core.session.SessionRegistry;
|
import org.springframework.security.core.session.SessionRegistry;
|
||||||
import org.springframework.security.core.session.SessionRegistryImpl;
|
import org.springframework.security.core.session.SessionRegistryImpl;
|
||||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
|
import org.springframework.security.oauth2.client.registration.ClientRegistration;
|
||||||
|
import org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository;
|
||||||
|
import org.springframework.security.oauth2.core.user.OAuth2User;
|
||||||
import org.springframework.security.web.SecurityFilterChain;
|
import org.springframework.security.web.SecurityFilterChain;
|
||||||
|
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
|
||||||
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;
|
||||||
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 org.springframework.security.oauth2.client.registration.ClientRegistrations;
|
||||||
|
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
|
||||||
|
|
||||||
import jakarta.servlet.http.HttpSession;
|
import jakarta.servlet.http.HttpSession;
|
||||||
|
import stirling.software.SPDF.model.ApplicationProperties;
|
||||||
import stirling.software.SPDF.repository.JPATokenRepositoryImpl;
|
import stirling.software.SPDF.repository.JPATokenRepositoryImpl;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableWebSecurity()
|
@EnableWebSecurity()
|
||||||
@EnableMethodSecurity
|
@EnableMethodSecurity
|
||||||
|
@ -42,6 +56,8 @@ public class SecurityConfiguration {
|
||||||
@Qualifier("loginEnabled")
|
@Qualifier("loginEnabled")
|
||||||
public boolean loginEnabledValue;
|
public boolean loginEnabledValue;
|
||||||
|
|
||||||
|
@Autowired ApplicationProperties applicationProperties;
|
||||||
|
|
||||||
@Autowired private UserAuthenticationFilter userAuthenticationFilter;
|
@Autowired private UserAuthenticationFilter userAuthenticationFilter;
|
||||||
|
|
||||||
@Autowired private LoginAttemptService loginAttemptService;
|
@Autowired private LoginAttemptService loginAttemptService;
|
||||||
|
@ -87,7 +103,7 @@ public class SecurityConfiguration {
|
||||||
logout ->
|
logout ->
|
||||||
logout.logoutRequestMatcher(
|
logout.logoutRequestMatcher(
|
||||||
new AntPathRequestMatcher("/logout"))
|
new AntPathRequestMatcher("/logout"))
|
||||||
.logoutSuccessUrl("/login?logout=true")
|
.logoutSuccessHandler(new CustomLogoutSuccessHandler()) // Use a Custom Logout Handler to handle custom error message if OAUTH2 Auto Create is disabled
|
||||||
.invalidateHttpSession(true) // Invalidate session
|
.invalidateHttpSession(true) // Invalidate session
|
||||||
.deleteCookies("JSESSIONID", "remember-me")
|
.deleteCookies("JSESSIONID", "remember-me")
|
||||||
.addLogoutHandler(
|
.addLogoutHandler(
|
||||||
|
@ -124,6 +140,7 @@ public class SecurityConfiguration {
|
||||||
: uri;
|
: uri;
|
||||||
|
|
||||||
return trimmedUri.startsWith("/login")
|
return trimmedUri.startsWith("/login")
|
||||||
|
|| trimmedUri.startsWith("/oauth")
|
||||||
|| trimmedUri.endsWith(".svg")
|
|| trimmedUri.endsWith(".svg")
|
||||||
|| trimmedUri.startsWith(
|
|| trimmedUri.startsWith(
|
||||||
"/register")
|
"/register")
|
||||||
|
@ -140,6 +157,33 @@ public class SecurityConfiguration {
|
||||||
.authenticated())
|
.authenticated())
|
||||||
.userDetailsService(userDetailsService)
|
.userDetailsService(userDetailsService)
|
||||||
.authenticationProvider(authenticationProvider());
|
.authenticationProvider(authenticationProvider());
|
||||||
|
|
||||||
|
// Handle OAUTH2 Logins
|
||||||
|
if (applicationProperties.getSecurity().getOAUTH2().getEnabled()) {
|
||||||
|
|
||||||
|
http.oauth2Login( oauth2 -> oauth2
|
||||||
|
.loginPage("/oauth2")
|
||||||
|
/*
|
||||||
|
This Custom handler is used to check if the OAUTH2 user trying to log in, already exists in the database.
|
||||||
|
If user exists, login proceeds as usual. If user does not exist, then it is autocreated but only if 'OAUTH2AutoCreateUser'
|
||||||
|
is set as true, else login fails with an error message advising the same.
|
||||||
|
*/
|
||||||
|
.successHandler(new AuthenticationSuccessHandler() {
|
||||||
|
@Override
|
||||||
|
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
|
||||||
|
Authentication authentication) throws ServletException , IOException{
|
||||||
|
OAuth2User oauthUser = (OAuth2User) authentication.getPrincipal();
|
||||||
|
if (userService.processOAuth2PostLogin(oauthUser.getAttribute("email"), applicationProperties.getSecurity().getOAUTH2().getAutoCreateUser())) {
|
||||||
|
response.sendRedirect("/");
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
response.sendRedirect("/logout?oauth2AutoCreateDisabled=true");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
http.csrf(csrf -> csrf.disable())
|
http.csrf(csrf -> csrf.disable())
|
||||||
.authorizeHttpRequests(authz -> authz.anyRequest().permitAll());
|
.authorizeHttpRequests(authz -> authz.anyRequest().permitAll());
|
||||||
|
@ -148,6 +192,24 @@ public class SecurityConfiguration {
|
||||||
return http.build();
|
return http.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Client Registration Repository for OAUTH2 OIDC Login
|
||||||
|
@Bean
|
||||||
|
@ConditionalOnProperty(value = "security.oauth2.enabled" , havingValue = "true", matchIfMissing = false)
|
||||||
|
public ClientRegistrationRepository clientRegistrationRepository() {
|
||||||
|
return new InMemoryClientRegistrationRepository(this.oidcClientRegistration());
|
||||||
|
}
|
||||||
|
|
||||||
|
private ClientRegistration oidcClientRegistration() {
|
||||||
|
return ClientRegistrations.fromOidcIssuerLocation(applicationProperties.getSecurity().getOAUTH2().getIssuer())
|
||||||
|
.registrationId("oidc")
|
||||||
|
.clientId(applicationProperties.getSecurity().getOAUTH2().getClientId())
|
||||||
|
.clientSecret(applicationProperties.getSecurity().getOAUTH2().getClientSecret())
|
||||||
|
.scope("openid", "profile", "email")
|
||||||
|
.userNameAttributeName("email")
|
||||||
|
.clientName("OIDC")
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public IPRateLimitingFilter rateLimitingFilter() {
|
public IPRateLimitingFilter rateLimitingFilter() {
|
||||||
int maxRequestsPerIp = 1000000; // Example limit TODO add config level
|
int maxRequestsPerIp = 1000000; // Example limit TODO add config level
|
||||||
|
@ -166,4 +228,9 @@ public class SecurityConfiguration {
|
||||||
public PersistentTokenRepository persistentTokenRepository() {
|
public PersistentTokenRepository persistentTokenRepository() {
|
||||||
return new JPATokenRepositoryImpl();
|
return new JPATokenRepositoryImpl();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public boolean activSecurity() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,24 @@ public class UserService implements UserServiceInterface {
|
||||||
|
|
||||||
@Autowired private PasswordEncoder passwordEncoder;
|
@Autowired private PasswordEncoder passwordEncoder;
|
||||||
|
|
||||||
|
// Handle OAUTH2 login and user auto creation.
|
||||||
|
public boolean processOAuth2PostLogin(String username, boolean autoCreateUser) {
|
||||||
|
Optional<User> existUser = userRepository.findByUsernameIgnoreCase(username);
|
||||||
|
if (existUser.isPresent()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (autoCreateUser) {
|
||||||
|
User user = new User();
|
||||||
|
user.setUsername(username);
|
||||||
|
user.setEnabled(true);
|
||||||
|
user.setFirstLogin(false);
|
||||||
|
user.addAuthority(new Authority( Role.USER.getRoleId(), user));
|
||||||
|
userRepository.save(user);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public Authentication getAuthentication(String apiKey) {
|
public Authentication getAuthentication(String apiKey) {
|
||||||
User user = getUserByApiKey(apiKey);
|
User user = getUserByApiKey(apiKey);
|
||||||
if (user == null) {
|
if (user == null) {
|
||||||
|
|
|
@ -4,8 +4,6 @@ import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.zip.ZipEntry;
|
import java.util.zip.ZipEntry;
|
||||||
import java.util.zip.ZipOutputStream;
|
import java.util.zip.ZipOutputStream;
|
||||||
|
|
||||||
|
@ -41,69 +39,114 @@ public class SplitPdfBySizeController {
|
||||||
+ " if 10MB and each page is 1MB and you enter 2MB then 5 docs each 2MB (rounded so that it accepts 1.9MB but not 2.1MB) Input:PDF Output:ZIP-PDF Type:SISO")
|
+ " if 10MB and each page is 1MB and you enter 2MB then 5 docs each 2MB (rounded so that it accepts 1.9MB but not 2.1MB) Input:PDF Output:ZIP-PDF Type:SISO")
|
||||||
public ResponseEntity<byte[]> autoSplitPdf(@ModelAttribute SplitPdfBySizeOrCountRequest request)
|
public ResponseEntity<byte[]> autoSplitPdf(@ModelAttribute SplitPdfBySizeOrCountRequest request)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
List<ByteArrayOutputStream> splitDocumentsBoas = new ArrayList<ByteArrayOutputStream>();
|
|
||||||
|
|
||||||
MultipartFile file = request.getFileInput();
|
MultipartFile file = request.getFileInput();
|
||||||
PDDocument sourceDocument = Loader.loadPDF(file.getBytes());
|
Path zipFile = Files.createTempFile("split_documents", ".zip");
|
||||||
|
String filename =
|
||||||
|
Filenames.toSimpleFileName(file.getOriginalFilename())
|
||||||
|
.replaceFirst("[.][^.]+$", "");
|
||||||
|
byte[] data = null;
|
||||||
|
try (ZipOutputStream zipOut = new ZipOutputStream(Files.newOutputStream(zipFile));
|
||||||
|
PDDocument sourceDocument = Loader.loadPDF(file.getBytes())) {
|
||||||
|
|
||||||
// 0 = size, 1 = page count, 2 = doc count
|
|
||||||
int type = request.getSplitType();
|
int type = request.getSplitType();
|
||||||
String value = request.getSplitValue();
|
String value = request.getSplitValue();
|
||||||
|
|
||||||
if (type == 0) { // Split by size
|
if (type == 0) {
|
||||||
long maxBytes = GeneralUtils.convertSizeToBytes(value);
|
long maxBytes = GeneralUtils.convertSizeToBytes(value);
|
||||||
|
handleSplitBySize(sourceDocument, maxBytes, zipOut, filename);
|
||||||
|
} else if (type == 1) {
|
||||||
|
int pageCount = Integer.parseInt(value);
|
||||||
|
handleSplitByPageCount(sourceDocument, pageCount, zipOut, filename);
|
||||||
|
} else if (type == 2) {
|
||||||
|
int documentCount = Integer.parseInt(value);
|
||||||
|
handleSplitByDocCount(sourceDocument, documentCount, zipOut, filename);
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException("Invalid argument for split type");
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} finally {
|
||||||
|
data = Files.readAllBytes(zipFile);
|
||||||
|
Files.deleteIfExists(zipFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
return WebResponseUtils.bytesToWebResponse(
|
||||||
|
data, filename + ".zip", MediaType.APPLICATION_OCTET_STREAM);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleSplitBySize(
|
||||||
|
PDDocument sourceDocument, long maxBytes, ZipOutputStream zipOut, String baseFilename)
|
||||||
|
throws IOException {
|
||||||
long currentSize = 0;
|
long currentSize = 0;
|
||||||
PDDocument currentDoc = new PDDocument();
|
PDDocument currentDoc = new PDDocument();
|
||||||
|
int fileIndex = 1;
|
||||||
|
|
||||||
for (PDPage page : sourceDocument.getPages()) {
|
for (int pageIndex = 0; pageIndex < sourceDocument.getNumberOfPages(); pageIndex++) {
|
||||||
|
PDPage page = sourceDocument.getPage(pageIndex);
|
||||||
ByteArrayOutputStream pageOutputStream = new ByteArrayOutputStream();
|
ByteArrayOutputStream pageOutputStream = new ByteArrayOutputStream();
|
||||||
PDDocument tempDoc = new PDDocument();
|
|
||||||
tempDoc.addPage(page);
|
try (PDDocument tempDoc = new PDDocument()) {
|
||||||
|
PDPage importedPage = tempDoc.importPage(page); // This creates a new PDPage object
|
||||||
tempDoc.save(pageOutputStream);
|
tempDoc.save(pageOutputStream);
|
||||||
tempDoc.close();
|
}
|
||||||
|
|
||||||
long pageSize = pageOutputStream.size();
|
long pageSize = pageOutputStream.size();
|
||||||
if (currentSize + pageSize > maxBytes) {
|
if (currentSize + pageSize > maxBytes) {
|
||||||
// Save and reset current document
|
if (currentDoc.getNumberOfPages() > 0) {
|
||||||
splitDocumentsBoas.add(currentDocToByteArray(currentDoc));
|
saveDocumentToZip(currentDoc, zipOut, baseFilename, fileIndex++);
|
||||||
|
currentDoc.close(); // Make sure to close the document
|
||||||
currentDoc = new PDDocument();
|
currentDoc = new PDDocument();
|
||||||
currentSize = 0;
|
currentSize = 0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
currentDoc.addPage(page);
|
PDPage newPage = new PDPage(page.getCOSObject()); // Re-create the page
|
||||||
|
currentDoc.addPage(newPage);
|
||||||
currentSize += pageSize;
|
currentSize += pageSize;
|
||||||
}
|
}
|
||||||
// Add the last document if it contains any pages
|
|
||||||
if (currentDoc.getPages().getCount() != 0) {
|
if (currentDoc.getNumberOfPages() != 0) {
|
||||||
splitDocumentsBoas.add(currentDocToByteArray(currentDoc));
|
saveDocumentToZip(currentDoc, zipOut, baseFilename, fileIndex++);
|
||||||
|
currentDoc.close();
|
||||||
}
|
}
|
||||||
} else if (type == 1) { // Split by page count
|
}
|
||||||
int pageCount = Integer.parseInt(value);
|
|
||||||
|
private void handleSplitByPageCount(
|
||||||
|
PDDocument sourceDocument, int pageCount, ZipOutputStream zipOut, String baseFilename)
|
||||||
|
throws IOException {
|
||||||
int currentPageCount = 0;
|
int currentPageCount = 0;
|
||||||
PDDocument currentDoc = new PDDocument();
|
PDDocument currentDoc = new PDDocument();
|
||||||
|
int fileIndex = 1;
|
||||||
for (PDPage page : sourceDocument.getPages()) {
|
for (PDPage page : sourceDocument.getPages()) {
|
||||||
currentDoc.addPage(page);
|
currentDoc.addPage(page);
|
||||||
currentPageCount++;
|
currentPageCount++;
|
||||||
|
|
||||||
if (currentPageCount == pageCount) {
|
if (currentPageCount == pageCount) {
|
||||||
// Save and reset current document
|
// Save and reset current document
|
||||||
splitDocumentsBoas.add(currentDocToByteArray(currentDoc));
|
saveDocumentToZip(currentDoc, zipOut, baseFilename, fileIndex++);
|
||||||
currentDoc = new PDDocument();
|
currentDoc = new PDDocument();
|
||||||
currentPageCount = 0;
|
currentPageCount = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Add the last document if it contains any pages
|
// Add the last document if it contains any pages
|
||||||
if (currentDoc.getPages().getCount() != 0) {
|
if (currentDoc.getPages().getCount() != 0) {
|
||||||
splitDocumentsBoas.add(currentDocToByteArray(currentDoc));
|
saveDocumentToZip(currentDoc, zipOut, baseFilename, fileIndex++);
|
||||||
}
|
}
|
||||||
} else if (type == 2) { // Split by doc count
|
}
|
||||||
int documentCount = Integer.parseInt(value);
|
|
||||||
|
private void handleSplitByDocCount(
|
||||||
|
PDDocument sourceDocument,
|
||||||
|
int documentCount,
|
||||||
|
ZipOutputStream zipOut,
|
||||||
|
String baseFilename)
|
||||||
|
throws IOException {
|
||||||
int totalPageCount = sourceDocument.getNumberOfPages();
|
int totalPageCount = sourceDocument.getNumberOfPages();
|
||||||
int pagesPerDocument = totalPageCount / documentCount;
|
int pagesPerDocument = totalPageCount / documentCount;
|
||||||
int extraPages = totalPageCount % documentCount;
|
int extraPages = totalPageCount % documentCount;
|
||||||
int currentPageIndex = 0;
|
int currentPageIndex = 0;
|
||||||
|
int fileIndex = 1;
|
||||||
for (int i = 0; i < documentCount; i++) {
|
for (int i = 0; i < documentCount; i++) {
|
||||||
PDDocument currentDoc = new PDDocument();
|
PDDocument currentDoc = new PDDocument();
|
||||||
int pagesToAdd = pagesPerDocument + (i < extraPages ? 1 : 0);
|
int pagesToAdd = pagesPerDocument + (i < extraPages ? 1 : 0);
|
||||||
|
@ -112,46 +155,21 @@ public class SplitPdfBySizeController {
|
||||||
currentDoc.addPage(sourceDocument.getPage(currentPageIndex++));
|
currentDoc.addPage(sourceDocument.getPage(currentPageIndex++));
|
||||||
}
|
}
|
||||||
|
|
||||||
splitDocumentsBoas.add(currentDocToByteArray(currentDoc));
|
saveDocumentToZip(currentDoc, zipOut, baseFilename, fileIndex++);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
throw new IllegalArgumentException("Invalid argument for split type");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sourceDocument.close();
|
private void saveDocumentToZip(
|
||||||
|
PDDocument document, ZipOutputStream zipOut, String baseFilename, int index)
|
||||||
|
throws IOException {
|
||||||
|
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
|
||||||
|
document.save(outStream);
|
||||||
|
document.close(); // Close the document to free resources
|
||||||
|
|
||||||
Path zipFile = Files.createTempFile("split_documents", ".zip");
|
// Create a new zip entry
|
||||||
String filename =
|
ZipEntry zipEntry = new ZipEntry(baseFilename + "_" + index + ".pdf");
|
||||||
Filenames.toSimpleFileName(file.getOriginalFilename())
|
zipOut.putNextEntry(zipEntry);
|
||||||
.replaceFirst("[.][^.]+$", "");
|
zipOut.write(outStream.toByteArray());
|
||||||
byte[] data;
|
|
||||||
|
|
||||||
try (ZipOutputStream zipOut = new ZipOutputStream(Files.newOutputStream(zipFile))) {
|
|
||||||
for (int i = 0; i < splitDocumentsBoas.size(); i++) {
|
|
||||||
String fileName = filename + "_" + (i + 1) + ".pdf";
|
|
||||||
ByteArrayOutputStream baos = splitDocumentsBoas.get(i);
|
|
||||||
byte[] pdf = baos.toByteArray();
|
|
||||||
|
|
||||||
ZipEntry pdfEntry = new ZipEntry(fileName);
|
|
||||||
zipOut.putNextEntry(pdfEntry);
|
|
||||||
zipOut.write(pdf);
|
|
||||||
zipOut.closeEntry();
|
zipOut.closeEntry();
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
} finally {
|
|
||||||
data = Files.readAllBytes(zipFile);
|
|
||||||
Files.delete(zipFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
return WebResponseUtils.bytesToWebResponse(
|
|
||||||
data, filename + ".zip", MediaType.APPLICATION_OCTET_STREAM);
|
|
||||||
}
|
|
||||||
|
|
||||||
private ByteArrayOutputStream currentDocToByteArray(PDDocument document) throws IOException {
|
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
|
||||||
document.save(baos);
|
|
||||||
document.close();
|
|
||||||
return baos;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,10 +6,6 @@ import java.net.URLConnection;
|
||||||
import org.apache.pdfbox.rendering.ImageType;
|
import org.apache.pdfbox.rendering.ImageType;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.core.io.ByteArrayResource;
|
|
||||||
import org.springframework.core.io.Resource;
|
|
||||||
import org.springframework.http.HttpHeaders;
|
|
||||||
import org.springframework.http.HttpStatus;
|
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||||
|
@ -39,7 +35,7 @@ public class ConvertImgPDFController {
|
||||||
summary = "Convert PDF to image(s)",
|
summary = "Convert PDF to image(s)",
|
||||||
description =
|
description =
|
||||||
"This endpoint converts a PDF file to image(s) with the specified image format, color type, and DPI. Users can choose to get a single image or multiple images. Input:PDF Output:Image Type:SI-Conditional")
|
"This endpoint converts a PDF file to image(s) with the specified image format, color type, and DPI. Users can choose to get a single image or multiple images. Input:PDF Output:Image Type:SI-Conditional")
|
||||||
public ResponseEntity<Resource> convertToImage(@ModelAttribute ConvertToImageRequest request)
|
public ResponseEntity<byte[]> convertToImage(@ModelAttribute ConvertToImageRequest request)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
MultipartFile file = request.getFileInput();
|
MultipartFile file = request.getFileInput();
|
||||||
String imageFormat = request.getImageFormat();
|
String imageFormat = request.getImageFormat();
|
||||||
|
@ -76,22 +72,15 @@ public class ConvertImgPDFController {
|
||||||
// TODO Auto-generated catch block
|
// TODO Auto-generated catch block
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (singleImage) {
|
if (singleImage) {
|
||||||
HttpHeaders headers = new HttpHeaders();
|
String docName = filename + "." + imageFormat;
|
||||||
headers.setContentType(MediaType.parseMediaType(getMediaType(imageFormat)));
|
MediaType mediaType = MediaType.parseMediaType(getMediaType(imageFormat));
|
||||||
ResponseEntity<Resource> response =
|
return WebResponseUtils.bytesToWebResponse(result, docName, mediaType);
|
||||||
new ResponseEntity<>(new ByteArrayResource(result), headers, HttpStatus.OK);
|
|
||||||
return response;
|
|
||||||
} else {
|
} else {
|
||||||
ByteArrayResource resource = new ByteArrayResource(result);
|
String zipFilename = filename + "_convertedToImages.zip";
|
||||||
// return the Resource in the response
|
return WebResponseUtils.bytesToWebResponse(
|
||||||
return ResponseEntity.ok()
|
result, zipFilename, MediaType.APPLICATION_OCTET_STREAM);
|
||||||
.header(
|
|
||||||
HttpHeaders.CONTENT_DISPOSITION,
|
|
||||||
"attachment; filename=" + filename + "_convertedToImages.zip")
|
|
||||||
.contentType(MediaType.APPLICATION_OCTET_STREAM)
|
|
||||||
.contentLength(resource.contentLength())
|
|
||||||
.body(resource);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ import io.github.pixee.security.Filenames;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
|
||||||
import stirling.software.SPDF.model.api.PDFFile;
|
import stirling.software.SPDF.model.api.converters.PdfToPdfARequest;
|
||||||
import stirling.software.SPDF.utils.ProcessExecutor;
|
import stirling.software.SPDF.utils.ProcessExecutor;
|
||||||
import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult;
|
import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult;
|
||||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
@ -31,8 +31,10 @@ public class ConvertPDFToPDFA {
|
||||||
summary = "Convert a PDF to a PDF/A",
|
summary = "Convert a PDF to a PDF/A",
|
||||||
description =
|
description =
|
||||||
"This endpoint converts a PDF file to a PDF/A file. PDF/A is a format designed for long-term archiving of digital documents. Input:PDF Output:PDF Type:SISO")
|
"This endpoint converts a PDF file to a PDF/A file. PDF/A is a format designed for long-term archiving of digital documents. Input:PDF Output:PDF Type:SISO")
|
||||||
public ResponseEntity<byte[]> pdfToPdfA(@ModelAttribute PDFFile request) throws Exception {
|
public ResponseEntity<byte[]> pdfToPdfA(@ModelAttribute PdfToPdfARequest request)
|
||||||
|
throws Exception {
|
||||||
MultipartFile inputFile = request.getFileInput();
|
MultipartFile inputFile = request.getFileInput();
|
||||||
|
String outputFormat = request.getOutputFormat();
|
||||||
|
|
||||||
// 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");
|
||||||
|
@ -47,7 +49,7 @@ public class ConvertPDFToPDFA {
|
||||||
command.add("--skip-text");
|
command.add("--skip-text");
|
||||||
command.add("--tesseract-timeout=0");
|
command.add("--tesseract-timeout=0");
|
||||||
command.add("--output-type");
|
command.add("--output-type");
|
||||||
command.add("pdfa");
|
command.add(outputFormat.toString());
|
||||||
command.add(tempInputFile.toString());
|
command.add(tempInputFile.toString());
|
||||||
command.add(tempOutputFile.toString());
|
command.add(tempOutputFile.toString());
|
||||||
|
|
||||||
|
|
|
@ -1,27 +1,29 @@
|
||||||
package stirling.software.SPDF.controller.api.misc;
|
package stirling.software.SPDF.controller.api.misc;
|
||||||
|
|
||||||
|
import java.awt.AlphaComposite;
|
||||||
|
import java.awt.BasicStroke;
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
|
import java.awt.GradientPaint;
|
||||||
|
import java.awt.Graphics2D;
|
||||||
|
import java.awt.RenderingHints;
|
||||||
import java.awt.geom.AffineTransform;
|
import java.awt.geom.AffineTransform;
|
||||||
|
import java.awt.geom.Ellipse2D;
|
||||||
|
import java.awt.geom.Path2D;
|
||||||
import java.awt.image.AffineTransformOp;
|
import java.awt.image.AffineTransformOp;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.awt.image.BufferedImageOp;
|
import java.awt.image.BufferedImageOp;
|
||||||
import java.awt.image.ConvolveOp;
|
import java.awt.image.ConvolveOp;
|
||||||
import java.awt.image.Kernel;
|
import java.awt.image.Kernel;
|
||||||
import java.awt.image.RescaleOp;
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
|
||||||
import javax.imageio.ImageIO;
|
|
||||||
|
|
||||||
import org.apache.pdfbox.Loader;
|
import org.apache.pdfbox.Loader;
|
||||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
import org.apache.pdfbox.pdmodel.PDPage;
|
import org.apache.pdfbox.pdmodel.graphics.image.JPEGFactory;
|
||||||
import org.apache.pdfbox.pdmodel.PDPageContentStream;
|
|
||||||
import org.apache.pdfbox.pdmodel.common.PDRectangle;
|
|
||||||
import org.apache.pdfbox.pdmodel.graphics.image.LosslessFactory;
|
|
||||||
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
|
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
|
||||||
import org.apache.pdfbox.rendering.ImageType;
|
import org.apache.pdfbox.rendering.ImageType;
|
||||||
import org.apache.pdfbox.rendering.PDFRenderer;
|
import org.apache.pdfbox.rendering.PDFRenderer;
|
||||||
|
@ -29,6 +31,7 @@ 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.annotation.ModelAttribute;
|
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.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;
|
||||||
|
@ -39,6 +42,7 @@ import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
|
||||||
import stirling.software.SPDF.model.api.PDFFile;
|
import stirling.software.SPDF.model.api.PDFFile;
|
||||||
|
import stirling.software.SPDF.utils.PdfUtils;
|
||||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
|
@ -48,98 +52,39 @@ public class FakeScanControllerWIP {
|
||||||
|
|
||||||
private static final Logger logger = LoggerFactory.getLogger(FakeScanControllerWIP.class);
|
private static final Logger logger = LoggerFactory.getLogger(FakeScanControllerWIP.class);
|
||||||
|
|
||||||
// TODO
|
// TODO finish
|
||||||
|
@PostMapping(consumes = "multipart/form-data", value = "/fake-scan")
|
||||||
@Hidden
|
@Hidden
|
||||||
// @PostMapping(consumes = "multipart/form-data", value = "/fakeScan")
|
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Repair a PDF file",
|
summary = "Repair a PDF file",
|
||||||
description =
|
description =
|
||||||
"This endpoint repairs a given PDF file by running Ghostscript command. The PDF is first saved to a temporary location, repaired, read back, and then returned as a response.")
|
"This endpoint repairs a given PDF file by running Ghostscript command. The PDF is first saved to a temporary location, repaired, read back, and then returned as a response.")
|
||||||
public ResponseEntity<byte[]> repairPdf(@ModelAttribute PDFFile request) throws IOException {
|
public ResponseEntity<byte[]> fakeScan(@ModelAttribute PDFFile request) throws IOException {
|
||||||
MultipartFile inputFile = request.getFileInput();
|
MultipartFile inputFile = request.getFileInput();
|
||||||
|
|
||||||
|
// Load the PDF document
|
||||||
PDDocument document = Loader.loadPDF(inputFile.getBytes());
|
PDDocument document = Loader.loadPDF(inputFile.getBytes());
|
||||||
PDFRenderer pdfRenderer = new PDFRenderer(document);
|
PDFRenderer renderer = new PDFRenderer(document);
|
||||||
pdfRenderer.setSubsamplingAllowed(true);
|
List<BufferedImage> images = new ArrayList<>();
|
||||||
for (int page = 0; page < document.getNumberOfPages(); ++page) {
|
// Convert each page to an image
|
||||||
BufferedImage image = pdfRenderer.renderImageWithDPI(page, 300, ImageType.RGB);
|
for (int i = 0; i < document.getNumberOfPages(); i++) {
|
||||||
ImageIO.write(image, "png", new File("scanned-" + (page + 1) + ".png"));
|
BufferedImage image = renderer.renderImageWithDPI(i, 150, ImageType.GRAY);
|
||||||
|
images.add(processImage(image));
|
||||||
}
|
}
|
||||||
document.close();
|
document.close();
|
||||||
|
|
||||||
// Constants
|
// Create a new PDF document with the processed images
|
||||||
int scannedness = 90; // Value between 0 and 100
|
|
||||||
int dirtiness = 0; // Value between 0 and 100
|
|
||||||
|
|
||||||
// Load the source image
|
|
||||||
BufferedImage sourceImage = ImageIO.read(new File("scanned-1.png"));
|
|
||||||
|
|
||||||
// Create the destination image
|
|
||||||
BufferedImage destinationImage =
|
|
||||||
new BufferedImage(
|
|
||||||
sourceImage.getWidth(), sourceImage.getHeight(), sourceImage.getType());
|
|
||||||
|
|
||||||
// Apply a brightness and contrast effect based on the "scanned-ness"
|
|
||||||
float scaleFactor = 1.0f + (scannedness / 100.0f) * 0.5f; // Between 1.0 and 1.5
|
|
||||||
float offset = scannedness * 1.5f; // Between 0 and 150
|
|
||||||
BufferedImageOp op = new RescaleOp(scaleFactor, offset, null);
|
|
||||||
op.filter(sourceImage, destinationImage);
|
|
||||||
|
|
||||||
// Apply a rotation effect
|
|
||||||
double rotationRequired =
|
|
||||||
Math.toRadians(
|
|
||||||
(new SecureRandom().nextInt(3 - 1)
|
|
||||||
+ 1)); // Random angle between 1 and 3 degrees
|
|
||||||
double locationX = destinationImage.getWidth() / 2;
|
|
||||||
double locationY = destinationImage.getHeight() / 2;
|
|
||||||
AffineTransform tx =
|
|
||||||
AffineTransform.getRotateInstance(rotationRequired, locationX, locationY);
|
|
||||||
AffineTransformOp rotateOp = new AffineTransformOp(tx, AffineTransformOp.TYPE_BILINEAR);
|
|
||||||
destinationImage = rotateOp.filter(destinationImage, null);
|
|
||||||
|
|
||||||
// Apply a blur effect based on the "scanned-ness"
|
|
||||||
float blurIntensity = scannedness / 100.0f * 0.2f; // Between 0.0 and 0.2
|
|
||||||
float[] matrix = {
|
|
||||||
blurIntensity, blurIntensity, blurIntensity,
|
|
||||||
blurIntensity, blurIntensity, blurIntensity,
|
|
||||||
blurIntensity, blurIntensity, blurIntensity
|
|
||||||
};
|
|
||||||
BufferedImageOp blurOp =
|
|
||||||
new ConvolveOp(new Kernel(3, 3, matrix), ConvolveOp.EDGE_NO_OP, null);
|
|
||||||
destinationImage = blurOp.filter(destinationImage, null);
|
|
||||||
|
|
||||||
// Add noise to the image based on the "dirtiness"
|
|
||||||
Random random = new SecureRandom();
|
|
||||||
for (int y = 0; y < destinationImage.getHeight(); y++) {
|
|
||||||
for (int x = 0; x < destinationImage.getWidth(); x++) {
|
|
||||||
if (random.nextInt(100) < dirtiness) {
|
|
||||||
// Change the pixel color to black randomly based on the "dirtiness"
|
|
||||||
destinationImage.setRGB(x, y, Color.BLACK.getRGB());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save the image
|
|
||||||
ImageIO.write(destinationImage, "PNG", new File("scanned-1.png"));
|
|
||||||
|
|
||||||
PDDocument documentOut = new PDDocument();
|
|
||||||
for (int page = 1; page <= document.getNumberOfPages(); ++page) {
|
|
||||||
BufferedImage bim = ImageIO.read(new File("scanned-" + page + ".png"));
|
|
||||||
|
|
||||||
// Adjust the dimensions of the page
|
|
||||||
PDPage pdPage = new PDPage(new PDRectangle(bim.getWidth() - 1, bim.getHeight() - 1));
|
|
||||||
documentOut.addPage(pdPage);
|
|
||||||
|
|
||||||
PDImageXObject pdImage = LosslessFactory.createFromImage(documentOut, bim);
|
|
||||||
PDPageContentStream contentStream = new PDPageContentStream(documentOut, pdPage);
|
|
||||||
|
|
||||||
// Draw the image with a slight offset and enlarged dimensions
|
|
||||||
contentStream.drawImage(pdImage, -1, -1, bim.getWidth() + 2, bim.getHeight() + 2);
|
|
||||||
contentStream.close();
|
|
||||||
}
|
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
documentOut.save(baos);
|
PDDocument newDocument = new PDDocument();
|
||||||
documentOut.close();
|
for (BufferedImage img : images) {
|
||||||
|
// PDPageContentStream contentStream = new PDPageContentStream(newDocument, new
|
||||||
|
// PDPage());
|
||||||
|
PDImageXObject pdImage = JPEGFactory.createFromImage(newDocument, img);
|
||||||
|
PdfUtils.addImageToDocument(newDocument, pdImage, "maintainAspectRatio", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
newDocument.save(baos);
|
||||||
|
newDocument.close();
|
||||||
|
|
||||||
// Return the optimized PDF as a response
|
// Return the optimized PDF as a response
|
||||||
String outputFilename =
|
String outputFilename =
|
||||||
|
@ -148,4 +93,232 @@ public class FakeScanControllerWIP {
|
||||||
+ "_scanned.pdf";
|
+ "_scanned.pdf";
|
||||||
return WebResponseUtils.boasToWebResponse(baos, outputFilename);
|
return WebResponseUtils.boasToWebResponse(baos, outputFilename);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public BufferedImage processImage(BufferedImage image) {
|
||||||
|
// Rotation
|
||||||
|
|
||||||
|
image = softenEdges(image, 50);
|
||||||
|
image = rotate(image, 1);
|
||||||
|
|
||||||
|
image = applyGaussianBlur(image, 0.5);
|
||||||
|
addGaussianNoise(image, 0.5);
|
||||||
|
image = linearStretch(image);
|
||||||
|
addDustAndHairs(image, 3);
|
||||||
|
return image;
|
||||||
|
}
|
||||||
|
|
||||||
|
private BufferedImage rotate(BufferedImage image, double rotation) {
|
||||||
|
|
||||||
|
double rotationRequired = Math.toRadians(rotation);
|
||||||
|
double locationX = image.getWidth() / 2;
|
||||||
|
double locationY = image.getHeight() / 2;
|
||||||
|
AffineTransform tx =
|
||||||
|
AffineTransform.getRotateInstance(rotationRequired, locationX, locationY);
|
||||||
|
AffineTransformOp op = new AffineTransformOp(tx, AffineTransformOp.TYPE_BICUBIC);
|
||||||
|
return op.filter(image, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private BufferedImage applyGaussianBlur(BufferedImage image, double sigma) {
|
||||||
|
int radius = 3; // Fixed radius size for simplicity
|
||||||
|
|
||||||
|
int size = 2 * radius + 1;
|
||||||
|
float[] data = new float[size * size];
|
||||||
|
double sum = 0.0;
|
||||||
|
|
||||||
|
for (int i = -radius; i <= radius; i++) {
|
||||||
|
for (int j = -radius; j <= radius; j++) {
|
||||||
|
double xDistance = i * i;
|
||||||
|
double yDistance = j * j;
|
||||||
|
double g = Math.exp(-(xDistance + yDistance) / (2 * sigma * sigma));
|
||||||
|
data[(i + radius) * size + j + radius] = (float) g;
|
||||||
|
sum += g;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Normalize the kernel
|
||||||
|
for (int i = 0; i < data.length; i++) {
|
||||||
|
data[i] /= sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
Kernel kernel = new Kernel(size, size, data);
|
||||||
|
BufferedImageOp op = new ConvolveOp(kernel, ConvolveOp.EDGE_NO_OP, null);
|
||||||
|
return op.filter(image, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BufferedImage softenEdges(BufferedImage image, int featherRadius) {
|
||||||
|
int width = image.getWidth();
|
||||||
|
int height = image.getHeight();
|
||||||
|
BufferedImage output = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
|
||||||
|
|
||||||
|
Graphics2D g2 = output.createGraphics();
|
||||||
|
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||||
|
g2.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
|
||||||
|
g2.setRenderingHint(
|
||||||
|
RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
|
||||||
|
|
||||||
|
g2.drawImage(image, 0, 0, null);
|
||||||
|
g2.setComposite(AlphaComposite.DstIn);
|
||||||
|
|
||||||
|
// Top edge
|
||||||
|
g2.setPaint(
|
||||||
|
new GradientPaint(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
new Color(0, 0, 0, 1f),
|
||||||
|
0,
|
||||||
|
featherRadius * 2,
|
||||||
|
new Color(0, 0, 0, 0f)));
|
||||||
|
g2.fillRect(0, 0, width, featherRadius);
|
||||||
|
|
||||||
|
// Bottom edge
|
||||||
|
g2.setPaint(
|
||||||
|
new GradientPaint(
|
||||||
|
0,
|
||||||
|
height - featherRadius * 2,
|
||||||
|
new Color(0, 0, 0, 0f),
|
||||||
|
0,
|
||||||
|
height,
|
||||||
|
new Color(0, 0, 0, 1f)));
|
||||||
|
g2.fillRect(0, height - featherRadius, width, featherRadius);
|
||||||
|
|
||||||
|
// Left edge
|
||||||
|
g2.setPaint(
|
||||||
|
new GradientPaint(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
new Color(0, 0, 0, 1f),
|
||||||
|
featherRadius * 2,
|
||||||
|
0,
|
||||||
|
new Color(0, 0, 0, 0f)));
|
||||||
|
g2.fillRect(0, 0, featherRadius, height);
|
||||||
|
|
||||||
|
// Right edge
|
||||||
|
g2.setPaint(
|
||||||
|
new GradientPaint(
|
||||||
|
width - featherRadius * 2,
|
||||||
|
0,
|
||||||
|
new Color(0, 0, 0, 0f),
|
||||||
|
width,
|
||||||
|
0,
|
||||||
|
new Color(0, 0, 0, 1f)));
|
||||||
|
g2.fillRect(width - featherRadius, 0, featherRadius, height);
|
||||||
|
|
||||||
|
g2.dispose();
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addDustAndHairs(BufferedImage image, float intensity) {
|
||||||
|
int width = image.getWidth();
|
||||||
|
int height = image.getHeight();
|
||||||
|
Graphics2D g2d = image.createGraphics();
|
||||||
|
Random random = new SecureRandom();
|
||||||
|
|
||||||
|
// Set rendering hints for better quality
|
||||||
|
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||||
|
|
||||||
|
// Calculate the number of artifacts based on intensity
|
||||||
|
int numSpots = (int) (intensity * 10);
|
||||||
|
int numHairs = (int) (intensity * 20);
|
||||||
|
|
||||||
|
// Add spots with more variable sizes
|
||||||
|
g2d.setColor(new Color(100, 100, 100, 50)); // Semi-transparent gray
|
||||||
|
for (int i = 0; i < numSpots; i++) {
|
||||||
|
int x = random.nextInt(width);
|
||||||
|
int y = random.nextInt(height);
|
||||||
|
int ovalSize = 1 + random.nextInt(3); // Base size + variable component
|
||||||
|
if (random.nextFloat() > 0.9) {
|
||||||
|
// 10% chance to get a larger spot
|
||||||
|
ovalSize += random.nextInt(3);
|
||||||
|
}
|
||||||
|
g2d.fill(new Ellipse2D.Double(x, y, ovalSize, ovalSize));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add hairs
|
||||||
|
g2d.setStroke(new BasicStroke(0.5f)); // Thin stroke for hairs
|
||||||
|
g2d.setColor(new Color(80, 80, 80, 40)); // Slightly lighter and more transparent
|
||||||
|
for (int i = 0; i < numHairs; i++) {
|
||||||
|
int x1 = random.nextInt(width);
|
||||||
|
int y1 = random.nextInt(height);
|
||||||
|
int x2 = x1 + random.nextInt(20) - 10; // Random length and direction
|
||||||
|
int y2 = y1 + random.nextInt(20) - 10;
|
||||||
|
Path2D.Double hair = new Path2D.Double();
|
||||||
|
hair.moveTo(x1, y1);
|
||||||
|
hair.curveTo(x1, y1, (x1 + x2) / 2, (y1 + y2) / 2, x2, y2);
|
||||||
|
g2d.draw(hair);
|
||||||
|
}
|
||||||
|
|
||||||
|
g2d.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addGaussianNoise(BufferedImage image, double strength) {
|
||||||
|
Random rand = new SecureRandom();
|
||||||
|
int width = image.getWidth();
|
||||||
|
int height = image.getHeight();
|
||||||
|
|
||||||
|
for (int i = 0; i < width; i++) {
|
||||||
|
for (int j = 0; j < height; j++) {
|
||||||
|
int rgba = image.getRGB(i, j);
|
||||||
|
int alpha = (rgba >> 24) & 0xff;
|
||||||
|
int red = (rgba >> 16) & 0xff;
|
||||||
|
int green = (rgba >> 8) & 0xff;
|
||||||
|
int blue = rgba & 0xff;
|
||||||
|
|
||||||
|
// Apply Gaussian noise
|
||||||
|
red = (int) (red + rand.nextGaussian() * strength);
|
||||||
|
green = (int) (green + rand.nextGaussian() * strength);
|
||||||
|
blue = (int) (blue + rand.nextGaussian() * strength);
|
||||||
|
|
||||||
|
// Clamping values to the 0-255 range
|
||||||
|
red = Math.min(Math.max(0, red), 255);
|
||||||
|
green = Math.min(Math.max(0, green), 255);
|
||||||
|
blue = Math.min(Math.max(0, blue), 255);
|
||||||
|
|
||||||
|
image.setRGB(i, j, (alpha << 24) | (red << 16) | (green << 8) | blue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public BufferedImage linearStretch(BufferedImage image) {
|
||||||
|
int width = image.getWidth();
|
||||||
|
int height = image.getHeight();
|
||||||
|
int min = 255;
|
||||||
|
int max = 0;
|
||||||
|
|
||||||
|
// First pass: find the min and max grayscale values
|
||||||
|
for (int y = 0; y < height; y++) {
|
||||||
|
for (int x = 0; x < width; x++) {
|
||||||
|
int rgb = image.getRGB(x, y);
|
||||||
|
int gray =
|
||||||
|
(int)
|
||||||
|
(((rgb >> 16) & 0xff) * 0.299
|
||||||
|
+ ((rgb >> 8) & 0xff) * 0.587
|
||||||
|
+ (rgb & 0xff) * 0.114); // Convert to grayscale
|
||||||
|
if (gray < min) min = gray;
|
||||||
|
if (gray > max) max = gray;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Second pass: stretch the histogram
|
||||||
|
for (int y = 0; y < height; y++) {
|
||||||
|
for (int x = 0; x < width; x++) {
|
||||||
|
int rgb = image.getRGB(x, y);
|
||||||
|
int alpha = (rgb >> 24) & 0xff;
|
||||||
|
int red = (rgb >> 16) & 0xff;
|
||||||
|
int green = (rgb >> 8) & 0xff;
|
||||||
|
int blue = rgb & 0xff;
|
||||||
|
|
||||||
|
// Apply linear stretch to each channel
|
||||||
|
red = (int) (((red - min) / (float) (max - min)) * 255);
|
||||||
|
green = (int) (((green - min) / (float) (max - min)) * 255);
|
||||||
|
blue = (int) (((blue - min) / (float) (max - min)) * 255);
|
||||||
|
|
||||||
|
// Set new RGB value maintaining the alpha channel
|
||||||
|
rgb = (alpha << 24) | (red << 16) | (green << 8) | blue;
|
||||||
|
image.setRGB(x, y, rgb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return image;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,105 @@
|
||||||
|
package stirling.software.SPDF.controller.api.misc;
|
||||||
|
|
||||||
|
import java.awt.Graphics;
|
||||||
|
import java.awt.Graphics2D;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.awt.print.PageFormat;
|
||||||
|
import java.awt.print.Printable;
|
||||||
|
import java.awt.print.PrinterException;
|
||||||
|
import java.awt.print.PrinterJob;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
|
import javax.print.PrintService;
|
||||||
|
import javax.print.PrintServiceLookup;
|
||||||
|
|
||||||
|
import org.apache.pdfbox.Loader;
|
||||||
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
|
import org.apache.pdfbox.printing.PDFPageable;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||||
|
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.tags.Tag;
|
||||||
|
|
||||||
|
import stirling.software.SPDF.model.api.misc.PrintFileRequest;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/v1/misc")
|
||||||
|
@Tag(name = "Misc", description = "Miscellaneous APIs")
|
||||||
|
public class PrintFileController {
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
// @PostMapping(value = "/print-file", consumes = "multipart/form-data")
|
||||||
|
// @Operation(
|
||||||
|
// summary = "Prints PDF/Image file to a set printer",
|
||||||
|
// description =
|
||||||
|
// "Input of PDF or Image along with a printer name/URL/IP to match against to
|
||||||
|
// send it to (Fire and forget) Input:Any Output:N/A Type:SISO")
|
||||||
|
public ResponseEntity<String> printFile(@ModelAttribute PrintFileRequest request)
|
||||||
|
throws IOException {
|
||||||
|
MultipartFile file = request.getFileInput();
|
||||||
|
String printerName = request.getPrinterName();
|
||||||
|
String contentType = file.getContentType();
|
||||||
|
try {
|
||||||
|
// Find matching printer
|
||||||
|
PrintService[] services = PrintServiceLookup.lookupPrintServices(null, null);
|
||||||
|
PrintService selectedService =
|
||||||
|
Arrays.stream(services)
|
||||||
|
.filter(
|
||||||
|
service ->
|
||||||
|
service.getName().toLowerCase().contains(printerName))
|
||||||
|
.findFirst()
|
||||||
|
.orElseThrow(
|
||||||
|
() ->
|
||||||
|
new IllegalArgumentException(
|
||||||
|
"No matching printer found"));
|
||||||
|
|
||||||
|
System.out.println("Selected Printer: " + selectedService.getName());
|
||||||
|
|
||||||
|
if ("application/pdf".equals(contentType)) {
|
||||||
|
PDDocument document = Loader.loadPDF(file.getBytes());
|
||||||
|
PrinterJob job = PrinterJob.getPrinterJob();
|
||||||
|
job.setPrintService(selectedService);
|
||||||
|
job.setPageable(new PDFPageable(document));
|
||||||
|
job.print();
|
||||||
|
document.close();
|
||||||
|
} else if (contentType.startsWith("image/")) {
|
||||||
|
BufferedImage image = ImageIO.read(file.getInputStream());
|
||||||
|
PrinterJob job = PrinterJob.getPrinterJob();
|
||||||
|
job.setPrintService(selectedService);
|
||||||
|
job.setPrintable(
|
||||||
|
new Printable() {
|
||||||
|
public int print(
|
||||||
|
Graphics graphics, PageFormat pageFormat, int pageIndex)
|
||||||
|
throws PrinterException {
|
||||||
|
if (pageIndex != 0) {
|
||||||
|
return NO_SUCH_PAGE;
|
||||||
|
}
|
||||||
|
Graphics2D g2d = (Graphics2D) graphics;
|
||||||
|
g2d.translate(
|
||||||
|
pageFormat.getImageableX(), pageFormat.getImageableY());
|
||||||
|
g2d.drawImage(
|
||||||
|
image,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
(int) pageFormat.getImageableWidth(),
|
||||||
|
(int) pageFormat.getImageableHeight(),
|
||||||
|
null);
|
||||||
|
return PAGE_EXISTS;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
job.print();
|
||||||
|
}
|
||||||
|
return new ResponseEntity<>(
|
||||||
|
"File printed successfully to " + selectedService.getName(), HttpStatus.OK);
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.err.println("Failed to print: " + e.getMessage());
|
||||||
|
return new ResponseEntity<>(e.getMessage(), HttpStatus.BAD_REQUEST);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -139,25 +139,29 @@ public class SanitizeController {
|
||||||
|
|
||||||
for (PDPage page : allPages) {
|
for (PDPage page : allPages) {
|
||||||
PDResources res = page.getResources();
|
PDResources res = page.getResources();
|
||||||
|
if (res != null && res.getCOSObject() != null) {
|
||||||
// Remove embedded files from the PDF
|
|
||||||
res.getCOSObject().removeItem(COSName.getPDFName("EmbeddedFiles"));
|
res.getCOSObject().removeItem(COSName.getPDFName("EmbeddedFiles"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void sanitizeMetadata(PDDocument document) {
|
private void sanitizeMetadata(PDDocument document) {
|
||||||
|
if (document.getDocumentCatalog() != null) {
|
||||||
PDMetadata metadata = document.getDocumentCatalog().getMetadata();
|
PDMetadata metadata = document.getDocumentCatalog().getMetadata();
|
||||||
if (metadata != null) {
|
if (metadata != null) {
|
||||||
document.getDocumentCatalog().setMetadata(null);
|
document.getDocumentCatalog().setMetadata(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void sanitizeLinks(PDDocument document) throws IOException {
|
private void sanitizeLinks(PDDocument document) throws IOException {
|
||||||
for (PDPage page : document.getPages()) {
|
for (PDPage page : document.getPages()) {
|
||||||
for (PDAnnotation annotation : page.getAnnotations()) {
|
for (PDAnnotation annotation : page.getAnnotations()) {
|
||||||
if (annotation instanceof PDAnnotationLink) {
|
if (annotation != null && annotation instanceof PDAnnotationLink) {
|
||||||
PDAction action = ((PDAnnotationLink) annotation).getAction();
|
PDAction action = ((PDAnnotationLink) annotation).getAction();
|
||||||
if (action instanceof PDActionLaunch || action instanceof PDActionURI) {
|
if (action != null
|
||||||
|
&& (action instanceof PDActionLaunch
|
||||||
|
|| action instanceof PDActionURI)) {
|
||||||
((PDAnnotationLink) annotation).setAction(null);
|
((PDAnnotationLink) annotation).setAction(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -167,7 +171,11 @@ public class SanitizeController {
|
||||||
|
|
||||||
private void sanitizeFonts(PDDocument document) {
|
private void sanitizeFonts(PDDocument document) {
|
||||||
for (PDPage page : document.getPages()) {
|
for (PDPage page : document.getPages()) {
|
||||||
|
if (page != null
|
||||||
|
&& page.getResources() != null
|
||||||
|
&& page.getResources().getCOSObject() != null) {
|
||||||
page.getResources().getCOSObject().removeItem(COSName.getPDFName("Font"));
|
page.getResources().getCOSObject().removeItem(COSName.getPDFName("Font"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -6,9 +6,11 @@ import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.core.userdetails.UserDetails;
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
|
import org.springframework.security.oauth2.core.user.OAuth2User;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.ui.Model;
|
import org.springframework.ui.Model;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
@ -19,6 +21,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import stirling.software.SPDF.model.ApplicationProperties;
|
||||||
import stirling.software.SPDF.model.Authority;
|
import stirling.software.SPDF.model.Authority;
|
||||||
import stirling.software.SPDF.model.Role;
|
import stirling.software.SPDF.model.Role;
|
||||||
import stirling.software.SPDF.model.User;
|
import stirling.software.SPDF.model.User;
|
||||||
|
@ -28,12 +31,16 @@ import stirling.software.SPDF.repository.UserRepository;
|
||||||
@Tag(name = "Account Security", description = "Account Security APIs")
|
@Tag(name = "Account Security", description = "Account Security APIs")
|
||||||
public class AccountWebController {
|
public class AccountWebController {
|
||||||
|
|
||||||
|
@Autowired ApplicationProperties applicationProperties;
|
||||||
|
|
||||||
@GetMapping("/login")
|
@GetMapping("/login")
|
||||||
public String login(HttpServletRequest request, Model model, Authentication authentication) {
|
public String login(HttpServletRequest request, Model model, Authentication authentication) {
|
||||||
if (authentication != null && authentication.isAuthenticated()) {
|
if (authentication != null && authentication.isAuthenticated()) {
|
||||||
return "redirect:/";
|
return "redirect:/";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
model.addAttribute("oAuth2Enabled", applicationProperties.getSecurity().getOAUTH2().getEnabled());
|
||||||
|
|
||||||
model.addAttribute("currentPage", "login");
|
model.addAttribute("currentPage", "login");
|
||||||
|
|
||||||
if (request.getParameter("error") != null) {
|
if (request.getParameter("error") != null) {
|
||||||
|
@ -85,14 +92,29 @@ public class AccountWebController {
|
||||||
}
|
}
|
||||||
if (authentication != null && authentication.isAuthenticated()) {
|
if (authentication != null && authentication.isAuthenticated()) {
|
||||||
Object principal = authentication.getPrincipal();
|
Object principal = authentication.getPrincipal();
|
||||||
|
String username = null;
|
||||||
|
|
||||||
if (principal instanceof UserDetails) {
|
if (principal instanceof UserDetails) {
|
||||||
// Cast the principal object to UserDetails
|
// Cast the principal object to UserDetails
|
||||||
UserDetails userDetails = (UserDetails) principal;
|
UserDetails userDetails = (UserDetails) principal;
|
||||||
|
|
||||||
// Retrieve username and other attributes
|
// Retrieve username and other attributes
|
||||||
String username = userDetails.getUsername();
|
username = userDetails.getUsername();
|
||||||
|
|
||||||
|
// Add oAuth2 Login attributes to the model
|
||||||
|
model.addAttribute("oAuth2Login", false);
|
||||||
|
}
|
||||||
|
if (principal instanceof OAuth2User) {
|
||||||
|
// Cast the principal object to OAuth2User
|
||||||
|
OAuth2User userDetails = (OAuth2User) principal;
|
||||||
|
|
||||||
|
// Retrieve username and other attributes
|
||||||
|
username = userDetails.getAttribute("email");
|
||||||
|
|
||||||
|
// Add oAuth2 Login attributes to the model
|
||||||
|
model.addAttribute("oAuth2Login", true);
|
||||||
|
}
|
||||||
|
if (username != null) {
|
||||||
// Fetch user details from the database
|
// Fetch user details from the database
|
||||||
Optional<User> user =
|
Optional<User> user =
|
||||||
userRepository.findByUsernameIgnoreCase(
|
userRepository.findByUsernameIgnoreCase(
|
||||||
|
|
|
@ -17,6 +17,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
@Controller
|
@Controller
|
||||||
@Tag(name = "Misc", description = "Miscellaneous APIs")
|
@Tag(name = "Misc", description = "Miscellaneous APIs")
|
||||||
public class OtherWebController {
|
public class OtherWebController {
|
||||||
|
|
||||||
@GetMapping("/compress-pdf")
|
@GetMapping("/compress-pdf")
|
||||||
@Hidden
|
@Hidden
|
||||||
public String compressPdfForm(Model model) {
|
public String compressPdfForm(Model model) {
|
||||||
|
@ -53,6 +54,13 @@ public class OtherWebController {
|
||||||
return "misc/add-page-numbers";
|
return "misc/add-page-numbers";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("/fake-scan")
|
||||||
|
@Hidden
|
||||||
|
public String fakeScanForm(Model model) {
|
||||||
|
model.addAttribute("currentPage", "fake-scan");
|
||||||
|
return "misc/fake-scan";
|
||||||
|
}
|
||||||
|
|
||||||
@GetMapping("/extract-images")
|
@GetMapping("/extract-images")
|
||||||
@Hidden
|
@Hidden
|
||||||
public String extractImagesForm(Model model) {
|
public String extractImagesForm(Model model) {
|
||||||
|
@ -81,6 +89,13 @@ public class OtherWebController {
|
||||||
return "misc/compare";
|
return "misc/compare";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("/print-file")
|
||||||
|
@Hidden
|
||||||
|
public String printFileForm(Model model) {
|
||||||
|
model.addAttribute("currentPage", "print-file");
|
||||||
|
return "misc/print-file";
|
||||||
|
}
|
||||||
|
|
||||||
public List<String> getAvailableTesseractLanguages() {
|
public List<String> getAvailableTesseractLanguages() {
|
||||||
String tessdataDir = "/usr/share/tessdata";
|
String tessdataDir = "/usr/share/tessdata";
|
||||||
File[] files = new File(tessdataDir).listFiles();
|
File[] files = new File(tessdataDir).listFiles();
|
||||||
|
|
|
@ -118,6 +118,7 @@ public class ApplicationProperties {
|
||||||
private Boolean enableLogin;
|
private Boolean enableLogin;
|
||||||
private Boolean csrfDisabled;
|
private Boolean csrfDisabled;
|
||||||
private InitialLogin initialLogin;
|
private InitialLogin initialLogin;
|
||||||
|
private OAUTH2 oauth2;
|
||||||
private int loginAttemptCount;
|
private int loginAttemptCount;
|
||||||
private long loginResetTimeMinutes;
|
private long loginResetTimeMinutes;
|
||||||
|
|
||||||
|
@ -145,6 +146,14 @@ public class ApplicationProperties {
|
||||||
this.initialLogin = initialLogin;
|
this.initialLogin = initialLogin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public OAUTH2 getOAUTH2() {
|
||||||
|
return oauth2 != null ? oauth2 : new OAUTH2();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOAUTH2(OAUTH2 oauth2) {
|
||||||
|
this.oauth2 = oauth2;
|
||||||
|
}
|
||||||
|
|
||||||
public Boolean getEnableLogin() {
|
public Boolean getEnableLogin() {
|
||||||
return enableLogin;
|
return enableLogin;
|
||||||
}
|
}
|
||||||
|
@ -165,6 +174,8 @@ public class ApplicationProperties {
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "Security [enableLogin="
|
return "Security [enableLogin="
|
||||||
+ enableLogin
|
+ enableLogin
|
||||||
|
+ ", oauth2="
|
||||||
|
+ oauth2
|
||||||
+ ", initialLogin="
|
+ ", initialLogin="
|
||||||
+ initialLogin
|
+ initialLogin
|
||||||
+ ", csrfDisabled="
|
+ ", csrfDisabled="
|
||||||
|
@ -202,6 +213,70 @@ public class ApplicationProperties {
|
||||||
+ "]";
|
+ "]";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class OAUTH2 {
|
||||||
|
|
||||||
|
private boolean enabled;
|
||||||
|
private String issuer;
|
||||||
|
private String clientId;
|
||||||
|
private String clientSecret;
|
||||||
|
private boolean autoCreateUser;
|
||||||
|
|
||||||
|
public boolean getEnabled() {
|
||||||
|
return enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEnabled(boolean enabled) {
|
||||||
|
this.enabled = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getIssuer() {
|
||||||
|
return issuer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIssuer(String issuer) {
|
||||||
|
this.issuer = issuer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getClientId() {
|
||||||
|
return clientId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setClientId(String clientId) {
|
||||||
|
this.clientId = clientId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getClientSecret() {
|
||||||
|
return clientSecret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setClientSecret(String clientSecret) {
|
||||||
|
this.clientSecret = clientSecret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getAutoCreateUser() {
|
||||||
|
return autoCreateUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAutoCreateUser(boolean autoCreateUser) {
|
||||||
|
this.autoCreateUser = autoCreateUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "OAUTH2 [enabled="
|
||||||
|
+ enabled
|
||||||
|
+ ", issuer="
|
||||||
|
+ issuer
|
||||||
|
+ ", clientId="
|
||||||
|
+ clientId
|
||||||
|
+ ", clientSecret="
|
||||||
|
+ (clientSecret!= null && !clientSecret.isEmpty() ? "MASKED" : "NULL")
|
||||||
|
+ ", autoCreateUser="
|
||||||
|
+ autoCreateUser
|
||||||
|
+ "]";
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class System {
|
public static class System {
|
||||||
|
@ -210,6 +285,33 @@ public class ApplicationProperties {
|
||||||
private String rootURIPath;
|
private String rootURIPath;
|
||||||
private String customStaticFilePath;
|
private String customStaticFilePath;
|
||||||
private Integer maxFileSize;
|
private Integer maxFileSize;
|
||||||
|
private boolean showUpdate;
|
||||||
|
private Boolean showUpdateOnlyAdmin;
|
||||||
|
private boolean customHTMLFiles;
|
||||||
|
|
||||||
|
public boolean isCustomHTMLFiles() {
|
||||||
|
return customHTMLFiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCustomHTMLFiles(boolean customHTMLFiles) {
|
||||||
|
this.customHTMLFiles = customHTMLFiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getShowUpdateOnlyAdmin() {
|
||||||
|
return showUpdateOnlyAdmin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setShowUpdateOnlyAdmin(boolean showUpdateOnlyAdmin) {
|
||||||
|
this.showUpdateOnlyAdmin = showUpdateOnlyAdmin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getShowUpdate() {
|
||||||
|
return showUpdate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setShowUpdate(boolean showUpdate) {
|
||||||
|
this.showUpdate = showUpdate;
|
||||||
|
}
|
||||||
|
|
||||||
private Boolean enableAlphaFunctionality;
|
private Boolean enableAlphaFunctionality;
|
||||||
|
|
||||||
|
@ -275,6 +377,10 @@ public class ApplicationProperties {
|
||||||
+ maxFileSize
|
+ maxFileSize
|
||||||
+ ", enableAlphaFunctionality="
|
+ ", enableAlphaFunctionality="
|
||||||
+ enableAlphaFunctionality
|
+ enableAlphaFunctionality
|
||||||
|
+ ", showUpdate="
|
||||||
|
+ showUpdate
|
||||||
|
+ ", showUpdateOnlyAdmin="
|
||||||
|
+ showUpdateOnlyAdmin
|
||||||
+ "]";
|
+ "]";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
package stirling.software.SPDF.model.api.converters;
|
||||||
|
|
||||||
|
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 PdfToPdfARequest extends PDFFile {
|
||||||
|
|
||||||
|
@Schema(
|
||||||
|
description = "The output PDF/A type",
|
||||||
|
allowableValues = {"pdfa", "pdfa-1"})
|
||||||
|
private String outputFormat;
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
package stirling.software.SPDF.model.api.misc;
|
||||||
|
|
||||||
|
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 PrintFileRequest extends PDFFile {
|
||||||
|
|
||||||
|
@Schema(description = "Name of printer to match against", required = true)
|
||||||
|
private String printerName;
|
||||||
|
}
|
|
@ -336,14 +336,12 @@ public class PdfUtils {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void addImageToDocument(
|
public static void addImageToDocument(
|
||||||
PDDocument doc, PDImageXObject image, String fitOption, boolean autoRotate)
|
PDDocument doc, PDImageXObject image, String fitOption, boolean autoRotate)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
boolean imageIsLandscape = image.getWidth() > image.getHeight();
|
boolean imageIsLandscape = image.getWidth() > image.getHeight();
|
||||||
PDRectangle pageSize = PDRectangle.A4;
|
PDRectangle pageSize = PDRectangle.A4;
|
||||||
|
|
||||||
System.out.println(fitOption);
|
|
||||||
|
|
||||||
if (autoRotate && imageIsLandscape) {
|
if (autoRotate && imageIsLandscape) {
|
||||||
pageSize = new PDRectangle(pageSize.getHeight(), pageSize.getWidth());
|
pageSize = new PDRectangle(pageSize.getHeight(), pageSize.getWidth());
|
||||||
}
|
}
|
||||||
|
|
|
@ -112,6 +112,7 @@ navbar.settings=إعدادات
|
||||||
#############
|
#############
|
||||||
settings.title=الإعدادات
|
settings.title=الإعدادات
|
||||||
settings.update=التحديث متاح
|
settings.update=التحديث متاح
|
||||||
|
settings.updateAvailable={0} is the current installed version. A new version ({1}) is available.
|
||||||
settings.appVersion=إصدار التطبيق:
|
settings.appVersion=إصدار التطبيق:
|
||||||
settings.downloadOption.title=تحديد خيار التنزيل (للتنزيلات ذات الملف الواحد غير المضغوط):
|
settings.downloadOption.title=تحديد خيار التنزيل (للتنزيلات ذات الملف الواحد غير المضغوط):
|
||||||
settings.downloadOption.1=فتح في نفس النافذة
|
settings.downloadOption.1=فتح في نفس النافذة
|
||||||
|
@ -120,8 +121,9 @@ settings.downloadOption.3=تنزيل الملف
|
||||||
settings.zipThreshold=ملفات مضغوطة عند تجاوز عدد الملفات التي تم تنزيلها
|
settings.zipThreshold=ملفات مضغوطة عند تجاوز عدد الملفات التي تم تنزيلها
|
||||||
settings.signOut=Sign Out
|
settings.signOut=Sign Out
|
||||||
settings.accountSettings=Account Settings
|
settings.accountSettings=Account Settings
|
||||||
|
settings.bored.help=Enables easter egg game
|
||||||
|
settings.cacheInputs.name=Save form inputs
|
||||||
|
settings.cacheInputs.help=Enable to store previously used inputs for future runs
|
||||||
|
|
||||||
changeCreds.title=Change Credentials
|
changeCreds.title=Change Credentials
|
||||||
changeCreds.header=Update Your Account Details
|
changeCreds.header=Update Your Account Details
|
||||||
|
@ -435,6 +437,8 @@ login.rememberme=Remember me
|
||||||
login.invalid=Invalid username or password.
|
login.invalid=Invalid username or password.
|
||||||
login.locked=Your account has been locked.
|
login.locked=Your account has been locked.
|
||||||
login.signinTitle=Please sign in
|
login.signinTitle=Please sign in
|
||||||
|
login.ssoSignIn=تسجيل الدخول عبر تسجيل الدخول الأحادي
|
||||||
|
login.oauth2AutoCreateDisabled=تم تعطيل مستخدم الإنشاء التلقائي لـ OAuth2
|
||||||
|
|
||||||
|
|
||||||
#auto-redact
|
#auto-redact
|
||||||
|
@ -939,6 +943,7 @@ pdfToPDFA.header=PDF إلى PDF / A
|
||||||
pdfToPDFA.credit=تستخدم هذه الخدمة OCRmyPDF لتحويل PDF / A.
|
pdfToPDFA.credit=تستخدم هذه الخدمة OCRmyPDF لتحويل PDF / A.
|
||||||
pdfToPDFA.submit=تحويل
|
pdfToPDFA.submit=تحويل
|
||||||
pdfToPDFA.tip=Currently does not work for multiple inputs at once
|
pdfToPDFA.tip=Currently does not work for multiple inputs at once
|
||||||
|
pdfToPDFA.outputFormat=Output format
|
||||||
|
|
||||||
|
|
||||||
#PDFToWord
|
#PDFToWord
|
||||||
|
@ -1022,6 +1027,15 @@ split-by-sections.vertical.placeholder=Enter number of vertical divisions
|
||||||
split-by-sections.submit=Split PDF
|
split-by-sections.submit=Split PDF
|
||||||
split-by-sections.merge=Merge Into One PDF
|
split-by-sections.merge=Merge Into One PDF
|
||||||
|
|
||||||
|
|
||||||
|
#printFile
|
||||||
|
printFile.title=Print File
|
||||||
|
printFile.header=Print File to Printer
|
||||||
|
printFile.selectText.1=Select File to Print
|
||||||
|
printFile.selectText.2=Enter Printer Name
|
||||||
|
printFile.submit=Print
|
||||||
|
|
||||||
|
|
||||||
#licenses
|
#licenses
|
||||||
licenses.nav=Licenses
|
licenses.nav=Licenses
|
||||||
licenses.title=3rd Party Licenses
|
licenses.title=3rd Party Licenses
|
||||||
|
|
|
@ -112,6 +112,7 @@ navbar.settings=Настройки
|
||||||
#############
|
#############
|
||||||
settings.title=Настройки
|
settings.title=Настройки
|
||||||
settings.update=Налична актуализация
|
settings.update=Налична актуализация
|
||||||
|
settings.updateAvailable={0} is the current installed version. A new version ({1}) is available.
|
||||||
settings.appVersion=Версия на приложението:
|
settings.appVersion=Версия на приложението:
|
||||||
settings.downloadOption.title=Изберете опция за изтегляне (за изтегляния на един файл без да е архивиран):
|
settings.downloadOption.title=Изберете опция за изтегляне (за изтегляния на един файл без да е архивиран):
|
||||||
settings.downloadOption.1=Отваряне в същия прозорец
|
settings.downloadOption.1=Отваряне в същия прозорец
|
||||||
|
@ -120,8 +121,9 @@ settings.downloadOption.3=Изтегли файл
|
||||||
settings.zipThreshold=Архивирайте файловете, когато броят на изтеглените файлове надвишава
|
settings.zipThreshold=Архивирайте файловете, когато броят на изтеглените файлове надвишава
|
||||||
settings.signOut=Изход
|
settings.signOut=Изход
|
||||||
settings.accountSettings=Настройки на акаунта
|
settings.accountSettings=Настройки на акаунта
|
||||||
|
settings.bored.help=Enables easter egg game
|
||||||
|
settings.cacheInputs.name=Save form inputs
|
||||||
|
settings.cacheInputs.help=Enable to store previously used inputs for future runs
|
||||||
|
|
||||||
changeCreds.title=Промяна на идентификационните данни
|
changeCreds.title=Промяна на идентификационните данни
|
||||||
changeCreds.header=Актуализирайте данните за акаунта си
|
changeCreds.header=Актуализирайте данните за акаунта си
|
||||||
|
@ -435,6 +437,8 @@ login.rememberme=Запомни ме
|
||||||
login.invalid=Невалидно потребителско име или парола.
|
login.invalid=Невалидно потребителско име или парола.
|
||||||
login.locked=Вашият акаунт е заключен.
|
login.locked=Вашият акаунт е заключен.
|
||||||
login.signinTitle=Моля впишете се
|
login.signinTitle=Моля впишете се
|
||||||
|
login.ssoSignIn=Влизане чрез еднократно влизане
|
||||||
|
login.oauth2AutoCreateDisabled=OAUTH2 Автоматично създаване на потребител е деактивирано
|
||||||
|
|
||||||
|
|
||||||
#auto-redact
|
#auto-redact
|
||||||
|
@ -939,6 +943,7 @@ pdfToPDFA.header=PDF към PDF/A
|
||||||
pdfToPDFA.credit=Тази услуга използва OCRmyPDF за PDF/A преобразуване.
|
pdfToPDFA.credit=Тази услуга използва OCRmyPDF за PDF/A преобразуване.
|
||||||
pdfToPDFA.submit=Преобразуване
|
pdfToPDFA.submit=Преобразуване
|
||||||
pdfToPDFA.tip=Currently does not work for multiple inputs at once
|
pdfToPDFA.tip=Currently does not work for multiple inputs at once
|
||||||
|
pdfToPDFA.outputFormat=Output format
|
||||||
|
|
||||||
|
|
||||||
#PDFToWord
|
#PDFToWord
|
||||||
|
@ -1022,6 +1027,15 @@ split-by-sections.vertical.placeholder=Enter number of vertical divisions
|
||||||
split-by-sections.submit=Split PDF
|
split-by-sections.submit=Split PDF
|
||||||
split-by-sections.merge=Merge Into One PDF
|
split-by-sections.merge=Merge Into One PDF
|
||||||
|
|
||||||
|
|
||||||
|
#printFile
|
||||||
|
printFile.title=Print File
|
||||||
|
printFile.header=Print File to Printer
|
||||||
|
printFile.selectText.1=Select File to Print
|
||||||
|
printFile.selectText.2=Enter Printer Name
|
||||||
|
printFile.submit=Print
|
||||||
|
|
||||||
|
|
||||||
#licenses
|
#licenses
|
||||||
licenses.nav=Licenses
|
licenses.nav=Licenses
|
||||||
licenses.title=3rd Party Licenses
|
licenses.title=3rd Party Licenses
|
||||||
|
|
|
@ -112,6 +112,7 @@ navbar.settings=Opcions
|
||||||
#############
|
#############
|
||||||
settings.title=Opcions
|
settings.title=Opcions
|
||||||
settings.update=Actualització Disponible
|
settings.update=Actualització Disponible
|
||||||
|
settings.updateAvailable={0} is the current installed version. A new version ({1}) is available.
|
||||||
settings.appVersion=Versió App:
|
settings.appVersion=Versió App:
|
||||||
settings.downloadOption.title=Trieu l'opció de descàrrega (per a descàrregues d'un sol fitxer no zip):
|
settings.downloadOption.title=Trieu l'opció de descàrrega (per a descàrregues d'un sol fitxer no zip):
|
||||||
settings.downloadOption.1=Obre mateixa finestra
|
settings.downloadOption.1=Obre mateixa finestra
|
||||||
|
@ -120,8 +121,9 @@ settings.downloadOption.3=Descarrega Arxiu
|
||||||
settings.zipThreshold=Comprimiu els fitxers quan el nombre de fitxers baixats superi
|
settings.zipThreshold=Comprimiu els fitxers quan el nombre de fitxers baixats superi
|
||||||
settings.signOut=Sortir
|
settings.signOut=Sortir
|
||||||
settings.accountSettings=Account Settings
|
settings.accountSettings=Account Settings
|
||||||
|
settings.bored.help=Enables easter egg game
|
||||||
|
settings.cacheInputs.name=Save form inputs
|
||||||
|
settings.cacheInputs.help=Enable to store previously used inputs for future runs
|
||||||
|
|
||||||
changeCreds.title=Change Credentials
|
changeCreds.title=Change Credentials
|
||||||
changeCreds.header=Update Your Account Details
|
changeCreds.header=Update Your Account Details
|
||||||
|
@ -435,6 +437,8 @@ login.rememberme=Recordar
|
||||||
login.invalid=Nom usuari / password no vàlid
|
login.invalid=Nom usuari / password no vàlid
|
||||||
login.locked=Compte bloquejat
|
login.locked=Compte bloquejat
|
||||||
login.signinTitle=Autenticat
|
login.signinTitle=Autenticat
|
||||||
|
login.ssoSignIn=Inicia sessió mitjançant l'inici de sessió ún
|
||||||
|
login.oauth2AutoCreateDisabled=L'usuari de creació automàtica OAUTH2 està desactivat
|
||||||
|
|
||||||
|
|
||||||
#auto-redact
|
#auto-redact
|
||||||
|
@ -939,6 +943,7 @@ pdfToPDFA.header=PDF a PDF/A
|
||||||
pdfToPDFA.credit=Utilitza OCRmyPDF per la conversió a PDF/A
|
pdfToPDFA.credit=Utilitza OCRmyPDF per la conversió a PDF/A
|
||||||
pdfToPDFA.submit=Converteix
|
pdfToPDFA.submit=Converteix
|
||||||
pdfToPDFA.tip=Currently does not work for multiple inputs at once
|
pdfToPDFA.tip=Currently does not work for multiple inputs at once
|
||||||
|
pdfToPDFA.outputFormat=Output format
|
||||||
|
|
||||||
|
|
||||||
#PDFToWord
|
#PDFToWord
|
||||||
|
@ -1022,6 +1027,15 @@ split-by-sections.vertical.placeholder=Enter number of vertical divisions
|
||||||
split-by-sections.submit=Split PDF
|
split-by-sections.submit=Split PDF
|
||||||
split-by-sections.merge=Merge Into One PDF
|
split-by-sections.merge=Merge Into One PDF
|
||||||
|
|
||||||
|
|
||||||
|
#printFile
|
||||||
|
printFile.title=Print File
|
||||||
|
printFile.header=Print File to Printer
|
||||||
|
printFile.selectText.1=Select File to Print
|
||||||
|
printFile.selectText.2=Enter Printer Name
|
||||||
|
printFile.submit=Print
|
||||||
|
|
||||||
|
|
||||||
#licenses
|
#licenses
|
||||||
licenses.nav=Licenses
|
licenses.nav=Licenses
|
||||||
licenses.title=3rd Party Licenses
|
licenses.title=3rd Party Licenses
|
||||||
|
|
|
@ -46,7 +46,7 @@ green=Grün
|
||||||
blue=Blau
|
blue=Blau
|
||||||
custom=benutzerdefiniert...
|
custom=benutzerdefiniert...
|
||||||
WorkInProgess=In Arbeit, funktioniert möglicherweise nicht oder ist fehlerhaft. Bitte melden Sie alle Probleme!
|
WorkInProgess=In Arbeit, funktioniert möglicherweise nicht oder ist fehlerhaft. Bitte melden Sie alle Probleme!
|
||||||
poweredBy=Powered by
|
poweredBy=Unterstützt von
|
||||||
yes=Ja
|
yes=Ja
|
||||||
no=Nein
|
no=Nein
|
||||||
changedCredsMessage=Anmeldedaten geändert!
|
changedCredsMessage=Anmeldedaten geändert!
|
||||||
|
@ -112,6 +112,7 @@ navbar.settings=Einstellungen
|
||||||
#############
|
#############
|
||||||
settings.title=Einstellungen
|
settings.title=Einstellungen
|
||||||
settings.update=Update verfügbar
|
settings.update=Update verfügbar
|
||||||
|
settings.updateAvailable={0} ist die aktuelle installierte Version. Eine neue Version ({1}) ist verfügbar.
|
||||||
settings.appVersion=App-Version:
|
settings.appVersion=App-Version:
|
||||||
settings.downloadOption.title=Download-Option wählen (für einzelne Dateien, die keine Zip-Downloads sind):
|
settings.downloadOption.title=Download-Option wählen (für einzelne Dateien, die keine Zip-Downloads sind):
|
||||||
settings.downloadOption.1=Im selben Fenster öffnen
|
settings.downloadOption.1=Im selben Fenster öffnen
|
||||||
|
@ -120,8 +121,9 @@ settings.downloadOption.3=Datei herunterladen
|
||||||
settings.zipThreshold=Dateien komprimieren, wenn die Anzahl der heruntergeladenen Dateien überschritten wird
|
settings.zipThreshold=Dateien komprimieren, wenn die Anzahl der heruntergeladenen Dateien überschritten wird
|
||||||
settings.signOut=Abmelden
|
settings.signOut=Abmelden
|
||||||
settings.accountSettings=Kontoeinstellungen
|
settings.accountSettings=Kontoeinstellungen
|
||||||
|
settings.bored.help=Aktiviert das Easter-Egg-Spiel
|
||||||
|
settings.cacheInputs.name=Formulareingaben speichern
|
||||||
|
settings.cacheInputs.help=Aktivieren, um zuvor verwendete Eingaben für zukünftige Durchläufe zu speichern
|
||||||
|
|
||||||
changeCreds.title=Anmeldeinformationen ändern
|
changeCreds.title=Anmeldeinformationen ändern
|
||||||
changeCreds.header=Aktualisieren Sie Ihre Kontodaten
|
changeCreds.header=Aktualisieren Sie Ihre Kontodaten
|
||||||
|
@ -188,58 +190,58 @@ home.multiTool.desc=Seiten zusammenführen, drehen, neu anordnen und entfernen
|
||||||
multiTool.tags=Multi Tool,Multi operation,UI,click drag,front end,client side
|
multiTool.tags=Multi Tool,Multi operation,UI,click drag,front end,client side
|
||||||
|
|
||||||
home.merge.title=Zusammenführen
|
home.merge.title=Zusammenführen
|
||||||
home.merge.desc=Mehrere PDF-Dateien zu einer einzigen zusammenführen.
|
home.merge.desc=Mehrere PDF-Dateien zu einer einzigen zusammenführen
|
||||||
merge.tags=zusammenführen,seitenvorgänge,back end,serverseite
|
merge.tags=zusammenführen,seitenvorgänge,back end,serverseite
|
||||||
|
|
||||||
home.split.title=Aufteilen
|
home.split.title=Aufteilen
|
||||||
home.split.desc=PDFs in mehrere Dokumente aufteilen.
|
home.split.desc=PDFs in mehrere Dokumente aufteilen
|
||||||
split.tags=seitenoperationen,teilen,mehrseitig,ausschneiden,serverseitig
|
split.tags=seitenoperationen,teilen,mehrseitig,ausschneiden,serverseitig
|
||||||
|
|
||||||
home.rotate.title=Drehen
|
home.rotate.title=Drehen
|
||||||
home.rotate.desc=Drehen Sie Ihre PDFs ganz einfach.
|
home.rotate.desc=Drehen Sie Ihre PDFs ganz einfach
|
||||||
rotate.tags=serverseitig
|
rotate.tags=serverseitig
|
||||||
|
|
||||||
|
|
||||||
home.imageToPdf.title=Bild zu PDF
|
home.imageToPdf.title=Bild zu PDF
|
||||||
home.imageToPdf.desc=Konvertieren Sie ein Bild (PNG, JPEG, GIF) in ein PDF.
|
home.imageToPdf.desc=Konvertieren Sie ein Bild (PNG, JPEG, GIF) in ein PDF
|
||||||
imageToPdf.tags=konvertierung,img,jpg,bild,foto
|
imageToPdf.tags=konvertierung,img,jpg,bild,foto
|
||||||
|
|
||||||
home.pdfToImage.title=PDF zu Bild
|
home.pdfToImage.title=PDF zu Bild
|
||||||
home.pdfToImage.desc=Konvertieren Sie ein PDF in ein Bild (PNG, JPEG, GIF).
|
home.pdfToImage.desc=Konvertieren Sie ein PDF in ein Bild (PNG, JPEG, GIF)
|
||||||
pdfToImage.tags=konvertierung,img,jpg,bild,foto
|
pdfToImage.tags=konvertierung,img,jpg,bild,foto
|
||||||
|
|
||||||
home.pdfOrganiser.title=Organisieren
|
home.pdfOrganiser.title=Organisieren
|
||||||
home.pdfOrganiser.desc=Seiten entfernen und Seitenreihenfolge ändern.
|
home.pdfOrganiser.desc=Seiten entfernen und Seitenreihenfolge ändern
|
||||||
pdfOrganiser.tags=duplex,gerade,ungerade,sortieren,verschieben
|
pdfOrganiser.tags=duplex,gerade,ungerade,sortieren,verschieben
|
||||||
|
|
||||||
|
|
||||||
home.addImage.title=Bild einfügen
|
home.addImage.title=Bild einfügen
|
||||||
home.addImage.desc=Fügt ein Bild an eine bestimmte Stelle im PDF ein (in Arbeit).
|
home.addImage.desc=Fügt ein Bild an eine bestimmte Stelle im PDF ein (in Arbeit)
|
||||||
addImage.tags=img,jpg,bild,foto
|
addImage.tags=img,jpg,bild,foto
|
||||||
|
|
||||||
home.watermark.title=Wasserzeichen hinzufügen
|
home.watermark.title=Wasserzeichen hinzufügen
|
||||||
home.watermark.desc=Fügen Sie ein eigenes Wasserzeichen zu Ihrem PDF hinzu.
|
home.watermark.desc=Fügen Sie ein eigenes Wasserzeichen zu Ihrem PDF hinzu
|
||||||
watermark.tags=text,wiederholend,beschriftung,besitzen,urheberrecht,marke,img,jpg,bild,foto
|
watermark.tags=text,wiederholend,beschriftung,besitzen,urheberrecht,marke,img,jpg,bild,foto
|
||||||
|
|
||||||
home.permissions.title=Berechtigungen ändern
|
home.permissions.title=Berechtigungen ändern
|
||||||
home.permissions.desc=Die Berechtigungen für Ihr PDF-Dokument verändern.
|
home.permissions.desc=Die Berechtigungen für Ihr PDF-Dokument verändern
|
||||||
permissions.tags=lesen,schreiben,bearbeiten,drucken
|
permissions.tags=lesen,schreiben,bearbeiten,drucken
|
||||||
|
|
||||||
|
|
||||||
home.removePages.title=Entfernen
|
home.removePages.title=Entfernen
|
||||||
home.removePages.desc=Ungewollte Seiten aus dem PDF entfernen.
|
home.removePages.desc=Ungewollte Seiten aus dem PDF entfernen
|
||||||
removePages.tags=seiten entfernen,seiten löschen
|
removePages.tags=seiten entfernen,seiten löschen
|
||||||
|
|
||||||
home.addPassword.title=Passwort hinzufügen
|
home.addPassword.title=Passwort hinzufügen
|
||||||
home.addPassword.desc=Das PDF mit einem Passwort verschlüsseln.
|
home.addPassword.desc=Das PDF mit einem Passwort verschlüsseln
|
||||||
addPassword.tags=sicher,sicherheit
|
addPassword.tags=sicher,sicherheit
|
||||||
|
|
||||||
home.removePassword.title=Passwort entfernen
|
home.removePassword.title=Passwort entfernen
|
||||||
home.removePassword.desc=Den Passwortschutz eines PDFs entfernen.
|
home.removePassword.desc=Den Passwortschutz eines PDFs entfernen
|
||||||
removePassword.tags=sichern,entschlüsseln,sicherheit,passwort aufheben,passwort löschen
|
removePassword.tags=sichern,entschlüsseln,sicherheit,passwort aufheben,passwort löschen
|
||||||
|
|
||||||
home.compressPdfs.title=Komprimieren
|
home.compressPdfs.title=Komprimieren
|
||||||
home.compressPdfs.desc=PDF komprimieren um die Dateigröße zu reduzieren.
|
home.compressPdfs.desc=PDF komprimieren um die Dateigröße zu reduzieren
|
||||||
compressPdfs.tags=komprimieren,verkleinern,minimieren
|
compressPdfs.tags=komprimieren,verkleinern,minimieren
|
||||||
|
|
||||||
|
|
||||||
|
@ -252,7 +254,7 @@ home.fileToPDF.desc=Konvertieren Sie nahezu jede Datei in PDF (DOCX, PNG, XLS, P
|
||||||
fileToPDF.tags=transformation,format,dokument,bild,folie,text,konvertierung,büro,dokumente,word,excel,powerpoint
|
fileToPDF.tags=transformation,format,dokument,bild,folie,text,konvertierung,büro,dokumente,word,excel,powerpoint
|
||||||
|
|
||||||
home.ocr.title=Führe OCR/Cleanup-Scans aus
|
home.ocr.title=Führe OCR/Cleanup-Scans aus
|
||||||
home.ocr.desc=Cleanup scannt und erkennt Text aus Bildern in einer PDF-Datei und fügt ihn erneut als Text hinzu.
|
home.ocr.desc=Cleanup scannt und erkennt Text aus Bildern in einer PDF-Datei und fügt ihn erneut als Text hinzu
|
||||||
ocr.tags=erkennung,text,bild,scannen,lesen,identifizieren,erkennung,bearbeitbar
|
ocr.tags=erkennung,text,bild,scannen,lesen,identifizieren,erkennung,bearbeitbar
|
||||||
|
|
||||||
|
|
||||||
|
@ -435,6 +437,8 @@ login.rememberme=Angemeldet bleiben
|
||||||
login.invalid=Benutzername oder Passwort ungültig.
|
login.invalid=Benutzername oder Passwort ungültig.
|
||||||
login.locked=Ihr Konto wurde gesperrt.
|
login.locked=Ihr Konto wurde gesperrt.
|
||||||
login.signinTitle=Bitte melden Sie sich an.
|
login.signinTitle=Bitte melden Sie sich an.
|
||||||
|
login.ssoSignIn=Anmeldung per Single Sign-On
|
||||||
|
login.oauth2AutoCreateDisabled=OAUTH2 Benutzer automatisch erstellen deaktiviert
|
||||||
|
|
||||||
|
|
||||||
#auto-redact
|
#auto-redact
|
||||||
|
@ -445,7 +449,7 @@ autoRedact.textsToRedactLabel=Zu zensierender Text (einer pro Zeile)
|
||||||
autoRedact.textsToRedactPlaceholder=z.B. \nVertraulich \nStreng geheim
|
autoRedact.textsToRedactPlaceholder=z.B. \nVertraulich \nStreng geheim
|
||||||
autoRedact.useRegexLabel=Regex verwenden
|
autoRedact.useRegexLabel=Regex verwenden
|
||||||
autoRedact.wholeWordSearchLabel=Ganzes Wort suchen
|
autoRedact.wholeWordSearchLabel=Ganzes Wort suchen
|
||||||
autoRedact.customPaddingLabel=Benutzerdefinierte Extra-Padding
|
autoRedact.customPaddingLabel=Zensierten Bereich vergrößern
|
||||||
autoRedact.convertPDFToImageLabel=PDF in PDF-Bild konvertieren (zum Entfernen von Text hinter dem Kasten)
|
autoRedact.convertPDFToImageLabel=PDF in PDF-Bild konvertieren (zum Entfernen von Text hinter dem Kasten)
|
||||||
autoRedact.submitButton=Zensieren
|
autoRedact.submitButton=Zensieren
|
||||||
|
|
||||||
|
@ -499,16 +503,16 @@ HTMLToPDF.header=HTML zu PDF
|
||||||
HTMLToPDF.help=Akzeptiert HTML-Dateien und ZIPs mit html/css/images etc.
|
HTMLToPDF.help=Akzeptiert HTML-Dateien und ZIPs mit html/css/images etc.
|
||||||
HTMLToPDF.submit=Konvertieren
|
HTMLToPDF.submit=Konvertieren
|
||||||
HTMLToPDF.credit=Verwendet WeasyPrint
|
HTMLToPDF.credit=Verwendet WeasyPrint
|
||||||
HTMLToPDF.zoom=Zoomstufe zur Darstellung der Website.
|
HTMLToPDF.zoom=Zoomstufe zur Darstellung der Website
|
||||||
HTMLToPDF.pageWidth=Breite der Seite in Zentimetern. (Leer auf Standard)
|
HTMLToPDF.pageWidth=Breite der Seite in Zentimetern (Leer auf Standard)
|
||||||
HTMLToPDF.pageHeight=Höhe der Seite in Zentimetern. (Leer auf Standard)
|
HTMLToPDF.pageHeight=Höhe der Seite in Zentimetern (Leer auf Standard)
|
||||||
HTMLToPDF.marginTop=Oberer Rand der Seite in Millimetern. (Leer auf Standard)
|
HTMLToPDF.marginTop=Oberer Rand der Seite in Millimetern (Leer auf Standard)
|
||||||
HTMLToPDF.marginBottom=Unterer Rand der Seite in Millimetern. (Leer auf Standard)
|
HTMLToPDF.marginBottom=Unterer Rand der Seite in Millimetern (Leer auf Standard)
|
||||||
HTMLToPDF.marginLeft=Linker Rand der Seite in Millimetern. (Leer auf Standard)
|
HTMLToPDF.marginLeft=Linker Rand der Seite in Millimetern (Leer auf Standard)
|
||||||
HTMLToPDF.marginRight=Linker Rand der Seite in Millimetern. (Leer auf Standard)
|
HTMLToPDF.marginRight=Linker Rand der Seite in Millimetern (Leer auf Standard)
|
||||||
HTMLToPDF.printBackground=Den Hintergrund der Website rendern.
|
HTMLToPDF.printBackground=Den Hintergrund der Website rendern
|
||||||
HTMLToPDF.defaultHeader=Standardkopfzeile aktivieren (Name und Seitenzahl)
|
HTMLToPDF.defaultHeader=Standardkopfzeile aktivieren (Name und Seitenzahl)
|
||||||
HTMLToPDF.cssMediaType=CSS-Medientyp der Seite ändern.
|
HTMLToPDF.cssMediaType=CSS-Medientyp der Seite ändern
|
||||||
HTMLToPDF.none=Keine
|
HTMLToPDF.none=Keine
|
||||||
HTMLToPDF.print=Drucken
|
HTMLToPDF.print=Drucken
|
||||||
HTMLToPDF.screen=Bildschirm
|
HTMLToPDF.screen=Bildschirm
|
||||||
|
@ -609,8 +613,8 @@ pageLayout.submit=Abschicken
|
||||||
#scalePages
|
#scalePages
|
||||||
scalePages.title=Seitengröße anpassen
|
scalePages.title=Seitengröße anpassen
|
||||||
scalePages.header=Seitengröße anpassen
|
scalePages.header=Seitengröße anpassen
|
||||||
scalePages.pageSize=Format der Seiten des Dokuments.
|
scalePages.pageSize=Format der Seiten des Dokuments
|
||||||
scalePages.scaleFactor=Zoomstufe (Ausschnitt) einer Seite.
|
scalePages.scaleFactor=Zoomstufe (Ausschnitt) einer Seite
|
||||||
scalePages.submit=Abschicken
|
scalePages.submit=Abschicken
|
||||||
|
|
||||||
|
|
||||||
|
@ -753,7 +757,7 @@ compress.submit=Komprimieren
|
||||||
#Add image
|
#Add image
|
||||||
addImage.title=Bild hinzufügen
|
addImage.title=Bild hinzufügen
|
||||||
addImage.header=Ein Bild einfügen
|
addImage.header=Ein Bild einfügen
|
||||||
addImage.everyPage=Jede Seite?
|
addImage.everyPage=In jede Seite einfügen?
|
||||||
addImage.upload=Bild hinzufügen
|
addImage.upload=Bild hinzufügen
|
||||||
addImage.submit=Bild hinzufügen
|
addImage.submit=Bild hinzufügen
|
||||||
|
|
||||||
|
@ -938,7 +942,8 @@ pdfToPDFA.title=PDF zu PDF/A
|
||||||
pdfToPDFA.header=PDF zu PDF/A
|
pdfToPDFA.header=PDF zu PDF/A
|
||||||
pdfToPDFA.credit=Dieser Dienst verwendet OCRmyPDF für die PDF/A-Konvertierung
|
pdfToPDFA.credit=Dieser Dienst verwendet OCRmyPDF für die PDF/A-Konvertierung
|
||||||
pdfToPDFA.submit=Konvertieren
|
pdfToPDFA.submit=Konvertieren
|
||||||
pdfToPDFA.tip=Currently does not work for multiple inputs at once
|
pdfToPDFA.tip=Dieser Dienst kann nur einzelne Eingangsdateien verarbeiten.
|
||||||
|
pdfToPDFA.outputFormat=Ausgabeformat
|
||||||
|
|
||||||
|
|
||||||
#PDFToWord
|
#PDFToWord
|
||||||
|
@ -1022,6 +1027,15 @@ split-by-sections.vertical.placeholder=Anzahl vertikaler Teiler eingeben
|
||||||
split-by-sections.submit=PDF teilen
|
split-by-sections.submit=PDF teilen
|
||||||
split-by-sections.merge=In eine PDF zusammenfügen
|
split-by-sections.merge=In eine PDF zusammenfügen
|
||||||
|
|
||||||
|
|
||||||
|
#printFile
|
||||||
|
printFile.title=Datei drucken
|
||||||
|
printFile.header=Datei an Drucker senden
|
||||||
|
printFile.selectText.1=Wähle die auszudruckende Datei
|
||||||
|
printFile.selectText.2=Druckernamen eingeben
|
||||||
|
printFile.submit=Drucken
|
||||||
|
|
||||||
|
|
||||||
#licenses
|
#licenses
|
||||||
licenses.nav=Lizenzen
|
licenses.nav=Lizenzen
|
||||||
licenses.title=Lizenzen von Drittanbietern
|
licenses.title=Lizenzen von Drittanbietern
|
||||||
|
|
|
@ -112,6 +112,7 @@ navbar.settings=Ρυθμίσεις
|
||||||
#############
|
#############
|
||||||
settings.title=Ρυθμίσεις
|
settings.title=Ρυθμίσεις
|
||||||
settings.update=Υπάρχει διαθέσιμη ενημέρωση
|
settings.update=Υπάρχει διαθέσιμη ενημέρωση
|
||||||
|
settings.updateAvailable={0} is the current installed version. A new version ({1}) is available.
|
||||||
settings.appVersion=Έκδοση εφαρμογής:
|
settings.appVersion=Έκδοση εφαρμογής:
|
||||||
settings.downloadOption.title=Επιλέξετε την επιλογή λήψης (Για λήψεις μεμονωμένων αρχείων χωρίς zip):
|
settings.downloadOption.title=Επιλέξετε την επιλογή λήψης (Για λήψεις μεμονωμένων αρχείων χωρίς zip):
|
||||||
settings.downloadOption.1=Άνοιγμα στο ίδιο παράθυρο
|
settings.downloadOption.1=Άνοιγμα στο ίδιο παράθυρο
|
||||||
|
@ -120,8 +121,9 @@ settings.downloadOption.3=Λήψη αρχείου
|
||||||
settings.zipThreshold=Αρχεία Zip όταν ο αριθμός των ληφθέντων αρχείων είναι πολύ μεγάλος
|
settings.zipThreshold=Αρχεία Zip όταν ο αριθμός των ληφθέντων αρχείων είναι πολύ μεγάλος
|
||||||
settings.signOut=Αποσύνδεση
|
settings.signOut=Αποσύνδεση
|
||||||
settings.accountSettings=Ρυθμίσεις Λογαριασμού
|
settings.accountSettings=Ρυθμίσεις Λογαριασμού
|
||||||
|
settings.bored.help=Enables easter egg game
|
||||||
|
settings.cacheInputs.name=Save form inputs
|
||||||
|
settings.cacheInputs.help=Enable to store previously used inputs for future runs
|
||||||
|
|
||||||
changeCreds.title=Αλλαγή Διαπιστευτηρίων
|
changeCreds.title=Αλλαγή Διαπιστευτηρίων
|
||||||
changeCreds.header=Ενημέρωση των λεπτομερειών του Λογαριασμού σας
|
changeCreds.header=Ενημέρωση των λεπτομερειών του Λογαριασμού σας
|
||||||
|
@ -435,6 +437,8 @@ login.rememberme=Να Με Θυμάσαι
|
||||||
login.invalid=Λάθος όνομα χρήστη ή κωδικού πρόσβασης.
|
login.invalid=Λάθος όνομα χρήστη ή κωδικού πρόσβασης.
|
||||||
login.locked=Ο λογαριασμός σας έχει κλειδωθεί.
|
login.locked=Ο λογαριασμός σας έχει κλειδωθεί.
|
||||||
login.signinTitle=Παρακαλώ, συνδεθείτε
|
login.signinTitle=Παρακαλώ, συνδεθείτε
|
||||||
|
login.ssoSignIn=Σύνδεση μέσω μοναδικής σύνδεσης
|
||||||
|
login.oauth2AutoCreateDisabled=Απενεργοποιήθηκε ο χρήστης αυτόματης δημιουργίας OAUTH2
|
||||||
|
|
||||||
|
|
||||||
#auto-redact
|
#auto-redact
|
||||||
|
@ -939,6 +943,7 @@ pdfToPDFA.header=PDF σε PDF/A
|
||||||
pdfToPDFA.credit=Αυτή η υπηρεσία χρησιμοποιεί OCRmyPDF για PDF/A μετατροπή
|
pdfToPDFA.credit=Αυτή η υπηρεσία χρησιμοποιεί OCRmyPDF για PDF/A μετατροπή
|
||||||
pdfToPDFA.submit=Μετατροπή
|
pdfToPDFA.submit=Μετατροπή
|
||||||
pdfToPDFA.tip=Προς το παρόν δεν λειτουργεί για πολλαπλές εισόδους ταυτόχρονα
|
pdfToPDFA.tip=Προς το παρόν δεν λειτουργεί για πολλαπλές εισόδους ταυτόχρονα
|
||||||
|
pdfToPDFA.outputFormat=Output format
|
||||||
|
|
||||||
|
|
||||||
#PDFToWord
|
#PDFToWord
|
||||||
|
@ -1022,6 +1027,15 @@ split-by-sections.vertical.placeholder=Εισαγάγετε τον αριθμό
|
||||||
split-by-sections.submit=Διαχωρισμός PDF
|
split-by-sections.submit=Διαχωρισμός PDF
|
||||||
split-by-sections.merge=Συγχώνευση σε ένα PDF
|
split-by-sections.merge=Συγχώνευση σε ένα PDF
|
||||||
|
|
||||||
|
|
||||||
|
#printFile
|
||||||
|
printFile.title=Print File
|
||||||
|
printFile.header=Print File to Printer
|
||||||
|
printFile.selectText.1=Select File to Print
|
||||||
|
printFile.selectText.2=Enter Printer Name
|
||||||
|
printFile.submit=Print
|
||||||
|
|
||||||
|
|
||||||
#licenses
|
#licenses
|
||||||
licenses.nav=Άδειες
|
licenses.nav=Άδειες
|
||||||
licenses.title=3rd Party Άδειες
|
licenses.title=3rd Party Άδειες
|
||||||
|
|
|
@ -112,6 +112,7 @@ navbar.settings=Settings
|
||||||
#############
|
#############
|
||||||
settings.title=Settings
|
settings.title=Settings
|
||||||
settings.update=Update available
|
settings.update=Update available
|
||||||
|
settings.updateAvailable={0} is the current installed version. A new version ({1}) is available.
|
||||||
settings.appVersion=App Version:
|
settings.appVersion=App Version:
|
||||||
settings.downloadOption.title=Choose download option (For single file non zip downloads):
|
settings.downloadOption.title=Choose download option (For single file non zip downloads):
|
||||||
settings.downloadOption.1=Open in same window
|
settings.downloadOption.1=Open in same window
|
||||||
|
@ -120,8 +121,9 @@ settings.downloadOption.3=Download file
|
||||||
settings.zipThreshold=Zip files when the number of downloaded files exceeds
|
settings.zipThreshold=Zip files when the number of downloaded files exceeds
|
||||||
settings.signOut=Sign Out
|
settings.signOut=Sign Out
|
||||||
settings.accountSettings=Account Settings
|
settings.accountSettings=Account Settings
|
||||||
|
settings.bored.help=Enables easter egg game
|
||||||
|
settings.cacheInputs.name=Save form inputs
|
||||||
|
settings.cacheInputs.help=Enable to store previously used inputs for future runs
|
||||||
|
|
||||||
changeCreds.title=Change Credentials
|
changeCreds.title=Change Credentials
|
||||||
changeCreds.header=Update Your Account Details
|
changeCreds.header=Update Your Account Details
|
||||||
|
@ -435,6 +437,8 @@ login.rememberme=Remember me
|
||||||
login.invalid=Invalid username or password.
|
login.invalid=Invalid username or password.
|
||||||
login.locked=Your account has been locked.
|
login.locked=Your account has been locked.
|
||||||
login.signinTitle=Please sign in
|
login.signinTitle=Please sign in
|
||||||
|
login.ssoSignIn=Login via Single Sign-on
|
||||||
|
login.oauth2AutoCreateDisabled=OAUTH2 Auto-Create User Disabled
|
||||||
|
|
||||||
|
|
||||||
#auto-redact
|
#auto-redact
|
||||||
|
@ -939,6 +943,7 @@ pdfToPDFA.header=PDF To PDF/A
|
||||||
pdfToPDFA.credit=This service uses OCRmyPDF for PDF/A conversion
|
pdfToPDFA.credit=This service uses OCRmyPDF for PDF/A conversion
|
||||||
pdfToPDFA.submit=Convert
|
pdfToPDFA.submit=Convert
|
||||||
pdfToPDFA.tip=Currently does not work for multiple inputs at once
|
pdfToPDFA.tip=Currently does not work for multiple inputs at once
|
||||||
|
pdfToPDFA.outputFormat=Output format
|
||||||
|
|
||||||
|
|
||||||
#PDFToWord
|
#PDFToWord
|
||||||
|
@ -1022,6 +1027,15 @@ split-by-sections.vertical.placeholder=Enter number of vertical divisions
|
||||||
split-by-sections.submit=Split PDF
|
split-by-sections.submit=Split PDF
|
||||||
split-by-sections.merge=Merge Into One PDF
|
split-by-sections.merge=Merge Into One PDF
|
||||||
|
|
||||||
|
|
||||||
|
#printFile
|
||||||
|
printFile.title=Print File
|
||||||
|
printFile.header=Print File to Printer
|
||||||
|
printFile.selectText.1=Select File to Print
|
||||||
|
printFile.selectText.2=Enter Printer Name
|
||||||
|
printFile.submit=Print
|
||||||
|
|
||||||
|
|
||||||
#licenses
|
#licenses
|
||||||
licenses.nav=Licenses
|
licenses.nav=Licenses
|
||||||
licenses.title=3rd Party Licenses
|
licenses.title=3rd Party Licenses
|
||||||
|
|
|
@ -112,6 +112,7 @@ navbar.settings=Settings
|
||||||
#############
|
#############
|
||||||
settings.title=Settings
|
settings.title=Settings
|
||||||
settings.update=Update available
|
settings.update=Update available
|
||||||
|
settings.updateAvailable={0} is the current installed version. A new version ({1}) is available.
|
||||||
settings.appVersion=App Version:
|
settings.appVersion=App Version:
|
||||||
settings.downloadOption.title=Choose download option (For single file non zip downloads):
|
settings.downloadOption.title=Choose download option (For single file non zip downloads):
|
||||||
settings.downloadOption.1=Open in same window
|
settings.downloadOption.1=Open in same window
|
||||||
|
@ -120,8 +121,9 @@ settings.downloadOption.3=Download file
|
||||||
settings.zipThreshold=Zip files when the number of downloaded files exceeds
|
settings.zipThreshold=Zip files when the number of downloaded files exceeds
|
||||||
settings.signOut=Sign Out
|
settings.signOut=Sign Out
|
||||||
settings.accountSettings=Account Settings
|
settings.accountSettings=Account Settings
|
||||||
|
settings.bored.help=Enables easter egg game
|
||||||
|
settings.cacheInputs.name=Save form inputs
|
||||||
|
settings.cacheInputs.help=Enable to store previously used inputs for future runs
|
||||||
|
|
||||||
changeCreds.title=Change Credentials
|
changeCreds.title=Change Credentials
|
||||||
changeCreds.header=Update Your Account Details
|
changeCreds.header=Update Your Account Details
|
||||||
|
@ -435,6 +437,8 @@ login.rememberme=Remember me
|
||||||
login.invalid=Invalid username or password.
|
login.invalid=Invalid username or password.
|
||||||
login.locked=Your account has been locked.
|
login.locked=Your account has been locked.
|
||||||
login.signinTitle=Please sign in
|
login.signinTitle=Please sign in
|
||||||
|
login.ssoSignIn=Login via Single Sign-on
|
||||||
|
login.oauth2AutoCreateDisabled=OAUTH2 Auto-Create User Disabled
|
||||||
|
|
||||||
|
|
||||||
#auto-redact
|
#auto-redact
|
||||||
|
@ -939,6 +943,7 @@ pdfToPDFA.header=PDF To PDF/A
|
||||||
pdfToPDFA.credit=This service uses OCRmyPDF for PDF/A conversion
|
pdfToPDFA.credit=This service uses OCRmyPDF for PDF/A conversion
|
||||||
pdfToPDFA.submit=Convert
|
pdfToPDFA.submit=Convert
|
||||||
pdfToPDFA.tip=Currently does not work for multiple inputs at once
|
pdfToPDFA.tip=Currently does not work for multiple inputs at once
|
||||||
|
pdfToPDFA.outputFormat=Output format
|
||||||
|
|
||||||
|
|
||||||
#PDFToWord
|
#PDFToWord
|
||||||
|
@ -1022,6 +1027,15 @@ split-by-sections.vertical.placeholder=Enter number of vertical divisions
|
||||||
split-by-sections.submit=Split PDF
|
split-by-sections.submit=Split PDF
|
||||||
split-by-sections.merge=Merge Into One PDF
|
split-by-sections.merge=Merge Into One PDF
|
||||||
|
|
||||||
|
|
||||||
|
#printFile
|
||||||
|
printFile.title=Print File
|
||||||
|
printFile.header=Print File to Printer
|
||||||
|
printFile.selectText.1=Select File to Print
|
||||||
|
printFile.selectText.2=Enter Printer Name
|
||||||
|
printFile.submit=Print
|
||||||
|
|
||||||
|
|
||||||
#licenses
|
#licenses
|
||||||
licenses.nav=Licenses
|
licenses.nav=Licenses
|
||||||
licenses.title=3rd Party Licenses
|
licenses.title=3rd Party Licenses
|
||||||
|
|
|
@ -58,15 +58,15 @@ invalidUsernameMessage=Nombre de usuario no válido, El nombre de ususario debe
|
||||||
deleteCurrentUserMessage=No puede eliminar el usuario que tiene la sesión actualmente en uso.
|
deleteCurrentUserMessage=No puede eliminar el usuario que tiene la sesión actualmente en uso.
|
||||||
deleteUsernameExistsMessage=El usuario no existe y no puede eliminarse.
|
deleteUsernameExistsMessage=El usuario no existe y no puede eliminarse.
|
||||||
error=Error
|
error=Error
|
||||||
oops=Oops!
|
oops=Ups!
|
||||||
help=Help
|
help=Help
|
||||||
goHomepage=Go to Homepage
|
goHomepage=Ir a la página principal
|
||||||
joinDiscord=Join our Discord server
|
joinDiscord=Únase a nuestro servidor Discord
|
||||||
seeDockerHub=See Docker Hub
|
seeDockerHub=Ver Docker Hub
|
||||||
visitGithub=Visit Github Repository
|
visitGithub=Visitar Repositorio de Github
|
||||||
donate=Donate
|
donate=Donar
|
||||||
color=Color
|
color=Color
|
||||||
sponsor=Sponsor
|
sponsor=Patrocinador
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -78,8 +78,8 @@ pipeline.uploadButton=Cargar personalización
|
||||||
pipeline.configureButton=Configurar
|
pipeline.configureButton=Configurar
|
||||||
pipeline.defaultOption=Personalizar
|
pipeline.defaultOption=Personalizar
|
||||||
pipeline.submitButton=Enviar
|
pipeline.submitButton=Enviar
|
||||||
pipeline.help=Pipeline Help
|
pipeline.help=Ayuda de Canalización
|
||||||
pipeline.scanHelp=Folder Scanning Help
|
pipeline.scanHelp=Ayuda de escaneado de carpetas
|
||||||
|
|
||||||
######################
|
######################
|
||||||
# Pipeline Options #
|
# Pipeline Options #
|
||||||
|
@ -112,6 +112,7 @@ navbar.settings=Configuración
|
||||||
#############
|
#############
|
||||||
settings.title=Configuración
|
settings.title=Configuración
|
||||||
settings.update=Actualización disponible
|
settings.update=Actualización disponible
|
||||||
|
settings.updateAvailable={0} es la versión instalada. Hay disponible una versión nueva ({1}).
|
||||||
settings.appVersion=Versión de la aplicación:
|
settings.appVersion=Versión de la aplicación:
|
||||||
settings.downloadOption.title=Elegir la opción de descarga (para descargas de un solo archivo sin ZIP):
|
settings.downloadOption.title=Elegir la opción de descarga (para descargas de un solo archivo sin ZIP):
|
||||||
settings.downloadOption.1=Abrir en la misma ventana
|
settings.downloadOption.1=Abrir en la misma ventana
|
||||||
|
@ -120,8 +121,9 @@ settings.downloadOption.3=Descargar el archivo
|
||||||
settings.zipThreshold=Archivos ZIP cuando excede el número de archivos descargados
|
settings.zipThreshold=Archivos ZIP cuando excede el número de archivos descargados
|
||||||
settings.signOut=Desconectar
|
settings.signOut=Desconectar
|
||||||
settings.accountSettings=Configuración de la cuenta
|
settings.accountSettings=Configuración de la cuenta
|
||||||
|
settings.bored.help=Habilita el juego del huevo de pascua
|
||||||
|
settings.cacheInputs.name=Guardar entradas del formulario
|
||||||
|
settings.cacheInputs.help=Habilitar guardar entradas previamente utilizadas para futuras acciones
|
||||||
|
|
||||||
changeCreds.title=Cambiar Credenciales
|
changeCreds.title=Cambiar Credenciales
|
||||||
changeCreds.header=Actualice los detalles de su cuenta
|
changeCreds.header=Actualice los detalles de su cuenta
|
||||||
|
@ -245,7 +247,7 @@ compressPdfs.tags=aplastar,pequeño,diminuto
|
||||||
|
|
||||||
home.changeMetadata.title=Cambiar metadatos
|
home.changeMetadata.title=Cambiar metadatos
|
||||||
home.changeMetadata.desc=Cambiar/Eliminar/Añadir metadatos al documento PDF
|
home.changeMetadata.desc=Cambiar/Eliminar/Añadir metadatos al documento PDF
|
||||||
changeMetadata.tags==Título,autor,fecha,creación,hora,editorial,productor,estadísticas
|
changeMetadata.tags=título,autor,fecha,creación,hora,editorial,productor,estadísticas
|
||||||
|
|
||||||
home.fileToPDF.title=Convertir archivo a PDF
|
home.fileToPDF.title=Convertir archivo a PDF
|
||||||
home.fileToPDF.desc=Convertir casi cualquier archivo a PDF (DOCX, PNG, XLS, PPT, TXT y más)
|
home.fileToPDF.desc=Convertir casi cualquier archivo a PDF (DOCX, PNG, XLS, PPT, TXT y más)
|
||||||
|
@ -435,6 +437,8 @@ login.rememberme=Recordarme
|
||||||
login.invalid=Nombre de usuario o contraseña erróneos.
|
login.invalid=Nombre de usuario o contraseña erróneos.
|
||||||
login.locked=Su cuenta se ha bloqueado.
|
login.locked=Su cuenta se ha bloqueado.
|
||||||
login.signinTitle=Por favor, inicie sesión
|
login.signinTitle=Por favor, inicie sesión
|
||||||
|
login.ssoSignIn=Iniciar sesión a través del inicio de sesión único
|
||||||
|
login.oauth2AutoCreateDisabled=Usuario DE creación automática de OAUTH2 DESACTIVADO
|
||||||
|
|
||||||
|
|
||||||
#auto-redact
|
#auto-redact
|
||||||
|
@ -770,23 +774,23 @@ merge.submit=Unir
|
||||||
pdfOrganiser.title=Organizador de páginas
|
pdfOrganiser.title=Organizador de páginas
|
||||||
pdfOrganiser.header=Organizador de páginas PDF
|
pdfOrganiser.header=Organizador de páginas PDF
|
||||||
pdfOrganiser.submit=Organizar páginas
|
pdfOrganiser.submit=Organizar páginas
|
||||||
pdfOrganiser.mode=Mode
|
pdfOrganiser.mode=Modo
|
||||||
pdfOrganiser.mode.1=Custom Page Order
|
pdfOrganiser.mode.1=Orden de páginas personalizado
|
||||||
pdfOrganiser.mode.2=Reverse Order
|
pdfOrganiser.mode.2=Orden inverso
|
||||||
pdfOrganiser.mode.3=Duplex Sort
|
pdfOrganiser.mode.3=Ordenar dúplex
|
||||||
pdfOrganiser.mode.4=Booklet Sort
|
pdfOrganiser.mode.4=Ordenar folleto
|
||||||
pdfOrganiser.mode.5=Side Stitch Booklet Sort
|
pdfOrganiser.mode.5=Orden de folleto de encuadernado lateral
|
||||||
pdfOrganiser.mode.6=Odd-Even Split
|
pdfOrganiser.mode.6=División par-impar
|
||||||
pdfOrganiser.mode.7=Remove First
|
pdfOrganiser.mode.7=Quitar primera
|
||||||
pdfOrganiser.mode.8=Remove Last
|
pdfOrganiser.mode.8=Quitar última
|
||||||
pdfOrganiser.mode.9=Remove First and Last
|
pdfOrganiser.mode.9=Quitar primera y última
|
||||||
pdfOrganiser.placeholder=(e.g. 1,3,2 or 4-8,2,10-12 or 2n-1)
|
pdfOrganiser.placeholder=(por ej., 1,3,2 o 4-8,2,10-12 o 2n-1)
|
||||||
|
|
||||||
|
|
||||||
#multiTool
|
#multiTool
|
||||||
multiTool.title=Multi-herramienta PDF
|
multiTool.title=Multi-herramienta PDF
|
||||||
multiTool.header=Multi-herramienta PDF
|
multiTool.header=Multi-herramienta PDF
|
||||||
multiTool.uploadPrompts=Please Upload PDF
|
multiTool.uploadPrompts=Por favor, cargue PDF
|
||||||
|
|
||||||
#view pdf
|
#view pdf
|
||||||
viewPdf.title=Ver PDF
|
viewPdf.title=Ver PDF
|
||||||
|
@ -885,8 +889,8 @@ watermark.selectText.7=Opacidad (0% - 100%):
|
||||||
watermark.selectText.8=Tipo de marca de agua:
|
watermark.selectText.8=Tipo de marca de agua:
|
||||||
watermark.selectText.9=Imagen de marca de agua:
|
watermark.selectText.9=Imagen de marca de agua:
|
||||||
watermark.submit=Añadir marca de agua
|
watermark.submit=Añadir marca de agua
|
||||||
watermark.type.1=Text
|
watermark.type.1=Texto
|
||||||
watermark.type.2=Image
|
watermark.type.2=Imagen
|
||||||
|
|
||||||
|
|
||||||
#Change permissions
|
#Change permissions
|
||||||
|
@ -938,7 +942,8 @@ pdfToPDFA.title=PDF a PDF/A
|
||||||
pdfToPDFA.header=PDF a PDF/A
|
pdfToPDFA.header=PDF a PDF/A
|
||||||
pdfToPDFA.credit=Este servicio usa OCRmyPDF para la conversión a PDF/A
|
pdfToPDFA.credit=Este servicio usa OCRmyPDF para la conversión a PDF/A
|
||||||
pdfToPDFA.submit=Convertir
|
pdfToPDFA.submit=Convertir
|
||||||
pdfToPDFA.tip=Currently does not work for multiple inputs at once
|
pdfToPDFA.tip=Actualmente no funciona para múltiples entrada a la vez
|
||||||
|
pdfToPDFA.outputFormat=Output format
|
||||||
|
|
||||||
|
|
||||||
#PDFToWord
|
#PDFToWord
|
||||||
|
@ -1022,6 +1027,15 @@ split-by-sections.vertical.placeholder=Introduzca el número de divisiones verti
|
||||||
split-by-sections.submit=Dividir PDF
|
split-by-sections.submit=Dividir PDF
|
||||||
split-by-sections.merge=Unir en Un PDF
|
split-by-sections.merge=Unir en Un PDF
|
||||||
|
|
||||||
|
|
||||||
|
#printFile
|
||||||
|
printFile.title=Imprimir archivo
|
||||||
|
printFile.header=Imprimir archivo en la impresora
|
||||||
|
printFile.selectText.1=Seleccionar archivo para imprimir
|
||||||
|
printFile.selectText.2=Introducir nombre de la impresora
|
||||||
|
printFile.submit=Imprimir
|
||||||
|
|
||||||
|
|
||||||
#licenses
|
#licenses
|
||||||
licenses.nav=Licencias
|
licenses.nav=Licencias
|
||||||
licenses.title=Licencias de terceros
|
licenses.title=Licencias de terceros
|
||||||
|
@ -1032,15 +1046,15 @@ licenses.license=Licencia
|
||||||
|
|
||||||
|
|
||||||
# error
|
# error
|
||||||
error.sorry=Sorry for the issue!
|
error.sorry=¡Perdón por el fallo!
|
||||||
error.needHelp=Need help / Found an issue?
|
error.needHelp=Necesita ayuda / Encontró un fallo?
|
||||||
error.contactTip=If you're still having trouble, don't hesitate to reach out to us for help. You can submit a ticket on our GitHub page or contact us through Discord:
|
error.contactTip=Si sigue experimentando errores, no dude en contactarnos para solicitar soporte. Puede enviarnos un ticket en la página de GitHub o contactarnos mediante Discord:
|
||||||
error.404.head=404 - Page Not Found | Oops, we tripped in the code!
|
error.404.head=404 - Página no encontrada | Ups, tropezamos con el código!
|
||||||
error.404.1=We can't seem to find the page you're looking for.
|
error.404.1=Parece que no podemos encontrar la página que está buscando.
|
||||||
error.404.2=Something went wrong
|
error.404.2=Algo salió mal
|
||||||
error.github=Submit a ticket on GitHub
|
error.github=Envíe un ticket en GitHub
|
||||||
error.showStack=Show Stack Trace
|
error.showStack=Mostrar seguimiento de pila
|
||||||
error.copyStack=Copy Stack Trace
|
error.copyStack=Mostrar seguimiento de pila
|
||||||
error.githubSubmit=GitHub - Submit a ticket
|
error.githubSubmit=GitHub - Enviar un ticket
|
||||||
error.discordSubmit=Discord - Submit Support post
|
error.discordSubmit=Discord - Enviar mensaje de soporte
|
||||||
|
|
||||||
|
|
|
@ -112,6 +112,7 @@ navbar.settings=Ezarpenak
|
||||||
#############
|
#############
|
||||||
settings.title=Ezarpenak
|
settings.title=Ezarpenak
|
||||||
settings.update=Eguneratze eskuragarria
|
settings.update=Eguneratze eskuragarria
|
||||||
|
settings.updateAvailable={0} is the current installed version. A new version ({1}) is available.
|
||||||
settings.appVersion=Aplikazioaren bertsioa:
|
settings.appVersion=Aplikazioaren bertsioa:
|
||||||
settings.downloadOption.title=Hautatu deskargatzeko aukera (fitxategi bakarra deskargatzeko ZIP gabe):
|
settings.downloadOption.title=Hautatu deskargatzeko aukera (fitxategi bakarra deskargatzeko ZIP gabe):
|
||||||
settings.downloadOption.1=Ireki leiho berean
|
settings.downloadOption.1=Ireki leiho berean
|
||||||
|
@ -120,8 +121,9 @@ settings.downloadOption.3=Deskargatu fitxategia
|
||||||
settings.zipThreshold=ZIP fitxategiak deskargatutako fitxategi kopurua gainditzen denean
|
settings.zipThreshold=ZIP fitxategiak deskargatutako fitxategi kopurua gainditzen denean
|
||||||
settings.signOut=Saioa itxi
|
settings.signOut=Saioa itxi
|
||||||
settings.accountSettings=Kontuaren ezarpenak
|
settings.accountSettings=Kontuaren ezarpenak
|
||||||
|
settings.bored.help=Enables easter egg game
|
||||||
|
settings.cacheInputs.name=Save form inputs
|
||||||
|
settings.cacheInputs.help=Enable to store previously used inputs for future runs
|
||||||
|
|
||||||
changeCreds.title=Change Credentials
|
changeCreds.title=Change Credentials
|
||||||
changeCreds.header=Update Your Account Details
|
changeCreds.header=Update Your Account Details
|
||||||
|
@ -435,6 +437,8 @@ login.rememberme=Oroitu nazazu
|
||||||
login.invalid=Okerreko erabiltzaile izena edo pasahitza.
|
login.invalid=Okerreko erabiltzaile izena edo pasahitza.
|
||||||
login.locked=Zure kontua blokeatu egin da.
|
login.locked=Zure kontua blokeatu egin da.
|
||||||
login.signinTitle=Mesedez, hasi saioa
|
login.signinTitle=Mesedez, hasi saioa
|
||||||
|
login.ssoSignIn=Hasi saioa Saioa hasteko modu bakarraren bidez
|
||||||
|
login.oauth2AutoCreateDisabled=OAUTH2 Sortu automatikoki erabiltzailea desgaituta dago
|
||||||
|
|
||||||
|
|
||||||
#auto-redact
|
#auto-redact
|
||||||
|
@ -939,6 +943,7 @@ pdfToPDFA.header=PDFa PDF/A bihurtu
|
||||||
pdfToPDFA.credit=Zerbitzu honek OCRmyPDF erabiltzen du PDFak PDF/A bihurtzeko
|
pdfToPDFA.credit=Zerbitzu honek OCRmyPDF erabiltzen du PDFak PDF/A bihurtzeko
|
||||||
pdfToPDFA.submit=Bihurtu
|
pdfToPDFA.submit=Bihurtu
|
||||||
pdfToPDFA.tip=Currently does not work for multiple inputs at once
|
pdfToPDFA.tip=Currently does not work for multiple inputs at once
|
||||||
|
pdfToPDFA.outputFormat=Output format
|
||||||
|
|
||||||
|
|
||||||
#PDFToWord
|
#PDFToWord
|
||||||
|
@ -1022,6 +1027,15 @@ split-by-sections.vertical.placeholder=Enter number of vertical divisions
|
||||||
split-by-sections.submit=Split PDF
|
split-by-sections.submit=Split PDF
|
||||||
split-by-sections.merge=Merge Into One PDF
|
split-by-sections.merge=Merge Into One PDF
|
||||||
|
|
||||||
|
|
||||||
|
#printFile
|
||||||
|
printFile.title=Print File
|
||||||
|
printFile.header=Print File to Printer
|
||||||
|
printFile.selectText.1=Select File to Print
|
||||||
|
printFile.selectText.2=Enter Printer Name
|
||||||
|
printFile.submit=Print
|
||||||
|
|
||||||
|
|
||||||
#licenses
|
#licenses
|
||||||
licenses.nav=Licenses
|
licenses.nav=Licenses
|
||||||
licenses.title=3rd Party Licenses
|
licenses.title=3rd Party Licenses
|
||||||
|
|
|
@ -112,6 +112,7 @@ navbar.settings=Paramètres
|
||||||
#############
|
#############
|
||||||
settings.title=Paramètres
|
settings.title=Paramètres
|
||||||
settings.update=Mise à jour disponible
|
settings.update=Mise à jour disponible
|
||||||
|
settings.updateAvailable={0} is the current installed version. A new version ({1}) is available.
|
||||||
settings.appVersion=Version de l’application :
|
settings.appVersion=Version de l’application :
|
||||||
settings.downloadOption.title=Choisissez l’option de téléchargement (pour les téléchargements à fichier unique non ZIP) :
|
settings.downloadOption.title=Choisissez l’option de téléchargement (pour les téléchargements à fichier unique non ZIP) :
|
||||||
settings.downloadOption.1=Ouvrir dans la même fenêtre
|
settings.downloadOption.1=Ouvrir dans la même fenêtre
|
||||||
|
@ -120,8 +121,9 @@ settings.downloadOption.3=Télécharger le fichier
|
||||||
settings.zipThreshold=Compresser les fichiers en ZIP lorsque le nombre de fichiers téléchargés dépasse
|
settings.zipThreshold=Compresser les fichiers en ZIP lorsque le nombre de fichiers téléchargés dépasse
|
||||||
settings.signOut=Déconnexion
|
settings.signOut=Déconnexion
|
||||||
settings.accountSettings=Paramètres du compte
|
settings.accountSettings=Paramètres du compte
|
||||||
|
settings.bored.help=Enables easter egg game
|
||||||
|
settings.cacheInputs.name=Save form inputs
|
||||||
|
settings.cacheInputs.help=Enable to store previously used inputs for future runs
|
||||||
|
|
||||||
changeCreds.title=Modifiez vos identifiants
|
changeCreds.title=Modifiez vos identifiants
|
||||||
changeCreds.header=Mettez à jour vos identifiants de connexion
|
changeCreds.header=Mettez à jour vos identifiants de connexion
|
||||||
|
@ -435,6 +437,8 @@ login.rememberme=Se souvenir de moi
|
||||||
login.invalid=Nom d’utilisateur ou mot de passe invalide.
|
login.invalid=Nom d’utilisateur ou mot de passe invalide.
|
||||||
login.locked=Votre compte a été verrouillé.
|
login.locked=Votre compte a été verrouillé.
|
||||||
login.signinTitle=Veuillez vous connecter
|
login.signinTitle=Veuillez vous connecter
|
||||||
|
login.ssoSignIn=Se connecter via l'authentification unique
|
||||||
|
login.oauth2AutoCreateDisabled=OAUTH2 Création automatique d'utilisateur désactivée
|
||||||
|
|
||||||
|
|
||||||
#auto-redact
|
#auto-redact
|
||||||
|
@ -939,6 +943,7 @@ pdfToPDFA.header=PDF en PDF/A
|
||||||
pdfToPDFA.credit=Ce service utilise OCRmyPDF pour la conversion en PDF/A.
|
pdfToPDFA.credit=Ce service utilise OCRmyPDF pour la conversion en PDF/A.
|
||||||
pdfToPDFA.submit=Convertir
|
pdfToPDFA.submit=Convertir
|
||||||
pdfToPDFA.tip=Currently does not work for multiple inputs at once
|
pdfToPDFA.tip=Currently does not work for multiple inputs at once
|
||||||
|
pdfToPDFA.outputFormat=Output format
|
||||||
|
|
||||||
|
|
||||||
#PDFToWord
|
#PDFToWord
|
||||||
|
@ -1022,6 +1027,15 @@ split-by-sections.vertical.placeholder=Entrer le nombre de divisions verticales
|
||||||
split-by-sections.submit=Diviser le PDF
|
split-by-sections.submit=Diviser le PDF
|
||||||
split-by-sections.merge=Fusionner en un seul PDF
|
split-by-sections.merge=Fusionner en un seul PDF
|
||||||
|
|
||||||
|
|
||||||
|
#printFile
|
||||||
|
printFile.title=Print File
|
||||||
|
printFile.header=Print File to Printer
|
||||||
|
printFile.selectText.1=Select File to Print
|
||||||
|
printFile.selectText.2=Enter Printer Name
|
||||||
|
printFile.submit=Print
|
||||||
|
|
||||||
|
|
||||||
#licenses
|
#licenses
|
||||||
licenses.nav=Licences
|
licenses.nav=Licences
|
||||||
licenses.title=Licences tierces
|
licenses.title=Licences tierces
|
||||||
|
|
|
@ -112,6 +112,7 @@ navbar.settings=सेटिंग्स
|
||||||
#############
|
#############
|
||||||
settings.title=सेटिंग्स
|
settings.title=सेटिंग्स
|
||||||
settings.update=अपडेट उपलब्ध है
|
settings.update=अपडेट उपलब्ध है
|
||||||
|
settings.updateAvailable={0} is the current installed version. A new version ({1}) is available.
|
||||||
settings.appVersion=ऐप संस्करण:
|
settings.appVersion=ऐप संस्करण:
|
||||||
settings.downloadOption.title=डाउनलोड विकल्प चुनें (एकल फ़ाइल गैर-ज़िप डाउनलोड के लिए):
|
settings.downloadOption.title=डाउनलोड विकल्प चुनें (एकल फ़ाइल गैर-ज़िप डाउनलोड के लिए):
|
||||||
settings.downloadOption.1=एक ही विंडो में खोलें
|
settings.downloadOption.1=एक ही विंडो में खोलें
|
||||||
|
@ -120,8 +121,9 @@ settings.downloadOption.3=फ़ाइल डाउनलोड करें
|
||||||
settings.zipThreshold=जब डाउनलोड की गई फ़ाइलों की संख्या सीमा से अधिक हो
|
settings.zipThreshold=जब डाउनलोड की गई फ़ाइलों की संख्या सीमा से अधिक हो
|
||||||
settings.signOut=साइन आउट
|
settings.signOut=साइन आउट
|
||||||
settings.accountSettings=खाता सेटिंग्स
|
settings.accountSettings=खाता सेटिंग्स
|
||||||
|
settings.bored.help=Enables easter egg game
|
||||||
|
settings.cacheInputs.name=Save form inputs
|
||||||
|
settings.cacheInputs.help=Enable to store previously used inputs for future runs
|
||||||
|
|
||||||
changeCreds.title=क्रेडेंशियल बदलें
|
changeCreds.title=क्रेडेंशियल बदलें
|
||||||
changeCreds.header=अपना खाता विवरण अपडेट करें
|
changeCreds.header=अपना खाता विवरण अपडेट करें
|
||||||
|
@ -435,6 +437,8 @@ login.rememberme=मुझे याद रखें
|
||||||
login.invalid=अमान्य उपयोगकर्ता नाम या पासवर्ड।
|
login.invalid=अमान्य उपयोगकर्ता नाम या पासवर्ड।
|
||||||
login.locked=आपका खाता लॉक कर दिया गया है।
|
login.locked=आपका खाता लॉक कर दिया गया है।
|
||||||
login.signinTitle=कृपया साइन इन करें
|
login.signinTitle=कृपया साइन इन करें
|
||||||
|
login.ssoSignIn=सिंगल साइन - ऑन के ज़रिए लॉग इन करें
|
||||||
|
login.oauth2AutoCreateDisabled=OAUTH2 ऑटो - क्रिएट यूज़र अक्षम किया गया
|
||||||
|
|
||||||
|
|
||||||
#auto-redact
|
#auto-redact
|
||||||
|
@ -939,6 +943,7 @@ pdfToPDFA.header=PDF से PDF/A में
|
||||||
pdfToPDFA.credit=इस सेवा में PDF/A परिवर्तन के लिए OCRmyPDF का उपयोग किया जाता है।
|
pdfToPDFA.credit=इस सेवा में PDF/A परिवर्तन के लिए OCRmyPDF का उपयोग किया जाता है।
|
||||||
pdfToPDFA.submit=परिवर्तित करें
|
pdfToPDFA.submit=परिवर्तित करें
|
||||||
pdfToPDFA.tip=Currently does not work for multiple inputs at once
|
pdfToPDFA.tip=Currently does not work for multiple inputs at once
|
||||||
|
pdfToPDFA.outputFormat=Output format
|
||||||
|
|
||||||
|
|
||||||
#PDFToWord
|
#PDFToWord
|
||||||
|
@ -1022,6 +1027,15 @@ split-by-sections.vertical.placeholder=लंबवत विभाजन की
|
||||||
split-by-sections.submit=PDF को विभाजित करें
|
split-by-sections.submit=PDF को विभाजित करें
|
||||||
split-by-sections.merge=Merge Into One PDF
|
split-by-sections.merge=Merge Into One PDF
|
||||||
|
|
||||||
|
|
||||||
|
#printFile
|
||||||
|
printFile.title=Print File
|
||||||
|
printFile.header=Print File to Printer
|
||||||
|
printFile.selectText.1=Select File to Print
|
||||||
|
printFile.selectText.2=Enter Printer Name
|
||||||
|
printFile.submit=Print
|
||||||
|
|
||||||
|
|
||||||
#licenses
|
#licenses
|
||||||
licenses.nav=Licenses
|
licenses.nav=Licenses
|
||||||
licenses.title=3rd Party Licenses
|
licenses.title=3rd Party Licenses
|
||||||
|
|
|
@ -112,6 +112,7 @@ navbar.settings=Beállítások
|
||||||
#############
|
#############
|
||||||
settings.title=Beállítások
|
settings.title=Beállítások
|
||||||
settings.update=Frisítés elérhető
|
settings.update=Frisítés elérhető
|
||||||
|
settings.updateAvailable={0} is the current installed version. A new version ({1}) is available.
|
||||||
settings.appVersion=App Verzió:
|
settings.appVersion=App Verzió:
|
||||||
settings.downloadOption.title=Válassza ki a letöltési lehetőséget (Egyetlen fájl esetén a nem tömörített letöltésekhez):
|
settings.downloadOption.title=Válassza ki a letöltési lehetőséget (Egyetlen fájl esetén a nem tömörített letöltésekhez):
|
||||||
settings.downloadOption.1=Nyissa meg ugyanabban az ablakban
|
settings.downloadOption.1=Nyissa meg ugyanabban az ablakban
|
||||||
|
@ -120,8 +121,9 @@ settings.downloadOption.3=Töltse le a fájlt
|
||||||
settings.zipThreshold=Fájlok tömörítése, ha a letöltött fájlok száma meghaladja
|
settings.zipThreshold=Fájlok tömörítése, ha a letöltött fájlok száma meghaladja
|
||||||
settings.signOut=Kijelentkezés
|
settings.signOut=Kijelentkezés
|
||||||
settings.accountSettings=Fiókbeállítások
|
settings.accountSettings=Fiókbeállítások
|
||||||
|
settings.bored.help=Enables easter egg game
|
||||||
|
settings.cacheInputs.name=Save form inputs
|
||||||
|
settings.cacheInputs.help=Enable to store previously used inputs for future runs
|
||||||
|
|
||||||
changeCreds.title=Hitelesítés megváltoztatása
|
changeCreds.title=Hitelesítés megváltoztatása
|
||||||
changeCreds.header=Frissítse fiókadatait
|
changeCreds.header=Frissítse fiókadatait
|
||||||
|
@ -435,6 +437,8 @@ login.rememberme=Emlékezz rám
|
||||||
login.invalid=Érvénytelen felhasználónév vagy jelszó!
|
login.invalid=Érvénytelen felhasználónév vagy jelszó!
|
||||||
login.locked=A fiókja zárolva lett!
|
login.locked=A fiókja zárolva lett!
|
||||||
login.signinTitle=Kérjük, jelentkezzen be!
|
login.signinTitle=Kérjük, jelentkezzen be!
|
||||||
|
login.ssoSignIn=Bejelentkezés egyszeri bejelentkezéssel
|
||||||
|
login.oauth2AutoCreateDisabled=OAUTH2 Felhasználó automatikus létrehozása letiltva
|
||||||
|
|
||||||
|
|
||||||
#auto-redact
|
#auto-redact
|
||||||
|
@ -939,6 +943,7 @@ pdfToPDFA.header=PDF >> PDF/A
|
||||||
pdfToPDFA.credit=Ez a szolgáltatás az OCRmyPDF-t használja a PDF/A konverzióhoz
|
pdfToPDFA.credit=Ez a szolgáltatás az OCRmyPDF-t használja a PDF/A konverzióhoz
|
||||||
pdfToPDFA.submit=Konvertálás
|
pdfToPDFA.submit=Konvertálás
|
||||||
pdfToPDFA.tip=Currently does not work for multiple inputs at once
|
pdfToPDFA.tip=Currently does not work for multiple inputs at once
|
||||||
|
pdfToPDFA.outputFormat=Output format
|
||||||
|
|
||||||
|
|
||||||
#PDFToWord
|
#PDFToWord
|
||||||
|
@ -1022,6 +1027,15 @@ split-by-sections.vertical.placeholder=Adja meg a függőleges szakaszok számá
|
||||||
split-by-sections.submit=Felosztás
|
split-by-sections.submit=Felosztás
|
||||||
split-by-sections.merge=Merge Into One PDF
|
split-by-sections.merge=Merge Into One PDF
|
||||||
|
|
||||||
|
|
||||||
|
#printFile
|
||||||
|
printFile.title=Print File
|
||||||
|
printFile.header=Print File to Printer
|
||||||
|
printFile.selectText.1=Select File to Print
|
||||||
|
printFile.selectText.2=Enter Printer Name
|
||||||
|
printFile.submit=Print
|
||||||
|
|
||||||
|
|
||||||
#licenses
|
#licenses
|
||||||
licenses.nav=Licenses
|
licenses.nav=Licenses
|
||||||
licenses.title=3rd Party Licenses
|
licenses.title=3rd Party Licenses
|
||||||
|
|
|
@ -112,6 +112,7 @@ navbar.settings=Pengaturan
|
||||||
#############
|
#############
|
||||||
settings.title=Pengaturan
|
settings.title=Pengaturan
|
||||||
settings.update=Pembaruan tersedia
|
settings.update=Pembaruan tersedia
|
||||||
|
settings.updateAvailable={0} is the current installed version. A new version ({1}) is available.
|
||||||
settings.appVersion=Versi Aplikasi:
|
settings.appVersion=Versi Aplikasi:
|
||||||
settings.downloadOption.title=Pilih opsi unduhan (Untuk unduhan berkas tunggal non zip):
|
settings.downloadOption.title=Pilih opsi unduhan (Untuk unduhan berkas tunggal non zip):
|
||||||
settings.downloadOption.1=Buka di jendela yang sama
|
settings.downloadOption.1=Buka di jendela yang sama
|
||||||
|
@ -120,8 +121,9 @@ settings.downloadOption.3=Unduh berkas
|
||||||
settings.zipThreshold=Berkas zip ketika jumlah berkas yang diunduh melebihi
|
settings.zipThreshold=Berkas zip ketika jumlah berkas yang diunduh melebihi
|
||||||
settings.signOut=Keluar
|
settings.signOut=Keluar
|
||||||
settings.accountSettings=Pengaturan Akun
|
settings.accountSettings=Pengaturan Akun
|
||||||
|
settings.bored.help=Enables easter egg game
|
||||||
|
settings.cacheInputs.name=Save form inputs
|
||||||
|
settings.cacheInputs.help=Enable to store previously used inputs for future runs
|
||||||
|
|
||||||
changeCreds.title=Ubah Kredensial
|
changeCreds.title=Ubah Kredensial
|
||||||
changeCreds.header=Perbarui Detail Akun Anda
|
changeCreds.header=Perbarui Detail Akun Anda
|
||||||
|
@ -435,6 +437,8 @@ login.rememberme=Ingat saya
|
||||||
login.invalid=Nama pengguna atau kata sandi tidak valid.
|
login.invalid=Nama pengguna atau kata sandi tidak valid.
|
||||||
login.locked=Akun Anda telah dikunci.
|
login.locked=Akun Anda telah dikunci.
|
||||||
login.signinTitle=Silakan masuk
|
login.signinTitle=Silakan masuk
|
||||||
|
login.ssoSignIn=Masuk melalui Single Sign - on
|
||||||
|
login.oauth2AutoCreateDisabled=OAUTH2 Buat Otomatis Pengguna Dinonaktifkan
|
||||||
|
|
||||||
|
|
||||||
#auto-redact
|
#auto-redact
|
||||||
|
@ -939,6 +943,7 @@ pdfToPDFA.header=PDF ke PDF/A
|
||||||
pdfToPDFA.credit=Layanan ini menggunakan OCRmyPDF untuk konversi PDF/A.
|
pdfToPDFA.credit=Layanan ini menggunakan OCRmyPDF untuk konversi PDF/A.
|
||||||
pdfToPDFA.submit=Konversi
|
pdfToPDFA.submit=Konversi
|
||||||
pdfToPDFA.tip=Currently does not work for multiple inputs at once
|
pdfToPDFA.tip=Currently does not work for multiple inputs at once
|
||||||
|
pdfToPDFA.outputFormat=Output format
|
||||||
|
|
||||||
|
|
||||||
#PDFToWord
|
#PDFToWord
|
||||||
|
@ -1022,6 +1027,15 @@ split-by-sections.vertical.placeholder=Input angka untuk pembagian vertikal
|
||||||
split-by-sections.submit=Pisahkan PDF
|
split-by-sections.submit=Pisahkan PDF
|
||||||
split-by-sections.merge=Merge Into One PDF
|
split-by-sections.merge=Merge Into One PDF
|
||||||
|
|
||||||
|
|
||||||
|
#printFile
|
||||||
|
printFile.title=Print File
|
||||||
|
printFile.header=Print File to Printer
|
||||||
|
printFile.selectText.1=Select File to Print
|
||||||
|
printFile.selectText.2=Enter Printer Name
|
||||||
|
printFile.submit=Print
|
||||||
|
|
||||||
|
|
||||||
#licenses
|
#licenses
|
||||||
licenses.nav=Licenses
|
licenses.nav=Licenses
|
||||||
licenses.title=3rd Party Licenses
|
licenses.title=3rd Party Licenses
|
||||||
|
|
|
@ -112,6 +112,7 @@ navbar.settings=Impostazioni
|
||||||
#############
|
#############
|
||||||
settings.title=Impostazioni
|
settings.title=Impostazioni
|
||||||
settings.update=Aggiornamento disponibile
|
settings.update=Aggiornamento disponibile
|
||||||
|
settings.updateAvailable={0} is the current installed version. A new version ({1}) is available.
|
||||||
settings.appVersion=Versione App:
|
settings.appVersion=Versione App:
|
||||||
settings.downloadOption.title=Scegli opzione di download (Per file singoli non compressi):
|
settings.downloadOption.title=Scegli opzione di download (Per file singoli non compressi):
|
||||||
settings.downloadOption.1=Apri in questa finestra
|
settings.downloadOption.1=Apri in questa finestra
|
||||||
|
@ -120,8 +121,9 @@ settings.downloadOption.3=Scarica file
|
||||||
settings.zipThreshold=Comprimi file in .zip quando il numero di download supera
|
settings.zipThreshold=Comprimi file in .zip quando il numero di download supera
|
||||||
settings.signOut=Logout
|
settings.signOut=Logout
|
||||||
settings.accountSettings=Impostazioni Account
|
settings.accountSettings=Impostazioni Account
|
||||||
|
settings.bored.help=Abilita easter egg game
|
||||||
|
settings.cacheInputs.name=Salva gli input del modulo
|
||||||
|
settings.cacheInputs.help=Abilitare per memorizzare gli input utilizzati in precedenza per esecuzioni future
|
||||||
|
|
||||||
changeCreds.title=Cambia credenziali
|
changeCreds.title=Cambia credenziali
|
||||||
changeCreds.header=Aggiorna i dettagli del tuo account
|
changeCreds.header=Aggiorna i dettagli del tuo account
|
||||||
|
@ -435,6 +437,8 @@ login.rememberme=Ricordami
|
||||||
login.invalid=Nome utente o password errati.
|
login.invalid=Nome utente o password errati.
|
||||||
login.locked=Il tuo account è stato bloccato.
|
login.locked=Il tuo account è stato bloccato.
|
||||||
login.signinTitle=Per favore accedi
|
login.signinTitle=Per favore accedi
|
||||||
|
login.ssoSignIn=Accedi tramite Single Sign-on
|
||||||
|
login.oauth2AutoCreateDisabled=Creazione automatica utente OAUTH2 DISABILITATA
|
||||||
|
|
||||||
|
|
||||||
#auto-redact
|
#auto-redact
|
||||||
|
@ -644,7 +648,7 @@ removeBlanks.submit=Rimuovi
|
||||||
|
|
||||||
#removeAnnotations
|
#removeAnnotations
|
||||||
removeAnnotations.title=Rimuovi Annotazioni
|
removeAnnotations.title=Rimuovi Annotazioni
|
||||||
removeAnnotations.header=Remuovi Annotazioni
|
removeAnnotations.header=Rimuovi Annotazioni
|
||||||
removeAnnotations.submit=Rimuovi
|
removeAnnotations.submit=Rimuovi
|
||||||
|
|
||||||
|
|
||||||
|
@ -939,6 +943,7 @@ pdfToPDFA.header=Da PDF a PDF/A
|
||||||
pdfToPDFA.credit=Questo servizio utilizza OCRmyPDF per la conversione in PDF/A.
|
pdfToPDFA.credit=Questo servizio utilizza OCRmyPDF per la conversione in PDF/A.
|
||||||
pdfToPDFA.submit=Converti
|
pdfToPDFA.submit=Converti
|
||||||
pdfToPDFA.tip=Attualmente non funziona per più input contemporaneamente
|
pdfToPDFA.tip=Attualmente non funziona per più input contemporaneamente
|
||||||
|
pdfToPDFA.outputFormat=Formato di output
|
||||||
|
|
||||||
|
|
||||||
#PDFToWord
|
#PDFToWord
|
||||||
|
@ -1022,6 +1027,15 @@ split-by-sections.vertical.placeholder=Inserire il numero di divisioni verticali
|
||||||
split-by-sections.submit=Dividi PDF
|
split-by-sections.submit=Dividi PDF
|
||||||
split-by-sections.merge=Unisci in un unico PDF
|
split-by-sections.merge=Unisci in un unico PDF
|
||||||
|
|
||||||
|
|
||||||
|
#printFile
|
||||||
|
printFile.title=Stampa file
|
||||||
|
printFile.header=Stampa file su stampante
|
||||||
|
printFile.selectText.1=Seleziona file da stampare
|
||||||
|
printFile.selectText.2=Inserire il nome della stampante
|
||||||
|
printFile.submit=Stampare
|
||||||
|
|
||||||
|
|
||||||
#licenses
|
#licenses
|
||||||
licenses.nav=Licenze
|
licenses.nav=Licenze
|
||||||
licenses.title=Licenze di terze parti
|
licenses.title=Licenze di terze parti
|
||||||
|
|
|
@ -112,6 +112,7 @@ navbar.settings=設定
|
||||||
#############
|
#############
|
||||||
settings.title=設定
|
settings.title=設定
|
||||||
settings.update=利用可能なアップデート
|
settings.update=利用可能なアップデート
|
||||||
|
settings.updateAvailable={0} is the current installed version. A new version ({1}) is available.
|
||||||
settings.appVersion=Appバージョン:
|
settings.appVersion=Appバージョン:
|
||||||
settings.downloadOption.title=ダウンロードオプション (zip以外の単一ファイル):
|
settings.downloadOption.title=ダウンロードオプション (zip以外の単一ファイル):
|
||||||
settings.downloadOption.1=同じウィンドウで開く
|
settings.downloadOption.1=同じウィンドウで開く
|
||||||
|
@ -120,8 +121,9 @@ settings.downloadOption.3=ファイルをダウンロード
|
||||||
settings.zipThreshold=このファイル数を超えたときにファイルを圧縮する
|
settings.zipThreshold=このファイル数を超えたときにファイルを圧縮する
|
||||||
settings.signOut=サインアウト
|
settings.signOut=サインアウト
|
||||||
settings.accountSettings=アカウント設定
|
settings.accountSettings=アカウント設定
|
||||||
|
settings.bored.help=Enables easter egg game
|
||||||
|
settings.cacheInputs.name=Save form inputs
|
||||||
|
settings.cacheInputs.help=Enable to store previously used inputs for future runs
|
||||||
|
|
||||||
changeCreds.title=資格情報の変更
|
changeCreds.title=資格情報の変更
|
||||||
changeCreds.header=アカウントの詳細を更新する
|
changeCreds.header=アカウントの詳細を更新する
|
||||||
|
@ -435,6 +437,8 @@ login.rememberme=サインイン状態を記憶する
|
||||||
login.invalid=ユーザー名かパスワードが無効です。
|
login.invalid=ユーザー名かパスワードが無効です。
|
||||||
login.locked=あなたのアカウントはロックされています。
|
login.locked=あなたのアカウントはロックされています。
|
||||||
login.signinTitle=サインインしてください
|
login.signinTitle=サインインしてください
|
||||||
|
login.ssoSignIn=シングルサインオンでログイン
|
||||||
|
login.oauth2AutoCreateDisabled=OAuth 2自動作成ユーザーが無効
|
||||||
|
|
||||||
|
|
||||||
#auto-redact
|
#auto-redact
|
||||||
|
@ -939,6 +943,7 @@ pdfToPDFA.header=PDFをPDF/Aに変換
|
||||||
pdfToPDFA.credit=本サービスはPDF/Aの変換にOCRmyPDFを使用しています。
|
pdfToPDFA.credit=本サービスはPDF/Aの変換にOCRmyPDFを使用しています。
|
||||||
pdfToPDFA.submit=変換
|
pdfToPDFA.submit=変換
|
||||||
pdfToPDFA.tip=現在、一度に複数の入力に対して機能しません
|
pdfToPDFA.tip=現在、一度に複数の入力に対して機能しません
|
||||||
|
pdfToPDFA.outputFormat=Output format
|
||||||
|
|
||||||
|
|
||||||
#PDFToWord
|
#PDFToWord
|
||||||
|
@ -1022,6 +1027,15 @@ split-by-sections.vertical.placeholder=垂直方向の分割数を選択
|
||||||
split-by-sections.submit=分割
|
split-by-sections.submit=分割
|
||||||
split-by-sections.merge=1 つの PDF に結合するかどうか
|
split-by-sections.merge=1 つの PDF に結合するかどうか
|
||||||
|
|
||||||
|
|
||||||
|
#printFile
|
||||||
|
printFile.title=Print File
|
||||||
|
printFile.header=Print File to Printer
|
||||||
|
printFile.selectText.1=Select File to Print
|
||||||
|
printFile.selectText.2=Enter Printer Name
|
||||||
|
printFile.submit=Print
|
||||||
|
|
||||||
|
|
||||||
#licenses
|
#licenses
|
||||||
licenses.nav=ライセンス
|
licenses.nav=ライセンス
|
||||||
licenses.title=サードパーティライセンス
|
licenses.title=サードパーティライセンス
|
||||||
|
|
|
@ -112,6 +112,7 @@ navbar.settings=설정
|
||||||
#############
|
#############
|
||||||
settings.title=설정
|
settings.title=설정
|
||||||
settings.update=업데이트 가능
|
settings.update=업데이트 가능
|
||||||
|
settings.updateAvailable={0} is the current installed version. A new version ({1}) is available.
|
||||||
settings.appVersion=앱 버전:
|
settings.appVersion=앱 버전:
|
||||||
settings.downloadOption.title=다운로드 옵션 선택 (zip 파일이 아닌 단일 파일 다운로드 시):
|
settings.downloadOption.title=다운로드 옵션 선택 (zip 파일이 아닌 단일 파일 다운로드 시):
|
||||||
settings.downloadOption.1=현재 창에서 열기
|
settings.downloadOption.1=현재 창에서 열기
|
||||||
|
@ -120,8 +121,9 @@ settings.downloadOption.3=다운로드
|
||||||
settings.zipThreshold=다운로드한 파일 수가 초과된 경우 파일 압축하기
|
settings.zipThreshold=다운로드한 파일 수가 초과된 경우 파일 압축하기
|
||||||
settings.signOut=로그아웃
|
settings.signOut=로그아웃
|
||||||
settings.accountSettings=계정 설정
|
settings.accountSettings=계정 설정
|
||||||
|
settings.bored.help=Enables easter egg game
|
||||||
|
settings.cacheInputs.name=Save form inputs
|
||||||
|
settings.cacheInputs.help=Enable to store previously used inputs for future runs
|
||||||
|
|
||||||
changeCreds.title=계정 정보 변경
|
changeCreds.title=계정 정보 변경
|
||||||
changeCreds.header=계정 정보 업데이트
|
changeCreds.header=계정 정보 업데이트
|
||||||
|
@ -435,6 +437,8 @@ login.rememberme=로그인 유지
|
||||||
login.invalid=사용자 이름이나 비밀번호가 틀립니다.
|
login.invalid=사용자 이름이나 비밀번호가 틀립니다.
|
||||||
login.locked=계정이 잠겼습니다.
|
login.locked=계정이 잠겼습니다.
|
||||||
login.signinTitle=로그인해 주세요.
|
login.signinTitle=로그인해 주세요.
|
||||||
|
login.ssoSignIn=싱글사인온을 통한 로그인
|
||||||
|
login.oauth2AutoCreateDisabled=OAUTH2 사용자 자동 생성 비활성화됨
|
||||||
|
|
||||||
|
|
||||||
#auto-redact
|
#auto-redact
|
||||||
|
@ -939,6 +943,7 @@ pdfToPDFA.header=PDF 문서를 PDF/A로 변환
|
||||||
pdfToPDFA.credit=이 서비스는 PDF/A 변환을 위해 OCRmyPDF 문서를 사용합니다.
|
pdfToPDFA.credit=이 서비스는 PDF/A 변환을 위해 OCRmyPDF 문서를 사용합니다.
|
||||||
pdfToPDFA.submit=변환
|
pdfToPDFA.submit=변환
|
||||||
pdfToPDFA.tip=현재 한 번에 여러 입력에 대해 작동하지 않습니다.
|
pdfToPDFA.tip=현재 한 번에 여러 입력에 대해 작동하지 않습니다.
|
||||||
|
pdfToPDFA.outputFormat=Output format
|
||||||
|
|
||||||
|
|
||||||
#PDFToWord
|
#PDFToWord
|
||||||
|
@ -1022,6 +1027,15 @@ split-by-sections.vertical.placeholder=수직 분할 수를 입력합니다
|
||||||
split-by-sections.submit=PDF 분할
|
split-by-sections.submit=PDF 분할
|
||||||
split-by-sections.merge=하나의 PDF로 병합
|
split-by-sections.merge=하나의 PDF로 병합
|
||||||
|
|
||||||
|
|
||||||
|
#printFile
|
||||||
|
printFile.title=Print File
|
||||||
|
printFile.header=Print File to Printer
|
||||||
|
printFile.selectText.1=Select File to Print
|
||||||
|
printFile.selectText.2=Enter Printer Name
|
||||||
|
printFile.submit=Print
|
||||||
|
|
||||||
|
|
||||||
#licenses
|
#licenses
|
||||||
licenses.nav=라이센스
|
licenses.nav=라이센스
|
||||||
licenses.title=제3자 라이선스
|
licenses.title=제3자 라이선스
|
||||||
|
|
|
@ -112,6 +112,7 @@ navbar.settings=Instellingen
|
||||||
#############
|
#############
|
||||||
settings.title=Instellingen
|
settings.title=Instellingen
|
||||||
settings.update=Update beschikbaar
|
settings.update=Update beschikbaar
|
||||||
|
settings.updateAvailable={0} is the current installed version. A new version ({1}) is available.
|
||||||
settings.appVersion=App versie:
|
settings.appVersion=App versie:
|
||||||
settings.downloadOption.title=Kies download optie (Voor enkelvoudige bestanddownloads zonder zip):
|
settings.downloadOption.title=Kies download optie (Voor enkelvoudige bestanddownloads zonder zip):
|
||||||
settings.downloadOption.1=Open in hetzelfde venster
|
settings.downloadOption.1=Open in hetzelfde venster
|
||||||
|
@ -120,8 +121,9 @@ settings.downloadOption.3=Download bestand
|
||||||
settings.zipThreshold=Bestanden zippen wanneer het aantal gedownloade bestanden meer is dan
|
settings.zipThreshold=Bestanden zippen wanneer het aantal gedownloade bestanden meer is dan
|
||||||
settings.signOut=Uitloggen
|
settings.signOut=Uitloggen
|
||||||
settings.accountSettings=Account instellingen
|
settings.accountSettings=Account instellingen
|
||||||
|
settings.bored.help=Enables easter egg game
|
||||||
|
settings.cacheInputs.name=Save form inputs
|
||||||
|
settings.cacheInputs.help=Enable to store previously used inputs for future runs
|
||||||
|
|
||||||
changeCreds.title=Inloggegevens wijzigen
|
changeCreds.title=Inloggegevens wijzigen
|
||||||
changeCreds.header=Werk je accountgegevens bij
|
changeCreds.header=Werk je accountgegevens bij
|
||||||
|
@ -435,6 +437,8 @@ login.rememberme=Onthoud mij
|
||||||
login.invalid=Ongeldige gebruikersnaam of wachtwoord.
|
login.invalid=Ongeldige gebruikersnaam of wachtwoord.
|
||||||
login.locked=Je account is geblokkeerd.
|
login.locked=Je account is geblokkeerd.
|
||||||
login.signinTitle=Gelieve in te loggen
|
login.signinTitle=Gelieve in te loggen
|
||||||
|
login.ssoSignIn=Inloggen via Single Sign-on
|
||||||
|
login.oauth2AutoCreateDisabled=OAUTH2 Automatisch aanmaken gebruiker uitgeschakeld
|
||||||
|
|
||||||
|
|
||||||
#auto-redact
|
#auto-redact
|
||||||
|
@ -939,6 +943,7 @@ pdfToPDFA.header=PDF naar PDF/A
|
||||||
pdfToPDFA.credit=Deze service gebruikt OCRmyPDF voor PDF/A-conversie
|
pdfToPDFA.credit=Deze service gebruikt OCRmyPDF voor PDF/A-conversie
|
||||||
pdfToPDFA.submit=Converteren
|
pdfToPDFA.submit=Converteren
|
||||||
pdfToPDFA.tip=Currently does not work for multiple inputs at once
|
pdfToPDFA.tip=Currently does not work for multiple inputs at once
|
||||||
|
pdfToPDFA.outputFormat=Output format
|
||||||
|
|
||||||
|
|
||||||
#PDFToWord
|
#PDFToWord
|
||||||
|
@ -1022,6 +1027,15 @@ split-by-sections.vertical.placeholder=Voer het aantal verticale secties in
|
||||||
split-by-sections.submit=PDF splitsen
|
split-by-sections.submit=PDF splitsen
|
||||||
split-by-sections.merge=Merge Into One PDF
|
split-by-sections.merge=Merge Into One PDF
|
||||||
|
|
||||||
|
|
||||||
|
#printFile
|
||||||
|
printFile.title=Print File
|
||||||
|
printFile.header=Print File to Printer
|
||||||
|
printFile.selectText.1=Select File to Print
|
||||||
|
printFile.selectText.2=Enter Printer Name
|
||||||
|
printFile.submit=Print
|
||||||
|
|
||||||
|
|
||||||
#licenses
|
#licenses
|
||||||
licenses.nav=Licenties
|
licenses.nav=Licenties
|
||||||
licenses.title=Licenties van derden
|
licenses.title=Licenties van derden
|
||||||
|
|
|
@ -112,6 +112,7 @@ navbar.settings=Ustawienia
|
||||||
#############
|
#############
|
||||||
settings.title=Ustawienia
|
settings.title=Ustawienia
|
||||||
settings.update=Dostępna aktualizacja
|
settings.update=Dostępna aktualizacja
|
||||||
|
settings.updateAvailable={0} is the current installed version. A new version ({1}) is available.
|
||||||
settings.appVersion=Wersia aplikacji:
|
settings.appVersion=Wersia aplikacji:
|
||||||
settings.downloadOption.title=Wybierz opcję pobierania (w przypadku pobierania pojedynczych plików innych niż ZIP):
|
settings.downloadOption.title=Wybierz opcję pobierania (w przypadku pobierania pojedynczych plików innych niż ZIP):
|
||||||
settings.downloadOption.1=Otwórz w tym samym oknie
|
settings.downloadOption.1=Otwórz w tym samym oknie
|
||||||
|
@ -120,8 +121,9 @@ settings.downloadOption.3=Pobierz plik
|
||||||
settings.zipThreshold=Spakuj pliki, gdy liczba pobranych plików przekroczy
|
settings.zipThreshold=Spakuj pliki, gdy liczba pobranych plików przekroczy
|
||||||
settings.signOut=Sign Out
|
settings.signOut=Sign Out
|
||||||
settings.accountSettings=Account Settings
|
settings.accountSettings=Account Settings
|
||||||
|
settings.bored.help=Enables easter egg game
|
||||||
|
settings.cacheInputs.name=Save form inputs
|
||||||
|
settings.cacheInputs.help=Enable to store previously used inputs for future runs
|
||||||
|
|
||||||
changeCreds.title=Change Credentials
|
changeCreds.title=Change Credentials
|
||||||
changeCreds.header=Update Your Account Details
|
changeCreds.header=Update Your Account Details
|
||||||
|
@ -435,6 +437,8 @@ login.rememberme=Remember me
|
||||||
login.invalid=Invalid username or password.
|
login.invalid=Invalid username or password.
|
||||||
login.locked=Your account has been locked.
|
login.locked=Your account has been locked.
|
||||||
login.signinTitle=Please sign in
|
login.signinTitle=Please sign in
|
||||||
|
login.ssoSignIn=Zaloguj się za pomocą logowania jednokrotnego
|
||||||
|
login.oauth2AutoCreateDisabled=Wyłączono automatyczne tworzenie użytkownika OAUTH2
|
||||||
|
|
||||||
|
|
||||||
#auto-redact
|
#auto-redact
|
||||||
|
@ -939,6 +943,7 @@ pdfToPDFA.header=PDF na PDF/A
|
||||||
pdfToPDFA.credit=Ta usługa używa OCRmyPDF do konwersji PDF/A
|
pdfToPDFA.credit=Ta usługa używa OCRmyPDF do konwersji PDF/A
|
||||||
pdfToPDFA.submit=Konwertuj
|
pdfToPDFA.submit=Konwertuj
|
||||||
pdfToPDFA.tip=Currently does not work for multiple inputs at once
|
pdfToPDFA.tip=Currently does not work for multiple inputs at once
|
||||||
|
pdfToPDFA.outputFormat=Output format
|
||||||
|
|
||||||
|
|
||||||
#PDFToWord
|
#PDFToWord
|
||||||
|
@ -1022,6 +1027,15 @@ split-by-sections.vertical.placeholder=Enter number of vertical divisions
|
||||||
split-by-sections.submit=Split PDF
|
split-by-sections.submit=Split PDF
|
||||||
split-by-sections.merge=Merge Into One PDF
|
split-by-sections.merge=Merge Into One PDF
|
||||||
|
|
||||||
|
|
||||||
|
#printFile
|
||||||
|
printFile.title=Print File
|
||||||
|
printFile.header=Print File to Printer
|
||||||
|
printFile.selectText.1=Select File to Print
|
||||||
|
printFile.selectText.2=Enter Printer Name
|
||||||
|
printFile.submit=Print
|
||||||
|
|
||||||
|
|
||||||
#licenses
|
#licenses
|
||||||
licenses.nav=Licenses
|
licenses.nav=Licenses
|
||||||
licenses.title=3rd Party Licenses
|
licenses.title=3rd Party Licenses
|
||||||
|
|
|
@ -112,6 +112,7 @@ navbar.settings=Configurações
|
||||||
#############
|
#############
|
||||||
settings.title=Configurações
|
settings.title=Configurações
|
||||||
settings.update=Atualização disponível
|
settings.update=Atualização disponível
|
||||||
|
settings.updateAvailable={0} is the current installed version. A new version ({1}) is available.
|
||||||
settings.appVersion=Versão do aplicativo:
|
settings.appVersion=Versão do aplicativo:
|
||||||
settings.downloadOption.title=Escolha a opção de download (para downloads não compactados de arquivo único):
|
settings.downloadOption.title=Escolha a opção de download (para downloads não compactados de arquivo único):
|
||||||
settings.downloadOption.1=Abrir na mesma janela
|
settings.downloadOption.1=Abrir na mesma janela
|
||||||
|
@ -120,8 +121,9 @@ settings.downloadOption.3=⇬ Fazer download do arquivo
|
||||||
settings.zipThreshold=Compactar arquivos quando o número de arquivos baixados exceder
|
settings.zipThreshold=Compactar arquivos quando o número de arquivos baixados exceder
|
||||||
settings.signOut=Sign Out
|
settings.signOut=Sign Out
|
||||||
settings.accountSettings=Account Settings
|
settings.accountSettings=Account Settings
|
||||||
|
settings.bored.help=Enables easter egg game
|
||||||
|
settings.cacheInputs.name=Save form inputs
|
||||||
|
settings.cacheInputs.help=Enable to store previously used inputs for future runs
|
||||||
|
|
||||||
changeCreds.title=Change Credentials
|
changeCreds.title=Change Credentials
|
||||||
changeCreds.header=Update Your Account Details
|
changeCreds.header=Update Your Account Details
|
||||||
|
@ -435,6 +437,8 @@ login.rememberme=Remember me
|
||||||
login.invalid=Invalid username or password.
|
login.invalid=Invalid username or password.
|
||||||
login.locked=Your account has been locked.
|
login.locked=Your account has been locked.
|
||||||
login.signinTitle=Please sign in
|
login.signinTitle=Please sign in
|
||||||
|
login.ssoSignIn=Iniciar sessão através de início de sessão único
|
||||||
|
login.oauth2AutoCreateDisabled=OAUTH2 Auto-Criar Usuário Desativado
|
||||||
|
|
||||||
|
|
||||||
#auto-redact
|
#auto-redact
|
||||||
|
@ -939,6 +943,7 @@ pdfToPDFA.header=PDF para PDF/A
|
||||||
pdfToPDFA.credit=Este serviço usa OCRmyPDF para Conversão de PDF/A
|
pdfToPDFA.credit=Este serviço usa OCRmyPDF para Conversão de PDF/A
|
||||||
pdfToPDFA.submit=Converter
|
pdfToPDFA.submit=Converter
|
||||||
pdfToPDFA.tip=Currently does not work for multiple inputs at once
|
pdfToPDFA.tip=Currently does not work for multiple inputs at once
|
||||||
|
pdfToPDFA.outputFormat=Output format
|
||||||
|
|
||||||
|
|
||||||
#PDFToWord
|
#PDFToWord
|
||||||
|
@ -1022,6 +1027,15 @@ split-by-sections.vertical.placeholder=Enter number of vertical divisions
|
||||||
split-by-sections.submit=Split PDF
|
split-by-sections.submit=Split PDF
|
||||||
split-by-sections.merge=Merge Into One PDF
|
split-by-sections.merge=Merge Into One PDF
|
||||||
|
|
||||||
|
|
||||||
|
#printFile
|
||||||
|
printFile.title=Print File
|
||||||
|
printFile.header=Print File to Printer
|
||||||
|
printFile.selectText.1=Select File to Print
|
||||||
|
printFile.selectText.2=Enter Printer Name
|
||||||
|
printFile.submit=Print
|
||||||
|
|
||||||
|
|
||||||
#licenses
|
#licenses
|
||||||
licenses.nav=Licenses
|
licenses.nav=Licenses
|
||||||
licenses.title=3rd Party Licenses
|
licenses.title=3rd Party Licenses
|
||||||
|
|
|
@ -112,6 +112,7 @@ navbar.settings=Configurações
|
||||||
#############
|
#############
|
||||||
settings.title=Configurações
|
settings.title=Configurações
|
||||||
settings.update=Atualização disponível
|
settings.update=Atualização disponível
|
||||||
|
settings.updateAvailable={0} is the current installed version. A new version ({1}) is available.
|
||||||
settings.appVersion=Versão da aplicação:
|
settings.appVersion=Versão da aplicação:
|
||||||
settings.downloadOption.title=Escolha a opção de download (para downloads não compactados de ficheiro único):
|
settings.downloadOption.title=Escolha a opção de download (para downloads não compactados de ficheiro único):
|
||||||
settings.downloadOption.1=Abrir na mesma janela
|
settings.downloadOption.1=Abrir na mesma janela
|
||||||
|
@ -120,8 +121,9 @@ settings.downloadOption.3=⇬ Fazer download do ficheiro
|
||||||
settings.zipThreshold=Compactar ficheiros quando o número de ficheiros baixados exceder
|
settings.zipThreshold=Compactar ficheiros quando o número de ficheiros baixados exceder
|
||||||
settings.signOut=Terminar Sessão
|
settings.signOut=Terminar Sessão
|
||||||
settings.accountSettings=Configuração de Conta
|
settings.accountSettings=Configuração de Conta
|
||||||
|
settings.bored.help=Enables easter egg game
|
||||||
|
settings.cacheInputs.name=Save form inputs
|
||||||
|
settings.cacheInputs.help=Enable to store previously used inputs for future runs
|
||||||
|
|
||||||
changeCreds.title=Alterar senha
|
changeCreds.title=Alterar senha
|
||||||
changeCreds.header=Alterar dados da sua conta
|
changeCreds.header=Alterar dados da sua conta
|
||||||
|
@ -435,6 +437,8 @@ login.rememberme=Lembrar dados
|
||||||
login.invalid=Utilizador ou senha inválidos.
|
login.invalid=Utilizador ou senha inválidos.
|
||||||
login.locked=A sua conta foi bloqueada.
|
login.locked=A sua conta foi bloqueada.
|
||||||
login.signinTitle=Introduza os seus dados de acesso
|
login.signinTitle=Introduza os seus dados de acesso
|
||||||
|
login.ssoSignIn=Iniciar sessão através de início de sessão único
|
||||||
|
login.oauth2AutoCreateDisabled=OAUTH2 Criação Automática de Utilizador Desativada
|
||||||
|
|
||||||
|
|
||||||
#auto-redact
|
#auto-redact
|
||||||
|
@ -939,6 +943,7 @@ pdfToPDFA.header=PDF para PDF/A
|
||||||
pdfToPDFA.credit=Este serviço usa OCRmyPDF para Conversão de PDF/A
|
pdfToPDFA.credit=Este serviço usa OCRmyPDF para Conversão de PDF/A
|
||||||
pdfToPDFA.submit=Converter
|
pdfToPDFA.submit=Converter
|
||||||
pdfToPDFA.tip=Currently does not work for multiple inputs at once
|
pdfToPDFA.tip=Currently does not work for multiple inputs at once
|
||||||
|
pdfToPDFA.outputFormat=Output format
|
||||||
|
|
||||||
|
|
||||||
#PDFToWord
|
#PDFToWord
|
||||||
|
@ -1022,6 +1027,15 @@ split-by-sections.vertical.placeholder=Introduza o número de divisões verticai
|
||||||
split-by-sections.submit=Dividir PDF
|
split-by-sections.submit=Dividir PDF
|
||||||
split-by-sections.merge=Merge Into One PDF
|
split-by-sections.merge=Merge Into One PDF
|
||||||
|
|
||||||
|
|
||||||
|
#printFile
|
||||||
|
printFile.title=Print File
|
||||||
|
printFile.header=Print File to Printer
|
||||||
|
printFile.selectText.1=Select File to Print
|
||||||
|
printFile.selectText.2=Enter Printer Name
|
||||||
|
printFile.submit=Print
|
||||||
|
|
||||||
|
|
||||||
#licenses
|
#licenses
|
||||||
licenses.nav=Licenças
|
licenses.nav=Licenças
|
||||||
licenses.title=Licenças de terceiros
|
licenses.title=Licenças de terceiros
|
||||||
|
|
|
@ -112,6 +112,7 @@ navbar.settings=Setări
|
||||||
#############
|
#############
|
||||||
settings.title=Setări
|
settings.title=Setări
|
||||||
settings.update=Actualizare disponibilă
|
settings.update=Actualizare disponibilă
|
||||||
|
settings.updateAvailable={0} is the current installed version. A new version ({1}) is available.
|
||||||
settings.appVersion=Versiune aplicație:
|
settings.appVersion=Versiune aplicație:
|
||||||
settings.downloadOption.title=Alege opțiunea de descărcare (pentru descărcarea unui singur fișier non-zip):
|
settings.downloadOption.title=Alege opțiunea de descărcare (pentru descărcarea unui singur fișier non-zip):
|
||||||
settings.downloadOption.1=Deschide în aceeași fereastră
|
settings.downloadOption.1=Deschide în aceeași fereastră
|
||||||
|
@ -120,8 +121,9 @@ settings.downloadOption.3=Descarcă fișierul
|
||||||
settings.zipThreshold=Împachetează fișierele când numărul de fișiere descărcate depășește
|
settings.zipThreshold=Împachetează fișierele când numărul de fișiere descărcate depășește
|
||||||
settings.signOut=Sign Out
|
settings.signOut=Sign Out
|
||||||
settings.accountSettings=Account Settings
|
settings.accountSettings=Account Settings
|
||||||
|
settings.bored.help=Enables easter egg game
|
||||||
|
settings.cacheInputs.name=Save form inputs
|
||||||
|
settings.cacheInputs.help=Enable to store previously used inputs for future runs
|
||||||
|
|
||||||
changeCreds.title=Change Credentials
|
changeCreds.title=Change Credentials
|
||||||
changeCreds.header=Update Your Account Details
|
changeCreds.header=Update Your Account Details
|
||||||
|
@ -435,6 +437,8 @@ login.rememberme=Remember me
|
||||||
login.invalid=Invalid username or password.
|
login.invalid=Invalid username or password.
|
||||||
login.locked=Your account has been locked.
|
login.locked=Your account has been locked.
|
||||||
login.signinTitle=Please sign in
|
login.signinTitle=Please sign in
|
||||||
|
login.ssoSignIn=Conectare prin conectare unică
|
||||||
|
login.oauth2AutoCreateDisabled=OAUTH2 Creare automată utilizator dezactivată
|
||||||
|
|
||||||
|
|
||||||
#auto-redact
|
#auto-redact
|
||||||
|
@ -939,6 +943,7 @@ pdfToPDFA.header=PDF către PDF/A
|
||||||
pdfToPDFA.credit=Acest serviciu utilizează OCRmyPDF pentru conversia în PDF/A
|
pdfToPDFA.credit=Acest serviciu utilizează OCRmyPDF pentru conversia în PDF/A
|
||||||
pdfToPDFA.submit=Convert
|
pdfToPDFA.submit=Convert
|
||||||
pdfToPDFA.tip=Currently does not work for multiple inputs at once
|
pdfToPDFA.tip=Currently does not work for multiple inputs at once
|
||||||
|
pdfToPDFA.outputFormat=Output format
|
||||||
|
|
||||||
|
|
||||||
#PDFToWord
|
#PDFToWord
|
||||||
|
@ -1022,6 +1027,15 @@ split-by-sections.vertical.placeholder=Enter number of vertical divisions
|
||||||
split-by-sections.submit=Split PDF
|
split-by-sections.submit=Split PDF
|
||||||
split-by-sections.merge=Merge Into One PDF
|
split-by-sections.merge=Merge Into One PDF
|
||||||
|
|
||||||
|
|
||||||
|
#printFile
|
||||||
|
printFile.title=Print File
|
||||||
|
printFile.header=Print File to Printer
|
||||||
|
printFile.selectText.1=Select File to Print
|
||||||
|
printFile.selectText.2=Enter Printer Name
|
||||||
|
printFile.submit=Print
|
||||||
|
|
||||||
|
|
||||||
#licenses
|
#licenses
|
||||||
licenses.nav=Licenses
|
licenses.nav=Licenses
|
||||||
licenses.title=3rd Party Licenses
|
licenses.title=3rd Party Licenses
|
||||||
|
|
|
@ -112,6 +112,7 @@ navbar.settings=Настройки
|
||||||
#############
|
#############
|
||||||
settings.title=Настройки
|
settings.title=Настройки
|
||||||
settings.update=Доступно обновление
|
settings.update=Доступно обновление
|
||||||
|
settings.updateAvailable={0} is the current installed version. A new version ({1}) is available.
|
||||||
settings.appVersion=Версия приложения:
|
settings.appVersion=Версия приложения:
|
||||||
settings.downloadOption.title=Выберите вариант загрузки (для загрузки одного файла без zip):
|
settings.downloadOption.title=Выберите вариант загрузки (для загрузки одного файла без zip):
|
||||||
settings.downloadOption.1=Открыть в том же окне
|
settings.downloadOption.1=Открыть в том же окне
|
||||||
|
@ -120,8 +121,9 @@ settings.downloadOption.3=Загрузить файл
|
||||||
settings.zipThreshold=Zip-файлы, когда количество загруженных файлов превышает
|
settings.zipThreshold=Zip-файлы, когда количество загруженных файлов превышает
|
||||||
settings.signOut=Выйти
|
settings.signOut=Выйти
|
||||||
settings.accountSettings=Настройки аккаунта
|
settings.accountSettings=Настройки аккаунта
|
||||||
|
settings.bored.help=Enables easter egg game
|
||||||
|
settings.cacheInputs.name=Save form inputs
|
||||||
|
settings.cacheInputs.help=Enable to store previously used inputs for future runs
|
||||||
|
|
||||||
changeCreds.title=Изменить учетные данные
|
changeCreds.title=Изменить учетные данные
|
||||||
changeCreds.header=Обновите данные вашей учетной записи
|
changeCreds.header=Обновите данные вашей учетной записи
|
||||||
|
@ -435,6 +437,8 @@ login.rememberme=Запомнить меня
|
||||||
login.invalid=Недействительное имя пользователя или пароль.
|
login.invalid=Недействительное имя пользователя или пароль.
|
||||||
login.locked=Ваша учетная запись заблокирована.
|
login.locked=Ваша учетная запись заблокирована.
|
||||||
login.signinTitle=Пожалуйста, войдите
|
login.signinTitle=Пожалуйста, войдите
|
||||||
|
login.ssoSignIn=Вход через единый вход
|
||||||
|
login.oauth2AutoCreateDisabled=OAUTH2 Автоматическое создание пользователя отключено
|
||||||
|
|
||||||
|
|
||||||
#auto-redact
|
#auto-redact
|
||||||
|
@ -939,6 +943,7 @@ pdfToPDFA.header=PDF в PDF/A
|
||||||
pdfToPDFA.credit=Этот сервис использует OCRmyPDF для преобразования PDF/A
|
pdfToPDFA.credit=Этот сервис использует OCRmyPDF для преобразования PDF/A
|
||||||
pdfToPDFA.submit=Конвертировать
|
pdfToPDFA.submit=Конвертировать
|
||||||
pdfToPDFA.tip=Currently does not work for multiple inputs at once
|
pdfToPDFA.tip=Currently does not work for multiple inputs at once
|
||||||
|
pdfToPDFA.outputFormat=Output format
|
||||||
|
|
||||||
|
|
||||||
#PDFToWord
|
#PDFToWord
|
||||||
|
@ -1022,6 +1027,15 @@ split-by-sections.vertical.placeholder=Введите количество ве
|
||||||
split-by-sections.submit=Разделить PDF
|
split-by-sections.submit=Разделить PDF
|
||||||
split-by-sections.merge=Объединить в один PDF
|
split-by-sections.merge=Объединить в один PDF
|
||||||
|
|
||||||
|
|
||||||
|
#printFile
|
||||||
|
printFile.title=Print File
|
||||||
|
printFile.header=Print File to Printer
|
||||||
|
printFile.selectText.1=Select File to Print
|
||||||
|
printFile.selectText.2=Enter Printer Name
|
||||||
|
printFile.submit=Print
|
||||||
|
|
||||||
|
|
||||||
#licenses
|
#licenses
|
||||||
licenses.nav=Лицензии
|
licenses.nav=Лицензии
|
||||||
licenses.title=Лицензии от третьих сторон
|
licenses.title=Лицензии от третьих сторон
|
||||||
|
|
|
@ -112,6 +112,7 @@ navbar.settings=Podešavanja
|
||||||
#############
|
#############
|
||||||
settings.title=Podešavanja
|
settings.title=Podešavanja
|
||||||
settings.update=Dostupno ažuriranje
|
settings.update=Dostupno ažuriranje
|
||||||
|
settings.updateAvailable={0} is the current installed version. A new version ({1}) is available.
|
||||||
settings.appVersion=Verzija aplikacije:
|
settings.appVersion=Verzija aplikacije:
|
||||||
settings.downloadOption.title=Odaberite opciju preuzimanja (Za preuzimanje pojedinačnih fajlova bez zip formata):
|
settings.downloadOption.title=Odaberite opciju preuzimanja (Za preuzimanje pojedinačnih fajlova bez zip formata):
|
||||||
settings.downloadOption.1=Otvori u istom prozoru
|
settings.downloadOption.1=Otvori u istom prozoru
|
||||||
|
@ -120,8 +121,9 @@ settings.downloadOption.3=Preuzmi fajl
|
||||||
settings.zipThreshold=Zipuj fajlove kada pređe broj preuzetih fajlova
|
settings.zipThreshold=Zipuj fajlove kada pređe broj preuzetih fajlova
|
||||||
settings.signOut=Odjava
|
settings.signOut=Odjava
|
||||||
settings.accountSettings=Podešavanja naloga
|
settings.accountSettings=Podešavanja naloga
|
||||||
|
settings.bored.help=Enables easter egg game
|
||||||
|
settings.cacheInputs.name=Save form inputs
|
||||||
|
settings.cacheInputs.help=Enable to store previously used inputs for future runs
|
||||||
|
|
||||||
changeCreds.title=Promeni pristupne podatke
|
changeCreds.title=Promeni pristupne podatke
|
||||||
changeCreds.header=Ažurirajte detalje svog naloga
|
changeCreds.header=Ažurirajte detalje svog naloga
|
||||||
|
@ -435,6 +437,8 @@ login.rememberme=Zapamti me
|
||||||
login.invalid=Neispravno korisničko ime ili lozinka.
|
login.invalid=Neispravno korisničko ime ili lozinka.
|
||||||
login.locked=Vaš nalog je zaključan.
|
login.locked=Vaš nalog je zaključan.
|
||||||
login.signinTitle=Molimo vas da se prijavite
|
login.signinTitle=Molimo vas da se prijavite
|
||||||
|
login.ssoSignIn=Prijavite se putem jedinstvene prijave
|
||||||
|
login.oauth2AutoCreateDisabled=OAUTH2 automatsko kreiranje korisnika je onemogućeno
|
||||||
|
|
||||||
|
|
||||||
#auto-redact
|
#auto-redact
|
||||||
|
@ -939,6 +943,7 @@ pdfToPDFA.header=PDF u PDF/A
|
||||||
pdfToPDFA.credit=Ova usluga koristi OCRmyPDF za konverziju u PDF/A format
|
pdfToPDFA.credit=Ova usluga koristi OCRmyPDF za konverziju u PDF/A format
|
||||||
pdfToPDFA.submit=Konvertuj
|
pdfToPDFA.submit=Konvertuj
|
||||||
pdfToPDFA.tip=Currently does not work for multiple inputs at once
|
pdfToPDFA.tip=Currently does not work for multiple inputs at once
|
||||||
|
pdfToPDFA.outputFormat=Output format
|
||||||
|
|
||||||
|
|
||||||
#PDFToWord
|
#PDFToWord
|
||||||
|
@ -1022,6 +1027,15 @@ split-by-sections.vertical.placeholder=Unesite broj vertikalnih podele
|
||||||
split-by-sections.submit=Razdvoji PDF
|
split-by-sections.submit=Razdvoji PDF
|
||||||
split-by-sections.merge=Merge Into One PDF
|
split-by-sections.merge=Merge Into One PDF
|
||||||
|
|
||||||
|
|
||||||
|
#printFile
|
||||||
|
printFile.title=Print File
|
||||||
|
printFile.header=Print File to Printer
|
||||||
|
printFile.selectText.1=Select File to Print
|
||||||
|
printFile.selectText.2=Enter Printer Name
|
||||||
|
printFile.submit=Print
|
||||||
|
|
||||||
|
|
||||||
#licenses
|
#licenses
|
||||||
licenses.nav=Licenses
|
licenses.nav=Licenses
|
||||||
licenses.title=3rd Party Licenses
|
licenses.title=3rd Party Licenses
|
||||||
|
|
|
@ -112,6 +112,7 @@ navbar.settings=Inställningar
|
||||||
#############
|
#############
|
||||||
settings.title=Inställningar
|
settings.title=Inställningar
|
||||||
settings.update=Uppdatering tillgänglig
|
settings.update=Uppdatering tillgänglig
|
||||||
|
settings.updateAvailable={0} is the current installed version. A new version ({1}) is available.
|
||||||
settings.appVersion=Appversion:
|
settings.appVersion=Appversion:
|
||||||
settings.downloadOption.title=Välj nedladdningsalternativ (för nedladdning av en fil utan zip):
|
settings.downloadOption.title=Välj nedladdningsalternativ (för nedladdning av en fil utan zip):
|
||||||
settings.downloadOption.1=Öppnas i samma fönster
|
settings.downloadOption.1=Öppnas i samma fönster
|
||||||
|
@ -120,8 +121,9 @@ settings.downloadOption.3=Ladda ner fil
|
||||||
settings.zipThreshold=Zip-filer när antalet nedladdade filer överskrider
|
settings.zipThreshold=Zip-filer när antalet nedladdade filer överskrider
|
||||||
settings.signOut=Sign Out
|
settings.signOut=Sign Out
|
||||||
settings.accountSettings=Account Settings
|
settings.accountSettings=Account Settings
|
||||||
|
settings.bored.help=Enables easter egg game
|
||||||
|
settings.cacheInputs.name=Save form inputs
|
||||||
|
settings.cacheInputs.help=Enable to store previously used inputs for future runs
|
||||||
|
|
||||||
changeCreds.title=Change Credentials
|
changeCreds.title=Change Credentials
|
||||||
changeCreds.header=Update Your Account Details
|
changeCreds.header=Update Your Account Details
|
||||||
|
@ -435,6 +437,8 @@ login.rememberme=Remember me
|
||||||
login.invalid=Invalid username or password.
|
login.invalid=Invalid username or password.
|
||||||
login.locked=Your account has been locked.
|
login.locked=Your account has been locked.
|
||||||
login.signinTitle=Please sign in
|
login.signinTitle=Please sign in
|
||||||
|
login.ssoSignIn=Logga in via enkel inloggning
|
||||||
|
login.oauth2AutoCreateDisabled=OAUTH2 Auto-Create User inaktiverad
|
||||||
|
|
||||||
|
|
||||||
#auto-redact
|
#auto-redact
|
||||||
|
@ -939,6 +943,7 @@ pdfToPDFA.header=PDF till PDF/A
|
||||||
pdfToPDFA.credit=Denna tjänst använder OCRmyPDF för PDF/A-konvertering
|
pdfToPDFA.credit=Denna tjänst använder OCRmyPDF för PDF/A-konvertering
|
||||||
pdfToPDFA.submit=Konvertera
|
pdfToPDFA.submit=Konvertera
|
||||||
pdfToPDFA.tip=Currently does not work for multiple inputs at once
|
pdfToPDFA.tip=Currently does not work for multiple inputs at once
|
||||||
|
pdfToPDFA.outputFormat=Output format
|
||||||
|
|
||||||
|
|
||||||
#PDFToWord
|
#PDFToWord
|
||||||
|
@ -1022,6 +1027,15 @@ split-by-sections.vertical.placeholder=Enter number of vertical divisions
|
||||||
split-by-sections.submit=Split PDF
|
split-by-sections.submit=Split PDF
|
||||||
split-by-sections.merge=Merge Into One PDF
|
split-by-sections.merge=Merge Into One PDF
|
||||||
|
|
||||||
|
|
||||||
|
#printFile
|
||||||
|
printFile.title=Print File
|
||||||
|
printFile.header=Print File to Printer
|
||||||
|
printFile.selectText.1=Select File to Print
|
||||||
|
printFile.selectText.2=Enter Printer Name
|
||||||
|
printFile.submit=Print
|
||||||
|
|
||||||
|
|
||||||
#licenses
|
#licenses
|
||||||
licenses.nav=Licenses
|
licenses.nav=Licenses
|
||||||
licenses.title=3rd Party Licenses
|
licenses.title=3rd Party Licenses
|
||||||
|
|
|
@ -66,31 +66,31 @@ seeDockerHub=Docker Hub'a bakın
|
||||||
visitGithub=Github Deposunu Ziyaret Edin
|
visitGithub=Github Deposunu Ziyaret Edin
|
||||||
donate=Bağış Yapın
|
donate=Bağış Yapın
|
||||||
color=Renk
|
color=Renk
|
||||||
sponsor=Sponsor
|
sponsor=Bağış
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
###############
|
###############
|
||||||
# Pipeline #
|
# Pipeline #
|
||||||
###############
|
###############
|
||||||
pipeline.header=Pipeline Menü (Beta)
|
pipeline.header=Çoklu İşlemler Menü (Beta)
|
||||||
pipeline.uploadButton=Upload edin
|
pipeline.uploadButton=Upload edin
|
||||||
pipeline.configureButton=Yapılandır
|
pipeline.configureButton=Yapılandır
|
||||||
pipeline.defaultOption=Özel
|
pipeline.defaultOption=Özel
|
||||||
pipeline.submitButton=Gönder
|
pipeline.submitButton=Gönder
|
||||||
pipeline.help=Pipeline Yardım
|
pipeline.help=Çoklu İşlemler Yardım
|
||||||
pipeline.scanHelp=Klasör Tarama Yardımı
|
pipeline.scanHelp=Klasör Tarama Yardımı
|
||||||
|
|
||||||
######################
|
######################
|
||||||
# Pipeline Options #
|
# Pipeline Options #
|
||||||
######################
|
######################
|
||||||
pipelineOptions.header=Pipeline Yapılandırma
|
pipelineOptions.header=Çoklu İşlemler Yapılandırma
|
||||||
pipelineOptions.pipelineNameLabel=Pipeline İsim
|
pipelineOptions.pipelineNameLabel=Çoklu İşlemler İsim
|
||||||
pipelineOptions.saveSettings=Ayarları Kaydet
|
pipelineOptions.saveSettings=Ayarları Kaydet
|
||||||
pipelineOptions.pipelineNamePrompt=Buraya isim girin
|
pipelineOptions.pipelineNamePrompt=Buraya isim girin
|
||||||
pipelineOptions.selectOperation=İşlem Seçin
|
pipelineOptions.selectOperation=İşlem Seçin
|
||||||
pipelineOptions.addOperationButton=İşlem ekle
|
pipelineOptions.addOperationButton=İşlem ekle
|
||||||
pipelineOptions.pipelineHeader=Pipeline:
|
pipelineOptions.pipelineHeader=Çoklu İşlemler:
|
||||||
pipelineOptions.saveButton=İndir
|
pipelineOptions.saveButton=İndir
|
||||||
pipelineOptions.validateButton=Doğrula
|
pipelineOptions.validateButton=Doğrula
|
||||||
|
|
||||||
|
@ -112,6 +112,7 @@ navbar.settings=Ayarlar
|
||||||
#############
|
#############
|
||||||
settings.title=Ayarlar
|
settings.title=Ayarlar
|
||||||
settings.update=Güncelleme mevcut
|
settings.update=Güncelleme mevcut
|
||||||
|
settings.updateAvailable={0} mevcut kurulu sürümdür. Yeni bir sürüm ({1}) mevcuttur.
|
||||||
settings.appVersion=Uygulama Sürümü:
|
settings.appVersion=Uygulama Sürümü:
|
||||||
settings.downloadOption.title=İndirme seçeneği seçin (Zip olmayan tek dosya indirmeler için):
|
settings.downloadOption.title=İndirme seçeneği seçin (Zip olmayan tek dosya indirmeler için):
|
||||||
settings.downloadOption.1=Aynı pencerede aç
|
settings.downloadOption.1=Aynı pencerede aç
|
||||||
|
@ -120,8 +121,9 @@ settings.downloadOption.3=Dosyayı indir
|
||||||
settings.zipThreshold=İndirilen dosya sayısı şu değeri aştığında zip dosyası oluştur:
|
settings.zipThreshold=İndirilen dosya sayısı şu değeri aştığında zip dosyası oluştur:
|
||||||
settings.signOut=Oturumu Kapat
|
settings.signOut=Oturumu Kapat
|
||||||
settings.accountSettings=Hesap Ayarları
|
settings.accountSettings=Hesap Ayarları
|
||||||
|
settings.bored.help=Paskalya yumurtası oyunu etkinleştirir
|
||||||
|
settings.cacheInputs.name=Form girdilerini kaydet
|
||||||
|
settings.cacheInputs.help=Gelecekteki çalıştırmalar için önceden kullanılan girdileri saklamayı etkinleştirin
|
||||||
|
|
||||||
changeCreds.title=Giriş Bilgilerini Değiştir
|
changeCreds.title=Giriş Bilgilerini Değiştir
|
||||||
changeCreds.header=Hesap Detaylarınızı Güncelleyin
|
changeCreds.header=Hesap Detaylarınızı Güncelleyin
|
||||||
|
@ -325,8 +327,8 @@ home.scalePages.title=Sayfa boyutunu/ölçeğini ayarla
|
||||||
home.scalePages.desc=Bir sayfanın ve/veya içeriğinin boyutunu/ölçeğini değiştirir
|
home.scalePages.desc=Bir sayfanın ve/veya içeriğinin boyutunu/ölçeğini değiştirir
|
||||||
scalePages.tags=boyutlandır,değiştir,boyut,uyarla
|
scalePages.tags=boyutlandır,değiştir,boyut,uyarla
|
||||||
|
|
||||||
home.pipeline.title=Hattı (İleri Seviye)
|
home.pipeline.title=Çoklu İşlemler (İleri Seviye)
|
||||||
home.pipeline.desc=Hattı betikleri tanımlayarak PDF'lere birden fazla işlemi çalıştır
|
home.pipeline.desc=Çoklu İşlemler tanımlayarak PDF'lere birden fazla işlemi çalıştır
|
||||||
pipeline.tags=otomatikleştir,sıralı,betikli,toplu-işlem
|
pipeline.tags=otomatikleştir,sıralı,betikli,toplu-işlem
|
||||||
|
|
||||||
home.add-page-numbers.title=Sayfa Numaraları Ekle
|
home.add-page-numbers.title=Sayfa Numaraları Ekle
|
||||||
|
@ -435,6 +437,8 @@ login.rememberme=Beni hatırla
|
||||||
login.invalid=Geçersiz kullanıcı adı veya şifre.
|
login.invalid=Geçersiz kullanıcı adı veya şifre.
|
||||||
login.locked=Hesabınız kilitlendi.
|
login.locked=Hesabınız kilitlendi.
|
||||||
login.signinTitle=Lütfen giriş yapınız.
|
login.signinTitle=Lütfen giriş yapınız.
|
||||||
|
login.ssoSignIn=Tek Oturum Açma ile Giriş Yap
|
||||||
|
login.oauth2AutoCreateDisabled=OAUTH2 Otomatik Oluşturma Kullanıcı Devre Dışı Bırakıldı
|
||||||
|
|
||||||
|
|
||||||
#auto-redact
|
#auto-redact
|
||||||
|
@ -595,7 +599,7 @@ autoSplitPDF.submit=Gönder
|
||||||
|
|
||||||
|
|
||||||
#pipeline
|
#pipeline
|
||||||
pipeline.title=Pipeline
|
pipeline.title=Çoklu İşlemler
|
||||||
|
|
||||||
|
|
||||||
#pageLayout
|
#pageLayout
|
||||||
|
@ -664,7 +668,7 @@ BookToPDF.submit=Dönüştür
|
||||||
#PDFToBook
|
#PDFToBook
|
||||||
PDFToBook.title=PDF'den Kitaba
|
PDFToBook.title=PDF'den Kitaba
|
||||||
PDFToBook.header=PDF'den Kitaba
|
PDFToBook.header=PDF'den Kitaba
|
||||||
PDFToBook.selectText.1=Format
|
PDFToBook.selectText.1=Format biçimi
|
||||||
PDFToBook.credit=Kalibre Kullanır
|
PDFToBook.credit=Kalibre Kullanır
|
||||||
PDFToBook.submit=Dönüştür
|
PDFToBook.submit=Dönüştür
|
||||||
|
|
||||||
|
@ -939,6 +943,7 @@ pdfToPDFA.header=PDF'den PDF/A'ya
|
||||||
pdfToPDFA.credit=Bu hizmet PDF/A dönüşümü için OCRmyPDF kullanır
|
pdfToPDFA.credit=Bu hizmet PDF/A dönüşümü için OCRmyPDF kullanır
|
||||||
pdfToPDFA.submit=Dönüştür
|
pdfToPDFA.submit=Dönüştür
|
||||||
pdfToPDFA.tip=Şu anda aynı anda birden fazla giriş için çalışmıyor
|
pdfToPDFA.tip=Şu anda aynı anda birden fazla giriş için çalışmıyor
|
||||||
|
pdfToPDFA.outputFormat=Çıkış formatı
|
||||||
|
|
||||||
|
|
||||||
#PDFToWord
|
#PDFToWord
|
||||||
|
@ -1022,6 +1027,15 @@ split-by-sections.vertical.placeholder=Dikey bölme sayısını girin
|
||||||
split-by-sections.submit=PDF'yi Böl
|
split-by-sections.submit=PDF'yi Böl
|
||||||
split-by-sections.merge=Bir PDF'de Birleştirin
|
split-by-sections.merge=Bir PDF'de Birleştirin
|
||||||
|
|
||||||
|
|
||||||
|
#printFile
|
||||||
|
printFile.title=Dosya Yazdır
|
||||||
|
printFile.header=Dosyayı Yazıcıya Yazdır
|
||||||
|
printFile.selectText.1=Yazdırılacak Dosyayı Seçin
|
||||||
|
printFile.selectText.2=Yazıcı Adını Girin
|
||||||
|
printFile.submit=Yazdır
|
||||||
|
|
||||||
|
|
||||||
#licenses
|
#licenses
|
||||||
licenses.nav=Lisanslar
|
licenses.nav=Lisanslar
|
||||||
licenses.title=3. Taraf Lisansları
|
licenses.title=3. Taraf Lisansları
|
||||||
|
|
|
@ -112,6 +112,7 @@ navbar.settings=Налаштування
|
||||||
#############
|
#############
|
||||||
settings.title=Налаштування
|
settings.title=Налаштування
|
||||||
settings.update=Доступне оновлення
|
settings.update=Доступне оновлення
|
||||||
|
settings.updateAvailable={0} is the current installed version. A new version ({1}) is available.
|
||||||
settings.appVersion=Версія додатку:
|
settings.appVersion=Версія додатку:
|
||||||
settings.downloadOption.title=Виберіть варіант завантаження (для завантаження одного файлу без zip):
|
settings.downloadOption.title=Виберіть варіант завантаження (для завантаження одного файлу без zip):
|
||||||
settings.downloadOption.1=Відкрити в тому ж вікні
|
settings.downloadOption.1=Відкрити в тому ж вікні
|
||||||
|
@ -120,8 +121,9 @@ settings.downloadOption.3=Завантажити файл
|
||||||
settings.zipThreshold=Zip-файли, коли кількість завантажених файлів перевищує
|
settings.zipThreshold=Zip-файли, коли кількість завантажених файлів перевищує
|
||||||
settings.signOut=Вийти
|
settings.signOut=Вийти
|
||||||
settings.accountSettings=Налаштування акаунта
|
settings.accountSettings=Налаштування акаунта
|
||||||
|
settings.bored.help=Enables easter egg game
|
||||||
|
settings.cacheInputs.name=Save form inputs
|
||||||
|
settings.cacheInputs.help=Enable to store previously used inputs for future runs
|
||||||
|
|
||||||
changeCreds.title=Змінити облікові дані
|
changeCreds.title=Змінити облікові дані
|
||||||
changeCreds.header=Оновіть дані вашого облікового запису
|
changeCreds.header=Оновіть дані вашого облікового запису
|
||||||
|
@ -132,6 +134,8 @@ changeCreds.newPassword=Новий пароль
|
||||||
changeCreds.confirmNewPassword=Підтвердіть новий пароль
|
changeCreds.confirmNewPassword=Підтвердіть новий пароль
|
||||||
changeCreds.submit=Надіслати зміни
|
changeCreds.submit=Надіслати зміни
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
account.title=Налаштування акаунта
|
account.title=Налаштування акаунта
|
||||||
account.accountSettings=Налаштування акаунта
|
account.accountSettings=Налаштування акаунта
|
||||||
account.adminSettings=Налаштування адміністратора - Перегляд і додавання користувачів
|
account.adminSettings=Налаштування адміністратора - Перегляд і додавання користувачів
|
||||||
|
@ -152,6 +156,7 @@ account.webBrowserSettings=Налаштування веб-браузера
|
||||||
account.syncToBrowser=Синхронізувати обліковий запис -> Браузер
|
account.syncToBrowser=Синхронізувати обліковий запис -> Браузер
|
||||||
account.syncToAccount=Синхронізувати обліковий запис <- Браузер
|
account.syncToAccount=Синхронізувати обліковий запис <- Браузер
|
||||||
|
|
||||||
|
|
||||||
adminUserSettings.title=Налаштування контролю користувача
|
adminUserSettings.title=Налаштування контролю користувача
|
||||||
adminUserSettings.header=Налаштування контролю користувача адміністратора
|
adminUserSettings.header=Налаштування контролю користувача адміністратора
|
||||||
adminUserSettings.admin=Адміністратор
|
adminUserSettings.admin=Адміністратор
|
||||||
|
@ -244,12 +249,10 @@ home.changeMetadata.title=Змінити метадані
|
||||||
home.changeMetadata.desc=Змінити/видалити/додати метадані з документа PDF
|
home.changeMetadata.desc=Змінити/видалити/додати метадані з документа PDF
|
||||||
changeMetadata.tags=Title,author,date,creation,time,publisher,producer,stats
|
changeMetadata.tags=Title,author,date,creation,time,publisher,producer,stats
|
||||||
|
|
||||||
|
|
||||||
home.fileToPDF.title=Конвертувати файл в PDF
|
home.fileToPDF.title=Конвертувати файл в PDF
|
||||||
home.fileToPDF.desc=Конвертуйте майже будь-який файл в PDF (DOCX, PNG, XLS, PPT, TXT та інші)
|
home.fileToPDF.desc=Конвертуйте майже будь-який файл в PDF (DOCX, PNG, XLS, PPT, TXT та інші)
|
||||||
fileToPDF.tags=transformation,format,document,picture,slide,text,conversion,office,docs,word,excel,powerpoint
|
fileToPDF.tags=transformation,format,document,picture,slide,text,conversion,office,docs,word,excel,powerpoint
|
||||||
|
|
||||||
|
|
||||||
home.ocr.title=OCR/Очищення сканування
|
home.ocr.title=OCR/Очищення сканування
|
||||||
home.ocr.desc=Очищення сканування та виявлення тексту на зображеннях у файлі PDF та повторне додавання його як текст.
|
home.ocr.desc=Очищення сканування та виявлення тексту на зображеннях у файлі PDF та повторне додавання його як текст.
|
||||||
ocr.tags=recognition,text,image,scan,read,identify,detection,editable
|
ocr.tags=recognition,text,image,scan,read,identify,detection,editable
|
||||||
|
@ -403,12 +406,10 @@ home.overlay-pdfs.title=Накладення PDF
|
||||||
home.overlay-pdfs.desc=Накладення одного PDF поверх іншого PDF
|
home.overlay-pdfs.desc=Накладення одного PDF поверх іншого PDF
|
||||||
overlay-pdfs.tags=Overlay
|
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
|
||||||
|
|
||||||
|
|
||||||
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
|
||||||
|
@ -418,11 +419,11 @@ home.PDFToBook.title=PDF у книгу/комікс
|
||||||
home.PDFToBook.desc=Конвертує PDF у формат книги/комікса за допомогою calibre
|
home.PDFToBook.desc=Конвертує PDF у формат книги/комікса за допомогою calibre
|
||||||
PDFToBook.tags=Book,Comic,Calibre,Convert,manga,amazon,kindle
|
PDFToBook.tags=Book,Comic,Calibre,Convert,manga,amazon,kindle
|
||||||
|
|
||||||
|
|
||||||
home.BookToPDF.title=Книга у PDF
|
home.BookToPDF.title=Книга у PDF
|
||||||
home.BookToPDF.desc=Конвертує формати книги/комікса у PDF за допомогою calibre
|
home.BookToPDF.desc=Конвертує формати книги/комікса у PDF за допомогою calibre
|
||||||
BookToPDF.tags=Book,Comic,Calibre,Convert,manga,amazon,kindle
|
BookToPDF.tags=Book,Comic,Calibre,Convert,manga,amazon,kindle
|
||||||
|
|
||||||
|
|
||||||
###########################
|
###########################
|
||||||
# #
|
# #
|
||||||
# WEB PAGES #
|
# WEB PAGES #
|
||||||
|
@ -436,6 +437,8 @@ login.rememberme=Запам'ятати мене
|
||||||
login.invalid=Недійсне ім'я користувача або пароль.
|
login.invalid=Недійсне ім'я користувача або пароль.
|
||||||
login.locked=Ваш обліковий запис заблоковано.
|
login.locked=Ваш обліковий запис заблоковано.
|
||||||
login.signinTitle=Будь ласка, увійдіть
|
login.signinTitle=Будь ласка, увійдіть
|
||||||
|
login.ssoSignIn=Увійти через єдиний вхід
|
||||||
|
login.oauth2AutoCreateDisabled=Автоматичне створення користувача OAUTH2 ВИМКНЕНО
|
||||||
|
|
||||||
|
|
||||||
#auto-redact
|
#auto-redact
|
||||||
|
@ -606,6 +609,7 @@ pageLayout.pagesPerSheet=Сторінок на одному аркуші:
|
||||||
pageLayout.addBorder=Додати рамки
|
pageLayout.addBorder=Додати рамки
|
||||||
pageLayout.submit=Відправити
|
pageLayout.submit=Відправити
|
||||||
|
|
||||||
|
|
||||||
#scalePages
|
#scalePages
|
||||||
scalePages.title=Відрегулювати масштаб сторінки
|
scalePages.title=Відрегулювати масштаб сторінки
|
||||||
scalePages.header=Відрегулювати масштаб сторінки
|
scalePages.header=Відрегулювати масштаб сторінки
|
||||||
|
@ -939,6 +943,7 @@ pdfToPDFA.header=PDF в PDF/A
|
||||||
pdfToPDFA.credit=Цей сервіс використовує OCRmyPDF для перетворення у формат PDF/A
|
pdfToPDFA.credit=Цей сервіс використовує OCRmyPDF для перетворення у формат PDF/A
|
||||||
pdfToPDFA.submit=Конвертувати
|
pdfToPDFA.submit=Конвертувати
|
||||||
pdfToPDFA.tip=Наразі не працює для кількох вхідних файлів одночасно
|
pdfToPDFA.tip=Наразі не працює для кількох вхідних файлів одночасно
|
||||||
|
pdfToPDFA.outputFormat=Output format
|
||||||
|
|
||||||
|
|
||||||
#PDFToWord
|
#PDFToWord
|
||||||
|
@ -1022,6 +1027,15 @@ split-by-sections.vertical.placeholder=Введіть кількість вер
|
||||||
split-by-sections.submit=Розділити PDF
|
split-by-sections.submit=Розділити PDF
|
||||||
split-by-sections.merge=Об'єднати в один PDF
|
split-by-sections.merge=Об'єднати в один PDF
|
||||||
|
|
||||||
|
|
||||||
|
#printFile
|
||||||
|
printFile.title=Print File
|
||||||
|
printFile.header=Print File to Printer
|
||||||
|
printFile.selectText.1=Select File to Print
|
||||||
|
printFile.selectText.2=Enter Printer Name
|
||||||
|
printFile.submit=Print
|
||||||
|
|
||||||
|
|
||||||
#licenses
|
#licenses
|
||||||
licenses.nav=Ліцензії
|
licenses.nav=Ліцензії
|
||||||
licenses.title=Ліцензії від третіх сторін
|
licenses.title=Ліцензії від третіх сторін
|
||||||
|
|
|
@ -112,6 +112,7 @@ navbar.settings=设置
|
||||||
#############
|
#############
|
||||||
settings.title=设置
|
settings.title=设置
|
||||||
settings.update=可更新
|
settings.update=可更新
|
||||||
|
settings.updateAvailable={0} is the current installed version. A new version ({1}) is available.
|
||||||
settings.appVersion=应用程序版本:
|
settings.appVersion=应用程序版本:
|
||||||
settings.downloadOption.title=选择下载选项(单个文件非压缩文件):
|
settings.downloadOption.title=选择下载选项(单个文件非压缩文件):
|
||||||
settings.downloadOption.1=在同一窗口打开
|
settings.downloadOption.1=在同一窗口打开
|
||||||
|
@ -120,8 +121,9 @@ settings.downloadOption.3=下载文件
|
||||||
settings.zipThreshold=当下载的文件数量超过限制时,将文件压缩。
|
settings.zipThreshold=当下载的文件数量超过限制时,将文件压缩。
|
||||||
settings.signOut=登出
|
settings.signOut=登出
|
||||||
settings.accountSettings=帐号设定
|
settings.accountSettings=帐号设定
|
||||||
|
settings.bored.help=Enables easter egg game
|
||||||
|
settings.cacheInputs.name=Save form inputs
|
||||||
|
settings.cacheInputs.help=Enable to store previously used inputs for future runs
|
||||||
|
|
||||||
changeCreds.title=更改凭证
|
changeCreds.title=更改凭证
|
||||||
changeCreds.header=更新您的账户详情
|
changeCreds.header=更新您的账户详情
|
||||||
|
@ -435,6 +437,8 @@ login.rememberme=记住我
|
||||||
login.invalid=用户名或密码无效。
|
login.invalid=用户名或密码无效。
|
||||||
login.locked=您的账户已被锁定。
|
login.locked=您的账户已被锁定。
|
||||||
login.signinTitle=请登录
|
login.signinTitle=请登录
|
||||||
|
login.ssoSignIn=通过单点登录登录
|
||||||
|
login.oauth2AutoCreateDisabled=OAUTH2自动创建用户已禁用
|
||||||
|
|
||||||
|
|
||||||
#auto-redact
|
#auto-redact
|
||||||
|
@ -939,6 +943,7 @@ pdfToPDFA.header=PDF转换为PDF/A
|
||||||
pdfToPDFA.credit=此服务使用OCRmyPDF进行PDF/A转换
|
pdfToPDFA.credit=此服务使用OCRmyPDF进行PDF/A转换
|
||||||
pdfToPDFA.submit=转换
|
pdfToPDFA.submit=转换
|
||||||
pdfToPDFA.tip=目前不支持上传多个
|
pdfToPDFA.tip=目前不支持上传多个
|
||||||
|
pdfToPDFA.outputFormat=Output format
|
||||||
|
|
||||||
|
|
||||||
#PDFToWord
|
#PDFToWord
|
||||||
|
@ -1022,6 +1027,15 @@ split-by-sections.vertical.placeholder=输入垂直分割数
|
||||||
split-by-sections.submit=分割PDF
|
split-by-sections.submit=分割PDF
|
||||||
split-by-sections.merge=是否合并为一个pdf
|
split-by-sections.merge=是否合并为一个pdf
|
||||||
|
|
||||||
|
|
||||||
|
#printFile
|
||||||
|
printFile.title=Print File
|
||||||
|
printFile.header=Print File to Printer
|
||||||
|
printFile.selectText.1=Select File to Print
|
||||||
|
printFile.selectText.2=Enter Printer Name
|
||||||
|
printFile.submit=Print
|
||||||
|
|
||||||
|
|
||||||
#licenses
|
#licenses
|
||||||
licenses.nav=许可证
|
licenses.nav=许可证
|
||||||
licenses.title=第三方许可证
|
licenses.title=第三方许可证
|
||||||
|
|
|
@ -112,6 +112,7 @@ navbar.settings=設定
|
||||||
#############
|
#############
|
||||||
settings.title=設定
|
settings.title=設定
|
||||||
settings.update=有更新可用
|
settings.update=有更新可用
|
||||||
|
settings.updateAvailable={0} is the current installed version. A new version ({1}) is available.
|
||||||
settings.appVersion=應用版本:
|
settings.appVersion=應用版本:
|
||||||
settings.downloadOption.title=選擇下載選項(對於單一檔案非壓縮下載):
|
settings.downloadOption.title=選擇下載選項(對於單一檔案非壓縮下載):
|
||||||
settings.downloadOption.1=在同一視窗中開啟
|
settings.downloadOption.1=在同一視窗中開啟
|
||||||
|
@ -120,8 +121,9 @@ settings.downloadOption.3=下載檔案
|
||||||
settings.zipThreshold=當下載的檔案數量超過時,壓縮檔案
|
settings.zipThreshold=當下載的檔案數量超過時,壓縮檔案
|
||||||
settings.signOut=登出
|
settings.signOut=登出
|
||||||
settings.accountSettings=帳戶設定
|
settings.accountSettings=帳戶設定
|
||||||
|
settings.bored.help=Enables easter egg game
|
||||||
|
settings.cacheInputs.name=Save form inputs
|
||||||
|
settings.cacheInputs.help=Enable to store previously used inputs for future runs
|
||||||
|
|
||||||
changeCreds.title=變更憑證
|
changeCreds.title=變更憑證
|
||||||
changeCreds.header=更新您的帳戶詳細資訊
|
changeCreds.header=更新您的帳戶詳細資訊
|
||||||
|
@ -435,6 +437,8 @@ login.rememberme=記住我
|
||||||
login.invalid=使用者名稱或密碼無效。
|
login.invalid=使用者名稱或密碼無效。
|
||||||
login.locked=您的帳戶已被鎖定。
|
login.locked=您的帳戶已被鎖定。
|
||||||
login.signinTitle=請登入
|
login.signinTitle=請登入
|
||||||
|
login.ssoSignIn=透過織網單一簽入
|
||||||
|
login.oauth2AutoCreateDisabled=OAUTH2自動建立使用者已停用
|
||||||
|
|
||||||
|
|
||||||
#auto-redact
|
#auto-redact
|
||||||
|
@ -939,6 +943,7 @@ pdfToPDFA.header=PDF 轉 PDF/A
|
||||||
pdfToPDFA.credit=此服務使用 OCRmyPDF 進行 PDF/A 轉換
|
pdfToPDFA.credit=此服務使用 OCRmyPDF 進行 PDF/A 轉換
|
||||||
pdfToPDFA.submit=轉換
|
pdfToPDFA.submit=轉換
|
||||||
pdfToPDFA.tip=目前不支援上傳多個
|
pdfToPDFA.tip=目前不支援上傳多個
|
||||||
|
pdfToPDFA.outputFormat=Output format
|
||||||
|
|
||||||
|
|
||||||
#PDFToWord
|
#PDFToWord
|
||||||
|
@ -1022,6 +1027,15 @@ split-by-sections.vertical.placeholder=輸入垂直劃分的數量
|
||||||
split-by-sections.submit=分割 PDF
|
split-by-sections.submit=分割 PDF
|
||||||
split-by-sections.merge=是否合併為一個pdf
|
split-by-sections.merge=是否合併為一個pdf
|
||||||
|
|
||||||
|
|
||||||
|
#printFile
|
||||||
|
printFile.title=Print File
|
||||||
|
printFile.header=Print File to Printer
|
||||||
|
printFile.selectText.1=Select File to Print
|
||||||
|
printFile.selectText.2=Enter Printer Name
|
||||||
|
printFile.submit=Print
|
||||||
|
|
||||||
|
|
||||||
#licenses
|
#licenses
|
||||||
licenses.nav=許可證
|
licenses.nav=許可證
|
||||||
licenses.title=第三方許可證
|
licenses.title=第三方許可證
|
||||||
|
|
|
@ -7,11 +7,20 @@ security:
|
||||||
csrfDisabled: true
|
csrfDisabled: true
|
||||||
loginAttemptCount: 5 # lock user account after 5 tries
|
loginAttemptCount: 5 # lock user account after 5 tries
|
||||||
loginResetTimeMinutes : 120 # lock account for 2 hours after x attempts
|
loginResetTimeMinutes : 120 # lock account for 2 hours after x attempts
|
||||||
|
#oauth2:
|
||||||
|
# enabled: false # set to 'true' to enable login (Note: enableLogin must also be 'true' for this to work)
|
||||||
|
# issuer: "" # set to any provider that supports OpenID Connect Discovery (/.well-known/openid-configuration) end-point
|
||||||
|
# clientId: "" # Client ID from your provider
|
||||||
|
# clientSecret: "" # Client Secret from your provider
|
||||||
|
# autoCreateUser: false # set to 'true' to allow auto-creation of non-existing users
|
||||||
|
|
||||||
system:
|
system:
|
||||||
defaultLocale: 'en-US' # Set the default language (e.g. 'de-DE', 'fr-FR', etc)
|
defaultLocale: 'en-US' # Set the default language (e.g. 'de-DE', 'fr-FR', etc)
|
||||||
googlevisibility: false # 'true' to allow Google visibility (via robots.txt), 'false' to disallow
|
googlevisibility: false # 'true' to allow Google visibility (via robots.txt), 'false' to disallow
|
||||||
enableAlphaFunctionality: false # Set to enable functionality which might need more testing before it fully goes live (This feature might make no changes)
|
enableAlphaFunctionality: false # Set to enable functionality which might need more testing before it fully goes live (This feature might make no changes)
|
||||||
|
showUpdate: true # see when a new update is available
|
||||||
|
showUpdateOnlyAdmin: false # Only admins can see when a new update is available, depending on showUpdate it must be set to 'true'
|
||||||
|
customHTMLFiles: false # Enable to have files placed in /customFiles/templates override the existing template html files
|
||||||
|
|
||||||
#ui:
|
#ui:
|
||||||
# appName: exampleAppName # Application's visible name
|
# appName: exampleAppName # Application's visible name
|
||||||
|
|
|
@ -81,6 +81,13 @@
|
||||||
"moduleLicense": "GNU Lesser General Public License v3 (LGPL-v3)",
|
"moduleLicense": "GNU Lesser General Public License v3 (LGPL-v3)",
|
||||||
"moduleLicenseUrl": "http://www.gnu.org/licenses/lgpl-3.0.html"
|
"moduleLicenseUrl": "http://www.gnu.org/licenses/lgpl-3.0.html"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"moduleName": "com.github.stephenc.jcip:jcip-annotations",
|
||||||
|
"moduleUrl": "http://stephenc.github.com/jcip-annotations",
|
||||||
|
"moduleVersion": "1.0-1",
|
||||||
|
"moduleLicense": "Apache License, Version 2.0",
|
||||||
|
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "com.github.vladimir-bukhtoyarov:bucket4j-core",
|
"moduleName": "com.github.vladimir-bukhtoyarov:bucket4j-core",
|
||||||
"moduleUrl": "http://github.com/vladimir-bukhtoyarov/bucket4j/bucket4j-core",
|
"moduleUrl": "http://github.com/vladimir-bukhtoyarov/bucket4j/bucket4j-core",
|
||||||
|
@ -109,6 +116,34 @@
|
||||||
"moduleLicense": "LGPL",
|
"moduleLicense": "LGPL",
|
||||||
"moduleLicenseUrl": "http://www.martiansoftware.com/jsap/license.html"
|
"moduleLicenseUrl": "http://www.martiansoftware.com/jsap/license.html"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"moduleName": "com.nimbusds:content-type",
|
||||||
|
"moduleUrl": "https://connect2id.com",
|
||||||
|
"moduleVersion": "2.2",
|
||||||
|
"moduleLicense": "The Apache Software License, Version 2.0",
|
||||||
|
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"moduleName": "com.nimbusds:lang-tag",
|
||||||
|
"moduleUrl": "https://connect2id.com/",
|
||||||
|
"moduleVersion": "1.7",
|
||||||
|
"moduleLicense": "The Apache Software License, Version 2.0",
|
||||||
|
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"moduleName": "com.nimbusds:nimbus-jose-jwt",
|
||||||
|
"moduleUrl": "https://connect2id.com",
|
||||||
|
"moduleVersion": "9.24.4",
|
||||||
|
"moduleLicense": "The Apache Software License, Version 2.0",
|
||||||
|
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"moduleName": "com.nimbusds:oauth2-oidc-sdk",
|
||||||
|
"moduleUrl": "https://bitbucket.org/connect2id/oauth-2.0-sdk-with-openid-connect-extensions",
|
||||||
|
"moduleVersion": "9.43.3",
|
||||||
|
"moduleLicense": "Apache License, version 2.0",
|
||||||
|
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.html"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "com.opencsv:opencsv",
|
"moduleName": "com.opencsv:opencsv",
|
||||||
"moduleUrl": "http://opencsv.sf.net",
|
"moduleUrl": "http://opencsv.sf.net",
|
||||||
|
@ -335,6 +370,20 @@
|
||||||
"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": "net.minidev:accessors-smart",
|
||||||
|
"moduleUrl": "https://urielch.github.io/",
|
||||||
|
"moduleVersion": "2.5.0",
|
||||||
|
"moduleLicense": "The Apache Software License, Version 2.0",
|
||||||
|
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"moduleName": "net.minidev:json-smart",
|
||||||
|
"moduleUrl": "https://urielch.github.io/",
|
||||||
|
"moduleVersion": "2.5.0",
|
||||||
|
"moduleLicense": "The Apache Software License, Version 2.0",
|
||||||
|
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "org.antlr:antlr4-runtime",
|
"moduleName": "org.antlr:antlr4-runtime",
|
||||||
"moduleUrl": "https://www.antlr.org/",
|
"moduleUrl": "https://www.antlr.org/",
|
||||||
|
@ -547,6 +596,13 @@
|
||||||
"moduleLicense": "Public Domain, per Creative Commons CC0",
|
"moduleLicense": "Public Domain, per Creative Commons CC0",
|
||||||
"moduleLicenseUrl": "http://creativecommons.org/publicdomain/zero/1.0/"
|
"moduleLicenseUrl": "http://creativecommons.org/publicdomain/zero/1.0/"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"moduleName": "org.ow2.asm:asm",
|
||||||
|
"moduleUrl": "http://asm.ow2.org",
|
||||||
|
"moduleVersion": "9.3",
|
||||||
|
"moduleLicense": "The Apache Software License, Version 2.0",
|
||||||
|
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "org.slf4j:jul-to-slf4j",
|
"moduleName": "org.slf4j:jul-to-slf4j",
|
||||||
"moduleUrl": "http://www.slf4j.org",
|
"moduleUrl": "http://www.slf4j.org",
|
||||||
|
@ -663,6 +719,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.boot:spring-boot-starter-oauth2-client",
|
||||||
|
"moduleUrl": "https://spring.io/projects/spring-boot",
|
||||||
|
"moduleVersion": "3.2.4",
|
||||||
|
"moduleLicense": "Apache License, Version 2.0",
|
||||||
|
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "org.springframework.boot:spring-boot-starter-security",
|
"moduleName": "org.springframework.boot:spring-boot-starter-security",
|
||||||
"moduleUrl": "https://spring.io/projects/spring-boot",
|
"moduleUrl": "https://spring.io/projects/spring-boot",
|
||||||
|
@ -726,6 +789,27 @@
|
||||||
"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.security:spring-security-oauth2-client",
|
||||||
|
"moduleUrl": "https://spring.io/projects/spring-security",
|
||||||
|
"moduleVersion": "6.2.3",
|
||||||
|
"moduleLicense": "Apache License, Version 2.0",
|
||||||
|
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"moduleName": "org.springframework.security:spring-security-oauth2-core",
|
||||||
|
"moduleUrl": "https://spring.io/projects/spring-security",
|
||||||
|
"moduleVersion": "6.2.3",
|
||||||
|
"moduleLicense": "Apache License, Version 2.0",
|
||||||
|
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"moduleName": "org.springframework.security:spring-security-oauth2-jose",
|
||||||
|
"moduleUrl": "https://spring.io/projects/spring-security",
|
||||||
|
"moduleVersion": "6.2.3",
|
||||||
|
"moduleLicense": "Apache License, Version 2.0",
|
||||||
|
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "org.springframework.security:spring-security-web",
|
"moduleName": "org.springframework.security:spring-security-web",
|
||||||
"moduleUrl": "https://spring.io/projects/spring-security",
|
"moduleUrl": "https://spring.io/projects/spring-security",
|
||||||
|
|
|
@ -89,3 +89,38 @@
|
||||||
.jumbotron {
|
.jumbotron {
|
||||||
padding: 3rem 3rem; /* Reduce vertical padding */
|
padding: 3rem 3rem; /* Reduce vertical padding */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.lookatme {
|
||||||
|
opacity: 1;
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lookatme::after {
|
||||||
|
color: #e33100;
|
||||||
|
text-shadow: 0 0 5px #e33100;
|
||||||
|
/* in the html, the data-lookatme-text attribute must */
|
||||||
|
/* contain the same text as the .lookatme element */
|
||||||
|
content: attr(data-lookatme-text);
|
||||||
|
padding: inherit;
|
||||||
|
position: absolute;
|
||||||
|
inset: 0 0 0 0;
|
||||||
|
z-index: 1;
|
||||||
|
/* 20 steps / 2 seconds = 10fps */
|
||||||
|
-webkit-animation: 2s infinite Pulse steps(20);
|
||||||
|
animation: 2s infinite Pulse steps(20);
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes Pulse {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
to {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
1
src/main/resources/static/images/update.svg
Normal file
1
src/main/resources/static/images/update.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M21,10.12H14.22L16.96,7.3C14.23,4.6 9.81,4.5 7.08,7.2C4.35,9.91 4.35,14.28 7.08,17C9.81,19.7 14.23,19.7 16.96,17C18.32,15.65 19,14.08 19,12.1H21C21,14.08 20.12,16.65 18.36,18.39C14.85,21.87 9.15,21.87 5.64,18.39C2.14,14.92 2.11,9.28 5.62,5.81C9.13,2.34 14.76,2.34 18.27,5.81L21,3V10.12M12.5,8V12.25L16,14.33L15.28,15.54L11,13V8H12.5Z" /></svg>
|
After Width: | Height: | Size: 412 B |
82
src/main/resources/static/js/cacheFormInputs.js
Normal file
82
src/main/resources/static/js/cacheFormInputs.js
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
document.addEventListener("DOMContentLoaded", function() {
|
||||||
|
|
||||||
|
var cacheInputs = localStorage.getItem("cacheInputs") || "disabled";
|
||||||
|
if (cacheInputs !== "enabled") {
|
||||||
|
return; // Stop execution if caching is not enabled
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to generate a key based on the form's action attribute
|
||||||
|
function generateStorageKey(form) {
|
||||||
|
const action = form.getAttribute('action');
|
||||||
|
if (!action || action.length < 3) {
|
||||||
|
return null; // Not a valid action, return null to skip processing
|
||||||
|
}
|
||||||
|
return 'formData_' + encodeURIComponent(action);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to save form data to localStorage
|
||||||
|
function saveFormData(form) {
|
||||||
|
const formKey = generateStorageKey(form);
|
||||||
|
if (!formKey) return; // Skip if no valid key
|
||||||
|
|
||||||
|
const formData = {};
|
||||||
|
const elements = form.elements;
|
||||||
|
for (let i = 0; i < elements.length; i++) {
|
||||||
|
const element = elements[i];
|
||||||
|
// Skip elements without names, passwords, files, hidden fields, and submit/reset buttons
|
||||||
|
if (!element.name ||
|
||||||
|
element.type === 'password' ||
|
||||||
|
element.type === 'file' ||
|
||||||
|
//element.type === 'hidden' ||
|
||||||
|
element.type === 'submit' ||
|
||||||
|
element.type === 'reset') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Handle checkboxes: store only if checked
|
||||||
|
if (element.type === 'checkbox') {
|
||||||
|
if (element.checked) {
|
||||||
|
formData[element.name] = element.value;
|
||||||
|
} else {
|
||||||
|
continue; // Skip unchecked boxes
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Skip saving empty values
|
||||||
|
if (element.value === "" || element.value == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
formData[element.name] = element.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
localStorage.setItem(formKey, JSON.stringify(formData));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to load form data from localStorage
|
||||||
|
function loadFormData(form) {
|
||||||
|
const formKey = generateStorageKey(form);
|
||||||
|
if (!formKey) return; // Skip if no valid key
|
||||||
|
|
||||||
|
const savedData = localStorage.getItem(formKey);
|
||||||
|
if (savedData) {
|
||||||
|
const formData = JSON.parse(savedData);
|
||||||
|
for (const key in formData) {
|
||||||
|
if (formData.hasOwnProperty(key) && form.elements[key]) {
|
||||||
|
const element = form.elements[key];
|
||||||
|
if (element.type === 'checkbox') {
|
||||||
|
element.checked = true;
|
||||||
|
} else {
|
||||||
|
element.value = formData[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attach event listeners and load data for all forms
|
||||||
|
const forms = document.querySelectorAll('form');
|
||||||
|
forms.forEach(form => {
|
||||||
|
form.addEventListener('submit', function(event) {
|
||||||
|
saveFormData(form);
|
||||||
|
});
|
||||||
|
loadFormData(form);
|
||||||
|
});
|
||||||
|
});
|
|
@ -5,6 +5,7 @@ const DraggableUtils = {
|
||||||
pdfDoc: null,
|
pdfDoc: null,
|
||||||
pageIndex: 0,
|
pageIndex: 0,
|
||||||
documentsMap: new Map(),
|
documentsMap: new Map(),
|
||||||
|
lastInteracted: null,
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
interact(".draggable-canvas")
|
interact(".draggable-canvas")
|
||||||
|
@ -12,14 +13,18 @@ const DraggableUtils = {
|
||||||
listeners: {
|
listeners: {
|
||||||
move: (event) => {
|
move: (event) => {
|
||||||
const target = event.target;
|
const target = event.target;
|
||||||
const x = (parseFloat(target.getAttribute("data-bs-x")) || 0) + event.dx;
|
const x = (parseFloat(target.getAttribute("data-bs-x")) || 0)
|
||||||
const y = (parseFloat(target.getAttribute("data-bs-y")) || 0) + event.dy;
|
+ event.dx;
|
||||||
|
const y = (parseFloat(target.getAttribute("data-bs-y")) || 0)
|
||||||
|
+ event.dy;
|
||||||
|
|
||||||
target.style.transform = `translate(${x}px, ${y}px)`;
|
target.style.transform = `translate(${x}px, ${y}px)`;
|
||||||
target.setAttribute("data-bs-x", x);
|
target.setAttribute("data-bs-x", x);
|
||||||
target.setAttribute("data-bs-y", y);
|
target.setAttribute("data-bs-y", y);
|
||||||
|
|
||||||
this.onInteraction(target);
|
this.onInteraction(target);
|
||||||
|
//update the last interacted element
|
||||||
|
this.lastInteracted = event.target;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -38,7 +43,8 @@ const DraggableUtils = {
|
||||||
let width = event.rect.width;
|
let width = event.rect.width;
|
||||||
let height = event.rect.height;
|
let height = event.rect.height;
|
||||||
|
|
||||||
if (Math.abs(event.deltaRect.width) >= Math.abs(event.deltaRect.height)) {
|
if (Math.abs(event.deltaRect.width) >= Math.abs(
|
||||||
|
event.deltaRect.height)) {
|
||||||
height = width / aspectRatio;
|
height = width / aspectRatio;
|
||||||
} else {
|
} else {
|
||||||
width = height * aspectRatio;
|
width = height * aspectRatio;
|
||||||
|
@ -59,7 +65,8 @@ const DraggableUtils = {
|
||||||
|
|
||||||
target.setAttribute("data-bs-x", x);
|
target.setAttribute("data-bs-x", x);
|
||||||
target.setAttribute("data-bs-y", y);
|
target.setAttribute("data-bs-y", y);
|
||||||
target.textContent = Math.round(event.rect.width) + "\u00D7" + Math.round(event.rect.height);
|
target.textContent = Math.round(event.rect.width) + "\u00D7"
|
||||||
|
+ Math.round(event.rect.height);
|
||||||
|
|
||||||
this.onInteraction(target);
|
this.onInteraction(target);
|
||||||
},
|
},
|
||||||
|
@ -72,7 +79,56 @@ const DraggableUtils = {
|
||||||
],
|
],
|
||||||
inertia: true,
|
inertia: true,
|
||||||
});
|
});
|
||||||
|
//Arrow key Support for Add-Image and Sign pages
|
||||||
|
if(window.location.pathname.endsWith('sign') || window.location.pathname.endsWith('add-image')) {
|
||||||
|
window.addEventListener('keydown', (event) => {
|
||||||
|
//Check for last interacted element
|
||||||
|
if (!this.lastInteracted){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Get the currently selected element
|
||||||
|
const target = this.lastInteracted;
|
||||||
|
|
||||||
|
// Step size relatively to the elements size
|
||||||
|
const stepX = target.offsetWidth * 0.05;
|
||||||
|
const stepY = target.offsetHeight * 0.05;
|
||||||
|
|
||||||
|
// Get the current x and y coordinates
|
||||||
|
let x = (parseFloat(target.getAttribute('data-bs-x')) || 0);
|
||||||
|
let y = (parseFloat(target.getAttribute('data-bs-y')) || 0);
|
||||||
|
|
||||||
|
// Check which key was pressed and update the coordinates accordingly
|
||||||
|
switch (event.key) {
|
||||||
|
case 'ArrowUp':
|
||||||
|
y -= stepY;
|
||||||
|
event.preventDefault(); // Prevent the default action
|
||||||
|
break;
|
||||||
|
case 'ArrowDown':
|
||||||
|
y += stepY;
|
||||||
|
event.preventDefault();
|
||||||
|
break;
|
||||||
|
case 'ArrowLeft':
|
||||||
|
x -= stepX;
|
||||||
|
event.preventDefault();
|
||||||
|
break;
|
||||||
|
case 'ArrowRight':
|
||||||
|
x += stepX;
|
||||||
|
event.preventDefault();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return; // Listen only to arrow keys
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update position
|
||||||
|
target.style.transform = `translate(${x}px, ${y}px)`;
|
||||||
|
target.setAttribute('data-bs-x', x);
|
||||||
|
target.setAttribute('data-bs-y', y);
|
||||||
|
|
||||||
|
DraggableUtils.onInteraction(target);
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
onInteraction(target) {
|
onInteraction(target) {
|
||||||
this.boxDragContainer.appendChild(target);
|
this.boxDragContainer.appendChild(target);
|
||||||
},
|
},
|
||||||
|
@ -88,9 +144,18 @@ const DraggableUtils = {
|
||||||
createdCanvas.setAttribute("data-bs-x", x);
|
createdCanvas.setAttribute("data-bs-x", x);
|
||||||
createdCanvas.setAttribute("data-bs-y", y);
|
createdCanvas.setAttribute("data-bs-y", y);
|
||||||
|
|
||||||
|
//Click element in order to enable arrow keys
|
||||||
|
createdCanvas.addEventListener('click', () => {
|
||||||
|
this.lastInteracted = createdCanvas;
|
||||||
|
});
|
||||||
|
|
||||||
createdCanvas.onclick = (e) => this.onInteraction(e.target);
|
createdCanvas.onclick = (e) => this.onInteraction(e.target);
|
||||||
|
|
||||||
this.boxDragContainer.appendChild(createdCanvas);
|
this.boxDragContainer.appendChild(createdCanvas);
|
||||||
|
|
||||||
|
//Enable Arrow keys directly after the element is created
|
||||||
|
this.lastInteracted = createdCanvas;
|
||||||
|
|
||||||
return createdCanvas;
|
return createdCanvas;
|
||||||
},
|
},
|
||||||
createDraggableCanvasFromUrl(dataUrl) {
|
createDraggableCanvasFromUrl(dataUrl) {
|
||||||
|
@ -134,6 +199,11 @@ const DraggableUtils = {
|
||||||
},
|
},
|
||||||
deleteDraggableCanvas(element) {
|
deleteDraggableCanvas(element) {
|
||||||
if (element) {
|
if (element) {
|
||||||
|
//Check if deleted element is the last interacted
|
||||||
|
if (this.lastInteracted === element) {
|
||||||
|
// If it is, set lastInteracted to null
|
||||||
|
this.lastInteracted = null;
|
||||||
|
}
|
||||||
element.remove();
|
element.remove();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -30,19 +30,39 @@ async function getLatestReleaseVersion() {
|
||||||
|
|
||||||
async function checkForUpdate() {
|
async function checkForUpdate() {
|
||||||
// Initialize the update button as hidden
|
// Initialize the update button as hidden
|
||||||
var updateBtn = document.getElementById("update-btn");
|
var updateBtn = document.getElementById("update-btn") || null;
|
||||||
|
var updateLink = document.getElementById("update-link") || null;
|
||||||
if (updateBtn !== null) {
|
if (updateBtn !== null) {
|
||||||
updateBtn.style.display = "none";
|
updateBtn.style.display = "none";
|
||||||
}
|
}
|
||||||
|
if (updateLink !== null) {
|
||||||
|
console.log("hidden!");
|
||||||
|
if (!updateLink.classList.contains("visually-hidden")) {
|
||||||
|
updateLink.classList.add("visually-hidden");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const latestVersion = await getLatestReleaseVersion();
|
const latestVersion = await getLatestReleaseVersion();
|
||||||
console.log("latestVersion=" + latestVersion);
|
console.log("latestVersion=" + latestVersion);
|
||||||
console.log("currentVersion=" + currentVersion);
|
console.log("currentVersion=" + currentVersion);
|
||||||
console.log("compareVersions(latestVersion, currentVersion) > 0)=" + compareVersions(latestVersion, currentVersion));
|
console.log("compareVersions(latestVersion, currentVersion) > 0)=" + compareVersions(latestVersion, currentVersion));
|
||||||
if (latestVersion && compareVersions(latestVersion, currentVersion) > 0) {
|
if (latestVersion && compareVersions(latestVersion, currentVersion) > 0) {
|
||||||
|
if (updateBtn != null) {
|
||||||
document.getElementById("update-btn").style.display = "block";
|
document.getElementById("update-btn").style.display = "block";
|
||||||
|
}
|
||||||
|
if (updateLink !== null) {
|
||||||
|
document.getElementById("app-update").innerHTML = updateAvailable.replace("{0}", '<b>' + currentVersion + '</b>').replace("{1}", '<b>' + latestVersion + '</b>');
|
||||||
|
if (updateLink.classList.contains("visually-hidden")) {
|
||||||
|
updateLink.classList.remove("visually-hidden");
|
||||||
|
}
|
||||||
|
}
|
||||||
console.log("visible");
|
console.log("visible");
|
||||||
} else {
|
} else {
|
||||||
|
if (updateLink !== null) {
|
||||||
|
if (!updateLink.classList.contains("visually-hidden")) {
|
||||||
|
updateLink.classList.add("visually-hidden");
|
||||||
|
}
|
||||||
|
}
|
||||||
console.log("hidden");
|
console.log("hidden");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,6 +46,12 @@ function reorderCards() {
|
||||||
cards.sort(function (a, b) {
|
cards.sort(function (a, b) {
|
||||||
var aIsFavorite = localStorage.getItem(a.id) === "favorite";
|
var aIsFavorite = localStorage.getItem(a.id) === "favorite";
|
||||||
var bIsFavorite = localStorage.getItem(b.id) === "favorite";
|
var bIsFavorite = localStorage.getItem(b.id) === "favorite";
|
||||||
|
if (a.id === "update-link") {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (b.id === "update-link") {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
if (aIsFavorite && !bIsFavorite) {
|
if (aIsFavorite && !bIsFavorite) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,3 +31,12 @@ document.getElementById("boredWaiting").addEventListener("change", function () {
|
||||||
boredWaiting = this.checked ? "enabled" : "disabled";
|
boredWaiting = this.checked ? "enabled" : "disabled";
|
||||||
localStorage.setItem("boredWaiting", boredWaiting);
|
localStorage.setItem("boredWaiting", boredWaiting);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var cacheInputs = localStorage.getItem("cacheInputs") || "disabled";
|
||||||
|
document.getElementById("cacheInputs").checked = cacheInputs === "enabled";
|
||||||
|
|
||||||
|
document.getElementById("cacheInputs").addEventListener("change", function () {
|
||||||
|
cacheInputs = this.checked ? "enabled" : "disabled";
|
||||||
|
localStorage.setItem("cacheInputs", cacheInputs);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
|
@ -42,7 +42,7 @@
|
||||||
</div>
|
</div>
|
||||||
</th:block>
|
</th:block>
|
||||||
<!-- Change Username Form -->
|
<!-- Change Username Form -->
|
||||||
<form action="api/v1/user/change-username" method="post">
|
<form th:if="${!oAuth2Login}" action="api/v1/user/change-username" method="post">
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="newUsername" th:text="#{account.changeUsername}">Change Username</label>
|
<label for="newUsername" th:text="#{account.changeUsername}">Change Username</label>
|
||||||
<input type="text" class="form-control" name="newUsername" id="newUsername" th:placeholder="#{account.newUsername}">
|
<input type="text" class="form-control" name="newUsername" id="newUsername" th:placeholder="#{account.newUsername}">
|
||||||
|
@ -59,8 +59,8 @@
|
||||||
<hr> <!-- Separator Line -->
|
<hr> <!-- Separator Line -->
|
||||||
|
|
||||||
<!-- Change Password Form -->
|
<!-- Change Password Form -->
|
||||||
<h4 th:text="#{account.changePassword}">Change Password?</h4>
|
<h4 th:if="${!oAuth2Login}" th:text="#{account.changePassword}">Change Password?</h4>
|
||||||
<form action="api/v1/user/change-password" method="post">
|
<form th:if="${!oAuth2Login}" action="api/v1/user/change-password" method="post">
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="currentPassword" th:text="#{account.oldPassword}">Old Password</label>
|
<label for="currentPassword" th:text="#{account.oldPassword}">Old Password</label>
|
||||||
<input type="password" class="form-control" name="currentPassword" id="currentPasswordPassword" th:placeholder="#{account.oldPassword}">
|
<input type="password" class="form-control" name="currentPassword" id="currentPasswordPassword" th:placeholder="#{account.oldPassword}">
|
||||||
|
|
|
@ -17,6 +17,13 @@
|
||||||
<p th:text="#{pdfToPDFA.tip}"></p>
|
<p th:text="#{pdfToPDFA.tip}"></p>
|
||||||
<form method="post" enctype="multipart/form-data" th:action="@{api/v1/convert/pdf/pdfa}">
|
<form method="post" enctype="multipart/form-data" th:action="@{api/v1/convert/pdf/pdfa}">
|
||||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
|
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label th:text="#{pdfToPDFA.outputFormat}"></label>
|
||||||
|
<select class="form-control" name="outputFormat">
|
||||||
|
<option value="pdfa-1">PDF/A-1b</option>
|
||||||
|
<option value="pdfa">PDF/A-2b</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
<br>
|
<br>
|
||||||
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{pdfToPDFA.submit}"></button>
|
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{pdfToPDFA.submit}"></button>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -19,14 +19,13 @@
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label th:text="#{PDFToText.selectText.1}"></label>
|
<label th:text="#{PDFToText.selectText.1}"></label>
|
||||||
<select class="form-control" name="outputFormat">
|
<select class="form-control" name="outputFormat">
|
||||||
<option value="rtf">RTF</option>
|
<option th:if="${@endpointConfiguration.isEndpointEnabled('pdf-to-rtf')}" value="rtf">RTF</option>
|
||||||
<option value="txt">TXT</option>
|
<option value="txt">TXT</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<br>
|
|
||||||
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{PDFToText.submit}"></button>
|
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{PDFToText.submit}"></button>
|
||||||
</form>
|
</form>
|
||||||
<p class="mt-3" th:text="#{PDFToText.credit}"></p>
|
<p th:if="${@endpointConfiguration.isEndpointEnabled('pdf-to-rtf')}" class="mt-3" th:text="#{PDFToText.credit}"></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -60,7 +60,7 @@
|
||||||
|
|
||||||
<!-- Help Modal -->
|
<!-- Help Modal -->
|
||||||
<link rel="stylesheet" href="css/errorBanner.css">
|
<link rel="stylesheet" href="css/errorBanner.css">
|
||||||
|
<script src="js/cacheFormInputs.js"></script>
|
||||||
<script src="js/tab-container.js"></script>
|
<script src="js/tab-container.js"></script>
|
||||||
<script src="js/darkmode.js"></script>
|
<script src="js/darkmode.js"></script>
|
||||||
</th:block>
|
</th:block>
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
<script th:inline="javascript">
|
<script th:inline="javascript">
|
||||||
const currentVersion = /*[[${@appVersion}]]*/ '';
|
const currentVersion = /*[[${@appVersion}]]*/ '';
|
||||||
const noFavourites = /*[[#{noFavourites}]]*/ '';
|
const noFavourites = /*[[#{noFavourites}]]*/ '';
|
||||||
|
const updateAvailable = /*[[#{settings.updateAvailable}]]*/ '';
|
||||||
</script>
|
</script>
|
||||||
<script th:src="@{js/githubVersion.js}"></script>
|
<script th:src="@{js/githubVersion.js}"></script>
|
||||||
<nav class="navbar navbar-expand-lg navbar-light bg-light">
|
<nav class="navbar navbar-expand-lg navbar-light bg-light">
|
||||||
|
@ -16,20 +17,20 @@
|
||||||
</button>
|
</button>
|
||||||
<div class="collapse navbar-collapse" id="navbarNav">
|
<div class="collapse navbar-collapse" id="navbarNav">
|
||||||
<ul class="navbar-nav me-auto flex-nowrap">
|
<ul class="navbar-nav me-auto flex-nowrap">
|
||||||
<li class="nav-item">
|
<li class="nav-item" th:if="${@endpointConfiguration.isEndpointEnabled('multi-tool')}">
|
||||||
<a class="nav-link" href="#" th:href="@{multi-tool}" th:classappend="${currentPage}=='multi-tool' ? 'active' : ''" th:title="#{home.multiTool.desc}">
|
<a class="nav-link" href="#" th:href="@{multi-tool}" th:classappend="${currentPage}=='multi-tool' ? 'active' : ''" th:title="#{home.multiTool.desc}">
|
||||||
<img class="icon" src="images/tools.svg" alt="icon">
|
<img class="icon" src="images/tools.svg" alt="icon">
|
||||||
<span class="icon-text" th:text="#{home.multiTool.title}"></span>
|
<span class="icon-text" th:text="#{home.multiTool.title}"></span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item nav-item-separator"></li>
|
<li th:if="${@endpointConfiguration.isEndpointEnabled('multi-tool')}" class="nav-item nav-item-separator"></li>
|
||||||
<li class="nav-item">
|
<li th:if="${@endpointConfiguration.isEndpointEnabled('pipeline')}" class="nav-item">
|
||||||
<a class="nav-link" href="#" th:href="@{pipeline}" th:classappend="${currentPage}=='pipeline' ? 'active' : ''" th:title="#{home.pipeline.desc}">
|
<a class="nav-link" href="#" th:href="@{pipeline}" th:classappend="${currentPage}=='pipeline' ? 'active' : ''" th:title="#{home.pipeline.desc}">
|
||||||
<img class="icon" src="images/pipeline.svg" alt="icon">
|
<img class="icon" src="images/pipeline.svg" alt="icon">
|
||||||
<span class="icon-text" th:text="#{home.pipeline.title}"></span>
|
<span class="icon-text" th:text="#{home.pipeline.title}"></span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item nav-item-separator"></li>
|
<li th:if="${@endpointConfiguration.isEndpointEnabled('pipeline')}" class="nav-item nav-item-separator"></li>
|
||||||
<li class="nav-item dropdown" th:classappend="${currentPage}=='remove-pages' OR ${currentPage}=='merge-pdfs' OR ${currentPage}=='split-pdfs' OR ${currentPage}=='crop' OR ${currentPage}=='adjust-contrast' OR ${currentPage}=='pdf-organizer' OR ${currentPage}=='rotate-pdf' OR ${currentPage}=='multi-page-layout' OR ${currentPage}=='scale-pages' OR ${currentPage}=='auto-split-pdf' OR ${currentPage}=='extract-page' OR ${currentPage}=='pdf-to-single-page' ? 'active' : ''">
|
<li class="nav-item dropdown" th:classappend="${currentPage}=='remove-pages' OR ${currentPage}=='merge-pdfs' OR ${currentPage}=='split-pdfs' OR ${currentPage}=='crop' OR ${currentPage}=='adjust-contrast' OR ${currentPage}=='pdf-organizer' OR ${currentPage}=='rotate-pdf' OR ${currentPage}=='multi-page-layout' OR ${currentPage}=='scale-pages' OR ${currentPage}=='auto-split-pdf' OR ${currentPage}=='extract-page' OR ${currentPage}=='pdf-to-single-page' ? 'active' : ''">
|
||||||
<a class="nav-link dropdown-toggle" id="navbarDropdown-1" href="#" role="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
<a class="nav-link dropdown-toggle" id="navbarDropdown-1" href="#" role="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||||
<img class="icon" src="images/file-earmark-pdf.svg" alt="icon">
|
<img class="icon" src="images/file-earmark-pdf.svg" alt="icon">
|
||||||
|
@ -194,7 +195,7 @@
|
||||||
<p class="mb-0" th:utext="#{settings.appVersion} + ' ' + ${@appVersion}"></p>
|
<p class="mb-0" th:utext="#{settings.appVersion} + ' ' + ${@appVersion}"></p>
|
||||||
<a href="https://github.com/sponsors/Frooodle" class="btn btn-sm btn-outline-primary" role="button" target="_blank" th:text="#{sponsor}+' Stirling-PDF'"></a>
|
<a href="https://github.com/sponsors/Frooodle" class="btn btn-sm btn-outline-primary" role="button" target="_blank" th:text="#{sponsor}+' Stirling-PDF'"></a>
|
||||||
<a href="swagger-ui/index.html" class="btn btn-sm btn-outline-primary" role="button" target="_blank">API</a>
|
<a href="swagger-ui/index.html" class="btn btn-sm btn-outline-primary" role="button" target="_blank">API</a>
|
||||||
<a href="https://github.com/Stirling-Tools/Stirling-PDF/releases" class="btn btn-sm btn-outline-primary" id="update-btn" th:utext="#{settings.update}" role="button" target="_blank"></a>
|
<a th:if="${@shouldShow}" href="https://github.com/Stirling-Tools/Stirling-PDF/releases" class="btn btn-sm btn-outline-primary" id="update-btn" th:utext="#{settings.update}" role="button" target="_blank" rel="noopener"></a>
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="downloadOption" th:utext="#{settings.downloadOption.title}"></label>
|
<label for="downloadOption" th:utext="#{settings.downloadOption.title}"></label>
|
||||||
|
@ -210,13 +211,17 @@
|
||||||
<span id="zipThresholdValue" class="ms-2"></span>
|
<span id="zipThresholdValue" class="ms-2"></span>
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-3 form-check">
|
<div class="mb-3 form-check">
|
||||||
<input type="checkbox" class="form-check-input" id="boredWaiting">
|
<input type="checkbox" class="form-check-input" id="boredWaiting" th:title="#{settings.bored.help}">
|
||||||
<label class="form-check-label" for="boredWaiting" th:text="#{bored}"></label>
|
<label class="form-check-label" for="boredWaiting" th:text="#{bored}"></label>
|
||||||
</div>
|
</div>
|
||||||
<a th:if="${@loginEnabled}" href="account" class="btn btn-sm btn-outline-primary" role="button" th:text="#{settings.accountSettings}" target="_blank">Account Settings</a>
|
<div class="mb-3 form-check">
|
||||||
|
<input type="checkbox" class="form-check-input" id="cacheInputs" th:title="#{settings.cacheInputs.help}">
|
||||||
|
<label class="form-check-label" for="cacheInputs" th:text="#{settings.cacheInputs.name}"></label>
|
||||||
|
</div>
|
||||||
|
<a th:if="${@loginEnabled and @activSecurity}" href="account" class="btn btn-sm btn-outline-primary" role="button" th:text="#{settings.accountSettings}" target="_blank">Account Settings</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<a th:if="${@loginEnabled}" class="btn btn-danger" role="button" th:text="#{settings.signOut}" href="logout">Sign Out</a>
|
<a th:if="${@loginEnabled and @activSecurity}" class="btn btn-danger" role="button" th:text="#{settings.signOut}" href="logout">Sign Out</a>
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal" th:text="#{close}"></button>
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal" th:text="#{close}"></button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -23,6 +23,15 @@
|
||||||
<br>
|
<br>
|
||||||
<input type="text" id="searchBar" onkeyup="filterCards()" th:placeholder="#{home.searchBar}" autofocus>
|
<input type="text" id="searchBar" onkeyup="filterCards()" th:placeholder="#{home.searchBar}" autofocus>
|
||||||
<div class="features-container">
|
<div class="features-container">
|
||||||
|
<div th:if="${@shouldShow}" class="feature-card favorite" id="update-link" style="display: none;">
|
||||||
|
<a href="https://github.com/Stirling-Tools/Stirling-PDF/releases" target="_blank" class="nav-link text-body-secondary px-2" rel="noopener">
|
||||||
|
<div class="d-flex align-items-center">
|
||||||
|
<img class="card-icon home-card-icon home-card-icon-colour" src="images/update.svg" alt="Icon" width="30" height="30">
|
||||||
|
<h5 class="card-title lookatme ms-2" th:text="#{settings.update}" th:data-lookatme-text="#{settings.update}"></h5>
|
||||||
|
</div>
|
||||||
|
<p class="card-text" id="app-update"></p>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
<div th:replace="~{fragments/card :: card(id='pipeline', cardTitle=#{home.pipeline.title}, cardText=#{home.pipeline.desc}, cardLink='pipeline', svgPath='images/pipeline.svg', tags=#{pipeline.tags})}"></div>
|
<div th:replace="~{fragments/card :: card(id='pipeline', cardTitle=#{home.pipeline.title}, cardText=#{home.pipeline.desc}, cardLink='pipeline', svgPath='images/pipeline.svg', tags=#{pipeline.tags})}"></div>
|
||||||
|
|
||||||
<div th:replace="~{fragments/card :: card(id='view-pdf', cardTitle=#{home.viewPdf.title}, cardText=#{home.viewPdf.desc}, cardLink='view-pdf', svgPath='images/book-opened.svg', tags=#{viewPdf.tags})}"></div>
|
<div th:replace="~{fragments/card :: card(id='view-pdf', cardTitle=#{home.viewPdf.title}, cardText=#{home.viewPdf.desc}, cardLink='view-pdf', svgPath='images/book-opened.svg', tags=#{viewPdf.tags})}"></div>
|
||||||
|
|
|
@ -52,7 +52,7 @@
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
|
||||||
const defaultLocale = document.documentElement.getAttribute('language') || 'en_GB';
|
const defaultLocale = document.documentElement.getAttribute('data-language') || 'en_GB';
|
||||||
const storedLocale = localStorage.getItem('languageCode') || defaultLocale;
|
const storedLocale = localStorage.getItem('languageCode') || defaultLocale;
|
||||||
|
|
||||||
const currentURL = new URL(window.location.href);
|
const currentURL = new URL(window.location.href);
|
||||||
|
@ -139,6 +139,13 @@
|
||||||
<form th:action="@{login}" method="post">
|
<form th:action="@{login}" method="post">
|
||||||
<img class="mb-4" src="favicon.svg?v=2" alt="" width="144" height="144">
|
<img class="mb-4" src="favicon.svg?v=2" alt="" width="144" height="144">
|
||||||
<h1 class="h1 mb-3 fw-normal" th:text="${@appName}">Stirling-PDF</h1>
|
<h1 class="h1 mb-3 fw-normal" th:text="${@appName}">Stirling-PDF</h1>
|
||||||
|
<div th:if="${oAuth2Enabled}">
|
||||||
|
<a href="oauth2/authorization/oidc" class="w-100 btn btn-lg btn-primary" th:text="#{login.ssoSignIn}">Login Via SSO</a>
|
||||||
|
<div class="text-danger text-center">
|
||||||
|
<div th:if="${error == 'oauth2AutoCreateDisabled'}" th:text="#{login.oauth2AutoCreateDisabled}">OAUTH2 Auto-Create User Disabled.</div>
|
||||||
|
</div>
|
||||||
|
<hr />
|
||||||
|
</div>
|
||||||
<h2 class="h5 mb-3 fw-normal" th:text="#{login.signinTitle}">Please sign in</h2>
|
<h2 class="h5 mb-3 fw-normal" th:text="#{login.signinTitle}">Please sign in</h2>
|
||||||
|
|
||||||
<div class="form-floating">
|
<div class="form-floating">
|
||||||
|
|
29
src/main/resources/templates/misc/fake-scan.html
Normal file
29
src/main/resources/templates/misc/fake-scan.html
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html th:lang="${#locale.language}" th:dir="#{language.direction}" th:data-language="${#locale.toString()}" xmlns:th="http://www.thymeleaf.org">
|
||||||
|
<head>
|
||||||
|
<th:block th:insert="~{fragments/common :: head(title=#{fakeScan.title}, header=#{fakeScan.header})}"></th:block>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<th:block th:insert="~{fragments/common :: game}"></th:block>
|
||||||
|
<div id="page-container">
|
||||||
|
<div id="content-wrap">
|
||||||
|
<th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
|
||||||
|
<br><br>
|
||||||
|
<div class="container">
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<h2 th:text="#{fakeScan.header}"></h2>
|
||||||
|
<form method="post" enctype="multipart/form-data" th:action="@{api/v1/misc/fake-scan}">
|
||||||
|
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
|
||||||
|
<br>
|
||||||
|
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{fakeScan.submit}"></button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
35
src/main/resources/templates/misc/print-file.html
Normal file
35
src/main/resources/templates/misc/print-file.html
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html th:lang="${#locale.language}" th:dir="#{language.direction}" th:data-language="${#locale.toString()}" xmlns:th="http://www.thymeleaf.org">
|
||||||
|
<head>
|
||||||
|
<th:block th:insert="~{fragments/common :: head(title=#{printFile.title}, header=#{printFile.header})}"></th:block>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<th:block th:insert="~{fragments/common :: game}"></th:block>
|
||||||
|
<div id="page-container">
|
||||||
|
<div id="content-wrap">
|
||||||
|
<th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
|
||||||
|
<br><br>
|
||||||
|
<div class="container">
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<h2 th:text="#{printFile.header}"></h2>
|
||||||
|
<form action="#" th:action="@{api/v1/misc/print-file}" method="post" enctype="multipart/form-data">
|
||||||
|
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf,image/*')}"></div>
|
||||||
|
<div class="card mb-3">
|
||||||
|
<div class="card-body">
|
||||||
|
<h4 th:text="#{printFile.selectText.1}">Select Printer</h4> <!-- Assuming the message code printFile.selectText.3 corresponds to "Select Printer" -->
|
||||||
|
<label for="printerName" th:text="#{printFile.selectText.2}">Printer Name:</label> <!-- Assuming the message code printFile.selectText.4 corresponds to "Printer Name:" -->
|
||||||
|
<input type="text" name="printerName" id="printerName" class="form-control">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{printFile.submit}"></button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
8
test.sh
8
test.sh
|
@ -78,8 +78,8 @@ main() {
|
||||||
|
|
||||||
|
|
||||||
# Building Docker images
|
# Building Docker images
|
||||||
docker build --build-arg VERSION_TAG=alpha -t frooodle/s-pdf:latest -f ./Dockerfile .
|
docker build --no-cache --build-arg VERSION_TAG=alpha -t frooodle/s-pdf:latest -f ./Dockerfile .
|
||||||
docker build --build-arg VERSION_TAG=alpha -t frooodle/s-pdf:latest-ultra-lite -f ./Dockerfile-ultra-lite .
|
docker build --no-cache --build-arg VERSION_TAG=alpha -t frooodle/s-pdf:latest-ultra-lite -f ./Dockerfile-ultra-lite .
|
||||||
|
|
||||||
# Test each configuration
|
# Test each configuration
|
||||||
run_tests "Stirling-PDF-Ultra-Lite" "./exampleYmlFiles/docker-compose-latest-ultra-lite.yml"
|
run_tests "Stirling-PDF-Ultra-Lite" "./exampleYmlFiles/docker-compose-latest-ultra-lite.yml"
|
||||||
|
@ -94,8 +94,8 @@ main() {
|
||||||
|
|
||||||
|
|
||||||
# Building Docker images with security enabled
|
# Building Docker images with security enabled
|
||||||
docker build --build-arg VERSION_TAG=alpha -t frooodle/s-pdf:latest -f ./Dockerfile .
|
docker build --no-cache --build-arg VERSION_TAG=alpha -t frooodle/s-pdf:latest -f ./Dockerfile .
|
||||||
docker build --build-arg VERSION_TAG=alpha -t frooodle/s-pdf:latest-ultra-lite -f ./Dockerfile-ultra-lite .
|
docker build --no-cache --build-arg VERSION_TAG=alpha -t frooodle/s-pdf:latest-ultra-lite -f ./Dockerfile-ultra-lite .
|
||||||
|
|
||||||
# Test each configuration with security
|
# Test each configuration with security
|
||||||
run_tests "Stirling-PDF-Ultra-Lite-Security" "./exampleYmlFiles/docker-compose-latest-ultra-lite-security.yml"
|
run_tests "Stirling-PDF-Ultra-Lite-Security" "./exampleYmlFiles/docker-compose-latest-ultra-lite-security.yml"
|
||||||
|
|
Loading…
Reference in a new issue