Compare commits

..

2 Commits

Author SHA1 Message Date
Anthony Stirling
94df4c7067 add comment 2025-01-15 23:25:00 +00:00
Anthony Stirling
481fdd60bf verify 2025-01-15 22:33:40 +00:00
125 changed files with 4925 additions and 11767 deletions

View File

@@ -1,34 +1,15 @@
# Description of Changes # Description
Please provide a summary of the changes, including: Please provide a summary of the changes, including relevant motivation and context.
- What was changed
- Why the change was made
- Any challenges encountered
Closes #(issue_number) Closes #(issue_number)
---
## Checklist ## Checklist
### General
- [ ] I have read the [Contribution Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md) - [ ] I have read the [Contribution Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
- [ ] I have read the [Stirling-PDF Developer Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DeveloperGuide.md) (if applicable)
- [ ] I have read the [How to add new languages to Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/HowToAddNewLanguage.md) (if applicable)
- [ ] I have performed a self-review of my own code - [ ] I have performed a self-review of my own code
- [ ] I have attached images of the change if it is UI based
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] If my code has heavily changed functionality I have updated relevant docs on [Stirling-PDFs doc repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/)
- [ ] My changes generate no new warnings - [ ] My changes generate no new warnings
### Documentation
- [ ] I have updated relevant docs on [Stirling-PDF's doc repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/) (if functionality has heavily changed)
- [ ] I have read the section [Add New Translation Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/HowToAddNewLanguage.md#add-new-translation-tags) (for new translation tags only) - [ ] I have read the section [Add New Translation Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/HowToAddNewLanguage.md#add-new-translation-tags) (for new translation tags only)
### UI Changes (if applicable)
- [ ] Screenshots or videos demonstrating the UI changes are attached (e.g., as comments or direct attachments in the PR)
### Testing (if applicable)
- [ ] I have tested my changes locally. Refer to the [Testing Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DeveloperGuide.md#6-testing) for more details.

51
.github/scripts/check_duplicates.py vendored Normal file
View File

@@ -0,0 +1,51 @@
import sys
def find_duplicate_keys(file_path):
"""
Finds duplicate keys in a properties file and returns their occurrences.
This function reads a properties file, identifies any keys that occur more than
once, and returns a dictionary with these keys and the line numbers of their occurrences.
Parameters:
file_path (str): The path to the properties file to be checked.
Returns:
dict: A dictionary where each key is a duplicated key in the file, and the value is a list
of line numbers where the key occurs.
"""
with open(file_path, "r", encoding="utf-8") as file:
lines = file.readlines()
keys = {}
duplicates = {}
for line_number, line in enumerate(lines, start=1):
line = line.strip()
if line and not line.startswith("#") and "=" in line:
key = line.split("=", 1)[0].strip()
if key in keys:
# If the key already exists, add the current line number
duplicates.setdefault(key, []).append(line_number)
# Also add the first instance of the key if not already done
if keys[key] not in duplicates[key]:
duplicates[key].insert(0, keys[key])
else:
# Store the line number of the first instance of the key
keys[key] = line_number
return duplicates
if __name__ == "__main__":
failed = False
for ar in sys.argv[1:]:
duplicates = find_duplicate_keys(ar)
if duplicates:
for key, lines in duplicates.items():
lines_str = ", ".join(map(str, lines))
print(f"{key} duplicated in {ar} on lines {lines_str}")
failed = True
if failed:
sys.exit(1)

View File

@@ -11,8 +11,6 @@ adjusting the format.
Usage: Usage:
python check_language_properties.py --reference-file <path_to_reference_file> --branch <branch_name> [--actor <actor_name>] [--files <list_of_changed_files>] python check_language_properties.py --reference-file <path_to_reference_file> --branch <branch_name> [--actor <actor_name>] [--files <list_of_changed_files>]
""" """
# Sample for Windows:
# python .github/scripts/check_language_properties.py --reference-file src\main\resources\messages_en_GB.properties --branch "" --files src\main\resources\messages_de_DE.properties src\main\resources\messages_uk_UA.properties
import copy import copy
import glob import glob
@@ -21,60 +19,25 @@ import argparse
import re import re
def find_duplicate_keys(file_path):
"""
Identifies duplicate keys in a .properties file.
:param file_path: Path to the .properties file.
:return: List of tuples (key, first_occurrence_line, duplicate_line).
"""
keys = {}
duplicates = []
with open(file_path, "r", encoding="utf-8") as file:
for line_number, line in enumerate(file, start=1):
stripped_line = line.strip()
# Skip empty lines and comments
if not stripped_line or stripped_line.startswith("#"):
continue
# Split the line into key and value
if "=" in stripped_line:
key, _ = stripped_line.split("=", 1)
key = key.strip()
# Check if the key already exists
if key in keys:
duplicates.append((key, keys[key], line_number))
else:
keys[key] = line_number
return duplicates
# Maximum size for properties files (e.g., 200 KB) # Maximum size for properties files (e.g., 200 KB)
MAX_FILE_SIZE = 200 * 1024 MAX_FILE_SIZE = 200 * 1024
def parse_properties_file(file_path): def parse_properties_file(file_path):
""" """Parses a .properties file and returns a list of objects (including comments, empty lines, and line numbers)."""
Parses a .properties file and returns a structured list of its contents.
:param file_path: Path to the .properties file.
:return: List of dictionaries representing each line in the file.
"""
properties_list = [] properties_list = []
with open(file_path, "r", encoding="utf-8") as file: with open(file_path, "r", encoding="utf-8") as file:
for line_number, line in enumerate(file, start=1): for line_number, line in enumerate(file, start=1):
stripped_line = line.strip() stripped_line = line.strip()
# Handle empty lines # Empty lines
if not stripped_line: if not stripped_line:
properties_list.append( properties_list.append(
{"line_number": line_number, "type": "empty", "content": ""} {"line_number": line_number, "type": "empty", "content": ""}
) )
continue continue
# Handle comments # Comments
if stripped_line.startswith("#"): if stripped_line.startswith("#"):
properties_list.append( properties_list.append(
{ {
@@ -85,7 +48,7 @@ def parse_properties_file(file_path):
) )
continue continue
# Handle key-value pairs # Key-value pairs
match = re.match(r"^([^=]+)=(.*)$", line) match = re.match(r"^([^=]+)=(.*)$", line)
if match: if match:
key, value = match.groups() key, value = match.groups()
@@ -102,14 +65,9 @@ def parse_properties_file(file_path):
def write_json_file(file_path, updated_properties): def write_json_file(file_path, updated_properties):
"""
Writes updated properties back to the file in their original format.
:param file_path: Path to the .properties file.
:param updated_properties: List of updated properties to write.
"""
updated_lines = {entry["line_number"]: entry for entry in updated_properties} updated_lines = {entry["line_number"]: entry for entry in updated_properties}
# Sort lines by their numbers and retain comments and empty lines # Sort by line numbers and retain comments and empty lines
all_lines = sorted(set(updated_lines.keys())) all_lines = sorted(set(updated_lines.keys()))
original_format = [] original_format = []
@@ -128,8 +86,8 @@ def write_json_file(file_path, updated_properties):
# Replace entries with those from the current JSON # Replace entries with those from the current JSON
original_format.append(entry) original_format.append(entry)
# Write the updated content back to the file # Write back in the original format
with open(file_path, "w", encoding="utf-8", newline="\n") as file: with open(file_path, "w", encoding="utf-8") as file:
for entry in original_format: for entry in original_format:
if entry["type"] == "comment": if entry["type"] == "comment":
file.write(f"{entry['content']}\n") file.write(f"{entry['content']}\n")
@@ -140,12 +98,6 @@ def write_json_file(file_path, updated_properties):
def update_missing_keys(reference_file, file_list, branch=""): def update_missing_keys(reference_file, file_list, branch=""):
"""
Updates missing keys in the translation files based on the reference file.
:param reference_file: Path to the reference .properties file.
:param file_list: List of translation files to update.
:param branch: Branch where the files are located.
"""
reference_properties = parse_properties_file(reference_file) reference_properties = parse_properties_file(reference_file)
for file_path in file_list: for file_path in file_list:
basename_current_file = os.path.basename(os.path.join(branch, file_path)) basename_current_file = os.path.basename(os.path.join(branch, file_path))
@@ -212,14 +164,8 @@ def check_for_differences(reference_file, file_list, branch, actor):
basename_current_file = os.path.basename(os.path.join(branch, file_path)) basename_current_file = os.path.basename(os.path.join(branch, file_path))
if ( if (
basename_current_file == basename_reference_file basename_current_file == basename_reference_file
or ( or not file_path.startswith(
# only local windows command os.path.join("src", "main", "resources", "messages_")
not file_path.startswith(
os.path.join("", "src", "main", "resources", "messages_")
)
and not file_path.startswith(
os.path.join(os.getcwd(), "src", "main", "resources", "messages_")
)
) )
or not file_path.endswith(".properties") or not file_path.endswith(".properties")
or not basename_current_file.startswith("messages_") or not basename_current_file.startswith("messages_")
@@ -291,24 +237,6 @@ def check_for_differences(reference_file, file_list, branch, actor):
) )
else: else:
report.append("2. **Test Status:** ✅ **_Passed_**") report.append("2. **Test Status:** ✅ **_Passed_**")
if find_duplicate_keys(os.path.join(branch, file_path)):
has_differences = True
output = "\n".join(
[
f" - `{key}`: first at line {first}, duplicate at `line {duplicate}`"
for key, first, duplicate in find_duplicate_keys(
os.path.join(branch, file_path)
)
]
)
report.append("3. **Test Status:** ❌ **_Failed_**")
report.append(" - **Issue:**")
report.append(" - duplicate entries were found:")
report.append(output)
else:
report.append("3. **Test Status:** ✅ **_Passed_**")
report.append("") report.append("")
report.append("---") report.append("---")
report.append("") report.append("")
@@ -347,12 +275,6 @@ if __name__ == "__main__":
required=True, required=True,
help="Branch name.", help="Branch name.",
) )
parser.add_argument(
"--check-file",
type=str,
required=False,
help="List of changed files, separated by spaces.",
)
parser.add_argument( parser.add_argument(
"--files", "--files",
nargs="+", nargs="+",
@@ -371,14 +293,11 @@ if __name__ == "__main__":
file_list = args.files file_list = args.files
if file_list is None: if file_list is None:
if args.check_file: file_list = glob.glob(
file_list = [args.check_file] os.path.join(
else: os.getcwd(), "src", "main", "resources", "messages_*.properties"
file_list = glob.glob(
os.path.join(
os.getcwd(), "src", "main", "resources", "messages_*.properties"
)
) )
)
update_missing_keys(args.reference_file, file_list) update_missing_keys(args.reference_file, file_list)
else: else:
check_for_differences(args.reference_file, file_list, args.branch, args.actor) check_for_differences(args.reference_file, file_list, args.branch, args.actor)

85
.github/scripts/check_tabulator.py vendored Normal file
View File

@@ -0,0 +1,85 @@
"""check_tabulator.py"""
import argparse
import sys
def check_tabs(file_path):
"""
Checks for tabs in the specified file.
Args:
file_path (str): The path to the file to be checked.
Returns:
bool: True if tabs are found, False otherwise.
"""
with open(file_path, "r", encoding="utf-8") as file:
content = file.read()
if "\t" in content:
print(f"Tab found in {file_path}")
return True
return False
def replace_tabs_with_spaces(file_path, replace_with=" "):
"""
Replaces tabs with a specified number of spaces in the file.
Args:
file_path (str): The path to the file where tabs will be replaced.
replace_with (str): The character(s) to replace tabs with. Defaults to two spaces.
"""
with open(file_path, "r", encoding="utf-8") as file:
content = file.read()
updated_content = content.replace("\t", replace_with)
with open(file_path, "w", encoding="utf-8") as file:
file.write(updated_content)
def main():
"""
Main function to replace tabs with spaces in the provided files.
The replacement character and files to check are taken from command line arguments.
"""
# Create ArgumentParser instance
parser = argparse.ArgumentParser(
description="Replace tabs in files with specified characters."
)
# Define optional argument `--replace_with`
parser.add_argument(
"--replace_with",
default=" ",
help="Character(s) to replace tabs with. Default is two spaces.",
)
# Define argument for file paths
parser.add_argument("files", metavar="FILE", nargs="+", help="Files to process.")
# Parse arguments
args = parser.parse_args()
# Extract replacement characters and files from the parsed arguments
replace_with = args.replace_with
files_checked = args.files
error = False
for file_path in files_checked:
if check_tabs(file_path):
replace_tabs_with_spaces(file_path, replace_with)
error = True
if error:
print("Error: Originally found tabs in HTML files, now replaced.")
sys.exit(1)
sys.exit(0)
if __name__ == "__main__":
main()

View File

@@ -36,7 +36,7 @@ jobs:
steps: steps:
- name: Harden Runner - name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 uses: step-security/harden-runner@c95a14d0e5bab51a9f56296a4eb0e416910cd350 # v2.10.3
with: with:
egress-policy: audit egress-policy: audit
@@ -81,7 +81,7 @@ jobs:
steps: steps:
- name: Harden Runner - name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 uses: step-security/harden-runner@c95a14d0e5bab51a9f56296a4eb0e416910cd350 # v2.10.3
with: with:
egress-policy: audit egress-policy: audit
@@ -119,7 +119,7 @@ jobs:
password: ${{ secrets.DOCKER_HUB_API }} password: ${{ secrets.DOCKER_HUB_API }}
- name: Build and push PR-specific image - name: Build and push PR-specific image
uses: docker/build-push-action@67a2d409c0a876cbe6b11854e3e25193efe4e62d # v6.12.0 uses: docker/build-push-action@b32b51a8eda65d6793cd0494a773d4f6bcef32dc # v6.11.0
with: with:
context: . context: .
file: ./Dockerfile file: ./Dockerfile

View File

@@ -21,7 +21,7 @@ jobs:
steps: steps:
- name: Harden Runner - name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 uses: step-security/harden-runner@c95a14d0e5bab51a9f56296a4eb0e416910cd350 # v2.10.3
with: with:
egress-policy: audit egress-policy: audit

View File

@@ -13,7 +13,7 @@ jobs:
pull-requests: write pull-requests: write
steps: steps:
- name: Harden Runner - name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 uses: step-security/harden-runner@c95a14d0e5bab51a9f56296a4eb0e416910cd350 # v2.10.3
with: with:
egress-policy: audit egress-policy: audit

View File

@@ -24,7 +24,7 @@ jobs:
steps: steps:
- name: Harden Runner - name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 uses: step-security/harden-runner@c95a14d0e5bab51a9f56296a4eb0e416910cd350 # v2.10.3
with: with:
egress-policy: audit egress-policy: audit
@@ -37,12 +37,6 @@ jobs:
java-version: ${{ matrix.jdk-version }} java-version: ${{ matrix.jdk-version }}
distribution: "temurin" distribution: "temurin"
- name: PR | Generate verification metadata with signatures and checksums for dependabot[bot]
if: github.event.pull_request.user.login == 'dependabot[bot]'
run: |
./gradlew clean dependencies buildEnvironment spotlessApply --write-verification-metadata sha256 --refresh-dependencies help
./gradlew clean dependencies buildEnvironment spotlessApply --write-verification-metadata sha256,pgp --refresh-keys --export-keys --refresh-dependencies help
- name: Build with Gradle and no spring security - name: Build with Gradle and no spring security
run: ./gradlew clean build run: ./gradlew clean build
env: env:
@@ -83,7 +77,7 @@ jobs:
steps: steps:
- name: Harden Runner - name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 uses: step-security/harden-runner@c95a14d0e5bab51a9f56296a4eb0e416910cd350 # v2.10.3
with: with:
egress-policy: audit egress-policy: audit
@@ -101,21 +95,20 @@ jobs:
- name: Install Docker Compose - name: Install Docker Compose
run: | run: |
sudo curl -SL "https://github.com/docker/compose/releases/download/v2.32.4/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose sudo curl -SL "https://github.com/docker/compose/releases/download/v2.32.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: Set up Python - name: Set up Python
uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0 uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0
with: with:
python-version: "3.12" python-version: "3.12"
cache: 'pip' # caching pip dependencies
- name: Pip requirements - name: Pip requirements
run: | run: |
pip install --require-hashes -r ./testing/cucumber/requirements.txt pip install --require-hashes -r ./cucumber/requirements.txt
- name: Run Docker Compose Tests - name: Run Docker Compose Tests
run: | run: |
chmod +x ./testing/test_webpages.sh chmod +x ./cucumber/test_webpages.sh
chmod +x ./testing/test.sh chmod +x ./test.sh
./testing/test.sh "${{ github.event.pull_request.user.login == 'dependabot[bot]' }}" ./test.sh

View File

@@ -18,7 +18,7 @@ jobs:
pull-requests: write pull-requests: write
steps: steps:
- name: Harden Runner - name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 uses: step-security/harden-runner@c95a14d0e5bab51a9f56296a4eb0e416910cd350 # v2.10.3
with: with:
egress-policy: audit egress-policy: audit
@@ -58,7 +58,7 @@ jobs:
run: | run: |
echo "Fetching PR changed files..." echo "Fetching PR changed files..."
echo "Getting list of changed files from PR..." echo "Getting list of changed files from PR..."
gh pr view ${{ steps.get-pr-data.outputs.pr_number }} --json files -q ".files[].path" | grep -E '^src/main/resources/messages_[a-zA-Z_]{2}_[a-zA-Z_]{2,7}\.properties$' > changed_files.txt # Filter only matching property files gh pr view ${{ steps.get-pr-data.outputs.pr_number }} --json files -q ".files[].path" | grep -E '^src/main/resources/messages_[a-zA-Z_]+\.properties$' > changed_files.txt # Filter only matching property files
- name: Determine reference file test - name: Determine reference file test
id: determine-file id: determine-file
@@ -99,7 +99,7 @@ jobs:
// Filter for relevant files based on the PR changes // Filter for relevant files based on the PR changes
const changedFiles = files const changedFiles = files
.map(file => file.filename) .map(file => file.filename)
.filter(file => /^src\/main\/resources\/messages_[a-zA-Z_]{2}_[a-zA-Z_]{2,7}\.properties$/.test(file)); .filter(file => /^src\/main\/resources\/messages_[a-zA-Z_]+\.properties$/.test(file));
console.log("Changed files:", changedFiles); console.log("Changed files:", changedFiles);

View File

@@ -17,7 +17,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Harden Runner - name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 uses: step-security/harden-runner@c95a14d0e5bab51a9f56296a4eb0e416910cd350 # v2.10.3
with: with:
egress-policy: audit egress-policy: audit

View File

@@ -18,7 +18,7 @@ jobs:
pull-requests: write pull-requests: write
steps: steps:
- name: Harden Runner - name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 uses: step-security/harden-runner@c95a14d0e5bab51a9f56296a4eb0e416910cd350 # v2.10.3
with: with:
egress-policy: audit egress-policy: audit

View File

@@ -15,7 +15,7 @@ jobs:
issues: write issues: write
steps: steps:
- name: Harden Runner - name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 uses: step-security/harden-runner@c95a14d0e5bab51a9f56296a4eb0e416910cd350 # v2.10.3
with: with:
egress-policy: audit egress-policy: audit

View File

@@ -16,7 +16,7 @@ jobs:
versionMac: ${{ steps.versionNumberMac.outputs.versionNumberMac }} versionMac: ${{ steps.versionNumberMac.outputs.versionNumberMac }}
steps: steps:
- name: Harden Runner - name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 uses: step-security/harden-runner@c95a14d0e5bab51a9f56296a4eb0e416910cd350 # v2.10.3
with: with:
egress-policy: audit egress-policy: audit
@@ -51,7 +51,7 @@ jobs:
file_suffix: "" file_suffix: ""
steps: steps:
- name: Harden Runner - name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 uses: step-security/harden-runner@c95a14d0e5bab51a9f56296a4eb0e416910cd350 # v2.10.3
with: with:
egress-policy: audit egress-policy: audit
@@ -101,7 +101,7 @@ jobs:
file_suffix: "" file_suffix: ""
steps: steps:
- name: Harden Runner - name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 uses: step-security/harden-runner@c95a14d0e5bab51a9f56296a4eb0e416910cd350 # v2.10.3
with: with:
egress-policy: audit egress-policy: audit
@@ -130,8 +130,8 @@ jobs:
include: include:
- os: windows-latest - os: windows-latest
platform: win- platform: win-
- os: macos-latest # - os: macos-latest
platform: mac- # platform: mac-
# - os: ubuntu-latest # - os: ubuntu-latest
# platform: linux- # platform: linux-
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
@@ -139,7 +139,7 @@ jobs:
contents: write contents: write
steps: steps:
- name: Harden Runner - name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 uses: step-security/harden-runner@c95a14d0e5bab51a9f56296a4eb0e416910cd350 # v2.10.3
with: with:
egress-policy: audit egress-policy: audit
@@ -168,7 +168,6 @@ jobs:
env: env:
DOCKER_ENABLE_SECURITY: false DOCKER_ENABLE_SECURITY: false
STIRLING_PDF_DESKTOP_UI: true STIRLING_PDF_DESKTOP_UI: true
BROWSER_OPEN: true
# Rename and collect artifacts based on OS # Rename and collect artifacts based on OS
- name: Prepare artifacts - name: Prepare artifacts
@@ -203,14 +202,14 @@ jobs:
include: include:
- os: windows-latest - os: windows-latest
platform: win- platform: win-
- os: macos-latest # - os: macos-latest
platform: mac- # platform: mac-
# - os: ubuntu-latest # - os: ubuntu-latest
# platform: linux- # platform: linux-
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Harden Runner - name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 uses: step-security/harden-runner@c95a14d0e5bab51a9f56296a4eb0e416910cd350 # v2.10.3
with: with:
egress-policy: audit egress-policy: audit
@@ -271,7 +270,7 @@ jobs:
contents: write contents: write
steps: steps:
- name: Harden Runner - name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 uses: step-security/harden-runner@c95a14d0e5bab51a9f56296a4eb0e416910cd350 # v2.10.3
with: with:
egress-policy: audit egress-policy: audit

View File

@@ -2,41 +2,23 @@ name: Pre-commit
on: on:
workflow_dispatch: workflow_dispatch:
schedule:
- cron: "0 0 * * 1"
permissions: permissions:
contents: read contents: read
jobs: jobs:
pre-commit: pre-commit:
if: ${{ github.event.pull_request.user.login != 'dependabot[bot]' }}
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions: permissions:
contents: write contents: write
pull-requests: write pull-requests: write
steps: steps:
- name: Harden Runner - name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 uses: step-security/harden-runner@c95a14d0e5bab51a9f56296a4eb0e416910cd350 # v2.10.3
with: with:
egress-policy: audit egress-policy: audit
- name: Generate GitHub App Token
id: generate-token
uses: actions/create-github-app-token@c1a285145b9d317df6ced56c09f525b5c2b6f755 # v1.11.1
with:
app-id: ${{ secrets.GH_APP_ID }}
private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}
- name: Get GitHub App User ID
id: get-user-id
run: echo "user-id=$(gh api "/users/${{ steps.generate-token.outputs.app-slug }}[bot]" --jq .id)" >> $GITHUB_OUTPUT
env:
GH_TOKEN: ${{ steps.generate-token.outputs.token }}
- id: committer
run: |
echo "string=${{ steps.generate-token.outputs.app-slug }}[bot] <${{ steps.get-user-id.outputs.user-id }}+${{ steps.generate-token.outputs.app-slug }}[bot]@users.noreply.github.com>" >> "$GITHUB_OUTPUT"
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with: with:
@@ -45,7 +27,6 @@ jobs:
uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0 uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0
with: with:
python-version: 3.12 python-version: 3.12
cache: 'pip' # caching pip dependencies
- name: Run Pre-Commit Hooks - name: Run Pre-Commit Hooks
run: | run: |
pip install --require-hashes -r ./.github/scripts/requirements_pre_commit.txt pip install --require-hashes -r ./.github/scripts/requirements_pre_commit.txt
@@ -53,25 +34,25 @@ jobs:
continue-on-error: true continue-on-error: true
- name: Set up git config - name: Set up git config
run: | run: |
git config --global user.name ${{ steps.generate-token.outputs.app-slug }}[bot] git config --global user.name "github-actions[bot]"
git config --global user.email "${{ steps.get-user-id.outputs.user-id }}+${{ steps.generate-token.outputs.app-slug }}[bot]@users.noreply.github.com" git config --global user.email "github-actions[bot]@users.noreply.github.com"
- name: git add - name: git add
run: | run: |
git add . git add .
git diff --staged --quiet || echo "CHANGES_DETECTED=true" >> $GITHUB_ENV git diff --staged --quiet || git commit -m ":file_folder: pre-commit
> Made via .github/workflows/pre_commit.yml" || echo "pre-commit: no changes"
- name: Create Pull Request - name: Create Pull Request
if: env.CHANGES_DETECTED == 'true'
uses: peter-evans/create-pull-request@67ccf781d68cd99b580ae25a5c18a1cc84ffff1f # v7.0.6 uses: peter-evans/create-pull-request@67ccf781d68cd99b580ae25a5c18a1cc84ffff1f # v7.0.6
with: with:
token: ${{ steps.generate-token.outputs.token }} token: ${{ secrets.GITHUB_TOKEN }}
commit-message: ":file_folder: pre-commit" commit-message: "ci: 🤖 format everything with pre-commit"
committer: ${{ steps.committer.outputs.string }} committer: GitHub Action <action@github.com>
author: ${{ steps.committer.outputs.string }} author: GitHub Action <action@github.com>
signoff: true signoff: true
branch: pre-commit branch: pre-commit
title: "🤖 format everything with pre-commit by <${{ steps.generate-token.outputs.app-slug }}>" title: "🤖 format everything with pre-commit by <github-actions[bot]>"
body: | body: |
Auto-generated by [create-pull-request][1] with **${{ steps.generate-token.outputs.app-slug }}** Auto-generated by [create-pull-request][1]
[1]: https://github.com/peter-evans/create-pull-request [1]: https://github.com/peter-evans/create-pull-request
draft: false draft: false

View File

@@ -18,7 +18,7 @@ jobs:
id-token: write id-token: write
steps: steps:
- name: Harden Runner - name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 uses: step-security/harden-runner@c95a14d0e5bab51a9f56296a4eb0e416910cd350 # v2.10.3
with: with:
egress-policy: audit egress-policy: audit
@@ -89,7 +89,7 @@ jobs:
- name: Build and push main Dockerfile - name: Build and push main Dockerfile
id: build-push-regular id: build-push-regular
uses: docker/build-push-action@67a2d409c0a876cbe6b11854e3e25193efe4e62d # v6.12.0 uses: docker/build-push-action@b32b51a8eda65d6793cd0494a773d4f6bcef32dc # v6.11.0
with: with:
builder: ${{ steps.buildx.outputs.name }} builder: ${{ steps.buildx.outputs.name }}
context: . context: .
@@ -134,7 +134,7 @@ jobs:
- name: Build and push Dockerfile-ultra-lite - name: Build and push Dockerfile-ultra-lite
id: build-push-lite id: build-push-lite
uses: docker/build-push-action@67a2d409c0a876cbe6b11854e3e25193efe4e62d # v6.12.0 uses: docker/build-push-action@b32b51a8eda65d6793cd0494a773d4f6bcef32dc # v6.11.0
if: github.ref != 'refs/heads/main' if: github.ref != 'refs/heads/main'
with: with:
context: . context: .
@@ -165,7 +165,7 @@ jobs:
- name: Build and push main Dockerfile fat - name: Build and push main Dockerfile fat
id: build-push-fat id: build-push-fat
uses: docker/build-push-action@67a2d409c0a876cbe6b11854e3e25193efe4e62d # v6.12.0 uses: docker/build-push-action@b32b51a8eda65d6793cd0494a773d4f6bcef32dc # v6.11.0
if: github.ref != 'refs/heads/main' if: github.ref != 'refs/heads/main'
with: with:
builder: ${{ steps.buildx.outputs.name }} builder: ${{ steps.buildx.outputs.name }}

View File

@@ -23,7 +23,7 @@ jobs:
version: ${{ steps.versionNumber.outputs.versionNumber }} version: ${{ steps.versionNumber.outputs.versionNumber }}
steps: steps:
- name: Harden Runner - name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 uses: step-security/harden-runner@c95a14d0e5bab51a9f56296a4eb0e416910cd350 # v2.10.3
with: with:
egress-policy: audit egress-policy: audit
@@ -83,7 +83,7 @@ jobs:
file_suffix: "" file_suffix: ""
steps: steps:
- name: Harden Runner - name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 uses: step-security/harden-runner@c95a14d0e5bab51a9f56296a4eb0e416910cd350 # v2.10.3
with: with:
egress-policy: audit egress-policy: audit
@@ -161,7 +161,7 @@ jobs:
file_suffix: "" file_suffix: ""
steps: steps:
- name: Harden Runner - name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 uses: step-security/harden-runner@c95a14d0e5bab51a9f56296a4eb0e416910cd350 # v2.10.3
with: with:
egress-policy: audit egress-policy: audit

View File

@@ -34,7 +34,7 @@ jobs:
steps: steps:
- name: Harden Runner - name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 uses: step-security/harden-runner@c95a14d0e5bab51a9f56296a4eb0e416910cd350 # v2.10.3
with: with:
egress-policy: audit egress-policy: audit

View File

@@ -16,7 +16,7 @@ jobs:
pull-requests: write pull-requests: write
steps: steps:
- name: Harden Runner - name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 uses: step-security/harden-runner@c95a14d0e5bab51a9f56296a4eb0e416910cd350 # v2.10.3
with: with:
egress-policy: audit egress-policy: audit

View File

@@ -14,7 +14,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Harden Runner - name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 uses: step-security/harden-runner@c95a14d0e5bab51a9f56296a4eb0e416910cd350 # v2.10.3
with: with:
egress-policy: audit egress-policy: audit

View File

@@ -1,170 +1,62 @@
name: Sync Files name: Sync Files
on: on:
workflow_dispatch:
push: push:
branches: branches:
- main - main
paths: paths:
- "build.gradle" - "build.gradle"
- "README.md"
- "gradle/verification-keyring.keys"
- "gradle/verification-metadata.xml"
- "src/main/resources/messages_*.properties" - "src/main/resources/messages_*.properties"
- "src/main/resources/static/3rdPartyLicenses.json"
- "scripts/ignore_translation.toml" - "scripts/ignore_translation.toml"
permissions: permissions:
contents: read contents: read
jobs: jobs:
read_bot_entries: sync-readme:
runs-on: ubuntu-latest runs-on: ubuntu-latest
outputs: permissions:
userName: ${{ steps.get-user-id.outputs.user_name }} contents: write
userEmail: ${{ steps.get-user-id.outputs.user_email }} pull-requests: write
committer: ${{ steps.committer.outputs.committer }}
steps: steps:
- name: Harden Runner - name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 uses: step-security/harden-runner@c95a14d0e5bab51a9f56296a4eb0e416910cd350 # v2.10.3
with: with:
egress-policy: audit egress-policy: audit
- name: Generate GitHub App Token
id: generate-token
uses: actions/create-github-app-token@c1a285145b9d317df6ced56c09f525b5c2b6f755 # v1.11.1
with:
app-id: ${{ secrets.GH_APP_ID }}
private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}
- name: Get GitHub App User ID
id: get-user-id
run: |
USER_NAME="${{ steps.generate-token.outputs.app-slug }}[bot]"
USER_ID=$(gh api "/users/$USER_NAME" --jq .id)
USER_EMAIL="$USER_ID+$USER_NAME@users.noreply.github.com"
echo "user_name=$USER_NAME" >> "$GITHUB_OUTPUT"
echo "user_email=$USER_EMAIL" >> "$GITHUB_OUTPUT"
echo "user-id=$USER_ID" >> "$GITHUB_OUTPUT"
env:
GH_TOKEN: ${{ steps.generate-token.outputs.token }}
- id: committer
run: |
COMMITTER="${{ steps.get-user-id.outputs.user_name }} <${{ steps.get-user-id.outputs.user_email }}>"
echo "committer=$COMMITTER" >> "$GITHUB_OUTPUT"
sync-files:
needs: ["read_bot_entries"]
runs-on: ubuntu-latest
steps:
- name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
with:
egress-policy: audit
- name: Generate GitHub App Token
id: generate-token
uses: actions/create-github-app-token@c1a285145b9d317df6ced56c09f525b5c2b6f755 # v1.11.1
with:
app-id: ${{ vars.GH_APP_ID }}
private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Set up Python - name: Set up Python
uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0 uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0
with: with:
python-version: "3.12" python-version: "3.12"
cache: 'pip' # caching pip dependencies
- name: Sync translation property files
run: |
python .github/scripts/check_language_properties.py --reference-file "src/main/resources/messages_en_GB.properties" --branch main
- name: Set up git config
run: |
git config --global user.name ${{ needs.read_bot_entries.outputs.userName }}
git config --global user.email ${{ needs.read_bot_entries.outputs.userEmail }}
- name: Run git add
run: |
git add src/main/resources/messages_*.properties
git diff --staged --quiet || git commit -m ":memo: Sync translation files" || echo "no changes"
- name: Install dependencies - name: Install dependencies
run: pip install --require-hashes -r ./.github/scripts/requirements_sync_readme.txt run: pip install --require-hashes -r ./.github/scripts/requirements_sync_readme.txt
- name: Sync README
- name: Sync README.md run: python scripts/counter_translation.py
- name: Set up git config
run: | run: |
python scripts/counter_translation.py git config --global user.name "github-actions[bot]"
git config --global user.email "github-actions[bot]@users.noreply.github.com"
- name: Run git add - name: Run git add
run: | run: |
git add README.md git add .
git diff --staged --quiet || git commit -m ":memo: Sync README.md" || echo "no changes" git diff --staged --quiet || git commit -m ":memo: Sync README
> Made via sync_files.yml" || echo "no changes"
- name: Generate verification metadata with signatures and checksums
run: |
set -e
if [ -f ./gradle/verification-metadata.xml ]; then
rm ./gradle/verification-metadata.xml
fi
./gradlew clean dependencies buildEnvironment spotlessApply --write-verification-metadata sha256 help
./gradlew clean dependencies buildEnvironment spotlessApply --write-verification-metadata sha256,pgp --refresh-keys --export-keys --refresh-dependencies help
./gradlew clean build
- name: Run git add
run: |
git add gradle/verification-keyring.keys
git add gradle/verification-metadata.xml
git diff --staged --quiet || git commit -m ":memo: Generate verification metadata with signatures and checksums" || echo "no changes"
- name: Create Pull Request - name: Create Pull Request
uses: peter-evans/create-pull-request@67ccf781d68cd99b580ae25a5c18a1cc84ffff1f # v7.0.6 uses: peter-evans/create-pull-request@67ccf781d68cd99b580ae25a5c18a1cc84ffff1f # v7.0.6
with: with:
token: ${{ steps.generate-token.outputs.token }} token: ${{ secrets.GITHUB_TOKEN }}
commit-message: Update files commit-message: Update files
committer: ${{ needs.read_bot_entries.outputs.committer }} committer: GitHub Action <action@github.com>
author: ${{ needs.read_bot_entries.outputs.committer }} author: GitHub Action <action@github.com>
signoff: true signoff: true
branch: sync_readme branch: sync_readme
title: ":globe_with_meridians: Sync Translations + Update README Progress Table + Update Verification Metadata" title: ":memo: Update README: Translation Progress Table"
body: | body: |
### Description of Changes Auto-generated by [create-pull-request][1]
This Pull Request was automatically generated to synchronize updates to translation files, verification metadata, and documentation. Below are the details of the changes made:
#### **1. Synchronization of Translation Files**
- Updated translation files (`messages_*.properties`) to reflect changes in the reference file `messages_en_GB.properties`.
- Ensured consistency and synchronization across all supported language files.
- Highlighted any missing or incomplete translations.
#### **2. Update README.md**
- Generated the translation progress table in `README.md`.
- Added a summary of the current translation status for all supported languages.
- Included up-to-date statistics on translation coverage.
#### **3. Verification Metadata Updates**
- Generated or refreshed the `verification-keyring.keys` and `verification-metadata.xml` files.
- Included the latest dependency signatures and checksums to enhance the build's integrity.
#### **Why these changes are necessary**
- Keeps translation files aligned with the latest reference updates.
- Ensures the documentation reflects the current translation progress.
- Strengthens dependency verification for a more secure build process.
---
Auto-generated by [create-pull-request][1].
[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
labels: github-actions labels: Documentation,Translation,github-actions
sign-commits: true sign-commits: true
add-paths: |
README.md
src/main/resources/messages_*.properties
gradle/verification-keyring.keys
gradle/verification-metadata.xml

View File

@@ -12,7 +12,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Harden Runner - name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 uses: step-security/harden-runner@c95a14d0e5bab51a9f56296a4eb0e416910cd350 # v2.10.3
with: with:
egress-policy: audit egress-policy: audit
@@ -46,7 +46,7 @@ jobs:
password: ${{ secrets.DOCKER_HUB_API }} password: ${{ secrets.DOCKER_HUB_API }}
- name: Build and push test image - name: Build and push test image
uses: docker/build-push-action@67a2d409c0a876cbe6b11854e3e25193efe4e62d # v6.12.0 uses: docker/build-push-action@b32b51a8eda65d6793cd0494a773d4f6bcef32dc # v6.11.0
with: with:
context: . context: .
file: ./Dockerfile file: ./Dockerfile
@@ -105,7 +105,7 @@ jobs:
steps: steps:
- name: Harden Runner - name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 uses: step-security/harden-runner@c95a14d0e5bab51a9f56296a4eb0e416910cd350 # v2.10.3
with: with:
egress-policy: audit egress-policy: audit
@@ -122,7 +122,7 @@ jobs:
Start-Process "C:/Program Files/Google/Chrome/Application/chrome.exe" -ArgumentList "--start-maximized", "--load-extension=$(pwd)/node_modules/dashcam-chrome/build", "http://${{ secrets.VPS_HOST }}:1337" Start-Process "C:/Program Files/Google/Chrome/Application/chrome.exe" -ArgumentList "--start-maximized", "--load-extension=$(pwd)/node_modules/dashcam-chrome/build", "http://${{ secrets.VPS_HOST }}:1337"
Start-Sleep -Seconds 20 Start-Sleep -Seconds 20
prompt: | prompt: |
1. /run testing/testdriver/test.yml 1. /run testdriver/test.yml
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
FORCE_COLOR: "3" FORCE_COLOR: "3"
@@ -134,7 +134,7 @@ jobs:
steps: steps:
- name: Harden Runner - name: Harden Runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 uses: step-security/harden-runner@c95a14d0e5bab51a9f56296a4eb0e416910cd350 # v2.10.3
with: with:
egress-policy: audit egress-policy: audit

View File

@@ -0,0 +1,72 @@
name: Update Translations
on:
push:
branches: ["main"]
paths:
- "src/main/resources/messages_en_GB.properties"
permissions:
contents: read
jobs:
update-translations-main:
if: github.event_name == 'push'
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
steps:
- name: Harden Runner
uses: step-security/harden-runner@c95a14d0e5bab51a9f56296a4eb0e416910cd350 # v2.10.3
with:
egress-policy: audit
- name: Checkout repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Set up Python
uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0
with:
python-version: "3.12"
- name: Run Python script to check files
id: run-check
run: |
echo "Running Python script to check files..."
python .github/scripts/check_language_properties.py \
--reference-file src/main/resources/messages_en_GB.properties \
--branch main
- name: Set up git config
run: |
git config --global user.name "github-actions[bot]"
git config --global user.email "github-actions[bot]@users.noreply.github.com"
- name: Add translation keys
run: |
git add src/main/resources/messages_*.properties
git diff --staged --quiet || echo "CHANGES_DETECTED=true" >> $GITHUB_ENV
- name: Create Pull Request
id: cpr
if: env.CHANGES_DETECTED == 'true'
uses: peter-evans/create-pull-request@67ccf781d68cd99b580ae25a5c18a1cc84ffff1f # v7.0.6
with:
token: ${{ secrets.GITHUB_TOKEN }}
commit-message: "Update translation files"
committer: GitHub Action <action@github.com>
author: GitHub Action <action@github.com>
signoff: true
branch: update_translation_files
title: "Update translation files"
add-paths: |
src/main/resources/messages_*.properties
body: |
Auto-generated by [create-pull-request][1]
[1]: https://github.com/peter-evans/create-pull-request
draft: false
delete-branch: true
labels: Translation,github-actions
sign-commits: true

2
.gitignore vendored
View File

@@ -21,11 +21,9 @@ pipeline/finishedFolders/
customFiles/ customFiles/
configs/ configs/
watchedFolders/ watchedFolders/
clientWebUI/
!cucumber/ !cucumber/
!cucumber/exampleFiles/ !cucumber/exampleFiles/
!cucumber/exampleFiles/example_html.zip !cucumber/exampleFiles/example_html.zip
exampleYmlFiles/stirling/
# Gradle # Gradle
.gradle .gradle

View File

@@ -6,10 +6,10 @@ repos:
args: args:
- --fix - --fix
- --line-length=127 - --line-length=127
files: ^((\.github/scripts|scripts)/.+)?[^/]+\.py$ files: ^((.github/scripts|scripts)/.+)?[^/]+\.py$
exclude: (split_photos.py) exclude: (split_photos.py)
- id: ruff-format - id: ruff-format
files: ^((\.github/scripts|scripts)/.+)?[^/]+\.py$ files: ^((.github/scripts|scripts)/.+)?[^/]+\.py$
exclude: (split_photos.py) exclude: (split_photos.py)
- repo: https://github.com/codespell-project/codespell - repo: https://github.com/codespell-project/codespell
rev: v2.3.0 rev: v2.3.0
@@ -19,18 +19,39 @@ repos:
- --ignore-words-list= - --ignore-words-list=
- --skip="./.*,*.csv,*.json,*.ambr" - --skip="./.*,*.csv,*.json,*.ambr"
- --quiet-level=2 - --quiet-level=2
files: \.(html|css|js|py|md)$ files: \.(properties|html|css|js|py|md)$
exclude: (.vscode|.devcontainer|src/main/resources|Dockerfile|.*/pdfjs.*|.*/thirdParty.*|bootstrap.*|.*\.min\..*|.*diff\.js) exclude: (.vscode|.devcontainer|src/main/resources|Dockerfile|.*/pdfjs.*|.*/thirdParty.*|bootstrap.*|.*\.min\..*|.*diff\.js)
- repo: https://github.com/gitleaks/gitleaks - repo: https://github.com/gitleaks/gitleaks
rev: v8.22.0 rev: v8.22.0
hooks: hooks:
- id: gitleaks - id: gitleaks
- repo: https://github.com/jumanjihouse/pre-commit-hooks
rev: 3.0.0
hooks:
- id: shellcheck
files: ^.*(\.bash|\.sh|\.ksh|\.zsh)$
- repo: https://github.com/pre-commit/pre-commit-hooks - repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0 rev: v5.0.0
hooks: hooks:
- id: end-of-file-fixer - id: end-of-file-fixer
files: ^.*(\.js|\.java|\.py|\.yml)$ files: ^.*(\.js|\.java|\.py|\.yml)$
exclude: ^(.*/pdfjs.*|.*/thirdParty.*|bootstrap.*|.*\.min\..*|.*diff\.js|\.github/workflows/.*$) exclude: ^(.*/pdfjs.*|.*/thirdParty.*|bootstrap.*|.*\.min\..*|.*diff\.js$)
- id: trailing-whitespace - id: trailing-whitespace
files: ^.*(\.js|\.java|\.py|\.yml)$ files: ^.*(\.js|\.java|\.py|\.yml)$
exclude: ^(.*/pdfjs.*|.*/thirdParty.*|bootstrap.*|.*\.min\..*|.*diff\.js|\.github/workflows/.*$) exclude: ^(.*/pdfjs.*|.*/thirdParty.*|bootstrap.*|.*\.min\..*|.*diff\.js$)
- repo: local
hooks:
- id: check-duplicate-properties-keys
name: Check Duplicate Properties Keys
entry: python .github/scripts/check_duplicates.py
language: python
files: ^(src)/.+\.properties$
- id: check-html-tabs
name: Check HTML for tabs
description: Ensures HTML/CSS/JS files do not contain tab characters
# args: ["--replace_with= "]
entry: python .github/scripts/check_tabulator.py
language: python
exclude: ^(.*/pdfjs.*|.*/thirdParty.*|bootstrap.*|.*\.min\..*|.*diff\.js$)
files: ^.*(\.html|\.css|\.js)$

View File

@@ -592,7 +592,7 @@ dependencies {
2. Generate new verification metadata and keys: 2. Generate new verification metadata and keys:
```bash ```bash
# Generate verification metadata with signatures and checksums # Generate verification metadata with signatures and checksums
./gradlew clean dependencies buildEnvironment spotlessApply --write-verification-metadata sha256,pgp ./gradlew clean dependencies buildEnvironment --write-verification-metadata sha256,pgp
# Export the .keys file # Export the .keys file
./gradlew --export-keys ./gradlew --export-keys

View File

@@ -25,13 +25,7 @@ LABEL org.opencontainers.image.keywords="PDF, manipulation, merge, split, conver
# Set Environment Variables # Set Environment Variables
ENV DOCKER_ENABLE_SECURITY=false \ ENV DOCKER_ENABLE_SECURITY=false \
VERSION_TAG=$VERSION_TAG \ VERSION_TAG=$VERSION_TAG \
JAVA_TOOL_OPTIONS="-XX:+UnlockExperimentalVMOptions \ JAVA_TOOL_OPTIONS="$JAVA_TOOL_OPTIONS -XX:MaxRAMPercentage=75" \
-XX:MaxRAMPercentage=75 \
-XX:InitiatingHeapOccupancyPercent=20 \
-XX:+G1PeriodicGCInvokesConcurrent \
-XX:G1PeriodicGCInterval=10000 \
-XX:+UseStringDeduplication \
-XX:G1PeriodicGCSystemLoadThreshold=70" \
HOME=/home/stirlingpdfuser \ HOME=/home/stirlingpdfuser \
PUID=1000 \ PUID=1000 \
PGID=1000 \ PGID=1000 \

View File

@@ -25,13 +25,7 @@ ARG VERSION_TAG
# Set Environment Variables # Set Environment Variables
ENV DOCKER_ENABLE_SECURITY=false \ ENV DOCKER_ENABLE_SECURITY=false \
VERSION_TAG=$VERSION_TAG \ VERSION_TAG=$VERSION_TAG \
JAVA_TOOL_OPTIONS="-XX:+UnlockExperimentalVMOptions \ JAVA_TOOL_OPTIONS="$JAVA_TOOL_OPTIONS -XX:MaxRAMPercentage=75" \
-XX:MaxRAMPercentage=75 \
-XX:InitiatingHeapOccupancyPercent=20 \
-XX:+G1PeriodicGCInvokesConcurrent \
-XX:G1PeriodicGCInterval=10000 \
-XX:+UseStringDeduplication \
-XX:G1PeriodicGCSystemLoadThreshold=70" \
HOME=/home/stirlingpdfuser \ HOME=/home/stirlingpdfuser \
PUID=1000 \ PUID=1000 \
PGID=1000 \ PGID=1000 \

View File

@@ -7,13 +7,7 @@ ARG VERSION_TAG
ENV DOCKER_ENABLE_SECURITY=false \ ENV DOCKER_ENABLE_SECURITY=false \
HOME=/home/stirlingpdfuser \ HOME=/home/stirlingpdfuser \
VERSION_TAG=$VERSION_TAG \ VERSION_TAG=$VERSION_TAG \
JAVA_TOOL_OPTIONS="-XX:+UnlockExperimentalVMOptions \ JAVA_TOOL_OPTIONS="$JAVA_TOOL_OPTIONS -XX:MaxRAMPercentage=75" \
-XX:MaxRAMPercentage=75 \
-XX:InitiatingHeapOccupancyPercent=20 \
-XX:+G1PeriodicGCInvokesConcurrent \
-XX:G1PeriodicGCInterval=10000 \
-XX:+UseStringDeduplication \
-XX:G1PeriodicGCSystemLoadThreshold=70" \
PUID=1000 \ PUID=1000 \
PGID=1000 \ PGID=1000 \
UMASK=022 UMASK=022

View File

@@ -60,13 +60,3 @@ ignore = [
- After adding the new tags to `messages_en_GB.properties`, add and translate them in the respective language file (e.g., `messages_pl_PL.properties`). - After adding the new tags to `messages_en_GB.properties`, add and translate them in the respective language file (e.g., `messages_pl_PL.properties`).
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. 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.
### Use this code to perform a local check
#### Windows command
```ps
python .github/scripts/check_language_properties.py --reference-file src\main\resources\messages_en_GB.properties --branch "" --files src\main\resources\messages_pl_PL.properties
python .github/scripts/check_language_properties.py --reference-file src\main\resources\messages_en_GB.properties --branch "" --check-file src\main\resources\messages_pl_PL.properties
```

View File

@@ -113,46 +113,45 @@ Visit our comprehensive documentation at [docs.stirlingpdf.com](https://docs.sti
## Supported Languages ## Supported Languages
Stirling-PDF currently supports 39 languages! Stirling-PDF currently supports 38 languages!
| Language | Progress | | Language | Progress |
| -------------------------------------------- | -------------------------------------- | | -------------------------------------------- | -------------------------------------- |
| Arabic (العربية) (ar_AR) | ![90%](https://geps.dev/progress/90) | | Arabic (العربية) (ar_AR) | ![91%](https://geps.dev/progress/91) |
| Azerbaijani (Azərbaycan Dili) (az_AZ) | ![89%](https://geps.dev/progress/89) | | Azerbaijani (Azərbaycan Dili) (az_AZ) | ![89%](https://geps.dev/progress/89) |
| Basque (Euskara) (eu_ES) | ![51%](https://geps.dev/progress/51) | | Basque (Euskara) (eu_ES) | ![51%](https://geps.dev/progress/51) |
| Bulgarian (Български) (bg_BG) | ![86%](https://geps.dev/progress/86) | | Bulgarian (Български) (bg_BG) | ![86%](https://geps.dev/progress/86) |
| Catalan (Català) (ca_CA) | ![81%](https://geps.dev/progress/81) | | Catalan (Català) (ca_CA) | ![81%](https://geps.dev/progress/81) |
| Croatian (Hrvatski) (hr_HR) | ![87%](https://geps.dev/progress/87) | | Croatian (Hrvatski) (hr_HR) | ![88%](https://geps.dev/progress/88) |
| Czech (Česky) (cs_CZ) | ![99%](https://geps.dev/progress/99) | | Czech (Česky) (cs_CZ) | ![87%](https://geps.dev/progress/87) |
| Danish (Dansk) (da_DK) | ![86%](https://geps.dev/progress/86) | | Danish (Dansk) (da_DK) | ![87%](https://geps.dev/progress/87) |
| Dutch (Nederlands) (nl_NL) | ![85%](https://geps.dev/progress/85) | | Dutch (Nederlands) (nl_NL) | ![86%](https://geps.dev/progress/86) |
| 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) |
| French (Français) (fr_FR) | ![96%](https://geps.dev/progress/96) | | French (Français) (fr_FR) | ![93%](https://geps.dev/progress/93) |
| German (Deutsch) (de_DE) | ![100%](https://geps.dev/progress/100) | | German (Deutsch) (de_DE) | ![96%](https://geps.dev/progress/96) |
| Greek (Ελληνικά) (el_GR) | ![98%](https://geps.dev/progress/98) | | Greek (Ελληνικά) (el_GR) | ![87%](https://geps.dev/progress/87) |
| Hindi (हिंदी) (hi_IN) | ![99%](https://geps.dev/progress/99) | | Hindi (हिंदी) (hi_IN) | ![85%](https://geps.dev/progress/85) |
| Hungarian (Magyar) (hu_HU) | ![96%](https://geps.dev/progress/96) | | Hungarian (Magyar) (hu_HU) | ![97%](https://geps.dev/progress/97) |
| Indonesian (Bahasa Indonesia) (id_ID) | ![87%](https://geps.dev/progress/87) | | Indonesian (Bahasa Indonesia) (id_ID) | ![87%](https://geps.dev/progress/87) |
| Irish (Gaeilge) (ga_IE) | ![79%](https://geps.dev/progress/79) | | Irish (Gaeilge) (ga_IE) | ![80%](https://geps.dev/progress/80) |
| Italian (Italiano) (it_IT) | ![99%](https://geps.dev/progress/99) | | Italian (Italiano) (it_IT) | ![99%](https://geps.dev/progress/99) |
| Japanese (日本語) (ja_JP) | ![90%](https://geps.dev/progress/90) | | Japanese (日本語) (ja_JP) | ![90%](https://geps.dev/progress/90) |
| Korean (한국어) (ko_KR) | ![99%](https://geps.dev/progress/99) | | Korean (한국어) (ko_KR) | ![86%](https://geps.dev/progress/86) |
| Norwegian (Norsk) (no_NB) | ![79%](https://geps.dev/progress/79) | | Norwegian (Norsk) (no_NB) | ![80%](https://geps.dev/progress/80) |
| Persian (فارسی) (fa_IR) | ![95%](https://geps.dev/progress/95) | | Persian (فارسی) (fa_IR) | ![95%](https://geps.dev/progress/95) |
| Polish (Polski) (pl_PL) | ![86%](https://geps.dev/progress/86) | | Polish (Polski) (pl_PL) | ![87%](https://geps.dev/progress/87) |
| Portuguese (Português) (pt_PT) | ![98%](https://geps.dev/progress/98) | | Portuguese (Português) (pt_PT) | ![98%](https://geps.dev/progress/98) |
| Portuguese Brazilian (Português) (pt_BR) | ![97%](https://geps.dev/progress/97) | | Portuguese Brazilian (Português) (pt_BR) | ![98%](https://geps.dev/progress/98) |
| Romanian (Română) (ro_RO) | ![81%](https://geps.dev/progress/81) | | Romanian (Română) (ro_RO) | ![82%](https://geps.dev/progress/82) |
| Russian (Русский) (ru_RU) | ![99%](https://geps.dev/progress/99) | | Russian (Русский) (ru_RU) | ![87%](https://geps.dev/progress/87) |
| Serbian Latin alphabet (Srpski) (sr_LATN_RS) | ![64%](https://geps.dev/progress/64) | | Serbian Latin alphabet (Srpski) (sr_LATN_RS) | ![64%](https://geps.dev/progress/64) |
| Simplified Chinese (简体中文) (zh_CN) | ![90%](https://geps.dev/progress/90) | | Simplified Chinese (简体中文) (zh_CN) | ![90%](https://geps.dev/progress/90) |
| Slovakian (Slovensky) (sk_SK) | ![75%](https://geps.dev/progress/75) | | Slovakian (Slovensky) (sk_SK) | ![75%](https://geps.dev/progress/75) |
| Slovenian (Slovenščina) (sl_SI) | ![97%](https://geps.dev/progress/97) | | Spanish (Español) (es_ES) | ![88%](https://geps.dev/progress/88) |
| Spanish (Español) (es_ES) | ![87%](https://geps.dev/progress/87) | | Swedish (Svenska) (sv_SE) | ![88%](https://geps.dev/progress/88) |
| Swedish (Svenska) (sv_SE) | ![87%](https://geps.dev/progress/87) | | Thai (ไทย) (th_TH) | ![87%](https://geps.dev/progress/87) |
| Thai (ไทย) (th_TH) | ![86%](https://geps.dev/progress/86) | | Tibetan (བོད་ཡིག་) (zh_BO) | ![96%](https://geps.dev/progress/96) |
| Tibetan (བོད་ཡིག་) (zh_BO) | ![95%](https://geps.dev/progress/95) |
| Traditional Chinese (繁體中文) (zh_TW) | ![99%](https://geps.dev/progress/99) | | Traditional Chinese (繁體中文) (zh_TW) | ![99%](https://geps.dev/progress/99) |
| Turkish (Türkçe) (tr_TR) | ![83%](https://geps.dev/progress/83) | | Turkish (Türkçe) (tr_TR) | ![83%](https://geps.dev/progress/83) |
| Ukrainian (Українська) (uk_UA) | ![73%](https://geps.dev/progress/73) | | Ukrainian (Українська) (uk_UA) | ![73%](https://geps.dev/progress/73) |

View File

@@ -5,10 +5,10 @@ plugins {
id "org.springdoc.openapi-gradle-plugin" version "1.8.0" id "org.springdoc.openapi-gradle-plugin" version "1.8.0"
id "io.swagger.swaggerhub" version "1.3.2" id "io.swagger.swaggerhub" version "1.3.2"
id "edu.sc.seis.launch4j" version "3.0.6" id "edu.sc.seis.launch4j" version "3.0.6"
id "com.diffplug.spotless" version "7.0.2" id "com.diffplug.spotless" version "7.0.1"
id "com.github.jk1.dependency-license-report" version "2.9" id "com.github.jk1.dependency-license-report" version "2.9"
//id "nebula.lint" version "19.0.3" //id "nebula.lint" version "19.0.3"
id("org.panteleyev.jpackageplugin") version "1.6.0" id("org.panteleyev.jpackageplugin") version "1.6.0"
} }
import com.github.jk1.license.render.* import com.github.jk1.license.render.*
@@ -19,13 +19,13 @@ ext {
logbackVersion = "1.5.7" logbackVersion = "1.5.7"
imageioVersion = "3.12.0" imageioVersion = "3.12.0"
lombokVersion = "1.18.36" lombokVersion = "1.18.36"
bouncycastleVersion = "1.80" bouncycastleVersion = "1.79"
springSecuritySamlVersion = "6.4.2" springSecuritySamlVersion = "6.4.2"
openSamlVersion = "4.3.2" openSamlVersion = "4.3.2"
} }
group = "stirling.software" group = "stirling.software"
version = "0.39.0" version = "0.37.0"
java { java {
@@ -35,9 +35,9 @@ java {
repositories { repositories {
mavenCentral() mavenCentral()
maven { url = "https://jitpack.io" } maven { url "https://jitpack.io" }
maven { url = "https://build.shibboleth.net/maven/releases" } maven { url "https://build.shibboleth.net/maven/releases" }
maven { url = "https://maven.pkg.github.com/jcefmaven/jcefmaven" } maven { url "https://maven.pkg.github.com/jcefmaven/jcefmaven" }
} }
@@ -66,7 +66,7 @@ sourceSets {
} }
if (System.getenv("STIRLING_PDF_DESKTOP_UI") == "false") { if (System.getenv("STIRLING_PDF_DESKTOP_UI") == "false") {
exclude "stirling/software/SPDF/UI/impl/**" exclude "stirling/software/SPDF/UI/impl/**"
} }
} }
@@ -111,15 +111,18 @@ def getMacVersion(String version) {
jpackage { jpackage {
input = "build/libs" input = "build/libs"
destination = "${projectDir}/build/jpackage"
mainJar = "Stirling-PDF-${project.version}.jar"
appName = "Stirling-PDF" appName = "Stirling-PDF"
appVersion = project.version appVersion = project.version
vendor = "Stirling-Software" vendor = "Stirling-Software"
appDescription = "Stirling PDF - Your Local PDF Editor" appDescription = "Stirling PDF - Your Local PDF Editor"
mainJar = "Stirling-PDF-${project.version}.jar"
mainClass = "org.springframework.boot.loader.launch.JarLauncher"
icon = "src/main/resources/static/favicon.ico" icon = "src/main/resources/static/favicon.ico"
verbose = true
// mainClass = "org.springframework.boot.loader.launch.JarLauncher"
// JVM Options // JVM Options
javaOptions = [ javaOptions = [
@@ -127,21 +130,23 @@ jpackage {
"-DSTIRLING_PDF_DESKTOP_UI=true", "-DSTIRLING_PDF_DESKTOP_UI=true",
"-Djava.awt.headless=false", "-Djava.awt.headless=false",
"-Dapple.awt.UIElement=true", "-Dapple.awt.UIElement=true",
"--add-opens=java.base/java.lang=ALL-UNNAMED", "--add-opens", "java.base/java.lang=ALL-UNNAMED",
"--add-opens=java.desktop/java.awt.event=ALL-UNNAMED", "--add-opens", "java.desktop/java.awt.event=ALL-UNNAMED",
"--add-opens=java.desktop/sun.awt=ALL-UNNAMED", "--add-opens", "java.desktop/sun.awt=ALL-UNNAMED"
"--add-opens=java.desktop/sun.awt.X11=ALL-UNNAMED",
"--add-opens=java.desktop/sun.awt.windows=ALL-UNNAMED",
"--add-opens=java.desktop/sun.lwawt=ALL-UNNAMED",
"--add-opens=java.desktop/sun.lwawt.macosx=ALL-UNNAMED",
] ]
verbose = true
destination = "${projectDir}/build/jpackage"
// Windows-specific configuration // Windows-specific configuration
windows { windows {
launcherAsService = false launcherAsService = false
appVersion = project.version appVersion = project.version
winConsole = false winConsole = false
winMenu = true // Creates start menu entry winMenu = true // Creates start menu entry
winShortcut = true // Creates desktop shortcut winShortcut = true // Creates desktop shortcut
winShortcutPrompt = true // Lets user choose whether to create shortcuts winShortcutPrompt = true // Lets user choose whether to create shortcuts
@@ -157,7 +162,7 @@ jpackage {
// macOS-specific configuration // macOS-specific configuration
mac { mac {
appVersion = getMacVersion(project.version.toString()) appVersion = getMacVersion(project.version.toString())
icon = "src/main/resources/static/favicon.icns" icon = "src/main/resources/static/favicon.icns"
type = "dmg" type = "dmg"
macPackageIdentifier = "com.stirling.software.pdf" macPackageIdentifier = "com.stirling.software.pdf"
@@ -181,7 +186,7 @@ jpackage {
// Linux-specific configuration // Linux-specific configuration
linux { linux {
appVersion = project.version appVersion = project.version
icon = "src/main/resources/static/favicon.png" icon = "src/main/resources/static/favicon.png"
type = "deb" // Can also use "rpm" for Red Hat-based systems type = "deb" // Can also use "rpm" for Red Hat-based systems
@@ -229,9 +234,9 @@ launch4j {
outfile="Stirling-PDF.exe" outfile="Stirling-PDF.exe"
if(System.getenv("STIRLING_PDF_DESKTOP_UI") == 'true') { if(System.getenv("STIRLING_PDF_DESKTOP_UI") == 'true') {
headerType = "gui" headerType = "gui"
} else { } else {
headerType = "console" headerType = "console"
} }
jarTask = tasks.bootJar jarTask = tasks.bootJar
@@ -239,11 +244,13 @@ launch4j {
downloadUrl="https://download.oracle.com/java/21/latest/jdk-21_windows-x64_bin.exe" downloadUrl="https://download.oracle.com/java/21/latest/jdk-21_windows-x64_bin.exe"
if(System.getenv("STIRLING_PDF_DESKTOP_UI") == 'true') { if(System.getenv("STIRLING_PDF_DESKTOP_UI") == 'true') {
variables=["BROWSER_OPEN=true", "STIRLING_PDF_DESKTOP_UI=true"] variables=["BROWSER_OPEN=true", "STIRLING_PDF_DESKTOP_UI=true"]
} else { } else {
variables=["BROWSER_OPEN=true"] variables=["BROWSER_OPEN=true"]
} }
jreMinVersion="17" jreMinVersion="17"
mutexName="Stirling-PDF" mutexName="Stirling-PDF"
@@ -265,7 +272,7 @@ spotless {
importOrder("java", "javax", "org", "com", "net", "io") importOrder("java", "javax", "org", "com", "net", "io")
toggleOffOn() toggleOffOn()
trimTrailingWhitespace() trimTrailingWhitespace()
leadingTabsToSpaces() indentWithSpaces()
endWithNewline() endWithNewline()
} }
} }
@@ -284,14 +291,14 @@ configurations.all {
} }
dependencies { dependencies {
if (System.getenv("STIRLING_PDF_DESKTOP_UI") != "false") { if (System.getenv("STIRLING_PDF_DESKTOP_UI") != "false") {
implementation "me.friwi:jcefmaven:127.3.1" implementation "me.friwi:jcefmaven:127.3.1"
implementation "org.openjfx:javafx-controls:21" implementation "org.openjfx:javafx-controls:21"
implementation "org.openjfx:javafx-swing:21" implementation "org.openjfx:javafx-swing:21"
} }
//security updates //security updates
implementation "org.springframework:spring-webmvc:6.2.2" implementation "org.springframework:spring-webmvc:6.2.1"
implementation("io.github.pixee:java-security-toolkit:1.2.1") implementation("io.github.pixee:java-security-toolkit:1.2.1")
@@ -313,10 +320,10 @@ dependencies {
implementation "org.springframework.boot:spring-boot-starter-data-jpa:$springBootVersion" implementation "org.springframework.boot:spring-boot-starter-data-jpa:$springBootVersion"
implementation "org.springframework.boot:spring-boot-starter-oauth2-client:$springBootVersion" implementation "org.springframework.boot:spring-boot-starter-oauth2-client:$springBootVersion"
implementation "org.springframework.session:spring-session-core:$springBootVersion" implementation "org.springframework.session:spring-session-core:$springBootVersion"
implementation "org.springframework:spring-jdbc:6.2.2" implementation "org.springframework:spring-jdbc:6.2.1"
implementation 'com.unboundid.product.scim2:scim2-sdk-client:2.3.5' implementation 'com.unboundid.product.scim2:scim2-sdk-client:2.3.5'
// Don't upgrade h2database // Don't upgrade h2database
runtimeOnly "com.h2database:h2:2.3.232" runtimeOnly "com.h2database:h2:2.3.232"
runtimeOnly "org.postgresql:postgresql:42.7.4" runtimeOnly "org.postgresql:postgresql:42.7.4"
@@ -326,7 +333,7 @@ dependencies {
implementation "org.opensaml:opensaml-saml-impl:$openSamlVersion" implementation "org.opensaml:opensaml-saml-impl:$openSamlVersion"
} }
implementation "org.springframework.security:spring-security-saml2-service-provider:$springSecuritySamlVersion" implementation "org.springframework.security:spring-security-saml2-service-provider:$springSecuritySamlVersion"
// implementation 'org.springframework.security:spring-security-core:$springSecuritySamlVersion' // implementation 'org.springframework.security:spring-security-core:$springSecuritySamlVersion'
implementation 'com.coveo:saml-client:5.0.0' implementation 'com.coveo:saml-client:5.0.0'
@@ -370,8 +377,6 @@ dependencies {
implementation ("org.apache.pdfbox:pdfbox:$pdfboxVersion") { implementation ("org.apache.pdfbox:pdfbox:$pdfboxVersion") {
exclude group: "commons-logging", module: "commons-logging" exclude group: "commons-logging", module: "commons-logging"
} }
implementation "org.apache.pdfbox:preflight:$pdfboxVersion"
implementation ("org.apache.pdfbox:xmpbox:$pdfboxVersion") { implementation ("org.apache.pdfbox:xmpbox:$pdfboxVersion") {
exclude group: "commons-logging", module: "commons-logging" exclude group: "commons-logging", module: "commons-logging"
@@ -398,8 +403,8 @@ dependencies {
implementation "com.bucket4j:bucket4j_jdk17-core:8.14.0" implementation "com.bucket4j:bucket4j_jdk17-core:8.14.0"
implementation "com.fathzer:javaluator:3.0.5" implementation "com.fathzer:javaluator:3.0.5"
implementation 'com.vladsch.flexmark:flexmark-html2md-converter:0.64.8' implementation 'org.jsoup:jsoup:1.18.3'
developmentOnly("org.springframework.boot:spring-boot-devtools:$springBootVersion") developmentOnly("org.springframework.boot:spring-boot-devtools:$springBootVersion")
compileOnly "org.projectlombok:lombok:$lombokVersion" compileOnly "org.projectlombok:lombok:$lombokVersion"
annotationProcessor "org.projectlombok:lombok:$lombokVersion" annotationProcessor "org.projectlombok:lombok:$lombokVersion"
@@ -423,13 +428,13 @@ task writeVersion {
} }
swaggerhubUpload { swaggerhubUpload {
// dependsOn = generateOpenApiDocs // Depends on your task generating Swagger docs //dependsOn generateOpenApiDocs // Depends on your task generating Swagger docs
api = "Stirling-PDF" // The name of your API on SwaggerHub api "Stirling-PDF" // The name of your API on SwaggerHub
owner = "Frooodle" // Your SwaggerHub username (or organization name) owner "Frooodle" // Your SwaggerHub username (or organization name)
version = project.version // The version of your API version project.version // The version of your API
inputFile = "./SwaggerDoc.json" // The path to your Swagger docs inputFile "./SwaggerDoc.json" // The path to your Swagger docs
token = "${System.getenv("SWAGGERHUB_API_KEY")}" // Your SwaggerHub API key, passed as an environment variable token "${System.getenv("SWAGGERHUB_API_KEY")}" // Your SwaggerHub API key, passed as an environment variable
oas = "3.0.0" // The version of the OpenAPI Specification you"re using oas "3.0.0" // The version of the OpenAPI Specification you"re using
} }
jar { jar {

View File

@@ -204,12 +204,4 @@ Feature: API Validation
Then the response status code should be 200 Then the response status code should be 200
And the response file should have size greater than 100 And the response file should have size greater than 100
And the response file should have extension ".pdf" And the response file should have extension ".pdf"
Scenario: Convert PDF to Markdown format
Given I generate a PDF file as "fileInput"
And the pdf contains 3 pages with random text
When I send the API request to the endpoint "/api/v1/convert/pdf/markdown"
Then the response status code should be 200
And the response file should have size greater than 100
And the response file should have extension ".md"

View File

@@ -2,16 +2,17 @@
# Function to check a single webpage # Function to check a single webpage
check_webpage() { check_webpage() {
local url=$(echo "$1" | tr -d '\r') # Remove carriage returns local url=$1
local base_url=$(echo "$2" | tr -d '\r') local base_url=${2:-"http://localhost:8080"}
local full_url="${base_url}${url}" local full_url="${base_url}${url}"
local timeout=10 local timeout=10
echo -n "Testing $full_url ... " echo -n "Testing $full_url ... "
# Use curl to fetch the page with timeout # Use curl to fetch the page with timeout
response=$(curl -s -w "\n%{http_code}" --max-time $timeout "$full_url") response=$(curl -s -w "\n%{http_code}" --max-time $timeout "$full_url")
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
echo "FAILED - Connection error or timeout $full_url " echo "FAILED - Connection error or timeout"
return 1 return 1
fi fi
@@ -26,7 +27,7 @@ check_webpage() {
fi fi
# Check if response contains HTML # Check if response contains HTML
if ! printf '%s' "$BODY" | grep -q "<!DOCTYPE html>\|<html"; then if ! echo "$BODY" | grep -q "<!DOCTYPE html>\|<html"; then
echo "FAILED - Response is not HTML" echo "FAILED - Response is not HTML"
return 1 return 1
fi fi
@@ -45,12 +46,11 @@ test_all_urls() {
echo "Starting webpage tests..." echo "Starting webpage tests..."
echo "Base URL: $base_url" echo "Base URL: $base_url"
echo "Number of lines: $(wc -l < "$url_file")"
echo "----------------------------------------" echo "----------------------------------------"
while IFS= read -r url || [ -n "$url" ]; do while IFS= read -r url || [ -n "$url" ]; do
# Skip empty lines and comments # Skip empty lines
[[ -z "$url" || "$url" =~ ^#.*$ ]] && continue [ -z "$url" ] && continue
((total_count++)) ((total_count++))
if ! check_webpage "$url" "$base_url"; then if ! check_webpage "$url" "$base_url"; then
@@ -60,7 +60,7 @@ test_all_urls() {
local end_time=$(date +%s) local end_time=$(date +%s)
local duration=$((end_time - start_time)) local duration=$((end_time - start_time))
echo "----------------------------------------" echo "----------------------------------------"
echo "Test Summary:" echo "Test Summary:"
echo "Total tests: $total_count" echo "Total tests: $total_count"
@@ -71,44 +71,18 @@ test_all_urls() {
return $failed_count return $failed_count
} }
# Print usage information
usage() {
echo "Usage: $0 [-f url_file] [-b base_url]"
echo "Options:"
echo " -f url_file Path to file containing URLs to test (required)"
echo " -b base_url Base URL to prepend to test URLs (default: http://localhost:8080)"
exit 1
}
# Main execution # Main execution
main() { main() {
local url_file="" local script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
local base_url="http://localhost:8080" local url_file="${script_dir}/webpage_urls.txt"
# Parse command line options
while getopts ":f:b:h" opt; do
case $opt in
f) url_file="$OPTARG" ;;
b) base_url="$OPTARG" ;;
h) usage ;;
\?) echo "Invalid option -$OPTARG" >&2; usage ;;
esac
done
# Check if URL file is provided
if [ -z "$url_file" ]; then
echo "Error: URL file is required"
usage
fi
# Check if URL file exists
if [ ! -f "$url_file" ]; then if [ ! -f "$url_file" ]; then
echo "Error: URL list file not found: $url_file" echo "Error: URL list file not found: $url_file"
exit 1 exit 1
fi fi
# Run tests using the URL list # Run tests using the URL list
if test_all_urls "$url_file" "$base_url"; then if test_all_urls "$url_file"; then
echo "All webpage tests passed!" echo "All webpage tests passed!"
exit 0 exit 0
else else

View File

@@ -12,6 +12,7 @@
/extract-page /extract-page
/pdf-to-single-page /pdf-to-single-page
/img-to-pdf /img-to-pdf
/markdown-to-pdf
/pdf-to-img /pdf-to-img
/pdf-to-text /pdf-to-text
/pdf-to-csv /pdf-to-csv

View File

@@ -1,6 +1,6 @@
services: services:
stirling-pdf: stirling-pdf:
container_name: Stirling-PDF-Security-Fat-with-login container_name: Stirling-PDF-Security-Fat
image: stirlingtools/stirling-pdf:latest-fat image: stirlingtools/stirling-pdf:latest-fat
deploy: deploy:
resources: resources:

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -75,7 +75,7 @@ def write_readme(progress_list: list[tuple[str, int]]) -> None:
f"![{value}%](https://geps.dev/progress/{value})", f"![{value}%](https://geps.dev/progress/{value})",
) )
with open("README.md", "w", encoding="utf-8", newline="\n") as file: with open("README.md", "w", encoding="utf-8") as file:
file.writelines(content) file.writelines(content)
@@ -196,7 +196,7 @@ def compare_files(
) )
) )
ignore_translation = convert_to_multiline(sort_ignore_translation) ignore_translation = convert_to_multiline(sort_ignore_translation)
with open(ignore_translation_file, "w", encoding="utf-8", newline="\n") as file: with open(ignore_translation_file, "w", encoding="utf-8") as file:
file.write(tomlkit.dumps(ignore_translation)) file.write(tomlkit.dumps(ignore_translation))
unique_data = list(set(result_list)) unique_data = list(set(result_list))

View File

@@ -24,6 +24,7 @@ ignore = [
[cs_CZ] [cs_CZ]
ignore = [ ignore = [
'language.direction', 'language.direction',
'pipeline.header',
'text', 'text',
] ]
@@ -49,7 +50,6 @@ ignore = [
'pipeline.title', 'pipeline.title',
'pipelineOptions.pipelineHeader', 'pipelineOptions.pipelineHeader',
'pro', 'pro',
'redact.zoom',
'sponsor', 'sponsor',
'text', 'text',
'validateSignature.cert.bits', 'validateSignature.cert.bits',
@@ -210,11 +210,6 @@ ignore = [
'watermark.type.1', 'watermark.type.1',
] ]
[sl_SI]
ignore = [
'language.direction',
]
[sr_LATN_RS] [sr_LATN_RS]
ignore = [ ignore = [
'language.direction', 'language.direction',

View File

@@ -25,7 +25,7 @@ public class EEAppConfig {
@Bean(name = "runningEE") @Bean(name = "runningEE")
public boolean runningEnterpriseEdition() { public boolean runningEnterpriseEdition() {
return licenseKeyChecker.getEnterpriseEnabledResult(); return licenseKeyChecker.getEnterpriseEnabledResult();
} }
@Bean(name = "SSOAutoLogin") @Bean(name = "SSOAutoLogin")

View File

@@ -126,7 +126,6 @@ public class EndpointConfiguration {
addEndpointToGroup("Convert", "url-to-pdf"); addEndpointToGroup("Convert", "url-to-pdf");
addEndpointToGroup("Convert", "markdown-to-pdf"); addEndpointToGroup("Convert", "markdown-to-pdf");
addEndpointToGroup("Convert", "pdf-to-csv"); addEndpointToGroup("Convert", "pdf-to-csv");
addEndpointToGroup("Convert", "pdf-to-markdown");
// Adding endpoints to "Security" group // Adding endpoints to "Security" group
addEndpointToGroup("Security", "add-password"); addEndpointToGroup("Security", "add-password");
@@ -244,7 +243,6 @@ public class EndpointConfiguration {
addEndpointToGroup("Java", REMOVE_BLANKS); addEndpointToGroup("Java", REMOVE_BLANKS);
addEndpointToGroup("Java", "pdf-to-text"); addEndpointToGroup("Java", "pdf-to-text");
addEndpointToGroup("Java", "remove-image-pdf"); addEndpointToGroup("Java", "remove-image-pdf");
addEndpointToGroup("Java", "pdf-to-markdown");
// Javascript // Javascript
addEndpointToGroup("Javascript", "pdf-organizer"); addEndpointToGroup("Javascript", "pdf-organizer");
@@ -260,11 +258,9 @@ public class EndpointConfiguration {
// Weasyprint dependent endpoints // Weasyprint dependent endpoints
addEndpointToGroup("Weasyprint", "html-to-pdf"); addEndpointToGroup("Weasyprint", "html-to-pdf");
addEndpointToGroup("Weasyprint", "url-to-pdf"); addEndpointToGroup("Weasyprint", "url-to-pdf");
addEndpointToGroup("Weasyprint", "markdown-to-pdf");
// Pdftohtml dependent endpoints // Pdftohtml dependent endpoints
addEndpointToGroup("Pdftohtml", "pdf-to-html"); addEndpointToGroup("Pdftohtml", "pdf-to-html");
addEndpointToGroup("Pdftohtml", "pdf-to-markdown");
// disabled for now while we resolve issues // disabled for now while we resolve issues
disableEndpoint("pdf-to-pdfa"); disableEndpoint("pdf-to-pdfa");

View File

@@ -33,11 +33,7 @@ public class DatabaseConfig {
public DatabaseConfig( public DatabaseConfig(
ApplicationProperties applicationProperties, ApplicationProperties applicationProperties,
@Qualifier("runningEE") boolean runningEE) { @Qualifier("runningEE") boolean runningEE) {
DATASOURCE_DEFAULT_URL = DATASOURCE_DEFAULT_URL = "jdbc:h2:file:" + InstallationPathConfig.getConfigPath() + File.separator + "stirling-pdf-DB-2.3.232;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE";
"jdbc:h2:file:"
+ InstallationPathConfig.getConfigPath()
+ File.separator
+ "stirling-pdf-DB-2.3.232;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE";
this.applicationProperties = applicationProperties; this.applicationProperties = applicationProperties;
this.runningEE = runningEE; this.runningEE = runningEE;
} }

View File

@@ -1,180 +0,0 @@
package stirling.software.SPDF.controller.api;
import org.apache.pdfbox.Loader;
import org.apache.pdfbox.cos.COSName;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageTree;
import org.apache.pdfbox.pdmodel.PDDocumentInformation;
import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm;
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotation;
import org.apache.pdfbox.pdmodel.encryption.PDEncryption;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import stirling.software.SPDF.model.api.PDFFile;
import java.io.IOException;
import java.util.*;
@RestController
@RequestMapping("/api/v1/analysis")
@Tag(name = "Analysis", description = "Analysis APIs")
public class AnalysisController {
@PostMapping(value = "/page-count", consumes = "multipart/form-data")
@Operation(summary = "Get PDF page count",
description = "Returns total number of pages in PDF. Input:PDF Output:JSON Type:SISO")
public Map<String, Integer> getPageCount(@ModelAttribute PDFFile file) throws IOException {
try (PDDocument document = Loader.loadPDF(file.getFileInput().getBytes())) {
return Map.of("pageCount", document.getNumberOfPages());
}
}
@PostMapping(value ="/basic-info", consumes = "multipart/form-data")
@Operation(summary = "Get basic PDF information",
description = "Returns page count, version, file size. Input:PDF Output:JSON Type:SISO")
public Map<String, Object> getBasicInfo(@ModelAttribute PDFFile file) throws IOException {
try (PDDocument document = Loader.loadPDF(file.getFileInput().getBytes())) {
Map<String, Object> info = new HashMap<>();
info.put("pageCount", document.getNumberOfPages());
info.put("pdfVersion", document.getVersion());
info.put("fileSize", file.getFileInput().getSize());
return info;
}
}
@PostMapping(value ="/document-properties", consumes = "multipart/form-data")
@Operation(summary = "Get PDF document properties",
description = "Returns title, author, subject, etc. Input:PDF Output:JSON Type:SISO")
public Map<String, String> getDocumentProperties(@ModelAttribute PDFFile file) throws IOException {
try (PDDocument document = Loader.loadPDF(file.getFileInput().getBytes())) {
PDDocumentInformation info = document.getDocumentInformation();
Map<String, String> properties = new HashMap<>();
properties.put("title", info.getTitle());
properties.put("author", info.getAuthor());
properties.put("subject", info.getSubject());
properties.put("keywords", info.getKeywords());
properties.put("creator", info.getCreator());
properties.put("producer", info.getProducer());
properties.put("creationDate", info.getCreationDate().toString());
properties.put("modificationDate", info.getModificationDate().toString());
return properties;
}
}
@PostMapping(value ="/page-dimensions", consumes = "multipart/form-data")
@Operation(summary = "Get page dimensions for all pages",
description = "Returns width and height of each page. Input:PDF Output:JSON Type:SISO")
public List<Map<String, Float>> getPageDimensions(@ModelAttribute PDFFile file) throws IOException {
try (PDDocument document = Loader.loadPDF(file.getFileInput().getBytes())) {
List<Map<String, Float>> dimensions = new ArrayList<>();
PDPageTree pages = document.getPages();
for (PDPage page : pages) {
Map<String, Float> pageDim = new HashMap<>();
pageDim.put("width", page.getBBox().getWidth());
pageDim.put("height", page.getBBox().getHeight());
dimensions.add(pageDim);
}
return dimensions;
}
}
@PostMapping(value ="/form-fields", consumes = "multipart/form-data")
@Operation(summary = "Get form field information",
description = "Returns count and details of form fields. Input:PDF Output:JSON Type:SISO")
public Map<String, Object> getFormFields(@ModelAttribute PDFFile file) throws IOException {
try (PDDocument document = Loader.loadPDF(file.getFileInput().getBytes())) {
Map<String, Object> formInfo = new HashMap<>();
PDAcroForm form = document.getDocumentCatalog().getAcroForm();
if (form != null) {
formInfo.put("fieldCount", form.getFields().size());
formInfo.put("hasXFA", form.hasXFA());
formInfo.put("isSignaturesExist", form.isSignaturesExist());
} else {
formInfo.put("fieldCount", 0);
formInfo.put("hasXFA", false);
formInfo.put("isSignaturesExist", false);
}
return formInfo;
}
}
@PostMapping(value ="/annotation-info", consumes = "multipart/form-data")
@Operation(summary = "Get annotation information",
description = "Returns count and types of annotations. Input:PDF Output:JSON Type:SISO")
public Map<String, Object> getAnnotationInfo(@ModelAttribute PDFFile file) throws IOException {
try (PDDocument document = Loader.loadPDF(file.getFileInput().getBytes())) {
Map<String, Object> annotInfo = new HashMap<>();
int totalAnnotations = 0;
Map<String, Integer> annotationTypes = new HashMap<>();
for (PDPage page : document.getPages()) {
for (PDAnnotation annot : page.getAnnotations()) {
totalAnnotations++;
String subType = annot.getSubtype();
annotationTypes.merge(subType, 1, Integer::sum);
}
}
annotInfo.put("totalCount", totalAnnotations);
annotInfo.put("typeBreakdown", annotationTypes);
return annotInfo;
}
}
@PostMapping(value ="/font-info", consumes = "multipart/form-data")
@Operation(summary = "Get font information",
description = "Returns list of fonts used in the document. Input:PDF Output:JSON Type:SISO")
public Map<String, Object> getFontInfo(@ModelAttribute PDFFile file) throws IOException {
try (PDDocument document = Loader.loadPDF(file.getFileInput().getBytes())) {
Map<String, Object> fontInfo = new HashMap<>();
Set<String> fontNames = new HashSet<>();
for (PDPage page : document.getPages()) {
for (COSName font : page.getResources().getFontNames()) {
fontNames.add(font.getName());
}
}
fontInfo.put("fontCount", fontNames.size());
fontInfo.put("fonts", fontNames);
return fontInfo;
}
}
@PostMapping(value ="/security-info", consumes = "multipart/form-data")
@Operation(summary = "Get security information",
description = "Returns encryption and permission details. Input:PDF Output:JSON Type:SISO")
public Map<String, Object> getSecurityInfo(@ModelAttribute PDFFile file) throws IOException {
try (PDDocument document = Loader.loadPDF(file.getFileInput().getBytes())) {
Map<String, Object> securityInfo = new HashMap<>();
PDEncryption encryption = document.getEncryption();
if (encryption != null) {
securityInfo.put("isEncrypted", true);
securityInfo.put("keyLength", encryption.getLength());
// Get permissions
Map<String, Boolean> permissions = new HashMap<>();
permissions.put("canPrint", document.getCurrentAccessPermission().canPrint());
permissions.put("canModify", document.getCurrentAccessPermission().canModify());
permissions.put("canExtractContent", document.getCurrentAccessPermission().canExtractContent());
permissions.put("canModifyAnnotations", document.getCurrentAccessPermission().canModifyAnnotations());
securityInfo.put("permissions", permissions);
} else {
securityInfo.put("isEncrypted", false);
}
return securityInfo;
}
}
}

View File

@@ -44,13 +44,6 @@ public class ConverterWebController {
return "convert/markdown-to-pdf"; return "convert/markdown-to-pdf";
} }
@GetMapping("/pdf-to-markdown")
@Hidden
public String convertPdfToMarkdownForm(Model model) {
model.addAttribute("currentPage", "pdf-to-markdown");
return "convert/pdf-to-markdown";
}
@GetMapping("/url-to-pdf") @GetMapping("/url-to-pdf")
@Hidden @Hidden
public String convertURLToPdfForm(Model model) { public String convertURLToPdfForm(Model model) {

View File

@@ -55,10 +55,7 @@ public class GeneralWebController {
List<String> pipelineConfigs = new ArrayList<>(); List<String> pipelineConfigs = new ArrayList<>();
List<Map<String, String>> pipelineConfigsWithNames = new ArrayList<>(); List<Map<String, String>> pipelineConfigsWithNames = new ArrayList<>();
if (new File(InstallationPathConfig.getPipelineDefaultWebUIConfigsDir()).exists()) { if (new File(InstallationPathConfig.getPipelineDefaultWebUIConfigsDir()).exists()) {
try (Stream<Path> paths = try (Stream<Path> paths = Files.walk(Paths.get(InstallationPathConfig.getPipelineDefaultWebUIConfigsDir()))) {
Files.walk(
Paths.get(
InstallationPathConfig.getPipelineDefaultWebUIConfigsDir()))) {
List<Path> jsonFiles = List<Path> jsonFiles =
paths.filter(Files::isRegularFile) paths.filter(Files::isRegularFile)
.filter(p -> p.toString().endsWith(".json")) .filter(p -> p.toString().endsWith(".json"))

View File

@@ -1,32 +0,0 @@
package stirling.software.SPDF.model.api.converters;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import stirling.software.SPDF.model.api.PDFFile;
import stirling.software.SPDF.utils.PDFToFile;
@RestController
@Tag(name = "Convert", description = "Convert APIs")
@RequestMapping("/api/v1/convert")
public class ConvertPDFToMarkdown {
@PostMapping(consumes = "multipart/form-data", value = "/pdf/markdown")
@Operation(
summary = "Convert PDF to Markdown",
description =
"This endpoint converts a PDF file to Markdown format. Input:PDF Output:Markdown Type:SISO")
public ResponseEntity<byte[]> processPdfToMarkdown(@ModelAttribute PDFFile request)
throws Exception {
MultipartFile inputFile = request.getFileInput();
PDFToFile pdfToFile = new PDFToFile();
return pdfToFile.processPdfToMarkdown(inputFile);
}
}

View File

@@ -26,7 +26,7 @@ public class OptimizePdfRequest extends PDFFile {
@Schema( @Schema(
description = description =
"Whether to normalize the PDF content for better compatibility. Default is false.", "Whether to normalize the PDF content for better compatibility. Default is true.",
defaultValue = "false") defaultValue = "true")
private Boolean normalize = false; private Boolean normalize = true;
} }

View File

@@ -39,7 +39,7 @@ public class MetricsAggregatorService {
if (method == null || uri == null) { if (method == null || uri == null) {
return; return;
} }
if (!"GET".equals(method) && !"POST".equals(method)) { if (!method.equals("GET") && !method.equals("POST")) {
return; return;
} }
// Skip URIs that are 2 characters or shorter // Skip URIs that are 2 characters or shorter

View File

@@ -20,9 +20,6 @@ import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import com.vladsch.flexmark.html2md.converter.FlexmarkHtmlConverter;
import com.vladsch.flexmark.util.data.MutableDataSet;
import io.github.pixee.security.Filenames; import io.github.pixee.security.Filenames;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@@ -31,123 +28,6 @@ import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult;
@Slf4j @Slf4j
public class PDFToFile { public class PDFToFile {
public ResponseEntity<byte[]> processPdfToMarkdown(MultipartFile inputFile)
throws IOException, InterruptedException {
if (!"application/pdf".equals(inputFile.getContentType())) {
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}
MutableDataSet options =
new MutableDataSet()
.set(
FlexmarkHtmlConverter.MAX_BLANK_LINES,
2) // Control max consecutive blank lines
.set(
FlexmarkHtmlConverter.MAX_TRAILING_BLANK_LINES,
1) // Control trailing blank lines
.set(
FlexmarkHtmlConverter.SETEXT_HEADINGS,
true) // Use Setext headings for h1 and h2
.set(
FlexmarkHtmlConverter.OUTPUT_UNKNOWN_TAGS,
false) // Don't output HTML for unknown tags
.set(
FlexmarkHtmlConverter.TYPOGRAPHIC_QUOTES,
true) // Convert quotation marks
.set(
FlexmarkHtmlConverter.BR_AS_PARA_BREAKS,
true) // Convert <br> to paragraph breaks
.set(FlexmarkHtmlConverter.CODE_INDENT, " "); // Indent for code blocks
FlexmarkHtmlConverter htmlToMarkdownConverter =
FlexmarkHtmlConverter.builder(options).build();
String originalPdfFileName = Filenames.toSimpleFileName(inputFile.getOriginalFilename());
String pdfBaseName = originalPdfFileName;
if (originalPdfFileName.contains(".")) {
pdfBaseName = originalPdfFileName.substring(0, originalPdfFileName.lastIndexOf('.'));
}
Path tempInputFile = null;
Path tempOutputDir = null;
byte[] fileBytes;
String fileName = "temp.file";
try {
tempInputFile = Files.createTempFile("input_", ".pdf");
inputFile.transferTo(tempInputFile);
tempOutputDir = Files.createTempDirectory("output_");
List<String> command =
new ArrayList<>(
Arrays.asList(
"pdftohtml",
"-s",
"-noframes",
"-c",
tempInputFile.toString(),
pdfBaseName));
ProcessExecutorResult returnCode =
ProcessExecutor.getInstance(ProcessExecutor.Processes.PDFTOHTML)
.runCommandWithOutputHandling(command, tempOutputDir.toFile());
// Process HTML files to Markdown
File[] outputFiles = Objects.requireNonNull(tempOutputDir.toFile().listFiles());
List<File> markdownFiles = new ArrayList<>();
// Convert HTML files to Markdown
for (File outputFile : outputFiles) {
if (outputFile.getName().endsWith(".html")) {
String html = Files.readString(outputFile.toPath());
String markdown = htmlToMarkdownConverter.convert(html);
String mdFileName = outputFile.getName().replace(".html", ".md");
File mdFile = new File(tempOutputDir.toFile(), mdFileName);
Files.writeString(mdFile.toPath(), markdown);
markdownFiles.add(mdFile);
}
}
// If there's only one markdown file, return it directly
if (markdownFiles.size() == 1) {
fileName = pdfBaseName + ".md";
fileBytes = Files.readAllBytes(markdownFiles.get(0).toPath());
} else {
// Multiple files - create a zip
fileName = pdfBaseName + "ToMarkdown.zip";
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
try (ZipOutputStream zipOutputStream = new ZipOutputStream(byteArrayOutputStream)) {
// Add markdown files
for (File mdFile : markdownFiles) {
ZipEntry mdEntry = new ZipEntry(mdFile.getName());
zipOutputStream.putNextEntry(mdEntry);
Files.copy(mdFile.toPath(), zipOutputStream);
zipOutputStream.closeEntry();
}
// Add images and other assets
for (File file : outputFiles) {
if (!file.getName().endsWith(".html") && !file.getName().endsWith(".md")) {
ZipEntry assetEntry = new ZipEntry(file.getName());
zipOutputStream.putNextEntry(assetEntry);
Files.copy(file.toPath(), zipOutputStream);
zipOutputStream.closeEntry();
}
}
}
fileBytes = byteArrayOutputStream.toByteArray();
}
} finally {
if (tempInputFile != null) Files.deleteIfExists(tempInputFile);
if (tempOutputDir != null) FileUtils.deleteDirectory(tempOutputDir.toFile());
}
return WebResponseUtils.bytesToWebResponse(
fileBytes, fileName, MediaType.APPLICATION_OCTET_STREAM);
}
public ResponseEntity<byte[]> processPdfToHtml(MultipartFile inputFile) public ResponseEntity<byte[]> processPdfToHtml(MultipartFile inputFile)
throws IOException, InterruptedException { throws IOException, InterruptedException {
if (!"application/pdf".equals(inputFile.getContentType())) { if (!"application/pdf".equals(inputFile.getContentType())) {

View File

@@ -452,9 +452,6 @@ home.MarkdownToPDF.title=Markdown إلى PDF
home.MarkdownToPDF.desc=يحول أي ملف Markdown إلى PDF home.MarkdownToPDF.desc=يحول أي ملف Markdown إلى PDF
MarkdownToPDF.tags=لغة الترميز,محتوى الويب,تحويل,تحويل MarkdownToPDF.tags=لغة الترميز,محتوى الويب,تحويل,تحويل
home.PDFToMarkdown.title=PDF to Markdown
home.PDFToMarkdown.desc=Converts any PDF to Markdown
PDFToMarkdown.tags=markup,web-content,transformation,convert,md
home.getPdfInfo.title=الحصول على جميع المعلومات عن PDF home.getPdfInfo.title=الحصول على جميع المعلومات عن PDF
home.getPdfInfo.desc=يجمع أي وكل المعلومات الممكنة عن ملفات PDF home.getPdfInfo.desc=يجمع أي وكل المعلومات الممكنة عن ملفات PDF
@@ -649,11 +646,6 @@ MarkdownToPDF.help=العمل قيد التقدم
MarkdownToPDF.credit=يستخدم WeasyPrint MarkdownToPDF.credit=يستخدم WeasyPrint
#pdf-to-markdown
PDFToMarkdown.title=PDF To Markdown
PDFToMarkdown.header=PDF To Markdown
PDFToMarkdown.submit=Convert
#url-to-pdf #url-to-pdf
URLToPDF.title=URL إلى PDF URLToPDF.title=URL إلى PDF

View File

@@ -452,9 +452,6 @@ home.MarkdownToPDF.title=Markdown-dan PDF-ə
home.MarkdownToPDF.desc=Hər hansı Markdown faylını PDF-ə çevirir home.MarkdownToPDF.desc=Hər hansı Markdown faylını PDF-ə çevirir
MarkdownToPDF.tags=işarələmə,web-məzmun,dəyişmə,çevirmə MarkdownToPDF.tags=işarələmə,web-məzmun,dəyişmə,çevirmə
home.PDFToMarkdown.title=PDF to Markdown
home.PDFToMarkdown.desc=Converts any PDF to Markdown
PDFToMarkdown.tags=markup,web-content,transformation,convert,md
home.getPdfInfo.title=PDF-in Bütün Məlumatları home.getPdfInfo.title=PDF-in Bütün Məlumatları
home.getPdfInfo.desc=PDF barədə mümkün olan bütün məlumatları əldə edir home.getPdfInfo.desc=PDF barədə mümkün olan bütün məlumatları əldə edir
@@ -649,11 +646,6 @@ MarkdownToPDF.help=İş davam edir
MarkdownToPDF.credit=WeasyPrint İstifadə Edir MarkdownToPDF.credit=WeasyPrint İstifadə Edir
#pdf-to-markdown
PDFToMarkdown.title=PDF To Markdown
PDFToMarkdown.header=PDF To Markdown
PDFToMarkdown.submit=Convert
#url-to-pdf #url-to-pdf
URLToPDF.title=URL-i PDF-ə URLToPDF.title=URL-i PDF-ə

View File

@@ -452,9 +452,6 @@ home.MarkdownToPDF.title=Markdown към PDF
home.MarkdownToPDF.desc=Преобразува всеки Markdown файл към PDF home.MarkdownToPDF.desc=Преобразува всеки Markdown файл към PDF
MarkdownToPDF.tags=маркиране,уеб-съдържание,трансформация,преобразуване MarkdownToPDF.tags=маркиране,уеб-съдържание,трансформация,преобразуване
home.PDFToMarkdown.title=PDF to Markdown
home.PDFToMarkdown.desc=Converts any PDF to Markdown
PDFToMarkdown.tags=markup,web-content,transformation,convert,md
home.getPdfInfo.title=Вземете ЦЯЛАТА информация от PDF home.getPdfInfo.title=Вземете ЦЯЛАТА информация от PDF
home.getPdfInfo.desc=Взима всяка възможна информация от PDF файлове home.getPdfInfo.desc=Взима всяка възможна информация от PDF файлове
@@ -649,11 +646,6 @@ MarkdownToPDF.help=Работата е в ход
MarkdownToPDF.credit=Използва WeasyPrint MarkdownToPDF.credit=Използва WeasyPrint
#pdf-to-markdown
PDFToMarkdown.title=PDF To Markdown
PDFToMarkdown.header=PDF To Markdown
PDFToMarkdown.submit=Convert
#url-to-pdf #url-to-pdf
URLToPDF.title=URL към PDF URLToPDF.title=URL към PDF

View File

@@ -452,9 +452,6 @@ home.MarkdownToPDF.title=Markdown a PDF
home.MarkdownToPDF.desc=Converteix qualsevol fitxer Markdown a PDF home.MarkdownToPDF.desc=Converteix qualsevol fitxer Markdown a PDF
MarkdownToPDF.tags=markup,web-content,transformation,convert MarkdownToPDF.tags=markup,web-content,transformation,convert
home.PDFToMarkdown.title=PDF to Markdown
home.PDFToMarkdown.desc=Converts any PDF to Markdown
PDFToMarkdown.tags=markup,web-content,transformation,convert,md
home.getPdfInfo.title=Obteniu Tota la Informació sobre el PDF home.getPdfInfo.title=Obteniu Tota la Informació sobre el PDF
home.getPdfInfo.desc=Recupera tota la informació possible sobre els PDFs home.getPdfInfo.desc=Recupera tota la informació possible sobre els PDFs
@@ -649,11 +646,6 @@ MarkdownToPDF.help=Work in progress
MarkdownToPDF.credit=Uses WeasyPrint MarkdownToPDF.credit=Uses WeasyPrint
#pdf-to-markdown
PDFToMarkdown.title=PDF To Markdown
PDFToMarkdown.header=PDF To Markdown
PDFToMarkdown.submit=Convert
#url-to-pdf #url-to-pdf
URLToPDF.title=URL a PDF URLToPDF.title=URL a PDF

File diff suppressed because it is too large Load Diff

View File

@@ -452,9 +452,6 @@ home.MarkdownToPDF.title=Markdown til PDF
home.MarkdownToPDF.desc=Konverterer enhver Markdown-fil til PDF home.MarkdownToPDF.desc=Konverterer enhver Markdown-fil til PDF
MarkdownToPDF.tags=markup,webindhold,transformation,konvertér MarkdownToPDF.tags=markup,webindhold,transformation,konvertér
home.PDFToMarkdown.title=PDF to Markdown
home.PDFToMarkdown.desc=Converts any PDF to Markdown
PDFToMarkdown.tags=markup,web-content,transformation,convert,md
home.getPdfInfo.title=Få ALLE Oplysninger om PDF home.getPdfInfo.title=Få ALLE Oplysninger om PDF
home.getPdfInfo.desc=Henter alle mulige oplysninger om PDF'er home.getPdfInfo.desc=Henter alle mulige oplysninger om PDF'er
@@ -649,11 +646,6 @@ MarkdownToPDF.help=Arbejde i gang
MarkdownToPDF.credit=Bruger WeasyPrint MarkdownToPDF.credit=Bruger WeasyPrint
#pdf-to-markdown
PDFToMarkdown.title=PDF To Markdown
PDFToMarkdown.header=PDF To Markdown
PDFToMarkdown.submit=Convert
#url-to-pdf #url-to-pdf
URLToPDF.title=URL Til PDF URLToPDF.title=URL Til PDF

View File

@@ -82,7 +82,7 @@ pages=Seiten
loading=Laden... loading=Laden...
addToDoc=In Dokument hinzufügen addToDoc=In Dokument hinzufügen
reset=Zurücksetzen reset=Zurücksetzen
apply=Anwenden apply=Apply
legal.privacy=Datenschutz legal.privacy=Datenschutz
legal.terms=AGB legal.terms=AGB
@@ -249,7 +249,7 @@ database.backupCreated=Datenbanksicherung erfolgreich
database.fileNotFound=Datei nicht gefunden database.fileNotFound=Datei nicht gefunden
database.fileNullOrEmpty=Datei darf nicht null oder leer sein database.fileNullOrEmpty=Datei darf nicht null oder leer sein
database.failedImportFile=Dateiimport fehlgeschlagen database.failedImportFile=Dateiimport fehlgeschlagen
database.notSupported=Diese Funktion ist für deine Datenbankverbindung nicht verfügbar. database.notSupported=This function is not available for your database connection.
session.expired=Ihre Sitzung ist abgelaufen. Bitte laden Sie die Seite neu und versuchen Sie es erneut. session.expired=Ihre Sitzung ist abgelaufen. Bitte laden Sie die Seite neu und versuchen Sie es erneut.
session.refreshPage=Seite aktualisieren session.refreshPage=Seite aktualisieren
@@ -271,7 +271,7 @@ 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,serverseitig 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
@@ -452,9 +452,6 @@ home.MarkdownToPDF.title=Markdown zu PDF
home.MarkdownToPDF.desc=Konvertiert jede Markdown-Datei zu PDF home.MarkdownToPDF.desc=Konvertiert jede Markdown-Datei zu PDF
MarkdownToPDF.tags=markup,web-content,transformation,konvertieren MarkdownToPDF.tags=markup,web-content,transformation,konvertieren
home.PDFToMarkdown.title=PDF zu Markdown
home.PDFToMarkdown.desc=Konvertiert jedes PDF in Markdown
PDFToMarkdown.tags=markup,web inhalt,transformation,konvertieren,md
home.getPdfInfo.title=Alle Informationen anzeigen home.getPdfInfo.title=Alle Informationen anzeigen
home.getPdfInfo.desc=Erfasst alle möglichen Informationen in einer PDF home.getPdfInfo.desc=Erfasst alle möglichen Informationen in einer PDF
@@ -479,9 +476,9 @@ home.autoRedact.title=Automatisch zensieren/schwärzen
home.autoRedact.desc=Automatisches Zensieren (Schwärzen) von Text in einer PDF-Datei basierend auf dem eingegebenen Text home.autoRedact.desc=Automatisches Zensieren (Schwärzen) von Text in einer PDF-Datei basierend auf dem eingegebenen Text
autoRedact.tags=zensieren,schwärzen autoRedact.tags=zensieren,schwärzen
home.redact.title=Manuell zensieren/schwärzen home.redact.title=Manual Redaction
home.redact.desc=Zensiere (Schwärze) eine PDF-Datei durch Auswählen von Text, gezeichneten Formen und/oder ausgewählten Seite(n) home.redact.desc=Redacts a PDF based on selected text, drawn shapes and/or selected page(s)
redact.tags=zensieren,schwärzen,verstecken,verdunkeln,schwarz,markieren,verbergen,manuell redact.tags=Redact,Hide,black out,black,marker,hidden,manual
home.tableExtraxt.title=Tabelle extrahieren home.tableExtraxt.title=Tabelle extrahieren
home.tableExtraxt.desc=Tabelle aus PDF in CSV extrahieren home.tableExtraxt.desc=Tabelle aus PDF in CSV extrahieren
@@ -589,30 +586,30 @@ autoRedact.convertPDFToImageLabel=PDF in PDF-Bild konvertieren (zum Entfernen vo
autoRedact.submitButton=Zensieren autoRedact.submitButton=Zensieren
#redact #redact
redact.title=Manuelles Zensieren (Schwärzen) redact.title=Manual Redaction
redact.header=Manuelles Zensieren (Schwärzen) redact.header=Manual Redaction
redact.submit=Zensieren redact.submit=Redact
redact.textBasedRedaction=Textbasiertes Zensieren redact.textBasedRedaction=Text based Redaction
redact.pageBasedRedaction=Seitenweises Zensieren redact.pageBasedRedaction=Page-based Redaction
redact.convertPDFToImageLabel=Konvertiere PDF zu einem Bild (Zum Entfernen von Text hinter der Box verwenden) redact.convertPDFToImageLabel=Convert PDF to PDF-Image (Used to remove text behind the box)
redact.pageRedactionNumbers.title=Seiten redact.pageRedactionNumbers.title=Pages
redact.pageRedactionNumbers.placeholder=(z.B. 1,2,8 oder 4,7,12-16 oder 2n-1) redact.pageRedactionNumbers.placeholder=(e.g. 1,2,8 or 4,7,12-16 or 2n-1)
redact.redactionColor.title=Zensurfarbe redact.redactionColor.title=Redaction Color
redact.export=Exportieren redact.export=Export
redact.upload=Hochladen redact.upload=Upload
redact.boxRedaction=Rechteck zeichnen zum zensieren redact.boxRedaction=Box draw redaction
redact.zoom=Zoom redact.zoom=Zoom
redact.zoomIn=Vergrößern redact.zoomIn=Zoom in
redact.zoomOut=Verkleinern redact.zoomOut=Zoom out
redact.nextPage=Nächste Seite redact.nextPage=Next Page
redact.previousPage=Vorherige Seite redact.previousPage=Previous Page
redact.toggleSidebar=Seitenleiste umschalten redact.toggleSidebar=Toggle Sidebar
redact.showThumbnails=Vorschau anzeigen redact.showThumbnails=Show Thumbnails
redact.showDocumentOutline=Dokumentübersicht anzeigen (Doppelklick zum Auf/Einklappen aller Elemente) redact.showDocumentOutline=Show Document Outline (double-click to expand/collapse all items)
redact.showAttatchments=Zeige Anhänge redact.showAttatchments=Show Attachments
redact.showLayers=Ebenen anzeigen (Doppelklick, um alle Ebenen auf den Standardzustand zurückzusetzen) redact.showLayers=Show Layers (double-click to reset all layers to the default state)
redact.colourPicker=Farbauswahl redact.colourPicker=Colour Picker
redact.findCurrentOutlineItem=Aktuell gewähltes Element finden redact.findCurrentOutlineItem=Find current outline item
#showJS #showJS
showJS.title=Javascript anzeigen showJS.title=Javascript anzeigen
@@ -649,11 +646,6 @@ MarkdownToPDF.help=In Arbeit
MarkdownToPDF.credit=Verwendet WeasyPrint MarkdownToPDF.credit=Verwendet WeasyPrint
#pdf-to-markdown
PDFToMarkdown.title=PDF zu Markdown
PDFToMarkdown.header=PDF zu Markdown
PDFToMarkdown.submit=Konvertieren
#url-to-pdf #url-to-pdf
URLToPDF.title=URL zu PDF URLToPDF.title=URL zu PDF
@@ -870,7 +862,7 @@ sign.first=Erste Seite
sign.last=Letzte Seite sign.last=Letzte Seite
sign.next=Nächste Seite sign.next=Nächste Seite
sign.previous=Vorherige Seite sign.previous=Vorherige Seite
sign.maintainRatio=Seitenverhältnis beibehalten ein-/ausschalten sign.maintainRatio=Toggle maintain aspect ratio
#repair #repair
@@ -942,7 +934,7 @@ compress.title=Komprimieren
compress.header=PDF komprimieren compress.header=PDF komprimieren
compress.credit=Dieser Dienst verwendet qpdf für die PDF-Komprimierung/-Optimierung. compress.credit=Dieser Dienst verwendet qpdf für die PDF-Komprimierung/-Optimierung.
compress.selectText.1=Manueller Modus Von 1 bis 5 compress.selectText.1=Manueller Modus Von 1 bis 5
compress.selectText.1.1=In den Optimierungsstufen 6 bis 9 wird zusätzlich zur allgemeinen PDF-Komprimierung die Bildauflösung reduziert, um die Dateigröße weiter zu verringern. Höhere Stufen führen zu einer stärkeren Bildkomprimierung (bis zu 50 % der Originalgröße), wodurch eine stärkere Größenreduzierung erreicht wird, die jedoch mit einem möglichen Qualitätsverlust der Bilder einhergeht. compress.selectText.1.1=In optimization levels 6 to 9, in addition to general PDF compression, image resolution is scaled down to further reduce file size. Higher levels result in stronger image compression (up to 50% of the original size), achieving greater size reduction but with potential quality loss in images.
compress.selectText.2=Optimierungsstufe: compress.selectText.2=Optimierungsstufe:
compress.selectText.3=4 (Schrecklich für Textbilder) compress.selectText.3=4 (Schrecklich für Textbilder)
compress.selectText.4=Automatischer Modus Passt die Qualität automatisch an, um das PDF auf die exakte Größe zu bringen compress.selectText.4=Automatischer Modus Passt die Qualität automatisch an, um das PDF auf die exakte Größe zu bringen
@@ -1328,8 +1320,8 @@ splitByChapters.submit=PDF teilen
fileChooser.click=Klicken fileChooser.click=Klicken
fileChooser.or=oder fileChooser.or=oder
fileChooser.dragAndDrop=Drag & Drop fileChooser.dragAndDrop=Drag & Drop
fileChooser.dragAndDropPDF=Drag & Drop PDF-Datei fileChooser.dragAndDropPDF=Drag & Drop PDF file
fileChooser.dragAndDropImage=Drag & Drop Bilddatei fileChooser.dragAndDropImage=Drag & Drop Image file
fileChooser.hoveredDragAndDrop=Datei(en) hierhin Ziehen & Fallenlassen fileChooser.hoveredDragAndDrop=Datei(en) hierhin Ziehen & Fallenlassen
#release notes #release notes

File diff suppressed because it is too large Load Diff

View File

@@ -450,11 +450,8 @@ HTMLToPDF.tags=markup,web-content,transformation,convert
home.MarkdownToPDF.title=Markdown to PDF home.MarkdownToPDF.title=Markdown to PDF
home.MarkdownToPDF.desc=Converts any Markdown file to PDF home.MarkdownToPDF.desc=Converts any Markdown file to PDF
MarkdownToPDF.tags=markup,web-content,transformation,convert,md MarkdownToPDF.tags=markup,web-content,transformation,convert
home.PDFToMarkdown.title=PDF to Markdown
home.PDFToMarkdown.desc=Converts any PDF to Markdown
PDFToMarkdown.tags=markup,web-content,transformation,convert,md
home.getPdfInfo.title=Get ALL Info on PDF home.getPdfInfo.title=Get ALL Info on PDF
home.getPdfInfo.desc=Grabs any and all information possible on PDFs home.getPdfInfo.desc=Grabs any and all information possible on PDFs
@@ -649,11 +646,6 @@ MarkdownToPDF.help=Work in progress
MarkdownToPDF.credit=Uses WeasyPrint MarkdownToPDF.credit=Uses WeasyPrint
#pdf-to-markdown
PDFToMarkdown.title=PDF To Markdown
PDFToMarkdown.header=PDF To Markdown
PDFToMarkdown.submit=Convert
#url-to-pdf #url-to-pdf
URLToPDF.title=URL To PDF URLToPDF.title=URL To PDF

View File

@@ -450,11 +450,8 @@ HTMLToPDF.tags=markup,web-content,transformation,convert
home.MarkdownToPDF.title=Markdown to PDF home.MarkdownToPDF.title=Markdown to PDF
home.MarkdownToPDF.desc=Converts any Markdown file to PDF home.MarkdownToPDF.desc=Converts any Markdown file to PDF
MarkdownToPDF.tags=markup,web-content,transformation,convert,md MarkdownToPDF.tags=markup,web-content,transformation,convert
home.PDFToMarkdown.title=PDF to Markdown
home.PDFToMarkdown.desc=Converts any PDF to Markdown
PDFToMarkdown.tags=markup,web-content,transformation,convert,md
home.getPdfInfo.title=Get ALL Info on PDF home.getPdfInfo.title=Get ALL Info on PDF
home.getPdfInfo.desc=Grabs any and all information possible on PDFs home.getPdfInfo.desc=Grabs any and all information possible on PDFs
@@ -649,11 +646,6 @@ MarkdownToPDF.help=Work in progress
MarkdownToPDF.credit=Uses WeasyPrint MarkdownToPDF.credit=Uses WeasyPrint
#pdf-to-markdown
PDFToMarkdown.title=PDF To Markdown
PDFToMarkdown.header=PDF To Markdown
PDFToMarkdown.submit=Convert
#url-to-pdf #url-to-pdf
URLToPDF.title=URL To PDF URLToPDF.title=URL To PDF

View File

@@ -452,9 +452,6 @@ home.MarkdownToPDF.title=Markdown a PDF
home.MarkdownToPDF.desc=Convierte cualquier archivo Markdown a PDF home.MarkdownToPDF.desc=Convierte cualquier archivo Markdown a PDF
MarkdownToPDF.tags=margen,contenido web,transformación,convertir MarkdownToPDF.tags=margen,contenido web,transformación,convertir
home.PDFToMarkdown.title=PDF to Markdown
home.PDFToMarkdown.desc=Converts any PDF to Markdown
PDFToMarkdown.tags=markup,web-content,transformation,convert,md
home.getPdfInfo.title=Obtener toda la información en PDF home.getPdfInfo.title=Obtener toda la información en PDF
home.getPdfInfo.desc=Obtiene toda la información posible de archivos PDF home.getPdfInfo.desc=Obtiene toda la información posible de archivos PDF
@@ -649,11 +646,6 @@ MarkdownToPDF.help=Tarea en proceso
MarkdownToPDF.credit=Usa WeasyPrint MarkdownToPDF.credit=Usa WeasyPrint
#pdf-to-markdown
PDFToMarkdown.title=PDF To Markdown
PDFToMarkdown.header=PDF To Markdown
PDFToMarkdown.submit=Convert
#url-to-pdf #url-to-pdf
URLToPDF.title=URL a PDF URLToPDF.title=URL a PDF

View File

@@ -452,9 +452,6 @@ home.MarkdownToPDF.title=Markdown PDF-ra
home.MarkdownToPDF.desc=Bihurtu Markdown fitxategi guztiak PDF home.MarkdownToPDF.desc=Bihurtu Markdown fitxategi guztiak PDF
MarkdownToPDF.tags=markup,web-content,transformation,convert MarkdownToPDF.tags=markup,web-content,transformation,convert
home.PDFToMarkdown.title=PDF to Markdown
home.PDFToMarkdown.desc=Converts any PDF to Markdown
PDFToMarkdown.tags=markup,web-content,transformation,convert,md
home.getPdfInfo.title=Lortu informazio guztia PDF-tik home.getPdfInfo.title=Lortu informazio guztia PDF-tik
home.getPdfInfo.desc=Eskuratu PDF fitxategiko Informazio guztia home.getPdfInfo.desc=Eskuratu PDF fitxategiko Informazio guztia
@@ -649,11 +646,6 @@ MarkdownToPDF.help=Lanean
MarkdownToPDF.credit=WeasyPrint darabil MarkdownToPDF.credit=WeasyPrint darabil
#pdf-to-markdown
PDFToMarkdown.title=PDF To Markdown
PDFToMarkdown.header=PDF To Markdown
PDFToMarkdown.submit=Convert
#url-to-pdf #url-to-pdf
URLToPDF.title=URL bat PDF-ra URLToPDF.title=URL bat PDF-ra

View File

@@ -452,9 +452,6 @@ home.MarkdownToPDF.title=مارک‌داون به PDF
home.MarkdownToPDF.desc=تبدیل هر فایل مارک‌داون به PDF home.MarkdownToPDF.desc=تبدیل هر فایل مارک‌داون به PDF
MarkdownToPDF.tags=مارک‌آپ،محتوای وب،تبدیل،تغییر MarkdownToPDF.tags=مارک‌آپ،محتوای وب،تبدیل،تغییر
home.PDFToMarkdown.title=PDF to Markdown
home.PDFToMarkdown.desc=Converts any PDF to Markdown
PDFToMarkdown.tags=markup,web-content,transformation,convert,md
home.getPdfInfo.title=دریافت تمام اطلاعات در مورد PDF home.getPdfInfo.title=دریافت تمام اطلاعات در مورد PDF
home.getPdfInfo.desc=گرفتن هر اطلاعات ممکن در مورد PDF home.getPdfInfo.desc=گرفتن هر اطلاعات ممکن در مورد PDF
@@ -649,11 +646,6 @@ MarkdownToPDF.help=در حال پیشرفت
MarkdownToPDF.credit=از WeasyPrint استفاده می‌کند MarkdownToPDF.credit=از WeasyPrint استفاده می‌کند
#pdf-to-markdown
PDFToMarkdown.title=PDF To Markdown
PDFToMarkdown.header=PDF To Markdown
PDFToMarkdown.submit=Convert
#url-to-pdf #url-to-pdf
URLToPDF.title=URL به PDF URLToPDF.title=URL به PDF

View File

@@ -82,7 +82,7 @@ pages=Pages
loading=Chargement... loading=Chargement...
addToDoc=Ajouter au Document addToDoc=Ajouter au Document
reset=Réinitialiser reset=Réinitialiser
apply=Appliquer apply=Apply
legal.privacy=Politique de Confidentialité legal.privacy=Politique de Confidentialité
legal.terms=Conditions Générales legal.terms=Conditions Générales
@@ -239,20 +239,20 @@ database.creationDate=Date de Création
database.fileSize=Taille du Fichier database.fileSize=Taille du Fichier
database.deleteBackupFile=Supprimer le fichier de sauvegarde database.deleteBackupFile=Supprimer le fichier de sauvegarde
database.importBackupFile=Importer le fichier de sauvegarde database.importBackupFile=Importer le fichier de sauvegarde
database.createBackupFile=Créer un fichier de sauvegarde database.createBackupFile=Create Backup File
database.downloadBackupFile=Télécharger le fichier de sauvegarde database.downloadBackupFile=Télécharger le fichier de sauvegarde
database.info_1=Lors de l'importation des données, il est crucial de garantir la structure correcte. Si vous n'êtes pas sûr de ce que vous faites, sollicitez un avis et un soutien d'un professionnel. Une erreur dans la structure peut entraîner des dysfonctionnements de l'application, allant jusqu'à l'incapacité totale d'exécuter l'application. database.info_1=Lors de l'importation des données, il est crucial de garantir la structure correcte. Si vous n'êtes pas sûr de ce que vous faites, sollicitez un avis et un soutien d'un professionnel. Une erreur dans la structure peut entraîner des dysfonctionnements de l'application, allant jusqu'à l'incapacité totale d'exécuter l'application.
database.info_2=Le nom du fichier ne fait pas de différence lors de l'upload. Il sera renommé ultérieurement selon le format backup_user_yyyyMMddHHmm.sql, assurant ainsi une convention de nommage cohérente. database.info_2=Le nom du fichier ne fait pas de différence lors de l'upload. Il sera renommé ultérieurement selon le format backup_user_yyyyMMddHHmm.sql, assurant ainsi une convention de nommage cohérente.
database.submit=Importer la sauvegarde database.submit=Importer la sauvegarde
database.importIntoDatabaseSuccessed=Importation dans la base de données réussie database.importIntoDatabaseSuccessed=Importation dans la base de données réussie
database.backupCreated=Sauvegarde de la base de donnée réussie database.backupCreated=Database backup successful
database.fileNotFound=Fichier introuvable database.fileNotFound=File not Found
database.fileNullOrEmpty=Fichier ne peut pas être null ou vide database.fileNullOrEmpty=Fichier ne peut pas être null ou vide
database.failedImportFile=Échec de l'imporation du fichier database.failedImportFile=Failed Import File
database.notSupported=Cette fonctionnalité n'est pas supportée avec votre base de donnée database.notSupported=This function is not available for your database connection.
session.expired=Votre session a expiré. Veuillez recharger la page et réessayer. session.expired=Votre session a expiré. Veuillez recharger la page et réessayer.
session.refreshPage=Rafraichir la page session.refreshPage=Refresh Page
############# #############
# HOME-PAGE # # HOME-PAGE #
@@ -452,9 +452,6 @@ home.MarkdownToPDF.title=Markdown en PDF
home.MarkdownToPDF.desc=Convertissez n'importe quel fichier Markdown en PDF. home.MarkdownToPDF.desc=Convertissez n'importe quel fichier Markdown en PDF.
MarkdownToPDF.tags=markdown,markup,contenu Web,transformation,convert MarkdownToPDF.tags=markdown,markup,contenu Web,transformation,convert
home.PDFToMarkdown.title=PDF to Markdown
home.PDFToMarkdown.desc=Converts any PDF to Markdown
PDFToMarkdown.tags=markup,web-content,transformation,convert,md
home.getPdfInfo.title=Récupérer les informations home.getPdfInfo.title=Récupérer les informations
home.getPdfInfo.desc=Récupérez toutes les informations possibles sur un PDF. home.getPdfInfo.desc=Récupérez toutes les informations possibles sur un PDF.
@@ -479,8 +476,8 @@ home.autoRedact.title=Caviarder automatiquement
home.autoRedact.desc=Caviardez automatiquement les informations sensibles d'un PDF. home.autoRedact.desc=Caviardez automatiquement les informations sensibles d'un PDF.
autoRedact.tags=caviarder,redact,auto autoRedact.tags=caviarder,redact,auto
home.redact.title=Rédaction manuelle home.redact.title=Manual Redaction
home.redact.desc=Rédiger un PDF en fonction de texte sélectionné, formes dessinées et/ou des pages sélectionnées. home.redact.desc=Redacts a PDF based on selected text, drawn shapes and/or selected page(s)
redact.tags=Redact,Hide,black out,black,marker,hidden,manual redact.tags=Redact,Hide,black out,black,marker,hidden,manual
home.tableExtraxt.title=PDF en CSV home.tableExtraxt.title=PDF en CSV
@@ -589,30 +586,30 @@ autoRedact.convertPDFToImageLabel=Convertir un PDF en PDF-Image (utilisé pour s
autoRedact.submitButton=Caviarder autoRedact.submitButton=Caviarder
#redact #redact
redact.title=Rédaction manuelle redact.title=Manual Redaction
redact.header=Rédaction manuelle redact.header=Manual Redaction
redact.submit=Rédiger redact.submit=Redact
redact.textBasedRedaction=Rédaction en fonction de texte redact.textBasedRedaction=Text based Redaction
redact.pageBasedRedaction=Rédaction en fonction de pages redact.pageBasedRedaction=Page-based Redaction
redact.convertPDFToImageLabel=Convertir en PDF-Image (pour supprimer le texte derrière le rectangle) redact.convertPDFToImageLabel=Convert PDF to PDF-Image (Used to remove text behind the box)
redact.pageRedactionNumbers.title=Pages redact.pageRedactionNumbers.title=Pages
redact.pageRedactionNumbers.placeholder=(ex: 1,2,8 ou 4,7,12-16 ou 2n-1) redact.pageRedactionNumbers.placeholder=(e.g. 1,2,8 or 4,7,12-16 or 2n-1)
redact.redactionColor.title=Couleur redact.redactionColor.title=Redaction Color
redact.export=Exporter redact.export=Export
redact.upload=Téléverser redact.upload=Upload
redact.boxRedaction=Dessiner le rectangle à rédiger redact.boxRedaction=Box draw redaction
redact.zoom=Zoom redact.zoom=Zoom
redact.zoomIn=Zoom avant redact.zoomIn=Zoom in
redact.zoomOut=Zoom arrière redact.zoomOut=Zoom out
redact.nextPage=Page suivante redact.nextPage=Next Page
redact.previousPage=Page précédente redact.previousPage=Previous Page
redact.toggleSidebar=Toggle Sidebar redact.toggleSidebar=Toggle Sidebar
redact.showThumbnails=Afficher les miniatures redact.showThumbnails=Show Thumbnails
redact.showDocumentOutline=Montrer les contours du document (double-click pour agrandir/réduire tous les éléments) redact.showDocumentOutline=Show Document Outline (double-click to expand/collapse all items)
redact.showAttatchments=Montrer les éléments attachés redact.showAttatchments=Show Attachments
redact.showLayers=Montrer les calques (double-click pour réinitialiser tous les calques à l'état par défaut) redact.showLayers=Show Layers (double-click to reset all layers to the default state)
redact.colourPicker=Sélection de couleur redact.colourPicker=Colour Picker
redact.findCurrentOutlineItem=Trouver l'élément de contour courrant redact.findCurrentOutlineItem=Find current outline item
#showJS #showJS
showJS.title=Afficher le JavaScript showJS.title=Afficher le JavaScript
@@ -649,11 +646,6 @@ MarkdownToPDF.help=(Travail en cours).
MarkdownToPDF.credit=Utilise WeasyPrint. MarkdownToPDF.credit=Utilise WeasyPrint.
#pdf-to-markdown
PDFToMarkdown.title=PDF To Markdown
PDFToMarkdown.header=PDF To Markdown
PDFToMarkdown.submit=Convert
#url-to-pdf #url-to-pdf
URLToPDF.title=URL en PDF URLToPDF.title=URL en PDF
@@ -864,13 +856,13 @@ sign.save=Enregistrer le sceau
sign.personalSigs=Sceaux personnels sign.personalSigs=Sceaux personnels
sign.sharedSigs=Sceaux partagés sign.sharedSigs=Sceaux partagés
sign.noSavedSigs=Aucun sceau enregistré trouvé sign.noSavedSigs=Aucun sceau enregistré trouvé
sign.addToAll=Ajouter à toutes les pages sign.addToAll=Add to all pages
sign.delete=Supprimer sign.delete=Delete
sign.first=Première page sign.first=First page
sign.last=Dernière page sign.last=Last page
sign.next=Page suivante sign.next=Next page
sign.previous=Page précédente sign.previous=Previous page
sign.maintainRatio=Conserver les proportions sign.maintainRatio=Toggle maintain aspect ratio
#repair #repair
@@ -1011,14 +1003,14 @@ multiTool.undo=Undo
multiTool.redo=Redo multiTool.redo=Redo
#decrypt #decrypt
decrypt.passwordPrompt=Ce fichier est protégé par un mot de passe. Veuillez saisir le mot de passe : decrypt.passwordPrompt=This file is password-protected. Please enter the password:
decrypt.cancelled=Operation annulée pour le PDF: {0} decrypt.cancelled=Operation cancelled for PDF: {0}
decrypt.noPassword=Pas de mot de passe fourni pour le PDF chiffré : {0} decrypt.noPassword=No password provided for encrypted PDF: {0}
decrypt.invalidPassword=Veuillez réessayer avec le bon mot de passe decrypt.invalidPassword=Please try again with the correct password.
decrypt.invalidPasswordHeader=Mauvais mot de passe ou chiffrement non supporté pour le PDF : {0} decrypt.invalidPasswordHeader=Incorrect password or unsupported encryption for PDF: {0}
decrypt.unexpectedError=Une erreur est survenue lors de traitement du fichier. Veuillez essayer de nouveau. decrypt.unexpectedError=There was an error processing the file. Please try again.
decrypt.serverError=Erreur du serveur lors du déchiffrement : {0} decrypt.serverError=Server error while decrypting: {0}
decrypt.success=Fichier déchiffré avec succès. decrypt.success=File decrypted successfully.
#multiTool-advert #multiTool-advert
multiTool-advert.message=Cette fonctionnalité est aussi disponible dans la <a href="{0}">page de l'outil multifonction</a>. Allez-y pour une interface page par page améliorée et des fonctionnalités additionnelles ! multiTool-advert.message=Cette fonctionnalité est aussi disponible dans la <a href="{0}">page de l'outil multifonction</a>. Allez-y pour une interface page par page améliorée et des fonctionnalités additionnelles !

View File

@@ -452,9 +452,6 @@ home.MarkdownToPDF.title=Marcáil síos go PDF
home.MarkdownToPDF.desc=Tiontaíonn aon chomhad Markdown go PDF home.MarkdownToPDF.desc=Tiontaíonn aon chomhad Markdown go PDF
MarkdownToPDF.tags=marcáil, ábhar gréasáin, claochlú, tiontú MarkdownToPDF.tags=marcáil, ábhar gréasáin, claochlú, tiontú
home.PDFToMarkdown.title=PDF to Markdown
home.PDFToMarkdown.desc=Converts any PDF to Markdown
PDFToMarkdown.tags=markup,web-content,transformation,convert,md
home.getPdfInfo.title=Faigh GACH Eolas ar PDF home.getPdfInfo.title=Faigh GACH Eolas ar PDF
home.getPdfInfo.desc=Grab aon fhaisnéis agus is féidir ar PDFs home.getPdfInfo.desc=Grab aon fhaisnéis agus is féidir ar PDFs
@@ -649,11 +646,6 @@ MarkdownToPDF.help=Obair idir lámha
MarkdownToPDF.credit=Úsáideann WeasyPrint MarkdownToPDF.credit=Úsáideann WeasyPrint
#pdf-to-markdown
PDFToMarkdown.title=PDF To Markdown
PDFToMarkdown.header=PDF To Markdown
PDFToMarkdown.submit=Convert
#url-to-pdf #url-to-pdf
URLToPDF.title=URL go PDF URLToPDF.title=URL go PDF

View File

@@ -452,9 +452,6 @@ home.MarkdownToPDF.title=Markdown से PDF
home.MarkdownToPDF.desc=किसी भी Markdown फ़ाइल को PDF में बदलें home.MarkdownToPDF.desc=किसी भी Markdown फ़ाइल को PDF में बदलें
MarkdownToPDF.tags=मार्कअप,वेब-सामग्री,रूपांतरण,बदलें MarkdownToPDF.tags=मार्कअप,वेब-सामग्री,रूपांतरण,बदलें
home.PDFToMarkdown.title=PDF to Markdown
home.PDFToMarkdown.desc=Converts any PDF to Markdown
PDFToMarkdown.tags=markup,web-content,transformation,convert,md
home.getPdfInfo.title=PDF की सभी जानकारी प्राप्त करें home.getPdfInfo.title=PDF की सभी जानकारी प्राप्त करें
home.getPdfInfo.desc=PDF से संभव सभी जानकारी प्राप्त करें home.getPdfInfo.desc=PDF से संभव सभी जानकारी प्राप्त करें
@@ -649,11 +646,6 @@ MarkdownToPDF.help=कार्य प्रगति पर है
MarkdownToPDF.credit=WeasyPrint का उपयोग करता है MarkdownToPDF.credit=WeasyPrint का उपयोग करता है
#pdf-to-markdown
PDFToMarkdown.title=PDF To Markdown
PDFToMarkdown.header=PDF To Markdown
PDFToMarkdown.submit=Convert
#url-to-pdf #url-to-pdf
URLToPDF.title=URL से PDF URLToPDF.title=URL से PDF

View File

@@ -452,9 +452,6 @@ home.MarkdownToPDF.title=Markdown u PDF
home.MarkdownToPDF.desc=Pretvara bilo koju Markdown datoteku u PDF home.MarkdownToPDF.desc=Pretvara bilo koju Markdown datoteku u PDF
MarkdownToPDF.tags=oznake,web-sadržaj,transformacija,konvertiranje MarkdownToPDF.tags=oznake,web-sadržaj,transformacija,konvertiranje
home.PDFToMarkdown.title=PDF to Markdown
home.PDFToMarkdown.desc=Converts any PDF to Markdown
PDFToMarkdown.tags=markup,web-content,transformation,convert,md
home.getPdfInfo.title=Dohvati SVE informacije o PDF-u home.getPdfInfo.title=Dohvati SVE informacije o PDF-u
home.getPdfInfo.desc=Dohvaća sve moguće informacije o PDF-ovima home.getPdfInfo.desc=Dohvaća sve moguće informacije o PDF-ovima
@@ -649,11 +646,6 @@ MarkdownToPDF.help=Rad u toku
MarkdownToPDF.credit=Koristi WeasyPrint MarkdownToPDF.credit=Koristi WeasyPrint
#pdf-to-markdown
PDFToMarkdown.title=PDF To Markdown
PDFToMarkdown.header=PDF To Markdown
PDFToMarkdown.submit=Convert
#url-to-pdf #url-to-pdf
URLToPDF.title=URL u PDF URLToPDF.title=URL u PDF

View File

@@ -452,9 +452,6 @@ home.MarkdownToPDF.title=Markdown konvertálása PDF-be
home.MarkdownToPDF.desc=Markdown fájl konvertálása PDF-be home.MarkdownToPDF.desc=Markdown fájl konvertálása PDF-be
MarkdownToPDF.tags=jelölőnyelv,webtartalom,átalakítás,konvertálás MarkdownToPDF.tags=jelölőnyelv,webtartalom,átalakítás,konvertálás
home.PDFToMarkdown.title=PDF to Markdown
home.PDFToMarkdown.desc=Converts any PDF to Markdown
PDFToMarkdown.tags=markup,web-content,transformation,convert,md
home.getPdfInfo.title=PDF összes információjának lekérése home.getPdfInfo.title=PDF összes információjának lekérése
home.getPdfInfo.desc=Minden elérhető információ lekérése PDF-ekről home.getPdfInfo.desc=Minden elérhető információ lekérése PDF-ekről
@@ -649,11 +646,6 @@ MarkdownToPDF.help=Fejlesztés alatt
MarkdownToPDF.credit=WeasyPrint használatával MarkdownToPDF.credit=WeasyPrint használatával
#pdf-to-markdown
PDFToMarkdown.title=PDF To Markdown
PDFToMarkdown.header=PDF To Markdown
PDFToMarkdown.submit=Convert
#url-to-pdf #url-to-pdf
URLToPDF.title=URL konvertálása PDF-be URLToPDF.title=URL konvertálása PDF-be

View File

@@ -452,9 +452,6 @@ home.MarkdownToPDF.title=Penurunan harga ke PDF
home.MarkdownToPDF.desc=Mengonversi berkas Markdown apa pun ke PDF home.MarkdownToPDF.desc=Mengonversi berkas Markdown apa pun ke PDF
MarkdownToPDF.tags=markup, konten web, transformasi, konversi MarkdownToPDF.tags=markup, konten web, transformasi, konversi
home.PDFToMarkdown.title=PDF to Markdown
home.PDFToMarkdown.desc=Converts any PDF to Markdown
PDFToMarkdown.tags=markup,web-content,transformation,convert,md
home.getPdfInfo.title=Dapatkan Semua Info tentang PDF home.getPdfInfo.title=Dapatkan Semua Info tentang PDF
home.getPdfInfo.desc=Mengambil setiap dan semua informasi yang mungkin ada pada PDF home.getPdfInfo.desc=Mengambil setiap dan semua informasi yang mungkin ada pada PDF
@@ -649,11 +646,6 @@ MarkdownToPDF.help=Pekerjaan sedang berlangsung
MarkdownToPDF.credit=Menggunakan WeasyPrint MarkdownToPDF.credit=Menggunakan WeasyPrint
#pdf-to-markdown
PDFToMarkdown.title=PDF To Markdown
PDFToMarkdown.header=PDF To Markdown
PDFToMarkdown.submit=Convert
#url-to-pdf #url-to-pdf
URLToPDF.title=URL ke PDF URLToPDF.title=URL ke PDF

View File

@@ -452,9 +452,6 @@ home.MarkdownToPDF.title=Markdown in PDF
home.MarkdownToPDF.desc=Converte qualsiasi file Markdown in PDF home.MarkdownToPDF.desc=Converte qualsiasi file Markdown in PDF
MarkdownToPDF.tags=markup,contenuto web,trasformazione,conversione MarkdownToPDF.tags=markup,contenuto web,trasformazione,conversione
home.PDFToMarkdown.title=PDF in Markdown
home.PDFToMarkdown.desc=Converte qualsiasi PDF in Markdown
PDFToMarkdown.tags=markup,contenuto-web,trasformazione,convertire,md
home.getPdfInfo.title=Ottieni TUTTE le informazioni in PDF home.getPdfInfo.title=Ottieni TUTTE le informazioni in PDF
home.getPdfInfo.desc=Raccogli tutte le informazioni possibili sui PDF home.getPdfInfo.desc=Raccogli tutte le informazioni possibili sui PDF
@@ -649,11 +646,6 @@ MarkdownToPDF.help=Conversione in corso
MarkdownToPDF.credit=Utilizza WeasyPrint MarkdownToPDF.credit=Utilizza WeasyPrint
#pdf-to-markdown
PDFToMarkdown.title=PDF in Markdown
PDFToMarkdown.header=PDF in Markdown
PDFToMarkdown.submit=Converti
#url-to-pdf #url-to-pdf
URLToPDF.title=URL a PDF URLToPDF.title=URL a PDF

View File

@@ -452,9 +452,6 @@ home.MarkdownToPDF.title=MarkdownをPDFに変換
home.MarkdownToPDF.desc=あらゆるMarkdownファイルをPDFに変換します。 home.MarkdownToPDF.desc=あらゆるMarkdownファイルをPDFに変換します。
MarkdownToPDF.tags=markup,web-content,transformation,convert MarkdownToPDF.tags=markup,web-content,transformation,convert
home.PDFToMarkdown.title=PDF to Markdown
home.PDFToMarkdown.desc=Converts any PDF to Markdown
PDFToMarkdown.tags=markup,web-content,transformation,convert,md
home.getPdfInfo.title=PDFのすべての情報を入手 home.getPdfInfo.title=PDFのすべての情報を入手
home.getPdfInfo.desc=PDFのあらゆる情報を取得します。 home.getPdfInfo.desc=PDFのあらゆる情報を取得します。
@@ -649,11 +646,6 @@ MarkdownToPDF.help=処理中
MarkdownToPDF.credit=WeasyPrintを使用 MarkdownToPDF.credit=WeasyPrintを使用
#pdf-to-markdown
PDFToMarkdown.title=PDF To Markdown
PDFToMarkdown.header=PDF To Markdown
PDFToMarkdown.submit=Convert
#url-to-pdf #url-to-pdf
URLToPDF.title=URLをPDFに変換 URLToPDF.title=URLをPDFに変換

File diff suppressed because it is too large Load Diff

View File

@@ -452,9 +452,6 @@ home.MarkdownToPDF.title=Markdown naar PDF
home.MarkdownToPDF.desc=Zet Markdown-bestand om naar PDF home.MarkdownToPDF.desc=Zet Markdown-bestand om naar PDF
MarkdownToPDF.tags=markup,web-inhoud,transformatie,omzetten MarkdownToPDF.tags=markup,web-inhoud,transformatie,omzetten
home.PDFToMarkdown.title=PDF to Markdown
home.PDFToMarkdown.desc=Converts any PDF to Markdown
PDFToMarkdown.tags=markup,web-content,transformation,convert,md
home.getPdfInfo.title=Haal ALLE informatie op over PDF home.getPdfInfo.title=Haal ALLE informatie op over PDF
home.getPdfInfo.desc=Haalt alle mogelijke informatie op van PDF's home.getPdfInfo.desc=Haalt alle mogelijke informatie op van PDF's
@@ -649,11 +646,6 @@ MarkdownToPDF.help=In ontwikkeling
MarkdownToPDF.credit=Gebruikt WeasyPrint MarkdownToPDF.credit=Gebruikt WeasyPrint
#pdf-to-markdown
PDFToMarkdown.title=PDF To Markdown
PDFToMarkdown.header=PDF To Markdown
PDFToMarkdown.submit=Convert
#url-to-pdf #url-to-pdf
URLToPDF.title=URL naar PDF URLToPDF.title=URL naar PDF

View File

@@ -452,9 +452,6 @@ home.MarkdownToPDF.title=Markdown til PDF
home.MarkdownToPDF.desc=Konverter hvilken som helst Markdown-fil til PDF home.MarkdownToPDF.desc=Konverter hvilken som helst Markdown-fil til PDF
MarkdownToPDF.tags=markup,web-innhold,transformasjon,konverter MarkdownToPDF.tags=markup,web-innhold,transformasjon,konverter
home.PDFToMarkdown.title=PDF to Markdown
home.PDFToMarkdown.desc=Converts any PDF to Markdown
PDFToMarkdown.tags=markup,web-content,transformation,convert,md
home.getPdfInfo.title=Få ALL informasjon om PDF home.getPdfInfo.title=Få ALL informasjon om PDF
home.getPdfInfo.desc=Fanger opp all tilgjengelig informasjon om PDF-er home.getPdfInfo.desc=Fanger opp all tilgjengelig informasjon om PDF-er
@@ -649,11 +646,6 @@ MarkdownToPDF.help=Arbeid pågår
MarkdownToPDF.credit=Bruker WeasyPrint MarkdownToPDF.credit=Bruker WeasyPrint
#pdf-to-markdown
PDFToMarkdown.title=PDF To Markdown
PDFToMarkdown.header=PDF To Markdown
PDFToMarkdown.submit=Convert
#url-to-pdf #url-to-pdf
URLToPDF.title=URL Til PDF URLToPDF.title=URL Til PDF

View File

@@ -452,9 +452,6 @@ home.MarkdownToPDF.title=Markdown do PDF
home.MarkdownToPDF.desc=Zapisuje dokument Markdown do PDF home.MarkdownToPDF.desc=Zapisuje dokument Markdown do PDF
MarkdownToPDF.tags=znaczniki, treść internetowa, transformacja, konwertowanie MarkdownToPDF.tags=znaczniki, treść internetowa, transformacja, konwertowanie
home.PDFToMarkdown.title=PDF to Markdown
home.PDFToMarkdown.desc=Converts any PDF to Markdown
PDFToMarkdown.tags=markup,web-content,transformation,convert,md
home.getPdfInfo.title=Pobierz informacje o pliku PDF home.getPdfInfo.title=Pobierz informacje o pliku PDF
home.getPdfInfo.desc=Pobiera wszelkie informacje o pliku PDF home.getPdfInfo.desc=Pobiera wszelkie informacje o pliku PDF
@@ -649,11 +646,6 @@ MarkdownToPDF.help=Prace trwają
MarkdownToPDF.credit=Użyj WeasyPrint MarkdownToPDF.credit=Użyj WeasyPrint
#pdf-to-markdown
PDFToMarkdown.title=PDF To Markdown
PDFToMarkdown.header=PDF To Markdown
PDFToMarkdown.submit=Convert
#url-to-pdf #url-to-pdf
URLToPDF.title=URL do PDF URLToPDF.title=URL do PDF

View File

@@ -452,9 +452,6 @@ home.MarkdownToPDF.title=Markdown para PDF
home.MarkdownToPDF.desc=Converte qualquer arquivo Markdown para PDF. home.MarkdownToPDF.desc=Converte qualquer arquivo Markdown para PDF.
MarkdownToPDF.tags=marcação,conteúdo-web,transformação,converter MarkdownToPDF.tags=marcação,conteúdo-web,transformação,converter
home.PDFToMarkdown.title=PDF to Markdown
home.PDFToMarkdown.desc=Converts any PDF to Markdown
PDFToMarkdown.tags=markup,web-content,transformation,convert,md
home.getPdfInfo.title=Obter Informações de um PDF home.getPdfInfo.title=Obter Informações de um PDF
home.getPdfInfo.desc=Obtém informações (metadata) de um PDF. home.getPdfInfo.desc=Obtém informações (metadata) de um PDF.
@@ -649,11 +646,6 @@ MarkdownToPDF.help=Em desenvolvimento.
MarkdownToPDF.credit=Utiliza o WeasyPrint. MarkdownToPDF.credit=Utiliza o WeasyPrint.
#pdf-to-markdown
PDFToMarkdown.title=PDF To Markdown
PDFToMarkdown.header=PDF To Markdown
PDFToMarkdown.submit=Convert
#url-to-pdf #url-to-pdf
URLToPDF.title=Converter URL/Site para PDF URLToPDF.title=Converter URL/Site para PDF

View File

@@ -452,9 +452,6 @@ home.MarkdownToPDF.title=Markdown para PDF
home.MarkdownToPDF.desc=Converte qualquer ficheiro Markdown para PDF home.MarkdownToPDF.desc=Converte qualquer ficheiro Markdown para PDF
MarkdownToPDF.tags=marcação,conteúdo-web,transformação,converter MarkdownToPDF.tags=marcação,conteúdo-web,transformação,converter
home.PDFToMarkdown.title=PDF to Markdown
home.PDFToMarkdown.desc=Converts any PDF to Markdown
PDFToMarkdown.tags=markup,web-content,transformation,convert,md
home.getPdfInfo.title=Obter TODA Informação sobre PDF home.getPdfInfo.title=Obter TODA Informação sobre PDF
home.getPdfInfo.desc=Obtém qualquer e toda informação possível sobre PDFs home.getPdfInfo.desc=Obtém qualquer e toda informação possível sobre PDFs
@@ -649,11 +646,6 @@ MarkdownToPDF.help=Trabalho em progresso
MarkdownToPDF.credit=Usa WeasyPrint MarkdownToPDF.credit=Usa WeasyPrint
#pdf-to-markdown
PDFToMarkdown.title=PDF To Markdown
PDFToMarkdown.header=PDF To Markdown
PDFToMarkdown.submit=Convert
#url-to-pdf #url-to-pdf
URLToPDF.title=URL Para PDF URLToPDF.title=URL Para PDF

View File

@@ -452,9 +452,6 @@ home.MarkdownToPDF.title=Markdown în PDF
home.MarkdownToPDF.desc=Convertește orice fișier Markdown în PDF home.MarkdownToPDF.desc=Convertește orice fișier Markdown în PDF
MarkdownToPDF.tags=markup,conținut-web,transformare,convertește MarkdownToPDF.tags=markup,conținut-web,transformare,convertește
home.PDFToMarkdown.title=PDF to Markdown
home.PDFToMarkdown.desc=Converts any PDF to Markdown
PDFToMarkdown.tags=markup,web-content,transformation,convert,md
home.getPdfInfo.title=Obține TOATE Informațiile despre PDF home.getPdfInfo.title=Obține TOATE Informațiile despre PDF
home.getPdfInfo.desc=Extrage orice și toate informațiile posibile despre PDF-uri home.getPdfInfo.desc=Extrage orice și toate informațiile posibile despre PDF-uri
@@ -649,11 +646,6 @@ MarkdownToPDF.help=Lucrare în curs
MarkdownToPDF.credit=Folosește WeasyPrint MarkdownToPDF.credit=Folosește WeasyPrint
#pdf-to-markdown
PDFToMarkdown.title=PDF To Markdown
PDFToMarkdown.header=PDF To Markdown
PDFToMarkdown.submit=Convert
#url-to-pdf #url-to-pdf
URLToPDF.title=URL în PDF URLToPDF.title=URL în PDF

File diff suppressed because it is too large Load Diff

View File

@@ -452,9 +452,6 @@ home.MarkdownToPDF.title=Markdown do PDF
home.MarkdownToPDF.desc=Konvertuje akýkoľvek Markdown súbor do PDF home.MarkdownToPDF.desc=Konvertuje akýkoľvek Markdown súbor do PDF
MarkdownToPDF.tags=markup, webový obsah, transformácia, konvertovať MarkdownToPDF.tags=markup, webový obsah, transformácia, konvertovať
home.PDFToMarkdown.title=PDF to Markdown
home.PDFToMarkdown.desc=Converts any PDF to Markdown
PDFToMarkdown.tags=markup,web-content,transformation,convert,md
home.getPdfInfo.title=Získať všetky informácie o PDF home.getPdfInfo.title=Získať všetky informácie o PDF
home.getPdfInfo.desc=Získava všetky dostupné informácie o PDF home.getPdfInfo.desc=Získava všetky dostupné informácie o PDF
@@ -649,11 +646,6 @@ MarkdownToPDF.help=Práca prebieha
MarkdownToPDF.credit=Používa WeasyPrint MarkdownToPDF.credit=Používa WeasyPrint
#pdf-to-markdown
PDFToMarkdown.title=PDF To Markdown
PDFToMarkdown.header=PDF To Markdown
PDFToMarkdown.submit=Convert
#url-to-pdf #url-to-pdf
URLToPDF.title=URL do PDF URLToPDF.title=URL do PDF

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More