Compare commits
32 Commits
saml2-sso-
...
saml2-keyc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5ad3cfdd07 | ||
|
|
34ef4c7384 | ||
|
|
1c1bea090d | ||
|
|
f23007515a | ||
|
|
227d18a469 | ||
|
|
84abd60c4f | ||
|
|
09c9944fc3 | ||
|
|
b31564968c | ||
|
|
ca535b0abe | ||
|
|
376ec865b8 | ||
|
|
094ed12b85 | ||
|
|
fe92f99093 | ||
|
|
46a6a585a9 | ||
|
|
8e9acdd053 | ||
|
|
8aadef1412 | ||
|
|
80d80f7d8f | ||
|
|
4132e5b78b | ||
|
|
bd36841094 | ||
|
|
22b727df17 | ||
|
|
6bb2910b2d | ||
|
|
c2236349ac | ||
|
|
320bd14d1e | ||
|
|
9ee5dc3486 | ||
|
|
dfad952612 | ||
|
|
e023b13505 | ||
|
|
2078b75790 | ||
|
|
23bda46653 | ||
|
|
73b87c15cc | ||
|
|
c85463bc18 | ||
|
|
ceeecc37ab | ||
|
|
fec717484f | ||
|
|
85e1716aa2 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -110,7 +110,6 @@ watchedFolders/
|
||||
*.war
|
||||
*.nar
|
||||
*.ear
|
||||
*.zip
|
||||
*.tar.gz
|
||||
*.rar
|
||||
*.db
|
||||
|
||||
@@ -29,7 +29,7 @@ If you would like to add or modify a translation, please see [How to add new lan
|
||||
|
||||
## Docs
|
||||
|
||||
Documentation for Stirling-PDF is handled in a separate repository. Please see [Docs repository](https://github.com/Stirling-Tools/Stirling-Tools.github.io) or use "edit this page"-button at the bottom of each page at [https://stirlingtools.com/docs/](https://stirlingtools.com/docs/).
|
||||
Documentation for Stirling-PDF is handled in a separate repository. Please see [Docs repository](https://github.com/Stirling-Tools/Stirling-Tools.github.io) or use "edit this page"-button at the bottom of each page at [https://docs.stirlingpdf.com/](https://docs.stirlingpdf.com/).
|
||||
|
||||
## Fixing Bugs or Adding a New Feature
|
||||
|
||||
@@ -41,4 +41,4 @@ If, at any point of time, you have a question, please feel free to ask in the sa
|
||||
|
||||
## License
|
||||
|
||||
By contributing to this project, you agree that your contributions will be licensed under the [GPL 3 License](LICENSE). You also acknowledge and agree that your contributions will be included in Stirling-PDF and that they can be relicensed in the future under the MPL 2.0 (Mozilla Public License Version 2.0) license.
|
||||
By contributing to this project, you agree that your contributions will be licensed under the [MIT License](LICENSE).
|
||||
|
||||
557
DeveloperGuide.md
Normal file
557
DeveloperGuide.md
Normal file
@@ -0,0 +1,557 @@
|
||||
# Stirling-PDF Developer Guide
|
||||
|
||||
## 1. Introduction
|
||||
|
||||
Stirling-PDF is a robust, locally hosted web-based PDF manipulation tool. This guide focuses on Docker-based development and testing, which is the recommended approach for working with the full version of Stirling-PDF.
|
||||
|
||||
## 2. Project Overview
|
||||
|
||||
Stirling-PDF is built using:
|
||||
- Spring Boot + Thymeleaf
|
||||
- PDFBox
|
||||
- LibreOffice
|
||||
- OcrMyPdf
|
||||
- HTML, CSS, JavaScript
|
||||
- Docker
|
||||
- PDF.js
|
||||
- PDF-LIB.js
|
||||
- Lombok
|
||||
|
||||
## 3. Development Environment Setup
|
||||
|
||||
### Prerequisites
|
||||
- Docker
|
||||
- Git
|
||||
- Java JDK 17 or later
|
||||
- Gradle 7.0 or later (Included within repo)
|
||||
|
||||
### Setup Steps
|
||||
1. Clone the repository:
|
||||
```
|
||||
git clone https://github.com/Stirling-Tools/Stirling-PDF.git
|
||||
cd Stirling-PDF
|
||||
```
|
||||
|
||||
2. Install Docker and JDK17 if not already installed.
|
||||
|
||||
3. Install a recommended Java IDE such as Eclipse, IntelliJ or VSCode
|
||||
|
||||
4. Lombok Setup
|
||||
Stirling-PDF uses Lombok to reduce boilerplate code. Some IDEs, like Eclipse, don't support Lombok out of the box. To set up Lombok in your development environment:
|
||||
Visit the [Lombok website](https://projectlombok.org/setup/) for installation instructions specific to your IDE.
|
||||
|
||||
5. Add environment variable
|
||||
For local testing you should generally be testing the full 'Security' version of Stirling-PDF to do this you must add the environment flag DOCKER_ENABLE_SECURITY=true to your system and/or IDE build/run step
|
||||
|
||||
|
||||
## 4. Project Structure
|
||||
|
||||
```
|
||||
Stirling-PDF/
|
||||
├── .github/ # GitHub-specific files (workflows, issue templates)
|
||||
├── configs/ # Configuration files used by stirling at runtime (generated at runtime)
|
||||
├── cucumber/ # Cucumber test files
|
||||
│ ├── features/
|
||||
├── customFiles/ # Custom static files and templates (generated at runtime used to replace existing files)
|
||||
├── docs/ # Documentation files
|
||||
├── exampleYmlFiles/ # Example YAML configuration files
|
||||
├── images/ # Image assets
|
||||
├── pipeline/ # Pipeline-related files (generated at runtime)
|
||||
├── scripts/ # Utility scripts
|
||||
├── src/ # Source code
|
||||
│ ├── main/
|
||||
│ │ ├── java/
|
||||
│ │ │ └── stirling/
|
||||
│ │ │ └── software/
|
||||
│ │ │ └── SPDF/
|
||||
│ │ │ ├── config/
|
||||
│ │ │ ├── controller/
|
||||
│ │ │ ├── model/
|
||||
│ │ │ ├── repository/
|
||||
│ │ │ ├── service/
|
||||
│ │ │ └── utils/
|
||||
│ │ └── resources/
|
||||
│ │ ├── static/
|
||||
│ │ │ ├── css/
|
||||
│ │ │ ├── js/
|
||||
│ │ │ └── pdfjs/
|
||||
│ │ └── templates/
|
||||
│ └── test/
|
||||
│ └── java/
|
||||
│ └── stirling/
|
||||
│ └── software/
|
||||
│ └── SPDF/
|
||||
├── build.gradle # Gradle build configuration
|
||||
├── Dockerfile # Main Dockerfile
|
||||
├── Dockerfile-ultra-lite # Dockerfile for ultra-lite version
|
||||
├── Dockerfile-fat # Dockerfile for fat version
|
||||
├── docker-compose.yml # Docker Compose configuration
|
||||
└── test.sh # Test script to deploy all docker versions and run cuke tests
|
||||
```
|
||||
|
||||
## 5. Docker-based Development
|
||||
|
||||
Stirling-PDF offers several Docker versions:
|
||||
- Full: All features included
|
||||
- Ultra-Lite: Basic PDF operations only
|
||||
- Fat: Includes additional libraries and fonts predownloaded
|
||||
|
||||
### Example Docker Compose Files
|
||||
|
||||
Stirling-PDF provides several example Docker Compose files in the `exampleYmlFiles` directory such as :
|
||||
|
||||
- `docker-compose-latest.yml`: Latest version without security features
|
||||
- `docker-compose-latest-security.yml`: Latest version with security features enabled
|
||||
- `docker-compose-latest-fat-security.yml`: Fat version with security features enabled
|
||||
|
||||
These files provide pre-configured setups for different scenarios. For example, here's a snippet from `docker-compose-latest-security.yml`:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
stirling-pdf:
|
||||
container_name: Stirling-PDF-Security
|
||||
image: frooodle/s-pdf:latest
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: 4G
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "curl -f http://localhost:8080/api/v1/info/status | grep -q 'UP' && curl -fL http://localhost:8080/ | grep -q 'Please sign in'"]
|
||||
interval: 5s
|
||||
timeout: 10s
|
||||
retries: 16
|
||||
ports:
|
||||
- "8080:8080"
|
||||
volumes:
|
||||
- /stirling/latest/data:/usr/share/tessdata:rw
|
||||
- /stirling/latest/config:/configs:rw
|
||||
- /stirling/latest/logs:/logs:rw
|
||||
environment:
|
||||
DOCKER_ENABLE_SECURITY: "true"
|
||||
SECURITY_ENABLELOGIN: "true"
|
||||
PUID: 1002
|
||||
PGID: 1002
|
||||
UMASK: "022"
|
||||
SYSTEM_DEFAULTLOCALE: en-US
|
||||
UI_APPNAME: Stirling-PDF
|
||||
UI_HOMEDESCRIPTION: Demo site for Stirling-PDF Latest with Security
|
||||
UI_APPNAMENAVBAR: Stirling-PDF Latest
|
||||
SYSTEM_MAXFILESIZE: "100"
|
||||
METRICS_ENABLED: "true"
|
||||
SYSTEM_GOOGLEVISIBILITY: "true"
|
||||
restart: on-failure:5
|
||||
```
|
||||
|
||||
To use these example files, copy the desired file to your project root and rename it to `docker-compose.yml`, or specify the file explicitly when running Docker Compose:
|
||||
|
||||
```bash
|
||||
docker-compose -f exampleYmlFiles/docker-compose-latest-security.yml up
|
||||
```
|
||||
|
||||
### Building Docker Images
|
||||
|
||||
Stirling-PDF uses different Docker images for various configurations. The build process is controlled by environment variables and uses specific Dockerfile variants. Here's how to build the Docker images:
|
||||
|
||||
1. Set the security environment variable:
|
||||
```bash
|
||||
export DOCKER_ENABLE_SECURITY=false # or true for security-enabled builds
|
||||
```
|
||||
|
||||
2. Build the project with Gradle:
|
||||
```bash
|
||||
./gradlew clean build
|
||||
```
|
||||
|
||||
3. Build the Docker images:
|
||||
|
||||
For the latest version:
|
||||
```bash
|
||||
docker build --no-cache --pull --build-arg VERSION_TAG=alpha -t frooodle/s-pdf:latest -f ./Dockerfile .
|
||||
```
|
||||
|
||||
For the ultra-lite version:
|
||||
```bash
|
||||
docker build --no-cache --pull --build-arg VERSION_TAG=alpha -t frooodle/s-pdf:latest-ultra-lite -f ./Dockerfile-ultra-lite .
|
||||
```
|
||||
|
||||
For the fat version (with security enabled):
|
||||
```bash
|
||||
export DOCKER_ENABLE_SECURITY=true
|
||||
docker build --no-cache --pull --build-arg VERSION_TAG=alpha -t frooodle/s-pdf:latest-fat -f ./Dockerfile-fat .
|
||||
```
|
||||
|
||||
Note: The `--no-cache` and `--pull` flags ensure that the build process uses the latest base images and doesn't use cached layers, which is useful for testing and ensuring reproducible builds. however to improve build times these can often be removed depending on your usecase
|
||||
|
||||
|
||||
|
||||
## 6. Testing
|
||||
|
||||
### Comprehensive Testing Script
|
||||
|
||||
Stirling-PDF provides a `test.sh` script in the root directory. This script builds all versions of Stirling-PDF, checks that each version works, and runs Cucumber tests. It's recommended to run this script before submitting a final pull request.
|
||||
|
||||
To run the test script:
|
||||
|
||||
```bash
|
||||
./test.sh
|
||||
```
|
||||
|
||||
This script performs the following actions:
|
||||
1. Builds all Docker images (full, ultra-lite, fat)
|
||||
2. Runs each version to ensure it starts correctly
|
||||
3. Executes Cucumber tests against main version and ensures feature compatibility, in the event these tests fail your PR will not be merged
|
||||
|
||||
Note: The `test.sh` script will run automatically when you raise a PR. However, it's recommended to run it locally first to save resources and catch any issues early.
|
||||
|
||||
### Full Testing with Docker
|
||||
|
||||
1. Build and run the Docker container per the above instructions:
|
||||
|
||||
2. Access the application at `http://localhost:8080` and manually test all features developed.
|
||||
|
||||
|
||||
### Local Testing (Java and UI Components)
|
||||
|
||||
For quick iterations and development of Java backend, JavaScript, and UI components, you can run and test Stirling-PDF locally without Docker. This approach allows you to work on and verify changes to:
|
||||
|
||||
- Java backend logic
|
||||
- RESTful API endpoints
|
||||
- JavaScript functionality
|
||||
- User interface components and styling
|
||||
- Thymeleaf templates
|
||||
|
||||
To run Stirling-PDF locally:
|
||||
|
||||
1. Compile and run the project using built in IDE methods or by running:
|
||||
```
|
||||
./gradlew bootRun
|
||||
```
|
||||
|
||||
2. Access the application at `http://localhost:8080` in your web browser.
|
||||
|
||||
3. Manually test the features you're working on through the UI.
|
||||
|
||||
4. For API changes, use tools like Postman or curl to test endpoints directly.
|
||||
|
||||
Important notes:
|
||||
- Local testing doesn't include features that depend on external tools like OCRmyPDF, LibreOffice, or Python scripts.
|
||||
- There are currently no automated unit tests. All testing is done manually through the UI or API calls. (You are welcome to add JUnits!)
|
||||
- Always verify your changes in the full Docker environment before submitting pull requests, as some integrations and features will only work in the complete setup.
|
||||
|
||||
|
||||
## 7. Contributing
|
||||
|
||||
1. Fork the repository on GitHub.
|
||||
2. Create a new branch for your feature or bug fix.
|
||||
3. Make your changes and commit them with clear, descriptive messages and ensure any documentation is updated related to your changes.
|
||||
4. Test your changes thoroughly in the Docker environment.
|
||||
5. Run the `test.sh` script to ensure all versions build correctly and pass the Cucumber tests:
|
||||
```bash
|
||||
./test.sh
|
||||
```
|
||||
6. Push your changes to your fork.
|
||||
7. Submit a pull request to the main repository.
|
||||
8. See additional [contributing guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
|
||||
|
||||
When you raise a PR:
|
||||
- The `test.sh` script will run automatically against your PR.
|
||||
- The PR checks will verify versioning and dependency updates.
|
||||
- Documentation will be automatically updated for dependency changes.
|
||||
- Security issues will be checked using Snyk and PixeeBot.
|
||||
|
||||
Address any issues that arise from these checks before finalizing your pull request.
|
||||
|
||||
## 8. API Documentation
|
||||
|
||||
API documentation is available at `/swagger-ui/index.html` when running the application. You can also view the latest API documentation [here](https://app.swaggerhub.com/apis-docs/Stirling-Tools/Stirling-PDF/).
|
||||
|
||||
## 9. Customization
|
||||
|
||||
Stirling-PDF can be customized through environment variables or a `settings.yml` file. Key customization options include:
|
||||
- Application name and branding
|
||||
- Security settings
|
||||
- UI customization
|
||||
- Endpoint management
|
||||
|
||||
When using Docker, pass environment variables using the `-e` flag or in your `docker-compose.yml` file.
|
||||
|
||||
Example:
|
||||
```
|
||||
docker run -p 8080:8080 -e APP_NAME="My PDF Tool" stirling-pdf:full
|
||||
```
|
||||
|
||||
Refer to the main README for a full list of customization options.
|
||||
|
||||
## 10. Language Translations
|
||||
|
||||
For managing language translations that affect multiple files, Stirling-PDF provides a helper script:
|
||||
|
||||
```bash
|
||||
/scripts/replace_translation_line.sh
|
||||
```
|
||||
|
||||
This script helps you make consistent replacements across language files.
|
||||
|
||||
When contributing translations:
|
||||
1. Use the helper script for multi-file changes.
|
||||
2. Ensure all language files are updated consistently.
|
||||
3. The PR checks will verify consistency in language file updates.
|
||||
|
||||
Remember to test your changes thoroughly to ensure they don't break any existing functionality.
|
||||
|
||||
|
||||
|
||||
|
||||
# Code examples
|
||||
|
||||
### Overview of Thymeleaf
|
||||
|
||||
Thymeleaf is a server-side Java HTML template engine. It is used in Stirling-PDF to render dynamic web pages. Thymeleaf integrates heavily with Spring Boot
|
||||
|
||||
### Thymeleaf overview
|
||||
|
||||
In Stirling-PDF, Thymeleaf is used to create HTML templates that are rendered on the server side. These templates are located in the `src/main/resources/templates` directory. Thymeleaf templates use a combination of HTML and special Thymeleaf attributes to dynamically generate content.
|
||||
Some examples of this are
|
||||
```html
|
||||
<th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
|
||||
or
|
||||
<th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
|
||||
```
|
||||
Where it uses the th:block, th: indicating its a special thymeleaf element to be used serverside in generating the html, and block being the actual element type.
|
||||
In this case we are inserting the ``navbar`` entry within the ``fragments/navbar.html`` fragment into the ``th:block`` element.
|
||||
|
||||
They can be more complex such as
|
||||
```html
|
||||
<th:block th:insert="~{fragments/common :: head(title=#{pageExtracter.title}, header=#{pageExtracter.header})}"></th:block>
|
||||
```
|
||||
Which is the same as above but passes the parameters title and header into the fragment common.html to be used in its HTML generation
|
||||
|
||||
Thymeleaf can also be used to loop through objects or pass things from java side into html side.
|
||||
```java
|
||||
@GetMapping
|
||||
public String newFeaturePage(Model model) {
|
||||
model.addAttribute("exampleData", exampleData);
|
||||
return "new-feature";
|
||||
}
|
||||
```
|
||||
in above example if exampleData is a list of plain java objects of class Person and within it you had id, name, age etc. You can reference it like so
|
||||
```html
|
||||
<tbody>
|
||||
<!-- Use th:each to iterate over the list -->
|
||||
<tr th:each="person : ${exampleData}">
|
||||
<td th:text="${person.id}"></td>
|
||||
<td th:text="${person.name}"></td>
|
||||
<td th:text="${person.age}"></td>
|
||||
<td th:text="${person.email}"></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
```
|
||||
This would generate n entries of tr for each person in exampleData
|
||||
|
||||
### Adding a New Feature to the Backend (API)
|
||||
|
||||
1. **Create a New Controller:**
|
||||
- Create a new Java class in the `src/main/java/stirling/software/SPDF/controller/api` directory.
|
||||
- Annotate the class with `@RestController` and `@RequestMapping` to define the API endpoint.
|
||||
- Ensure to add API documentation annotations like `@Tag(name = "General", description = "General APIs")` and `@Operation(summary = "Crops a PDF document", description = "This operation takes an input PDF file and crops it according to the given coordinates. Input:PDF Output:PDF Type:SISO")`.
|
||||
|
||||
```java
|
||||
package stirling.software.SPDF.controller.api;
|
||||
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/new-feature")
|
||||
@Tag(name = "General", description = "General APIs")
|
||||
public class NewFeatureController {
|
||||
|
||||
@GetMapping
|
||||
@Operation(summary = "New Feature", description = "This is a new feature endpoint.")
|
||||
public String newFeature() {
|
||||
return "NewFeatureResponse"; // This refers to the NewFeatureResponse.html template presenting the user with the generated html from that file when they navigate to /api/v1/new-feature
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
2. **Define the Service Layer:** (Not required but often useful)
|
||||
- Create a new service class in the `src/main/java/stirling/software/SPDF/service` directory.
|
||||
- Implement the business logic for the new feature.
|
||||
|
||||
```java
|
||||
package stirling.software.SPDF.service;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class NewFeatureService {
|
||||
|
||||
public String getNewFeatureData() {
|
||||
// Implement business logic here
|
||||
return "New Feature Data";
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
2b. **Integrate the Service with the Controller:**
|
||||
- Autowire the service class in the controller and use it to handle the API request.
|
||||
|
||||
```java
|
||||
package stirling.software.SPDF.controller.api;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import stirling.software.SPDF.service.NewFeatureService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/new-feature")
|
||||
@Tag(name = "General", description = "General APIs")
|
||||
public class NewFeatureController {
|
||||
|
||||
@Autowired
|
||||
private NewFeatureService newFeatureService;
|
||||
|
||||
@GetMapping
|
||||
@Operation(summary = "New Feature", description = "This is a new feature endpoint.")
|
||||
public String newFeature() {
|
||||
return newFeatureService.getNewFeatureData();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Adding a New Feature to the Frontend (UI)
|
||||
|
||||
1. **Create a New Thymeleaf Template:**
|
||||
- Create a new HTML file in the `src/main/resources/templates` directory.
|
||||
- Use Thymeleaf attributes to dynamically generate content.
|
||||
- Use `extract-page.html` as a base example for the HTML template, useful to ensure importing of the general layout, navbar and footer.
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html th:lang="${#locale.language}" th:dir="#{language.direction}" th:data-language="${#locale.toString()}" xmlns:th="https://www.thymeleaf.org">
|
||||
<head>
|
||||
<th:block th:insert="~{fragments/common :: head(title=#{newFeature.title}, header=#{newFeature.header})}"></th:block>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="page-container">
|
||||
<div id="content-wrap">
|
||||
<th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
|
||||
<br><br>
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6 bg-card">
|
||||
<div class="tool-header">
|
||||
<span class="material-symbols-rounded tool-header-icon organize">upload</span>
|
||||
<span class="tool-header-text" th:text="#{newFeature.header}"></span>
|
||||
</div>
|
||||
<form th:action="@{'/api/v1/new-feature'}" method="post" enctype="multipart/form-data">
|
||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='application/pdf')}"></div>
|
||||
<input type="hidden" id="customMode" name="customMode" value="">
|
||||
<div class="mb-3">
|
||||
<label for="featureInput" th:text="#{newFeature.prompt}"></label>
|
||||
<input type="text" class="form-control" id="featureInput" name="featureInput" th:placeholder="#{newFeature.placeholder}" required>
|
||||
</div>
|
||||
|
||||
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{newFeature.submit}"></button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
2. **Create a New Controller for the UI:**
|
||||
- Create a new Java class in the `src/main/java/stirling/software/SPDF/controller/ui` directory.
|
||||
- Annotate the class with `@Controller` and `@RequestMapping` to define the UI endpoint.
|
||||
|
||||
```java
|
||||
package stirling.software.SPDF.controller.ui;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import stirling.software.SPDF.service.NewFeatureService;
|
||||
|
||||
@Controller
|
||||
@RequestMapping("/new-feature")
|
||||
public class NewFeatureUIController {
|
||||
|
||||
@Autowired
|
||||
private NewFeatureService newFeatureService;
|
||||
|
||||
@GetMapping
|
||||
public String newFeaturePage(Model model) {
|
||||
model.addAttribute("newFeatureData", newFeatureService.getNewFeatureData());
|
||||
return "new-feature";
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
3. **Update the Navigation Bar:**
|
||||
- Add a link to the new feature page in the navigation bar.
|
||||
- Update the `src/main/resources/templates/fragments/navbar.html` file.
|
||||
|
||||
```html
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" th:href="@{/new-feature}">New Feature</a>
|
||||
</li>
|
||||
```
|
||||
|
||||
|
||||
## Adding New Translations to Existing Language Files in Stirling-PDF
|
||||
|
||||
When adding a new feature or modifying existing ones in Stirling-PDF, you'll need to add new translation entries to the existing language files. Here's a step-by-step guide:
|
||||
|
||||
### 1. Locate Existing Language Files
|
||||
|
||||
Find the existing `messages.properties` files in the `src/main/resources` directory. You'll see files like:
|
||||
|
||||
- `messages.properties` (default, usually English)
|
||||
- `messages_en_GB.properties`
|
||||
- `messages_fr.properties`
|
||||
- `messages_de.properties`
|
||||
- etc.
|
||||
|
||||
### 2. Add New Translation Entries
|
||||
|
||||
Open each of these files and add your new translation entries. For example, if you're adding a new feature called "PDF Splitter",
|
||||
Use descriptive, hierarchical keys (e.g., `feature.element.description`)
|
||||
you might add:
|
||||
|
||||
```properties
|
||||
pdfSplitter.title=PDF Splitter
|
||||
pdfSplitter.description=Split your PDF into multiple documents
|
||||
pdfSplitter.button.split=Split PDF
|
||||
pdfSplitter.input.pages=Enter page numbers to split
|
||||
```
|
||||
|
||||
Add these entries to the default GB language file and any others you wish, translating the values as appropriate for each language.
|
||||
|
||||
### 3. Use Translations in Thymeleaf Templates
|
||||
|
||||
In your Thymeleaf templates, use the `#{key}` syntax to reference the new translations:
|
||||
|
||||
```html
|
||||
<h1 th:text="#{pdfSplitter.title}">PDF Splitter</h1>
|
||||
<p th:text="#{pdfSplitter.description}">Split your PDF into multiple documents</p>
|
||||
<input type="text" th:placeholder="#{pdfSplitter.input.pages}">
|
||||
<button th:text="#{pdfSplitter.button.split}">Split PDF</button>
|
||||
```
|
||||
|
||||
|
||||
|
||||
Remember, never hard-code text in your templates or Java code. Always use translation keys to ensure proper localization.
|
||||
68
README.md
68
README.md
@@ -172,42 +172,42 @@ Stirling PDF currently supports 38!
|
||||
|
||||
| Language | Progress |
|
||||
| ------------------------------------------- | -------------------------------------- |
|
||||
| Arabic (العربية) (ar_AR) |  |
|
||||
| Basque (Euskara) (eu_ES) |  |
|
||||
| Bulgarian (Български) (bg_BG) |  |
|
||||
| Catalan (Català) (ca_CA) |  |
|
||||
| Croatian (Hrvatski) (hr_HR) |  |
|
||||
| Czech (Česky) (cs_CZ) |  |
|
||||
| Danish (Dansk) (da_DK) |  |
|
||||
| Dutch (Nederlands) (nl_NL) |  |
|
||||
| Arabic (العربية) (ar_AR) |  |
|
||||
| Basque (Euskara) (eu_ES) |  |
|
||||
| Bulgarian (Български) (bg_BG) |  |
|
||||
| Catalan (Català) (ca_CA) |  |
|
||||
| Croatian (Hrvatski) (hr_HR) |  |
|
||||
| Czech (Česky) (cs_CZ) |  |
|
||||
| Danish (Dansk) (da_DK) |  |
|
||||
| Dutch (Nederlands) (nl_NL) |  |
|
||||
| English (English) (en_GB) |  |
|
||||
| English (US) (en_US) |  |
|
||||
| French (Français) (fr_FR) |  |
|
||||
| German (Deutsch) (de_DE) |  |
|
||||
| Greek (Ελληνικά) (el_GR) |  |
|
||||
| Hindi (हिंदी) (hi_IN) |  |
|
||||
| Hungarian (Magyar) (hu_HU) |  |
|
||||
| Indonesia (Bahasa Indonesia) (id_ID) |  |
|
||||
| Irish (Gaeilge) (ga_IE) |  |
|
||||
| Italian (Italiano) (it_IT) |  |
|
||||
| Japanese (日本語) (ja_JP) |  |
|
||||
| Korean (한국어) (ko_KR) |  |
|
||||
| Norwegian (Norsk) (no_NB) |  |
|
||||
| Polish (Polski) (pl_PL) |  |
|
||||
| Portuguese (Português) (pt_PT) |  |
|
||||
| Portuguese Brazilian (Português) (pt_BR) |  |
|
||||
| Romanian (Română) (ro_RO) |  |
|
||||
| Russian (Русский) (ru_RU) |  |
|
||||
| Serbian Latin alphabet (Srpski) (sr_LATN_RS) |  |
|
||||
| Simplified Chinese (简体中文) (zh_CN) |  |
|
||||
| Slovakian (Slovensky) (sk_SK) |  |
|
||||
| Spanish (Español) (es_ES) |  |
|
||||
| Swedish (Svenska) (sv_SE) |  |
|
||||
| Thai (ไทย) (th_TH) |  |
|
||||
| Traditional Chinese (繁體中文) (zh_TW) |  |
|
||||
| Turkish (Türkçe) (tr_TR) |  |
|
||||
| Ukrainian (Українська) (uk_UA) |  |
|
||||
| Vietnamese (Tiếng Việt) (vi_VN) |  |
|
||||
| French (Français) (fr_FR) |  |
|
||||
| German (Deutsch) (de_DE) |  |
|
||||
| Greek (Ελληνικά) (el_GR) |  |
|
||||
| Hindi (हिंदी) (hi_IN) |  |
|
||||
| Hungarian (Magyar) (hu_HU) |  |
|
||||
| Indonesia (Bahasa Indonesia) (id_ID) |  |
|
||||
| Irish (Gaeilge) (ga_IE) |  |
|
||||
| Italian (Italiano) (it_IT) |  |
|
||||
| Japanese (日本語) (ja_JP) |  |
|
||||
| Korean (한국어) (ko_KR) |  |
|
||||
| Norwegian (Norsk) (no_NB) |  |
|
||||
| Polish (Polski) (pl_PL) |  |
|
||||
| Portuguese (Português) (pt_PT) |  |
|
||||
| Portuguese Brazilian (Português) (pt_BR) |  |
|
||||
| Romanian (Română) (ro_RO) |  |
|
||||
| Russian (Русский) (ru_RU) |  |
|
||||
| Serbian Latin alphabet (Srpski) (sr_LATN_RS) |  |
|
||||
| Simplified Chinese (简体中文) (zh_CN) |  |
|
||||
| Slovakian (Slovensky) (sk_SK) |  |
|
||||
| Spanish (Español) (es_ES) |  |
|
||||
| Swedish (Svenska) (sv_SE) |  |
|
||||
| Thai (ไทย) (th_TH) |  |
|
||||
| Traditional Chinese (繁體中文) (zh_TW) |  |
|
||||
| Turkish (Türkçe) (tr_TR) |  |
|
||||
| Ukrainian (Українська) (uk_UA) |  |
|
||||
| Vietnamese (Tiếng Việt) (vi_VN) |  |
|
||||
|
||||
## Contributing (creating issues, translations, fixing bugs, etc.)
|
||||
|
||||
|
||||
24
build.gradle
24
build.gradle
@@ -16,13 +16,13 @@ ext {
|
||||
springBootVersion = "3.3.4"
|
||||
pdfboxVersion = "3.0.3"
|
||||
logbackVersion = "1.5.7"
|
||||
imageioVersion = "3.11.0"
|
||||
imageioVersion = "3.12.0"
|
||||
lombokVersion = "1.18.34"
|
||||
bouncycastleVersion = "1.78.1"
|
||||
}
|
||||
|
||||
group = "stirling.software"
|
||||
version = "0.29.0"
|
||||
version = "0.30.0"
|
||||
|
||||
java {
|
||||
// 17 is lowest but we support and recommend 21
|
||||
@@ -32,11 +32,9 @@ java {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
maven { url "https://jitpack.io" }
|
||||
maven {
|
||||
url "https://build.shibboleth.net/nexus/content/repositories/releases/"
|
||||
}
|
||||
maven { url "https://build.shibboleth.net/nexus/content/repositories/releases/" }
|
||||
maven {
|
||||
url "https://build.shibboleth.net/maven/releases/"
|
||||
url 'https://build.shibboleth.net/maven/releases'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,6 +132,8 @@ dependencies {
|
||||
|
||||
implementation "org.springframework.boot:spring-boot-starter-thymeleaf:$springBootVersion"
|
||||
implementation 'com.posthog.java:posthog:1.1.1'
|
||||
implementation 'com.googlecode.owasp-java-html-sanitizer:owasp-java-html-sanitizer:20240325.1'
|
||||
|
||||
|
||||
if (System.getenv("DOCKER_ENABLE_SECURITY") != "false") {
|
||||
implementation "org.springframework.boot:spring-boot-starter-security:$springBootVersion"
|
||||
@@ -146,12 +146,20 @@ dependencies {
|
||||
//2.2.x requires rebuild of DB file.. need migration path
|
||||
runtimeOnly "com.h2database:h2:2.1.214"
|
||||
// implementation "com.h2database:h2:2.2.224"
|
||||
constraints {
|
||||
implementation "org.opensaml:opensaml-core"
|
||||
implementation "org.opensaml:opensaml-saml-api"
|
||||
implementation "org.opensaml:opensaml-saml-impl"
|
||||
}
|
||||
implementation "org.springframework.security:spring-security-saml2-service-provider"
|
||||
|
||||
implementation 'com.coveo:saml-client:5.0.0'
|
||||
}
|
||||
|
||||
testImplementation "org.springframework.boot:spring-boot-starter-test:$springBootVersion"
|
||||
|
||||
// Batik
|
||||
implementation "org.apache.xmlgraphics:batik-all:1.17"
|
||||
implementation "org.apache.xmlgraphics:batik-all:1.18"
|
||||
|
||||
// TwelveMonkeys
|
||||
runtimeOnly "com.twelvemonkeys.imageio:imageio-batik:$imageioVersion"
|
||||
@@ -193,7 +201,7 @@ dependencies {
|
||||
implementation "org.bouncycastle:bcprov-jdk18on:$bouncycastleVersion"
|
||||
implementation "org.bouncycastle:bcpkix-jdk18on:$bouncycastleVersion"
|
||||
implementation "org.springframework.boot:spring-boot-starter-actuator:$springBootVersion"
|
||||
implementation "io.micrometer:micrometer-core:1.13.4"
|
||||
implementation "io.micrometer:micrometer-core:1.13.6"
|
||||
implementation group: "com.google.zxing", name: "core", version: "3.5.3"
|
||||
// https://mvnrepository.com/artifact/org.commonmark/commonmark
|
||||
implementation "org.commonmark:commonmark:0.23.0"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
apiVersion: v2
|
||||
appVersion: 0.29.0
|
||||
appVersion: 0.30.0
|
||||
description: locally hosted web application that allows you to perform various operations
|
||||
on PDF files
|
||||
home: https://github.com/Stirling-Tools/Stirling-PDF
|
||||
|
||||
11
cucumber/exampleFiles/example.html
Normal file
11
cucumber/exampleFiles/example.html
Normal file
@@ -0,0 +1,11 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<body>
|
||||
|
||||
<h1>My First Heading</h1>
|
||||
|
||||
<p>My first paragraph.</p>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
16
cucumber/exampleFiles/example.md
Normal file
16
cucumber/exampleFiles/example.md
Normal file
@@ -0,0 +1,16 @@
|
||||
header
|
||||
============
|
||||
|
||||
Header2
|
||||
------------
|
||||
text
|
||||
|
||||
text2
|
||||
|
||||
## **PDF Features**
|
||||
|
||||
### **Page Operations**
|
||||
|
||||
- View and modify PDFs - View multi page PDFs with custom viewing sorting and searching. Plus on page edit features like annotate, draw and adding text and images. (Using PDF.js with Joxit and Liberation.Liberation fonts)
|
||||
- Full interactive GUI for merging/splitting/rotating/moving PDFs and their pages.
|
||||
- Merge multiple PDFs together into a single resultant file.
|
||||
BIN
cucumber/exampleFiles/example_html.zip
Normal file
BIN
cucumber/exampleFiles/example_html.zip
Normal file
Binary file not shown.
@@ -218,6 +218,28 @@ Feature: API Validation
|
||||
| .odt |
|
||||
| .pptx |
|
||||
| .rtf |
|
||||
|
||||
|
||||
|
||||
@calibre @positive @htmltopdf
|
||||
Scenario: Convert HTML to PDF
|
||||
Given I use an example file at "exampleFiles/example.html" as parameter "fileInput"
|
||||
When I send the API request to the endpoint "/api/v1/convert/html/pdf"
|
||||
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 ".pdf"
|
||||
|
||||
@calibre @positive @zippedhtmltopdf
|
||||
Scenario: Convert zipped HTML to PDF
|
||||
Given I use an example file at "exampleFiles/example_html.zip" as parameter "fileInput"
|
||||
When I send the API request to the endpoint "/api/v1/convert/html/pdf"
|
||||
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 ".pdf"
|
||||
|
||||
@calibre @positive @markdowntopdf
|
||||
Scenario: Convert Markdown to PDF
|
||||
Given I use an example file at "exampleFiles/example.md" as parameter "fileInput"
|
||||
When I send the API request to the endpoint "/api/v1/convert/markdown/pdf"
|
||||
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 ".pdf"
|
||||
|
||||
@@ -7,7 +7,7 @@ services:
|
||||
limits:
|
||||
memory: 4G
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "curl -f http://localhost:8080/api/v1/info/status | grep -q 'UP' && curl -fL http://localhost:8080/ | grep -q 'Please sign in'"]
|
||||
test: ["CMD-SHELL", "curl -f http://localhost:8080/api/v1/info/status | grep -q 'UP'"]
|
||||
interval: 5s
|
||||
timeout: 10s
|
||||
retries: 16
|
||||
@@ -19,7 +19,7 @@ services:
|
||||
- /stirling/latest/logs:/logs:rw
|
||||
environment:
|
||||
DOCKER_ENABLE_SECURITY: "true"
|
||||
SECURITY_ENABLELOGIN: "true"
|
||||
SECURITY_ENABLELOGIN: "false"
|
||||
PUID: 1002
|
||||
PGID: 1002
|
||||
UMASK: "022"
|
||||
|
||||
@@ -5,6 +5,7 @@ import java.net.http.HttpClient;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
@@ -12,19 +13,22 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.posthog.java.shaded.org.json.JSONObject;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import stirling.software.SPDF.model.ApplicationProperties;
|
||||
import stirling.software.SPDF.utils.GeneralUtils;
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
public class KeygenLicenseVerifier {
|
||||
private static final String ACCOUNT_ID = "e5430f69-e834-4ae4-befd-b602aae5f372";
|
||||
private static final String PRODUCT_ID = "f9bb2423-62c9-4d39-8def-4fdc5aca751e";
|
||||
private static final String BASE_URL = "https://api.keygen.sh/v1/accounts";
|
||||
private static final ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
// 23:26:20.344 [scheduling-1] INFO s.s.SPDF.EE.KeygenLicenseVerifier -
|
||||
// validateLicenseResponse body:
|
||||
// {"data":{"id":"808ed3c9-584b-46dd-8a80-c9217ef70915","type":"licenses","attributes":{"name":"userCounTest","key":"A7EW-KUPF-PRML-RRVL-HLMP-7THR-F7KE-XF4C","expiry":"2024-10-31T21:39:49.271Z","status":"ACTIVE","uses":0,"suspended":false,"scheme":null,"encrypted":false,"strict":true,"floating":true,"protected":true,"version":null,"maxMachines":1,"maxProcesses":null,"maxUsers":null,"maxCores":null,"maxUses":null,"requireHeartbeat":false,"requireCheckIn":false,"lastValidated":"2024-10-01T22:26:18.121Z","lastCheckIn":null,"nextCheckIn":null,"lastCheckOut":null,"metadata":{"users":10},"created":"2024-10-01T21:39:49.268Z","updated":"2024-10-01T21:39:49.268Z"},"relationships":{"account":{"links":{"related":"/v1/accounts/e5430f69-e834-4ae4-befd-b602aae5f372"},"data":{"type":"accounts","id":"e5430f69-e834-4ae4-befd-b602aae5f372"}},"environment":{"links":{"related":null},"data":null},"product":{"links":{"related":"/v1/accounts/e5430f69-e834-4ae4-befd-b602aae5f372/licenses/808ed3c9-584b-46dd-8a80-c9217ef70915/product"},"data":{"type":"products","id":"f9bb2423-62c9-4d39-8def-4fdc5aca751e"}},"policy":{"links":{"related":"/v1/accounts/e5430f69-e834-4ae4-befd-b602aae5f372/licenses/808ed3c9-584b-46dd-8a80-c9217ef70915/policy"},"data":{"type":"policies","id":"04caef06-9ac2-4084-bf3c-bca4a0d29143"}},"group":{"links":{"related":"/v1/accounts/e5430f69-e834-4ae4-befd-b602aae5f372/licenses/808ed3c9-584b-46dd-8a80-c9217ef70915/group"},"data":null},"owner":{"links":{"related":"/v1/accounts/e5430f69-e834-4ae4-befd-b602aae5f372/licenses/808ed3c9-584b-46dd-8a80-c9217ef70915/owner"},"data":null},"users":{"links":{"related":"/v1/accounts/e5430f69-e834-4ae4-befd-b602aae5f372/licenses/808ed3c9-584b-46dd-8a80-c9217ef70915/users"},"meta":{"count":0}},"machines":{"links":{"related":"/v1/accounts/e5430f69-e834-4ae4-befd-b602aae5f372/licenses/808ed3c9-584b-46dd-8a80-c9217ef70915/machines"},"meta":{"cores":0,"count":0}},"tokens":{"links":{"related":"/v1/accounts/e5430f69-e834-4ae4-befd-b602aae5f372/licenses/808ed3c9-584b-46dd-8a80-c9217ef70915/tokens"}},"entitlements":{"links":{"related":"/v1/accounts/e5430f69-e834-4ae4-befd-b602aae5f372/licenses/808ed3c9-584b-46dd-8a80-c9217ef70915/entitlements"}}},"links":{"self":"/v1/accounts/e5430f69-e834-4ae4-befd-b602aae5f372/licenses/808ed3c9-584b-46dd-8a80-c9217ef70915"}},"meta":{"ts":"2024-10-01T22:26:18.124Z","valid":false,"detail":"fingerprint is not activated (has no associated machines)","code":"NO_MACHINES","scope":{"fingerprint":"example-fingerprint"}}}
|
||||
private final ApplicationProperties applicationProperties;
|
||||
|
||||
@Autowired
|
||||
public KeygenLicenseVerifier(ApplicationProperties applicationProperties) {
|
||||
this.applicationProperties = applicationProperties;
|
||||
}
|
||||
|
||||
public boolean verifyLicense(String licenseKey) {
|
||||
try {
|
||||
@@ -68,7 +72,7 @@ public class KeygenLicenseVerifier {
|
||||
}
|
||||
}
|
||||
|
||||
private static JsonNode validateLicense(String licenseKey, String machineFingerprint)
|
||||
private JsonNode validateLicense(String licenseKey, String machineFingerprint)
|
||||
throws Exception {
|
||||
HttpClient client = HttpClient.newHttpClient();
|
||||
String requestBody =
|
||||
@@ -104,14 +108,24 @@ public class KeygenLicenseVerifier {
|
||||
log.debug("Validation detail: " + detail);
|
||||
log.debug("Validation code: " + code);
|
||||
|
||||
int users =
|
||||
jsonResponse
|
||||
.path("data")
|
||||
.path("attributes")
|
||||
.path("metadata")
|
||||
.path("users")
|
||||
.asInt(0);
|
||||
applicationProperties.getEnterpriseEdition().setMaxUsers(users);
|
||||
log.info(applicationProperties.toString());
|
||||
|
||||
} else {
|
||||
log.error("Error validating license. Status code: " + response.statusCode());
|
||||
}
|
||||
return jsonResponse;
|
||||
}
|
||||
|
||||
private static boolean activateMachine(
|
||||
String licenseKey, String licenseId, String machineFingerprint) throws Exception {
|
||||
private boolean activateMachine(String licenseKey, String licenseId, String machineFingerprint)
|
||||
throws Exception {
|
||||
HttpClient client = HttpClient.newHttpClient();
|
||||
|
||||
String hostname;
|
||||
@@ -184,7 +198,7 @@ public class KeygenLicenseVerifier {
|
||||
}
|
||||
}
|
||||
|
||||
private static String generateMachineFingerprint() {
|
||||
private String generateMachineFingerprint() {
|
||||
return GeneralUtils.generateMachineFingerprint();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,6 @@ public class LicenseKeyChecker {
|
||||
|
||||
private boolean enterpriseEnbaledResult = false;
|
||||
|
||||
// Inject your license service or configuration
|
||||
@Autowired
|
||||
public LicenseKeyChecker(
|
||||
KeygenLicenseVerifier licenseService, ApplicationProperties applicationProperties) {
|
||||
|
||||
@@ -33,11 +33,15 @@ public class SPdfApplication {
|
||||
@Autowired private Environment env;
|
||||
@Autowired ApplicationProperties applicationProperties;
|
||||
|
||||
private static String baseUrlStatic;
|
||||
private static String serverPortStatic;
|
||||
|
||||
@Value("${baseUrl:http://localhost}")
|
||||
private String baseUrl;
|
||||
|
||||
@Value("${server.port:8080}")
|
||||
public void setServerPortStatic(String port) {
|
||||
if (port.equalsIgnoreCase("auto")) {
|
||||
if ("auto".equalsIgnoreCase(port)) {
|
||||
// Use Spring Boot's automatic port assignment (server.port=0)
|
||||
SPdfApplication.serverPortStatic =
|
||||
"0"; // This will let Spring Boot assign an available port
|
||||
@@ -65,12 +69,13 @@ public class SPdfApplication {
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
baseUrlStatic = this.baseUrl;
|
||||
// Check if the BROWSER_OPEN environment variable is set to true
|
||||
String browserOpenEnv = env.getProperty("BROWSER_OPEN");
|
||||
boolean browserOpen = browserOpenEnv != null && "true".equalsIgnoreCase(browserOpenEnv);
|
||||
if (browserOpen) {
|
||||
try {
|
||||
String url = "http://localhost:" + getStaticPort();
|
||||
String url = baseUrl + ":" + getStaticPort();
|
||||
|
||||
String os = System.getProperty("os.name").toLowerCase();
|
||||
Runtime rt = Runtime.getRuntime();
|
||||
@@ -78,9 +83,9 @@ public class SPdfApplication {
|
||||
// For Windows
|
||||
SystemCommand.runCommand(rt, "rundll32 url.dll,FileProtocolHandler " + url);
|
||||
} else if (os.contains("mac")) {
|
||||
rt.exec("open " + url);
|
||||
SystemCommand.runCommand(rt, "open " + url);
|
||||
} else if (os.contains("nix") || os.contains("nux")) {
|
||||
rt.exec("xdg-open " + url);
|
||||
SystemCommand.runCommand(rt, "xdg-open " + url);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("Error opening browser: {}", e.getMessage());
|
||||
@@ -138,10 +143,18 @@ public class SPdfApplication {
|
||||
|
||||
private static void printStartupLogs() {
|
||||
logger.info("Stirling-PDF Started.");
|
||||
String url = "http://localhost:" + getStaticPort();
|
||||
String url = baseUrlStatic + ":" + getStaticPort();
|
||||
logger.info("Navigate to {}", url);
|
||||
}
|
||||
|
||||
public static String getStaticBaseUrl() {
|
||||
return baseUrlStatic;
|
||||
}
|
||||
|
||||
public String getNonStaticBaseUrl() {
|
||||
return baseUrlStatic;
|
||||
}
|
||||
|
||||
public static String getStaticPort() {
|
||||
return serverPortStatic;
|
||||
}
|
||||
|
||||
@@ -1,27 +1,237 @@
|
||||
package stirling.software.SPDF.config.security;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.security.interfaces.RSAPrivateKey;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
|
||||
import org.springframework.security.saml2.provider.service.authentication.Saml2Authentication;
|
||||
import org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler;
|
||||
|
||||
import com.coveo.saml.SamlClient;
|
||||
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import stirling.software.SPDF.SPdfApplication;
|
||||
import stirling.software.SPDF.config.security.saml2.CertificateUtils;
|
||||
import stirling.software.SPDF.config.security.saml2.CustomSaml2AuthenticatedPrincipal;
|
||||
import stirling.software.SPDF.model.ApplicationProperties;
|
||||
import stirling.software.SPDF.model.ApplicationProperties.Security.OAUTH2;
|
||||
import stirling.software.SPDF.model.ApplicationProperties.Security.SAML2;
|
||||
import stirling.software.SPDF.model.Provider;
|
||||
import stirling.software.SPDF.model.provider.UnsupportedProviderException;
|
||||
import stirling.software.SPDF.utils.UrlUtils;
|
||||
|
||||
@Slf4j
|
||||
@AllArgsConstructor
|
||||
public class CustomLogoutSuccessHandler extends SimpleUrlLogoutSuccessHandler {
|
||||
|
||||
private final ApplicationProperties applicationProperties;
|
||||
|
||||
@Override
|
||||
public void onLogoutSuccess(
|
||||
HttpServletRequest request, HttpServletResponse response, Authentication authentication)
|
||||
throws IOException, ServletException {
|
||||
|
||||
if (request.getParameter("userIsDisabled") != null) {
|
||||
getRedirectStrategy()
|
||||
.sendRedirect(request, response, "/login?erroroauth=userIsDisabled");
|
||||
return;
|
||||
if (!response.isCommitted()) {
|
||||
// Handle user logout due to disabled account
|
||||
if (request.getParameter("userIsDisabled") != null) {
|
||||
response.sendRedirect(
|
||||
request.getContextPath() + "/login?erroroauth=userIsDisabled");
|
||||
return;
|
||||
}
|
||||
// Handle OAuth2 authentication error
|
||||
if (request.getParameter("oauth2AuthenticationErrorWeb") != null) {
|
||||
response.sendRedirect(
|
||||
request.getContextPath() + "/login?erroroauth=userAlreadyExistsWeb");
|
||||
return;
|
||||
}
|
||||
if (authentication != null) {
|
||||
// Handle SAML2 logout redirection
|
||||
if (authentication instanceof Saml2Authentication) {
|
||||
getRedirect_saml2(request, response, authentication);
|
||||
return;
|
||||
}
|
||||
// Handle OAuth2 logout redirection
|
||||
else if (authentication instanceof OAuth2AuthenticationToken) {
|
||||
getRedirect_oauth2(request, response, authentication);
|
||||
return;
|
||||
}
|
||||
// Handle Username/Password logout
|
||||
else if (authentication instanceof UsernamePasswordAuthenticationToken) {
|
||||
getRedirectStrategy().sendRedirect(request, response, "/login?logout=true");
|
||||
return;
|
||||
}
|
||||
// Handle unknown authentication types
|
||||
else {
|
||||
log.error(
|
||||
"authentication class unknown: "
|
||||
+ authentication.getClass().getSimpleName());
|
||||
getRedirectStrategy().sendRedirect(request, response, "/login?logout=true");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// Redirect to login page after logout
|
||||
getRedirectStrategy().sendRedirect(request, response, "/login?logout=true");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Redirect for SAML2 authentication logout
|
||||
private void getRedirect_saml2(
|
||||
HttpServletRequest request, HttpServletResponse response, Authentication authentication)
|
||||
throws IOException {
|
||||
|
||||
SAML2 samlConf = applicationProperties.getSecurity().getSaml2();
|
||||
String registrationId = samlConf.getRegistrationId();
|
||||
|
||||
Saml2Authentication samlAuthentication = (Saml2Authentication) authentication;
|
||||
CustomSaml2AuthenticatedPrincipal principal =
|
||||
(CustomSaml2AuthenticatedPrincipal) samlAuthentication.getPrincipal();
|
||||
|
||||
String nameIdValue = principal.getName();
|
||||
|
||||
try {
|
||||
// Read certificate from the resource
|
||||
Resource certificateResource = samlConf.getSpCert();
|
||||
X509Certificate certificate = CertificateUtils.readCertificate(certificateResource);
|
||||
|
||||
List<X509Certificate> certificates = new ArrayList<>();
|
||||
certificates.add(certificate);
|
||||
|
||||
// Construct URLs required for SAML configuration
|
||||
String serverUrl =
|
||||
SPdfApplication.getStaticBaseUrl() + ":" + SPdfApplication.getStaticPort();
|
||||
|
||||
String relyingPartyIdentifier =
|
||||
serverUrl + "/saml2/service-provider-metadata/" + registrationId;
|
||||
|
||||
String assertionConsumerServiceUrl = serverUrl + "/login/saml2/sso/" + registrationId;
|
||||
|
||||
String idpUrl = samlConf.getIdpSingleLogoutUrl();
|
||||
|
||||
String idpIssuer = samlConf.getIdpIssuer();
|
||||
|
||||
// Create SamlClient instance for SAML logout
|
||||
SamlClient samlClient =
|
||||
new SamlClient(
|
||||
relyingPartyIdentifier,
|
||||
assertionConsumerServiceUrl,
|
||||
idpUrl,
|
||||
idpIssuer,
|
||||
certificates,
|
||||
SamlClient.SamlIdpBinding.POST);
|
||||
|
||||
// Read private key for service provider
|
||||
Resource privateKeyResource = samlConf.getPrivateKey();
|
||||
RSAPrivateKey privateKey = CertificateUtils.readPrivateKey(privateKeyResource);
|
||||
|
||||
// Set service provider keys for the SamlClient
|
||||
samlClient.setSPKeys(certificate, privateKey);
|
||||
|
||||
// Redirect to identity provider for logout
|
||||
samlClient.redirectToIdentityProvider(response, null, nameIdValue);
|
||||
} catch (Exception e) {
|
||||
log.error(nameIdValue, e);
|
||||
getRedirectStrategy().sendRedirect(request, response, "/login?logout=true");
|
||||
}
|
||||
}
|
||||
|
||||
// Redirect for OAuth2 authentication logout
|
||||
private void getRedirect_oauth2(
|
||||
HttpServletRequest request, HttpServletResponse response, Authentication authentication)
|
||||
throws IOException {
|
||||
String param = "logout=true";
|
||||
String registrationId = null;
|
||||
String issuer = null;
|
||||
String clientId = null;
|
||||
OAUTH2 oauth = applicationProperties.getSecurity().getOauth2();
|
||||
|
||||
if (authentication instanceof OAuth2AuthenticationToken) {
|
||||
OAuth2AuthenticationToken oauthToken = (OAuth2AuthenticationToken) authentication;
|
||||
registrationId = oauthToken.getAuthorizedClientRegistrationId();
|
||||
|
||||
try {
|
||||
// Get OAuth2 provider details from configuration
|
||||
Provider provider = oauth.getClient().get(registrationId);
|
||||
issuer = provider.getIssuer();
|
||||
clientId = provider.getClientId();
|
||||
} catch (UnsupportedProviderException e) {
|
||||
log.error(e.getMessage());
|
||||
}
|
||||
} else {
|
||||
registrationId = oauth.getProvider() != null ? oauth.getProvider() : "";
|
||||
issuer = oauth.getIssuer();
|
||||
clientId = oauth.getClientId();
|
||||
}
|
||||
String errorMessage = "";
|
||||
// Handle different error scenarios during logout
|
||||
if (request.getParameter("oauth2AuthenticationErrorWeb") != null) {
|
||||
param = "erroroauth=oauth2AuthenticationErrorWeb";
|
||||
} else if ((errorMessage = request.getParameter("error")) != null) {
|
||||
param = "error=" + sanitizeInput(errorMessage);
|
||||
} else if ((errorMessage = request.getParameter("erroroauth")) != null) {
|
||||
param = "erroroauth=" + sanitizeInput(errorMessage);
|
||||
} else if (request.getParameter("oauth2AutoCreateDisabled") != null) {
|
||||
param = "error=oauth2AutoCreateDisabled";
|
||||
} else if (request.getParameter("oauth2_admin_blocked_user") != null) {
|
||||
param = "erroroauth=oauth2_admin_blocked_user";
|
||||
} else if (request.getParameter("userIsDisabled") != null) {
|
||||
param = "erroroauth=userIsDisabled";
|
||||
} else if (request.getParameter("badcredentials") != null) {
|
||||
param = "error=badcredentials";
|
||||
}
|
||||
|
||||
getRedirectStrategy().sendRedirect(request, response, "/login?logout=true");
|
||||
String redirect_url = UrlUtils.getOrigin(request) + "/login?" + param;
|
||||
|
||||
// Redirect based on OAuth2 provider
|
||||
switch (registrationId.toLowerCase()) {
|
||||
case "keycloak":
|
||||
// Add Keycloak specific logout URL if needed
|
||||
String logoutUrl =
|
||||
issuer
|
||||
+ "/protocol/openid-connect/logout"
|
||||
+ "?client_id="
|
||||
+ clientId
|
||||
+ "&post_logout_redirect_uri="
|
||||
+ response.encodeRedirectURL(redirect_url);
|
||||
log.info("Redirecting to Keycloak logout URL: " + logoutUrl);
|
||||
response.sendRedirect(logoutUrl);
|
||||
break;
|
||||
case "github":
|
||||
// Add GitHub specific logout URL if needed
|
||||
String githubLogoutUrl = "https://github.com/logout";
|
||||
log.info("Redirecting to GitHub logout URL: " + githubLogoutUrl);
|
||||
response.sendRedirect(githubLogoutUrl);
|
||||
break;
|
||||
case "google":
|
||||
// Add Google specific logout URL if needed
|
||||
// String googleLogoutUrl =
|
||||
// "https://accounts.google.com/Logout?continue=https://appengine.google.com/_ah/logout?continue="
|
||||
// + response.encodeRedirectURL(redirect_url);
|
||||
log.info("Google does not have a specific logout URL");
|
||||
// log.info("Redirecting to Google logout URL: " + googleLogoutUrl);
|
||||
// response.sendRedirect(googleLogoutUrl);
|
||||
// break;
|
||||
default:
|
||||
String defaultRedirectUrl = request.getContextPath() + "/login?" + param;
|
||||
log.info("Redirecting to default logout URL: " + defaultRedirectUrl);
|
||||
response.sendRedirect(defaultRedirectUrl);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Sanitize input to avoid potential security vulnerabilities
|
||||
private String sanitizeInput(String input) {
|
||||
return input.replaceAll("[^a-zA-Z0-9 ]", "");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,26 +1,38 @@
|
||||
package stirling.software.SPDF.config.security;
|
||||
|
||||
import static org.springframework.security.config.Customizer.withDefaults;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.*;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.security.authentication.AuthenticationProvider;
|
||||
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
|
||||
import org.springframework.security.config.http.SessionCreationPolicy;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistration;
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistrations;
|
||||
import org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository;
|
||||
import org.springframework.security.oauth2.core.user.OAuth2UserAuthority;
|
||||
import org.springframework.security.saml2.core.Saml2X509Credential;
|
||||
import org.springframework.security.saml2.core.Saml2X509Credential.Saml2X509CredentialType;
|
||||
import org.springframework.security.saml2.provider.service.authentication.OpenSaml4AuthenticationProvider;
|
||||
import org.springframework.security.saml2.provider.service.registration.InMemoryRelyingPartyRegistrationRepository;
|
||||
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration;
|
||||
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository;
|
||||
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrations;
|
||||
import org.springframework.security.saml2.provider.service.web.authentication.Saml2WebSsoAuthenticationFilter;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||
@@ -31,13 +43,20 @@ import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import stirling.software.SPDF.config.security.oauth2.CustomOAuth2AuthenticationFailureHandler;
|
||||
import stirling.software.SPDF.config.security.oauth2.CustomOAuth2AuthenticationSuccessHandler;
|
||||
import stirling.software.SPDF.config.security.oauth2.CustomOAuth2LogoutSuccessHandler;
|
||||
import stirling.software.SPDF.config.security.oauth2.CustomOAuth2UserService;
|
||||
import stirling.software.SPDF.config.security.saml.ConvertResponseToAuthentication;
|
||||
import stirling.software.SPDF.config.security.saml.CustomSAMLAuthenticationFailureHandler;
|
||||
import stirling.software.SPDF.config.security.saml.CustomSAMLAuthenticationSuccessHandler;
|
||||
import stirling.software.SPDF.config.security.saml2.CertificateUtils;
|
||||
import stirling.software.SPDF.config.security.saml2.CustomSaml2AuthenticationFailureHandler;
|
||||
import stirling.software.SPDF.config.security.saml2.CustomSaml2AuthenticationSuccessHandler;
|
||||
import stirling.software.SPDF.config.security.saml2.CustomSaml2ResponseAuthenticationConverter;
|
||||
import stirling.software.SPDF.config.security.session.SessionPersistentRegistry;
|
||||
import stirling.software.SPDF.model.ApplicationProperties;
|
||||
import stirling.software.SPDF.model.ApplicationProperties.Security.OAUTH2;
|
||||
import stirling.software.SPDF.model.ApplicationProperties.Security.OAUTH2.Client;
|
||||
import stirling.software.SPDF.model.ApplicationProperties.Security.SAML2;
|
||||
import stirling.software.SPDF.model.User;
|
||||
import stirling.software.SPDF.model.provider.GithubProvider;
|
||||
import stirling.software.SPDF.model.provider.GoogleProvider;
|
||||
import stirling.software.SPDF.model.provider.KeycloakProvider;
|
||||
import stirling.software.SPDF.repository.JPATokenRepositoryImpl;
|
||||
|
||||
@Configuration
|
||||
@@ -48,12 +67,6 @@ public class SecurityConfiguration {
|
||||
|
||||
@Autowired private CustomUserDetailsService userDetailsService;
|
||||
|
||||
@Autowired(required = false)
|
||||
private GrantedAuthoritiesMapper userAuthoritiesMapper;
|
||||
|
||||
@Autowired(required = false)
|
||||
private RelyingPartyRegistrationRepository relyingPartyRegistrationRepository;
|
||||
|
||||
@Bean
|
||||
public PasswordEncoder passwordEncoder() {
|
||||
return new BCryptPasswordEncoder();
|
||||
@@ -74,16 +87,15 @@ public class SecurityConfiguration {
|
||||
@Autowired private FirstLoginFilter firstLoginFilter;
|
||||
@Autowired private SessionPersistentRegistry sessionRegistry;
|
||||
|
||||
@Autowired private ConvertResponseToAuthentication convertResponseToAuthentication;
|
||||
|
||||
@Bean
|
||||
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||
http.authenticationManager(authenticationManager(http));
|
||||
|
||||
if (loginEnabledValue) {
|
||||
http.addFilterBefore(
|
||||
userAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
|
||||
http.csrf(csrf -> csrf.disable());
|
||||
if (applicationProperties.getSecurity().getCsrfDisabled()) {
|
||||
http.csrf(csrf -> csrf.disable());
|
||||
}
|
||||
http.addFilterBefore(rateLimitingFilter(), UsernamePasswordAuthenticationFilter.class);
|
||||
http.addFilterAfter(firstLoginFilter, UsernamePasswordAuthenticationFilter.class);
|
||||
http.sessionManagement(
|
||||
@@ -95,165 +107,383 @@ public class SecurityConfiguration {
|
||||
.sessionRegistry(sessionRegistry)
|
||||
.expiredUrl("/login?logout=true"));
|
||||
|
||||
http.formLogin(
|
||||
formLogin ->
|
||||
formLogin
|
||||
.loginPage("/login")
|
||||
.successHandler(
|
||||
new CustomAuthenticationSuccessHandler(
|
||||
loginAttemptService, userService))
|
||||
.defaultSuccessUrl("/")
|
||||
.failureHandler(
|
||||
new CustomAuthenticationFailureHandler(
|
||||
loginAttemptService, userService))
|
||||
.permitAll())
|
||||
.requestCache(requestCache -> requestCache.requestCache(new NullRequestCache()))
|
||||
.logout(
|
||||
logout ->
|
||||
logout.logoutRequestMatcher(
|
||||
new AntPathRequestMatcher("/logout"))
|
||||
.logoutSuccessHandler(new CustomLogoutSuccessHandler())
|
||||
.invalidateHttpSession(true) // Invalidate session
|
||||
.deleteCookies("JSESSIONID", "remember-me"))
|
||||
.rememberMe(
|
||||
rememberMeConfigurer ->
|
||||
rememberMeConfigurer // Use the configurator directly
|
||||
.key("uniqueAndSecret")
|
||||
.tokenRepository(persistentTokenRepository())
|
||||
.tokenValiditySeconds(1209600) // 2 weeks
|
||||
)
|
||||
.authorizeHttpRequests(
|
||||
authz ->
|
||||
authz.requestMatchers(
|
||||
req -> {
|
||||
String uri = req.getRequestURI();
|
||||
String contextPath = req.getContextPath();
|
||||
http.authenticationProvider(daoAuthenticationProvider());
|
||||
http.requestCache(requestCache -> requestCache.requestCache(new NullRequestCache()));
|
||||
http.logout(
|
||||
logout ->
|
||||
logout.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
|
||||
.logoutSuccessHandler(
|
||||
new CustomLogoutSuccessHandler(applicationProperties))
|
||||
.invalidateHttpSession(true) // Invalidate session
|
||||
.deleteCookies("JSESSIONID", "remember-me"));
|
||||
http.rememberMe(
|
||||
rememberMeConfigurer ->
|
||||
rememberMeConfigurer // Use the configurator directly
|
||||
.key("uniqueAndSecret")
|
||||
.tokenRepository(persistentTokenRepository())
|
||||
.tokenValiditySeconds(1209600) // 2 weeks
|
||||
);
|
||||
http.authorizeHttpRequests(
|
||||
authz ->
|
||||
authz.requestMatchers(
|
||||
req -> {
|
||||
String uri = req.getRequestURI();
|
||||
String contextPath = req.getContextPath();
|
||||
|
||||
// Remove the context path from the URI
|
||||
String trimmedUri =
|
||||
uri.startsWith(contextPath)
|
||||
? uri.substring(
|
||||
contextPath
|
||||
.length())
|
||||
: uri;
|
||||
// Remove the context path from the URI
|
||||
String trimmedUri =
|
||||
uri.startsWith(contextPath)
|
||||
? uri.substring(
|
||||
contextPath.length())
|
||||
: uri;
|
||||
|
||||
return trimmedUri.startsWith("/login")
|
||||
|| trimmedUri.startsWith("/oauth")
|
||||
|| trimmedUri.startsWith("/saml2")
|
||||
|| trimmedUri.endsWith(".svg")
|
||||
|| trimmedUri.startsWith(
|
||||
"/register")
|
||||
|| trimmedUri.startsWith("/error")
|
||||
|| trimmedUri.startsWith("/images/")
|
||||
|| trimmedUri.startsWith("/public/")
|
||||
|| trimmedUri.startsWith("/css/")
|
||||
|| trimmedUri.startsWith("/fonts/")
|
||||
|| trimmedUri.startsWith("/js/")
|
||||
|| trimmedUri.startsWith(
|
||||
"/api/v1/info/status");
|
||||
})
|
||||
.permitAll()
|
||||
.anyRequest()
|
||||
.authenticated());
|
||||
return trimmedUri.startsWith("/login")
|
||||
|| trimmedUri.startsWith("/oauth")
|
||||
|| trimmedUri.startsWith("/saml2")
|
||||
|| trimmedUri.endsWith(".svg")
|
||||
|| trimmedUri.startsWith("/register")
|
||||
|| trimmedUri.startsWith("/error")
|
||||
|| trimmedUri.startsWith("/images/")
|
||||
|| trimmedUri.startsWith("/public/")
|
||||
|| trimmedUri.startsWith("/css/")
|
||||
|| trimmedUri.startsWith("/fonts/")
|
||||
|| trimmedUri.startsWith("/js/")
|
||||
|| trimmedUri.startsWith(
|
||||
"/api/v1/info/status");
|
||||
})
|
||||
.permitAll()
|
||||
.anyRequest()
|
||||
.authenticated());
|
||||
|
||||
// Handle User/Password Logins
|
||||
if (applicationProperties.getSecurity().isUserPass()) {
|
||||
http.formLogin(
|
||||
formLogin ->
|
||||
formLogin
|
||||
.loginPage("/login")
|
||||
.successHandler(
|
||||
new CustomAuthenticationSuccessHandler(
|
||||
loginAttemptService, userService))
|
||||
.failureHandler(
|
||||
new CustomAuthenticationFailureHandler(
|
||||
loginAttemptService, userService))
|
||||
.defaultSuccessUrl("/")
|
||||
.permitAll());
|
||||
}
|
||||
|
||||
// Handle OAUTH2 Logins
|
||||
if (applicationProperties.getSecurity().getOauth2() != null
|
||||
&& applicationProperties.getSecurity().getOauth2().getEnabled()
|
||||
&& !applicationProperties
|
||||
.getSecurity()
|
||||
.getLoginMethod()
|
||||
.equalsIgnoreCase("normal")) {
|
||||
if (applicationProperties.getSecurity().isOauth2Activ()) {
|
||||
|
||||
http.oauth2Login(
|
||||
oauth2 ->
|
||||
oauth2.loginPage("/oauth2")
|
||||
/*
|
||||
This Custom handler is used to check if the OAUTH2 user trying to log in, already exists in the database.
|
||||
If user exists, login proceeds as usual. If user does not exist, then it is autocreated but only if 'OAUTH2AutoCreateUser'
|
||||
is set as true, else login fails with an error message advising the same.
|
||||
*/
|
||||
oauth2 ->
|
||||
oauth2.loginPage("/oauth2")
|
||||
/*
|
||||
This Custom handler is used to check if the OAUTH2 user trying to log in, already exists in the database.
|
||||
If user exists, login proceeds as usual. If user does not exist, then it is autocreated but only if 'OAUTH2AutoCreateUser'
|
||||
is set as true, else login fails with an error message advising the same.
|
||||
*/
|
||||
.successHandler(
|
||||
new CustomOAuth2AuthenticationSuccessHandler(
|
||||
loginAttemptService,
|
||||
applicationProperties,
|
||||
userService))
|
||||
.failureHandler(
|
||||
new CustomOAuth2AuthenticationFailureHandler())
|
||||
// Add existing Authorities from the database
|
||||
.userInfoEndpoint(
|
||||
userInfoEndpoint ->
|
||||
userInfoEndpoint
|
||||
.oidcUserService(
|
||||
new CustomOAuth2UserService(
|
||||
applicationProperties,
|
||||
userService,
|
||||
loginAttemptService))
|
||||
.userAuthoritiesMapper(
|
||||
userAuthoritiesMapper()))
|
||||
.permitAll());
|
||||
}
|
||||
|
||||
// Handle SAML
|
||||
if (applicationProperties.getSecurity().isSaml2Activ()) {
|
||||
http.authenticationProvider(samlAuthenticationProvider());
|
||||
http.saml2Login(
|
||||
saml2 ->
|
||||
saml2.loginPage("/saml2")
|
||||
.successHandler(
|
||||
new CustomOAuth2AuthenticationSuccessHandler(
|
||||
new CustomSaml2AuthenticationSuccessHandler(
|
||||
loginAttemptService,
|
||||
applicationProperties,
|
||||
userService))
|
||||
.failureHandler(
|
||||
new CustomOAuth2AuthenticationFailureHandler())
|
||||
// Add existing Authorities from the database
|
||||
.userInfoEndpoint(
|
||||
userInfoEndpoint ->
|
||||
userInfoEndpoint
|
||||
.oidcUserService(
|
||||
new CustomOAuth2UserService(
|
||||
applicationProperties,
|
||||
userService,
|
||||
loginAttemptService))
|
||||
.userAuthoritiesMapper(
|
||||
userAuthoritiesMapper)))
|
||||
.logout(
|
||||
logout ->
|
||||
logout.logoutSuccessHandler(
|
||||
new CustomOAuth2LogoutSuccessHandler(
|
||||
applicationProperties)));
|
||||
}
|
||||
|
||||
// Handle SAML
|
||||
if (applicationProperties.getSecurity().getSaml() != null
|
||||
&& applicationProperties.getSecurity().getSaml().getEnabled()
|
||||
&& !applicationProperties
|
||||
.getSecurity()
|
||||
.getLoginMethod()
|
||||
.equalsIgnoreCase("normal")) {
|
||||
http.saml2Login(
|
||||
saml2 -> {
|
||||
saml2.relyingPartyRegistrationRepository(
|
||||
relyingPartyRegistrationRepository)
|
||||
.successHandler(
|
||||
new CustomSAMLAuthenticationSuccessHandler(
|
||||
loginAttemptService,
|
||||
userService,
|
||||
applicationProperties))
|
||||
.failureHandler(
|
||||
new CustomSAMLAuthenticationFailureHandler());
|
||||
})
|
||||
.saml2Logout(withDefaults())
|
||||
new CustomSaml2AuthenticationFailureHandler())
|
||||
.permitAll())
|
||||
.addFilterBefore(
|
||||
userAuthenticationFilter, Saml2WebSsoAuthenticationFilter.class);
|
||||
}
|
||||
} else {
|
||||
http.csrf(csrf -> csrf.disable())
|
||||
.authorizeHttpRequests(authz -> authz.anyRequest().permitAll());
|
||||
if (applicationProperties.getSecurity().getCsrfDisabled()) {
|
||||
http.csrf(csrf -> csrf.disable());
|
||||
}
|
||||
http.authorizeHttpRequests(authz -> authz.anyRequest().permitAll());
|
||||
}
|
||||
|
||||
return http.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnProperty(
|
||||
name = "security.saml2.enabled",
|
||||
havingValue = "true",
|
||||
matchIfMissing = false)
|
||||
public AuthenticationProvider samlAuthenticationProvider() {
|
||||
OpenSaml4AuthenticationProvider authenticationProvider =
|
||||
new OpenSaml4AuthenticationProvider();
|
||||
authenticationProvider.setResponseAuthenticationConverter(convertResponseToAuthentication);
|
||||
authenticationProvider.setResponseAuthenticationConverter(
|
||||
new CustomSaml2ResponseAuthenticationConverter(userService));
|
||||
return authenticationProvider;
|
||||
}
|
||||
|
||||
// Client Registration Repository for OAUTH2 OIDC Login
|
||||
@Bean
|
||||
public AuthenticationProvider daoAuthenticationProvider() {
|
||||
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
|
||||
provider.setUserDetailsService(userDetailsService); // UserDetailsService
|
||||
provider.setPasswordEncoder(passwordEncoder()); // PasswordEncoder
|
||||
return provider;
|
||||
@ConditionalOnProperty(
|
||||
value = "security.oauth2.enabled",
|
||||
havingValue = "true",
|
||||
matchIfMissing = false)
|
||||
public ClientRegistrationRepository clientRegistrationRepository() {
|
||||
List<ClientRegistration> registrations = new ArrayList<>();
|
||||
|
||||
githubClientRegistration().ifPresent(registrations::add);
|
||||
oidcClientRegistration().ifPresent(registrations::add);
|
||||
googleClientRegistration().ifPresent(registrations::add);
|
||||
keycloakClientRegistration().ifPresent(registrations::add);
|
||||
|
||||
if (registrations.isEmpty()) {
|
||||
log.error("At least one OAuth2 provider must be configured");
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
return new InMemoryClientRegistrationRepository(registrations);
|
||||
}
|
||||
|
||||
private Optional<ClientRegistration> googleClientRegistration() {
|
||||
OAUTH2 oauth = applicationProperties.getSecurity().getOauth2();
|
||||
if (oauth == null || !oauth.getEnabled()) {
|
||||
return Optional.empty();
|
||||
}
|
||||
Client client = oauth.getClient();
|
||||
if (client == null) {
|
||||
return Optional.empty();
|
||||
}
|
||||
GoogleProvider google = client.getGoogle();
|
||||
return google != null && google.isSettingsValid()
|
||||
? Optional.of(
|
||||
ClientRegistration.withRegistrationId(google.getName())
|
||||
.clientId(google.getClientId())
|
||||
.clientSecret(google.getClientSecret())
|
||||
.scope(google.getScopes())
|
||||
.authorizationUri(google.getAuthorizationuri())
|
||||
.tokenUri(google.getTokenuri())
|
||||
.userInfoUri(google.getUserinfouri())
|
||||
.userNameAttributeName(google.getUseAsUsername())
|
||||
.clientName(google.getClientName())
|
||||
.redirectUri("{baseUrl}/login/oauth2/code/" + google.getName())
|
||||
.authorizationGrantType(
|
||||
org.springframework.security.oauth2.core
|
||||
.AuthorizationGrantType.AUTHORIZATION_CODE)
|
||||
.build())
|
||||
: Optional.empty();
|
||||
}
|
||||
|
||||
private Optional<ClientRegistration> keycloakClientRegistration() {
|
||||
OAUTH2 oauth = applicationProperties.getSecurity().getOauth2();
|
||||
if (oauth == null || !oauth.getEnabled()) {
|
||||
return Optional.empty();
|
||||
}
|
||||
Client client = oauth.getClient();
|
||||
if (client == null) {
|
||||
return Optional.empty();
|
||||
}
|
||||
KeycloakProvider keycloak = client.getKeycloak();
|
||||
|
||||
return keycloak != null && keycloak.isSettingsValid()
|
||||
? Optional.of(
|
||||
ClientRegistrations.fromIssuerLocation(keycloak.getIssuer())
|
||||
.registrationId(keycloak.getName())
|
||||
.clientId(keycloak.getClientId())
|
||||
.clientSecret(keycloak.getClientSecret())
|
||||
.scope(keycloak.getScopes())
|
||||
.userNameAttributeName(keycloak.getUseAsUsername())
|
||||
.clientName(keycloak.getClientName())
|
||||
.build())
|
||||
: Optional.empty();
|
||||
}
|
||||
|
||||
private Optional<ClientRegistration> githubClientRegistration() {
|
||||
|
||||
OAUTH2 oauth = applicationProperties.getSecurity().getOauth2();
|
||||
if (oauth == null || !oauth.getEnabled()) {
|
||||
return Optional.empty();
|
||||
}
|
||||
Client client = oauth.getClient();
|
||||
if (client == null) {
|
||||
return Optional.empty();
|
||||
}
|
||||
GithubProvider github = client.getGithub();
|
||||
return github != null && github.isSettingsValid()
|
||||
? Optional.of(
|
||||
ClientRegistration.withRegistrationId(github.getName())
|
||||
.clientId(github.getClientId())
|
||||
.clientSecret(github.getClientSecret())
|
||||
.scope(github.getScopes())
|
||||
.authorizationUri(github.getAuthorizationuri())
|
||||
.tokenUri(github.getTokenuri())
|
||||
.userInfoUri(github.getUserinfouri())
|
||||
.userNameAttributeName(github.getUseAsUsername())
|
||||
.clientName(github.getClientName())
|
||||
.redirectUri("{baseUrl}/login/oauth2/code/" + github.getName())
|
||||
.authorizationGrantType(
|
||||
org.springframework.security.oauth2.core
|
||||
.AuthorizationGrantType.AUTHORIZATION_CODE)
|
||||
.build())
|
||||
: Optional.empty();
|
||||
}
|
||||
|
||||
private Optional<ClientRegistration> oidcClientRegistration() {
|
||||
OAUTH2 oauth = applicationProperties.getSecurity().getOauth2();
|
||||
if (oauth == null
|
||||
|| oauth.getIssuer() == null
|
||||
|| oauth.getIssuer().isEmpty()
|
||||
|| oauth.getClientId() == null
|
||||
|| oauth.getClientId().isEmpty()
|
||||
|| oauth.getClientSecret() == null
|
||||
|| oauth.getClientSecret().isEmpty()
|
||||
|| oauth.getScopes() == null
|
||||
|| oauth.getScopes().isEmpty()
|
||||
|| oauth.getUseAsUsername() == null
|
||||
|| oauth.getUseAsUsername().isEmpty()) {
|
||||
return Optional.empty();
|
||||
}
|
||||
return Optional.of(
|
||||
ClientRegistrations.fromIssuerLocation(oauth.getIssuer())
|
||||
.registrationId("oidc")
|
||||
.clientId(oauth.getClientId())
|
||||
.clientSecret(oauth.getClientSecret())
|
||||
.scope(oauth.getScopes())
|
||||
.userNameAttributeName(oauth.getUseAsUsername())
|
||||
.clientName("OIDC")
|
||||
.build());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public AuthenticationManager authenticationManager(HttpSecurity http) throws Exception {
|
||||
AuthenticationManagerBuilder authenticationManagerBuilder =
|
||||
http.getSharedObject(AuthenticationManagerBuilder.class);
|
||||
@ConditionalOnProperty(
|
||||
name = "security.saml2.enabled",
|
||||
havingValue = "true",
|
||||
matchIfMissing = false)
|
||||
public RelyingPartyRegistrationRepository relyingPartyRegistrations() throws Exception {
|
||||
|
||||
authenticationManagerBuilder
|
||||
.authenticationProvider(daoAuthenticationProvider()) // Benutzername/Passwort
|
||||
.authenticationProvider(samlAuthenticationProvider()); // SAML
|
||||
SAML2 samlConf = applicationProperties.getSecurity().getSaml2();
|
||||
|
||||
return authenticationManagerBuilder.build();
|
||||
Resource privateKeyResource = samlConf.getPrivateKey();
|
||||
|
||||
Resource certificateResource = samlConf.getSpCert();
|
||||
|
||||
Saml2X509Credential signingCredential =
|
||||
new Saml2X509Credential(
|
||||
CertificateUtils.readPrivateKey(privateKeyResource),
|
||||
CertificateUtils.readCertificate(certificateResource),
|
||||
Saml2X509CredentialType.SIGNING);
|
||||
|
||||
X509Certificate idpCert = CertificateUtils.readCertificate(samlConf.getidpCert());
|
||||
|
||||
Saml2X509Credential verificationCredential = Saml2X509Credential.verification(idpCert);
|
||||
|
||||
RelyingPartyRegistration rp =
|
||||
RelyingPartyRegistrations.fromMetadataLocation(samlConf.getIdpMetadataUriString())
|
||||
.entityId(samlConf.getEntityId())
|
||||
.registrationId(samlConf.getRegistrationId())
|
||||
.signingX509Credentials((c) -> c.add(signingCredential))
|
||||
.singleLogoutServiceLocation(samlConf.getIdpSingleLogoutUrl())
|
||||
.assertingPartyDetails(
|
||||
(details) ->
|
||||
details
|
||||
//
|
||||
// .entityId(samlConf.getIdpIssuer())
|
||||
//
|
||||
// .singleSignOnServiceLocation(
|
||||
//
|
||||
// samlConf.getIdpSingleLoginUrl())
|
||||
.verificationX509Credentials(
|
||||
(c) -> c.add(verificationCredential))
|
||||
.wantAuthnRequestsSigned(true))
|
||||
.build();
|
||||
|
||||
/*
|
||||
RelyingPartyRegistration rp =
|
||||
RelyingPartyRegistration.withRegistrationId(samlConf.getRegistrationId())
|
||||
.entityId(samlConf.getEntityId())
|
||||
.signingX509Credentials((c) -> c.add(signingCredential))
|
||||
.assertingPartyDetails(
|
||||
(details) ->
|
||||
details.entityId(samlConf.getEntityId())
|
||||
.singleSignOnServiceLocation(
|
||||
samlConf.getIdpSingleLoginUrl())
|
||||
.verificationX509Credentials(
|
||||
(c) -> c.add(verificationCredential))
|
||||
.wantAuthnRequestsSigned(true))
|
||||
.build();
|
||||
|
||||
*/
|
||||
return new InMemoryRelyingPartyRegistrationRepository(rp);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public DaoAuthenticationProvider daoAuthenticationProvider() {
|
||||
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
|
||||
provider.setUserDetailsService(userDetailsService);
|
||||
provider.setPasswordEncoder(passwordEncoder());
|
||||
return provider;
|
||||
}
|
||||
|
||||
/*
|
||||
This following function is to grant Authorities to the OAUTH2 user from the values stored in the database.
|
||||
This is required for the internal; 'hasRole()' function to give out the correct role.
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnProperty(
|
||||
value = "security.oauth2.enabled",
|
||||
havingValue = "true",
|
||||
matchIfMissing = false)
|
||||
GrantedAuthoritiesMapper userAuthoritiesMapper() {
|
||||
return (authorities) -> {
|
||||
Set<GrantedAuthority> mappedAuthorities = new HashSet<>();
|
||||
|
||||
authorities.forEach(
|
||||
authority -> {
|
||||
// Add existing OAUTH2 Authorities
|
||||
mappedAuthorities.add(new SimpleGrantedAuthority(authority.getAuthority()));
|
||||
|
||||
// Add Authorities from database for existing user, if user is present.
|
||||
if (authority instanceof OAuth2UserAuthority oauth2Auth) {
|
||||
String useAsUsername =
|
||||
applicationProperties
|
||||
.getSecurity()
|
||||
.getOauth2()
|
||||
.getUseAsUsername();
|
||||
Optional<User> userOpt =
|
||||
userService.findByUsernameIgnoreCase(
|
||||
(String) oauth2Auth.getAttributes().get(useAsUsername));
|
||||
if (userOpt.isPresent()) {
|
||||
User user = userOpt.get();
|
||||
if (user != null) {
|
||||
mappedAuthorities.add(
|
||||
new SimpleGrantedAuthority(
|
||||
userService.findRole(user).getAuthority()));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
return mappedAuthorities;
|
||||
};
|
||||
}
|
||||
|
||||
@Bean
|
||||
@@ -272,12 +502,13 @@ public class SecurityConfiguration {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Only Dev test
|
||||
@Bean
|
||||
public WebSecurityCustomizer webSecurityCustomizer() {
|
||||
return (web) ->
|
||||
web.ignoring()
|
||||
.requestMatchers(
|
||||
"/css/**", "/images/**", "/js/**", "/**.svg", "/pdfjs-legacy/**");
|
||||
}
|
||||
// // Only Dev test
|
||||
// @Bean
|
||||
// public WebSecurityCustomizer webSecurityCustomizer() {
|
||||
// return (web) ->
|
||||
// web.ignoring()
|
||||
// .requestMatchers(
|
||||
// "/css/**", "/images/**", "/js/**", "/**.svg",
|
||||
// "/pdfjs-legacy/**");
|
||||
// }
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import jakarta.servlet.FilterChain;
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import stirling.software.SPDF.config.security.saml2.CustomSaml2AuthenticatedPrincipal;
|
||||
import stirling.software.SPDF.config.security.session.SessionPersistentRegistry;
|
||||
import stirling.software.SPDF.model.ApiKeyAuthenticationToken;
|
||||
import stirling.software.SPDF.model.User;
|
||||
@@ -111,7 +112,9 @@ public class UserAuthenticationFilter extends OncePerRequestFilter {
|
||||
response.setStatus(HttpStatus.UNAUTHORIZED.value());
|
||||
response.getWriter()
|
||||
.write(
|
||||
"Authentication required. Please provide a X-API-KEY in request header.\nThis is found in Settings -> Account Settings -> API Key\nAlternatively you can disable authentication if this is unexpected");
|
||||
"Authentication required. Please provide a X-API-KEY in request header.\n"
|
||||
+ "This is found in Settings -> Account Settings -> API Key\n"
|
||||
+ "Alternatively you can disable authentication if this is unexpected");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -124,6 +127,8 @@ public class UserAuthenticationFilter extends OncePerRequestFilter {
|
||||
username = ((UserDetails) principal).getUsername();
|
||||
} else if (principal instanceof OAuth2User) {
|
||||
username = ((OAuth2User) principal).getName();
|
||||
} else if (principal instanceof CustomSaml2AuthenticatedPrincipal) {
|
||||
username = ((CustomSaml2AuthenticatedPrincipal) principal).getName();
|
||||
} else if (principal instanceof String) {
|
||||
username = (String) principal;
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import org.springframework.security.oauth2.core.user.OAuth2User;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import stirling.software.SPDF.config.interfaces.DatabaseBackupInterface;
|
||||
import stirling.software.SPDF.config.security.saml2.CustomSaml2AuthenticatedPrincipal;
|
||||
import stirling.software.SPDF.config.security.session.SessionPersistentRegistry;
|
||||
import stirling.software.SPDF.controller.api.pipeline.UserServiceInterface;
|
||||
import stirling.software.SPDF.model.AuthenticationType;
|
||||
@@ -44,6 +45,10 @@ public class UserService implements UserServiceInterface {
|
||||
|
||||
@Autowired DatabaseBackupInterface databaseBackupHelper;
|
||||
|
||||
public long getTotalUserCount() {
|
||||
return userRepository.count();
|
||||
}
|
||||
|
||||
// Handle OAUTH2 login and user auto creation.
|
||||
public boolean processOAuth2PostLogin(String username, boolean autoCreateUser)
|
||||
throws IllegalArgumentException, IOException {
|
||||
@@ -334,6 +339,10 @@ public class UserService implements UserServiceInterface {
|
||||
} else if (principal instanceof OAuth2User) {
|
||||
OAuth2User oAuth2User = (OAuth2User) principal;
|
||||
usernameP = oAuth2User.getName();
|
||||
} else if (principal instanceof CustomSaml2AuthenticatedPrincipal) {
|
||||
CustomSaml2AuthenticatedPrincipal saml2User =
|
||||
(CustomSaml2AuthenticatedPrincipal) principal;
|
||||
usernameP = saml2User.getName();
|
||||
} else if (principal instanceof String) {
|
||||
usernameP = (String) principal;
|
||||
}
|
||||
|
||||
@@ -51,8 +51,7 @@ public class CustomOAuth2AuthenticationFailureHandler
|
||||
}
|
||||
log.error("OAuth2 Authentication error: " + errorCode);
|
||||
log.error("OAuth2AuthenticationException", exception);
|
||||
getRedirectStrategy()
|
||||
.sendRedirect(request, response, "/logout?erroroauth=" + errorCode);
|
||||
getRedirectStrategy().sendRedirect(request, response, "/login?erroroauth=" + errorCode);
|
||||
return;
|
||||
}
|
||||
log.error("Unhandled authentication exception", exception);
|
||||
|
||||
@@ -75,6 +75,11 @@ public class CustomOAuth2AuthenticationSuccessHandler
|
||||
throw new LockedException(
|
||||
"Your account has been locked due to too many failed login attempts.");
|
||||
}
|
||||
if (userService.isUserDisabled(username)) {
|
||||
getRedirectStrategy()
|
||||
.sendRedirect(request, response, "/logout?userIsDisabled=true");
|
||||
return;
|
||||
}
|
||||
if (userService.usernameExistsIgnoreCase(username)
|
||||
&& userService.hasPassword(username)
|
||||
&& !userService.isAuthenticationTypeByUsername(
|
||||
|
||||
@@ -1,122 +0,0 @@
|
||||
package stirling.software.SPDF.config.security.oauth2;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
|
||||
import org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler;
|
||||
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import stirling.software.SPDF.model.ApplicationProperties;
|
||||
import stirling.software.SPDF.model.ApplicationProperties.Security.OAUTH2;
|
||||
import stirling.software.SPDF.model.Provider;
|
||||
import stirling.software.SPDF.model.provider.UnsupportedProviderException;
|
||||
import stirling.software.SPDF.utils.UrlUtils;
|
||||
|
||||
@Slf4j
|
||||
public class CustomOAuth2LogoutSuccessHandler extends SimpleUrlLogoutSuccessHandler {
|
||||
|
||||
private final ApplicationProperties applicationProperties;
|
||||
|
||||
public CustomOAuth2LogoutSuccessHandler(ApplicationProperties applicationProperties) {
|
||||
this.applicationProperties = applicationProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLogoutSuccess(
|
||||
HttpServletRequest request, HttpServletResponse response, Authentication authentication)
|
||||
throws IOException, ServletException {
|
||||
String param = "logout=true";
|
||||
String registrationId = null;
|
||||
String issuer = null;
|
||||
String clientId = null;
|
||||
|
||||
if (authentication == null) {
|
||||
if (request.getParameter("userIsDisabled") != null) {
|
||||
response.sendRedirect(
|
||||
request.getContextPath() + "/login?erroroauth=userIsDisabled");
|
||||
} else {
|
||||
super.onLogoutSuccess(request, response, authentication);
|
||||
}
|
||||
return;
|
||||
}
|
||||
OAUTH2 oauth = applicationProperties.getSecurity().getOauth2();
|
||||
|
||||
if (authentication instanceof OAuth2AuthenticationToken) {
|
||||
OAuth2AuthenticationToken oauthToken = (OAuth2AuthenticationToken) authentication;
|
||||
registrationId = oauthToken.getAuthorizedClientRegistrationId();
|
||||
|
||||
try {
|
||||
Provider provider = oauth.getClient().get(registrationId);
|
||||
issuer = provider.getIssuer();
|
||||
clientId = provider.getClientId();
|
||||
} catch (UnsupportedProviderException e) {
|
||||
log.error(e.getMessage());
|
||||
}
|
||||
} else {
|
||||
registrationId = oauth.getProvider() != null ? oauth.getProvider() : "";
|
||||
issuer = oauth.getIssuer();
|
||||
clientId = oauth.getClientId();
|
||||
}
|
||||
String errorMessage = "";
|
||||
if (request.getParameter("oauth2AuthenticationErrorWeb") != null) {
|
||||
param = "erroroauth=oauth2AuthenticationErrorWeb";
|
||||
} else if ((errorMessage = request.getParameter("error")) != null) {
|
||||
param = "error=" + sanitizeInput(errorMessage);
|
||||
} else if ((errorMessage = request.getParameter("erroroauth")) != null) {
|
||||
param = "erroroauth=" + sanitizeInput(errorMessage);
|
||||
} else if (request.getParameter("oauth2AutoCreateDisabled") != null) {
|
||||
param = "error=oauth2AutoCreateDisabled";
|
||||
} else if (request.getParameter("oauth2_admin_blocked_user") != null) {
|
||||
param = "erroroauth=oauth2_admin_blocked_user";
|
||||
} else if (request.getParameter("userIsDisabled") != null) {
|
||||
param = "erroroauth=userIsDisabled";
|
||||
} else if (request.getParameter("badcredentials") != null) {
|
||||
param = "error=badcredentials";
|
||||
}
|
||||
|
||||
String redirect_url = UrlUtils.getOrigin(request) + "/login?" + param;
|
||||
|
||||
switch (registrationId.toLowerCase()) {
|
||||
case "keycloak":
|
||||
// Add Keycloak specific logout URL if needed
|
||||
String logoutUrl =
|
||||
issuer
|
||||
+ "/protocol/openid-connect/logout"
|
||||
+ "?client_id="
|
||||
+ clientId
|
||||
+ "&post_logout_redirect_uri="
|
||||
+ response.encodeRedirectURL(redirect_url);
|
||||
log.info("Redirecting to Keycloak logout URL: " + logoutUrl);
|
||||
response.sendRedirect(logoutUrl);
|
||||
break;
|
||||
case "github":
|
||||
// Add GitHub specific logout URL if needed
|
||||
String githubLogoutUrl = "https://github.com/logout";
|
||||
log.info("Redirecting to GitHub logout URL: " + githubLogoutUrl);
|
||||
response.sendRedirect(githubLogoutUrl);
|
||||
break;
|
||||
case "google":
|
||||
// Add Google specific logout URL if needed
|
||||
// String googleLogoutUrl =
|
||||
// "https://accounts.google.com/Logout?continue=https://appengine.google.com/_ah/logout?continue="
|
||||
// + response.encodeRedirectURL(redirect_url);
|
||||
log.info("Google does not have a specific logout URL");
|
||||
// log.info("Redirecting to Google logout URL: " + googleLogoutUrl);
|
||||
// response.sendRedirect(googleLogoutUrl);
|
||||
// break;
|
||||
default:
|
||||
String defaultRedirectUrl = request.getContextPath() + "/login?" + param;
|
||||
log.info("Redirecting to default logout URL: " + defaultRedirectUrl);
|
||||
response.sendRedirect(defaultRedirectUrl);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private String sanitizeInput(String input) {
|
||||
return input.replaceAll("[^a-zA-Z0-9 ]", "");
|
||||
}
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
package stirling.software.SPDF.config.security.saml;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.opensaml.saml.saml2.core.Assertion;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.saml2.provider.service.authentication.OpenSaml4AuthenticationProvider.ResponseToken;
|
||||
import org.springframework.security.saml2.provider.service.authentication.Saml2Authentication;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
public class ConvertResponseToAuthentication
|
||||
implements Converter<ResponseToken, Saml2Authentication> {
|
||||
|
||||
private final Saml2AuthorityAttributeLookup saml2AuthorityAttributeLookup;
|
||||
|
||||
public ConvertResponseToAuthentication(
|
||||
Saml2AuthorityAttributeLookup saml2AuthorityAttributeLookup) {
|
||||
this.saml2AuthorityAttributeLookup = saml2AuthorityAttributeLookup;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Saml2Authentication convert(ResponseToken responseToken) {
|
||||
final Assertion assertion =
|
||||
CollectionUtils.firstElement(responseToken.getResponse().getAssertions());
|
||||
final Map<String, List<Object>> attributes =
|
||||
SamlAssertionUtils.getAssertionAttributes(assertion);
|
||||
final String registrationId =
|
||||
responseToken.getToken().getRelyingPartyRegistration().getRegistrationId();
|
||||
final ScimSaml2AuthenticatedPrincipal principal =
|
||||
new ScimSaml2AuthenticatedPrincipal(
|
||||
assertion,
|
||||
attributes,
|
||||
saml2AuthorityAttributeLookup.getIdentityMappings(registrationId));
|
||||
final Collection<? extends GrantedAuthority> assertionAuthorities =
|
||||
getAssertionAuthorities(
|
||||
attributes,
|
||||
saml2AuthorityAttributeLookup.getAuthorityAttribute(registrationId));
|
||||
return new Saml2Authentication(
|
||||
principal, responseToken.getToken().getSaml2Response(), assertionAuthorities);
|
||||
}
|
||||
|
||||
private static Collection<? extends GrantedAuthority> getAssertionAuthorities(
|
||||
final Map<String, List<Object>> attributes, final String authoritiesAttributeName) {
|
||||
if (attributes == null || attributes.isEmpty()) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
List<Object> groups = new ArrayList<>();
|
||||
|
||||
if (attributes.get(authoritiesAttributeName) != null) {
|
||||
groups = new ArrayList<>(attributes.get(authoritiesAttributeName));
|
||||
}
|
||||
|
||||
return groups.stream()
|
||||
.filter(String.class::isInstance)
|
||||
.map(String.class::cast)
|
||||
.map(String::toLowerCase)
|
||||
.map(SimpleGrantedAuthority::new)
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
package stirling.software.SPDF.config.security.saml;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.springframework.security.authentication.BadCredentialsException;
|
||||
import org.springframework.security.authentication.DisabledException;
|
||||
import org.springframework.security.authentication.LockedException;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationException;
|
||||
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
|
||||
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
public class CustomSAMLAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler {
|
||||
|
||||
@Override
|
||||
public void onAuthenticationFailure(
|
||||
HttpServletRequest request,
|
||||
HttpServletResponse response,
|
||||
AuthenticationException exception)
|
||||
throws IOException, ServletException {
|
||||
|
||||
if (exception instanceof BadCredentialsException) {
|
||||
log.error("BadCredentialsException", exception);
|
||||
getRedirectStrategy().sendRedirect(request, response, "/login?error=badcredentials");
|
||||
return;
|
||||
}
|
||||
if (exception instanceof DisabledException) {
|
||||
log.error("User is deactivated: ", exception);
|
||||
getRedirectStrategy().sendRedirect(request, response, "/logout?userIsDisabled=true");
|
||||
return;
|
||||
}
|
||||
if (exception instanceof LockedException) {
|
||||
log.error("Account locked: ", exception);
|
||||
getRedirectStrategy().sendRedirect(request, response, "/logout?error=locked");
|
||||
return;
|
||||
}
|
||||
if (exception instanceof Saml2AuthenticationException) {
|
||||
log.error("SAML2 Authentication error: ", exception);
|
||||
getRedirectStrategy()
|
||||
.sendRedirect(request, response, "/logout?error=saml2AuthenticationError");
|
||||
return;
|
||||
}
|
||||
log.error("Unhandled authentication exception", exception);
|
||||
super.onAuthenticationFailure(request, response, exception);
|
||||
}
|
||||
}
|
||||
@@ -1,108 +0,0 @@
|
||||
package stirling.software.SPDF.config.security.saml;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.springframework.security.authentication.LockedException;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.oauth2.core.user.OAuth2User;
|
||||
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
|
||||
import org.springframework.security.web.savedrequest.SavedRequest;
|
||||
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.servlet.http.HttpSession;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import stirling.software.SPDF.config.security.LoginAttemptService;
|
||||
import stirling.software.SPDF.config.security.UserService;
|
||||
import stirling.software.SPDF.model.ApplicationProperties;
|
||||
import stirling.software.SPDF.model.ApplicationProperties.Security.OAUTH2;
|
||||
import stirling.software.SPDF.model.AuthenticationType;
|
||||
import stirling.software.SPDF.utils.RequestUriUtils;
|
||||
|
||||
@Slf4j
|
||||
public class CustomSAMLAuthenticationSuccessHandler
|
||||
extends SavedRequestAwareAuthenticationSuccessHandler {
|
||||
|
||||
private LoginAttemptService loginAttemptService;
|
||||
private UserService userService;
|
||||
private ApplicationProperties applicationProperties;
|
||||
|
||||
public CustomSAMLAuthenticationSuccessHandler(
|
||||
LoginAttemptService loginAttemptService,
|
||||
UserService userService,
|
||||
ApplicationProperties applicationProperties) {
|
||||
this.loginAttemptService = loginAttemptService;
|
||||
this.userService = userService;
|
||||
this.applicationProperties = applicationProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAuthenticationSuccess(
|
||||
HttpServletRequest request, HttpServletResponse response, Authentication authentication)
|
||||
throws ServletException, IOException {
|
||||
|
||||
Object principal = authentication.getPrincipal();
|
||||
String username = "";
|
||||
|
||||
if (principal instanceof OAuth2User) {
|
||||
OAuth2User oauthUser = (OAuth2User) principal;
|
||||
username = oauthUser.getName();
|
||||
} else if (principal instanceof UserDetails) {
|
||||
UserDetails oauthUser = (UserDetails) principal;
|
||||
username = oauthUser.getUsername();
|
||||
} else if (principal instanceof ScimSaml2AuthenticatedPrincipal) {
|
||||
ScimSaml2AuthenticatedPrincipal samlPrincipal =
|
||||
(ScimSaml2AuthenticatedPrincipal) principal;
|
||||
username = samlPrincipal.getName();
|
||||
}
|
||||
|
||||
// Get the saved request
|
||||
HttpSession session = request.getSession(false);
|
||||
String contextPath = request.getContextPath();
|
||||
SavedRequest savedRequest =
|
||||
(session != null)
|
||||
? (SavedRequest) session.getAttribute("SPRING_SECURITY_SAVED_REQUEST")
|
||||
: null;
|
||||
|
||||
if (savedRequest != null
|
||||
&& !RequestUriUtils.isStaticResource(contextPath, savedRequest.getRedirectUrl())) {
|
||||
// Redirect to the original destination
|
||||
super.onAuthenticationSuccess(request, response, authentication);
|
||||
} else {
|
||||
OAUTH2 oAuth = applicationProperties.getSecurity().getOauth2();
|
||||
|
||||
if (loginAttemptService.isBlocked(username)) {
|
||||
if (session != null) {
|
||||
session.removeAttribute("SPRING_SECURITY_SAVED_REQUEST");
|
||||
}
|
||||
throw new LockedException(
|
||||
"Your account has been locked due to too many failed login attempts.");
|
||||
}
|
||||
if (userService.usernameExistsIgnoreCase(username)
|
||||
&& userService.hasPassword(username)
|
||||
&& !userService.isAuthenticationTypeByUsername(
|
||||
username, AuthenticationType.OAUTH2)
|
||||
&& oAuth.getAutoCreateUser()) {
|
||||
response.sendRedirect(contextPath + "/logout?oauth2AuthenticationErrorWeb=true");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
if (oAuth.getBlockRegistration()
|
||||
&& !userService.usernameExistsIgnoreCase(username)) {
|
||||
response.sendRedirect(contextPath + "/logout?oauth2_admin_blocked_user=true");
|
||||
return;
|
||||
}
|
||||
if (principal instanceof OAuth2User) {
|
||||
userService.processOAuth2PostLogin(username, oAuth.getAutoCreateUser());
|
||||
}
|
||||
response.sendRedirect(contextPath + "/");
|
||||
return;
|
||||
} catch (IllegalArgumentException e) {
|
||||
response.sendRedirect(contextPath + "/logout?invalidUsername=true");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
package stirling.software.SPDF.config.security.saml;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler;
|
||||
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
public class SAMLLogoutSuccessHandler extends SimpleUrlLogoutSuccessHandler {
|
||||
|
||||
@Override
|
||||
public void onLogoutSuccess(
|
||||
HttpServletRequest request, HttpServletResponse response, Authentication authentication)
|
||||
throws IOException, ServletException {
|
||||
|
||||
String redirectUrl = determineTargetUrl(request, response, authentication);
|
||||
|
||||
if (response.isCommitted()) {
|
||||
log.debug("Response has already been committed. Unable to redirect to " + redirectUrl);
|
||||
return;
|
||||
}
|
||||
|
||||
getRedirectStrategy().sendRedirect(request, response, redirectUrl);
|
||||
}
|
||||
|
||||
protected String determineTargetUrl(
|
||||
HttpServletRequest request,
|
||||
HttpServletResponse response,
|
||||
Authentication authentication) {
|
||||
// Default to the root URL
|
||||
return "/";
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
package stirling.software.SPDF.config.security.saml;
|
||||
|
||||
public interface Saml2AuthorityAttributeLookup {
|
||||
String getAuthorityAttribute(String registrationId);
|
||||
|
||||
SimpleScimMappings getIdentityMappings(String registrationId);
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
package stirling.software.SPDF.config.security.saml;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class Saml2AuthorityAttributeLookupImpl implements Saml2AuthorityAttributeLookup {
|
||||
|
||||
@Override
|
||||
public String getAuthorityAttribute(String registrationId) {
|
||||
return "authorityAttributeName";
|
||||
}
|
||||
|
||||
@Override
|
||||
public SimpleScimMappings getIdentityMappings(String registrationId) {
|
||||
return new SimpleScimMappings();
|
||||
}
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
package stirling.software.SPDF.config.security.saml;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.*;
|
||||
|
||||
import org.opensaml.core.xml.XMLObject;
|
||||
import org.opensaml.core.xml.schema.*;
|
||||
import org.opensaml.saml.saml2.core.Assertion;
|
||||
|
||||
public class SamlAssertionUtils {
|
||||
|
||||
public static Map<String, List<Object>> getAssertionAttributes(Assertion assertion) {
|
||||
Map<String, List<Object>> attributeMap = new LinkedHashMap<>();
|
||||
|
||||
assertion
|
||||
.getAttributeStatements()
|
||||
.forEach(
|
||||
attributeStatement -> {
|
||||
attributeStatement
|
||||
.getAttributes()
|
||||
.forEach(
|
||||
attribute -> {
|
||||
List<Object> attributeValues = new ArrayList<>();
|
||||
|
||||
attribute
|
||||
.getAttributeValues()
|
||||
.forEach(
|
||||
xmlObject -> {
|
||||
Object attributeValue =
|
||||
getXmlObjectValue(
|
||||
xmlObject);
|
||||
if (attributeValue != null) {
|
||||
attributeValues.add(
|
||||
attributeValue);
|
||||
}
|
||||
});
|
||||
|
||||
attributeMap.put(
|
||||
attribute.getName(), attributeValues);
|
||||
});
|
||||
});
|
||||
|
||||
return attributeMap;
|
||||
}
|
||||
|
||||
public static Object getXmlObjectValue(XMLObject xmlObject) {
|
||||
if (xmlObject instanceof XSAny) {
|
||||
return ((XSAny) xmlObject).getTextContent();
|
||||
} else if (xmlObject instanceof XSString) {
|
||||
return ((XSString) xmlObject).getValue();
|
||||
} else if (xmlObject instanceof XSInteger) {
|
||||
return ((XSInteger) xmlObject).getValue();
|
||||
} else if (xmlObject instanceof XSURI) {
|
||||
return ((XSURI) xmlObject).getURI();
|
||||
} else if (xmlObject instanceof XSBoolean) {
|
||||
return ((XSBoolean) xmlObject).getValue().getValue();
|
||||
} else if (xmlObject instanceof XSDateTime) {
|
||||
Instant dateTime = ((XSDateTime) xmlObject).getValue();
|
||||
return (dateTime != null) ? Instant.ofEpochMilli(dateTime.toEpochMilli()) : null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
package stirling.software.SPDF.config.security.saml;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.security.interfaces.RSAPrivateKey;
|
||||
|
||||
import org.opensaml.security.x509.X509Support;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.security.converter.RsaKeyConverters;
|
||||
import org.springframework.security.saml2.core.Saml2X509Credential;
|
||||
import org.springframework.security.saml2.provider.service.registration.*;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import stirling.software.SPDF.model.ApplicationProperties;
|
||||
|
||||
@Configuration
|
||||
@Slf4j
|
||||
public class SamlConfig {
|
||||
|
||||
@Autowired ApplicationProperties applicationProperties;
|
||||
|
||||
@Autowired ResourceLoader resourceLoader;
|
||||
|
||||
@Bean
|
||||
@ConditionalOnProperty(
|
||||
value = "security.saml.enabled",
|
||||
havingValue = "true",
|
||||
matchIfMissing = false)
|
||||
public RelyingPartyRegistrationRepository relyingPartyRegistrationRepository()
|
||||
throws CertificateException, IOException {
|
||||
|
||||
// Resource signingCertResource = new ClassPathResource(this.rpSigningCertLocation);
|
||||
Resource signingCertResource =
|
||||
resourceLoader.getResource(
|
||||
this.applicationProperties
|
||||
.getSecurity()
|
||||
.getSaml()
|
||||
.getCertificateLocation());
|
||||
// Resource signingKeyResource = new ClassPathResource(this.rpSigningKeyLocation);
|
||||
Resource signingKeyResource =
|
||||
resourceLoader.getResource(
|
||||
this.applicationProperties.getSecurity().getSaml().getPrivateKeyLocation());
|
||||
try (InputStream is = signingKeyResource.getInputStream();
|
||||
InputStream certIS = signingCertResource.getInputStream(); ) {
|
||||
X509Certificate rpCertificate = X509Support.decodeCertificate(certIS.readAllBytes());
|
||||
RSAPrivateKey rpKey = RsaKeyConverters.pkcs8().convert(is);
|
||||
final Saml2X509Credential rpSigningCredentials =
|
||||
Saml2X509Credential.signing(rpKey, rpCertificate);
|
||||
|
||||
X509Certificate apCert =
|
||||
X509Support.decodeCertificate(
|
||||
applicationProperties.getSecurity().getSaml().getSigningCertificate());
|
||||
Saml2X509Credential apCredential = Saml2X509Credential.verification(apCert);
|
||||
|
||||
RelyingPartyRegistration registration =
|
||||
RelyingPartyRegistrations.fromMetadataLocation(
|
||||
applicationProperties
|
||||
.getSecurity()
|
||||
.getSaml()
|
||||
.getIdpMetadataLocation())
|
||||
.entityId(applicationProperties.getSecurity().getSaml().getEntityId())
|
||||
.registrationId(
|
||||
applicationProperties
|
||||
.getSecurity()
|
||||
.getSaml()
|
||||
.getRegistrationId())
|
||||
.signingX509Credentials(c -> c.add(rpSigningCredentials))
|
||||
.assertingPartyDetails(
|
||||
party ->
|
||||
party.wantAuthnRequestsSigned(true)
|
||||
.verificationX509Credentials(
|
||||
c -> c.add(apCredential)))
|
||||
.singleLogoutServiceLocation("http://localhost:8090/logout/saml2/slo")
|
||||
.build();
|
||||
return new InMemoryRelyingPartyRegistrationRepository(registration);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,89 +0,0 @@
|
||||
package stirling.software.SPDF.config.security.saml;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.opensaml.saml.saml2.core.Assertion;
|
||||
import org.springframework.security.core.AuthenticatedPrincipal;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.unboundid.scim2.common.types.Email;
|
||||
import com.unboundid.scim2.common.types.Name;
|
||||
import com.unboundid.scim2.common.types.UserResource;
|
||||
|
||||
public class ScimSaml2AuthenticatedPrincipal implements AuthenticatedPrincipal, Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final transient UserResource userResource;
|
||||
|
||||
public ScimSaml2AuthenticatedPrincipal(
|
||||
final Assertion assertion,
|
||||
final Map<String, List<Object>> attributes,
|
||||
final SimpleScimMappings attributeMappings) {
|
||||
Assert.notNull(assertion, "assertion cannot be null");
|
||||
Assert.notNull(assertion.getSubject(), "assertion subject cannot be null");
|
||||
Assert.notNull(
|
||||
assertion.getSubject().getNameID(), "assertion subject NameID cannot be null");
|
||||
Assert.notNull(attributes, "attributes cannot be null");
|
||||
Assert.notNull(attributeMappings, "attributeMappings cannot be null");
|
||||
|
||||
final Name name =
|
||||
new Name()
|
||||
.setFamilyName(
|
||||
getAttribute(
|
||||
attributes,
|
||||
attributeMappings,
|
||||
SimpleScimMappings::getFamilyName))
|
||||
.setGivenName(
|
||||
getAttribute(
|
||||
attributes,
|
||||
attributeMappings,
|
||||
SimpleScimMappings::getGivenName));
|
||||
|
||||
final List<Email> emails = new ArrayList<>(1);
|
||||
emails.add(
|
||||
new Email()
|
||||
.setValue(
|
||||
getAttribute(
|
||||
attributes,
|
||||
attributeMappings,
|
||||
SimpleScimMappings::getEmail))
|
||||
.setPrimary(true));
|
||||
|
||||
userResource =
|
||||
new UserResource()
|
||||
.setUserName(assertion.getSubject().getNameID().getValue())
|
||||
.setName(name)
|
||||
.setEmails(emails);
|
||||
}
|
||||
|
||||
private static String getAttribute(
|
||||
final Map<String, List<Object>> attributes,
|
||||
final SimpleScimMappings simpleScimMappings,
|
||||
final Function<SimpleScimMappings, String> attributeMapper) {
|
||||
|
||||
final String key = attributeMapper.apply(simpleScimMappings);
|
||||
|
||||
final List<Object> values = attributes.getOrDefault(key, Collections.emptyList());
|
||||
|
||||
return values.stream()
|
||||
.filter(String.class::isInstance)
|
||||
.map(String.class::cast)
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return this.userResource.getUserName();
|
||||
}
|
||||
|
||||
public UserResource getUserResource() {
|
||||
return this.userResource;
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
package stirling.software.SPDF.config.security.saml;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class SimpleScimMappings {
|
||||
String givenName;
|
||||
String familyName;
|
||||
String email;
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package stirling.software.SPDF.config.security.saml2;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.KeyFactory;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.security.interfaces.RSAPrivateKey;
|
||||
import java.security.spec.PKCS8EncodedKeySpec;
|
||||
import java.util.Base64;
|
||||
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.util.FileCopyUtils;
|
||||
|
||||
public class CertificateUtils {
|
||||
|
||||
public static X509Certificate readCertificate(Resource certificateResource) throws Exception {
|
||||
String certificateString =
|
||||
new String(
|
||||
FileCopyUtils.copyToByteArray(certificateResource.getInputStream()),
|
||||
StandardCharsets.UTF_8);
|
||||
String certContent =
|
||||
certificateString
|
||||
.replace("-----BEGIN CERTIFICATE-----", "")
|
||||
.replace("-----END CERTIFICATE-----", "")
|
||||
.replaceAll("\\R", "")
|
||||
.replaceAll("\\s+", "");
|
||||
CertificateFactory cf = CertificateFactory.getInstance("X.509");
|
||||
byte[] decodedCert = Base64.getDecoder().decode(certContent);
|
||||
return (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(decodedCert));
|
||||
}
|
||||
|
||||
public static RSAPrivateKey readPrivateKey(Resource privateKeyResource) throws Exception {
|
||||
String privateKeyString =
|
||||
new String(
|
||||
FileCopyUtils.copyToByteArray(privateKeyResource.getInputStream()),
|
||||
StandardCharsets.UTF_8);
|
||||
String privateKeyContent =
|
||||
privateKeyString
|
||||
.replace("-----BEGIN PRIVATE KEY-----", "")
|
||||
.replace("-----END PRIVATE KEY-----", "")
|
||||
.replaceAll("\\R", "")
|
||||
.replaceAll("\\s+", "");
|
||||
KeyFactory kf = KeyFactory.getInstance("RSA");
|
||||
byte[] decodedKey = Base64.getDecoder().decode(privateKeyContent);
|
||||
return (RSAPrivateKey) kf.generatePrivate(new PKCS8EncodedKeySpec(decodedKey));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package stirling.software.SPDF.config.security.saml2;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticatedPrincipal;
|
||||
|
||||
public class CustomSaml2AuthenticatedPrincipal
|
||||
implements Saml2AuthenticatedPrincipal, Serializable {
|
||||
|
||||
private final String name;
|
||||
private final Map<String, List<Object>> attributes;
|
||||
private final String nameId;
|
||||
private final List<String> sessionIndexes;
|
||||
|
||||
public CustomSaml2AuthenticatedPrincipal(
|
||||
String name,
|
||||
Map<String, List<Object>> attributes,
|
||||
String nameId,
|
||||
List<String> sessionIndexes) {
|
||||
this.name = name;
|
||||
this.attributes = attributes;
|
||||
this.nameId = nameId;
|
||||
this.sessionIndexes = sessionIndexes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, List<Object>> getAttributes() {
|
||||
return this.attributes;
|
||||
}
|
||||
|
||||
public String getNameId() {
|
||||
return this.nameId;
|
||||
}
|
||||
|
||||
public List<String> getSessionIndexes() {
|
||||
return this.sessionIndexes;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package stirling.software.SPDF.config.security.saml2;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.springframework.security.authentication.ProviderNotFoundException;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.saml2.core.Saml2Error;
|
||||
import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationException;
|
||||
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
|
||||
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
public class CustomSaml2AuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler {
|
||||
|
||||
@Override
|
||||
public void onAuthenticationFailure(
|
||||
HttpServletRequest request,
|
||||
HttpServletResponse response,
|
||||
AuthenticationException exception)
|
||||
throws IOException, ServletException {
|
||||
if (exception instanceof Saml2AuthenticationException) {
|
||||
Saml2Error error = ((Saml2AuthenticationException) exception).getSaml2Error();
|
||||
getRedirectStrategy()
|
||||
.sendRedirect(request, response, "/login?erroroauth=" + error.getErrorCode());
|
||||
} else if (exception instanceof ProviderNotFoundException) {
|
||||
getRedirectStrategy()
|
||||
.sendRedirect(
|
||||
request,
|
||||
response,
|
||||
"/login?erroroauth=not_authentication_provider_found");
|
||||
}
|
||||
log.error("AuthenticationException: " + exception);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
package stirling.software.SPDF.config.security.saml2;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.springframework.security.authentication.LockedException;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
|
||||
import org.springframework.security.web.savedrequest.SavedRequest;
|
||||
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.servlet.http.HttpSession;
|
||||
import lombok.AllArgsConstructor;
|
||||
import stirling.software.SPDF.config.security.LoginAttemptService;
|
||||
import stirling.software.SPDF.config.security.UserService;
|
||||
import stirling.software.SPDF.model.ApplicationProperties;
|
||||
import stirling.software.SPDF.model.ApplicationProperties.Security.SAML2;
|
||||
import stirling.software.SPDF.model.AuthenticationType;
|
||||
import stirling.software.SPDF.utils.RequestUriUtils;
|
||||
|
||||
@AllArgsConstructor
|
||||
public class CustomSaml2AuthenticationSuccessHandler
|
||||
extends SavedRequestAwareAuthenticationSuccessHandler {
|
||||
|
||||
private LoginAttemptService loginAttemptService;
|
||||
|
||||
private ApplicationProperties applicationProperties;
|
||||
private UserService userService;
|
||||
|
||||
@Override
|
||||
public void onAuthenticationSuccess(
|
||||
HttpServletRequest request, HttpServletResponse response, Authentication authentication)
|
||||
throws ServletException, IOException {
|
||||
|
||||
Object principal = authentication.getPrincipal();
|
||||
|
||||
if (principal instanceof CustomSaml2AuthenticatedPrincipal) {
|
||||
String username = ((CustomSaml2AuthenticatedPrincipal) principal).getName();
|
||||
// Get the saved request
|
||||
HttpSession session = request.getSession(false);
|
||||
String contextPath = request.getContextPath();
|
||||
SavedRequest savedRequest =
|
||||
(session != null)
|
||||
? (SavedRequest) session.getAttribute("SPRING_SECURITY_SAVED_REQUEST")
|
||||
: null;
|
||||
|
||||
if (savedRequest != null
|
||||
&& !RequestUriUtils.isStaticResource(
|
||||
contextPath, savedRequest.getRedirectUrl())) {
|
||||
// Redirect to the original destination
|
||||
super.onAuthenticationSuccess(request, response, authentication);
|
||||
} else {
|
||||
SAML2 saml2 = applicationProperties.getSecurity().getSaml2();
|
||||
|
||||
if (loginAttemptService.isBlocked(username)) {
|
||||
if (session != null) {
|
||||
session.removeAttribute("SPRING_SECURITY_SAVED_REQUEST");
|
||||
}
|
||||
throw new LockedException(
|
||||
"Your account has been locked due to too many failed login attempts.");
|
||||
}
|
||||
if (userService.usernameExistsIgnoreCase(username)
|
||||
&& userService.hasPassword(username)
|
||||
&& !userService.isAuthenticationTypeByUsername(
|
||||
username, AuthenticationType.OAUTH2)
|
||||
&& saml2.getAutoCreateUser()) {
|
||||
response.sendRedirect(
|
||||
contextPath + "/logout?oauth2AuthenticationErrorWeb=true");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
if (saml2.getBlockRegistration()
|
||||
&& !userService.usernameExistsIgnoreCase(username)) {
|
||||
response.sendRedirect(
|
||||
contextPath + "/login?erroroauth=oauth2_admin_blocked_user");
|
||||
return;
|
||||
}
|
||||
userService.processOAuth2PostLogin(username, saml2.getAutoCreateUser());
|
||||
response.sendRedirect(contextPath + "/");
|
||||
return;
|
||||
} catch (IllegalArgumentException e) {
|
||||
response.sendRedirect(contextPath + "/logout?invalidUsername=true");
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
super.onAuthenticationSuccess(request, response, authentication);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
package stirling.software.SPDF.config.security.saml2;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import org.opensaml.core.xml.XMLObject;
|
||||
import org.opensaml.core.xml.schema.XSBoolean;
|
||||
import org.opensaml.core.xml.schema.XSString;
|
||||
import org.opensaml.saml.saml2.core.Assertion;
|
||||
import org.opensaml.saml.saml2.core.Attribute;
|
||||
import org.opensaml.saml.saml2.core.AttributeStatement;
|
||||
import org.opensaml.saml.saml2.core.AuthnStatement;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.saml2.provider.service.authentication.OpenSaml4AuthenticationProvider.ResponseToken;
|
||||
import org.springframework.security.saml2.provider.service.authentication.Saml2Authentication;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import stirling.software.SPDF.config.security.UserService;
|
||||
import stirling.software.SPDF.model.User;
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
public class CustomSaml2ResponseAuthenticationConverter
|
||||
implements Converter<ResponseToken, Saml2Authentication> {
|
||||
|
||||
private UserService userService;
|
||||
|
||||
public CustomSaml2ResponseAuthenticationConverter(UserService userService) {
|
||||
this.userService = userService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Saml2Authentication convert(ResponseToken responseToken) {
|
||||
// Extract the assertion from the response
|
||||
Assertion assertion = responseToken.getResponse().getAssertions().get(0);
|
||||
|
||||
// Extract the NameID
|
||||
String nameId = assertion.getSubject().getNameID().getValue();
|
||||
|
||||
Optional<User> userOpt = userService.findByUsernameIgnoreCase(nameId);
|
||||
SimpleGrantedAuthority simpleGrantedAuthority = new SimpleGrantedAuthority("ROLE_USER");
|
||||
if (userOpt.isPresent()) {
|
||||
User user = userOpt.get();
|
||||
if (user != null) {
|
||||
simpleGrantedAuthority =
|
||||
new SimpleGrantedAuthority(userService.findRole(user).getAuthority());
|
||||
}
|
||||
}
|
||||
|
||||
// Extract the SessionIndexes
|
||||
List<String> sessionIndexes = new ArrayList<>();
|
||||
for (AuthnStatement authnStatement : assertion.getAuthnStatements()) {
|
||||
sessionIndexes.add(authnStatement.getSessionIndex());
|
||||
}
|
||||
|
||||
// Extract the Attributes
|
||||
Map<String, List<Object>> attributes = extractAttributes(assertion);
|
||||
|
||||
// Create the custom principal
|
||||
CustomSaml2AuthenticatedPrincipal principal =
|
||||
new CustomSaml2AuthenticatedPrincipal(nameId, attributes, nameId, sessionIndexes);
|
||||
|
||||
// Create the Saml2Authentication
|
||||
return new Saml2Authentication(
|
||||
principal,
|
||||
responseToken.getToken().getSaml2Response(),
|
||||
Collections.singletonList(simpleGrantedAuthority));
|
||||
}
|
||||
|
||||
private Map<String, List<Object>> extractAttributes(Assertion assertion) {
|
||||
Map<String, List<Object>> attributes = new HashMap<>();
|
||||
try {
|
||||
for (AttributeStatement attributeStatement : assertion.getAttributeStatements()) {
|
||||
for (Attribute attribute : attributeStatement.getAttributes()) {
|
||||
String attributeName = attribute.getName();
|
||||
List<Object> values = new ArrayList<>();
|
||||
for (XMLObject xmlObject : attribute.getAttributeValues()) {
|
||||
log.info("BOOL: " + ((XSBoolean) xmlObject).getValue());
|
||||
values.add(((XSString) xmlObject).getValue());
|
||||
}
|
||||
attributes.put(attributeName, values);
|
||||
}
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
log.error("Could not extract attributes. Error: " + ex.getMessage());
|
||||
return attributes;
|
||||
}
|
||||
return attributes;
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,7 @@ import org.springframework.security.oauth2.core.user.OAuth2User;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import jakarta.transaction.Transactional;
|
||||
import stirling.software.SPDF.config.security.saml2.CustomSaml2AuthenticatedPrincipal;
|
||||
import stirling.software.SPDF.model.SessionEntity;
|
||||
|
||||
@Component
|
||||
@@ -50,6 +51,8 @@ public class SessionPersistentRegistry implements SessionRegistry {
|
||||
principalName = ((UserDetails) principal).getUsername();
|
||||
} else if (principal instanceof OAuth2User) {
|
||||
principalName = ((OAuth2User) principal).getName();
|
||||
} else if (principal instanceof CustomSaml2AuthenticatedPrincipal) {
|
||||
principalName = ((CustomSaml2AuthenticatedPrincipal) principal).getName();
|
||||
} else if (principal instanceof String) {
|
||||
principalName = (String) principal;
|
||||
}
|
||||
@@ -79,6 +82,8 @@ public class SessionPersistentRegistry implements SessionRegistry {
|
||||
principalName = ((UserDetails) principal).getUsername();
|
||||
} else if (principal instanceof OAuth2User) {
|
||||
principalName = ((OAuth2User) principal).getName();
|
||||
} else if (principal instanceof CustomSaml2AuthenticatedPrincipal) {
|
||||
principalName = ((CustomSaml2AuthenticatedPrincipal) principal).getName();
|
||||
} else if (principal instanceof String) {
|
||||
principalName = (String) principal;
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
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.service.CustomPDDocumentFactory;
|
||||
@@ -21,6 +22,7 @@ import stirling.software.SPDF.utils.WebResponseUtils;
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/general")
|
||||
@Tag(name = "General", description = "General APIs")
|
||||
public class PdfImageRemovalController {
|
||||
|
||||
// Service for removing images from PDFs
|
||||
|
||||
@@ -109,7 +109,7 @@ public class ScalePagesController {
|
||||
}
|
||||
|
||||
private PDRectangle getTargetSize(String targetPDRectangle, PDDocument sourceDocument) {
|
||||
if (targetPDRectangle.equals("KEEP")) {
|
||||
if ("KEEP".equals(targetPDRectangle)) {
|
||||
if (sourceDocument.getNumberOfPages() == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import stirling.software.SPDF.config.security.UserService;
|
||||
import stirling.software.SPDF.config.security.saml2.CustomSaml2AuthenticatedPrincipal;
|
||||
import stirling.software.SPDF.config.security.session.SessionPersistentRegistry;
|
||||
import stirling.software.SPDF.model.AuthenticationType;
|
||||
import stirling.software.SPDF.model.Role;
|
||||
@@ -336,6 +337,8 @@ public class UserController {
|
||||
userNameP = ((UserDetails) principal).getUsername();
|
||||
} else if (principal instanceof OAuth2User) {
|
||||
userNameP = ((OAuth2User) principal).getName();
|
||||
} else if (principal instanceof CustomSaml2AuthenticatedPrincipal) {
|
||||
userNameP = ((CustomSaml2AuthenticatedPrincipal) principal).getName();
|
||||
} else if (principal instanceof String) {
|
||||
userNameP = (String) principal;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package stirling.software.SPDF.controller.api.converters;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||
@@ -14,7 +15,6 @@ import stirling.software.SPDF.service.CustomPDDocumentFactory;
|
||||
import stirling.software.SPDF.utils.FileToPdf;
|
||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||
|
||||
// Disabled for now
|
||||
// @RestController
|
||||
// @Tag(name = "Convert", description = "Convert APIs")
|
||||
// @RequestMapping("/api/v1/convert")
|
||||
@@ -24,7 +24,7 @@ public class ConvertBookToPDFController {
|
||||
|
||||
private final CustomPDDocumentFactory pdfDocumentFactory;
|
||||
|
||||
// @Autowired
|
||||
@Autowired
|
||||
public ConvertBookToPDFController(
|
||||
CustomPDDocumentFactory pdfDocumentFactory,
|
||||
@Qualifier("bookAndHtmlFormatsInstalled") boolean bookAndHtmlFormatsInstalled) {
|
||||
@@ -66,6 +66,8 @@ public class ConvertBookToPDFController {
|
||||
}
|
||||
byte[] pdfBytes = FileToPdf.convertBookTypeToPdf(fileInput.getBytes(), originalFilename);
|
||||
|
||||
pdfBytes = pdfDocumentFactory.createNewBytesBasedOnOldDocument(pdfBytes);
|
||||
|
||||
String outputFilename =
|
||||
originalFilename.replaceFirst("[.][^.]+$", "")
|
||||
+ ".pdf"; // Remove file extension and append .pdf
|
||||
|
||||
@@ -1,27 +1,39 @@
|
||||
package stirling.software.SPDF.controller.api.converters;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
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.github.pixee.security.Filenames;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
|
||||
import stirling.software.SPDF.model.api.converters.HTMLToPdfRequest;
|
||||
import stirling.software.SPDF.service.CustomPDDocumentFactory;
|
||||
import stirling.software.SPDF.utils.FileToPdf;
|
||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||
|
||||
// Disabled for now
|
||||
// @RestController
|
||||
// @Tag(name = "Convert", description = "Convert APIs")
|
||||
// @RequestMapping("/api/v1/convert")
|
||||
@RestController
|
||||
@Tag(name = "Convert", description = "Convert APIs")
|
||||
@RequestMapping("/api/v1/convert")
|
||||
public class ConvertHtmlToPDF {
|
||||
|
||||
// @Autowired
|
||||
@Qualifier("bookAndHtmlFormatsInstalled")
|
||||
private boolean bookAndHtmlFormatsInstalled;
|
||||
private final boolean bookAndHtmlFormatsInstalled;
|
||||
|
||||
private final CustomPDDocumentFactory pdfDocumentFactory;
|
||||
|
||||
@Autowired
|
||||
public ConvertHtmlToPDF(
|
||||
CustomPDDocumentFactory pdfDocumentFactory,
|
||||
@Qualifier("bookAndHtmlFormatsInstalled") boolean bookAndHtmlFormatsInstalled) {
|
||||
this.pdfDocumentFactory = pdfDocumentFactory;
|
||||
this.bookAndHtmlFormatsInstalled = bookAndHtmlFormatsInstalled;
|
||||
}
|
||||
|
||||
@PostMapping(consumes = "multipart/form-data", value = "/html/pdf")
|
||||
@Operation(
|
||||
@@ -49,6 +61,8 @@ public class ConvertHtmlToPDF {
|
||||
originalFilename,
|
||||
bookAndHtmlFormatsInstalled);
|
||||
|
||||
pdfBytes = pdfDocumentFactory.createNewBytesBasedOnOldDocument(pdfBytes);
|
||||
|
||||
String outputFilename =
|
||||
originalFilename.replaceFirst("[.][^.]+$", "")
|
||||
+ ".pdf"; // Remove file extension and append .pdf
|
||||
|
||||
@@ -82,7 +82,7 @@ public class ConvertImgPDFController {
|
||||
result =
|
||||
PdfUtils.convertFromPdf(
|
||||
pdfBytes,
|
||||
imageFormat.equalsIgnoreCase("webp") ? "png" : imageFormat.toUpperCase(),
|
||||
"webp".equalsIgnoreCase(imageFormat) ? "png" : imageFormat.toUpperCase(),
|
||||
colorTypeResult,
|
||||
singleImage,
|
||||
Integer.valueOf(dpi),
|
||||
@@ -90,9 +90,9 @@ public class ConvertImgPDFController {
|
||||
if (result == null || result.length == 0) {
|
||||
logger.error("resultant bytes for {} is null, error converting ", filename);
|
||||
}
|
||||
if (imageFormat.equalsIgnoreCase("webp") && !CheckProgramInstall.isPythonAvailable()) {
|
||||
if ("webp".equalsIgnoreCase(imageFormat) && !CheckProgramInstall.isPythonAvailable()) {
|
||||
throw new IOException("Python is not installed. Required for WebP conversion.");
|
||||
} else if (imageFormat.equalsIgnoreCase("webp")
|
||||
} else if ("webp".equalsIgnoreCase(imageFormat)
|
||||
&& CheckProgramInstall.isPythonAvailable()) {
|
||||
// Write the output stream to a temp file
|
||||
Path tempFile = Files.createTempFile("temp_png", ".png");
|
||||
|
||||
@@ -10,28 +10,40 @@ import org.commonmark.node.Node;
|
||||
import org.commonmark.parser.Parser;
|
||||
import org.commonmark.renderer.html.AttributeProvider;
|
||||
import org.commonmark.renderer.html.HtmlRenderer;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
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.github.pixee.security.Filenames;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
|
||||
import stirling.software.SPDF.model.api.GeneralFile;
|
||||
import stirling.software.SPDF.service.CustomPDDocumentFactory;
|
||||
import stirling.software.SPDF.utils.FileToPdf;
|
||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||
|
||||
// Disabled for now
|
||||
// @RestController
|
||||
// @Tag(name = "Convert", description = "Convert APIs")
|
||||
// @RequestMapping("/api/v1/convert")
|
||||
@RestController
|
||||
@Tag(name = "Convert", description = "Convert APIs")
|
||||
@RequestMapping("/api/v1/convert")
|
||||
public class ConvertMarkdownToPdf {
|
||||
|
||||
// @Autowired
|
||||
@Qualifier("bookAndHtmlFormatsInstalled")
|
||||
private boolean bookAndHtmlFormatsInstalled;
|
||||
private final boolean bookAndHtmlFormatsInstalled;
|
||||
|
||||
private final CustomPDDocumentFactory pdfDocumentFactory;
|
||||
|
||||
@Autowired
|
||||
public ConvertMarkdownToPdf(
|
||||
CustomPDDocumentFactory pdfDocumentFactory,
|
||||
@Qualifier("bookAndHtmlFormatsInstalled") boolean bookAndHtmlFormatsInstalled) {
|
||||
this.pdfDocumentFactory = pdfDocumentFactory;
|
||||
this.bookAndHtmlFormatsInstalled = bookAndHtmlFormatsInstalled;
|
||||
}
|
||||
|
||||
@PostMapping(consumes = "multipart/form-data", value = "/markdown/pdf")
|
||||
@Operation(
|
||||
@@ -70,7 +82,7 @@ public class ConvertMarkdownToPdf {
|
||||
htmlContent.getBytes(),
|
||||
"converted.html",
|
||||
bookAndHtmlFormatsInstalled);
|
||||
|
||||
pdfBytes = pdfDocumentFactory.createNewBytesBasedOnOldDocument(pdfBytes);
|
||||
String outputFilename =
|
||||
originalFilename.replaceFirst("[.][^.]+$", "")
|
||||
+ ".pdf"; // Remove file extension and append .pdf
|
||||
|
||||
@@ -6,6 +6,7 @@ import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||
@@ -20,13 +21,12 @@ import stirling.software.SPDF.utils.ProcessExecutor;
|
||||
import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult;
|
||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||
|
||||
// Disabled for now
|
||||
// @RestController
|
||||
// @Tag(name = "Convert", description = "Convert APIs")
|
||||
// @RequestMapping("/api/v1/convert")
|
||||
public class ConvertPDFToBookController {
|
||||
|
||||
// @Autowired
|
||||
@Autowired
|
||||
@Qualifier("bookAndHtmlFormatsInstalled")
|
||||
private boolean bookAndHtmlFormatsInstalled;
|
||||
|
||||
|
||||
@@ -21,10 +21,13 @@ import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import stirling.software.SPDF.config.security.saml2.CustomSaml2AuthenticatedPrincipal;
|
||||
import stirling.software.SPDF.config.security.session.SessionPersistentRegistry;
|
||||
import stirling.software.SPDF.model.*;
|
||||
import stirling.software.SPDF.model.ApplicationProperties.Security;
|
||||
import stirling.software.SPDF.model.ApplicationProperties.Security.OAUTH2;
|
||||
import stirling.software.SPDF.model.ApplicationProperties.Security.OAUTH2.Client;
|
||||
import stirling.software.SPDF.model.ApplicationProperties.Security.SAML2;
|
||||
import stirling.software.SPDF.model.provider.GithubProvider;
|
||||
import stirling.software.SPDF.model.provider.GoogleProvider;
|
||||
import stirling.software.SPDF.model.provider.KeycloakProvider;
|
||||
@@ -51,27 +54,44 @@ public class AccountWebController {
|
||||
|
||||
Map<String, String> providerList = new HashMap<>();
|
||||
|
||||
OAUTH2 oauth = applicationProperties.getSecurity().getOauth2();
|
||||
Security securityProps = applicationProperties.getSecurity();
|
||||
|
||||
OAUTH2 oauth = securityProps.getOauth2();
|
||||
if (oauth != null) {
|
||||
if (oauth.isSettingsValid()) {
|
||||
providerList.put("oidc", oauth.getProvider());
|
||||
if (oauth.getEnabled()) {
|
||||
if (oauth.isSettingsValid()) {
|
||||
providerList.put("/oauth2/authorization/oidc", oauth.getProvider());
|
||||
}
|
||||
Client client = oauth.getClient();
|
||||
if (client != null) {
|
||||
GoogleProvider google = client.getGoogle();
|
||||
if (google.isSettingsValid()) {
|
||||
providerList.put(
|
||||
"/oauth2/authorization/" + google.getName(),
|
||||
google.getClientName());
|
||||
}
|
||||
|
||||
GithubProvider github = client.getGithub();
|
||||
if (github.isSettingsValid()) {
|
||||
providerList.put(
|
||||
"/oauth2/authorization/" + github.getName(),
|
||||
github.getClientName());
|
||||
}
|
||||
|
||||
KeycloakProvider keycloak = client.getKeycloak();
|
||||
if (keycloak.isSettingsValid()) {
|
||||
providerList.put(
|
||||
"/oauth2/authorization/" + keycloak.getName(),
|
||||
keycloak.getClientName());
|
||||
}
|
||||
}
|
||||
}
|
||||
Client client = oauth.getClient();
|
||||
if (client != null) {
|
||||
GoogleProvider google = client.getGoogle();
|
||||
if (google.isSettingsValid()) {
|
||||
providerList.put(google.getName(), google.getClientName());
|
||||
}
|
||||
}
|
||||
|
||||
GithubProvider github = client.getGithub();
|
||||
if (github.isSettingsValid()) {
|
||||
providerList.put(github.getName(), github.getClientName());
|
||||
}
|
||||
|
||||
KeycloakProvider keycloak = client.getKeycloak();
|
||||
if (keycloak.isSettingsValid()) {
|
||||
providerList.put(keycloak.getName(), keycloak.getClientName());
|
||||
}
|
||||
SAML2 saml2 = securityProps.getSaml2();
|
||||
if (saml2 != null) {
|
||||
if (saml2.getEnabled()) {
|
||||
providerList.put("/saml2/authenticate/" + saml2.getRegistrationId(), "SAML 2");
|
||||
}
|
||||
}
|
||||
// Remove any null keys/values from the providerList
|
||||
@@ -80,9 +100,8 @@ public class AccountWebController {
|
||||
.removeIf(entry -> entry.getKey() == null || entry.getValue() == null);
|
||||
model.addAttribute("providerlist", providerList);
|
||||
|
||||
model.addAttribute("loginMethod", applicationProperties.getSecurity().getLoginMethod());
|
||||
model.addAttribute(
|
||||
"oAuth2Enabled", applicationProperties.getSecurity().getOauth2().getEnabled());
|
||||
model.addAttribute("loginMethod", securityProps.getLoginMethod());
|
||||
model.addAttribute("altLogin", securityProps.isAltLogin());
|
||||
|
||||
model.addAttribute("currentPage", "login");
|
||||
|
||||
@@ -349,6 +368,17 @@ public class AccountWebController {
|
||||
// Add oAuth2 Login attributes to the model
|
||||
model.addAttribute("oAuth2Login", true);
|
||||
}
|
||||
if (principal instanceof CustomSaml2AuthenticatedPrincipal) {
|
||||
// Cast the principal object to OAuth2User
|
||||
CustomSaml2AuthenticatedPrincipal userDetails =
|
||||
(CustomSaml2AuthenticatedPrincipal) principal;
|
||||
|
||||
// Retrieve username and other attributes
|
||||
username = userDetails.getName();
|
||||
// Add oAuth2 Login attributes to the model
|
||||
model.addAttribute("oAuth2Login", true);
|
||||
}
|
||||
|
||||
if (username != null) {
|
||||
// Fetch user details from the database
|
||||
Optional<User> user =
|
||||
|
||||
@@ -1,20 +1,29 @@
|
||||
package stirling.software.SPDF.model;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.PropertySource;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.FileSystemResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
import stirling.software.SPDF.config.YamlPropertySourceFactory;
|
||||
import stirling.software.SPDF.model.provider.GithubProvider;
|
||||
@@ -38,7 +47,6 @@ public class ApplicationProperties {
|
||||
private AutomaticallyGenerated automaticallyGenerated = new AutomaticallyGenerated();
|
||||
private EnterpriseEdition enterpriseEdition = new EnterpriseEdition();
|
||||
private AutoPipeline autoPipeline = new AutoPipeline();
|
||||
private static final Logger logger = LoggerFactory.getLogger(ApplicationProperties.class);
|
||||
|
||||
@Data
|
||||
public static class AutoPipeline {
|
||||
@@ -60,48 +68,119 @@ public class ApplicationProperties {
|
||||
private Boolean csrfDisabled;
|
||||
private InitialLogin initialLogin = new InitialLogin();
|
||||
private OAUTH2 oauth2 = new OAUTH2();
|
||||
private SAML saml = new SAML();
|
||||
private SAML2 saml2 = new SAML2();
|
||||
private int loginAttemptCount;
|
||||
private long loginResetTimeMinutes;
|
||||
private String loginMethod = "all";
|
||||
|
||||
public Boolean isAltLogin() {
|
||||
return saml2.getEnabled() || oauth2.getEnabled();
|
||||
}
|
||||
|
||||
public enum LoginMethods {
|
||||
ALL("all"),
|
||||
NORMAL("normal"),
|
||||
OAUTH2("oauth2"),
|
||||
SAML2("saml2");
|
||||
|
||||
private String method;
|
||||
|
||||
LoginMethods(String method) {
|
||||
this.method = method;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return method;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isUserPass() {
|
||||
return (loginMethod.equalsIgnoreCase(LoginMethods.NORMAL.toString())
|
||||
|| loginMethod.equalsIgnoreCase(LoginMethods.ALL.toString()));
|
||||
}
|
||||
|
||||
public boolean isOauth2Activ() {
|
||||
return (oauth2 != null
|
||||
&& oauth2.getEnabled()
|
||||
&& !loginMethod.equalsIgnoreCase(LoginMethods.NORMAL.toString()));
|
||||
}
|
||||
|
||||
public boolean isSaml2Activ() {
|
||||
return (saml2 != null
|
||||
&& saml2.getEnabled()
|
||||
&& !loginMethod.equalsIgnoreCase(LoginMethods.NORMAL.toString()));
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class InitialLogin {
|
||||
private String username;
|
||||
@ToString.Exclude private String password;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class SAML {
|
||||
@Getter
|
||||
@Setter
|
||||
public static class SAML2 {
|
||||
private Boolean enabled = false;
|
||||
private String entityId;
|
||||
private String registrationId;
|
||||
private String spBaseUrl;
|
||||
private String idpMetadataLocation;
|
||||
// private KeyStore keystore;
|
||||
private String privateKeyLocation;
|
||||
private String certificateLocation;
|
||||
private String singleLogoutBinding;
|
||||
private String singleLogoutResponseUri;
|
||||
private String signingCertificate;
|
||||
private Boolean autoCreateUser = false;
|
||||
private Boolean blockRegistration = false;
|
||||
private String entityId = "stirling";
|
||||
private String registrationId = "stirling";
|
||||
private String idpMetadataUri;
|
||||
private String idpSingleLogoutUrl;
|
||||
private String idpSingleLoginUrl;
|
||||
private String idpIssuer;
|
||||
private String idpCert;
|
||||
private String privateKey;
|
||||
private String spCert;
|
||||
|
||||
// @Data
|
||||
// public static class KeyStore {
|
||||
// private String keystoreLocation;
|
||||
// private String keystorePassword;
|
||||
// private String keyAlias;
|
||||
// private String keyPassword;
|
||||
// private String realmCertificateAlias;
|
||||
//
|
||||
// public Resource getKeystoreResource() {
|
||||
// if (keystoreLocation.startsWith("classpath:")) {
|
||||
// return new ClassPathResource(
|
||||
// keystoreLocation.substring("classpath:".length()));
|
||||
// } else {
|
||||
// return new FileSystemResource(keystoreLocation);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
public InputStream getIdpMetadataUri() throws IOException {
|
||||
if (idpMetadataUri.startsWith("classpath:")) {
|
||||
return new ClassPathResource(idpMetadataUri.substring("classpath".length()))
|
||||
.getInputStream();
|
||||
}
|
||||
try {
|
||||
URI uri = new URI(idpMetadataUri);
|
||||
URL url = uri.toURL();
|
||||
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
||||
connection.setRequestMethod("GET");
|
||||
return connection.getInputStream();
|
||||
} catch (URISyntaxException e) {
|
||||
throw new IOException("Invalid URI format: " + idpMetadataUri, e);
|
||||
}
|
||||
}
|
||||
|
||||
public String getIdpMetadataUriString() {
|
||||
return this.idpMetadataUri;
|
||||
}
|
||||
|
||||
public Resource getSpCert() {
|
||||
if (spCert.startsWith("classpath:")) {
|
||||
return new ClassPathResource(spCert.substring("classpath:".length()));
|
||||
} else {
|
||||
return new FileSystemResource(spCert);
|
||||
}
|
||||
}
|
||||
|
||||
public Resource getidpCert() {
|
||||
if (idpCert.startsWith("classpath:")) {
|
||||
return new ClassPathResource(idpCert.substring("classpath:".length()));
|
||||
} else {
|
||||
return new FileSystemResource(idpCert);
|
||||
}
|
||||
}
|
||||
|
||||
public Resource getPrivateKey() {
|
||||
if (privateKey.startsWith("classpath:")) {
|
||||
return new ClassPathResource(privateKey.substring("classpath:".length()));
|
||||
} else {
|
||||
return new FileSystemResource(privateKey);
|
||||
}
|
||||
}
|
||||
|
||||
public String getEntityId() {
|
||||
return entityId;
|
||||
}
|
||||
}
|
||||
|
||||
@Data
|
||||
@@ -220,6 +299,7 @@ public class ApplicationProperties {
|
||||
public static class EnterpriseEdition {
|
||||
private boolean enabled;
|
||||
@ToString.Exclude private String key;
|
||||
private int maxUsers;
|
||||
private CustomMetadata customMetadata = new CustomMetadata();
|
||||
|
||||
@Data
|
||||
|
||||
@@ -19,7 +19,6 @@ public class Provider implements ProviderInterface {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
// throw new IllegalArgumentException(getName() + ": " + name + " is required!");
|
||||
}
|
||||
|
||||
protected boolean isValid(Collection<String> value, String name) {
|
||||
@@ -27,66 +26,55 @@ public class Provider implements ProviderInterface {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
// throw new IllegalArgumentException(getName() + ": " + name + " is required!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> getScopes() {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'getScope'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setScopes(String scopes) {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'setScope'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUseAsUsername() {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'getUseAsUsername'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUseAsUsername(String useAsUsername) {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'setUseAsUsername'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIssuer() {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'getIssuer'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setIssuer(String issuer) {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'setIssuer'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getClientSecret() {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'getClientSecret'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setClientSecret(String clientSecret) {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'setClientSecret'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getClientId() {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'getClientId'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setClientId(String clientId) {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'setClientId'");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,36 @@ public class CustomPDDocumentFactory {
|
||||
return document;
|
||||
}
|
||||
|
||||
public byte[] createNewBytesBasedOnOldDocument(byte[] oldDocument) throws IOException {
|
||||
PDDocument document = Loader.loadPDF(oldDocument);
|
||||
return createNewBytesBasedOnOldDocument(document);
|
||||
}
|
||||
|
||||
public byte[] createNewBytesBasedOnOldDocument(File oldDocument) throws IOException {
|
||||
PDDocument document = Loader.loadPDF(oldDocument);
|
||||
return createNewBytesBasedOnOldDocument(document);
|
||||
}
|
||||
|
||||
public byte[] createNewBytesBasedOnOldDocument(PDDocument oldDocument) throws IOException {
|
||||
pdfMetadataService.setMetadataToPdf(
|
||||
oldDocument, pdfMetadataService.extractMetadataFromPdf(oldDocument), true);
|
||||
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
oldDocument.save(baos);
|
||||
oldDocument.close();
|
||||
return baos.toByteArray();
|
||||
}
|
||||
|
||||
public PDDocument createNewDocumentBasedOnOldDocument(byte[] oldDocument) throws IOException {
|
||||
PDDocument document = Loader.loadPDF(oldDocument);
|
||||
return createNewDocumentBasedOnOldDocument(document);
|
||||
}
|
||||
|
||||
public PDDocument createNewDocumentBasedOnOldDocument(File oldDocument) throws IOException {
|
||||
PDDocument document = Loader.loadPDF(oldDocument);
|
||||
return createNewDocumentBasedOnOldDocument(document);
|
||||
}
|
||||
|
||||
public PDDocument createNewDocumentBasedOnOldDocument(PDDocument oldDocument)
|
||||
throws IOException {
|
||||
PDDocument document = new PDDocument();
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
package stirling.software.SPDF.utils;
|
||||
|
||||
import org.owasp.html.HtmlPolicyBuilder;
|
||||
import org.owasp.html.PolicyFactory;
|
||||
import org.owasp.html.Sanitizers;
|
||||
|
||||
public class CustomHtmlSanitizer {
|
||||
private static final PolicyFactory POLICY =
|
||||
Sanitizers.FORMATTING
|
||||
.and(Sanitizers.BLOCKS)
|
||||
.and(Sanitizers.STYLES)
|
||||
.and(Sanitizers.LINKS)
|
||||
.and(Sanitizers.TABLES)
|
||||
.and(Sanitizers.IMAGES)
|
||||
.and(new HtmlPolicyBuilder().disallowElements("noscript").toFactory());
|
||||
|
||||
public static String sanitize(String html) {
|
||||
String htmlAfter = POLICY.sanitize(html);
|
||||
return htmlAfter;
|
||||
}
|
||||
}
|
||||
@@ -2,16 +2,23 @@ package stirling.software.SPDF.utils;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.FileVisitResult;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.SimpleFileVisitor;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
import io.github.pixee.security.ZipSecurity;
|
||||
|
||||
@@ -33,19 +40,25 @@ public class FileToPdf {
|
||||
try {
|
||||
if (fileName.endsWith(".html")) {
|
||||
tempInputFile = Files.createTempFile("input_", ".html");
|
||||
Files.write(tempInputFile, fileBytes);
|
||||
} else {
|
||||
String sanitizedHtml =
|
||||
sanitizeHtmlContent(new String(fileBytes, StandardCharsets.UTF_8));
|
||||
Files.write(tempInputFile, sanitizedHtml.getBytes(StandardCharsets.UTF_8));
|
||||
} else if (fileName.endsWith(".zip")) {
|
||||
tempInputFile = Files.createTempFile("input_", ".zip");
|
||||
Files.write(tempInputFile, fileBytes);
|
||||
sanitizeHtmlFilesInZip(tempInputFile);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unsupported file format: " + fileName);
|
||||
}
|
||||
|
||||
List<String> command = new ArrayList<>();
|
||||
if (!htmlFormatsInstalled) {
|
||||
command.add("weasyprint");
|
||||
command.add("-e utf-8");
|
||||
command.add("-e");
|
||||
command.add("utf-8");
|
||||
command.add("-v");
|
||||
command.add(tempInputFile.toString());
|
||||
command.add(tempOutputFile.toString());
|
||||
|
||||
} else {
|
||||
command.add("ebook-convert");
|
||||
command.add(tempInputFile.toString());
|
||||
@@ -54,10 +67,8 @@ public class FileToPdf {
|
||||
command.add("a4");
|
||||
|
||||
if (request != null && request.getZoom() != 1.0) {
|
||||
// Create a temporary CSS file
|
||||
File tempCssFile = Files.createTempFile("customStyle", ".css").toFile();
|
||||
try (FileWriter writer = new FileWriter(tempCssFile)) {
|
||||
// Write the CSS rule to the file
|
||||
writer.write("body { zoom: " + request.getZoom() + "; }");
|
||||
}
|
||||
command.add("--extra-css");
|
||||
@@ -65,9 +76,7 @@ public class FileToPdf {
|
||||
}
|
||||
}
|
||||
|
||||
ProcessExecutorResult returnCode;
|
||||
|
||||
returnCode =
|
||||
ProcessExecutorResult returnCode =
|
||||
ProcessExecutor.getInstance(ProcessExecutor.Processes.WEASYPRINT)
|
||||
.runCommandWithOutputHandling(command);
|
||||
|
||||
@@ -78,8 +87,6 @@ public class FileToPdf {
|
||||
throw e;
|
||||
}
|
||||
} finally {
|
||||
|
||||
// Clean up temporary files
|
||||
Files.deleteIfExists(tempOutputFile);
|
||||
Files.deleteIfExists(tempInputFile);
|
||||
}
|
||||
@@ -87,6 +94,81 @@ public class FileToPdf {
|
||||
return pdfBytes;
|
||||
}
|
||||
|
||||
private static String sanitizeHtmlContent(String htmlContent) {
|
||||
return CustomHtmlSanitizer.sanitize(htmlContent);
|
||||
}
|
||||
|
||||
private static void sanitizeHtmlFilesInZip(Path zipFilePath) throws IOException {
|
||||
Path tempUnzippedDir = Files.createTempDirectory("unzipped_");
|
||||
try (ZipInputStream zipIn =
|
||||
ZipSecurity.createHardenedInputStream(
|
||||
new ByteArrayInputStream(Files.readAllBytes(zipFilePath)))) {
|
||||
ZipEntry entry = zipIn.getNextEntry();
|
||||
while (entry != null) {
|
||||
Path filePath = tempUnzippedDir.resolve(entry.getName());
|
||||
if (!entry.isDirectory()) {
|
||||
Files.createDirectories(filePath.getParent());
|
||||
if (entry.getName().toLowerCase().endsWith(".html")
|
||||
|| entry.getName().toLowerCase().endsWith(".htm")) {
|
||||
String content = new String(zipIn.readAllBytes(), StandardCharsets.UTF_8);
|
||||
String sanitizedContent = sanitizeHtmlContent(content);
|
||||
Files.write(filePath, sanitizedContent.getBytes(StandardCharsets.UTF_8));
|
||||
} else {
|
||||
Files.copy(zipIn, filePath);
|
||||
}
|
||||
}
|
||||
zipIn.closeEntry();
|
||||
entry = zipIn.getNextEntry();
|
||||
}
|
||||
}
|
||||
|
||||
// Repack the sanitized files
|
||||
zipDirectory(tempUnzippedDir, zipFilePath);
|
||||
|
||||
// Clean up
|
||||
deleteDirectory(tempUnzippedDir);
|
||||
}
|
||||
|
||||
private static void zipDirectory(Path sourceDir, Path zipFilePath) throws IOException {
|
||||
try (ZipOutputStream zos =
|
||||
new ZipOutputStream(new FileOutputStream(zipFilePath.toFile()))) {
|
||||
Files.walk(sourceDir)
|
||||
.filter(path -> !Files.isDirectory(path))
|
||||
.forEach(
|
||||
path -> {
|
||||
ZipEntry zipEntry =
|
||||
new ZipEntry(sourceDir.relativize(path).toString());
|
||||
try {
|
||||
zos.putNextEntry(zipEntry);
|
||||
Files.copy(path, zos);
|
||||
zos.closeEntry();
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private static void deleteDirectory(Path dir) throws IOException {
|
||||
Files.walkFileTree(
|
||||
dir,
|
||||
new SimpleFileVisitor<Path>() {
|
||||
@Override
|
||||
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
|
||||
throws IOException {
|
||||
Files.delete(file);
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileVisitResult postVisitDirectory(Path dir, IOException exc)
|
||||
throws IOException {
|
||||
Files.delete(dir);
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static Path unzipAndGetMainHtml(byte[] fileBytes) throws IOException {
|
||||
Path tempDirectory = Files.createTempDirectory("unzipped_");
|
||||
try (ZipInputStream zipIn =
|
||||
|
||||
@@ -50,4 +50,6 @@ springdoc.swagger-ui.url=/v1/api-docs
|
||||
|
||||
|
||||
posthog.api.key=phc_fiR65u5j6qmXTYL56MNrLZSWqLaDW74OrZH0Insd2xq
|
||||
posthog.host=https://eu.i.posthog.com
|
||||
posthog.host=https://eu.i.posthog.com
|
||||
|
||||
server.port=8090
|
||||
@@ -76,6 +76,7 @@ donate=تبرع
|
||||
color=لون
|
||||
sponsor=راعٍ
|
||||
info=معلومات
|
||||
pro=Pro
|
||||
page=Page
|
||||
pages=Pages
|
||||
|
||||
@@ -110,8 +111,24 @@ pipelineOptions.pipelineHeader=خط الأنابيب:
|
||||
pipelineOptions.saveButton=تنزيل
|
||||
pipelineOptions.validateButton=تحقق
|
||||
|
||||
########################
|
||||
# ENTERPRISE EDITION #
|
||||
########################
|
||||
enterpriseEdition.button=Upgrade to Pro
|
||||
enterpriseEdition.warning=This feature is only available to Pro users.
|
||||
enterpriseEdition.yamlAdvert=Stirling PDF Pro supports YAML configuration files and other SSO features.
|
||||
enterpriseEdition.ssoAdvert=Looking for more user management features? Check out Stirling PDF Pro
|
||||
|
||||
|
||||
#################
|
||||
# Analytics #
|
||||
#################
|
||||
analytics.title=Do you want make Stirling PDF better?
|
||||
analytics.paragraph1=Stirling PDF has opt in analytics to help us improve the product. We do not track any personal information or file contents.
|
||||
analytics.paragraph2=Please consider enabling analytics to help Stirling-PDF grow and to allow us to understand our users better.
|
||||
analytics.enable=Enable analytics
|
||||
analytics.disable=Disable analytics
|
||||
analytics.settings=You can change the settings for analytics in the config/settings.yml file
|
||||
|
||||
#############
|
||||
# NAVBAR #
|
||||
@@ -128,6 +145,7 @@ navbar.sections.convertFrom=تحويل من PDF
|
||||
navbar.sections.security=التوقيع والأمان
|
||||
navbar.sections.advance=متقدم
|
||||
navbar.sections.edit=عرض وتعديل
|
||||
navbar.sections.popular=Popular
|
||||
|
||||
#############
|
||||
# SETTINGS #
|
||||
@@ -225,6 +243,8 @@ database.fileNotFound=لم يتم العثور على الملف
|
||||
database.fileNullOrEmpty=يجب ألا يكون الملف فارغًا أو خاليًا
|
||||
database.failedImportFile=فشل استيراد الملف
|
||||
|
||||
session.expired=Your session has expired. Please refresh the page and try again.
|
||||
|
||||
#############
|
||||
# HOME-PAGE #
|
||||
#############
|
||||
@@ -482,6 +502,11 @@ home.removeImagePdf.title=إزالة الصورة
|
||||
home.removeImagePdf.desc=إزالة الصورة من PDF لتقليل حجم الملف
|
||||
removeImagePdf.tags=إزالة الصورة,عمليات الصفحة,الخلفية,جانب الخادم
|
||||
|
||||
|
||||
home.splitPdfByChapters.title=Split PDF by Chapters
|
||||
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
||||
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
||||
|
||||
#replace-invert-color
|
||||
replace-color.title=Replace-Invert-Color
|
||||
replace-color.header=Replace-Invert Color PDF
|
||||
@@ -526,7 +551,10 @@ login.oauth2AccessDenied=تم رفض الوصول
|
||||
login.oauth2InvalidTokenResponse=استجابة الرمز المميز غير صالحة
|
||||
login.oauth2InvalidIdToken=رمز الهوية غير صالح
|
||||
login.userIsDisabled=تم تعطيل المستخدم، تم حظر تسجيل الدخول حاليًا باستخدام اسم المستخدم هذا. يرجى الاتصال بالمسؤول.
|
||||
|
||||
login.alreadyLoggedIn=You are already logged in to
|
||||
login.alreadyLoggedIn2=devices. Please log out of the devices and try again.
|
||||
login.toManySessions=You have too many active sessions
|
||||
login.toManySessions2=Please log out of the devices and try again. Alternatively, you can upgrade to Stirling PDF Pro.
|
||||
|
||||
#auto-redact
|
||||
autoRedact.title=حجب تلقائي
|
||||
@@ -1154,6 +1182,8 @@ licenses.license=الترخيص
|
||||
survey.nav=استطلاع
|
||||
survey.title=استطلاع Stirling-PDF
|
||||
survey.description=Stirling-PDF لا يحتوي على تتبع لذا نريد أن نسمع من مستخدمينا لتحسين Stirling-PDF!
|
||||
survey.changes=Stirling-PDF has changed since the last survey! To find out more please check our blog post here:
|
||||
survey.changes2=With these changes we are getting paid business support and funding
|
||||
survey.please=يرجى النظر في المشاركة في استطلاعنا!
|
||||
survey.disabled=(سيتم تعطيل النافذة المنبثقة للاستطلاع في التحديثات التالية ولكنها ستكون متاحة في أسفل الصفحة)
|
||||
survey.button=المشاركة في الاستطلاع
|
||||
@@ -1179,3 +1209,17 @@ removeImage.title=إزالة الصورة
|
||||
removeImage.header=إزالة الصورة
|
||||
removeImage.removeImage=إزالة الصورة
|
||||
removeImage.submit=إزالة الصورة
|
||||
|
||||
|
||||
splitByChapters.title=Split PDF by Chapters
|
||||
splitByChapters.header=Split PDF by Chapters
|
||||
splitByChapters.bookmarkLevel=Bookmark Level
|
||||
splitByChapters.includeMetadata=Include Metadata
|
||||
splitByChapters.allowDuplicates=Allow Duplicates
|
||||
splitByChapters.desc.1=This tool splits a PDF file into multiple PDFs based on its chapter structure.
|
||||
splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for splitting (0 for top-level, 1 for second-level, etc.).
|
||||
splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF.
|
||||
splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs.
|
||||
splitByChapters.submit=Split PDF
|
||||
|
||||
|
||||
|
||||
@@ -76,6 +76,7 @@ donate=Направете дарение
|
||||
color=Цвят
|
||||
sponsor=Спонсор
|
||||
info=Info
|
||||
pro=Pro
|
||||
page=Page
|
||||
pages=Pages
|
||||
|
||||
@@ -110,8 +111,24 @@ pipelineOptions.pipelineHeader=Pipeline:
|
||||
pipelineOptions.saveButton=Изтегли
|
||||
pipelineOptions.validateButton=Валидирай
|
||||
|
||||
########################
|
||||
# ENTERPRISE EDITION #
|
||||
########################
|
||||
enterpriseEdition.button=Upgrade to Pro
|
||||
enterpriseEdition.warning=This feature is only available to Pro users.
|
||||
enterpriseEdition.yamlAdvert=Stirling PDF Pro supports YAML configuration files and other SSO features.
|
||||
enterpriseEdition.ssoAdvert=Looking for more user management features? Check out Stirling PDF Pro
|
||||
|
||||
|
||||
#################
|
||||
# Analytics #
|
||||
#################
|
||||
analytics.title=Do you want make Stirling PDF better?
|
||||
analytics.paragraph1=Stirling PDF has opt in analytics to help us improve the product. We do not track any personal information or file contents.
|
||||
analytics.paragraph2=Please consider enabling analytics to help Stirling-PDF grow and to allow us to understand our users better.
|
||||
analytics.enable=Enable analytics
|
||||
analytics.disable=Disable analytics
|
||||
analytics.settings=You can change the settings for analytics in the config/settings.yml file
|
||||
|
||||
#############
|
||||
# NAVBAR #
|
||||
@@ -128,6 +145,7 @@ navbar.sections.convertFrom=Преобразуване от PDF
|
||||
navbar.sections.security=Подписване и сигурност
|
||||
navbar.sections.advance=Разширено
|
||||
navbar.sections.edit=Преглед и редактиране
|
||||
navbar.sections.popular=Popular
|
||||
|
||||
#############
|
||||
# SETTINGS #
|
||||
@@ -225,6 +243,8 @@ database.fileNotFound=File not Found
|
||||
database.fileNullOrEmpty=File must not be null or empty
|
||||
database.failedImportFile=Failed Import File
|
||||
|
||||
session.expired=Your session has expired. Please refresh the page and try again.
|
||||
|
||||
#############
|
||||
# HOME-PAGE #
|
||||
#############
|
||||
@@ -482,6 +502,11 @@ home.removeImagePdf.title=Remove image
|
||||
home.removeImagePdf.desc=Remove image from PDF to reduce file size
|
||||
removeImagePdf.tags=Remove Image,Page operations,Back end,server side
|
||||
|
||||
|
||||
home.splitPdfByChapters.title=Split PDF by Chapters
|
||||
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
||||
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
||||
|
||||
#replace-invert-color
|
||||
replace-color.title=Replace-Invert-Color
|
||||
replace-color.header=Replace-Invert Color PDF
|
||||
@@ -526,7 +551,10 @@ login.oauth2AccessDenied=Отказан достъп
|
||||
login.oauth2InvalidTokenResponse=Невалиден отговор на токена
|
||||
login.oauth2InvalidIdToken=Невалиден токен за идентификатор
|
||||
login.userIsDisabled=User is deactivated, login is currently blocked with this username. Please contact the administrator.
|
||||
|
||||
login.alreadyLoggedIn=You are already logged in to
|
||||
login.alreadyLoggedIn2=devices. Please log out of the devices and try again.
|
||||
login.toManySessions=You have too many active sessions
|
||||
login.toManySessions2=Please log out of the devices and try again. Alternatively, you can upgrade to Stirling PDF Pro.
|
||||
|
||||
#auto-redact
|
||||
autoRedact.title=Автоматично редактиране
|
||||
@@ -1154,6 +1182,8 @@ licenses.license=Лиценз
|
||||
survey.nav=Survey
|
||||
survey.title=Stirling-PDF Survey
|
||||
survey.description=Stirling-PDF has no tracking so we want to hear from our users to improve Stirling-PDF!
|
||||
survey.changes=Stirling-PDF has changed since the last survey! To find out more please check our blog post here:
|
||||
survey.changes2=With these changes we are getting paid business support and funding
|
||||
survey.please=Please consider taking our survey!
|
||||
survey.disabled=(Survey popup will be disabled in following updates but available at foot of page)
|
||||
survey.button=Take Survey
|
||||
@@ -1179,3 +1209,17 @@ removeImage.title=Remove image
|
||||
removeImage.header=Remove image
|
||||
removeImage.removeImage=Remove image
|
||||
removeImage.submit=Remove image
|
||||
|
||||
|
||||
splitByChapters.title=Split PDF by Chapters
|
||||
splitByChapters.header=Split PDF by Chapters
|
||||
splitByChapters.bookmarkLevel=Bookmark Level
|
||||
splitByChapters.includeMetadata=Include Metadata
|
||||
splitByChapters.allowDuplicates=Allow Duplicates
|
||||
splitByChapters.desc.1=This tool splits a PDF file into multiple PDFs based on its chapter structure.
|
||||
splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for splitting (0 for top-level, 1 for second-level, etc.).
|
||||
splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF.
|
||||
splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs.
|
||||
splitByChapters.submit=Split PDF
|
||||
|
||||
|
||||
|
||||
@@ -76,6 +76,7 @@ donate=Donate
|
||||
color=Color
|
||||
sponsor=Sponsor
|
||||
info=Info
|
||||
pro=Pro
|
||||
page=Page
|
||||
pages=Pages
|
||||
|
||||
@@ -110,8 +111,24 @@ pipelineOptions.pipelineHeader=Pipeline:
|
||||
pipelineOptions.saveButton=Download
|
||||
pipelineOptions.validateButton=Validate
|
||||
|
||||
########################
|
||||
# ENTERPRISE EDITION #
|
||||
########################
|
||||
enterpriseEdition.button=Upgrade to Pro
|
||||
enterpriseEdition.warning=This feature is only available to Pro users.
|
||||
enterpriseEdition.yamlAdvert=Stirling PDF Pro supports YAML configuration files and other SSO features.
|
||||
enterpriseEdition.ssoAdvert=Looking for more user management features? Check out Stirling PDF Pro
|
||||
|
||||
|
||||
#################
|
||||
# Analytics #
|
||||
#################
|
||||
analytics.title=Do you want make Stirling PDF better?
|
||||
analytics.paragraph1=Stirling PDF has opt in analytics to help us improve the product. We do not track any personal information or file contents.
|
||||
analytics.paragraph2=Please consider enabling analytics to help Stirling-PDF grow and to allow us to understand our users better.
|
||||
analytics.enable=Enable analytics
|
||||
analytics.disable=Disable analytics
|
||||
analytics.settings=You can change the settings for analytics in the config/settings.yml file
|
||||
|
||||
#############
|
||||
# NAVBAR #
|
||||
@@ -128,6 +145,7 @@ navbar.sections.convertFrom=Convert from PDF
|
||||
navbar.sections.security=Sign & Security
|
||||
navbar.sections.advance=Advanced
|
||||
navbar.sections.edit=View & Edit
|
||||
navbar.sections.popular=Popular
|
||||
|
||||
#############
|
||||
# SETTINGS #
|
||||
@@ -225,6 +243,8 @@ database.fileNotFound=File not Found
|
||||
database.fileNullOrEmpty=File must not be null or empty
|
||||
database.failedImportFile=Failed Import File
|
||||
|
||||
session.expired=Your session has expired. Please refresh the page and try again.
|
||||
|
||||
#############
|
||||
# HOME-PAGE #
|
||||
#############
|
||||
@@ -482,6 +502,11 @@ home.removeImagePdf.title=Remove image
|
||||
home.removeImagePdf.desc=Remove image from PDF to reduce file size
|
||||
removeImagePdf.tags=Remove Image,Page operations,Back end,server side
|
||||
|
||||
|
||||
home.splitPdfByChapters.title=Split PDF by Chapters
|
||||
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
||||
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
||||
|
||||
#replace-invert-color
|
||||
replace-color.title=Replace-Invert-Color
|
||||
replace-color.header=Replace-Invert Color PDF
|
||||
@@ -526,7 +551,10 @@ login.oauth2AccessDenied=Access Denied
|
||||
login.oauth2InvalidTokenResponse=Invalid Token Response
|
||||
login.oauth2InvalidIdToken=Invalid Id Token
|
||||
login.userIsDisabled=User is deactivated, login is currently blocked with this username. Please contact the administrator.
|
||||
|
||||
login.alreadyLoggedIn=You are already logged in to
|
||||
login.alreadyLoggedIn2=devices. Please log out of the devices and try again.
|
||||
login.toManySessions=You have too many active sessions
|
||||
login.toManySessions2=Please log out of the devices and try again. Alternatively, you can upgrade to Stirling PDF Pro.
|
||||
|
||||
#auto-redact
|
||||
autoRedact.title=Auto Redact
|
||||
@@ -1154,6 +1182,8 @@ licenses.license=License
|
||||
survey.nav=Survey
|
||||
survey.title=Stirling-PDF Survey
|
||||
survey.description=Stirling-PDF has no tracking so we want to hear from our users to improve Stirling-PDF!
|
||||
survey.changes=Stirling-PDF has changed since the last survey! To find out more please check our blog post here:
|
||||
survey.changes2=With these changes we are getting paid business support and funding
|
||||
survey.please=Please consider taking our survey!
|
||||
survey.disabled=(Survey popup will be disabled in following updates but available at foot of page)
|
||||
survey.button=Take Survey
|
||||
@@ -1179,3 +1209,17 @@ removeImage.title=Remove image
|
||||
removeImage.header=Remove image
|
||||
removeImage.removeImage=Remove image
|
||||
removeImage.submit=Remove image
|
||||
|
||||
|
||||
splitByChapters.title=Split PDF by Chapters
|
||||
splitByChapters.header=Split PDF by Chapters
|
||||
splitByChapters.bookmarkLevel=Bookmark Level
|
||||
splitByChapters.includeMetadata=Include Metadata
|
||||
splitByChapters.allowDuplicates=Allow Duplicates
|
||||
splitByChapters.desc.1=This tool splits a PDF file into multiple PDFs based on its chapter structure.
|
||||
splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for splitting (0 for top-level, 1 for second-level, etc.).
|
||||
splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF.
|
||||
splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs.
|
||||
splitByChapters.submit=Split PDF
|
||||
|
||||
|
||||
|
||||
@@ -76,6 +76,7 @@ donate=Přispějte
|
||||
color=Barva
|
||||
sponsor=Sponzor
|
||||
info=Info
|
||||
pro=Pro
|
||||
page=Page
|
||||
pages=Pages
|
||||
|
||||
@@ -110,8 +111,24 @@ pipelineOptions.pipelineHeader=Pipeline:
|
||||
pipelineOptions.saveButton=Stáhnout
|
||||
pipelineOptions.validateButton=Ověřit
|
||||
|
||||
########################
|
||||
# ENTERPRISE EDITION #
|
||||
########################
|
||||
enterpriseEdition.button=Upgrade to Pro
|
||||
enterpriseEdition.warning=This feature is only available to Pro users.
|
||||
enterpriseEdition.yamlAdvert=Stirling PDF Pro supports YAML configuration files and other SSO features.
|
||||
enterpriseEdition.ssoAdvert=Looking for more user management features? Check out Stirling PDF Pro
|
||||
|
||||
|
||||
#################
|
||||
# Analytics #
|
||||
#################
|
||||
analytics.title=Do you want make Stirling PDF better?
|
||||
analytics.paragraph1=Stirling PDF has opt in analytics to help us improve the product. We do not track any personal information or file contents.
|
||||
analytics.paragraph2=Please consider enabling analytics to help Stirling-PDF grow and to allow us to understand our users better.
|
||||
analytics.enable=Enable analytics
|
||||
analytics.disable=Disable analytics
|
||||
analytics.settings=You can change the settings for analytics in the config/settings.yml file
|
||||
|
||||
#############
|
||||
# NAVBAR #
|
||||
@@ -128,6 +145,7 @@ navbar.sections.convertFrom=Převést z PDF
|
||||
navbar.sections.security=Podpis a Bezpečnost
|
||||
navbar.sections.advance=Pokročilé
|
||||
navbar.sections.edit=Prohlédnout a Upravit
|
||||
navbar.sections.popular=Popular
|
||||
|
||||
#############
|
||||
# SETTINGS #
|
||||
@@ -225,6 +243,8 @@ database.fileNotFound=File not Found
|
||||
database.fileNullOrEmpty=File must not be null or empty
|
||||
database.failedImportFile=Failed Import File
|
||||
|
||||
session.expired=Your session has expired. Please refresh the page and try again.
|
||||
|
||||
#############
|
||||
# HOME-PAGE #
|
||||
#############
|
||||
@@ -482,6 +502,11 @@ home.removeImagePdf.title=Remove image
|
||||
home.removeImagePdf.desc=Remove image from PDF to reduce file size
|
||||
removeImagePdf.tags=Remove Image,Page operations,Back end,server side
|
||||
|
||||
|
||||
home.splitPdfByChapters.title=Split PDF by Chapters
|
||||
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
||||
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
||||
|
||||
#replace-invert-color
|
||||
replace-color.title=Replace-Invert-Color
|
||||
replace-color.header=Replace-Invert Color PDF
|
||||
@@ -526,7 +551,10 @@ login.oauth2AccessDenied=Access Denied
|
||||
login.oauth2InvalidTokenResponse=Invalid Token Response
|
||||
login.oauth2InvalidIdToken=Invalid Id Token
|
||||
login.userIsDisabled=User is deactivated, login is currently blocked with this username. Please contact the administrator.
|
||||
|
||||
login.alreadyLoggedIn=You are already logged in to
|
||||
login.alreadyLoggedIn2=devices. Please log out of the devices and try again.
|
||||
login.toManySessions=You have too many active sessions
|
||||
login.toManySessions2=Please log out of the devices and try again. Alternatively, you can upgrade to Stirling PDF Pro.
|
||||
|
||||
#auto-redact
|
||||
autoRedact.title=Auto Redact
|
||||
@@ -1154,6 +1182,8 @@ licenses.license=Licence
|
||||
survey.nav=Survey
|
||||
survey.title=Stirling-PDF Survey
|
||||
survey.description=Stirling-PDF has no tracking so we want to hear from our users to improve Stirling-PDF!
|
||||
survey.changes=Stirling-PDF has changed since the last survey! To find out more please check our blog post here:
|
||||
survey.changes2=With these changes we are getting paid business support and funding
|
||||
survey.please=Please consider taking our survey!
|
||||
survey.disabled=(Survey popup will be disabled in following updates but available at foot of page)
|
||||
survey.button=Take Survey
|
||||
@@ -1179,3 +1209,17 @@ removeImage.title=Remove image
|
||||
removeImage.header=Remove image
|
||||
removeImage.removeImage=Remove image
|
||||
removeImage.submit=Remove image
|
||||
|
||||
|
||||
splitByChapters.title=Split PDF by Chapters
|
||||
splitByChapters.header=Split PDF by Chapters
|
||||
splitByChapters.bookmarkLevel=Bookmark Level
|
||||
splitByChapters.includeMetadata=Include Metadata
|
||||
splitByChapters.allowDuplicates=Allow Duplicates
|
||||
splitByChapters.desc.1=This tool splits a PDF file into multiple PDFs based on its chapter structure.
|
||||
splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for splitting (0 for top-level, 1 for second-level, etc.).
|
||||
splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF.
|
||||
splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs.
|
||||
splitByChapters.submit=Split PDF
|
||||
|
||||
|
||||
|
||||
@@ -76,6 +76,7 @@ donate=Donér
|
||||
color=Farve
|
||||
sponsor=Sponsor
|
||||
info=Info
|
||||
pro=Pro
|
||||
page=Page
|
||||
pages=Pages
|
||||
|
||||
@@ -110,8 +111,24 @@ pipelineOptions.pipelineHeader=Pipeline:
|
||||
pipelineOptions.saveButton=Download
|
||||
pipelineOptions.validateButton=Validér
|
||||
|
||||
########################
|
||||
# ENTERPRISE EDITION #
|
||||
########################
|
||||
enterpriseEdition.button=Upgrade to Pro
|
||||
enterpriseEdition.warning=This feature is only available to Pro users.
|
||||
enterpriseEdition.yamlAdvert=Stirling PDF Pro supports YAML configuration files and other SSO features.
|
||||
enterpriseEdition.ssoAdvert=Looking for more user management features? Check out Stirling PDF Pro
|
||||
|
||||
|
||||
#################
|
||||
# Analytics #
|
||||
#################
|
||||
analytics.title=Do you want make Stirling PDF better?
|
||||
analytics.paragraph1=Stirling PDF has opt in analytics to help us improve the product. We do not track any personal information or file contents.
|
||||
analytics.paragraph2=Please consider enabling analytics to help Stirling-PDF grow and to allow us to understand our users better.
|
||||
analytics.enable=Enable analytics
|
||||
analytics.disable=Disable analytics
|
||||
analytics.settings=You can change the settings for analytics in the config/settings.yml file
|
||||
|
||||
#############
|
||||
# NAVBAR #
|
||||
@@ -128,6 +145,7 @@ navbar.sections.convertFrom=Konvertér fra PDF
|
||||
navbar.sections.security=Signér & Sikkerhed
|
||||
navbar.sections.advance=Avanceret
|
||||
navbar.sections.edit=Vis & Redigér
|
||||
navbar.sections.popular=Popular
|
||||
|
||||
#############
|
||||
# SETTINGS #
|
||||
@@ -225,6 +243,8 @@ database.fileNotFound=Fil ikke fundet
|
||||
database.fileNullOrEmpty=Fil må ikke være null eller tom
|
||||
database.failedImportFile=Kunne ikke importere fil
|
||||
|
||||
session.expired=Your session has expired. Please refresh the page and try again.
|
||||
|
||||
#############
|
||||
# HOME-PAGE #
|
||||
#############
|
||||
@@ -482,6 +502,11 @@ home.removeImagePdf.title=Fjern billede
|
||||
home.removeImagePdf.desc=Fjern billede fra PDF for at reducere filstørrelse
|
||||
removeImagePdf.tags=Fjern Billede,Sideoperationer,Back end,server side
|
||||
|
||||
|
||||
home.splitPdfByChapters.title=Split PDF by Chapters
|
||||
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
||||
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
||||
|
||||
#replace-invert-color
|
||||
replace-color.title=Replace-Invert-Color
|
||||
replace-color.header=Replace-Invert Color PDF
|
||||
@@ -526,7 +551,10 @@ login.oauth2AccessDenied=Adgang Nægtet
|
||||
login.oauth2InvalidTokenResponse=Ugyldigt Token Svar
|
||||
login.oauth2InvalidIdToken=Ugyldigt Id Token
|
||||
login.userIsDisabled=Bruger er deaktiveret, login er i øjeblikket blokeret med dette brugernavn. Kontakt venligst administratoren.
|
||||
|
||||
login.alreadyLoggedIn=You are already logged in to
|
||||
login.alreadyLoggedIn2=devices. Please log out of the devices and try again.
|
||||
login.toManySessions=You have too many active sessions
|
||||
login.toManySessions2=Please log out of the devices and try again. Alternatively, you can upgrade to Stirling PDF Pro.
|
||||
|
||||
#auto-redact
|
||||
autoRedact.title=Auto Rediger
|
||||
@@ -1154,6 +1182,8 @@ licenses.license=License
|
||||
survey.nav=Undersøgelse
|
||||
survey.title=Stirling-PDF Undersøgelse
|
||||
survey.description=Stirling-PDF har ingen sporing, så vi vil gerne høre fra vores brugere for at forbedre Stirling-PDF!
|
||||
survey.changes=Stirling-PDF has changed since the last survey! To find out more please check our blog post here:
|
||||
survey.changes2=With these changes we are getting paid business support and funding
|
||||
survey.please=Overvej venligst at deltage i vores undersøgelse!
|
||||
survey.disabled=(Undersøgelsespop-up vil blive deaktiveret i følgende opdateringer, men vil være tilgængelig i bunden af siden)
|
||||
survey.button=Tag Undersøgelsen
|
||||
@@ -1179,3 +1209,17 @@ removeImage.title=Fjern billede
|
||||
removeImage.header=Fjern billede
|
||||
removeImage.removeImage=Fjern billede
|
||||
removeImage.submit=Fjern
|
||||
|
||||
|
||||
splitByChapters.title=Split PDF by Chapters
|
||||
splitByChapters.header=Split PDF by Chapters
|
||||
splitByChapters.bookmarkLevel=Bookmark Level
|
||||
splitByChapters.includeMetadata=Include Metadata
|
||||
splitByChapters.allowDuplicates=Allow Duplicates
|
||||
splitByChapters.desc.1=This tool splits a PDF file into multiple PDFs based on its chapter structure.
|
||||
splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for splitting (0 for top-level, 1 for second-level, etc.).
|
||||
splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF.
|
||||
splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs.
|
||||
splitByChapters.submit=Split PDF
|
||||
|
||||
|
||||
|
||||
@@ -76,6 +76,7 @@ donate=Spenden
|
||||
color=Farbe
|
||||
sponsor=Sponsor
|
||||
info=Informationen
|
||||
pro=Pro
|
||||
page=Page
|
||||
pages=Pages
|
||||
|
||||
@@ -110,8 +111,24 @@ pipelineOptions.pipelineHeader=Pipeline:
|
||||
pipelineOptions.saveButton=Herunterladen
|
||||
pipelineOptions.validateButton=Validieren
|
||||
|
||||
########################
|
||||
# ENTERPRISE EDITION #
|
||||
########################
|
||||
enterpriseEdition.button=Upgrade to Pro
|
||||
enterpriseEdition.warning=This feature is only available to Pro users.
|
||||
enterpriseEdition.yamlAdvert=Stirling PDF Pro supports YAML configuration files and other SSO features.
|
||||
enterpriseEdition.ssoAdvert=Looking for more user management features? Check out Stirling PDF Pro
|
||||
|
||||
|
||||
#################
|
||||
# Analytics #
|
||||
#################
|
||||
analytics.title=Do you want make Stirling PDF better?
|
||||
analytics.paragraph1=Stirling PDF has opt in analytics to help us improve the product. We do not track any personal information or file contents.
|
||||
analytics.paragraph2=Please consider enabling analytics to help Stirling-PDF grow and to allow us to understand our users better.
|
||||
analytics.enable=Enable analytics
|
||||
analytics.disable=Disable analytics
|
||||
analytics.settings=You can change the settings for analytics in the config/settings.yml file
|
||||
|
||||
#############
|
||||
# NAVBAR #
|
||||
@@ -128,6 +145,7 @@ navbar.sections.convertFrom=Konvertieren von PDF
|
||||
navbar.sections.security=Zeichen und Sicherheit
|
||||
navbar.sections.advance=Fortschrittlich
|
||||
navbar.sections.edit=Anzeigen und Bearbeiten
|
||||
navbar.sections.popular=Popular
|
||||
|
||||
#############
|
||||
# SETTINGS #
|
||||
@@ -225,6 +243,8 @@ database.fileNotFound=Datei nicht gefunden
|
||||
database.fileNullOrEmpty=Datei darf nicht null oder leer sein
|
||||
database.failedImportFile=Dateiimport fehlgeschlagen
|
||||
|
||||
session.expired=Your session has expired. Please refresh the page and try again.
|
||||
|
||||
#############
|
||||
# HOME-PAGE #
|
||||
#############
|
||||
@@ -482,6 +502,11 @@ home.removeImagePdf.title=Bild entfernen
|
||||
home.removeImagePdf.desc=Bild aus PDF entfernen, um die Dateigröße zu verringern
|
||||
removeImagePdf.tags=bild entfernen,seitenoperationen,back end,server side
|
||||
|
||||
|
||||
home.splitPdfByChapters.title=Split PDF by Chapters
|
||||
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
||||
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
||||
|
||||
#replace-invert-color
|
||||
replace-color.title=Replace-Invert-Color
|
||||
replace-color.header=Replace-Invert Color PDF
|
||||
@@ -526,7 +551,10 @@ login.oauth2AccessDenied=Zugriff abgelehnt
|
||||
login.oauth2InvalidTokenResponse=Ungültige Token-Antwort
|
||||
login.oauth2InvalidIdToken=Ungültiges ID-Token
|
||||
login.userIsDisabled=Benutzer ist deaktiviert, die Anmeldung ist mit diesem Benutzernamen derzeit gesperrt. Bitte wenden Sie sich an den Administrator.
|
||||
|
||||
login.alreadyLoggedIn=You are already logged in to
|
||||
login.alreadyLoggedIn2=devices. Please log out of the devices and try again.
|
||||
login.toManySessions=You have too many active sessions
|
||||
login.toManySessions2=Please log out of the devices and try again. Alternatively, you can upgrade to Stirling PDF Pro.
|
||||
|
||||
#auto-redact
|
||||
autoRedact.title=Automatisch zensieren/schwärzen
|
||||
@@ -1154,6 +1182,8 @@ licenses.license=Lizenz
|
||||
survey.nav=Umfrage
|
||||
survey.title=Stirling-PDF-Umfrage
|
||||
survey.description=Stirling-PDF hat kein Tracking, daher möchten wir von unseren Benutzern hören, wie wir Stirling-PDF verbessern können!
|
||||
survey.changes=Stirling-PDF has changed since the last survey! To find out more please check our blog post here:
|
||||
survey.changes2=With these changes we are getting paid business support and funding
|
||||
survey.please=Bitte nehmen Sie an unserer Umfrage teil!
|
||||
survey.disabled=(Das Umfrage-Popup wird in folgenden Updates deaktiviert, ist aber am Fuß der Seite verfügbar.)
|
||||
survey.button=Umfrage durchführen
|
||||
@@ -1179,3 +1209,17 @@ removeImage.title=Bild entfernen
|
||||
removeImage.header=Bild entfernen
|
||||
removeImage.removeImage=Bild entfernen
|
||||
removeImage.submit=Bild entfernen
|
||||
|
||||
|
||||
splitByChapters.title=Split PDF by Chapters
|
||||
splitByChapters.header=Split PDF by Chapters
|
||||
splitByChapters.bookmarkLevel=Bookmark Level
|
||||
splitByChapters.includeMetadata=Include Metadata
|
||||
splitByChapters.allowDuplicates=Allow Duplicates
|
||||
splitByChapters.desc.1=This tool splits a PDF file into multiple PDFs based on its chapter structure.
|
||||
splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for splitting (0 for top-level, 1 for second-level, etc.).
|
||||
splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF.
|
||||
splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs.
|
||||
splitByChapters.submit=Split PDF
|
||||
|
||||
|
||||
|
||||
@@ -76,6 +76,7 @@ donate=Δωρισε
|
||||
color=Χρώμα
|
||||
sponsor=Yποστηρικτής
|
||||
info=Info
|
||||
pro=Pro
|
||||
page=Page
|
||||
pages=Pages
|
||||
|
||||
@@ -110,8 +111,24 @@ pipelineOptions.pipelineHeader=Pipeline:
|
||||
pipelineOptions.saveButton=Λήψη
|
||||
pipelineOptions.validateButton=Επικυρώνω
|
||||
|
||||
########################
|
||||
# ENTERPRISE EDITION #
|
||||
########################
|
||||
enterpriseEdition.button=Upgrade to Pro
|
||||
enterpriseEdition.warning=This feature is only available to Pro users.
|
||||
enterpriseEdition.yamlAdvert=Stirling PDF Pro supports YAML configuration files and other SSO features.
|
||||
enterpriseEdition.ssoAdvert=Looking for more user management features? Check out Stirling PDF Pro
|
||||
|
||||
|
||||
#################
|
||||
# Analytics #
|
||||
#################
|
||||
analytics.title=Do you want make Stirling PDF better?
|
||||
analytics.paragraph1=Stirling PDF has opt in analytics to help us improve the product. We do not track any personal information or file contents.
|
||||
analytics.paragraph2=Please consider enabling analytics to help Stirling-PDF grow and to allow us to understand our users better.
|
||||
analytics.enable=Enable analytics
|
||||
analytics.disable=Disable analytics
|
||||
analytics.settings=You can change the settings for analytics in the config/settings.yml file
|
||||
|
||||
#############
|
||||
# NAVBAR #
|
||||
@@ -128,6 +145,7 @@ navbar.sections.convertFrom=Convert from PDF
|
||||
navbar.sections.security=Sign & Security
|
||||
navbar.sections.advance=Advanced
|
||||
navbar.sections.edit=View & Edit
|
||||
navbar.sections.popular=Popular
|
||||
|
||||
#############
|
||||
# SETTINGS #
|
||||
@@ -225,6 +243,8 @@ database.fileNotFound=File not Found
|
||||
database.fileNullOrEmpty=File must not be null or empty
|
||||
database.failedImportFile=Failed Import File
|
||||
|
||||
session.expired=Your session has expired. Please refresh the page and try again.
|
||||
|
||||
#############
|
||||
# HOME-PAGE #
|
||||
#############
|
||||
@@ -482,6 +502,11 @@ home.removeImagePdf.title=Remove image
|
||||
home.removeImagePdf.desc=Remove image from PDF to reduce file size
|
||||
removeImagePdf.tags=Remove Image,Page operations,Back end,server side
|
||||
|
||||
|
||||
home.splitPdfByChapters.title=Split PDF by Chapters
|
||||
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
||||
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
||||
|
||||
#replace-invert-color
|
||||
replace-color.title=Replace-Invert-Color
|
||||
replace-color.header=Replace-Invert Color PDF
|
||||
@@ -526,7 +551,10 @@ login.oauth2AccessDenied=Access Denied
|
||||
login.oauth2InvalidTokenResponse=Invalid Token Response
|
||||
login.oauth2InvalidIdToken=Invalid Id Token
|
||||
login.userIsDisabled=User is deactivated, login is currently blocked with this username. Please contact the administrator.
|
||||
|
||||
login.alreadyLoggedIn=You are already logged in to
|
||||
login.alreadyLoggedIn2=devices. Please log out of the devices and try again.
|
||||
login.toManySessions=You have too many active sessions
|
||||
login.toManySessions2=Please log out of the devices and try again. Alternatively, you can upgrade to Stirling PDF Pro.
|
||||
|
||||
#auto-redact
|
||||
autoRedact.title=Αυτόματο Μαύρισμα Κειμένου
|
||||
@@ -1154,6 +1182,8 @@ licenses.license=Άδεια
|
||||
survey.nav=Survey
|
||||
survey.title=Stirling-PDF Survey
|
||||
survey.description=Stirling-PDF has no tracking so we want to hear from our users to improve Stirling-PDF!
|
||||
survey.changes=Stirling-PDF has changed since the last survey! To find out more please check our blog post here:
|
||||
survey.changes2=With these changes we are getting paid business support and funding
|
||||
survey.please=Please consider taking our survey!
|
||||
survey.disabled=(Survey popup will be disabled in following updates but available at foot of page)
|
||||
survey.button=Take Survey
|
||||
@@ -1179,3 +1209,17 @@ removeImage.title=Remove image
|
||||
removeImage.header=Remove image
|
||||
removeImage.removeImage=Remove image
|
||||
removeImage.submit=Remove image
|
||||
|
||||
|
||||
splitByChapters.title=Split PDF by Chapters
|
||||
splitByChapters.header=Split PDF by Chapters
|
||||
splitByChapters.bookmarkLevel=Bookmark Level
|
||||
splitByChapters.includeMetadata=Include Metadata
|
||||
splitByChapters.allowDuplicates=Allow Duplicates
|
||||
splitByChapters.desc.1=This tool splits a PDF file into multiple PDFs based on its chapter structure.
|
||||
splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for splitting (0 for top-level, 1 for second-level, etc.).
|
||||
splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF.
|
||||
splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs.
|
||||
splitByChapters.submit=Split PDF
|
||||
|
||||
|
||||
|
||||
@@ -76,6 +76,7 @@ donate=Donate
|
||||
color=Color
|
||||
sponsor=Sponsor
|
||||
info=Info
|
||||
pro=Pro
|
||||
page=Page
|
||||
pages=Pages
|
||||
|
||||
@@ -110,8 +111,24 @@ pipelineOptions.pipelineHeader=Pipeline:
|
||||
pipelineOptions.saveButton=Download
|
||||
pipelineOptions.validateButton=Validate
|
||||
|
||||
########################
|
||||
# ENTERPRISE EDITION #
|
||||
########################
|
||||
enterpriseEdition.button=Upgrade to Pro
|
||||
enterpriseEdition.warning=This feature is only available to Pro users.
|
||||
enterpriseEdition.yamlAdvert=Stirling PDF Pro supports YAML configuration files and other SSO features.
|
||||
enterpriseEdition.ssoAdvert=Looking for more user management features? Check out Stirling PDF Pro
|
||||
|
||||
|
||||
#################
|
||||
# Analytics #
|
||||
#################
|
||||
analytics.title=Do you want make Stirling PDF better?
|
||||
analytics.paragraph1=Stirling PDF has opt in analytics to help us improve the product. We do not track any personal information or file contents.
|
||||
analytics.paragraph2=Please consider enabling analytics to help Stirling-PDF grow and to allow us to understand our users better.
|
||||
analytics.enable=Enable analytics
|
||||
analytics.disable=Disable analytics
|
||||
analytics.settings=You can change the settings for analytics in the config/settings.yml file
|
||||
|
||||
#############
|
||||
# NAVBAR #
|
||||
@@ -128,6 +145,7 @@ navbar.sections.convertFrom=Convert from PDF
|
||||
navbar.sections.security=Sign & Security
|
||||
navbar.sections.advance=Advanced
|
||||
navbar.sections.edit=View & Edit
|
||||
navbar.sections.popular=Popular
|
||||
|
||||
#############
|
||||
# SETTINGS #
|
||||
@@ -225,6 +243,8 @@ database.fileNotFound=File not Found
|
||||
database.fileNullOrEmpty=File must not be null or empty
|
||||
database.failedImportFile=Failed Import File
|
||||
|
||||
session.expired=Your session has expired. Please refresh the page and try again.
|
||||
|
||||
#############
|
||||
# HOME-PAGE #
|
||||
#############
|
||||
@@ -482,6 +502,11 @@ home.removeImagePdf.title=Remove image
|
||||
home.removeImagePdf.desc=Remove image from PDF to reduce file size
|
||||
removeImagePdf.tags=Remove Image,Page operations,Back end,server side
|
||||
|
||||
|
||||
home.splitPdfByChapters.title=Split PDF by Chapters
|
||||
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
||||
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
||||
|
||||
#replace-invert-color
|
||||
replace-color.title=Replace-Invert-Color
|
||||
replace-color.header=Replace-Invert Color PDF
|
||||
@@ -526,7 +551,10 @@ login.oauth2AccessDenied=Access Denied
|
||||
login.oauth2InvalidTokenResponse=Invalid Token Response
|
||||
login.oauth2InvalidIdToken=Invalid Id Token
|
||||
login.userIsDisabled=User is deactivated, login is currently blocked with this username. Please contact the administrator.
|
||||
|
||||
login.alreadyLoggedIn=You are already logged in to
|
||||
login.alreadyLoggedIn2=devices. Please log out of the devices and try again.
|
||||
login.toManySessions=You have too many active sessions
|
||||
login.toManySessions2=Please log out of the devices and try again. Alternatively, you can upgrade to Stirling PDF Pro.
|
||||
|
||||
#auto-redact
|
||||
autoRedact.title=Auto Redact
|
||||
@@ -1154,6 +1182,8 @@ licenses.license=License
|
||||
survey.nav=Survey
|
||||
survey.title=Stirling-PDF Survey
|
||||
survey.description=Stirling-PDF has no tracking so we want to hear from our users to improve Stirling-PDF!
|
||||
survey.changes=Stirling-PDF has changed since the last survey! To find out more please check our blog post here:
|
||||
survey.changes2=With these changes we are getting paid business support and funding
|
||||
survey.please=Please consider taking our survey!
|
||||
survey.disabled=(Survey popup will be disabled in following updates but available at foot of page)
|
||||
survey.button=Take Survey
|
||||
@@ -1179,3 +1209,17 @@ removeImage.title=Remove image
|
||||
removeImage.header=Remove image
|
||||
removeImage.removeImage=Remove image
|
||||
removeImage.submit=Remove image
|
||||
|
||||
|
||||
splitByChapters.title=Split PDF by Chapters
|
||||
splitByChapters.header=Split PDF by Chapters
|
||||
splitByChapters.bookmarkLevel=Bookmark Level
|
||||
splitByChapters.includeMetadata=Include Metadata
|
||||
splitByChapters.allowDuplicates=Allow Duplicates
|
||||
splitByChapters.desc.1=This tool splits a PDF file into multiple PDFs based on its chapter structure.
|
||||
splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for splitting (0 for top-level, 1 for second-level, etc.).
|
||||
splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF.
|
||||
splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs.
|
||||
splitByChapters.submit=Split PDF
|
||||
|
||||
|
||||
|
||||
@@ -76,6 +76,7 @@ donate=Donar
|
||||
color=Color
|
||||
sponsor=Patrocinador
|
||||
info=Info
|
||||
pro=Pro
|
||||
page=Page
|
||||
pages=Pages
|
||||
|
||||
@@ -110,8 +111,24 @@ pipelineOptions.pipelineHeader=Canalización:
|
||||
pipelineOptions.saveButton=Descargar
|
||||
pipelineOptions.validateButton=Validar
|
||||
|
||||
########################
|
||||
# ENTERPRISE EDITION #
|
||||
########################
|
||||
enterpriseEdition.button=Upgrade to Pro
|
||||
enterpriseEdition.warning=This feature is only available to Pro users.
|
||||
enterpriseEdition.yamlAdvert=Stirling PDF Pro supports YAML configuration files and other SSO features.
|
||||
enterpriseEdition.ssoAdvert=Looking for more user management features? Check out Stirling PDF Pro
|
||||
|
||||
|
||||
#################
|
||||
# Analytics #
|
||||
#################
|
||||
analytics.title=Do you want make Stirling PDF better?
|
||||
analytics.paragraph1=Stirling PDF has opt in analytics to help us improve the product. We do not track any personal information or file contents.
|
||||
analytics.paragraph2=Please consider enabling analytics to help Stirling-PDF grow and to allow us to understand our users better.
|
||||
analytics.enable=Enable analytics
|
||||
analytics.disable=Disable analytics
|
||||
analytics.settings=You can change the settings for analytics in the config/settings.yml file
|
||||
|
||||
#############
|
||||
# NAVBAR #
|
||||
@@ -128,6 +145,7 @@ navbar.sections.convertFrom=Convertir desde PDF
|
||||
navbar.sections.security=Señalización y seguridad
|
||||
navbar.sections.advance=Avanzado
|
||||
navbar.sections.edit=Ver y Editar
|
||||
navbar.sections.popular=Popular
|
||||
|
||||
#############
|
||||
# SETTINGS #
|
||||
@@ -225,6 +243,8 @@ database.fileNotFound=Archivo no encontrado
|
||||
database.fileNullOrEmpty=El archivo no debe ser nulo o vacío.
|
||||
database.failedImportFile=Archivo de importación fallido
|
||||
|
||||
session.expired=Your session has expired. Please refresh the page and try again.
|
||||
|
||||
#############
|
||||
# HOME-PAGE #
|
||||
#############
|
||||
@@ -482,6 +502,11 @@ home.removeImagePdf.title=Eliminar imagen
|
||||
home.removeImagePdf.desc=Eliminar imagen del PDF> para reducir el tamaño de archivo
|
||||
removeImagePdf.tags=Eliminar imagen,Operaciones de página,Back end,lado del servidor
|
||||
|
||||
|
||||
home.splitPdfByChapters.title=Split PDF by Chapters
|
||||
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
||||
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
||||
|
||||
#replace-invert-color
|
||||
replace-color.title=Replace-Invert-Color
|
||||
replace-color.header=Replace-Invert Color PDF
|
||||
@@ -526,7 +551,10 @@ login.oauth2AccessDenied=Acceso denegado
|
||||
login.oauth2InvalidTokenResponse=Respuesta de token no válida
|
||||
login.oauth2InvalidIdToken=Token de identificación no válido
|
||||
login.userIsDisabled=El usuario está desactivado, actualmente el acceso está bloqueado para ese nombre de usuario. Por favor, póngase en contacto con el administrador.
|
||||
|
||||
login.alreadyLoggedIn=You are already logged in to
|
||||
login.alreadyLoggedIn2=devices. Please log out of the devices and try again.
|
||||
login.toManySessions=You have too many active sessions
|
||||
login.toManySessions2=Please log out of the devices and try again. Alternatively, you can upgrade to Stirling PDF Pro.
|
||||
|
||||
#auto-redact
|
||||
autoRedact.title=Auto Redactar
|
||||
@@ -1154,6 +1182,8 @@ licenses.license=Licencia
|
||||
survey.nav=Encuesta
|
||||
survey.title=Encuesta Stirling-PDF
|
||||
survey.description=Stirling-PDF no tiene seguimiento, por lo que queremos escuchar a nuestros usuarios para mejorar Stirling-PDF.
|
||||
survey.changes=Stirling-PDF has changed since the last survey! To find out more please check our blog post here:
|
||||
survey.changes2=With these changes we are getting paid business support and funding
|
||||
survey.please=¡Considere realizar nuestra encuesta!
|
||||
survey.disabled=(La ventana emergente de la encuesta se desactivará en las siguientes actualizaciones, pero estará disponible al pie de la página.)
|
||||
survey.button=Realizar encuesta
|
||||
@@ -1179,3 +1209,17 @@ removeImage.title=Eliminar imagen
|
||||
removeImage.header=Eliminar imagen
|
||||
removeImage.removeImage=Eliminar imagen
|
||||
removeImage.submit=Eliminar imagen
|
||||
|
||||
|
||||
splitByChapters.title=Split PDF by Chapters
|
||||
splitByChapters.header=Split PDF by Chapters
|
||||
splitByChapters.bookmarkLevel=Bookmark Level
|
||||
splitByChapters.includeMetadata=Include Metadata
|
||||
splitByChapters.allowDuplicates=Allow Duplicates
|
||||
splitByChapters.desc.1=This tool splits a PDF file into multiple PDFs based on its chapter structure.
|
||||
splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for splitting (0 for top-level, 1 for second-level, etc.).
|
||||
splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF.
|
||||
splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs.
|
||||
splitByChapters.submit=Split PDF
|
||||
|
||||
|
||||
|
||||
@@ -76,6 +76,7 @@ donate=Donate
|
||||
color=Color
|
||||
sponsor=Sponsor
|
||||
info=Info
|
||||
pro=Pro
|
||||
page=Page
|
||||
pages=Pages
|
||||
|
||||
@@ -110,8 +111,24 @@ pipelineOptions.pipelineHeader=Pipeline:
|
||||
pipelineOptions.saveButton=Download
|
||||
pipelineOptions.validateButton=Validate
|
||||
|
||||
########################
|
||||
# ENTERPRISE EDITION #
|
||||
########################
|
||||
enterpriseEdition.button=Upgrade to Pro
|
||||
enterpriseEdition.warning=This feature is only available to Pro users.
|
||||
enterpriseEdition.yamlAdvert=Stirling PDF Pro supports YAML configuration files and other SSO features.
|
||||
enterpriseEdition.ssoAdvert=Looking for more user management features? Check out Stirling PDF Pro
|
||||
|
||||
|
||||
#################
|
||||
# Analytics #
|
||||
#################
|
||||
analytics.title=Do you want make Stirling PDF better?
|
||||
analytics.paragraph1=Stirling PDF has opt in analytics to help us improve the product. We do not track any personal information or file contents.
|
||||
analytics.paragraph2=Please consider enabling analytics to help Stirling-PDF grow and to allow us to understand our users better.
|
||||
analytics.enable=Enable analytics
|
||||
analytics.disable=Disable analytics
|
||||
analytics.settings=You can change the settings for analytics in the config/settings.yml file
|
||||
|
||||
#############
|
||||
# NAVBAR #
|
||||
@@ -128,6 +145,7 @@ navbar.sections.convertFrom=Convert from PDF
|
||||
navbar.sections.security=Sign & Security
|
||||
navbar.sections.advance=Advanced
|
||||
navbar.sections.edit=View & Edit
|
||||
navbar.sections.popular=Popular
|
||||
|
||||
#############
|
||||
# SETTINGS #
|
||||
@@ -225,6 +243,8 @@ database.fileNotFound=File not Found
|
||||
database.fileNullOrEmpty=File must not be null or empty
|
||||
database.failedImportFile=Failed Import File
|
||||
|
||||
session.expired=Your session has expired. Please refresh the page and try again.
|
||||
|
||||
#############
|
||||
# HOME-PAGE #
|
||||
#############
|
||||
@@ -482,6 +502,11 @@ home.removeImagePdf.title=Remove image
|
||||
home.removeImagePdf.desc=Remove image from PDF to reduce file size
|
||||
removeImagePdf.tags=Remove Image,Page operations,Back end,server side
|
||||
|
||||
|
||||
home.splitPdfByChapters.title=Split PDF by Chapters
|
||||
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
||||
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
||||
|
||||
#replace-invert-color
|
||||
replace-color.title=Replace-Invert-Color
|
||||
replace-color.header=Replace-Invert Color PDF
|
||||
@@ -526,7 +551,10 @@ login.oauth2AccessDenied=Access Denied
|
||||
login.oauth2InvalidTokenResponse=Invalid Token Response
|
||||
login.oauth2InvalidIdToken=Invalid Id Token
|
||||
login.userIsDisabled=User is deactivated, login is currently blocked with this username. Please contact the administrator.
|
||||
|
||||
login.alreadyLoggedIn=You are already logged in to
|
||||
login.alreadyLoggedIn2=devices. Please log out of the devices and try again.
|
||||
login.toManySessions=You have too many active sessions
|
||||
login.toManySessions2=Please log out of the devices and try again. Alternatively, you can upgrade to Stirling PDF Pro.
|
||||
|
||||
#auto-redact
|
||||
autoRedact.title=Auto Idatzi
|
||||
@@ -1154,6 +1182,8 @@ licenses.license=License
|
||||
survey.nav=Survey
|
||||
survey.title=Stirling-PDF Survey
|
||||
survey.description=Stirling-PDF has no tracking so we want to hear from our users to improve Stirling-PDF!
|
||||
survey.changes=Stirling-PDF has changed since the last survey! To find out more please check our blog post here:
|
||||
survey.changes2=With these changes we are getting paid business support and funding
|
||||
survey.please=Please consider taking our survey!
|
||||
survey.disabled=(Survey popup will be disabled in following updates but available at foot of page)
|
||||
survey.button=Take Survey
|
||||
@@ -1179,3 +1209,17 @@ removeImage.title=Remove image
|
||||
removeImage.header=Remove image
|
||||
removeImage.removeImage=Remove image
|
||||
removeImage.submit=Remove image
|
||||
|
||||
|
||||
splitByChapters.title=Split PDF by Chapters
|
||||
splitByChapters.header=Split PDF by Chapters
|
||||
splitByChapters.bookmarkLevel=Bookmark Level
|
||||
splitByChapters.includeMetadata=Include Metadata
|
||||
splitByChapters.allowDuplicates=Allow Duplicates
|
||||
splitByChapters.desc.1=This tool splits a PDF file into multiple PDFs based on its chapter structure.
|
||||
splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for splitting (0 for top-level, 1 for second-level, etc.).
|
||||
splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF.
|
||||
splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs.
|
||||
splitByChapters.submit=Split PDF
|
||||
|
||||
|
||||
|
||||
@@ -76,6 +76,7 @@ donate=Faire un don
|
||||
color=Couleur
|
||||
sponsor=Sponsor
|
||||
info=Info
|
||||
pro=Pro
|
||||
page=Page
|
||||
pages=Pages
|
||||
|
||||
@@ -110,8 +111,24 @@ pipelineOptions.pipelineHeader=Pipeline:
|
||||
pipelineOptions.saveButton=Télécharger
|
||||
pipelineOptions.validateButton=Valider
|
||||
|
||||
########################
|
||||
# ENTERPRISE EDITION #
|
||||
########################
|
||||
enterpriseEdition.button=Upgrade to Pro
|
||||
enterpriseEdition.warning=This feature is only available to Pro users.
|
||||
enterpriseEdition.yamlAdvert=Stirling PDF Pro supports YAML configuration files and other SSO features.
|
||||
enterpriseEdition.ssoAdvert=Looking for more user management features? Check out Stirling PDF Pro
|
||||
|
||||
|
||||
#################
|
||||
# Analytics #
|
||||
#################
|
||||
analytics.title=Do you want make Stirling PDF better?
|
||||
analytics.paragraph1=Stirling PDF has opt in analytics to help us improve the product. We do not track any personal information or file contents.
|
||||
analytics.paragraph2=Please consider enabling analytics to help Stirling-PDF grow and to allow us to understand our users better.
|
||||
analytics.enable=Enable analytics
|
||||
analytics.disable=Disable analytics
|
||||
analytics.settings=You can change the settings for analytics in the config/settings.yml file
|
||||
|
||||
#############
|
||||
# NAVBAR #
|
||||
@@ -128,6 +145,7 @@ navbar.sections.convertFrom=Convertir depuis PDF
|
||||
navbar.sections.security=Signature et sécurité
|
||||
navbar.sections.advance=Mode avancé
|
||||
navbar.sections.edit=Voir et modifier
|
||||
navbar.sections.popular=Popular
|
||||
|
||||
#############
|
||||
# SETTINGS #
|
||||
@@ -225,6 +243,8 @@ database.fileNotFound=File not Found
|
||||
database.fileNullOrEmpty=File must not be null or empty
|
||||
database.failedImportFile=Failed Import File
|
||||
|
||||
session.expired=Your session has expired. Please refresh the page and try again.
|
||||
|
||||
#############
|
||||
# HOME-PAGE #
|
||||
#############
|
||||
@@ -482,6 +502,11 @@ home.removeImagePdf.title=Remove image
|
||||
home.removeImagePdf.desc=Remove image from PDF to reduce file size
|
||||
removeImagePdf.tags=Remove Image,Page operations,Back end,server side
|
||||
|
||||
|
||||
home.splitPdfByChapters.title=Split PDF by Chapters
|
||||
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
||||
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
||||
|
||||
#replace-invert-color
|
||||
replace-color.title=Replace-Invert-Color
|
||||
replace-color.header=Replace-Invert Color PDF
|
||||
@@ -526,7 +551,10 @@ login.oauth2AccessDenied=Accès refusé
|
||||
login.oauth2InvalidTokenResponse=Réponse contenant le jeton est invalide
|
||||
login.oauth2InvalidIdToken=Jeton d'identification invalide
|
||||
login.userIsDisabled=User is deactivated, login is currently blocked with this username. Please contact the administrator.
|
||||
|
||||
login.alreadyLoggedIn=You are already logged in to
|
||||
login.alreadyLoggedIn2=devices. Please log out of the devices and try again.
|
||||
login.toManySessions=You have too many active sessions
|
||||
login.toManySessions2=Please log out of the devices and try again. Alternatively, you can upgrade to Stirling PDF Pro.
|
||||
|
||||
#auto-redact
|
||||
autoRedact.title=Caviarder automatiquement
|
||||
@@ -1154,6 +1182,8 @@ licenses.license=Licence
|
||||
survey.nav=Survey
|
||||
survey.title=Stirling-PDF Survey
|
||||
survey.description=Stirling-PDF has no tracking so we want to hear from our users to improve Stirling-PDF!
|
||||
survey.changes=Stirling-PDF has changed since the last survey! To find out more please check our blog post here:
|
||||
survey.changes2=With these changes we are getting paid business support and funding
|
||||
survey.please=Please consider taking our survey!
|
||||
survey.disabled=(Survey popup will be disabled in following updates but available at foot of page)
|
||||
survey.button=Take Survey
|
||||
@@ -1179,3 +1209,17 @@ removeImage.title=Remove image
|
||||
removeImage.header=Remove image
|
||||
removeImage.removeImage=Remove image
|
||||
removeImage.submit=Remove image
|
||||
|
||||
|
||||
splitByChapters.title=Split PDF by Chapters
|
||||
splitByChapters.header=Split PDF by Chapters
|
||||
splitByChapters.bookmarkLevel=Bookmark Level
|
||||
splitByChapters.includeMetadata=Include Metadata
|
||||
splitByChapters.allowDuplicates=Allow Duplicates
|
||||
splitByChapters.desc.1=This tool splits a PDF file into multiple PDFs based on its chapter structure.
|
||||
splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for splitting (0 for top-level, 1 for second-level, etc.).
|
||||
splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF.
|
||||
splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs.
|
||||
splitByChapters.submit=Split PDF
|
||||
|
||||
|
||||
|
||||
@@ -76,6 +76,7 @@ donate=Síntiúis
|
||||
color=Dath
|
||||
sponsor=Urraitheoir
|
||||
info=Eolas
|
||||
pro=Pro
|
||||
page=Page
|
||||
pages=Pages
|
||||
|
||||
@@ -110,8 +111,24 @@ pipelineOptions.pipelineHeader=Píblíne:
|
||||
pipelineOptions.saveButton=Íosluchtaigh
|
||||
pipelineOptions.validateButton=Bailíochtaigh
|
||||
|
||||
########################
|
||||
# ENTERPRISE EDITION #
|
||||
########################
|
||||
enterpriseEdition.button=Upgrade to Pro
|
||||
enterpriseEdition.warning=This feature is only available to Pro users.
|
||||
enterpriseEdition.yamlAdvert=Stirling PDF Pro supports YAML configuration files and other SSO features.
|
||||
enterpriseEdition.ssoAdvert=Looking for more user management features? Check out Stirling PDF Pro
|
||||
|
||||
|
||||
#################
|
||||
# Analytics #
|
||||
#################
|
||||
analytics.title=Do you want make Stirling PDF better?
|
||||
analytics.paragraph1=Stirling PDF has opt in analytics to help us improve the product. We do not track any personal information or file contents.
|
||||
analytics.paragraph2=Please consider enabling analytics to help Stirling-PDF grow and to allow us to understand our users better.
|
||||
analytics.enable=Enable analytics
|
||||
analytics.disable=Disable analytics
|
||||
analytics.settings=You can change the settings for analytics in the config/settings.yml file
|
||||
|
||||
#############
|
||||
# NAVBAR #
|
||||
@@ -128,6 +145,7 @@ navbar.sections.convertFrom=Tiontaigh ó PDF
|
||||
navbar.sections.security=Comhartha & Slándáil
|
||||
navbar.sections.advance=Casta
|
||||
navbar.sections.edit=Féach ar & Cuir in Eagar
|
||||
navbar.sections.popular=Popular
|
||||
|
||||
#############
|
||||
# SETTINGS #
|
||||
@@ -225,6 +243,8 @@ database.fileNotFound=Comhad gan aimsiú
|
||||
database.fileNullOrEmpty=Níor cheart go mbeadh an comhad ar neamhní nó folamh
|
||||
database.failedImportFile=Theip ar iompórtáil an chomhaid
|
||||
|
||||
session.expired=Your session has expired. Please refresh the page and try again.
|
||||
|
||||
#############
|
||||
# HOME-PAGE #
|
||||
#############
|
||||
@@ -482,6 +502,11 @@ home.removeImagePdf.title=Remove image
|
||||
home.removeImagePdf.desc=Remove image from PDF to reduce file size
|
||||
removeImagePdf.tags=Remove Image,Page operations,Back end,server side
|
||||
|
||||
|
||||
home.splitPdfByChapters.title=Split PDF by Chapters
|
||||
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
||||
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
||||
|
||||
#replace-invert-color
|
||||
replace-color.title=Replace-Invert-Color
|
||||
replace-color.header=Replace-Invert Color PDF
|
||||
@@ -526,7 +551,10 @@ login.oauth2AccessDenied=Rochtain Diúltaithe
|
||||
login.oauth2InvalidTokenResponse=Freagra Comhartha Neamhbhailí
|
||||
login.oauth2InvalidIdToken=Comhartha Aitheantais Neamhbhailí
|
||||
login.userIsDisabled=User is deactivated, login is currently blocked with this username. Please contact the administrator.
|
||||
|
||||
login.alreadyLoggedIn=You are already logged in to
|
||||
login.alreadyLoggedIn2=devices. Please log out of the devices and try again.
|
||||
login.toManySessions=You have too many active sessions
|
||||
login.toManySessions2=Please log out of the devices and try again. Alternatively, you can upgrade to Stirling PDF Pro.
|
||||
|
||||
#auto-redact
|
||||
autoRedact.title=Auto Redact
|
||||
@@ -1154,6 +1182,8 @@ licenses.license=Ceadúnas
|
||||
survey.nav=Suirbhé
|
||||
survey.title=Suirbhé Stirling-PDF
|
||||
survey.description=Níl aon rian ar Stirling-PDF agus mar sin ba mhaith linn cloisteáil ónár n-úsáideoirí chun feabhas a chur ar Stirling-PDF!
|
||||
survey.changes=Stirling-PDF has changed since the last survey! To find out more please check our blog post here:
|
||||
survey.changes2=With these changes we are getting paid business support and funding
|
||||
survey.please=Smaoinigh ar ár suirbhé a dhéanamh le do thoil!
|
||||
survey.disabled=(Díchumasófar aníos an tsuirbhé sna nuashonruithe seo a leanas ach beidh siad ar fáil ag bun an leathanaigh)
|
||||
survey.button=Tóg Suirbhé
|
||||
@@ -1179,3 +1209,17 @@ removeImage.title=Remove image
|
||||
removeImage.header=Remove image
|
||||
removeImage.removeImage=Remove image
|
||||
removeImage.submit=Remove image
|
||||
|
||||
|
||||
splitByChapters.title=Split PDF by Chapters
|
||||
splitByChapters.header=Split PDF by Chapters
|
||||
splitByChapters.bookmarkLevel=Bookmark Level
|
||||
splitByChapters.includeMetadata=Include Metadata
|
||||
splitByChapters.allowDuplicates=Allow Duplicates
|
||||
splitByChapters.desc.1=This tool splits a PDF file into multiple PDFs based on its chapter structure.
|
||||
splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for splitting (0 for top-level, 1 for second-level, etc.).
|
||||
splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF.
|
||||
splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs.
|
||||
splitByChapters.submit=Split PDF
|
||||
|
||||
|
||||
|
||||
@@ -76,6 +76,7 @@ donate=Donate
|
||||
color=Color
|
||||
sponsor=Sponsor
|
||||
info=Info
|
||||
pro=Pro
|
||||
page=पृष्ठ
|
||||
pages=पृष्ठों
|
||||
|
||||
@@ -110,8 +111,24 @@ pipelineOptions.pipelineHeader=Pipeline:
|
||||
pipelineOptions.saveButton=Download
|
||||
pipelineOptions.validateButton=Validate
|
||||
|
||||
########################
|
||||
# ENTERPRISE EDITION #
|
||||
########################
|
||||
enterpriseEdition.button=Upgrade to Pro
|
||||
enterpriseEdition.warning=This feature is only available to Pro users.
|
||||
enterpriseEdition.yamlAdvert=Stirling PDF Pro supports YAML configuration files and other SSO features.
|
||||
enterpriseEdition.ssoAdvert=Looking for more user management features? Check out Stirling PDF Pro
|
||||
|
||||
|
||||
#################
|
||||
# Analytics #
|
||||
#################
|
||||
analytics.title=Do you want make Stirling PDF better?
|
||||
analytics.paragraph1=Stirling PDF has opt in analytics to help us improve the product. We do not track any personal information or file contents.
|
||||
analytics.paragraph2=Please consider enabling analytics to help Stirling-PDF grow and to allow us to understand our users better.
|
||||
analytics.enable=Enable analytics
|
||||
analytics.disable=Disable analytics
|
||||
analytics.settings=You can change the settings for analytics in the config/settings.yml file
|
||||
|
||||
#############
|
||||
# NAVBAR #
|
||||
@@ -128,6 +145,7 @@ navbar.sections.convertFrom=पीडीएफ से कनवर्ट कर
|
||||
navbar.sections.security=संकेत और सुरक्षा
|
||||
navbar.sections.advance=उन्नत
|
||||
navbar.sections.edit=देखें और संपादित करें
|
||||
navbar.sections.popular=Popular
|
||||
|
||||
#############
|
||||
# SETTINGS #
|
||||
@@ -225,6 +243,8 @@ database.fileNotFound=File not Found
|
||||
database.fileNullOrEmpty=File must not be null or empty
|
||||
database.failedImportFile=Failed Import File
|
||||
|
||||
session.expired=Your session has expired. Please refresh the page and try again.
|
||||
|
||||
#############
|
||||
# HOME-PAGE #
|
||||
#############
|
||||
@@ -482,6 +502,11 @@ home.removeImagePdf.title=Remove image
|
||||
home.removeImagePdf.desc=Remove image from PDF to reduce file size
|
||||
removeImagePdf.tags=Remove Image,Page operations,Back end,server side
|
||||
|
||||
|
||||
home.splitPdfByChapters.title=Split PDF by Chapters
|
||||
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
||||
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
||||
|
||||
#replace-invert-color
|
||||
replace-color.title=Replace-Invert-Color
|
||||
replace-color.header=Replace-Invert Color PDF
|
||||
@@ -526,7 +551,10 @@ login.oauth2AccessDenied=Access Denied
|
||||
login.oauth2InvalidTokenResponse=Invalid Token Response
|
||||
login.oauth2InvalidIdToken=Invalid Id Token
|
||||
login.userIsDisabled=User is deactivated, login is currently blocked with this username. Please contact the administrator.
|
||||
|
||||
login.alreadyLoggedIn=You are already logged in to
|
||||
login.alreadyLoggedIn2=devices. Please log out of the devices and try again.
|
||||
login.toManySessions=You have too many active sessions
|
||||
login.toManySessions2=Please log out of the devices and try again. Alternatively, you can upgrade to Stirling PDF Pro.
|
||||
|
||||
#auto-redact
|
||||
autoRedact.title=स्वत: गोपनीयकरण
|
||||
@@ -1154,6 +1182,8 @@ licenses.license=License
|
||||
survey.nav=Survey
|
||||
survey.title=Stirling-PDF Survey
|
||||
survey.description=Stirling-PDF has no tracking so we want to hear from our users to improve Stirling-PDF!
|
||||
survey.changes=Stirling-PDF has changed since the last survey! To find out more please check our blog post here:
|
||||
survey.changes2=With these changes we are getting paid business support and funding
|
||||
survey.please=Please consider taking our survey!
|
||||
survey.disabled=(Survey popup will be disabled in following updates but available at foot of page)
|
||||
survey.button=Take Survey
|
||||
@@ -1179,3 +1209,17 @@ removeImage.title=Remove image
|
||||
removeImage.header=Remove image
|
||||
removeImage.removeImage=Remove image
|
||||
removeImage.submit=Remove image
|
||||
|
||||
|
||||
splitByChapters.title=Split PDF by Chapters
|
||||
splitByChapters.header=Split PDF by Chapters
|
||||
splitByChapters.bookmarkLevel=Bookmark Level
|
||||
splitByChapters.includeMetadata=Include Metadata
|
||||
splitByChapters.allowDuplicates=Allow Duplicates
|
||||
splitByChapters.desc.1=This tool splits a PDF file into multiple PDFs based on its chapter structure.
|
||||
splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for splitting (0 for top-level, 1 for second-level, etc.).
|
||||
splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF.
|
||||
splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs.
|
||||
splitByChapters.submit=Split PDF
|
||||
|
||||
|
||||
|
||||
@@ -76,6 +76,7 @@ donate=Doniraj
|
||||
color=Boja
|
||||
sponsor=Sponzor
|
||||
info=Info
|
||||
pro=Pro
|
||||
page=Page
|
||||
pages=Pages
|
||||
|
||||
@@ -110,8 +111,24 @@ pipelineOptions.pipelineHeader=Pipeline:
|
||||
pipelineOptions.saveButton=Preuzmi datoteku
|
||||
pipelineOptions.validateButton=Potvrdi
|
||||
|
||||
########################
|
||||
# ENTERPRISE EDITION #
|
||||
########################
|
||||
enterpriseEdition.button=Upgrade to Pro
|
||||
enterpriseEdition.warning=This feature is only available to Pro users.
|
||||
enterpriseEdition.yamlAdvert=Stirling PDF Pro supports YAML configuration files and other SSO features.
|
||||
enterpriseEdition.ssoAdvert=Looking for more user management features? Check out Stirling PDF Pro
|
||||
|
||||
|
||||
#################
|
||||
# Analytics #
|
||||
#################
|
||||
analytics.title=Do you want make Stirling PDF better?
|
||||
analytics.paragraph1=Stirling PDF has opt in analytics to help us improve the product. We do not track any personal information or file contents.
|
||||
analytics.paragraph2=Please consider enabling analytics to help Stirling-PDF grow and to allow us to understand our users better.
|
||||
analytics.enable=Enable analytics
|
||||
analytics.disable=Disable analytics
|
||||
analytics.settings=You can change the settings for analytics in the config/settings.yml file
|
||||
|
||||
#############
|
||||
# NAVBAR #
|
||||
@@ -128,6 +145,7 @@ navbar.sections.convertFrom=Pretvori iz PDF
|
||||
navbar.sections.security=Potpis & sigurnost
|
||||
navbar.sections.advance=Napredno
|
||||
navbar.sections.edit=Pregled & Uređivanje
|
||||
navbar.sections.popular=Popular
|
||||
|
||||
#############
|
||||
# SETTINGS #
|
||||
@@ -225,6 +243,8 @@ database.fileNotFound=File not Found
|
||||
database.fileNullOrEmpty=File must not be null or empty
|
||||
database.failedImportFile=Failed Import File
|
||||
|
||||
session.expired=Your session has expired. Please refresh the page and try again.
|
||||
|
||||
#############
|
||||
# HOME-PAGE #
|
||||
#############
|
||||
@@ -482,6 +502,11 @@ home.removeImagePdf.title=Remove image
|
||||
home.removeImagePdf.desc=Remove image from PDF to reduce file size
|
||||
removeImagePdf.tags=Remove Image,Page operations,Back end,server side
|
||||
|
||||
|
||||
home.splitPdfByChapters.title=Split PDF by Chapters
|
||||
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
||||
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
||||
|
||||
#replace-invert-color
|
||||
replace-color.title=Replace-Invert-Color
|
||||
replace-color.header=Replace-Invert Color PDF
|
||||
@@ -526,7 +551,10 @@ login.oauth2AccessDenied=Pristup odbijen
|
||||
login.oauth2InvalidTokenResponse=Nevažeći odgovor tokena
|
||||
login.oauth2InvalidIdToken=Nevažeći ID token
|
||||
login.userIsDisabled=User is deactivated, login is currently blocked with this username. Please contact the administrator.
|
||||
|
||||
login.alreadyLoggedIn=You are already logged in to
|
||||
login.alreadyLoggedIn2=devices. Please log out of the devices and try again.
|
||||
login.toManySessions=You have too many active sessions
|
||||
login.toManySessions2=Please log out of the devices and try again. Alternatively, you can upgrade to Stirling PDF Pro.
|
||||
|
||||
#auto-redact
|
||||
autoRedact.title=Automatsko uređivanje
|
||||
@@ -1154,6 +1182,8 @@ licenses.license=Licenca
|
||||
survey.nav=Survey
|
||||
survey.title=Stirling-PDF Survey
|
||||
survey.description=Stirling-PDF has no tracking so we want to hear from our users to improve Stirling-PDF!
|
||||
survey.changes=Stirling-PDF has changed since the last survey! To find out more please check our blog post here:
|
||||
survey.changes2=With these changes we are getting paid business support and funding
|
||||
survey.please=Please consider taking our survey!
|
||||
survey.disabled=(Survey popup will be disabled in following updates but available at foot of page)
|
||||
survey.button=Take Survey
|
||||
@@ -1179,3 +1209,17 @@ removeImage.title=Remove image
|
||||
removeImage.header=Remove image
|
||||
removeImage.removeImage=Remove image
|
||||
removeImage.submit=Remove image
|
||||
|
||||
|
||||
splitByChapters.title=Split PDF by Chapters
|
||||
splitByChapters.header=Split PDF by Chapters
|
||||
splitByChapters.bookmarkLevel=Bookmark Level
|
||||
splitByChapters.includeMetadata=Include Metadata
|
||||
splitByChapters.allowDuplicates=Allow Duplicates
|
||||
splitByChapters.desc.1=This tool splits a PDF file into multiple PDFs based on its chapter structure.
|
||||
splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for splitting (0 for top-level, 1 for second-level, etc.).
|
||||
splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF.
|
||||
splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs.
|
||||
splitByChapters.submit=Split PDF
|
||||
|
||||
|
||||
|
||||
@@ -76,6 +76,7 @@ donate=Donate
|
||||
color=Color
|
||||
sponsor=Sponsor
|
||||
info=Info
|
||||
pro=Pro
|
||||
page=Page
|
||||
pages=Pages
|
||||
|
||||
@@ -110,8 +111,24 @@ pipelineOptions.pipelineHeader=Pipeline:
|
||||
pipelineOptions.saveButton=Download
|
||||
pipelineOptions.validateButton=Validate
|
||||
|
||||
########################
|
||||
# ENTERPRISE EDITION #
|
||||
########################
|
||||
enterpriseEdition.button=Upgrade to Pro
|
||||
enterpriseEdition.warning=This feature is only available to Pro users.
|
||||
enterpriseEdition.yamlAdvert=Stirling PDF Pro supports YAML configuration files and other SSO features.
|
||||
enterpriseEdition.ssoAdvert=Looking for more user management features? Check out Stirling PDF Pro
|
||||
|
||||
|
||||
#################
|
||||
# Analytics #
|
||||
#################
|
||||
analytics.title=Do you want make Stirling PDF better?
|
||||
analytics.paragraph1=Stirling PDF has opt in analytics to help us improve the product. We do not track any personal information or file contents.
|
||||
analytics.paragraph2=Please consider enabling analytics to help Stirling-PDF grow and to allow us to understand our users better.
|
||||
analytics.enable=Enable analytics
|
||||
analytics.disable=Disable analytics
|
||||
analytics.settings=You can change the settings for analytics in the config/settings.yml file
|
||||
|
||||
#############
|
||||
# NAVBAR #
|
||||
@@ -128,6 +145,7 @@ navbar.sections.convertFrom=Convert from PDF
|
||||
navbar.sections.security=Sign & Security
|
||||
navbar.sections.advance=Advanced
|
||||
navbar.sections.edit=View & Edit
|
||||
navbar.sections.popular=Popular
|
||||
|
||||
#############
|
||||
# SETTINGS #
|
||||
@@ -225,6 +243,8 @@ database.fileNotFound=File not Found
|
||||
database.fileNullOrEmpty=File must not be null or empty
|
||||
database.failedImportFile=Failed Import File
|
||||
|
||||
session.expired=Your session has expired. Please refresh the page and try again.
|
||||
|
||||
#############
|
||||
# HOME-PAGE #
|
||||
#############
|
||||
@@ -482,6 +502,11 @@ home.removeImagePdf.title=Remove image
|
||||
home.removeImagePdf.desc=Remove image from PDF to reduce file size
|
||||
removeImagePdf.tags=Remove Image,Page operations,Back end,server side
|
||||
|
||||
|
||||
home.splitPdfByChapters.title=Split PDF by Chapters
|
||||
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
||||
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
||||
|
||||
#replace-invert-color
|
||||
replace-color.title=Replace-Invert-Color
|
||||
replace-color.header=Replace-Invert Color PDF
|
||||
@@ -526,7 +551,10 @@ login.oauth2AccessDenied=Access Denied
|
||||
login.oauth2InvalidTokenResponse=Invalid Token Response
|
||||
login.oauth2InvalidIdToken=Invalid Id Token
|
||||
login.userIsDisabled=User is deactivated, login is currently blocked with this username. Please contact the administrator.
|
||||
|
||||
login.alreadyLoggedIn=You are already logged in to
|
||||
login.alreadyLoggedIn2=devices. Please log out of the devices and try again.
|
||||
login.toManySessions=You have too many active sessions
|
||||
login.toManySessions2=Please log out of the devices and try again. Alternatively, you can upgrade to Stirling PDF Pro.
|
||||
|
||||
#auto-redact
|
||||
autoRedact.title=Érzékeny tartalom eltávolítása
|
||||
@@ -1154,6 +1182,8 @@ licenses.license=License
|
||||
survey.nav=Survey
|
||||
survey.title=Stirling-PDF Survey
|
||||
survey.description=Stirling-PDF has no tracking so we want to hear from our users to improve Stirling-PDF!
|
||||
survey.changes=Stirling-PDF has changed since the last survey! To find out more please check our blog post here:
|
||||
survey.changes2=With these changes we are getting paid business support and funding
|
||||
survey.please=Please consider taking our survey!
|
||||
survey.disabled=(Survey popup will be disabled in following updates but available at foot of page)
|
||||
survey.button=Take Survey
|
||||
@@ -1179,3 +1209,17 @@ removeImage.title=Remove image
|
||||
removeImage.header=Remove image
|
||||
removeImage.removeImage=Remove image
|
||||
removeImage.submit=Remove image
|
||||
|
||||
|
||||
splitByChapters.title=Split PDF by Chapters
|
||||
splitByChapters.header=Split PDF by Chapters
|
||||
splitByChapters.bookmarkLevel=Bookmark Level
|
||||
splitByChapters.includeMetadata=Include Metadata
|
||||
splitByChapters.allowDuplicates=Allow Duplicates
|
||||
splitByChapters.desc.1=This tool splits a PDF file into multiple PDFs based on its chapter structure.
|
||||
splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for splitting (0 for top-level, 1 for second-level, etc.).
|
||||
splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF.
|
||||
splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs.
|
||||
splitByChapters.submit=Split PDF
|
||||
|
||||
|
||||
|
||||
@@ -76,6 +76,7 @@ donate=Donate
|
||||
color=Color
|
||||
sponsor=Sponsor
|
||||
info=Info
|
||||
pro=Pro
|
||||
page=Page
|
||||
pages=Pages
|
||||
|
||||
@@ -110,8 +111,24 @@ pipelineOptions.pipelineHeader=Pipeline:
|
||||
pipelineOptions.saveButton=Download
|
||||
pipelineOptions.validateButton=Validate
|
||||
|
||||
########################
|
||||
# ENTERPRISE EDITION #
|
||||
########################
|
||||
enterpriseEdition.button=Upgrade to Pro
|
||||
enterpriseEdition.warning=This feature is only available to Pro users.
|
||||
enterpriseEdition.yamlAdvert=Stirling PDF Pro supports YAML configuration files and other SSO features.
|
||||
enterpriseEdition.ssoAdvert=Looking for more user management features? Check out Stirling PDF Pro
|
||||
|
||||
|
||||
#################
|
||||
# Analytics #
|
||||
#################
|
||||
analytics.title=Do you want make Stirling PDF better?
|
||||
analytics.paragraph1=Stirling PDF has opt in analytics to help us improve the product. We do not track any personal information or file contents.
|
||||
analytics.paragraph2=Please consider enabling analytics to help Stirling-PDF grow and to allow us to understand our users better.
|
||||
analytics.enable=Enable analytics
|
||||
analytics.disable=Disable analytics
|
||||
analytics.settings=You can change the settings for analytics in the config/settings.yml file
|
||||
|
||||
#############
|
||||
# NAVBAR #
|
||||
@@ -128,6 +145,7 @@ navbar.sections.convertFrom=Convert from PDF
|
||||
navbar.sections.security=Sign & Security
|
||||
navbar.sections.advance=Advanced
|
||||
navbar.sections.edit=View & Edit
|
||||
navbar.sections.popular=Popular
|
||||
|
||||
#############
|
||||
# SETTINGS #
|
||||
@@ -225,6 +243,8 @@ database.fileNotFound=File not Found
|
||||
database.fileNullOrEmpty=File must not be null or empty
|
||||
database.failedImportFile=Failed Import File
|
||||
|
||||
session.expired=Your session has expired. Please refresh the page and try again.
|
||||
|
||||
#############
|
||||
# HOME-PAGE #
|
||||
#############
|
||||
@@ -482,6 +502,11 @@ home.removeImagePdf.title=Remove image
|
||||
home.removeImagePdf.desc=Remove image from PDF to reduce file size
|
||||
removeImagePdf.tags=Remove Image,Page operations,Back end,server side
|
||||
|
||||
|
||||
home.splitPdfByChapters.title=Split PDF by Chapters
|
||||
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
||||
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
||||
|
||||
#replace-invert-color
|
||||
replace-color.title=Replace-Invert-Color
|
||||
replace-color.header=Replace-Invert Color PDF
|
||||
@@ -526,7 +551,10 @@ login.oauth2AccessDenied=Access Denied
|
||||
login.oauth2InvalidTokenResponse=Invalid Token Response
|
||||
login.oauth2InvalidIdToken=Invalid Id Token
|
||||
login.userIsDisabled=User is deactivated, login is currently blocked with this username. Please contact the administrator.
|
||||
|
||||
login.alreadyLoggedIn=You are already logged in to
|
||||
login.alreadyLoggedIn2=devices. Please log out of the devices and try again.
|
||||
login.toManySessions=You have too many active sessions
|
||||
login.toManySessions2=Please log out of the devices and try again. Alternatively, you can upgrade to Stirling PDF Pro.
|
||||
|
||||
#auto-redact
|
||||
autoRedact.title=Redaksional Otomatis
|
||||
@@ -1154,6 +1182,8 @@ licenses.license=License
|
||||
survey.nav=Survey
|
||||
survey.title=Stirling-PDF Survey
|
||||
survey.description=Stirling-PDF has no tracking so we want to hear from our users to improve Stirling-PDF!
|
||||
survey.changes=Stirling-PDF has changed since the last survey! To find out more please check our blog post here:
|
||||
survey.changes2=With these changes we are getting paid business support and funding
|
||||
survey.please=Please consider taking our survey!
|
||||
survey.disabled=(Survey popup will be disabled in following updates but available at foot of page)
|
||||
survey.button=Take Survey
|
||||
@@ -1179,3 +1209,17 @@ removeImage.title=Remove image
|
||||
removeImage.header=Remove image
|
||||
removeImage.removeImage=Remove image
|
||||
removeImage.submit=Remove image
|
||||
|
||||
|
||||
splitByChapters.title=Split PDF by Chapters
|
||||
splitByChapters.header=Split PDF by Chapters
|
||||
splitByChapters.bookmarkLevel=Bookmark Level
|
||||
splitByChapters.includeMetadata=Include Metadata
|
||||
splitByChapters.allowDuplicates=Allow Duplicates
|
||||
splitByChapters.desc.1=This tool splits a PDF file into multiple PDFs based on its chapter structure.
|
||||
splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for splitting (0 for top-level, 1 for second-level, etc.).
|
||||
splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF.
|
||||
splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs.
|
||||
splitByChapters.submit=Split PDF
|
||||
|
||||
|
||||
|
||||
@@ -76,8 +76,9 @@ donate=Donazione
|
||||
color=Colore
|
||||
sponsor=Sponsor
|
||||
info=Info
|
||||
page=Page
|
||||
pages=Pages
|
||||
pro=Pro
|
||||
page=Pagina
|
||||
pages=Pagine
|
||||
|
||||
legal.privacy=Informativa sulla privacy
|
||||
legal.terms=Termini e Condizioni
|
||||
@@ -110,8 +111,24 @@ pipelineOptions.pipelineHeader=Pipeline:
|
||||
pipelineOptions.saveButton=Download
|
||||
pipelineOptions.validateButton=Convalidare
|
||||
|
||||
########################
|
||||
# ENTERPRISE EDITION #
|
||||
########################
|
||||
enterpriseEdition.button=Aggiorna alla versione Pro
|
||||
enterpriseEdition.warning=Questa funzionalità è disponibile solo per gli utenti Pro.
|
||||
enterpriseEdition.yamlAdvert=Stirling PDF Pro supporta i file di configurazione YAML e altre funzionalità SSO.
|
||||
enterpriseEdition.ssoAdvert=Cerchi altre funzionalità di gestione degli utenti? Dai un'occhiata a Stirling PDF Pro
|
||||
|
||||
|
||||
#################
|
||||
# Analytics #
|
||||
#################
|
||||
analytics.title=Vuoi migliorare Stirling PDF?
|
||||
analytics.paragraph1=Stirling PDF ha opt-in analytics per aiutarci a migliorare il prodotto. Non tracciamo alcuna informazione personale o contenuto di file.
|
||||
analytics.paragraph2=Si prega di prendere in considerazione l'attivazione dell'analytics per aiutare Stirling-PDF a crescere e consentirci di comprendere meglio i nostri utenti.
|
||||
analytics.enable=Abilita analytics
|
||||
analytics.disable=Disabilita analytics
|
||||
analytics.settings=È possibile modificare le impostazioni per analitycs nel file config/settings.yml
|
||||
|
||||
#############
|
||||
# NAVBAR #
|
||||
@@ -128,6 +145,7 @@ navbar.sections.convertFrom=Converti da PDF
|
||||
navbar.sections.security=Firma & Sicurezza
|
||||
navbar.sections.advance=Avanzate
|
||||
navbar.sections.edit=Visualizza & Modifica
|
||||
navbar.sections.popular=Populare
|
||||
|
||||
#############
|
||||
# SETTINGS #
|
||||
@@ -225,6 +243,8 @@ database.fileNotFound=File non trovato
|
||||
database.fileNullOrEmpty=Il file non deve essere nullo o vuoto
|
||||
database.failedImportFile=Importazione file non riuscita
|
||||
|
||||
session.expired=La tua sessione è scaduta. Aggiorna la pagina e riprova.
|
||||
|
||||
#############
|
||||
# HOME-PAGE #
|
||||
#############
|
||||
@@ -482,24 +502,29 @@ home.removeImagePdf.title=Rimuovi immagine
|
||||
home.removeImagePdf.desc=Rimuovi le immagini dal PDF per ridurre la dimensione del file
|
||||
removeImagePdf.tags=Rimuovi immagine,operazioni sulla pagina,back-end,lato server
|
||||
|
||||
|
||||
home.splitPdfByChapters.title=Dividi PDF per capitoli
|
||||
home.splitPdfByChapters.desc=Dividi un PDF in più file in base alla struttura dei capitoli.
|
||||
splitPdfByChapters.tags=dividi, capitoli, segnalibri, organizza
|
||||
|
||||
#replace-invert-color
|
||||
replace-color.title=Replace-Invert-Color
|
||||
replace-color.header=Replace-Invert Color PDF
|
||||
home.replaceColorPdf.title=Replace and Invert Color
|
||||
home.replaceColorPdf.desc=Replace color for text and background in PDF and invert full color of pdf to reduce file size
|
||||
replaceColorPdf.tags=Replace Color,Page operations,Back end,server side
|
||||
replace-color.selectText.1=Replace or Invert color Options
|
||||
replace-color.selectText.2=Default(Default high contrast colors)
|
||||
replace-color.selectText.3=Custom(Customized colors)
|
||||
replace-color.selectText.4=Full-Invert(Invert all colors)
|
||||
replace-color.selectText.5=High contrast color options
|
||||
replace-color.selectText.6=white text on black background
|
||||
replace-color.selectText.7=Black text on white background
|
||||
replace-color.selectText.8=Yellow text on black background
|
||||
replace-color.selectText.9=Green text on black background
|
||||
replace-color.selectText.10=Choose text Color
|
||||
replace-color.selectText.11=Choose background Color
|
||||
replace-color.submit=Replace
|
||||
replace-color.title=Sostituisci-Inverti-Colore
|
||||
replace-color.header=Sostituisci-Inverti colore PDF
|
||||
home.replaceColorPdf.title=Sostituisci e inverti il colore
|
||||
home.replaceColorPdf.desc=Sostituisci il colore del testo e dello sfondo nel PDF e inverti il colore completo del PDF per ridurre le dimensioni del file
|
||||
replaceColorPdf.tags=Sostituisci colore, Operazioni di pagina, Back-end, lato server
|
||||
replace-color.selectText.1=Sostituisci o inverti le opzioni del colore
|
||||
replace-color.selectText.2=Predefinito (colori ad alto contrasto predefiniti)
|
||||
replace-color.selectText.3=Personalizzato (colori personalizzati)
|
||||
replace-color.selectText.4=Inversione completa (inverte tutti i colori)
|
||||
replace-color.selectText.5=Opzioni di colore ad alto contrasto
|
||||
replace-color.selectText.6=testo bianco su sfondo nero
|
||||
replace-color.selectText.7=Testo nero su sfondo bianco
|
||||
replace-color.selectText.8=Testo giallo su sfondo nero
|
||||
replace-color.selectText.9=Testo verde su sfondo nero
|
||||
replace-color.selectText.10=Scegli il colore del testo
|
||||
replace-color.selectText.11=Scegli il colore di sfondo
|
||||
replace-color.submit=Sostituisci
|
||||
|
||||
|
||||
|
||||
@@ -526,7 +551,10 @@ login.oauth2AccessDenied=Accesso negato
|
||||
login.oauth2InvalidTokenResponse=Risposta token non valida
|
||||
login.oauth2InvalidIdToken=Id Token non valido
|
||||
login.userIsDisabled=L'utente è disattivato, l'accesso è attualmente bloccato con questo nome utente. Si prega di contattare l'amministratore.
|
||||
|
||||
login.alreadyLoggedIn=Hai già effettuato l'accesso a
|
||||
login.alreadyLoggedIn2=dispositivi. Esci dai dispositivi e riprova.
|
||||
login.toManySessions=Hai troppe sessioni attive
|
||||
login.toManySessions2=Si prega di uscire dai dispositivi e riprovare. In alternativa, è possibile effettuare l'upgrade a Stirling PDF Pro.
|
||||
|
||||
#auto-redact
|
||||
autoRedact.title=Redazione automatica
|
||||
@@ -1154,6 +1182,8 @@ licenses.license=Licenza
|
||||
survey.nav=Sondaggio
|
||||
survey.title=Sondaggio Stirling-PDF
|
||||
survey.description=Stirling-PDF non fa tracciamento, quindi vogliamo sentire i nostri utenti per migliorare Stirling-PDF!
|
||||
survey.changes=Stirling-PDF è cambiato dall'ultimo sondaggio! Per saperne di più, consulta il nostro blog qui:
|
||||
survey.changes2=Con questi cambiamenti stiamo ricevendo supporto aziendale e finanziamenti retribuiti
|
||||
survey.please=Ti invitiamo a prendere in considerazione la possibilità di partecipare al nostro sondaggio!
|
||||
survey.disabled=(Il popup del sondaggio verrà disabilitato nei prossimi aggiornamenti ma sarà disponibile a piè di pagina)
|
||||
survey.button=Partecipa al sondaggio
|
||||
@@ -1179,3 +1209,17 @@ removeImage.title=Rimuovere immagine
|
||||
removeImage.header=Rimuovi immagine
|
||||
removeImage.removeImage=Rimuovi immagine
|
||||
removeImage.submit=Rimuovi immagine
|
||||
|
||||
|
||||
splitByChapters.title=Dividere PDF per capitoli
|
||||
splitByChapters.header=Dividi PDF per capitoli
|
||||
splitByChapters.bookmarkLevel=Livello segnalibro
|
||||
splitByChapters.includeMetadata=Includi Metadati
|
||||
splitByChapters.allowDuplicates=Consenti duplicati
|
||||
splitByChapters.desc.1=Questo strumento divide un file PDF in più PDF in base alla struttura dei capitoli.
|
||||
splitByChapters.desc.2=Livello segnalibro: seleziona il livello dei segnalibri da utilizzare per la suddivisione (0 per il livello superiore, 1 per il secondo livello, ecc.).
|
||||
splitByChapters.desc.3=Includi metadati: se selezionato, i metadati del PDF originale verranno inclusi in ogni PDF diviso.
|
||||
splitByChapters.desc.4=Consenti duplicati: se selezionata, consente più segnalibri sulla stessa pagina per creare PDF separati.
|
||||
splitByChapters.submit=Dividi PDF
|
||||
|
||||
|
||||
|
||||
@@ -76,6 +76,7 @@ donate=寄付する
|
||||
color=色
|
||||
sponsor=スポンサー
|
||||
info=Info
|
||||
pro=Pro
|
||||
page=Page
|
||||
pages=Pages
|
||||
|
||||
@@ -110,8 +111,24 @@ pipelineOptions.pipelineHeader=パイプライン:
|
||||
pipelineOptions.saveButton=ダウンロード
|
||||
pipelineOptions.validateButton=検証
|
||||
|
||||
########################
|
||||
# ENTERPRISE EDITION #
|
||||
########################
|
||||
enterpriseEdition.button=Upgrade to Pro
|
||||
enterpriseEdition.warning=This feature is only available to Pro users.
|
||||
enterpriseEdition.yamlAdvert=Stirling PDF Pro supports YAML configuration files and other SSO features.
|
||||
enterpriseEdition.ssoAdvert=Looking for more user management features? Check out Stirling PDF Pro
|
||||
|
||||
|
||||
#################
|
||||
# Analytics #
|
||||
#################
|
||||
analytics.title=Do you want make Stirling PDF better?
|
||||
analytics.paragraph1=Stirling PDF has opt in analytics to help us improve the product. We do not track any personal information or file contents.
|
||||
analytics.paragraph2=Please consider enabling analytics to help Stirling-PDF grow and to allow us to understand our users better.
|
||||
analytics.enable=Enable analytics
|
||||
analytics.disable=Disable analytics
|
||||
analytics.settings=You can change the settings for analytics in the config/settings.yml file
|
||||
|
||||
#############
|
||||
# NAVBAR #
|
||||
@@ -128,6 +145,7 @@ navbar.sections.convertFrom=PDFから変換
|
||||
navbar.sections.security=署名とセキュリティ
|
||||
navbar.sections.advance=アドバンスド
|
||||
navbar.sections.edit=閲覧と編集
|
||||
navbar.sections.popular=Popular
|
||||
|
||||
#############
|
||||
# SETTINGS #
|
||||
@@ -225,6 +243,8 @@ database.fileNotFound=ファイルが見つかりません
|
||||
database.fileNullOrEmpty=ファイルは null または空であってはなりません
|
||||
database.failedImportFile=ファイルのインポートに失敗
|
||||
|
||||
session.expired=Your session has expired. Please refresh the page and try again.
|
||||
|
||||
#############
|
||||
# HOME-PAGE #
|
||||
#############
|
||||
@@ -482,6 +502,11 @@ home.removeImagePdf.title=画像の削除
|
||||
home.removeImagePdf.desc=PDFから画像を削除してファイルサイズを小さくします
|
||||
removeImagePdf.tags=Remove Image,Page operations,Back end,server side
|
||||
|
||||
|
||||
home.splitPdfByChapters.title=Split PDF by Chapters
|
||||
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
||||
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
||||
|
||||
#replace-invert-color
|
||||
replace-color.title=Replace-Invert-Color
|
||||
replace-color.header=Replace-Invert Color PDF
|
||||
@@ -526,7 +551,10 @@ login.oauth2AccessDenied=アクセス拒否
|
||||
login.oauth2InvalidTokenResponse=無効なトークン応答
|
||||
login.oauth2InvalidIdToken=無効なIDトークン
|
||||
login.userIsDisabled=ユーザーは非アクティブ化されており、現在このユーザー名でのログインはブロックされています。管理者に連絡してください。
|
||||
|
||||
login.alreadyLoggedIn=You are already logged in to
|
||||
login.alreadyLoggedIn2=devices. Please log out of the devices and try again.
|
||||
login.toManySessions=You have too many active sessions
|
||||
login.toManySessions2=Please log out of the devices and try again. Alternatively, you can upgrade to Stirling PDF Pro.
|
||||
|
||||
#auto-redact
|
||||
autoRedact.title=自動塗りつぶし
|
||||
@@ -1154,6 +1182,8 @@ licenses.license=ライセンス
|
||||
survey.nav=アンケート
|
||||
survey.title=Stirling-PDFのアンケート
|
||||
survey.description=Stirling-PDFには追跡機能がないため、Stirling-PDFをより良くするために皆様の意見を聞かせてください!
|
||||
survey.changes=Stirling-PDF has changed since the last survey! To find out more please check our blog post here:
|
||||
survey.changes2=With these changes we are getting paid business support and funding
|
||||
survey.please=アンケートにご協力ください!
|
||||
survey.disabled=(アンケートのポップアップは、次の更新では無効になりますが、ページの下部に表示されます。)
|
||||
survey.button=アンケートに答える
|
||||
@@ -1179,3 +1209,17 @@ removeImage.title=画像の削除
|
||||
removeImage.header=画像の削除
|
||||
removeImage.removeImage=画像の削除
|
||||
removeImage.submit=画像を削除
|
||||
|
||||
|
||||
splitByChapters.title=Split PDF by Chapters
|
||||
splitByChapters.header=Split PDF by Chapters
|
||||
splitByChapters.bookmarkLevel=Bookmark Level
|
||||
splitByChapters.includeMetadata=Include Metadata
|
||||
splitByChapters.allowDuplicates=Allow Duplicates
|
||||
splitByChapters.desc.1=This tool splits a PDF file into multiple PDFs based on its chapter structure.
|
||||
splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for splitting (0 for top-level, 1 for second-level, etc.).
|
||||
splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF.
|
||||
splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs.
|
||||
splitByChapters.submit=Split PDF
|
||||
|
||||
|
||||
|
||||
@@ -76,6 +76,7 @@ donate=기부하기
|
||||
color=색상
|
||||
sponsor=스폰서
|
||||
info=Info
|
||||
pro=Pro
|
||||
page=Page
|
||||
pages=Pages
|
||||
|
||||
@@ -110,8 +111,24 @@ pipelineOptions.pipelineHeader=파이프라인:
|
||||
pipelineOptions.saveButton=다운로드
|
||||
pipelineOptions.validateButton=확인
|
||||
|
||||
########################
|
||||
# ENTERPRISE EDITION #
|
||||
########################
|
||||
enterpriseEdition.button=Upgrade to Pro
|
||||
enterpriseEdition.warning=This feature is only available to Pro users.
|
||||
enterpriseEdition.yamlAdvert=Stirling PDF Pro supports YAML configuration files and other SSO features.
|
||||
enterpriseEdition.ssoAdvert=Looking for more user management features? Check out Stirling PDF Pro
|
||||
|
||||
|
||||
#################
|
||||
# Analytics #
|
||||
#################
|
||||
analytics.title=Do you want make Stirling PDF better?
|
||||
analytics.paragraph1=Stirling PDF has opt in analytics to help us improve the product. We do not track any personal information or file contents.
|
||||
analytics.paragraph2=Please consider enabling analytics to help Stirling-PDF grow and to allow us to understand our users better.
|
||||
analytics.enable=Enable analytics
|
||||
analytics.disable=Disable analytics
|
||||
analytics.settings=You can change the settings for analytics in the config/settings.yml file
|
||||
|
||||
#############
|
||||
# NAVBAR #
|
||||
@@ -128,6 +145,7 @@ navbar.sections.convertFrom=Convert from PDF
|
||||
navbar.sections.security=Sign & Security
|
||||
navbar.sections.advance=Advanced
|
||||
navbar.sections.edit=View & Edit
|
||||
navbar.sections.popular=Popular
|
||||
|
||||
#############
|
||||
# SETTINGS #
|
||||
@@ -225,6 +243,8 @@ database.fileNotFound=File not Found
|
||||
database.fileNullOrEmpty=File must not be null or empty
|
||||
database.failedImportFile=Failed Import File
|
||||
|
||||
session.expired=Your session has expired. Please refresh the page and try again.
|
||||
|
||||
#############
|
||||
# HOME-PAGE #
|
||||
#############
|
||||
@@ -482,6 +502,11 @@ home.removeImagePdf.title=Remove image
|
||||
home.removeImagePdf.desc=Remove image from PDF to reduce file size
|
||||
removeImagePdf.tags=Remove Image,Page operations,Back end,server side
|
||||
|
||||
|
||||
home.splitPdfByChapters.title=Split PDF by Chapters
|
||||
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
||||
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
||||
|
||||
#replace-invert-color
|
||||
replace-color.title=Replace-Invert-Color
|
||||
replace-color.header=Replace-Invert Color PDF
|
||||
@@ -526,7 +551,10 @@ login.oauth2AccessDenied=Access Denied
|
||||
login.oauth2InvalidTokenResponse=Invalid Token Response
|
||||
login.oauth2InvalidIdToken=Invalid Id Token
|
||||
login.userIsDisabled=User is deactivated, login is currently blocked with this username. Please contact the administrator.
|
||||
|
||||
login.alreadyLoggedIn=You are already logged in to
|
||||
login.alreadyLoggedIn2=devices. Please log out of the devices and try again.
|
||||
login.toManySessions=You have too many active sessions
|
||||
login.toManySessions2=Please log out of the devices and try again. Alternatively, you can upgrade to Stirling PDF Pro.
|
||||
|
||||
#auto-redact
|
||||
autoRedact.title=자동 검열
|
||||
@@ -1154,6 +1182,8 @@ licenses.license=라이센스
|
||||
survey.nav=Survey
|
||||
survey.title=Stirling-PDF Survey
|
||||
survey.description=Stirling-PDF has no tracking so we want to hear from our users to improve Stirling-PDF!
|
||||
survey.changes=Stirling-PDF has changed since the last survey! To find out more please check our blog post here:
|
||||
survey.changes2=With these changes we are getting paid business support and funding
|
||||
survey.please=Please consider taking our survey!
|
||||
survey.disabled=(Survey popup will be disabled in following updates but available at foot of page)
|
||||
survey.button=Take Survey
|
||||
@@ -1179,3 +1209,17 @@ removeImage.title=Remove image
|
||||
removeImage.header=Remove image
|
||||
removeImage.removeImage=Remove image
|
||||
removeImage.submit=Remove image
|
||||
|
||||
|
||||
splitByChapters.title=Split PDF by Chapters
|
||||
splitByChapters.header=Split PDF by Chapters
|
||||
splitByChapters.bookmarkLevel=Bookmark Level
|
||||
splitByChapters.includeMetadata=Include Metadata
|
||||
splitByChapters.allowDuplicates=Allow Duplicates
|
||||
splitByChapters.desc.1=This tool splits a PDF file into multiple PDFs based on its chapter structure.
|
||||
splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for splitting (0 for top-level, 1 for second-level, etc.).
|
||||
splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF.
|
||||
splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs.
|
||||
splitByChapters.submit=Split PDF
|
||||
|
||||
|
||||
|
||||
@@ -76,6 +76,7 @@ donate=Doneer
|
||||
color=Kleur
|
||||
sponsor=Sponsor
|
||||
info=Info
|
||||
pro=Pro
|
||||
page=Page
|
||||
pages=Pages
|
||||
|
||||
@@ -110,8 +111,24 @@ pipelineOptions.pipelineHeader=Pijplijn:
|
||||
pipelineOptions.saveButton=Downloaden
|
||||
pipelineOptions.validateButton=Valideren
|
||||
|
||||
########################
|
||||
# ENTERPRISE EDITION #
|
||||
########################
|
||||
enterpriseEdition.button=Upgrade to Pro
|
||||
enterpriseEdition.warning=This feature is only available to Pro users.
|
||||
enterpriseEdition.yamlAdvert=Stirling PDF Pro supports YAML configuration files and other SSO features.
|
||||
enterpriseEdition.ssoAdvert=Looking for more user management features? Check out Stirling PDF Pro
|
||||
|
||||
|
||||
#################
|
||||
# Analytics #
|
||||
#################
|
||||
analytics.title=Do you want make Stirling PDF better?
|
||||
analytics.paragraph1=Stirling PDF has opt in analytics to help us improve the product. We do not track any personal information or file contents.
|
||||
analytics.paragraph2=Please consider enabling analytics to help Stirling-PDF grow and to allow us to understand our users better.
|
||||
analytics.enable=Enable analytics
|
||||
analytics.disable=Disable analytics
|
||||
analytics.settings=You can change the settings for analytics in the config/settings.yml file
|
||||
|
||||
#############
|
||||
# NAVBAR #
|
||||
@@ -128,6 +145,7 @@ navbar.sections.convertFrom=Converteren van PDF
|
||||
navbar.sections.security=Ondertekenen & beveiliging
|
||||
navbar.sections.advance=Geavanceerd
|
||||
navbar.sections.edit=Bekijken & wijzigen
|
||||
navbar.sections.popular=Popular
|
||||
|
||||
#############
|
||||
# SETTINGS #
|
||||
@@ -225,6 +243,8 @@ database.fileNotFound=File not Found
|
||||
database.fileNullOrEmpty=File must not be null or empty
|
||||
database.failedImportFile=Failed Import File
|
||||
|
||||
session.expired=Your session has expired. Please refresh the page and try again.
|
||||
|
||||
#############
|
||||
# HOME-PAGE #
|
||||
#############
|
||||
@@ -482,6 +502,11 @@ home.removeImagePdf.title=Remove image
|
||||
home.removeImagePdf.desc=Remove image from PDF to reduce file size
|
||||
removeImagePdf.tags=Remove Image,Page operations,Back end,server side
|
||||
|
||||
|
||||
home.splitPdfByChapters.title=Split PDF by Chapters
|
||||
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
||||
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
||||
|
||||
#replace-invert-color
|
||||
replace-color.title=Replace-Invert-Color
|
||||
replace-color.header=Replace-Invert Color PDF
|
||||
@@ -526,7 +551,10 @@ login.oauth2AccessDenied=Toegang geweigerd
|
||||
login.oauth2InvalidTokenResponse=Ongeldige tokenreactie
|
||||
login.oauth2InvalidIdToken=Ongeldige ID token
|
||||
login.userIsDisabled=User is deactivated, login is currently blocked with this username. Please contact the administrator.
|
||||
|
||||
login.alreadyLoggedIn=You are already logged in to
|
||||
login.alreadyLoggedIn2=devices. Please log out of the devices and try again.
|
||||
login.toManySessions=You have too many active sessions
|
||||
login.toManySessions2=Please log out of the devices and try again. Alternatively, you can upgrade to Stirling PDF Pro.
|
||||
|
||||
#auto-redact
|
||||
autoRedact.title=Automatisch censureren
|
||||
@@ -1154,6 +1182,8 @@ licenses.license=Licentie
|
||||
survey.nav=Enquête
|
||||
survey.title=Stirling-PDF Enquête
|
||||
survey.description=Stirling-PDF heeft geen tracking, dus we willen van onze gebruikers horen om Stirling-PDF te verbeteren.
|
||||
survey.changes=Stirling-PDF has changed since the last survey! To find out more please check our blog post here:
|
||||
survey.changes2=With these changes we are getting paid business support and funding
|
||||
survey.please=Overweeg alstublieft om onze enquête in te vullen!
|
||||
survey.disabled=(Enquête popup wordt in een toekomstige update weggehaald, maar is beschikbaar aan de onderkant van de pagina.)
|
||||
survey.button=Vul enquête in.
|
||||
@@ -1179,3 +1209,17 @@ removeImage.title=Remove image
|
||||
removeImage.header=Remove image
|
||||
removeImage.removeImage=Remove image
|
||||
removeImage.submit=Remove image
|
||||
|
||||
|
||||
splitByChapters.title=Split PDF by Chapters
|
||||
splitByChapters.header=Split PDF by Chapters
|
||||
splitByChapters.bookmarkLevel=Bookmark Level
|
||||
splitByChapters.includeMetadata=Include Metadata
|
||||
splitByChapters.allowDuplicates=Allow Duplicates
|
||||
splitByChapters.desc.1=This tool splits a PDF file into multiple PDFs based on its chapter structure.
|
||||
splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for splitting (0 for top-level, 1 for second-level, etc.).
|
||||
splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF.
|
||||
splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs.
|
||||
splitByChapters.submit=Split PDF
|
||||
|
||||
|
||||
|
||||
@@ -76,6 +76,7 @@ donate=Doner
|
||||
color=Farge
|
||||
sponsor=Sponsor
|
||||
info=Info
|
||||
pro=Pro
|
||||
page=Page
|
||||
pages=Pages
|
||||
|
||||
@@ -110,8 +111,24 @@ pipelineOptions.pipelineHeader=Pipeline:
|
||||
pipelineOptions.saveButton=Last ned
|
||||
pipelineOptions.validateButton=Valider
|
||||
|
||||
########################
|
||||
# ENTERPRISE EDITION #
|
||||
########################
|
||||
enterpriseEdition.button=Upgrade to Pro
|
||||
enterpriseEdition.warning=This feature is only available to Pro users.
|
||||
enterpriseEdition.yamlAdvert=Stirling PDF Pro supports YAML configuration files and other SSO features.
|
||||
enterpriseEdition.ssoAdvert=Looking for more user management features? Check out Stirling PDF Pro
|
||||
|
||||
|
||||
#################
|
||||
# Analytics #
|
||||
#################
|
||||
analytics.title=Do you want make Stirling PDF better?
|
||||
analytics.paragraph1=Stirling PDF has opt in analytics to help us improve the product. We do not track any personal information or file contents.
|
||||
analytics.paragraph2=Please consider enabling analytics to help Stirling-PDF grow and to allow us to understand our users better.
|
||||
analytics.enable=Enable analytics
|
||||
analytics.disable=Disable analytics
|
||||
analytics.settings=You can change the settings for analytics in the config/settings.yml file
|
||||
|
||||
#############
|
||||
# NAVBAR #
|
||||
@@ -128,6 +145,7 @@ navbar.sections.convertFrom=Konverter fra PDF
|
||||
navbar.sections.security=Signer & Sikkerhet
|
||||
navbar.sections.advance=Avansert
|
||||
navbar.sections.edit=Vis & Rediger
|
||||
navbar.sections.popular=Popular
|
||||
|
||||
#############
|
||||
# SETTINGS #
|
||||
@@ -225,6 +243,8 @@ database.fileNotFound=Fil ikke funnet
|
||||
database.fileNullOrEmpty=Fil må ikke være tom eller null
|
||||
database.failedImportFile=Import av fil mislyktes
|
||||
|
||||
session.expired=Your session has expired. Please refresh the page and try again.
|
||||
|
||||
#############
|
||||
# HOME-PAGE #
|
||||
#############
|
||||
@@ -482,6 +502,11 @@ home.removeImagePdf.title=Remove image
|
||||
home.removeImagePdf.desc=Remove image from PDF to reduce file size
|
||||
removeImagePdf.tags=Remove Image,Page operations,Back end,server side
|
||||
|
||||
|
||||
home.splitPdfByChapters.title=Split PDF by Chapters
|
||||
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
||||
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
||||
|
||||
#replace-invert-color
|
||||
replace-color.title=Replace-Invert-Color
|
||||
replace-color.header=Replace-Invert Color PDF
|
||||
@@ -526,7 +551,10 @@ login.oauth2AccessDenied=Tilgang nektet
|
||||
login.oauth2InvalidTokenResponse=Ugyldig tokenrespons
|
||||
login.oauth2InvalidIdToken=Ugyldig Id Token
|
||||
login.userIsDisabled=User is deactivated, login is currently blocked with this username. Please contact the administrator.
|
||||
|
||||
login.alreadyLoggedIn=You are already logged in to
|
||||
login.alreadyLoggedIn2=devices. Please log out of the devices and try again.
|
||||
login.toManySessions=You have too many active sessions
|
||||
login.toManySessions2=Please log out of the devices and try again. Alternatively, you can upgrade to Stirling PDF Pro.
|
||||
|
||||
#auto-redact
|
||||
autoRedact.title=Automatisk Sensurering
|
||||
@@ -1154,6 +1182,8 @@ licenses.license=Lisens
|
||||
survey.nav=Survey
|
||||
survey.title=Stirling-PDF Survey
|
||||
survey.description=Stirling-PDF has no tracking so we want to hear from our users to improve Stirling-PDF!
|
||||
survey.changes=Stirling-PDF has changed since the last survey! To find out more please check our blog post here:
|
||||
survey.changes2=With these changes we are getting paid business support and funding
|
||||
survey.please=Please consider taking our survey!
|
||||
survey.disabled=(Survey popup will be disabled in following updates but available at foot of page)
|
||||
survey.button=Take Survey
|
||||
@@ -1179,3 +1209,17 @@ removeImage.title=Remove image
|
||||
removeImage.header=Remove image
|
||||
removeImage.removeImage=Remove image
|
||||
removeImage.submit=Remove image
|
||||
|
||||
|
||||
splitByChapters.title=Split PDF by Chapters
|
||||
splitByChapters.header=Split PDF by Chapters
|
||||
splitByChapters.bookmarkLevel=Bookmark Level
|
||||
splitByChapters.includeMetadata=Include Metadata
|
||||
splitByChapters.allowDuplicates=Allow Duplicates
|
||||
splitByChapters.desc.1=This tool splits a PDF file into multiple PDFs based on its chapter structure.
|
||||
splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for splitting (0 for top-level, 1 for second-level, etc.).
|
||||
splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF.
|
||||
splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs.
|
||||
splitByChapters.submit=Split PDF
|
||||
|
||||
|
||||
|
||||
@@ -76,6 +76,7 @@ donate=Podaruj
|
||||
color=kolor
|
||||
sponsor=sponsor
|
||||
info=informacje
|
||||
pro=Pro
|
||||
page=Page
|
||||
pages=Pages
|
||||
|
||||
@@ -110,8 +111,24 @@ pipelineOptions.pipelineHeader=Automatyzacja
|
||||
pipelineOptions.saveButton=Pobierz
|
||||
pipelineOptions.validateButton=Waliduj
|
||||
|
||||
########################
|
||||
# ENTERPRISE EDITION #
|
||||
########################
|
||||
enterpriseEdition.button=Upgrade to Pro
|
||||
enterpriseEdition.warning=This feature is only available to Pro users.
|
||||
enterpriseEdition.yamlAdvert=Stirling PDF Pro supports YAML configuration files and other SSO features.
|
||||
enterpriseEdition.ssoAdvert=Looking for more user management features? Check out Stirling PDF Pro
|
||||
|
||||
|
||||
#################
|
||||
# Analytics #
|
||||
#################
|
||||
analytics.title=Do you want make Stirling PDF better?
|
||||
analytics.paragraph1=Stirling PDF has opt in analytics to help us improve the product. We do not track any personal information or file contents.
|
||||
analytics.paragraph2=Please consider enabling analytics to help Stirling-PDF grow and to allow us to understand our users better.
|
||||
analytics.enable=Enable analytics
|
||||
analytics.disable=Disable analytics
|
||||
analytics.settings=You can change the settings for analytics in the config/settings.yml file
|
||||
|
||||
#############
|
||||
# NAVBAR #
|
||||
@@ -128,6 +145,7 @@ navbar.sections.convertFrom=Przetwórz z PDF
|
||||
navbar.sections.security=Podpis i bezpieczeństwo
|
||||
navbar.sections.advance=Zaawansowane
|
||||
navbar.sections.edit=Podgląd i edycja
|
||||
navbar.sections.popular=Popular
|
||||
|
||||
#############
|
||||
# SETTINGS #
|
||||
@@ -225,6 +243,8 @@ database.fileNotFound=Plik nie znaleziony
|
||||
database.fileNullOrEmpty=Plik nie może być pusty
|
||||
database.failedImportFile=Nie udało się zaimportować pliku
|
||||
|
||||
session.expired=Your session has expired. Please refresh the page and try again.
|
||||
|
||||
#############
|
||||
# HOME-PAGE #
|
||||
#############
|
||||
@@ -482,6 +502,11 @@ home.removeImagePdf.title=Remove image
|
||||
home.removeImagePdf.desc=Remove image from PDF to reduce file size
|
||||
removeImagePdf.tags=Remove Image,Page operations,Back end,server side
|
||||
|
||||
|
||||
home.splitPdfByChapters.title=Split PDF by Chapters
|
||||
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
||||
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
||||
|
||||
#replace-invert-color
|
||||
replace-color.title=Replace-Invert-Color
|
||||
replace-color.header=Replace-Invert Color PDF
|
||||
@@ -526,7 +551,10 @@ login.oauth2AccessDenied=Brak dostępu
|
||||
login.oauth2InvalidTokenResponse=Nieprawidłowa odpowiedź na token
|
||||
login.oauth2InvalidIdToken=Nieprawidłowa wartość tokenu
|
||||
login.userIsDisabled=User is deactivated, login is currently blocked with this username. Please contact the administrator.
|
||||
|
||||
login.alreadyLoggedIn=You are already logged in to
|
||||
login.alreadyLoggedIn2=devices. Please log out of the devices and try again.
|
||||
login.toManySessions=You have too many active sessions
|
||||
login.toManySessions2=Please log out of the devices and try again. Alternatively, you can upgrade to Stirling PDF Pro.
|
||||
|
||||
#auto-redact
|
||||
autoRedact.title=Automatyczne zaciemnienie
|
||||
@@ -1154,6 +1182,8 @@ licenses.license=Licencja
|
||||
survey.nav=Ankieta
|
||||
survey.title=Ankieta Stirling-PDF
|
||||
survey.description=Stirling-PDF nie śledzi swoich użytkowników, więc chciałby poznać opinie swoich użytkowników!
|
||||
survey.changes=Stirling-PDF has changed since the last survey! To find out more please check our blog post here:
|
||||
survey.changes2=With these changes we are getting paid business support and funding
|
||||
survey.please=Wypełnij proszę ankietę dla nas!
|
||||
survey.disabled=(Blokada wyskakującego okienka z ankieta zostanie dodane w następnych aktualizacjach, ale będzie dostępna na dole strony)
|
||||
survey.button=Wypełnij ankietę
|
||||
@@ -1179,3 +1209,17 @@ removeImage.title=Remove image
|
||||
removeImage.header=Remove image
|
||||
removeImage.removeImage=Remove image
|
||||
removeImage.submit=Remove image
|
||||
|
||||
|
||||
splitByChapters.title=Split PDF by Chapters
|
||||
splitByChapters.header=Split PDF by Chapters
|
||||
splitByChapters.bookmarkLevel=Bookmark Level
|
||||
splitByChapters.includeMetadata=Include Metadata
|
||||
splitByChapters.allowDuplicates=Allow Duplicates
|
||||
splitByChapters.desc.1=This tool splits a PDF file into multiple PDFs based on its chapter structure.
|
||||
splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for splitting (0 for top-level, 1 for second-level, etc.).
|
||||
splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF.
|
||||
splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs.
|
||||
splitByChapters.submit=Split PDF
|
||||
|
||||
|
||||
|
||||
@@ -3,42 +3,42 @@
|
||||
###########
|
||||
# the direction that the language is written (ltr = left to right, rtl = right to left)
|
||||
language.direction=ltr
|
||||
addPageNumbers.fontSize=Tamanho da fonte
|
||||
addPageNumbers.fontName=Nome da fonte
|
||||
addPageNumbers.fontSize=Tamanho da Fonte
|
||||
addPageNumbers.fontName=Nome da Fonte
|
||||
pdfPrompt=Selecione PDF(s)
|
||||
multiPdfPrompt=Selecione PDFs (2+)
|
||||
multiPdfDropPrompt=Selecione (ou arraste e solte) todos os PDFs necessários
|
||||
imgPrompt=Selecione a(s) imagem(ns)
|
||||
multiPdfDropPrompt=Selecione (ou arraste e solte) todos os PDFs desejados
|
||||
imgPrompt=Selecione a(s) Imagem(ns)
|
||||
genericSubmit=Enviar
|
||||
processTimeWarning=Aviso: esse processo pode levar até um minuto, dependendo do tamanho do arquivo
|
||||
pageOrderPrompt=Ordem de página personalizada (digite uma lista de números de página separada por vírgula):
|
||||
pageSelectionPrompt=Seleção de página personalizada (digite uma lista de números de página separada por vírgula 1,5,6 ou Funções como 2n+1) :
|
||||
pageOrderPrompt=Ordem de Página Personalizada (Digite uma lista de números de páginas, separadas por vírgula ou Funções como 2n+1):
|
||||
pageSelectionPrompt=Seleção de Página Personalizada (Digite uma lista de números de páginas, separadas por vírgula 1,5,6 ou Funções como 2n+1) :
|
||||
goToPage=Ir
|
||||
true=Verdadeiro
|
||||
false=Falso
|
||||
unknown=Desconhecido
|
||||
save=Salvar
|
||||
saveToBrowser=Salvar no navegador
|
||||
saveToBrowser=Salvar no Navegador
|
||||
close=Fechar
|
||||
filesSelected=arquivos selecionados
|
||||
noFavourites=Nenhum favorito adicionado
|
||||
filesSelected=Arquivos Selecionados
|
||||
noFavourites=Nenhum Favorito Adicionado
|
||||
downloadComplete=Download Completo
|
||||
bored=Entediado esperando?
|
||||
bored=Entediado Esperando?
|
||||
alphabet=Alfabeto
|
||||
downloadPdf=Baixar PDF
|
||||
text=Texto
|
||||
font=Fonte
|
||||
selectFillter=-- Selecione --
|
||||
pageNum=Número da página
|
||||
pageNum=Número da Página
|
||||
sizes.small=Pequeno
|
||||
sizes.medium=Médio
|
||||
sizes.large=Grande
|
||||
sizes.x-large=Extra grande
|
||||
error.pdfPassword=O documento PDF está protegido por senha e a senha não foi fornecida ou está incorreta
|
||||
delete=apagar
|
||||
delete=Apagar
|
||||
username=Usuário
|
||||
password=Senha
|
||||
welcome=Bem vindo
|
||||
welcome=Bem-vindo
|
||||
property=Propriedade
|
||||
black=Preto
|
||||
white=Branco
|
||||
@@ -46,7 +46,7 @@ red=Vermelho
|
||||
green=Verde
|
||||
blue=Azul
|
||||
custom=Personalizado...
|
||||
WorkInProgess=Em progesso, Talvez não funcione ou apresente erros, Por favor, reporte qualquer problema!
|
||||
WorkInProgess=Trabalho em progresso, Talvez não funcione ou apresente erros, Por favor, reporte qualquer problema!
|
||||
poweredBy=Distribuído por
|
||||
yes=Sim
|
||||
no=Não
|
||||
@@ -55,29 +55,30 @@ notAuthenticatedMessage=Usuário não autenticado.
|
||||
userNotFoundMessage=Usuário não encontrado.
|
||||
incorrectPasswordMessage=A senha atual está incorreta.
|
||||
usernameExistsMessage=Novo Usuário já existe.
|
||||
invalidUsernameMessage=Usuário inválido, nome de usuário só pode incluir letras, números e os seguintes caracteres especiais @._+- ou deve ser um email válido.
|
||||
invalidUsernameMessage=Usuário inválido, nome de usuário só pode incluir letras, números e os seguintes caracteres especiais @._+- ou deve ser um e-mail válido.
|
||||
invalidPasswordMessage=A senha não deve estar vazia e não deve conter espaços no início ou no final.
|
||||
confirmPasswordErrorMessage=Nova Senha e Confirmar Nova Senha devem ser iguais.
|
||||
deleteCurrentUserMessage=Não é possível apagar o usuário da sessão atual.
|
||||
deleteCurrentUserMessage=Não é possível apagar usuário conectado no momento.
|
||||
deleteUsernameExistsMessage=O usuário não existe e não pode ser apagado.
|
||||
downgradeCurrentUserMessage=Não é possível fazer downgrade da função do usuário atual
|
||||
disabledCurrentUserMessage=O usuário atual não pode ser desativado
|
||||
downgradeCurrentUserMessage=Não é possível fazer downgrade da função do usuário conectado no momento.
|
||||
disabledCurrentUserMessage=O usuário atual não pode ser desativado.
|
||||
downgradeCurrentUserLongMessage=Não é possível fazer downgrade da função do usuário atual. Portanto, o usuário atual não será mostrado.
|
||||
userAlreadyExistsOAuthMessage=O usuário já existe como um usuário OAuth2.
|
||||
userAlreadyExistsWebMessage=O usuário já existe como um usuário web.
|
||||
userAlreadyExistsWebMessage=O usuário já existe como um usuário Web.
|
||||
error=Erro
|
||||
oops=Ops!
|
||||
help=Ajuda
|
||||
goHomepage=Ir para a Página Inicial
|
||||
joinDiscord=Junte-se ao nosso servidor Discord
|
||||
seeDockerHub=Visite o Docker Hub
|
||||
visitGithub=Visite o repositŕio no GitHub
|
||||
visitGithub=Visite o repositório no GitHub
|
||||
donate=Doar
|
||||
color=Cor
|
||||
sponsor=Patrocine
|
||||
sponsor=Patrocinador
|
||||
info=Informações
|
||||
page=Page
|
||||
pages=Pages
|
||||
pro=Pro
|
||||
page=Página
|
||||
pages=Páginas
|
||||
|
||||
legal.privacy=Política de Privacidade
|
||||
legal.terms=Termos e Condições
|
||||
@@ -89,7 +90,7 @@ legal.impressum=Informações legais
|
||||
# Pipeline #
|
||||
###############
|
||||
pipeline.header=Menu do Pipeline (Beta)
|
||||
pipeline.uploadButton=Upload personalizado
|
||||
pipeline.uploadButton=Upload Personalizado
|
||||
pipeline.configureButton=Configurar
|
||||
pipeline.defaultOption=Personalizado
|
||||
pipeline.submitButton=Enviar
|
||||
@@ -102,16 +103,32 @@ pipeline.deletePrompt=Tem certeza de que deseja excluir o pipeline
|
||||
######################
|
||||
pipelineOptions.header=Configuração do Pipeline
|
||||
pipelineOptions.pipelineNameLabel=Nome do Pipeline
|
||||
pipelineOptions.saveSettings=Salvar configurações da operação
|
||||
pipelineOptions.saveSettings=Salvar Configurações da Operação
|
||||
pipelineOptions.pipelineNamePrompt=Insira o nome do pipeline aqui
|
||||
pipelineOptions.selectOperation=Selecione uma operação
|
||||
pipelineOptions.addOperationButton=Adicione uma operação
|
||||
pipelineOptions.selectOperation=Selecione uma Operação
|
||||
pipelineOptions.addOperationButton=Adicione uma Operação
|
||||
pipelineOptions.pipelineHeader=Pipeline:
|
||||
pipelineOptions.saveButton=Baixar
|
||||
pipelineOptions.validateButton=Validar
|
||||
|
||||
########################
|
||||
# ENTERPRISE EDITION #
|
||||
########################
|
||||
enterpriseEdition.button=Atualize para versão Pro
|
||||
enterpriseEdition.warning=Esse recurso só está disponivel para usuários da versão Pro.
|
||||
enterpriseEdition.yamlAdvert=Stirling PDF Pro suporta arquivos de configuração YAML e outros recursos SSO.
|
||||
enterpriseEdition.ssoAdvert=Procurando por mais recursos de controle de usuários? Veja Stirling PDF Pro
|
||||
|
||||
|
||||
#################
|
||||
# Analytics #
|
||||
#################
|
||||
analytics.title=Você quer melhorar Stirling PDF?
|
||||
analytics.paragraph1=Stirling PDF possui coleta de dados opcional para ajudar a melhorar o produto. Nós não rastreamos nenhuma informação pessoal ou conteúdo dos arquivos.
|
||||
analytics.paragraph2=Por favor considere habilitar coleta de dados para ajudar Stirling-PDF a crescer e nos ajudar a entender nossos usuários melhor.
|
||||
analytics.enable=Habilitar coleta de dados
|
||||
analytics.disable=Desabilitar coleta de dados
|
||||
analytics.settings=Você pode alterar as configurações de coleta de dados no arquivo config/settings.yml
|
||||
|
||||
#############
|
||||
# NAVBAR #
|
||||
@@ -128,6 +145,7 @@ navbar.sections.convertFrom=Converter de PDF
|
||||
navbar.sections.security=Assinatura & Segurança
|
||||
navbar.sections.advance=Avançado
|
||||
navbar.sections.edit=Visualizar & editar
|
||||
navbar.sections.popular=Popular
|
||||
|
||||
#############
|
||||
# SETTINGS #
|
||||
@@ -144,61 +162,61 @@ settings.zipThreshold=Compactar arquivos quando o número de arquivos baixados e
|
||||
settings.signOut=Sair
|
||||
settings.accountSettings=Configurações de conta
|
||||
settings.bored.help=Habilitar jogos secretos
|
||||
settings.cacheInputs.name=Salvar entradas de formulário
|
||||
settings.cacheInputs.name=Salvar entradas do formulário
|
||||
settings.cacheInputs.help=Habilitar para armazenar entradas usadas anteriormente para execuções futuras
|
||||
|
||||
changeCreds.title=Alterar credenciais
|
||||
changeCreds.header=Atualizar detalhes da sua conta
|
||||
changeCreds.title=Alterar Credenciais
|
||||
changeCreds.header=Atualizar Detalhes da Conta
|
||||
changeCreds.changePassword=Você está usando as credenciais padrões. Por favor, insira uma nova senha
|
||||
changeCreds.newUsername=Novo usuário
|
||||
changeCreds.oldPassword=Senha atual
|
||||
changeCreds.newPassword=Nova senha
|
||||
changeCreds.confirmNewPassword=Confirmar nova senha
|
||||
changeCreds.submit=Enviar alterações
|
||||
changeCreds.newUsername=Novo Usuário
|
||||
changeCreds.oldPassword=Senha Atual
|
||||
changeCreds.newPassword=Senha Nova
|
||||
changeCreds.confirmNewPassword=Confirme a Nova Senha
|
||||
changeCreds.submit=Enviar Alterações
|
||||
|
||||
|
||||
|
||||
account.title=Configurações de conta
|
||||
account.accountSettings=Configurações de conta
|
||||
account.adminSettings=Configurações de Administrador – visualizar e adicionar usuários
|
||||
account.userControlSettings=Configurações de controle de usuário
|
||||
account.changeUsername=Alterar usuário
|
||||
account.newUsername=Novo usuário
|
||||
account.password=Senha de confirmação
|
||||
account.oldPassword=Senha antiga
|
||||
account.newPassword=Senha nova
|
||||
account.changePassword=Alterar a senha
|
||||
account.confirmNewPassword=Confirme a nova senha
|
||||
account.title=Configurações de Conta
|
||||
account.accountSettings=Configurações de Conta
|
||||
account.adminSettings=Configurações de Administrador – Visualizar e Adicionar Usuários
|
||||
account.userControlSettings=Configurações de Controle de Usuário
|
||||
account.changeUsername=Alterar Usuário
|
||||
account.newUsername=Novo Usuário
|
||||
account.password=Senha de Confirmação
|
||||
account.oldPassword=Senha Antiga
|
||||
account.newPassword=Senha Nova
|
||||
account.changePassword=Alterar a Senha
|
||||
account.confirmNewPassword=Confirme a Nova Senha
|
||||
account.signOut=Sair
|
||||
account.yourApiKey=Sua chave de API
|
||||
account.syncTitle=Sincronize as configurações do navegador com a conta
|
||||
account.settingsCompare=Comparação de configurações:
|
||||
account.settingsCompare=Comparação de Configurações:
|
||||
account.property=Propriedade
|
||||
account.webBrowserSettings=Configuração do navegador Web
|
||||
account.syncToBrowser=Sincronizar conta -> Navegador
|
||||
account.syncToAccount=Sincronizar conta <- navegador
|
||||
account.syncToBrowser=Sincronizar Conta -> Navegador
|
||||
account.syncToAccount=Sincronizar Conta <- Navegador
|
||||
|
||||
|
||||
adminUserSettings.title=Configurações de controle de usuário
|
||||
adminUserSettings.header=Configurações de controle de usuário administrador
|
||||
adminUserSettings.header=Configurações de controle do usuário administrador
|
||||
adminUserSettings.admin=Administrador
|
||||
adminUserSettings.user=Usuário
|
||||
adminUserSettings.addUser=Adicionar novo usuário
|
||||
adminUserSettings.deleteUser=Apagar usuário
|
||||
adminUserSettings.confirmDeleteUser=O usuário deve ser apagado?
|
||||
adminUserSettings.confirmChangeUserStatus=O usuário deve ser desabilitado/habilitado?
|
||||
adminUserSettings.usernameInfo=Nome de usuário só pode incluir letras, números e os seguintes caracteres especiais @._+- ou deve ser um email válido.
|
||||
adminUserSettings.usernameInfo=Nome de usuário só pode incluir letras, números e os seguintes caracteres especiais @._+- ou deve ser um e-mail válido.
|
||||
adminUserSettings.roles=Funções
|
||||
adminUserSettings.role=Função
|
||||
adminUserSettings.actions=Ações
|
||||
adminUserSettings.apiUser=Usuário de API limitado
|
||||
adminUserSettings.extraApiUser=Usuário de API limitado adicional
|
||||
adminUserSettings.webOnlyUser=Usuário apenas web
|
||||
adminUserSettings.webOnlyUser=Usuário web apenas
|
||||
adminUserSettings.demoUser=Usuário demo (Sem configurações personalizadas)
|
||||
adminUserSettings.internalApiUser=Usuário interno de API
|
||||
adminUserSettings.forceChange=Forçar usuário a trocar a senha ao iniciar sessão
|
||||
adminUserSettings.submit=Salvar usuário
|
||||
adminUserSettings.changeUserRole=Alterar Função de Usuário
|
||||
adminUserSettings.submit=Salvar Usuário
|
||||
adminUserSettings.changeUserRole=Alterar Função do Usuário
|
||||
adminUserSettings.authenticated=Autenticado
|
||||
adminUserSettings.editOwnProfil=Editar próprio perfil
|
||||
adminUserSettings.enabledUser=usuário habilitado
|
||||
@@ -217,14 +235,16 @@ database.fileSize=Tamanho do arquivo
|
||||
database.deleteBackupFile=Apagar arquivo de backup
|
||||
database.importBackupFile=Importar arquivo de backup
|
||||
database.downloadBackupFile=Baixar arquivo de backup
|
||||
database.info_1=Ao importar dados, é crucial garantir a estrutura correta. Se você não tem certeza do que está fazendo procure auxílio de um profissional. Um erro na estrutura pode ocasionar em mau funcionamento da aplicação, incluindo a possibilidade de perda total da aplicação.
|
||||
database.info_1=Ao importar dados, é crucial garantir a estrutura correta. Se você não tem certeza do que está fazendo procure auxílio de um profissional. Um erro na estrutura pode ocasionar em mau funcionamento da aplicação, incluindo a impossibilidade da aplicação ser executada.
|
||||
database.info_2=O nome do arquivo não importa ao enviar. Ele será renomeado em seguida para seguir o formato backup_user_yyyyMMddHHmm.sql, garantindo uma convenção de nomes coerente.
|
||||
database.submit=Importar Backup
|
||||
database.importIntoDatabaseSuccessed=Importação para o banco de dados bem sucedida
|
||||
database.fileNotFound=Arquivo não encontrado
|
||||
database.fileNullOrEmpty=O arquivo não estar nulo ou vazio
|
||||
database.fileNullOrEmpty=O arquivo não pode estar nulo ou vazio
|
||||
database.failedImportFile=Falha ao importar arquivo
|
||||
|
||||
session.expired=Sua sessão expirou. Por gentileza atualize a página e tente novamente.
|
||||
|
||||
#############
|
||||
# HOME-PAGE #
|
||||
#############
|
||||
@@ -237,11 +257,11 @@ home.viewPdf.desc=Visualizar, anotar, adicionar texto ou imagens
|
||||
viewPdf.tags=visualizar,ler,anotar,texto,imagem
|
||||
|
||||
home.multiTool.title=Multiferramenta de PDF
|
||||
home.multiTool.desc=Mesclar, girar, reorganizar e remover páginas
|
||||
multiTool.tags=Multiferramenta,Múltiplas operações,Interface do Usuário,Clique e arraste,front-end,lado do cliente,interativo,intratável,movimento
|
||||
home.multiTool.desc=Mesclar, girar, reorganizar, dividir e remover páginas
|
||||
multiTool.tags=Multiferramenta, múltiplas operações, Interface do Usuário, Clique e arraste, front-end, lado do cliente, interativo, intratável, movimento, excluir, migrar, dividir
|
||||
|
||||
home.merge.title=Mesclar
|
||||
home.merge.desc=Mesclar facilmente vários PDFs em um só.
|
||||
home.merge.desc=Mescle facilmente vários PDFs em um só.
|
||||
merge.tags=mesclar,Operações de Página,Back-end,lado do servidor
|
||||
|
||||
home.split.title=Dividir
|
||||
@@ -249,7 +269,7 @@ home.split.desc=Dividir PDFs em vários documentos
|
||||
split.tags=Operações de Página,dividir,Múltiplas Páginas,cortar,lado do servidor
|
||||
|
||||
home.rotate.title=Girar
|
||||
home.rotate.desc=Girar facilmente seus PDFs.
|
||||
home.rotate.desc=Gire facilmente seus PDFs.
|
||||
rotate.tags=Lado do servidor
|
||||
|
||||
|
||||
@@ -267,11 +287,11 @@ pdfOrganiser.tags=duplex,par,ímpar,ordenar,mover
|
||||
|
||||
|
||||
home.addImage.title=Adicionar Imagem
|
||||
home.addImage.desc=Adicionar uma imagem em um local definido no PDF (Em desenvolvimento)
|
||||
home.addImage.desc=Adicionar uma imagem em um local definido no PDF
|
||||
addImage.tags=img,jpg,imagem,foto
|
||||
|
||||
home.watermark.title="Adicionar Marca d'água"
|
||||
home.watermark.desc="Adicionar uma marca d'água personalizada ao seu documento PDF."
|
||||
home.watermark.title=Adicionar Marca d'água
|
||||
home.watermark.desc=Adicionar uma marca d'água personalizada ao seu documento PDF.
|
||||
watermark.tags=Texto,repetindo,rótulo,próprio,direitos autorais,marca registrada,img,jpg,imagem,foto
|
||||
|
||||
home.permissions.title=Alterar Permissões
|
||||
@@ -283,13 +303,13 @@ home.removePages.title=Remover
|
||||
home.removePages.desc=Excluir as páginas indesejadas do seu documento PDF.
|
||||
removePages.tags=Remover páginas,excluir páginas
|
||||
|
||||
home.addPassword.title=Adicionar senha
|
||||
home.addPassword.title=Adicionar Senha
|
||||
home.addPassword.desc=Criptografar seu documento PDF com uma senha.
|
||||
addPassword.tags=seguro,segurança
|
||||
|
||||
home.removePassword.title=Remover Senha
|
||||
home.removePassword.desc=Remover a proteção por senha do seu documento PDF.
|
||||
removePassword.tags=seguro, Descriptografar, segurança, remover senha
|
||||
removePassword.tags=seguro, descriptografar, segurança, remover senha
|
||||
|
||||
home.compressPdfs.title=Comprimir
|
||||
home.compressPdfs.desc=Comprimir PDFs para reduzir o tamanho do arquivo.
|
||||
@@ -319,7 +339,7 @@ pdfToPDFA.tags=arquivo,longo prazo,padrão,conversão,armazenamento,preservaçã
|
||||
|
||||
home.PDFToWord.title=PDF para Word
|
||||
home.PDFToWord.desc=Converter PDF para formatos Word (DOC, DOCX e ODT)
|
||||
PDFToWord.tags=doc,docx,odt,word,transformação,formato,conversão,escritório,microsoft,arquivo doc
|
||||
PDFToWord.tags=doc,docx,odt,word,transformação,formato,conversão,escritório,microsoft,doc
|
||||
|
||||
home.PDFToPresentation.title=PDF para Apresentação
|
||||
home.PDFToPresentation.desc=Converter PDF para formatos de apresentação (PPT, PPTX e ODP)
|
||||
@@ -335,12 +355,12 @@ PDFToHTML.tags=conteúdo web,compatível com navegador
|
||||
|
||||
|
||||
home.PDFToXML.title=PDF para XML
|
||||
home.PDFToXML.desc=Converter PDF para o formato XML
|
||||
home.PDFToXML.desc=Converter PDF para formato XML
|
||||
PDFToXML.tags=extração-de-dados,conteúdo-estruturado,interoperabilidade,transformação,converter
|
||||
|
||||
home.ScannerImageSplit.title=Detectar/Dividir Fotos Digitalizadas
|
||||
home.ScannerImageSplit.desc=Divide várias fotos de dentro de uma imagem/PDF digitalizado
|
||||
ScannerImageSplit.tags=separar,detecção-automática,digitalizações,foto-múltipla,organizar
|
||||
home.ScannerImageSplit.desc=Divide várias fotos de dentro de uma imagem/PDF
|
||||
ScannerImageSplit.tags=separar,detecção-automática,digitalizações,fotos-múltiplas,organizar
|
||||
|
||||
home.sign.title=Assinar
|
||||
home.sign.desc=Adicionar assinatura ao PDF por desenho, texto ou imagem
|
||||
@@ -358,7 +378,7 @@ home.removeBlanks.title=Remover Páginas em Branco
|
||||
home.removeBlanks.desc=Detectar e remover páginas em branco de um documento
|
||||
removeBlanks.tags=limpeza,otimização,sem-conteúdo,organizar
|
||||
|
||||
home.removeAnnotations.title=Remover anotações
|
||||
home.removeAnnotations.title=Remover Anotações
|
||||
home.removeAnnotations.desc=Remove todos os comentários/anotações de um PDF
|
||||
removeAnnotations.tags=comentários,destaque,notas,marcação,remover
|
||||
|
||||
@@ -406,7 +426,7 @@ home.autoSplitPDF.title=Divisão Automática de Páginas
|
||||
home.autoSplitPDF.desc=Dividir automaticamente um PDF digitalizado com separador de páginas físicas QR Code
|
||||
autoSplitPDF.tags=baseado-em-QR,separar,segmento-de-digitalização,organizar
|
||||
|
||||
home.sanitizePdf.title=Sanitizar
|
||||
home.sanitizePdf.title=Higienizar
|
||||
home.sanitizePdf.desc=Remover scripts e outros elementos de arquivos PDF
|
||||
sanitizePdf.tags=limpar,seguro,protegido,remover-ameaças
|
||||
|
||||
@@ -448,7 +468,7 @@ home.autoRedact.desc=Ocultação automática (escurecimento) de texto em um PDF
|
||||
autoRedact.tags=Redigir,ocultar,escurecer,preto,marcador,oculto
|
||||
|
||||
home.tableExtraxt.title=PDF para CSV
|
||||
home.tableExtraxt.desc=Extrai tabelas de um PDF convertendo-o para CSV
|
||||
home.tableExtraxt.desc=Extrai tabelas de um PDF convertendo para CSV
|
||||
tableExtraxt.tags=CSV,extração de tabela,extrair,converter
|
||||
|
||||
|
||||
@@ -461,13 +481,13 @@ home.overlay-pdfs.title=Sobrepor PDFs
|
||||
home.overlay-pdfs.desc=Sobrepõe PDFs sobre outro PDF
|
||||
overlay-pdfs.tags=Sobreposição
|
||||
|
||||
home.split-by-sections.title=Dividir PDF por seções
|
||||
home.split-by-sections.title=Dividir PDF por Seções
|
||||
home.split-by-sections.desc=Divida cada página de um PDF em seções horizontais e verticais menores
|
||||
split-by-sections.tags=Seção Dividir, Dividir, Personalizar
|
||||
|
||||
home.AddStampRequest.title=Adicionar carimbo ao PDF
|
||||
home.AddStampRequest.title=Adicionar Carimbo ao PDF
|
||||
home.AddStampRequest.desc=Adicione texto ou carimbos de imagem em locais definidos
|
||||
AddStampRequest.tags="Carimbo,Adicionar imagem,centralizar imagem,Marca d'água,PDF,Incorporar,Personalizar"
|
||||
AddStampRequest.tags=Carimbo,Adicionar imagem,centralizar imagem,Marca d'água,PDF,Incorporar,Personalizar
|
||||
|
||||
|
||||
home.PDFToBook.title=PDF para Livro
|
||||
@@ -475,31 +495,36 @@ home.PDFToBook.desc=Converte PDF para formatos de livro/quadrinhos usando Calibr
|
||||
PDFToBook.tags=Livro,Quadrinhos,Calibre,Converter,manga,amazon,kindle,epub,mobi,azw3,docx,rtf,txt,html,lit,fb2,pdb,lrf
|
||||
|
||||
home.BookToPDF.title=Livro para PDF
|
||||
home.BookToPDF.desc=Converte formatos de livros/quadrinhos em PDF usando Calibre
|
||||
home.BookToPDF.desc=Converte formatos de livros/quadrinhos para PDF usando Calibre
|
||||
BookToPDF.tags=Livro,Quadrinhos,Calibre,Converter,manga,amazon,kindle,epub,mobi,azw3,docx,rtf,txt,html,lit,fb2,pdb,lrf
|
||||
|
||||
home.removeImagePdf.title=Remover imagem
|
||||
home.removeImagePdf.title=Remover Imagem
|
||||
home.removeImagePdf.desc=Remova a imagem do PDF para reduzir o tamanho do arquivo
|
||||
removeImagePdf.tags=Remover imagem,operações de página,back-end,lado do servidor
|
||||
|
||||
|
||||
home.splitPdfByChapters.title=Divide PDF por Capítulos
|
||||
home.splitPdfByChapters.desc=Divide um PDF em vários arquivos baseado na sua estrutura de capítulos.
|
||||
splitPdfByChapters.tags=dividir,capítulos,favoritos,organizar
|
||||
|
||||
#replace-invert-color
|
||||
replace-color.title=Replace-Invert-Color
|
||||
replace-color.header=Replace-Invert Color PDF
|
||||
home.replaceColorPdf.title=Replace and Invert Color
|
||||
home.replaceColorPdf.desc=Replace color for text and background in PDF and invert full color of pdf to reduce file size
|
||||
replaceColorPdf.tags=Replace Color,Page operations,Back end,server side
|
||||
replace-color.selectText.1=Replace or Invert color Options
|
||||
replace-color.selectText.2=Default(Default high contrast colors)
|
||||
replace-color.selectText.3=Custom(Customized colors)
|
||||
replace-color.selectText.4=Full-Invert(Invert all colors)
|
||||
replace-color.selectText.5=High contrast color options
|
||||
replace-color.selectText.6=white text on black background
|
||||
replace-color.selectText.7=Black text on white background
|
||||
replace-color.selectText.8=Yellow text on black background
|
||||
replace-color.selectText.9=Green text on black background
|
||||
replace-color.selectText.10=Choose text Color
|
||||
replace-color.selectText.11=Choose background Color
|
||||
replace-color.submit=Replace
|
||||
replace-color.title=Substituir-Inverter-Cor
|
||||
replace-color.header=Substitui-Inverter Cor PDF
|
||||
home.replaceColorPdf.title=Substitui e Inverte Cor
|
||||
home.replaceColorPdf.desc=Substitui cor de um texto e plano de fundo de um PDF e inverte a toda cor do PDF para reduzir o tamanho
|
||||
replaceColorPdf.tags=Substitui Cor, Operações na Página, back end, lado do servidor
|
||||
replace-color.selectText.1=Substituir ou inverter cor Opções
|
||||
replace-color.selectText.2=Padrão(Padrão cores de alto constraste)
|
||||
replace-color.selectText.3=Customizado(Cores customizadas)
|
||||
replace-color.selectText.4=Inversão Completa(Inverte todas cores)
|
||||
replace-color.selectText.5=Opções de cores de alto contraste
|
||||
replace-color.selectText.6=Texto branco em um plano de fundo preto
|
||||
replace-color.selectText.7=Texto preto em um plano de fundo branco
|
||||
replace-color.selectText.8=Texto amarelo em um plano de fundo preto
|
||||
replace-color.selectText.9=Texto verde em um plano de fundo preto
|
||||
replace-color.selectText.10=Escolha cor do texto
|
||||
replace-color.selectText.11=Escolha cor do plano de fundo
|
||||
replace-color.submit=Substituir
|
||||
|
||||
|
||||
|
||||
@@ -516,21 +541,24 @@ login.rememberme=Lembrar de mim
|
||||
login.invalid=Usuário ou senha inválidos.
|
||||
login.locked=Sua conta foi bloqueada.
|
||||
login.signinTitle=Por favor, inicie a sessão
|
||||
login.ssoSignIn=Iniciar sessão através de início de sessão único
|
||||
login.ssoSignIn=Iniciar sessão através de login único (SSO)
|
||||
login.oauth2AutoCreateDisabled=Auto-Criar Usuário OAUTH2 Desativado
|
||||
login.oauth2AdminBlockedUser=O registro ou login de usuários não registrados está atualmente bloqueado. Entre em contato com o administrador.
|
||||
login.oauth2RequestNotFound=Solicitação de autorização não encontrada
|
||||
login.oauth2InvalidUserInfoResponse=Resposta de informação de usuário inválida
|
||||
login.oauth2invalidRequest=Requisição inválida
|
||||
login.oauth2AccessDenied=Acesso negado
|
||||
login.oauth2InvalidTokenResponse=Resposta de token inválida
|
||||
login.oauth2InvalidIdToken=Id de token inválido
|
||||
login.oauth2invalidRequest=Requisição Inválida
|
||||
login.oauth2AccessDenied=Acesso Negado
|
||||
login.oauth2InvalidTokenResponse=Resposta de Token Inválida
|
||||
login.oauth2InvalidIdToken=Id de Token Inválido
|
||||
login.userIsDisabled=O usuário está desativado, o login está atualmente bloqueado com este nome de usuário. Entre em contato com o administrador.
|
||||
|
||||
login.alreadyLoggedIn=Você já está conectado
|
||||
login.alreadyLoggedIn2=aparelhos. Por favor saia dos aparelhos e tente novamente.
|
||||
login.toManySessions=Você tem muitas sessões ativas
|
||||
login.toManySessions2=Por favor saida dos aparelhos e tente novamente. Alternativamente você pode adquirir Stirling PDF Pro.
|
||||
|
||||
#auto-redact
|
||||
autoRedact.title=Redigir automaticamente
|
||||
autoRedact.header=Redigir automaticamente
|
||||
autoRedact.title=Redação Automática de Dados
|
||||
autoRedact.header=Redação Automática de Dados
|
||||
autoRedact.colorLabel=Cor
|
||||
autoRedact.textsToRedactLabel=Texto para redigir (separado por linha)
|
||||
autoRedact.textsToRedactPlaceholder=por exemplo: \nConfidencial \nSecreto
|
||||
@@ -616,22 +644,22 @@ AddStampRequest.fontSize=Tamanho da fonte/imagem
|
||||
AddStampRequest.rotation=Rotação
|
||||
AddStampRequest.opacity=Opacidade
|
||||
AddStampRequest.position=Posição
|
||||
AddStampRequest.overrideX=Substituir coordenada X
|
||||
AddStampRequest.overrideY=Substituir coordenada Y
|
||||
AddStampRequest.overrideX=Substituir Coordenada X
|
||||
AddStampRequest.overrideY=Substituir Coordenada Y
|
||||
AddStampRequest.customMargin=Margem personalizada
|
||||
AddStampRequest.customColor=Cor de texto personalizada
|
||||
AddStampRequest.submit=Enviar
|
||||
|
||||
|
||||
#sanitizePDF
|
||||
sanitizePDF.title=Sanitizar PDF
|
||||
sanitizePDF.header=Sanitizar um arquivo PDF
|
||||
sanitizePDF.title=Higienizar PDF
|
||||
sanitizePDF.header=Higienizar um arquivo PDF
|
||||
sanitizePDF.selectText.1=Remover ações de JavaScript
|
||||
sanitizePDF.selectText.2=Remover arquivos embutidos
|
||||
sanitizePDF.selectText.3=Remover metadados
|
||||
sanitizePDF.selectText.4=Remover links
|
||||
sanitizePDF.selectText.5=Remover fontes
|
||||
sanitizePDF.submit=Sanitizar PDF
|
||||
sanitizePDF.submit=Higienizar PDF
|
||||
|
||||
|
||||
#addPageNumbers
|
||||
@@ -711,9 +739,9 @@ certSign.title=Assinatura com Certificado
|
||||
certSign.header=Assine um PDF com o seu certificado (Em desenvolvimento)
|
||||
certSign.selectPDF=Selecione um arquivo PDF para assinatura:
|
||||
certSign.jksNote=Nota: Se o seu tipo de certificado não estiver listado abaixo, converta-o em um arquivo Java Keystore (.jks) usando a ferramenta de linha de comando keytool. Em seguida, escolha a opção de arquivo .jks abaixo.
|
||||
certSign.selectKey="Selecione o seu arquivo de chave privada (formato PKCS#8, pode ser .pem ou .der):"
|
||||
certSign.selectKey=Selecione o seu arquivo de chave privada (formato PKCS#8, pode ser .pem ou .der):
|
||||
certSign.selectCert=Selecione o seu arquivo de certificado (formato X.509, pode ser .pem ou .der):
|
||||
certSign.selectP12="Selecione o seu arquivo de armazenamento de chave PKCS#12 (.p12 ou .pfx) (opcional, se fornecido, deve conter a sua chave privada e certificado):"
|
||||
certSign.selectP12=Selecione o seu arquivo de armazenamento de chave PKCS#12 (.p12 ou .pfx) (opcional, se fornecido, deve conter a sua chave privada e certificado):
|
||||
certSign.selectJKS=Selecione seu arquivo Java Keystore (.jks ou .keystore):
|
||||
certSign.certType=Tipo de Certificado
|
||||
certSign.password=Digite a senha do seu armazenamento de chave ou chave privada (se aplicável):
|
||||
@@ -725,7 +753,7 @@ certSign.submit=Assinar PDF
|
||||
|
||||
|
||||
#removeCertSign
|
||||
removeCertSign.title=Remover assinatura com Certificado
|
||||
removeCertSign.title=Remover Assinatura do Certificado
|
||||
removeCertSign.header=Remover o certificado digital do PDF
|
||||
removeCertSign.selectPDF=Selecione um arquivo PDF:
|
||||
removeCertSign.submit=Remover assinatura
|
||||
@@ -737,13 +765,13 @@ removeBlanks.header=Remover páginas em branco
|
||||
removeBlanks.threshold=Limite de brancura de pixel:
|
||||
removeBlanks.thresholdDesc=Limite para determinar o quão branco um pixel branco deve ser para ser classificado como 'Branco'. 0 = Preto, 255 branco puro.
|
||||
removeBlanks.whitePercent=Porcentagem de Branco (%):
|
||||
removeBlanks.whitePercentDesc=Porcentagem de páginas que devem ter pixels “brancos” para serem removidas
|
||||
removeBlanks.whitePercentDesc=Porcentagem da página que devem ter pixels “brancos” para serem removidas
|
||||
removeBlanks.submit=Remover páginas em branco
|
||||
|
||||
|
||||
#removeAnnotations
|
||||
removeAnnotations.title=Remover anotações
|
||||
removeAnnotations.header=Remover anotações
|
||||
removeAnnotations.title=Remover Anotações
|
||||
removeAnnotations.header=Remover Anotações
|
||||
removeAnnotations.submit=Remover
|
||||
|
||||
|
||||
@@ -809,26 +837,26 @@ ScannerImageSplit.info=Python não está instalado. É necessário para executar
|
||||
#OCR
|
||||
ocr.title=OCR / Limpeza de Digitalização
|
||||
ocr.header=OCR / Limpeza de Digitalização (Reconhecimento Óptico de Caracteres)
|
||||
ocr.selectText.1=Selecione os idiomas a serem detectados no PDF (os listados são os atualmente detectados):
|
||||
ocr.selectText.2=Criar um arquivo de texto contendo o texto OCR ao lado do PDF com OCR
|
||||
ocr.selectText.1=Selecione os idiomas a serem detectados no PDF (os listados são os atualmente instalados):
|
||||
ocr.selectText.2=Criar um arquivo de texto contendo o texto OCR junto do PDF com OCR
|
||||
ocr.selectText.3=Páginas corretamente digitalizadas em um ângulo inclinado, gire-as de volta à posição original
|
||||
ocr.selectText.4=Limpar a página para reduzir a probabilidade de o OCR encontrar texto no ruído de fundo (sem alteração na saída)
|
||||
ocr.selectText.5=Limpar a página para reduzir a probabilidade de o OCR encontrar texto no ruído de fundo, mantendo a limpeza na saída.
|
||||
ocr.selectText.6=Ignorar páginas com texto interativo, processar apenas as páginas de OCR que são imagens
|
||||
ocr.selectText.6=Ignorar páginas com texto interativo, processar por OCR apenas as páginas com imagens
|
||||
ocr.selectText.7=Forçar OCR, executar OCR em todas as páginas, removendo todos os elementos de texto originais
|
||||
ocr.selectText.8=Normal (gerará um erro se o PDF já contiver texto)
|
||||
ocr.selectText.9=Configurações adicionais
|
||||
ocr.selectText.9=Configurações Adicionais
|
||||
ocr.selectText.10=Modo OCR
|
||||
ocr.selectText.11=Remover imagens após o OCR (remove TODAS as imagens, útil apenas como parte do processo de conversão)
|
||||
ocr.selectText.12=Tipo de renderização (avançado)
|
||||
ocr.selectText.12=Tipo de Renderização (avançado)
|
||||
ocr.help=Por favor, leia a documentação sobre como usar isso para outros idiomas e/ou fora do ambiente Docker
|
||||
ocr.credit=Este serviço usa OCRmyPDF e Tesseract para OCR.
|
||||
ocr.submit=Processar PDF com OCR
|
||||
|
||||
|
||||
#extractImages
|
||||
extractImages.title=Extrair imagens
|
||||
extractImages.header=Extrair imagens
|
||||
extractImages.title=Extrair Imagens
|
||||
extractImages.header=Extrair Imagens
|
||||
extractImages.selectText=Selecione o formato de imagem para converter as imagens extraídas
|
||||
extractImages.allowDuplicates=Salvar imagens duplicadas
|
||||
extractImages.submit=Extrair
|
||||
@@ -856,7 +884,7 @@ compress.submit=Comprimir
|
||||
|
||||
|
||||
#Add image
|
||||
addImage.title=Adicionar imagem
|
||||
addImage.title=Adicionar Imagem
|
||||
addImage.header=Adicionar imagem ao PDF
|
||||
addImage.everyPage=Para cada página?
|
||||
addImage.upload=Enviar imagem
|
||||
@@ -865,7 +893,7 @@ addImage.submit=Adicionar imagem
|
||||
|
||||
#merge
|
||||
merge.title=Mesclar
|
||||
merge.header=Mesclar Vários PDFs (2+)
|
||||
merge.header=Mesclar vários PDFs (2+)
|
||||
merge.sortByName=Classificar por nome
|
||||
merge.sortByDate=Classificar por data
|
||||
merge.removeCertSign=Remover a assinatura digital do arquivo mesclado?
|
||||
@@ -879,7 +907,7 @@ pdfOrganiser.submit=Reorganizar páginas
|
||||
pdfOrganiser.mode=Modo
|
||||
pdfOrganiser.mode.1=Ordem de página personalizada
|
||||
pdfOrganiser.mode.2=Ordem inversa
|
||||
pdfOrganiser.mode.3=Classificação Duplex
|
||||
pdfOrganiser.mode.3=Classificação duplex
|
||||
pdfOrganiser.mode.4=Classificação de livreto
|
||||
pdfOrganiser.mode.5=Classificação de livreto com ponto lateral
|
||||
pdfOrganiser.mode.6=Divisão ímpar-par
|
||||
@@ -944,7 +972,7 @@ imageToPDF.selectText.5=Converter em PDFs separados
|
||||
|
||||
|
||||
#pdfToImage
|
||||
pdfToImage.title=PDF para imagem
|
||||
pdfToImage.title=PDF para Imagem
|
||||
pdfToImage.header=Converter PDF para imagem
|
||||
pdfToImage.selectText=Formato de imagem
|
||||
pdfToImage.singleOrMultiple=Tipo de resultado de imagem
|
||||
@@ -953,7 +981,7 @@ pdfToImage.multi=Várias imagens, uma imagem por página
|
||||
pdfToImage.colorType=Tipo de cor
|
||||
pdfToImage.color=Colorida
|
||||
pdfToImage.grey=Escala de Cinza
|
||||
pdfToImage.blackwhite=Preto e Branco (pode perder de dados!)
|
||||
pdfToImage.blackwhite=Preto e Branco (pode perder informações!)
|
||||
pdfToImage.submit=Converter
|
||||
pdfToImage.info=Python não está instalado. Necessário para conversão WebP.
|
||||
|
||||
@@ -964,7 +992,7 @@ addPassword.header=Adicionar Senha (Criptografar)
|
||||
addPassword.selectText.1=Selecione o PDF para Criptografar
|
||||
addPassword.selectText.2=Senha
|
||||
addPassword.selectText.3=Tamanho da Chave de Criptografia
|
||||
addPassword.selectText.4=Valores mais altos são mais seguros, mas valores mais baixos são mais compatíveis.
|
||||
addPassword.selectText.4=Valores mais altos são mais seguros, mas valores mais baixos são melhores para compatibilidade.
|
||||
addPassword.selectText.5=Permissões a serem definidas (recomendado para uso junto com a senha do proprietário)
|
||||
addPassword.selectText.6=Impedir a montagem do documento
|
||||
addPassword.selectText.7=Impedir a extração de conteúdo
|
||||
@@ -981,26 +1009,26 @@ addPassword.submit=Criptografar
|
||||
|
||||
|
||||
#watermark
|
||||
watermark.title="Adicionar marca d'água"
|
||||
watermark.header="Adicionar marca d'água"
|
||||
watermark.selectText.1="Selecione PDF para adicionar a marca d'água:"
|
||||
watermark.selectText.2="Texto da marca d'água:"
|
||||
watermark.title=Adicionar marca d'água
|
||||
watermark.header=Adicionar marca d'água
|
||||
watermark.selectText.1=Selecione PDF para adicionar a marca d'água:
|
||||
watermark.selectText.2=Texto da marca d'água:
|
||||
watermark.selectText.3=Tamanho da fonte:
|
||||
watermark.selectText.4=Rotação (0-360):
|
||||
watermark.selectText.5="widthSpacer (Espaço entre cada marca d'água horizontalmente):"
|
||||
watermark.selectText.6="heightSpacer (Espaço entre cada marca d'água verticalmente):"
|
||||
watermark.selectText.5=widthSpacer (Espaço entre cada marca d'água horizontalmente):
|
||||
watermark.selectText.6=heightSpacer (Espaço entre cada marca d'água verticalmente):
|
||||
watermark.selectText.7=Opacidade (0% - 100%):
|
||||
watermark.selectText.8="Tipo de marca d'água:"
|
||||
watermark.selectText.9="Imagem da marca d'água:"
|
||||
watermark.selectText.8=Tipo de marca d'água:
|
||||
watermark.selectText.9=Imagem da marca d'água:
|
||||
watermark.selectText.10=Converter PDF em imagem PDF
|
||||
watermark.submit="Adicionar marca d'água"
|
||||
watermark.submit=Adicionar marca d'água
|
||||
watermark.type.1=Texto
|
||||
watermark.type.2=Imagem
|
||||
|
||||
|
||||
#Change permissions
|
||||
permissions.title=Alterar permissões
|
||||
permissions.header=Alterar permissões
|
||||
permissions.title=Alterar Permissões
|
||||
permissions.header=Alterar Permissões
|
||||
permissions.warning=Aviso: para que essas permissões sejam imutáveis, é recomendável defini-las com uma senha através da página Adicionar Senha
|
||||
permissions.selectText.1=Selecione o PDF para alterar as permissões
|
||||
permissions.selectText.2=Permissões para definir
|
||||
@@ -1016,7 +1044,7 @@ permissions.submit=Alterar
|
||||
|
||||
|
||||
#remove password
|
||||
removePassword.title=Remover senha
|
||||
removePassword.title=Remover Senha
|
||||
removePassword.header=Remover senha (descriptografar)
|
||||
removePassword.selectText.1=Selecione o PDF para descriptografar
|
||||
removePassword.selectText.2=Senha
|
||||
@@ -1024,7 +1052,7 @@ removePassword.submit=Remover
|
||||
|
||||
|
||||
#changeMetadata
|
||||
changeMetadata.title=Alterar metadados
|
||||
changeMetadata.title=Alterar Metadados
|
||||
changeMetadata.header=Alterar metadados
|
||||
changeMetadata.selectText.1=Edite as variáveis que deseja alterar
|
||||
changeMetadata.selectText.2=Excluir todos os metadados
|
||||
@@ -1108,7 +1136,7 @@ split-by-size-or-count.submit=Enviar
|
||||
|
||||
|
||||
#overlay-pdfs
|
||||
overlay-pdfs.header=Sobrepor arquivos PDF
|
||||
overlay-pdfs.header=Sobrepor Arquivos PDF
|
||||
overlay-pdfs.baseFile.label=Selecione o arquivo PDF base
|
||||
overlay-pdfs.overlayFiles.label=Selecione os arquivos PDF para sobreposição
|
||||
overlay-pdfs.mode.label=Selecione o modo de sobreposição
|
||||
@@ -1126,7 +1154,7 @@ overlay-pdfs.submit=Enviar
|
||||
#split-by-sections
|
||||
split-by-sections.title=Dividir PDF por seções
|
||||
split-by-sections.header=Divida o PDF em seções
|
||||
split-by-sections.horizontal.label=Divisões horizontais
|
||||
split-by-sections.horizontal.label=Divisões Horizontais
|
||||
split-by-sections.vertical.label=Divisões Verticais
|
||||
split-by-sections.horizontal.placeholder=Insira o número de divisões horizontais
|
||||
split-by-sections.vertical.placeholder=Insira o número de divisões verticais
|
||||
@@ -1144,8 +1172,8 @@ printFile.submit=Imprimir
|
||||
|
||||
#licenses
|
||||
licenses.nav=Licenças
|
||||
licenses.title=Licenças de terceiros
|
||||
licenses.header=Licenças de terceiros
|
||||
licenses.title=Licenças de Terceiros
|
||||
licenses.header=Licenças de Terceiros
|
||||
licenses.module=Módulo
|
||||
licenses.version=Versão
|
||||
licenses.license=Licença
|
||||
@@ -1154,8 +1182,10 @@ licenses.license=Licença
|
||||
survey.nav=Pesquisa
|
||||
survey.title=Pesquisa Stirling-PDF
|
||||
survey.description=Stirling-PDF não tem rastreamento, então queremos ouvir nossos usuários para melhorar o Stirling-PDF!
|
||||
survey.changes=Stirling-PDF mudou desde o a última pesquisa! Para saber mais acesse nosso post no blog:
|
||||
survey.changes2=Com essas mudanças estamos implementando suporte empresarial pago e financeamento
|
||||
survey.please=Por favor, considere responder à nossa pesquisa!
|
||||
survey.disabled=(O pop-up da pesquisa será desativado nas atualizações seguintes, mas estará disponível no final da página)
|
||||
survey.disabled=(O pop-up da pesquisa será desativado nas atualizações seguintes, mas estará disponível no rodapé da página)
|
||||
survey.button=Responda a pesquisa
|
||||
survey.dontShowAgain=Não mostre novamente
|
||||
|
||||
@@ -1163,11 +1193,11 @@ survey.dontShowAgain=Não mostre novamente
|
||||
#error
|
||||
error.sorry=Desculpe pelo problema!
|
||||
error.needHelp=Precisa de ajuda / Encontrou um problema?
|
||||
error.contactTip=Se você ainda estiver com problemas, não hesite em entrar em contato conosco para obter ajuda. Você pode enviar um ticket em nossa página GitHub ou entrar em contato conosco através do Discord:
|
||||
error.contactTip=Se você ainda estiver com problemas, não hesite em entrar em contato conosco para obter ajuda. Você pode enviar um tíquete em nossa página GitHub ou entrar em contato conosco através do Discord:
|
||||
error.404.head=404 - Página não encontrada | Ops, tropeçamos no código!
|
||||
error.404.1=Não conseguimos encontrar a página que você está procurando.
|
||||
error.404.2=Algo deu errado
|
||||
error.github=Submeter um ticket no GitHub
|
||||
error.github=Submeter um tíquete no GitHub
|
||||
error.showStack=Mostrar rastreamento de pilha
|
||||
error.copyStack=Copiar rastreamento de pilha
|
||||
error.githubSubmit=GitHub - Submeter um tíquete
|
||||
@@ -1175,7 +1205,21 @@ error.discordSubmit=Discord - Submeter um post de suporte
|
||||
|
||||
|
||||
#remove-image
|
||||
removeImage.title=Remover imagem
|
||||
removeImage.title=Remover Imagem
|
||||
removeImage.header=Remover imagem
|
||||
removeImage.removeImage=Remover imagem
|
||||
removeImage.submit=Remover imagem
|
||||
|
||||
|
||||
splitByChapters.title=Dividir PDF por Capítulos
|
||||
splitByChapters.header=Dividir PDF por Capítulos
|
||||
splitByChapters.bookmarkLevel=Nível de Marcador
|
||||
splitByChapters.includeMetadata=Incluir Metadados
|
||||
splitByChapters.allowDuplicates=Permitir Cópias
|
||||
splitByChapters.desc.1=Essa ferramenta divide um arquivo PDF em vários arquivos PDFs baseado na estrutura de cápitulos.
|
||||
splitByChapters.desc.2=Nível de Marcador: Escolha o nível de marcador a ser usado para divisão (0 para o primeiro nível, 1 para o segundo nível, etc).
|
||||
splitByChapters.desc.3=Incluir Metadados: Se marcado, os metadados do PDF original serão incluidos em cada divisão do PDF.
|
||||
splitByChapters.desc.4=Permitir Cópias: Se marcado, habilita vários marcadores na mesma página para criar PDFs separados.
|
||||
splitByChapters.submit=Dividir PDF
|
||||
|
||||
|
||||
|
||||
@@ -76,6 +76,7 @@ donate=Donate
|
||||
color=Color
|
||||
sponsor=Sponsor
|
||||
info=Info
|
||||
pro=Pro
|
||||
page=Page
|
||||
pages=Pages
|
||||
|
||||
@@ -110,8 +111,24 @@ pipelineOptions.pipelineHeader=Pipeline:
|
||||
pipelineOptions.saveButton=Descarregar
|
||||
pipelineOptions.validateButton=Validar
|
||||
|
||||
########################
|
||||
# ENTERPRISE EDITION #
|
||||
########################
|
||||
enterpriseEdition.button=Upgrade to Pro
|
||||
enterpriseEdition.warning=This feature is only available to Pro users.
|
||||
enterpriseEdition.yamlAdvert=Stirling PDF Pro supports YAML configuration files and other SSO features.
|
||||
enterpriseEdition.ssoAdvert=Looking for more user management features? Check out Stirling PDF Pro
|
||||
|
||||
|
||||
#################
|
||||
# Analytics #
|
||||
#################
|
||||
analytics.title=Do you want make Stirling PDF better?
|
||||
analytics.paragraph1=Stirling PDF has opt in analytics to help us improve the product. We do not track any personal information or file contents.
|
||||
analytics.paragraph2=Please consider enabling analytics to help Stirling-PDF grow and to allow us to understand our users better.
|
||||
analytics.enable=Enable analytics
|
||||
analytics.disable=Disable analytics
|
||||
analytics.settings=You can change the settings for analytics in the config/settings.yml file
|
||||
|
||||
#############
|
||||
# NAVBAR #
|
||||
@@ -128,6 +145,7 @@ navbar.sections.convertFrom=Convert from PDF
|
||||
navbar.sections.security=Sign & Security
|
||||
navbar.sections.advance=Advanced
|
||||
navbar.sections.edit=View & Edit
|
||||
navbar.sections.popular=Popular
|
||||
|
||||
#############
|
||||
# SETTINGS #
|
||||
@@ -225,6 +243,8 @@ database.fileNotFound=File not Found
|
||||
database.fileNullOrEmpty=File must not be null or empty
|
||||
database.failedImportFile=Failed Import File
|
||||
|
||||
session.expired=Your session has expired. Please refresh the page and try again.
|
||||
|
||||
#############
|
||||
# HOME-PAGE #
|
||||
#############
|
||||
@@ -482,6 +502,11 @@ home.removeImagePdf.title=Remove image
|
||||
home.removeImagePdf.desc=Remove image from PDF to reduce file size
|
||||
removeImagePdf.tags=Remove Image,Page operations,Back end,server side
|
||||
|
||||
|
||||
home.splitPdfByChapters.title=Split PDF by Chapters
|
||||
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
||||
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
||||
|
||||
#replace-invert-color
|
||||
replace-color.title=Replace-Invert-Color
|
||||
replace-color.header=Replace-Invert Color PDF
|
||||
@@ -526,7 +551,10 @@ login.oauth2AccessDenied=Access Denied
|
||||
login.oauth2InvalidTokenResponse=Invalid Token Response
|
||||
login.oauth2InvalidIdToken=Invalid Id Token
|
||||
login.userIsDisabled=User is deactivated, login is currently blocked with this username. Please contact the administrator.
|
||||
|
||||
login.alreadyLoggedIn=You are already logged in to
|
||||
login.alreadyLoggedIn2=devices. Please log out of the devices and try again.
|
||||
login.toManySessions=You have too many active sessions
|
||||
login.toManySessions2=Please log out of the devices and try again. Alternatively, you can upgrade to Stirling PDF Pro.
|
||||
|
||||
#auto-redact
|
||||
autoRedact.title=Edição Automática
|
||||
@@ -1154,6 +1182,8 @@ licenses.license=Licença
|
||||
survey.nav=Survey
|
||||
survey.title=Stirling-PDF Survey
|
||||
survey.description=Stirling-PDF has no tracking so we want to hear from our users to improve Stirling-PDF!
|
||||
survey.changes=Stirling-PDF has changed since the last survey! To find out more please check our blog post here:
|
||||
survey.changes2=With these changes we are getting paid business support and funding
|
||||
survey.please=Please consider taking our survey!
|
||||
survey.disabled=(Survey popup will be disabled in following updates but available at foot of page)
|
||||
survey.button=Take Survey
|
||||
@@ -1179,3 +1209,17 @@ removeImage.title=Remove image
|
||||
removeImage.header=Remove image
|
||||
removeImage.removeImage=Remove image
|
||||
removeImage.submit=Remove image
|
||||
|
||||
|
||||
splitByChapters.title=Split PDF by Chapters
|
||||
splitByChapters.header=Split PDF by Chapters
|
||||
splitByChapters.bookmarkLevel=Bookmark Level
|
||||
splitByChapters.includeMetadata=Include Metadata
|
||||
splitByChapters.allowDuplicates=Allow Duplicates
|
||||
splitByChapters.desc.1=This tool splits a PDF file into multiple PDFs based on its chapter structure.
|
||||
splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for splitting (0 for top-level, 1 for second-level, etc.).
|
||||
splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF.
|
||||
splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs.
|
||||
splitByChapters.submit=Split PDF
|
||||
|
||||
|
||||
|
||||
@@ -76,6 +76,7 @@ donate=Donează
|
||||
color=Culoare
|
||||
sponsor=Sponsor
|
||||
info=Informații
|
||||
pro=Pro
|
||||
page=Page
|
||||
pages=Pages
|
||||
|
||||
@@ -110,8 +111,24 @@ pipelineOptions.pipelineHeader=Pipeline:
|
||||
pipelineOptions.saveButton=Descarcă
|
||||
pipelineOptions.validateButton=Validează
|
||||
|
||||
########################
|
||||
# ENTERPRISE EDITION #
|
||||
########################
|
||||
enterpriseEdition.button=Upgrade to Pro
|
||||
enterpriseEdition.warning=This feature is only available to Pro users.
|
||||
enterpriseEdition.yamlAdvert=Stirling PDF Pro supports YAML configuration files and other SSO features.
|
||||
enterpriseEdition.ssoAdvert=Looking for more user management features? Check out Stirling PDF Pro
|
||||
|
||||
|
||||
#################
|
||||
# Analytics #
|
||||
#################
|
||||
analytics.title=Do you want make Stirling PDF better?
|
||||
analytics.paragraph1=Stirling PDF has opt in analytics to help us improve the product. We do not track any personal information or file contents.
|
||||
analytics.paragraph2=Please consider enabling analytics to help Stirling-PDF grow and to allow us to understand our users better.
|
||||
analytics.enable=Enable analytics
|
||||
analytics.disable=Disable analytics
|
||||
analytics.settings=You can change the settings for analytics in the config/settings.yml file
|
||||
|
||||
#############
|
||||
# NAVBAR #
|
||||
@@ -128,6 +145,7 @@ navbar.sections.convertFrom=Convertește din PDF
|
||||
navbar.sections.security=Semnează & Securitate
|
||||
navbar.sections.advance=Avansat
|
||||
navbar.sections.edit=Vizualizează & Editează
|
||||
navbar.sections.popular=Popular
|
||||
|
||||
#############
|
||||
# SETTINGS #
|
||||
@@ -225,6 +243,8 @@ database.fileNotFound=Fișierul nu a fost găsit
|
||||
database.fileNullOrEmpty=Fișierul nu trebuie să fie nul sau gol
|
||||
database.failedImportFile=Importul Fișierului a Eșuat
|
||||
|
||||
session.expired=Your session has expired. Please refresh the page and try again.
|
||||
|
||||
#############
|
||||
# HOME-PAGE #
|
||||
#############
|
||||
@@ -482,6 +502,11 @@ home.removeImagePdf.title=Elimină imagine
|
||||
home.removeImagePdf.desc=Elimină imaginea din PDF pentru a reduce dimensiunea fișierului
|
||||
removeImagePdf.tags=Elimină Imagine,Operații pagină,Back end,server side
|
||||
|
||||
|
||||
home.splitPdfByChapters.title=Split PDF by Chapters
|
||||
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
||||
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
||||
|
||||
#replace-invert-color
|
||||
replace-color.title=Replace-Invert-Color
|
||||
replace-color.header=Replace-Invert Color PDF
|
||||
@@ -526,7 +551,10 @@ login.oauth2AccessDenied=Acces Refuzat
|
||||
login.oauth2InvalidTokenResponse=Răspuns Invalid la Token
|
||||
login.oauth2InvalidIdToken=Token de Id Invalid
|
||||
login.userIsDisabled=Utilizatorul este dezactivat, conectarea este în prezent blocată cu acest nume de utilizator. Te rugăm să contactezi administratorul.
|
||||
|
||||
login.alreadyLoggedIn=You are already logged in to
|
||||
login.alreadyLoggedIn2=devices. Please log out of the devices and try again.
|
||||
login.toManySessions=You have too many active sessions
|
||||
login.toManySessions2=Please log out of the devices and try again. Alternatively, you can upgrade to Stirling PDF Pro.
|
||||
|
||||
#auto-redact
|
||||
autoRedact.title=Redactare Automată
|
||||
@@ -1154,6 +1182,8 @@ licenses.license=Licență
|
||||
survey.nav=Sondaj
|
||||
survey.title=Sondaj Stirling-PDF
|
||||
survey.description=Stirling-PDF nu are urmărire, așa că vrem să auzim de la utilizatorii noștri pentru a îmbunătăți Stirling-PDF!
|
||||
survey.changes=Stirling-PDF has changed since the last survey! To find out more please check our blog post here:
|
||||
survey.changes2=With these changes we are getting paid business support and funding
|
||||
survey.please=Te rugăm să iei în considerare completarea sondajului nostru!
|
||||
survey.disabled=(Fereastra pop-up a sondajului va fi dezactivată în următoarele actualizări, dar va fi disponibilă în subsolul paginii)
|
||||
survey.button=Completează Sondajul
|
||||
@@ -1179,3 +1209,17 @@ removeImage.title=Elimină imagine
|
||||
removeImage.header=Elimină imagine
|
||||
removeImage.removeImage=Elimină imagine
|
||||
removeImage.submit=Elimină imagine
|
||||
|
||||
|
||||
splitByChapters.title=Split PDF by Chapters
|
||||
splitByChapters.header=Split PDF by Chapters
|
||||
splitByChapters.bookmarkLevel=Bookmark Level
|
||||
splitByChapters.includeMetadata=Include Metadata
|
||||
splitByChapters.allowDuplicates=Allow Duplicates
|
||||
splitByChapters.desc.1=This tool splits a PDF file into multiple PDFs based on its chapter structure.
|
||||
splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for splitting (0 for top-level, 1 for second-level, etc.).
|
||||
splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF.
|
||||
splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs.
|
||||
splitByChapters.submit=Split PDF
|
||||
|
||||
|
||||
|
||||
@@ -76,6 +76,7 @@ donate=Пожертвовать
|
||||
color=Цвет
|
||||
sponsor=Спонсор
|
||||
info=Info
|
||||
pro=Pro
|
||||
page=Page
|
||||
pages=Pages
|
||||
|
||||
@@ -110,8 +111,24 @@ pipelineOptions.pipelineHeader=Конвейер:
|
||||
pipelineOptions.saveButton=Скачать
|
||||
pipelineOptions.validateButton=Проверить
|
||||
|
||||
########################
|
||||
# ENTERPRISE EDITION #
|
||||
########################
|
||||
enterpriseEdition.button=Upgrade to Pro
|
||||
enterpriseEdition.warning=This feature is only available to Pro users.
|
||||
enterpriseEdition.yamlAdvert=Stirling PDF Pro supports YAML configuration files and other SSO features.
|
||||
enterpriseEdition.ssoAdvert=Looking for more user management features? Check out Stirling PDF Pro
|
||||
|
||||
|
||||
#################
|
||||
# Analytics #
|
||||
#################
|
||||
analytics.title=Do you want make Stirling PDF better?
|
||||
analytics.paragraph1=Stirling PDF has opt in analytics to help us improve the product. We do not track any personal information or file contents.
|
||||
analytics.paragraph2=Please consider enabling analytics to help Stirling-PDF grow and to allow us to understand our users better.
|
||||
analytics.enable=Enable analytics
|
||||
analytics.disable=Disable analytics
|
||||
analytics.settings=You can change the settings for analytics in the config/settings.yml file
|
||||
|
||||
#############
|
||||
# NAVBAR #
|
||||
@@ -128,6 +145,7 @@ navbar.sections.convertFrom=Convert from PDF
|
||||
navbar.sections.security=Sign & Security
|
||||
navbar.sections.advance=Advanced
|
||||
navbar.sections.edit=View & Edit
|
||||
navbar.sections.popular=Popular
|
||||
|
||||
#############
|
||||
# SETTINGS #
|
||||
@@ -225,6 +243,8 @@ database.fileNotFound=File not Found
|
||||
database.fileNullOrEmpty=File must not be null or empty
|
||||
database.failedImportFile=Failed Import File
|
||||
|
||||
session.expired=Your session has expired. Please refresh the page and try again.
|
||||
|
||||
#############
|
||||
# HOME-PAGE #
|
||||
#############
|
||||
@@ -482,6 +502,11 @@ home.removeImagePdf.title=Remove image
|
||||
home.removeImagePdf.desc=Remove image from PDF to reduce file size
|
||||
removeImagePdf.tags=Remove Image,Page operations,Back end,server side
|
||||
|
||||
|
||||
home.splitPdfByChapters.title=Split PDF by Chapters
|
||||
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
||||
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
||||
|
||||
#replace-invert-color
|
||||
replace-color.title=Replace-Invert-Color
|
||||
replace-color.header=Replace-Invert Color PDF
|
||||
@@ -526,7 +551,10 @@ login.oauth2AccessDenied=Access Denied
|
||||
login.oauth2InvalidTokenResponse=Invalid Token Response
|
||||
login.oauth2InvalidIdToken=Invalid Id Token
|
||||
login.userIsDisabled=User is deactivated, login is currently blocked with this username. Please contact the administrator.
|
||||
|
||||
login.alreadyLoggedIn=You are already logged in to
|
||||
login.alreadyLoggedIn2=devices. Please log out of the devices and try again.
|
||||
login.toManySessions=You have too many active sessions
|
||||
login.toManySessions2=Please log out of the devices and try again. Alternatively, you can upgrade to Stirling PDF Pro.
|
||||
|
||||
#auto-redact
|
||||
autoRedact.title=Автоматическое редактирование
|
||||
@@ -1154,6 +1182,8 @@ licenses.license=Лицензия
|
||||
survey.nav=Survey
|
||||
survey.title=Stirling-PDF Survey
|
||||
survey.description=Stirling-PDF has no tracking so we want to hear from our users to improve Stirling-PDF!
|
||||
survey.changes=Stirling-PDF has changed since the last survey! To find out more please check our blog post here:
|
||||
survey.changes2=With these changes we are getting paid business support and funding
|
||||
survey.please=Please consider taking our survey!
|
||||
survey.disabled=(Survey popup will be disabled in following updates but available at foot of page)
|
||||
survey.button=Take Survey
|
||||
@@ -1179,3 +1209,17 @@ removeImage.title=Remove image
|
||||
removeImage.header=Remove image
|
||||
removeImage.removeImage=Remove image
|
||||
removeImage.submit=Remove image
|
||||
|
||||
|
||||
splitByChapters.title=Split PDF by Chapters
|
||||
splitByChapters.header=Split PDF by Chapters
|
||||
splitByChapters.bookmarkLevel=Bookmark Level
|
||||
splitByChapters.includeMetadata=Include Metadata
|
||||
splitByChapters.allowDuplicates=Allow Duplicates
|
||||
splitByChapters.desc.1=This tool splits a PDF file into multiple PDFs based on its chapter structure.
|
||||
splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for splitting (0 for top-level, 1 for second-level, etc.).
|
||||
splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF.
|
||||
splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs.
|
||||
splitByChapters.submit=Split PDF
|
||||
|
||||
|
||||
|
||||
@@ -76,6 +76,7 @@ donate=Darovať
|
||||
color=Farba
|
||||
sponsor=Sponzorovať
|
||||
info=Info
|
||||
pro=Pro
|
||||
page=Page
|
||||
pages=Pages
|
||||
|
||||
@@ -110,8 +111,24 @@ pipelineOptions.pipelineHeader=Pipeline:
|
||||
pipelineOptions.saveButton=Stiahnuť
|
||||
pipelineOptions.validateButton=Overiť
|
||||
|
||||
########################
|
||||
# ENTERPRISE EDITION #
|
||||
########################
|
||||
enterpriseEdition.button=Upgrade to Pro
|
||||
enterpriseEdition.warning=This feature is only available to Pro users.
|
||||
enterpriseEdition.yamlAdvert=Stirling PDF Pro supports YAML configuration files and other SSO features.
|
||||
enterpriseEdition.ssoAdvert=Looking for more user management features? Check out Stirling PDF Pro
|
||||
|
||||
|
||||
#################
|
||||
# Analytics #
|
||||
#################
|
||||
analytics.title=Do you want make Stirling PDF better?
|
||||
analytics.paragraph1=Stirling PDF has opt in analytics to help us improve the product. We do not track any personal information or file contents.
|
||||
analytics.paragraph2=Please consider enabling analytics to help Stirling-PDF grow and to allow us to understand our users better.
|
||||
analytics.enable=Enable analytics
|
||||
analytics.disable=Disable analytics
|
||||
analytics.settings=You can change the settings for analytics in the config/settings.yml file
|
||||
|
||||
#############
|
||||
# NAVBAR #
|
||||
@@ -128,6 +145,7 @@ navbar.sections.convertFrom=Convert from PDF
|
||||
navbar.sections.security=Sign & Security
|
||||
navbar.sections.advance=Advanced
|
||||
navbar.sections.edit=View & Edit
|
||||
navbar.sections.popular=Popular
|
||||
|
||||
#############
|
||||
# SETTINGS #
|
||||
@@ -225,6 +243,8 @@ database.fileNotFound=File not Found
|
||||
database.fileNullOrEmpty=File must not be null or empty
|
||||
database.failedImportFile=Failed Import File
|
||||
|
||||
session.expired=Your session has expired. Please refresh the page and try again.
|
||||
|
||||
#############
|
||||
# HOME-PAGE #
|
||||
#############
|
||||
@@ -482,6 +502,11 @@ home.removeImagePdf.title=Remove image
|
||||
home.removeImagePdf.desc=Remove image from PDF to reduce file size
|
||||
removeImagePdf.tags=Remove Image,Page operations,Back end,server side
|
||||
|
||||
|
||||
home.splitPdfByChapters.title=Split PDF by Chapters
|
||||
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
||||
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
||||
|
||||
#replace-invert-color
|
||||
replace-color.title=Replace-Invert-Color
|
||||
replace-color.header=Replace-Invert Color PDF
|
||||
@@ -526,7 +551,10 @@ login.oauth2AccessDenied=Access Denied
|
||||
login.oauth2InvalidTokenResponse=Invalid Token Response
|
||||
login.oauth2InvalidIdToken=Invalid Id Token
|
||||
login.userIsDisabled=User is deactivated, login is currently blocked with this username. Please contact the administrator.
|
||||
|
||||
login.alreadyLoggedIn=You are already logged in to
|
||||
login.alreadyLoggedIn2=devices. Please log out of the devices and try again.
|
||||
login.toManySessions=You have too many active sessions
|
||||
login.toManySessions2=Please log out of the devices and try again. Alternatively, you can upgrade to Stirling PDF Pro.
|
||||
|
||||
#auto-redact
|
||||
autoRedact.title=Automatické redigovanie
|
||||
@@ -1154,6 +1182,8 @@ licenses.license=Licencia
|
||||
survey.nav=Survey
|
||||
survey.title=Stirling-PDF Survey
|
||||
survey.description=Stirling-PDF has no tracking so we want to hear from our users to improve Stirling-PDF!
|
||||
survey.changes=Stirling-PDF has changed since the last survey! To find out more please check our blog post here:
|
||||
survey.changes2=With these changes we are getting paid business support and funding
|
||||
survey.please=Please consider taking our survey!
|
||||
survey.disabled=(Survey popup will be disabled in following updates but available at foot of page)
|
||||
survey.button=Take Survey
|
||||
@@ -1179,3 +1209,17 @@ removeImage.title=Remove image
|
||||
removeImage.header=Remove image
|
||||
removeImage.removeImage=Remove image
|
||||
removeImage.submit=Remove image
|
||||
|
||||
|
||||
splitByChapters.title=Split PDF by Chapters
|
||||
splitByChapters.header=Split PDF by Chapters
|
||||
splitByChapters.bookmarkLevel=Bookmark Level
|
||||
splitByChapters.includeMetadata=Include Metadata
|
||||
splitByChapters.allowDuplicates=Allow Duplicates
|
||||
splitByChapters.desc.1=This tool splits a PDF file into multiple PDFs based on its chapter structure.
|
||||
splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for splitting (0 for top-level, 1 for second-level, etc.).
|
||||
splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF.
|
||||
splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs.
|
||||
splitByChapters.submit=Split PDF
|
||||
|
||||
|
||||
|
||||
@@ -76,6 +76,7 @@ donate=Donate
|
||||
color=Color
|
||||
sponsor=Sponsor
|
||||
info=Info
|
||||
pro=Pro
|
||||
page=Page
|
||||
pages=Pages
|
||||
|
||||
@@ -110,8 +111,24 @@ pipelineOptions.pipelineHeader=Pipeline:
|
||||
pipelineOptions.saveButton=Preuzmi
|
||||
pipelineOptions.validateButton=Proveri
|
||||
|
||||
########################
|
||||
# ENTERPRISE EDITION #
|
||||
########################
|
||||
enterpriseEdition.button=Upgrade to Pro
|
||||
enterpriseEdition.warning=This feature is only available to Pro users.
|
||||
enterpriseEdition.yamlAdvert=Stirling PDF Pro supports YAML configuration files and other SSO features.
|
||||
enterpriseEdition.ssoAdvert=Looking for more user management features? Check out Stirling PDF Pro
|
||||
|
||||
|
||||
#################
|
||||
# Analytics #
|
||||
#################
|
||||
analytics.title=Do you want make Stirling PDF better?
|
||||
analytics.paragraph1=Stirling PDF has opt in analytics to help us improve the product. We do not track any personal information or file contents.
|
||||
analytics.paragraph2=Please consider enabling analytics to help Stirling-PDF grow and to allow us to understand our users better.
|
||||
analytics.enable=Enable analytics
|
||||
analytics.disable=Disable analytics
|
||||
analytics.settings=You can change the settings for analytics in the config/settings.yml file
|
||||
|
||||
#############
|
||||
# NAVBAR #
|
||||
@@ -128,6 +145,7 @@ navbar.sections.convertFrom=Convert from PDF
|
||||
navbar.sections.security=Sign & Security
|
||||
navbar.sections.advance=Advanced
|
||||
navbar.sections.edit=View & Edit
|
||||
navbar.sections.popular=Popular
|
||||
|
||||
#############
|
||||
# SETTINGS #
|
||||
@@ -225,6 +243,8 @@ database.fileNotFound=File not Found
|
||||
database.fileNullOrEmpty=File must not be null or empty
|
||||
database.failedImportFile=Failed Import File
|
||||
|
||||
session.expired=Your session has expired. Please refresh the page and try again.
|
||||
|
||||
#############
|
||||
# HOME-PAGE #
|
||||
#############
|
||||
@@ -482,6 +502,11 @@ home.removeImagePdf.title=Remove image
|
||||
home.removeImagePdf.desc=Remove image from PDF to reduce file size
|
||||
removeImagePdf.tags=Remove Image,Page operations,Back end,server side
|
||||
|
||||
|
||||
home.splitPdfByChapters.title=Split PDF by Chapters
|
||||
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
||||
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
||||
|
||||
#replace-invert-color
|
||||
replace-color.title=Replace-Invert-Color
|
||||
replace-color.header=Replace-Invert Color PDF
|
||||
@@ -526,7 +551,10 @@ login.oauth2AccessDenied=Access Denied
|
||||
login.oauth2InvalidTokenResponse=Invalid Token Response
|
||||
login.oauth2InvalidIdToken=Invalid Id Token
|
||||
login.userIsDisabled=User is deactivated, login is currently blocked with this username. Please contact the administrator.
|
||||
|
||||
login.alreadyLoggedIn=You are already logged in to
|
||||
login.alreadyLoggedIn2=devices. Please log out of the devices and try again.
|
||||
login.toManySessions=You have too many active sessions
|
||||
login.toManySessions2=Please log out of the devices and try again. Alternatively, you can upgrade to Stirling PDF Pro.
|
||||
|
||||
#auto-redact
|
||||
autoRedact.title=Auto Cenzura
|
||||
@@ -1154,6 +1182,8 @@ licenses.license=License
|
||||
survey.nav=Survey
|
||||
survey.title=Stirling-PDF Survey
|
||||
survey.description=Stirling-PDF has no tracking so we want to hear from our users to improve Stirling-PDF!
|
||||
survey.changes=Stirling-PDF has changed since the last survey! To find out more please check our blog post here:
|
||||
survey.changes2=With these changes we are getting paid business support and funding
|
||||
survey.please=Please consider taking our survey!
|
||||
survey.disabled=(Survey popup will be disabled in following updates but available at foot of page)
|
||||
survey.button=Take Survey
|
||||
@@ -1179,3 +1209,17 @@ removeImage.title=Remove image
|
||||
removeImage.header=Remove image
|
||||
removeImage.removeImage=Remove image
|
||||
removeImage.submit=Remove image
|
||||
|
||||
|
||||
splitByChapters.title=Split PDF by Chapters
|
||||
splitByChapters.header=Split PDF by Chapters
|
||||
splitByChapters.bookmarkLevel=Bookmark Level
|
||||
splitByChapters.includeMetadata=Include Metadata
|
||||
splitByChapters.allowDuplicates=Allow Duplicates
|
||||
splitByChapters.desc.1=This tool splits a PDF file into multiple PDFs based on its chapter structure.
|
||||
splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for splitting (0 for top-level, 1 for second-level, etc.).
|
||||
splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF.
|
||||
splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs.
|
||||
splitByChapters.submit=Split PDF
|
||||
|
||||
|
||||
|
||||
@@ -76,6 +76,7 @@ donate=Donera
|
||||
color=Färg
|
||||
sponsor=Sponsor
|
||||
info=Info
|
||||
pro=Pro
|
||||
page=Page
|
||||
pages=Pages
|
||||
|
||||
@@ -110,8 +111,24 @@ pipelineOptions.pipelineHeader=Pipeline:
|
||||
pipelineOptions.saveButton=Ladda ner
|
||||
pipelineOptions.validateButton=Validera
|
||||
|
||||
########################
|
||||
# ENTERPRISE EDITION #
|
||||
########################
|
||||
enterpriseEdition.button=Upgrade to Pro
|
||||
enterpriseEdition.warning=This feature is only available to Pro users.
|
||||
enterpriseEdition.yamlAdvert=Stirling PDF Pro supports YAML configuration files and other SSO features.
|
||||
enterpriseEdition.ssoAdvert=Looking for more user management features? Check out Stirling PDF Pro
|
||||
|
||||
|
||||
#################
|
||||
# Analytics #
|
||||
#################
|
||||
analytics.title=Do you want make Stirling PDF better?
|
||||
analytics.paragraph1=Stirling PDF has opt in analytics to help us improve the product. We do not track any personal information or file contents.
|
||||
analytics.paragraph2=Please consider enabling analytics to help Stirling-PDF grow and to allow us to understand our users better.
|
||||
analytics.enable=Enable analytics
|
||||
analytics.disable=Disable analytics
|
||||
analytics.settings=You can change the settings for analytics in the config/settings.yml file
|
||||
|
||||
#############
|
||||
# NAVBAR #
|
||||
@@ -128,6 +145,7 @@ navbar.sections.convertFrom=Konvertera från PDF
|
||||
navbar.sections.security=Signera & Säkerhet
|
||||
navbar.sections.advance=Avancerat
|
||||
navbar.sections.edit=Visa & Redigera
|
||||
navbar.sections.popular=Popular
|
||||
|
||||
#############
|
||||
# SETTINGS #
|
||||
@@ -225,6 +243,8 @@ database.fileNotFound=Filen hittades inte
|
||||
database.fileNullOrEmpty=Filen får inte vara null eller tom
|
||||
database.failedImportFile=Misslyckades med att importera fil
|
||||
|
||||
session.expired=Your session has expired. Please refresh the page and try again.
|
||||
|
||||
#############
|
||||
# HOME-PAGE #
|
||||
#############
|
||||
@@ -482,6 +502,11 @@ home.removeImagePdf.title=Ta bort bild
|
||||
home.removeImagePdf.desc=Ta bort bild från PDF för att minska filstorlek
|
||||
removeImagePdf.tags=Ta bort bild,Sidoperationer,Backend,serversida
|
||||
|
||||
|
||||
home.splitPdfByChapters.title=Split PDF by Chapters
|
||||
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
||||
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
||||
|
||||
#replace-invert-color
|
||||
replace-color.title=Replace-Invert-Color
|
||||
replace-color.header=Replace-Invert Color PDF
|
||||
@@ -526,7 +551,10 @@ login.oauth2AccessDenied=Åtkomst nekad
|
||||
login.oauth2InvalidTokenResponse=Ogiltigt token-svar
|
||||
login.oauth2InvalidIdToken=Ogiltigt Id-token
|
||||
login.userIsDisabled=Användaren är inaktiverad, inloggning är för närvarande blockerad med detta användarnamn. Kontakta administratören.
|
||||
|
||||
login.alreadyLoggedIn=You are already logged in to
|
||||
login.alreadyLoggedIn2=devices. Please log out of the devices and try again.
|
||||
login.toManySessions=You have too many active sessions
|
||||
login.toManySessions2=Please log out of the devices and try again. Alternatively, you can upgrade to Stirling PDF Pro.
|
||||
|
||||
#auto-redact
|
||||
autoRedact.title=Auto-redigera
|
||||
@@ -1154,6 +1182,8 @@ licenses.license=Licens
|
||||
survey.nav=Undersökning
|
||||
survey.title=Stirling-PDF-undersökning
|
||||
survey.description=Stirling-PDF har ingen spårning så vi vill höra från våra användare för att förbättra Stirling-PDF!
|
||||
survey.changes=Stirling-PDF has changed since the last survey! To find out more please check our blog post here:
|
||||
survey.changes2=With these changes we are getting paid business support and funding
|
||||
survey.please=Vänligen överväg att delta i vår undersökning!
|
||||
survey.disabled=(Undersökningspopup kommer att inaktiveras i kommande uppdateringar men finns tillgänglig längst ner på sidan)
|
||||
survey.button=Delta i undersökningen
|
||||
@@ -1179,3 +1209,17 @@ removeImage.title=Ta bort bild
|
||||
removeImage.header=Ta bort bild
|
||||
removeImage.removeImage=Ta bort bild
|
||||
removeImage.submit=Ta bort bild
|
||||
|
||||
|
||||
splitByChapters.title=Split PDF by Chapters
|
||||
splitByChapters.header=Split PDF by Chapters
|
||||
splitByChapters.bookmarkLevel=Bookmark Level
|
||||
splitByChapters.includeMetadata=Include Metadata
|
||||
splitByChapters.allowDuplicates=Allow Duplicates
|
||||
splitByChapters.desc.1=This tool splits a PDF file into multiple PDFs based on its chapter structure.
|
||||
splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for splitting (0 for top-level, 1 for second-level, etc.).
|
||||
splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF.
|
||||
splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs.
|
||||
splitByChapters.submit=Split PDF
|
||||
|
||||
|
||||
|
||||
@@ -76,6 +76,7 @@ donate=บริจาค
|
||||
color=สี
|
||||
sponsor=ผู้สนับสนุน
|
||||
info=ข้อมูล
|
||||
pro=Pro
|
||||
page=Page
|
||||
pages=Pages
|
||||
|
||||
@@ -110,8 +111,24 @@ pipelineOptions.pipelineHeader=Pipeline:
|
||||
pipelineOptions.saveButton=ดาวน์โหลด
|
||||
pipelineOptions.validateButton=ตรวจสอบความถูกต้อง
|
||||
|
||||
########################
|
||||
# ENTERPRISE EDITION #
|
||||
########################
|
||||
enterpriseEdition.button=Upgrade to Pro
|
||||
enterpriseEdition.warning=This feature is only available to Pro users.
|
||||
enterpriseEdition.yamlAdvert=Stirling PDF Pro supports YAML configuration files and other SSO features.
|
||||
enterpriseEdition.ssoAdvert=Looking for more user management features? Check out Stirling PDF Pro
|
||||
|
||||
|
||||
#################
|
||||
# Analytics #
|
||||
#################
|
||||
analytics.title=Do you want make Stirling PDF better?
|
||||
analytics.paragraph1=Stirling PDF has opt in analytics to help us improve the product. We do not track any personal information or file contents.
|
||||
analytics.paragraph2=Please consider enabling analytics to help Stirling-PDF grow and to allow us to understand our users better.
|
||||
analytics.enable=Enable analytics
|
||||
analytics.disable=Disable analytics
|
||||
analytics.settings=You can change the settings for analytics in the config/settings.yml file
|
||||
|
||||
#############
|
||||
# NAVBAR #
|
||||
@@ -128,6 +145,7 @@ navbar.sections.convertFrom=แปลงจาก PDF
|
||||
navbar.sections.security=ลงนามและความปลอดภัย
|
||||
navbar.sections.advance=ขั้นสูง
|
||||
navbar.sections.edit=ดูและแก้ไข
|
||||
navbar.sections.popular=Popular
|
||||
|
||||
#############
|
||||
# SETTINGS #
|
||||
@@ -225,6 +243,8 @@ database.fileNotFound=ไม่พบไฟล์
|
||||
database.fileNullOrEmpty=ไฟล์ต้องไม่ว่างเปล่าหรือไม่มีข้อมูล
|
||||
database.failedImportFile=การนำเข้าไฟล์ล้มเหลว
|
||||
|
||||
session.expired=Your session has expired. Please refresh the page and try again.
|
||||
|
||||
#############
|
||||
# HOME-PAGE #
|
||||
#############
|
||||
@@ -482,6 +502,11 @@ home.removeImagePdf.title=Remove image
|
||||
home.removeImagePdf.desc=Remove image from PDF to reduce file size
|
||||
removeImagePdf.tags=Remove Image,Page operations,Back end,server side
|
||||
|
||||
|
||||
home.splitPdfByChapters.title=Split PDF by Chapters
|
||||
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
||||
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
||||
|
||||
#replace-invert-color
|
||||
replace-color.title=Replace-Invert-Color
|
||||
replace-color.header=Replace-Invert Color PDF
|
||||
@@ -526,7 +551,10 @@ login.oauth2AccessDenied=การเข้าถึงถูกปฏิเส
|
||||
login.oauth2InvalidTokenResponse=การตอบกลับโทเค็นไม่ถูกต้อง
|
||||
login.oauth2InvalidIdToken=โทเค็น Id ไม่ถูกต้อง
|
||||
login.userIsDisabled=User is deactivated, login is currently blocked with this username. Please contact the administrator.
|
||||
|
||||
login.alreadyLoggedIn=You are already logged in to
|
||||
login.alreadyLoggedIn2=devices. Please log out of the devices and try again.
|
||||
login.toManySessions=You have too many active sessions
|
||||
login.toManySessions2=Please log out of the devices and try again. Alternatively, you can upgrade to Stirling PDF Pro.
|
||||
|
||||
#auto-redact
|
||||
autoRedact.title=ซ่อนข้อมูลอัตโนมัติ
|
||||
@@ -1154,6 +1182,8 @@ licenses.license=ใบอนุญาต
|
||||
survey.nav=สำรวจ
|
||||
survey.title=สำรวจ Stirling-PDF
|
||||
survey.description=Stirling-PDF ไม่มีการติดตาม ดังนั้นเราต้องการฟังความคิดเห็นจากผู้ใช้เพื่อปรับปรุง Stirling-PDF!
|
||||
survey.changes=Stirling-PDF has changed since the last survey! To find out more please check our blog post here:
|
||||
survey.changes2=With these changes we are getting paid business support and funding
|
||||
survey.please=กรุณาพิจารณาการสำรวจของเรา!
|
||||
survey.disabled=(ป๊อปอัปการสำรวจจะถูกปิดใช้งานในการอัปเดตต่อไปนี้ แต่สามารถใช้ได้ที่ส่วนท้ายของหน้า)
|
||||
survey.button=เริ่มสำรวจ
|
||||
@@ -1179,3 +1209,17 @@ removeImage.title=Remove image
|
||||
removeImage.header=Remove image
|
||||
removeImage.removeImage=Remove image
|
||||
removeImage.submit=Remove image
|
||||
|
||||
|
||||
splitByChapters.title=Split PDF by Chapters
|
||||
splitByChapters.header=Split PDF by Chapters
|
||||
splitByChapters.bookmarkLevel=Bookmark Level
|
||||
splitByChapters.includeMetadata=Include Metadata
|
||||
splitByChapters.allowDuplicates=Allow Duplicates
|
||||
splitByChapters.desc.1=This tool splits a PDF file into multiple PDFs based on its chapter structure.
|
||||
splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for splitting (0 for top-level, 1 for second-level, etc.).
|
||||
splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF.
|
||||
splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs.
|
||||
splitByChapters.submit=Split PDF
|
||||
|
||||
|
||||
|
||||
@@ -76,6 +76,7 @@ donate=Bağış Yapın
|
||||
color=Renk
|
||||
sponsor=Bağış
|
||||
info=Bilgi
|
||||
pro=Pro
|
||||
page=Page
|
||||
pages=Pages
|
||||
|
||||
@@ -110,8 +111,24 @@ pipelineOptions.pipelineHeader=Çoklu İşlemler:
|
||||
pipelineOptions.saveButton=İndir
|
||||
pipelineOptions.validateButton=Doğrula
|
||||
|
||||
########################
|
||||
# ENTERPRISE EDITION #
|
||||
########################
|
||||
enterpriseEdition.button=Upgrade to Pro
|
||||
enterpriseEdition.warning=This feature is only available to Pro users.
|
||||
enterpriseEdition.yamlAdvert=Stirling PDF Pro supports YAML configuration files and other SSO features.
|
||||
enterpriseEdition.ssoAdvert=Looking for more user management features? Check out Stirling PDF Pro
|
||||
|
||||
|
||||
#################
|
||||
# Analytics #
|
||||
#################
|
||||
analytics.title=Do you want make Stirling PDF better?
|
||||
analytics.paragraph1=Stirling PDF has opt in analytics to help us improve the product. We do not track any personal information or file contents.
|
||||
analytics.paragraph2=Please consider enabling analytics to help Stirling-PDF grow and to allow us to understand our users better.
|
||||
analytics.enable=Enable analytics
|
||||
analytics.disable=Disable analytics
|
||||
analytics.settings=You can change the settings for analytics in the config/settings.yml file
|
||||
|
||||
#############
|
||||
# NAVBAR #
|
||||
@@ -128,6 +145,7 @@ navbar.sections.convertFrom=PDF'den dönüştür
|
||||
navbar.sections.security=Oturum ve Güvenlik
|
||||
navbar.sections.advance=Gelişmiş
|
||||
navbar.sections.edit=Görüntüle ve Düzenle
|
||||
navbar.sections.popular=Popular
|
||||
|
||||
#############
|
||||
# SETTINGS #
|
||||
@@ -225,6 +243,8 @@ database.fileNotFound=Dosya bulunamadı
|
||||
database.fileNullOrEmpty=Dosya yok veya boş olmamalıdır
|
||||
database.failedImportFile=Dosya İçe Aktarılamadı
|
||||
|
||||
session.expired=Your session has expired. Please refresh the page and try again.
|
||||
|
||||
#############
|
||||
# HOME-PAGE #
|
||||
#############
|
||||
@@ -482,6 +502,11 @@ home.removeImagePdf.title=Resmi kaldır
|
||||
home.removeImagePdf.desc=Dosya boyutunu küçültmek için PDF'den resmi kaldırın
|
||||
removeImagePdf.tags=Resmi Kaldır,Sayfa İşlemleri,Arka uç,sunucu tarafı
|
||||
|
||||
|
||||
home.splitPdfByChapters.title=Split PDF by Chapters
|
||||
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
||||
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
||||
|
||||
#replace-invert-color
|
||||
replace-color.title=Replace-Invert-Color
|
||||
replace-color.header=Replace-Invert Color PDF
|
||||
@@ -526,7 +551,10 @@ login.oauth2AccessDenied=Erişim Reddedildi
|
||||
login.oauth2InvalidTokenResponse=Geçersiz Belirteç Yanıtı
|
||||
login.oauth2InvalidIdToken=Geçersiz Kimlik Belirteci
|
||||
login.userIsDisabled=Kullanıcı devre dışı bırakıldı, şu anda bu kullanıcı adıyla giriş engellendi. Lütfen yöneticiyle iletişime geçin.
|
||||
|
||||
login.alreadyLoggedIn=You are already logged in to
|
||||
login.alreadyLoggedIn2=devices. Please log out of the devices and try again.
|
||||
login.toManySessions=You have too many active sessions
|
||||
login.toManySessions2=Please log out of the devices and try again. Alternatively, you can upgrade to Stirling PDF Pro.
|
||||
|
||||
#auto-redact
|
||||
autoRedact.title=Otomatik Karartma
|
||||
@@ -1154,6 +1182,8 @@ licenses.license=Lisans
|
||||
survey.nav=Anket
|
||||
survey.title=Stirling-PDF Anketi
|
||||
survey.description=Stirling-PDF'te izleme yok, bu yüzden Stirling-PDF'i iyileştirmek için kullanıcılarımızdan geri bildirim almak istiyoruz!
|
||||
survey.changes=Stirling-PDF has changed since the last survey! To find out more please check our blog post here:
|
||||
survey.changes2=With these changes we are getting paid business support and funding
|
||||
survey.please=Lütfen anketimize katılmayı düşünün!
|
||||
survey.disabled=(Anket açılır penceresi sonraki güncellemelerde devre dışı bırakılacak ancak sayfanın alt kısmında yer alacaktır)
|
||||
survey.button=Ankete Katıl
|
||||
@@ -1179,3 +1209,17 @@ removeImage.title=Resmi kaldır
|
||||
removeImage.header=Resmi kaldır
|
||||
removeImage.removeImage=Resmi kaldır
|
||||
removeImage.submit=Resmi kaldır
|
||||
|
||||
|
||||
splitByChapters.title=Split PDF by Chapters
|
||||
splitByChapters.header=Split PDF by Chapters
|
||||
splitByChapters.bookmarkLevel=Bookmark Level
|
||||
splitByChapters.includeMetadata=Include Metadata
|
||||
splitByChapters.allowDuplicates=Allow Duplicates
|
||||
splitByChapters.desc.1=This tool splits a PDF file into multiple PDFs based on its chapter structure.
|
||||
splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for splitting (0 for top-level, 1 for second-level, etc.).
|
||||
splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF.
|
||||
splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs.
|
||||
splitByChapters.submit=Split PDF
|
||||
|
||||
|
||||
|
||||
@@ -76,6 +76,7 @@ donate=Задонатити
|
||||
color=Колір
|
||||
sponsor=Спонсор
|
||||
info=Інформація
|
||||
pro=Pro
|
||||
page=Page
|
||||
pages=Pages
|
||||
|
||||
@@ -110,8 +111,24 @@ pipelineOptions.pipelineHeader=Конвеєр:
|
||||
pipelineOptions.saveButton=Завантажити
|
||||
pipelineOptions.validateButton=Перевірити
|
||||
|
||||
########################
|
||||
# ENTERPRISE EDITION #
|
||||
########################
|
||||
enterpriseEdition.button=Upgrade to Pro
|
||||
enterpriseEdition.warning=This feature is only available to Pro users.
|
||||
enterpriseEdition.yamlAdvert=Stirling PDF Pro supports YAML configuration files and other SSO features.
|
||||
enterpriseEdition.ssoAdvert=Looking for more user management features? Check out Stirling PDF Pro
|
||||
|
||||
|
||||
#################
|
||||
# Analytics #
|
||||
#################
|
||||
analytics.title=Do you want make Stirling PDF better?
|
||||
analytics.paragraph1=Stirling PDF has opt in analytics to help us improve the product. We do not track any personal information or file contents.
|
||||
analytics.paragraph2=Please consider enabling analytics to help Stirling-PDF grow and to allow us to understand our users better.
|
||||
analytics.enable=Enable analytics
|
||||
analytics.disable=Disable analytics
|
||||
analytics.settings=You can change the settings for analytics in the config/settings.yml file
|
||||
|
||||
#############
|
||||
# NAVBAR #
|
||||
@@ -128,6 +145,7 @@ navbar.sections.convertFrom=Конвертувати з PDF
|
||||
navbar.sections.security=Підпис та Безпека
|
||||
navbar.sections.advance=Додаткове
|
||||
navbar.sections.edit=Перегляд та Редагування
|
||||
navbar.sections.popular=Popular
|
||||
|
||||
#############
|
||||
# SETTINGS #
|
||||
@@ -225,6 +243,8 @@ database.fileNotFound=File not Found
|
||||
database.fileNullOrEmpty=File must not be null or empty
|
||||
database.failedImportFile=Failed Import File
|
||||
|
||||
session.expired=Your session has expired. Please refresh the page and try again.
|
||||
|
||||
#############
|
||||
# HOME-PAGE #
|
||||
#############
|
||||
@@ -482,6 +502,11 @@ home.removeImagePdf.title=Remove image
|
||||
home.removeImagePdf.desc=Remove image from PDF to reduce file size
|
||||
removeImagePdf.tags=Remove Image,Page operations,Back end,server side
|
||||
|
||||
|
||||
home.splitPdfByChapters.title=Split PDF by Chapters
|
||||
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
||||
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
||||
|
||||
#replace-invert-color
|
||||
replace-color.title=Replace-Invert-Color
|
||||
replace-color.header=Replace-Invert Color PDF
|
||||
@@ -526,7 +551,10 @@ login.oauth2AccessDenied=Доступ заблоковано
|
||||
login.oauth2InvalidTokenResponse=Недійсна відповідь з токеном
|
||||
login.oauth2InvalidIdToken=Недійсний Id токен
|
||||
login.userIsDisabled=User is deactivated, login is currently blocked with this username. Please contact the administrator.
|
||||
|
||||
login.alreadyLoggedIn=You are already logged in to
|
||||
login.alreadyLoggedIn2=devices. Please log out of the devices and try again.
|
||||
login.toManySessions=You have too many active sessions
|
||||
login.toManySessions2=Please log out of the devices and try again. Alternatively, you can upgrade to Stirling PDF Pro.
|
||||
|
||||
#auto-redact
|
||||
autoRedact.title=Автоматичне редагування
|
||||
@@ -1154,6 +1182,8 @@ licenses.license=Ліцензія
|
||||
survey.nav=Опитування
|
||||
survey.title=Опитування Stirling-PDF
|
||||
survey.description=Stirling-PDF не має аналітичних засобів для відслідковування, тому ми хочемо почути думку від користувачів, як покращити Stirling-PDF!
|
||||
survey.changes=Stirling-PDF has changed since the last survey! To find out more please check our blog post here:
|
||||
survey.changes2=With these changes we are getting paid business support and funding
|
||||
survey.please=Будь-ласка, пройдіть опитування!
|
||||
survey.disabled=(Вікно з опитування буде відключено у наступних оновленнях, але буде доступне внизу сторінки)
|
||||
survey.button=Пройти опитування
|
||||
@@ -1179,3 +1209,17 @@ removeImage.title=Remove image
|
||||
removeImage.header=Remove image
|
||||
removeImage.removeImage=Remove image
|
||||
removeImage.submit=Remove image
|
||||
|
||||
|
||||
splitByChapters.title=Split PDF by Chapters
|
||||
splitByChapters.header=Split PDF by Chapters
|
||||
splitByChapters.bookmarkLevel=Bookmark Level
|
||||
splitByChapters.includeMetadata=Include Metadata
|
||||
splitByChapters.allowDuplicates=Allow Duplicates
|
||||
splitByChapters.desc.1=This tool splits a PDF file into multiple PDFs based on its chapter structure.
|
||||
splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for splitting (0 for top-level, 1 for second-level, etc.).
|
||||
splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF.
|
||||
splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs.
|
||||
splitByChapters.submit=Split PDF
|
||||
|
||||
|
||||
|
||||
@@ -76,6 +76,7 @@ donate=Ủng hộ
|
||||
color=Màu sắc
|
||||
sponsor=Nhà tài trợ
|
||||
info=Thông tin
|
||||
pro=Pro
|
||||
page=Page
|
||||
pages=Pages
|
||||
|
||||
@@ -110,8 +111,24 @@ pipelineOptions.pipelineHeader=Pipeline:
|
||||
pipelineOptions.saveButton=Tải xuống
|
||||
pipelineOptions.validateButton=Xác thực
|
||||
|
||||
########################
|
||||
# ENTERPRISE EDITION #
|
||||
########################
|
||||
enterpriseEdition.button=Upgrade to Pro
|
||||
enterpriseEdition.warning=This feature is only available to Pro users.
|
||||
enterpriseEdition.yamlAdvert=Stirling PDF Pro supports YAML configuration files and other SSO features.
|
||||
enterpriseEdition.ssoAdvert=Looking for more user management features? Check out Stirling PDF Pro
|
||||
|
||||
|
||||
#################
|
||||
# Analytics #
|
||||
#################
|
||||
analytics.title=Do you want make Stirling PDF better?
|
||||
analytics.paragraph1=Stirling PDF has opt in analytics to help us improve the product. We do not track any personal information or file contents.
|
||||
analytics.paragraph2=Please consider enabling analytics to help Stirling-PDF grow and to allow us to understand our users better.
|
||||
analytics.enable=Enable analytics
|
||||
analytics.disable=Disable analytics
|
||||
analytics.settings=You can change the settings for analytics in the config/settings.yml file
|
||||
|
||||
#############
|
||||
# NAVBAR #
|
||||
@@ -128,6 +145,7 @@ navbar.sections.convertFrom=Chuyển đổi từ PDF
|
||||
navbar.sections.security=Ký & Bảo mật
|
||||
navbar.sections.advance=Nâng cao
|
||||
navbar.sections.edit=Xem & Chỉnh sửa
|
||||
navbar.sections.popular=Popular
|
||||
|
||||
#############
|
||||
# SETTINGS #
|
||||
@@ -225,6 +243,8 @@ database.fileNotFound=Không tìm thấy tệp
|
||||
database.fileNullOrEmpty=Tệp không được để trống hoặc rỗng
|
||||
database.failedImportFile=Không thể nhập tệp
|
||||
|
||||
session.expired=Your session has expired. Please refresh the page and try again.
|
||||
|
||||
#############
|
||||
# HOME-PAGE #
|
||||
#############
|
||||
@@ -482,6 +502,11 @@ home.removeImagePdf.title=Remove image
|
||||
home.removeImagePdf.desc=Remove image from PDF to reduce file size
|
||||
removeImagePdf.tags=Remove Image,Page operations,Back end,server side
|
||||
|
||||
|
||||
home.splitPdfByChapters.title=Split PDF by Chapters
|
||||
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
||||
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
||||
|
||||
#replace-invert-color
|
||||
replace-color.title=Replace-Invert-Color
|
||||
replace-color.header=Replace-Invert Color PDF
|
||||
@@ -526,7 +551,10 @@ login.oauth2AccessDenied=Truy cập bị từ chối
|
||||
login.oauth2InvalidTokenResponse=Phản hồi token không hợp lệ
|
||||
login.oauth2InvalidIdToken=Id Token không hợp lệ
|
||||
login.userIsDisabled=User is deactivated, login is currently blocked with this username. Please contact the administrator.
|
||||
|
||||
login.alreadyLoggedIn=You are already logged in to
|
||||
login.alreadyLoggedIn2=devices. Please log out of the devices and try again.
|
||||
login.toManySessions=You have too many active sessions
|
||||
login.toManySessions2=Please log out of the devices and try again. Alternatively, you can upgrade to Stirling PDF Pro.
|
||||
|
||||
#auto-redact
|
||||
autoRedact.title=Tự động biên tập
|
||||
@@ -1154,6 +1182,8 @@ licenses.license=Giấy phép
|
||||
survey.nav=Khảo sát
|
||||
survey.title=Khảo sát Stirling-PDF
|
||||
survey.description=Stirling-PDF không có cài đặt theo dõi nên chúng tôi muốn nghe từ người dùng để cải thiện Stirling-PDF!
|
||||
survey.changes=Stirling-PDF has changed since the last survey! To find out more please check our blog post here:
|
||||
survey.changes2=With these changes we are getting paid business support and funding
|
||||
survey.please=Vui lòng cân nhắc tham gia khảo sát của chúng tôi!
|
||||
survey.disabled=(Cửa sổ popup khảo sát sẽ bị vô hiệu hóa trong các bản cập nhật tiếp theo nhưng vẫn tìm thấy ở cuối trang)
|
||||
survey.button=Tham gia khảo sát
|
||||
@@ -1179,3 +1209,17 @@ removeImage.title=Remove image
|
||||
removeImage.header=Remove image
|
||||
removeImage.removeImage=Remove image
|
||||
removeImage.submit=Remove image
|
||||
|
||||
|
||||
splitByChapters.title=Split PDF by Chapters
|
||||
splitByChapters.header=Split PDF by Chapters
|
||||
splitByChapters.bookmarkLevel=Bookmark Level
|
||||
splitByChapters.includeMetadata=Include Metadata
|
||||
splitByChapters.allowDuplicates=Allow Duplicates
|
||||
splitByChapters.desc.1=This tool splits a PDF file into multiple PDFs based on its chapter structure.
|
||||
splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for splitting (0 for top-level, 1 for second-level, etc.).
|
||||
splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF.
|
||||
splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs.
|
||||
splitByChapters.submit=Split PDF
|
||||
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ green=绿色
|
||||
blue=蓝色
|
||||
custom=自定义...
|
||||
WorkInProgess=工作正在进行中,可能无法工作或有错误,请报告任何问题!
|
||||
poweredBy=Powered by
|
||||
poweredBy=服务来源:
|
||||
yes=是
|
||||
no=否
|
||||
changedCredsMessage=凭证已更改!
|
||||
@@ -76,6 +76,7 @@ donate=捐款
|
||||
color=颜色
|
||||
sponsor=赞助
|
||||
info=信息
|
||||
pro=Pro
|
||||
page=Page
|
||||
pages=Pages
|
||||
|
||||
@@ -110,8 +111,24 @@ pipelineOptions.pipelineHeader=流水线:
|
||||
pipelineOptions.saveButton=下载
|
||||
pipelineOptions.validateButton=验证
|
||||
|
||||
########################
|
||||
# ENTERPRISE EDITION #
|
||||
########################
|
||||
enterpriseEdition.button=Upgrade to Pro
|
||||
enterpriseEdition.warning=This feature is only available to Pro users.
|
||||
enterpriseEdition.yamlAdvert=Stirling PDF Pro supports YAML configuration files and other SSO features.
|
||||
enterpriseEdition.ssoAdvert=Looking for more user management features? Check out Stirling PDF Pro
|
||||
|
||||
|
||||
#################
|
||||
# Analytics #
|
||||
#################
|
||||
analytics.title=Do you want make Stirling PDF better?
|
||||
analytics.paragraph1=Stirling PDF has opt in analytics to help us improve the product. We do not track any personal information or file contents.
|
||||
analytics.paragraph2=Please consider enabling analytics to help Stirling-PDF grow and to allow us to understand our users better.
|
||||
analytics.enable=Enable analytics
|
||||
analytics.disable=Disable analytics
|
||||
analytics.settings=You can change the settings for analytics in the config/settings.yml file
|
||||
|
||||
#############
|
||||
# NAVBAR #
|
||||
@@ -128,12 +145,13 @@ navbar.sections.convertFrom=从PDF转换
|
||||
navbar.sections.security=签名和安全
|
||||
navbar.sections.advance=高级功能
|
||||
navbar.sections.edit=查看和编辑
|
||||
navbar.sections.popular=Popular
|
||||
|
||||
#############
|
||||
# SETTINGS #
|
||||
#############
|
||||
settings.title=设置
|
||||
settings.update=可更新
|
||||
settings.update=有可用的更新
|
||||
settings.updateAvailable=当前版本为 {0},新版本 ({1}) 可用。
|
||||
settings.appVersion=应用程序版本:
|
||||
settings.downloadOption.title=选择下载选项(单个文件非压缩文件):
|
||||
@@ -225,6 +243,8 @@ database.fileNotFound=未找到文件
|
||||
database.fileNullOrEmpty=文件不能为空
|
||||
database.failedImportFile=导入文件失败
|
||||
|
||||
session.expired=Your session has expired. Please refresh the page and try again.
|
||||
|
||||
#############
|
||||
# HOME-PAGE #
|
||||
#############
|
||||
@@ -482,6 +502,11 @@ home.removeImagePdf.title=删除图像
|
||||
home.removeImagePdf.desc=删除图像减少PDF大小
|
||||
removeImagePdf.tags=删除图像, 页面操作, 后端, 服务端
|
||||
|
||||
|
||||
home.splitPdfByChapters.title=Split PDF by Chapters
|
||||
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
||||
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
||||
|
||||
#replace-invert-color
|
||||
replace-color.title=Replace-Invert-Color
|
||||
replace-color.header=Replace-Invert Color PDF
|
||||
@@ -526,7 +551,10 @@ login.oauth2AccessDenied=拒绝访问
|
||||
login.oauth2InvalidTokenResponse=无效的Token响应
|
||||
login.oauth2InvalidIdToken=无效的Token
|
||||
login.userIsDisabled=用户被禁用,登录已被阻止。请联系管理员。
|
||||
|
||||
login.alreadyLoggedIn=You are already logged in to
|
||||
login.alreadyLoggedIn2=devices. Please log out of the devices and try again.
|
||||
login.toManySessions=You have too many active sessions
|
||||
login.toManySessions2=Please log out of the devices and try again. Alternatively, you can upgrade to Stirling PDF Pro.
|
||||
|
||||
#auto-redact
|
||||
autoRedact.title=自动删除
|
||||
@@ -1154,6 +1182,8 @@ licenses.license=许可证
|
||||
survey.nav=调查
|
||||
survey.title=Stirling-PDF调查
|
||||
survey.description=Stirling-PDF没有跟踪器,所以我们希望听取用户的意见来改进Stirling-PDF!
|
||||
survey.changes=Stirling-PDF has changed since the last survey! To find out more please check our blog post here:
|
||||
survey.changes2=With these changes we are getting paid business support and funding
|
||||
survey.please=请考虑参加我们的调查!
|
||||
survey.disabled=(调查弹出窗口将在后续更新中被禁用,但可在页脚处查看)
|
||||
survey.button=参与调查
|
||||
@@ -1179,3 +1209,17 @@ removeImage.title=删除图像
|
||||
removeImage.header=删除图像
|
||||
removeImage.removeImage=删除图像
|
||||
removeImage.submit=删除图像
|
||||
|
||||
|
||||
splitByChapters.title=Split PDF by Chapters
|
||||
splitByChapters.header=Split PDF by Chapters
|
||||
splitByChapters.bookmarkLevel=Bookmark Level
|
||||
splitByChapters.includeMetadata=Include Metadata
|
||||
splitByChapters.allowDuplicates=Allow Duplicates
|
||||
splitByChapters.desc.1=This tool splits a PDF file into multiple PDFs based on its chapter structure.
|
||||
splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for splitting (0 for top-level, 1 for second-level, etc.).
|
||||
splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF.
|
||||
splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs.
|
||||
splitByChapters.submit=Split PDF
|
||||
|
||||
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
###########
|
||||
# the direction that the language is written (ltr = left to right, rtl = right to left)
|
||||
language.direction=ltr
|
||||
addPageNumbers.fontSize=Font Size
|
||||
addPageNumbers.fontName=Font Name
|
||||
addPageNumbers.fontSize=字型大小
|
||||
addPageNumbers.fontName=字型名稱
|
||||
pdfPrompt=選擇 PDF 檔案
|
||||
multiPdfPrompt=選擇多個 PDF 檔案
|
||||
multiPdfDropPrompt=選擇(或拖放)所有需要的 PDF 檔案
|
||||
@@ -12,7 +12,7 @@ imgPrompt=選擇圖片
|
||||
genericSubmit=送出
|
||||
processTimeWarning=警告:此過程可能長達一分鐘,具體取決於檔案大小
|
||||
pageOrderPrompt=自訂頁面順序(輸入以逗號分隔的頁碼或函式,如 2n+1):
|
||||
pageSelectionPrompt=自訂頁面選擇(輸入以逗號分隔的頁碼 1、5、6 或 2n+1 等函數的清單):
|
||||
pageSelectionPrompt=自訂頁面選擇(輸入以逗號分隔的頁碼 1、5、6 或 2n+1 等函式的清單):
|
||||
goToPage=前往
|
||||
true=是
|
||||
false=否
|
||||
@@ -51,67 +51,84 @@ poweredBy=Powered by
|
||||
yes=是
|
||||
no=否
|
||||
changedCredsMessage=憑證已變更!
|
||||
notAuthenticatedMessage=使用者未認證。
|
||||
notAuthenticatedMessage=使用者未通過驗證。
|
||||
userNotFoundMessage=找不到使用者。
|
||||
incorrectPasswordMessage=目前密碼不正確。
|
||||
usernameExistsMessage=新使用者名稱已存在。
|
||||
invalidUsernameMessage=使用者名稱無效,使用者名稱只能包含字母、數字和以下特殊字元 @._+- 或必須是有效的電子郵件地址。
|
||||
invalidPasswordMessage=The password must not be empty and must not have spaces at the beginning or end.
|
||||
confirmPasswordErrorMessage=輸入的密碼必需和確認密碼相同。
|
||||
deleteCurrentUserMessage=無法刪除目前登錄的使用者。
|
||||
deleteUsernameExistsMessage=使用者名不存在,無法刪除。
|
||||
invalidUsernameMessage=無效的使用者名稱。使用者名稱只能包含字母、數字和以下特殊字元 @._+- 或必須是有效的電子郵件地址。
|
||||
invalidPasswordMessage=密碼不能為空,且開頭和結尾不能有空格。
|
||||
confirmPasswordErrorMessage=新密碼與確認新密碼必須相符。
|
||||
deleteCurrentUserMessage=無法刪除目前登入的使用者。
|
||||
deleteUsernameExistsMessage=使用者名稱不存在,無法刪除。
|
||||
downgradeCurrentUserMessage=無法降級目前使用者的角色
|
||||
disabledCurrentUserMessage=The current user cannot be disabled
|
||||
downgradeCurrentUserLongMessage=無法降級目前使用者的角色。因此,不會顯示目前的使用者。
|
||||
userAlreadyExistsOAuthMessage=該使用者已於 OAuth2 註冊。
|
||||
userAlreadyExistsWebMessage=該使用者已於網頁註冊。
|
||||
disabledCurrentUserMessage=無法停用目前使用者
|
||||
downgradeCurrentUserLongMessage=無法降級目前使用者的角色。因此,將不會顯示目前使用者。
|
||||
userAlreadyExistsOAuthMessage=使用者已經以 OAuth2 使用者身份存在。
|
||||
userAlreadyExistsWebMessage=使用者已經以網頁使用者身份存在。
|
||||
error=錯誤
|
||||
oops=哎呀!
|
||||
help=幫助
|
||||
help=說明
|
||||
goHomepage=前往首頁
|
||||
joinDiscord=加入我們的 Discord 伺服器
|
||||
seeDockerHub=查看 Docker Hub
|
||||
visitGithub=訪問 GitHub 存儲庫
|
||||
donate=捐贈
|
||||
seeDockerHub=造訪 Docker Hub 儲存庫
|
||||
visitGithub=造訪 GitHub 專案
|
||||
donate=捐款
|
||||
color=顏色
|
||||
sponsor=贊助
|
||||
info=Info
|
||||
page=Page
|
||||
pages=Pages
|
||||
info=資訊
|
||||
pro=專業版
|
||||
page=頁面
|
||||
pages=頁面
|
||||
|
||||
legal.privacy=Privacy Policy
|
||||
legal.terms=Terms and Conditions
|
||||
legal.accessibility=Accessibility
|
||||
legal.cookie=Cookie Policy
|
||||
legal.impressum=Impressum
|
||||
legal.privacy=隱私權政策
|
||||
legal.terms=使用條款
|
||||
legal.accessibility=無障礙性聲明
|
||||
legal.cookie=Cookie 政策
|
||||
legal.impressum=版本說明
|
||||
|
||||
###############
|
||||
# Pipeline #
|
||||
###############
|
||||
pipeline.header=管道選單(測試版)
|
||||
pipeline.uploadButton=上傳自定義
|
||||
pipeline.configureButton=配置
|
||||
pipeline.header=管道功能選單(測試版)
|
||||
pipeline.uploadButton=上傳自訂
|
||||
pipeline.configureButton=設定
|
||||
pipeline.defaultOption=自訂
|
||||
pipeline.submitButton=送出
|
||||
pipeline.help=管道説明
|
||||
pipeline.scanHelp=資料夾掃描説明
|
||||
pipeline.deletePrompt=確定刪除該管道?
|
||||
pipeline.help=管道功能說明
|
||||
pipeline.scanHelp=資料夾掃描說明
|
||||
pipeline.deletePrompt=您確定要刪除此管道嗎?
|
||||
|
||||
######################
|
||||
# Pipeline Options #
|
||||
######################
|
||||
pipelineOptions.header=管道配置
|
||||
pipelineOptions.header=管道設定
|
||||
pipelineOptions.pipelineNameLabel=管道名稱
|
||||
pipelineOptions.saveSettings=保存操作設置
|
||||
pipelineOptions.pipelineNamePrompt=在此處輸入管道名稱
|
||||
pipelineOptions.saveSettings=儲存操作設定
|
||||
pipelineOptions.pipelineNamePrompt=請在此輸入管道名稱
|
||||
pipelineOptions.selectOperation=選擇操作
|
||||
pipelineOptions.addOperationButton=添加操作
|
||||
pipelineOptions.addOperationButton=新增操作
|
||||
pipelineOptions.pipelineHeader=管道:
|
||||
pipelineOptions.saveButton=下載
|
||||
pipelineOptions.validateButton=驗證
|
||||
|
||||
########################
|
||||
# ENTERPRISE EDITION #
|
||||
########################
|
||||
enterpriseEdition.button=升級至專業版
|
||||
enterpriseEdition.warning=此功能僅提供給專業版使用者使用。
|
||||
enterpriseEdition.yamlAdvert=Stirling PDF 專業版支援 YAML 設定檔和其他單一登入 (SSO) 功能。
|
||||
enterpriseEdition.ssoAdvert=需要更多使用者管理功能嗎?請參考 Stirling PDF 專業版
|
||||
|
||||
|
||||
#################
|
||||
# Analytics #
|
||||
#################
|
||||
analytics.title=您想協助改善 Stirling PDF 嗎?
|
||||
analytics.paragraph1=Stirling PDF 有選擇性的分析功能,可幫助我們改進產品。我們不會追蹤任何個人資訊或檔案內容。
|
||||
analytics.paragraph2=請考慮啟用分析功能,以協助 Stirling-PDF 成長並讓我們更了解使用者需求。
|
||||
analytics.enable=啟用分析功能
|
||||
analytics.disable=停用分析功能
|
||||
analytics.settings=您可以在 config/settings.yml 檔案中變更分析功能的設定
|
||||
|
||||
#############
|
||||
# NAVBAR #
|
||||
@@ -121,35 +138,36 @@ navbar.darkmode=深色模式
|
||||
navbar.language=語言
|
||||
navbar.settings=設定
|
||||
navbar.allTools=工具
|
||||
navbar.multiTool=萬用工具
|
||||
navbar.sections.organize=組織
|
||||
navbar.multiTool=多功能工具
|
||||
navbar.sections.organize=整理
|
||||
navbar.sections.convertTo=轉換為 PDF
|
||||
navbar.sections.convertFrom=從 PDF 轉換
|
||||
navbar.sections.security=簽章與安全性
|
||||
navbar.sections.advance=進階
|
||||
navbar.sections.edit=檢視與編輯
|
||||
navbar.sections.popular=熱門功能
|
||||
|
||||
#############
|
||||
# SETTINGS #
|
||||
#############
|
||||
settings.title=設定
|
||||
settings.update=有更新可用
|
||||
settings.updateAvailable=當前版本為 {0}。歡迎你更新至最新版 ({1})。。
|
||||
settings.appVersion=應用版本:
|
||||
settings.downloadOption.title=選擇下載選項(對於單一檔案非壓縮下載):
|
||||
settings.updateAvailable=目前安裝的版本是 {0}。有新版本({1})可供使用。
|
||||
settings.appVersion=應用程式版本:
|
||||
settings.downloadOption.title=選擇下載選項(適用於單一檔案非壓縮下載):
|
||||
settings.downloadOption.1=在同一視窗中開啟
|
||||
settings.downloadOption.2=在新視窗中開啟
|
||||
settings.downloadOption.3=下載檔案
|
||||
settings.zipThreshold=當下載的檔案數量超過時,壓縮檔案
|
||||
settings.zipThreshold=當下載檔案數量超過此數值時,將檔案壓縮
|
||||
settings.signOut=登出
|
||||
settings.accountSettings=帳戶設定
|
||||
settings.bored.help=啟用彩蛋
|
||||
settings.cacheInputs.name=輸入檔案下載
|
||||
settings.cacheInputs.help=開啟記住先前的輸入,做為日後使用
|
||||
settings.accountSettings=帳號設定
|
||||
settings.bored.help=啟用彩蛋遊戲
|
||||
settings.cacheInputs.name=儲存表單輸入
|
||||
settings.cacheInputs.help=啟用此功能以儲存先前使用的輸入,以便日後使用
|
||||
|
||||
changeCreds.title=變更憑證
|
||||
changeCreds.header=更新你的帳戶詳細資訊
|
||||
changeCreds.changePassword=你使用的是預設登錄認證。請輸入新密碼
|
||||
changeCreds.header=更新您的帳號詳細資訊
|
||||
changeCreds.changePassword=您正在使用預設登入憑證。請輸入新密碼
|
||||
changeCreds.newUsername=新使用者名稱
|
||||
changeCreds.oldPassword=目前密碼
|
||||
changeCreds.newPassword=新密碼
|
||||
@@ -158,9 +176,9 @@ changeCreds.submit=送出變更
|
||||
|
||||
|
||||
|
||||
account.title=帳戶設定
|
||||
account.accountSettings=帳戶設定
|
||||
account.adminSettings=管理設定 - 檢視和新增使用者
|
||||
account.title=帳號設定
|
||||
account.accountSettings=帳號設定
|
||||
account.adminSettings=管理員設定 - 檢視和新增使用者
|
||||
account.userControlSettings=使用者控制設定
|
||||
account.changeUsername=修改使用者名稱
|
||||
account.newUsername=新使用者名稱
|
||||
@@ -170,43 +188,43 @@ account.newPassword=新密碼
|
||||
account.changePassword=修改密碼
|
||||
account.confirmNewPassword=確認新密碼
|
||||
account.signOut=登出
|
||||
account.yourApiKey=你的 API 金鑰
|
||||
account.syncTitle=將瀏覽器設定與帳戶同步
|
||||
account.yourApiKey=您的 API 金鑰
|
||||
account.syncTitle=將瀏覽器設定與帳號同步
|
||||
account.settingsCompare=設定比較:
|
||||
account.property=屬性
|
||||
account.webBrowserSettings=網頁瀏覽器設定
|
||||
account.syncToBrowser=同步帳戶 → 瀏覽器
|
||||
account.syncToAccount=同步帳戶 ← 瀏覽器
|
||||
account.syncToBrowser=同步帳號 → 瀏覽器
|
||||
account.syncToAccount=同步帳號 ← 瀏覽器
|
||||
|
||||
|
||||
adminUserSettings.title=使用者控制設定
|
||||
adminUserSettings.header=管理使用者控制設定
|
||||
adminUserSettings.header=管理員使用者控制設定
|
||||
adminUserSettings.admin=管理員
|
||||
adminUserSettings.user=使用者
|
||||
adminUserSettings.addUser=新增使用者
|
||||
adminUserSettings.deleteUser=刪除使用者
|
||||
adminUserSettings.confirmDeleteUser=確認刪除該使用者?
|
||||
adminUserSettings.confirmChangeUserStatus=Should the user be disabled/enabled?
|
||||
adminUserSettings.usernameInfo=使用者名稱只能包含字母、數字和以下特殊字元 @._+-,或必須是有效的電子郵件地址。
|
||||
adminUserSettings.confirmDeleteUser=確定要刪除此使用者?
|
||||
adminUserSettings.confirmChangeUserStatus=是否要停用/啟用此使用者?
|
||||
adminUserSettings.usernameInfo=使用者名稱只能包含字母、數字和以下特殊字元 @._+- 或必須是有效的電子郵件地址。
|
||||
adminUserSettings.roles=角色
|
||||
adminUserSettings.role=角色
|
||||
adminUserSettings.actions=操作
|
||||
adminUserSettings.apiUser=受限制的 API 使用者
|
||||
adminUserSettings.extraApiUser=其他受限 API 使用者
|
||||
adminUserSettings.webOnlyUser=僅使用網頁的使用者
|
||||
adminUserSettings.demoUser=示範用途的使用者(無自訂設定)
|
||||
adminUserSettings.extraApiUser=額外受限制的 API 使用者
|
||||
adminUserSettings.webOnlyUser=僅網頁版使用者
|
||||
adminUserSettings.demoUser=示範使用者(無自訂設定)
|
||||
adminUserSettings.internalApiUser=內部 API 使用者
|
||||
adminUserSettings.forceChange=強制使用者在登入時修改使用者名稱/密碼
|
||||
adminUserSettings.submit=儲存
|
||||
adminUserSettings.changeUserRole=更改使用者身份
|
||||
adminUserSettings.forceChange=強制使用者在登入時變更密碼
|
||||
adminUserSettings.submit=儲存使用者
|
||||
adminUserSettings.changeUserRole=變更使用者角色
|
||||
adminUserSettings.authenticated=已驗證
|
||||
adminUserSettings.editOwnProfil=Edit own profile
|
||||
adminUserSettings.enabledUser=enabled user
|
||||
adminUserSettings.disabledUser=disabled user
|
||||
adminUserSettings.activeUsers=Active Users:
|
||||
adminUserSettings.disabledUsers=Disabled Users:
|
||||
adminUserSettings.totalUsers=Total Users:
|
||||
adminUserSettings.lastRequest=Last Request
|
||||
adminUserSettings.editOwnProfil=編輯自己的個人資料
|
||||
adminUserSettings.enabledUser=已啟用使用者
|
||||
adminUserSettings.disabledUser=已停用使用者
|
||||
adminUserSettings.activeUsers=使用中的使用者:
|
||||
adminUserSettings.disabledUsers=已停用的使用者:
|
||||
adminUserSettings.totalUsers=使用者總數:
|
||||
adminUserSettings.lastRequest=最後請求時間
|
||||
|
||||
|
||||
database.title=資料庫匯入/匯出
|
||||
@@ -217,18 +235,20 @@ database.fileSize=檔案大小
|
||||
database.deleteBackupFile=刪除備份檔案
|
||||
database.importBackupFile=匯入備份檔案
|
||||
database.downloadBackupFile=下載備份檔案
|
||||
database.info_1=在匯入資料時,確保正確的結構是至關重要的。如果你不確定自己在做什麼,請尋求專業人士的建議和支持。結構錯誤可能會導致應用程式故障,甚至完全無法運行。
|
||||
database.info_2=上傳時檔案名稱無關緊要。上傳後將重新命名為 backup_user_yyyyMMddHHmm.sql 格式,以確保命名規範一致。
|
||||
database.info_1=在匯入資料時,確保正確的結構至關重要。如果您不確定自己在做什麼,請尋求專業人士的建議和支援。結構錯誤可能會導致應用程式故障,甚至完全無法執行應用程式。
|
||||
database.info_2=上傳時檔案名稱並不重要。上傳後將重新命名為 backup_user_yyyyMMddHHmm.sql 格式,以確保命名規範一致。
|
||||
database.submit=匯入備份
|
||||
database.importIntoDatabaseSuccessed=成功匯入資料庫
|
||||
database.fileNotFound=檔案未找到
|
||||
database.fileNullOrEmpty=檔案不能為空或空白
|
||||
database.fileNotFound=找不到檔案
|
||||
database.fileNullOrEmpty=檔案不得為空或空白
|
||||
database.failedImportFile=匯入檔案失敗
|
||||
|
||||
session.expired=您的工作階段已過期。請重新整理頁面並再試一次。
|
||||
|
||||
#############
|
||||
# HOME-PAGE #
|
||||
#############
|
||||
home.desc=你的本地主機一站式 PDF 需求解決方案。
|
||||
home.desc=你的本機主機一站式 PDF 需求解決方案。
|
||||
home.searchBar=搜尋功能...
|
||||
|
||||
|
||||
@@ -372,7 +392,7 @@ certSign.tags=驗證,PEM,P12,官方,加密
|
||||
|
||||
home.removeCertSign.title=移除簽章
|
||||
home.removeCertSign.desc=從 PDF 移除簽章
|
||||
removeCertSign.tags=authenticate,PEM,P12,official,decrypt
|
||||
removeCertSign.tags=驗證,PEM,P12,官方,解密
|
||||
|
||||
home.pageLayout.title=多頁面版面配置
|
||||
home.pageLayout.desc=將 PDF 檔案的多個頁面合併到單一頁面
|
||||
@@ -465,9 +485,9 @@ home.split-by-sections.title=依區段分割 PDF
|
||||
home.split-by-sections.desc=將 PDF 的每一頁分割為較小的水平和垂直區段
|
||||
split-by-sections.tags=區段分割, 劃分, 自訂
|
||||
|
||||
home.AddStampRequest.title=將圖章添加到 PDF
|
||||
home.AddStampRequest.desc=在設置位置添加文字或添加圖像圖章
|
||||
AddStampRequest.tags=圖章,添加圖片,中心圖像,浮水印,PDF,嵌入,自訂
|
||||
home.AddStampRequest.title=將圖章新增到 PDF
|
||||
home.AddStampRequest.desc=在設定位置新增文字或新增影像圖章
|
||||
AddStampRequest.tags=圖章,新增圖片,中心影像,浮水印,PDF,嵌入,自訂
|
||||
|
||||
|
||||
home.PDFToBook.title=PDF 轉電子書
|
||||
@@ -478,28 +498,33 @@ home.BookToPDF.title=電子書轉 PDF
|
||||
home.BookToPDF.desc=使用 calibre 將書籍/漫畫格式轉換為 PDF
|
||||
BookToPDF.tags=電子書,漫畫,Calibre,轉換,日本漫畫,亞馬遜,kindle
|
||||
|
||||
home.removeImagePdf.title=Remove image
|
||||
home.removeImagePdf.desc=Remove image from PDF to reduce file size
|
||||
removeImagePdf.tags=Remove Image,Page operations,Back end,server side
|
||||
home.removeImagePdf.title=移除圖片
|
||||
home.removeImagePdf.desc=從 PDF 中移除圖片以減少檔案大小
|
||||
removeImagePdf.tags=移除圖片,頁面操作,後端,伺服器端
|
||||
|
||||
|
||||
home.splitPdfByChapters.title=依章節分割 PDF
|
||||
home.splitPdfByChapters.desc=根據 PDF 的章節結構將其分割成多個檔案。
|
||||
splitPdfByChapters.tags=分割,章節,書籤,整理
|
||||
|
||||
#replace-invert-color
|
||||
replace-color.title=Replace-Invert-Color
|
||||
replace-color.header=Replace-Invert Color PDF
|
||||
home.replaceColorPdf.title=Replace and Invert Color
|
||||
home.replaceColorPdf.desc=Replace color for text and background in PDF and invert full color of pdf to reduce file size
|
||||
replaceColorPdf.tags=Replace Color,Page operations,Back end,server side
|
||||
replace-color.selectText.1=Replace or Invert color Options
|
||||
replace-color.selectText.2=Default(Default high contrast colors)
|
||||
replace-color.selectText.3=Custom(Customized colors)
|
||||
replace-color.selectText.4=Full-Invert(Invert all colors)
|
||||
replace-color.selectText.5=High contrast color options
|
||||
replace-color.selectText.6=white text on black background
|
||||
replace-color.selectText.7=Black text on white background
|
||||
replace-color.selectText.8=Yellow text on black background
|
||||
replace-color.selectText.9=Green text on black background
|
||||
replace-color.selectText.10=Choose text Color
|
||||
replace-color.selectText.11=Choose background Color
|
||||
replace-color.submit=Replace
|
||||
replace-color.title=取代-反轉顏色
|
||||
replace-color.header=取代-反轉 PDF 顏色
|
||||
home.replaceColorPdf.title=取代與反轉顏色
|
||||
home.replaceColorPdf.desc=取代 PDF 中文字和背景的顏色,並反轉整個 PDF 的顏色以減少檔案大小
|
||||
replaceColorPdf.tags=取代顏色,頁面操作,後端,伺服器端
|
||||
replace-color.selectText.1=取代或反轉顏色選項
|
||||
replace-color.selectText.2=預設(預設高對比度顏色)
|
||||
replace-color.selectText.3=自訂(自訂顏色)
|
||||
replace-color.selectText.4=全部反轉(反轉所有顏色)
|
||||
replace-color.selectText.5=高對比度顏色選項
|
||||
replace-color.selectText.6=黑底白字
|
||||
replace-color.selectText.7=白底黑字
|
||||
replace-color.selectText.8=黑底黃字
|
||||
replace-color.selectText.9=黑底綠字
|
||||
replace-color.selectText.10=選擇文字顏色
|
||||
replace-color.selectText.11=選擇背景顏色
|
||||
replace-color.submit=取代
|
||||
|
||||
|
||||
|
||||
@@ -517,16 +542,19 @@ login.invalid=使用者名稱或密碼無效。
|
||||
login.locked=你的帳戶已被鎖定。
|
||||
login.signinTitle=請登入
|
||||
login.ssoSignIn=透過織網單一簽入
|
||||
login.oauth2AutoCreateDisabled=OAuth 2.0 自動建立使用者已停用
|
||||
login.oauth2AdminBlockedUser=Registration or logging in of non-registered users is currently blocked. Please contact the administrator.
|
||||
login.oauth2AutoCreateDisabled=OAuth 2.0 自動建立使用者功能已停用
|
||||
login.oauth2AdminBlockedUser=目前已封鎖非註冊使用者的註冊或登入。請聯絡系統管理員。
|
||||
login.oauth2RequestNotFound=找不到驗證請求
|
||||
login.oauth2InvalidUserInfoResponse=無效的使用者資訊回應
|
||||
login.oauth2invalidRequest=無效的回應
|
||||
login.oauth2AccessDenied=存取被拒
|
||||
login.oauth2InvalidTokenResponse=無效的 Token 回應
|
||||
login.oauth2InvalidIdToken=無效的 Tokne
|
||||
login.userIsDisabled=User is deactivated, login is currently blocked with this username. Please contact the administrator.
|
||||
|
||||
login.oauth2InvalidTokenResponse=無效的權杖回應
|
||||
login.oauth2InvalidIdToken=無效的識別權杖
|
||||
login.userIsDisabled=使用者已停用,目前此使用者無法登入。請聯絡系統管理員。
|
||||
login.alreadyLoggedIn=您已經登入了
|
||||
login.alreadyLoggedIn2=個裝置。請登出其他裝置後再試一次。
|
||||
login.toManySessions=您有太多使用中的工作階段
|
||||
login.toManySessions2=請登出其他裝置後再試一次。或者,您可以升級至 Stirling PDF 專業版。
|
||||
|
||||
#auto-redact
|
||||
autoRedact.title=自動塗黑
|
||||
@@ -612,7 +640,7 @@ AddStampRequest.stampType=圖章類型
|
||||
AddStampRequest.stampText=圖章文字
|
||||
AddStampRequest.stampImage=圖章圖片
|
||||
AddStampRequest.alphabet=字母表
|
||||
AddStampRequest.fontSize=字體/圖像大小
|
||||
AddStampRequest.fontSize=字型/影像大小
|
||||
AddStampRequest.rotation=旋轉
|
||||
AddStampRequest.opacity=透明度
|
||||
AddStampRequest.position=位置
|
||||
@@ -701,7 +729,7 @@ pageLayout.submit=送出
|
||||
scalePages.title=調整頁面大小/比例
|
||||
scalePages.header=調整頁面大小/比例
|
||||
scalePages.pageSize=文件的頁面大小。
|
||||
scalePages.keepPageSize=Original Size
|
||||
scalePages.keepPageSize=原始大小
|
||||
scalePages.scaleFactor=頁面的縮放級別(裁剪)。
|
||||
scalePages.submit=送出
|
||||
|
||||
@@ -710,7 +738,7 @@ scalePages.submit=送出
|
||||
certSign.title=憑證簽章
|
||||
certSign.header=使用你的憑證簽章(進行中)
|
||||
certSign.selectPDF=選擇要簽章的 PDF 檔案:
|
||||
certSign.jksNote=注意:如果你的證書類型未在下面列出,請使用 keytool 命令行工具將其轉換為 Java Keystore (.jks) 檔。 然後,選擇下面的 .jks 文件選項。
|
||||
certSign.jksNote=注意:如果你的證書類型未在下面列出,請使用 keytool 命令列工具將其轉換為 Java Keystore (.jks) 檔。 然後,選擇下面的 .jks 文件選項。
|
||||
certSign.selectKey=選擇你的私鑰文件(PKCS#8 格式,可能是 .pem 或 .der):
|
||||
certSign.selectCert=選擇你的憑證文件(X.509 格式,可能是 .pem 或 .der):
|
||||
certSign.selectP12=選擇你的 PKCS#12 金鑰庫文件(.p12 或 .pfx)(可選,如果提供,它應包含你的私鑰和憑證):
|
||||
@@ -750,8 +778,8 @@ removeAnnotations.submit=移除
|
||||
#compare
|
||||
compare.title=比較
|
||||
compare.header=比較 PDF
|
||||
compare.highlightColor.1=Highlight Color 1:
|
||||
compare.highlightColor.2=Highlight Color 2:
|
||||
compare.highlightColor.1=標示顏色 1:
|
||||
compare.highlightColor.2=標示顏色 2:
|
||||
compare.document.1=文件 1
|
||||
compare.document.2=文件 2
|
||||
compare.submit=比較
|
||||
@@ -788,7 +816,7 @@ repair.submit=修復
|
||||
#flatten
|
||||
flatten.title=平坦化
|
||||
flatten.header=PDF 平坦化
|
||||
flatten.flattenOnlyForms=Flatten only forms
|
||||
flatten.flattenOnlyForms=僅將表單平坦化
|
||||
flatten.submit=平坦化
|
||||
|
||||
|
||||
@@ -803,7 +831,7 @@ ScannerImageSplit.selectText.7=最小輪廓區域:
|
||||
ScannerImageSplit.selectText.8=設定照片的最小輪廓區域閾值
|
||||
ScannerImageSplit.selectText.9=邊框大小:
|
||||
ScannerImageSplit.selectText.10=設定新增和移除的邊框大小,以防止輸出中的白色邊框(預設:1)。
|
||||
ScannerImageSplit.info=Python is not installed. It is required to run.
|
||||
ScannerImageSplit.info=尚未安裝 Python。需要安裝 Python 才能執行。
|
||||
|
||||
|
||||
#OCR
|
||||
@@ -886,14 +914,14 @@ pdfOrganiser.mode.6=奇偶拆分
|
||||
pdfOrganiser.mode.7=刪除第一頁
|
||||
pdfOrganiser.mode.8=刪除最後一頁
|
||||
pdfOrganiser.mode.9=刪除第一頁和最後一頁
|
||||
pdfOrganiser.mode.10=Odd-Even Merge
|
||||
pdfOrganiser.mode.10=奇偶合併
|
||||
pdfOrganiser.placeholder=(例如 1,3,2 或 4-8,2,10-12 或 2n-1)
|
||||
|
||||
|
||||
#multiTool
|
||||
multiTool.title=PDF 多工具
|
||||
multiTool.header=PDF 多工具
|
||||
multiTool.uploadPrompts=File Name
|
||||
multiTool.uploadPrompts=檔名
|
||||
|
||||
#view pdf
|
||||
viewPdf.title=檢視 PDF
|
||||
@@ -955,7 +983,7 @@ pdfToImage.color=顏色
|
||||
pdfToImage.grey=灰度
|
||||
pdfToImage.blackwhite=黑白(可能會遺失資料!)
|
||||
pdfToImage.submit=轉換
|
||||
pdfToImage.info=Python is not installed. Required for WebP conversion.
|
||||
pdfToImage.info=尚未安裝 Python。需要安裝 Python 才能進行 WebP 轉換。
|
||||
|
||||
|
||||
#addPassword
|
||||
@@ -992,7 +1020,7 @@ watermark.selectText.6=heightSpacer(每個浮水印之間的垂直間距):
|
||||
watermark.selectText.7=不透明度(0% - 100%):
|
||||
watermark.selectText.8=浮水印類型:
|
||||
watermark.selectText.9=浮水印影像:
|
||||
watermark.selectText.10=Convert PDF to PDF-Image
|
||||
watermark.selectText.10=將 PDF 轉換為 PDF 影像
|
||||
watermark.submit=新增浮水印
|
||||
watermark.type.1=文字
|
||||
watermark.type.2=圖片
|
||||
@@ -1143,39 +1171,55 @@ printFile.submit=列印
|
||||
|
||||
|
||||
#licenses
|
||||
licenses.nav=許可證
|
||||
licenses.title=第三方許可證
|
||||
licenses.header=第三方許可證
|
||||
licenses.nav=授權條款
|
||||
licenses.title=第三方授權條款
|
||||
licenses.header=第三方授權條款
|
||||
licenses.module=模組
|
||||
licenses.version=版本
|
||||
licenses.license=許可證
|
||||
licenses.license=授權條款
|
||||
|
||||
#survey
|
||||
survey.nav=問卷調查
|
||||
survey.title=Stirling-PDF 問卷調查
|
||||
survey.description=Stirling-PDF 沒有追蹤功能,所以我們希望聽取用戶的意見來改進 Stirling-PDF!
|
||||
survey.please=請考慮參加我們的問卷調查!
|
||||
survey.disabled=(問卷調查彈出窗口將在後續更新中停用,但仍可在頁腳處使用)
|
||||
survey.button=參加問卷調查
|
||||
survey.description=Stirling-PDF 沒有追蹤功能,因此我們希望聽取使用者的意見來改進 Stirling-PDF!
|
||||
survey.changes=Stirling-PDF 自上次調查以來已有所改變!欲了解更多資訊,請查看我們的部落格文章:
|
||||
survey.changes2=隨著這些變更,我們正在獲得付費的商業支援和資金
|
||||
survey.please=請考慮參與我們的問卷調查!
|
||||
survey.disabled=(問卷調查彈出視窗將在後續更新中停用,但仍可在頁尾使用)
|
||||
survey.button=參與問卷調查
|
||||
survey.dontShowAgain=不要再次顯示
|
||||
|
||||
|
||||
#error
|
||||
error.sorry=對於這個問題,我們感到抱歉!
|
||||
error.needHelp=需要幫助/發現了一個問題?
|
||||
error.contactTip=如果你仍然遇到問題,請不要猶豫,隨時向我們尋求幫助。你可以在我們的 GitHub 頁面提交工單,或通過 Discord 與我們聯繋:
|
||||
error.404.head=404 - 找不到頁面 | 哎呀,我們在代碼中走錯了路!
|
||||
error.404.1=我們好像找不到你正在尋找的頁面。
|
||||
error.404.2=出了點錯誤
|
||||
error.github=在 GitHub 上提交工單
|
||||
error.sorry=很抱歉造成您的困擾!
|
||||
error.needHelp=需要協助或發現問題?
|
||||
error.contactTip=如果您仍然遇到問題,請不要猶豫,隨時向我們尋求協助。您可以在我們的 GitHub 頁面回報問題,或透過 Discord 跟我們聯絡:
|
||||
error.404.head=404 - 找不到頁面 | 糟糕,我們在程式碼中迷路了!
|
||||
error.404.1=我們似乎找不到您正在尋找的頁面。
|
||||
error.404.2=發生了一些錯誤
|
||||
error.github=在 GitHub 上回報問題
|
||||
error.showStack=顯示堆疊追蹤
|
||||
error.copyStack=複製堆疊追蹤
|
||||
error.githubSubmit=GitHub - 提交工單
|
||||
error.discordSubmit=Discord - 提交支援帖子
|
||||
error.githubSubmit=GitHub - 回報問題
|
||||
error.discordSubmit=Discord - 發表支援文章
|
||||
|
||||
|
||||
#remove-image
|
||||
removeImage.title=Remove image
|
||||
removeImage.header=Remove image
|
||||
removeImage.removeImage=Remove image
|
||||
removeImage.submit=Remove image
|
||||
removeImage.title=移除圖片
|
||||
removeImage.header=移除圖片
|
||||
removeImage.removeImage=移除圖片
|
||||
removeImage.submit=移除圖片
|
||||
|
||||
|
||||
splitByChapters.title=依章節分割 PDF
|
||||
splitByChapters.header=依章節分割 PDF
|
||||
splitByChapters.bookmarkLevel=書籤層級
|
||||
splitByChapters.includeMetadata=包含中繼資料
|
||||
splitByChapters.allowDuplicates=允許重複
|
||||
splitByChapters.desc.1=此工具會根據 PDF 檔案的章節結構將其分割成多個 PDF。
|
||||
splitByChapters.desc.2=書籤層級:選擇用於分割的書籤層級(0 表示最上層,1 表示第二層,依此類推)。
|
||||
splitByChapters.desc.3=包含中繼資料:如果勾選,原始 PDF 的中繼資料將包含在每個分割後的 PDF 中。
|
||||
splitByChapters.desc.4=允許重複:如果勾選,允許同一頁面上的多個書籤建立獨立的 PDF。
|
||||
splitByChapters.submit=分割 PDF
|
||||
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
|
||||
security:
|
||||
enableLogin: false # set to 'true' to enable login
|
||||
enableLogin: true # set to 'true' to enable login
|
||||
csrfDisabled: true # Set to 'true' to disable CSRF protection (not recommended for production)
|
||||
loginAttemptCount: 5 # lock user account after 5 tries; when using e.g. Fail2Ban you can deactivate the function with -1
|
||||
loginResetTimeMinutes: 120 # lock account for 2 hours after x attempts
|
||||
@@ -47,6 +47,19 @@ security:
|
||||
useAsUsername: email # Default is 'email'; custom fields can be used as the username
|
||||
scopes: openid, profile, email # Specify the scopes for which the application will request permissions
|
||||
provider: google # Set this to your OAuth provider's name, e.g., 'google' or 'keycloak'
|
||||
saml2:
|
||||
enabled: true
|
||||
autoCreateUser: false # set to 'true' to allow auto-creation of non-existing users
|
||||
blockRegistration: false # set to 'true' to deny login with SSO without prior registration by an admin
|
||||
entityId: 'spring-boot-app'
|
||||
registrationId: 'keycloak'
|
||||
idpMetadataUri: 'http://localhost:8080/realms/saml-sso/protocol/saml/descriptor'
|
||||
idpSingleLogoutUrl: 'http://localhost:8080/realms/saml-sso/protocol/saml'
|
||||
idpSingleLoginUrl: 'http://localhost:8080/realms/saml-sso/protocol/saml'
|
||||
idpIssuer: 'http://localhost:8080/realms/saml-sso'
|
||||
idpCert: 'classpath:saml-public-cert.crt'
|
||||
privateKey: 'classpath:local.key'
|
||||
spCert: 'classpath:local.crt'
|
||||
|
||||
# Enterprise edition settings unused for now please ignore!
|
||||
enterpriseEdition:
|
||||
|
||||
@@ -63,6 +63,27 @@
|
||||
"moduleLicense": "The Apache Software License, Version 2.0",
|
||||
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||
},
|
||||
{
|
||||
"moduleName": "com.fasterxml.jackson.jaxrs:jackson-jaxrs-base",
|
||||
"moduleUrl": "https://github.com/FasterXML/jackson-jaxrs-providers/jackson-jaxrs-base",
|
||||
"moduleVersion": "2.17.2",
|
||||
"moduleLicense": "The Apache Software License, Version 2.0",
|
||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||
},
|
||||
{
|
||||
"moduleName": "com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider",
|
||||
"moduleUrl": "https://github.com/FasterXML/jackson-jaxrs-providers/jackson-jaxrs-json-provider",
|
||||
"moduleVersion": "2.17.2",
|
||||
"moduleLicense": "The Apache Software License, Version 2.0",
|
||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||
},
|
||||
{
|
||||
"moduleName": "com.fasterxml.jackson.module:jackson-module-jaxb-annotations",
|
||||
"moduleUrl": "https://github.com/FasterXML/jackson-modules-base",
|
||||
"moduleVersion": "2.17.2",
|
||||
"moduleLicense": "The Apache Software License, Version 2.0",
|
||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||
},
|
||||
{
|
||||
"moduleName": "com.fasterxml.jackson.module:jackson-module-parameter-names",
|
||||
"moduleUrl": "https://github.com/FasterXML/jackson-modules-java8/jackson-module-parameter-names",
|
||||
@@ -111,6 +132,46 @@
|
||||
"moduleLicense": "Apache License, Version 2.0",
|
||||
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||
},
|
||||
{
|
||||
"moduleName": "com.google.code.findbugs:jsr305",
|
||||
"moduleUrl": "http://findbugs.sourceforge.net/",
|
||||
"moduleVersion": "3.0.2",
|
||||
"moduleLicense": "The Apache Software License, Version 2.0",
|
||||
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||
},
|
||||
{
|
||||
"moduleName": "com.google.errorprone:error_prone_annotations",
|
||||
"moduleVersion": "2.11.0",
|
||||
"moduleLicense": "Apache 2.0",
|
||||
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||
},
|
||||
{
|
||||
"moduleName": "com.google.guava:failureaccess",
|
||||
"moduleUrl": "https://github.com/google/guava/",
|
||||
"moduleVersion": "1.0.1",
|
||||
"moduleLicense": "The Apache Software License, Version 2.0",
|
||||
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||
},
|
||||
{
|
||||
"moduleName": "com.google.guava:guava",
|
||||
"moduleUrl": "https://github.com/google/guava/",
|
||||
"moduleVersion": "31.1-jre",
|
||||
"moduleLicense": "Apache License, Version 2.0",
|
||||
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||
},
|
||||
{
|
||||
"moduleName": "com.google.guava:listenablefuture",
|
||||
"moduleVersion": "9999.0-empty-to-avoid-conflict-with-guava",
|
||||
"moduleLicense": "The Apache Software License, Version 2.0",
|
||||
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||
},
|
||||
{
|
||||
"moduleName": "com.google.j2objc:j2objc-annotations",
|
||||
"moduleUrl": "https://github.com/google/j2objc/",
|
||||
"moduleVersion": "1.3",
|
||||
"moduleLicense": "The Apache Software License, Version 2.0",
|
||||
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||
},
|
||||
{
|
||||
"moduleName": "com.google.zxing:core",
|
||||
"moduleUrl": "https://github.com/zxing/zxing/core",
|
||||
@@ -118,6 +179,25 @@
|
||||
"moduleLicense": "The Apache Software License, Version 2.0",
|
||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||
},
|
||||
{
|
||||
"moduleName": "com.googlecode.owasp-java-html-sanitizer:java10-shim",
|
||||
"moduleVersion": "20240325.1",
|
||||
"moduleLicense": "Apache License, Version 2.0",
|
||||
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||
},
|
||||
{
|
||||
"moduleName": "com.googlecode.owasp-java-html-sanitizer:java8-shim",
|
||||
"moduleVersion": "20240325.1",
|
||||
"moduleLicense": "Apache License, Version 2.0",
|
||||
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||
},
|
||||
{
|
||||
"moduleName": "com.googlecode.owasp-java-html-sanitizer:owasp-java-html-sanitizer",
|
||||
"moduleUrl": "https://owasp.org",
|
||||
"moduleVersion": "20240325.1",
|
||||
"moduleLicense": "Apache License, Version 2.0",
|
||||
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||
},
|
||||
{
|
||||
"moduleName": "com.h2database:h2",
|
||||
"moduleUrl": "https://h2database.com",
|
||||
@@ -167,6 +247,13 @@
|
||||
"moduleLicense": "Apache 2",
|
||||
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||
},
|
||||
{
|
||||
"moduleName": "com.posthog.java:posthog",
|
||||
"moduleUrl": "http://github.com/PostHog/posthog-java",
|
||||
"moduleVersion": "1.1.1",
|
||||
"moduleLicense": "MIT License",
|
||||
"moduleLicenseUrl": "http://www.opensource.org/licenses/mit-license.php"
|
||||
},
|
||||
{
|
||||
"moduleName": "com.sun.istack:istack-commons-runtime",
|
||||
"moduleUrl": "https://www.eclipse.org",
|
||||
@@ -176,64 +263,78 @@
|
||||
},
|
||||
{
|
||||
"moduleName": "com.twelvemonkeys.common:common-image",
|
||||
"moduleVersion": "3.11.0",
|
||||
"moduleVersion": "3.12.0",
|
||||
"moduleLicense": "The BSD License",
|
||||
"moduleLicenseUrl": "https://github.com/haraldk/TwelveMonkeys#license"
|
||||
},
|
||||
{
|
||||
"moduleName": "com.twelvemonkeys.common:common-io",
|
||||
"moduleVersion": "3.11.0",
|
||||
"moduleVersion": "3.12.0",
|
||||
"moduleLicense": "The BSD License",
|
||||
"moduleLicenseUrl": "https://github.com/haraldk/TwelveMonkeys#license"
|
||||
},
|
||||
{
|
||||
"moduleName": "com.twelvemonkeys.common:common-lang",
|
||||
"moduleVersion": "3.11.0",
|
||||
"moduleVersion": "3.12.0",
|
||||
"moduleLicense": "The BSD License",
|
||||
"moduleLicenseUrl": "https://github.com/haraldk/TwelveMonkeys#license"
|
||||
},
|
||||
{
|
||||
"moduleName": "com.twelvemonkeys.imageio:imageio-batik",
|
||||
"moduleVersion": "3.11.0",
|
||||
"moduleVersion": "3.12.0",
|
||||
"moduleLicense": "The BSD License",
|
||||
"moduleLicenseUrl": "https://github.com/haraldk/TwelveMonkeys#license"
|
||||
},
|
||||
{
|
||||
"moduleName": "com.twelvemonkeys.imageio:imageio-bmp",
|
||||
"moduleVersion": "3.11.0",
|
||||
"moduleVersion": "3.12.0",
|
||||
"moduleLicense": "The BSD License",
|
||||
"moduleLicenseUrl": "https://github.com/haraldk/TwelveMonkeys#license"
|
||||
},
|
||||
{
|
||||
"moduleName": "com.twelvemonkeys.imageio:imageio-core",
|
||||
"moduleVersion": "3.11.0",
|
||||
"moduleVersion": "3.12.0",
|
||||
"moduleLicense": "The BSD License",
|
||||
"moduleLicenseUrl": "https://github.com/haraldk/TwelveMonkeys#license"
|
||||
},
|
||||
{
|
||||
"moduleName": "com.twelvemonkeys.imageio:imageio-jpeg",
|
||||
"moduleVersion": "3.11.0",
|
||||
"moduleVersion": "3.12.0",
|
||||
"moduleLicense": "The BSD License",
|
||||
"moduleLicenseUrl": "https://github.com/haraldk/TwelveMonkeys#license"
|
||||
},
|
||||
{
|
||||
"moduleName": "com.twelvemonkeys.imageio:imageio-metadata",
|
||||
"moduleVersion": "3.11.0",
|
||||
"moduleVersion": "3.12.0",
|
||||
"moduleLicense": "The BSD License",
|
||||
"moduleLicenseUrl": "https://github.com/haraldk/TwelveMonkeys#license"
|
||||
},
|
||||
{
|
||||
"moduleName": "com.twelvemonkeys.imageio:imageio-tiff",
|
||||
"moduleVersion": "3.11.0",
|
||||
"moduleVersion": "3.12.0",
|
||||
"moduleLicense": "The BSD License",
|
||||
"moduleLicenseUrl": "https://github.com/haraldk/TwelveMonkeys#license"
|
||||
},
|
||||
{
|
||||
"moduleName": "com.twelvemonkeys.imageio:imageio-webp",
|
||||
"moduleVersion": "3.11.0",
|
||||
"moduleVersion": "3.12.0",
|
||||
"moduleLicense": "The BSD License",
|
||||
"moduleLicenseUrl": "https://github.com/haraldk/TwelveMonkeys#license"
|
||||
},
|
||||
{
|
||||
"moduleName": "com.unboundid.product.scim2:scim2-sdk-client",
|
||||
"moduleUrl": "https://github.com/pingidentity/scim2",
|
||||
"moduleVersion": "2.3.5",
|
||||
"moduleLicense": "UnboundID SCIM2 SDK Free Use License",
|
||||
"moduleLicenseUrl": "https://github.com/pingidentity/scim2"
|
||||
},
|
||||
{
|
||||
"moduleName": "com.unboundid.product.scim2:scim2-sdk-common",
|
||||
"moduleUrl": "https://github.com/pingidentity/scim2",
|
||||
"moduleVersion": "2.3.5",
|
||||
"moduleLicense": "UnboundID SCIM2 SDK Free Use License",
|
||||
"moduleLicenseUrl": "https://github.com/pingidentity/scim2"
|
||||
},
|
||||
{
|
||||
"moduleName": "com.zaxxer:HikariCP",
|
||||
"moduleUrl": "https://github.com/brettwooldridge/HikariCP",
|
||||
@@ -248,6 +349,13 @@
|
||||
"moduleLicense": "Apache License, Version 2.0",
|
||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||
},
|
||||
{
|
||||
"moduleName": "commons-codec:commons-codec",
|
||||
"moduleUrl": "https://commons.apache.org/proper/commons-codec/",
|
||||
"moduleVersion": "1.16.1",
|
||||
"moduleLicense": "Apache-2.0",
|
||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||
},
|
||||
{
|
||||
"moduleName": "commons-collections:commons-collections",
|
||||
"moduleUrl": "http://commons.apache.org/collections/",
|
||||
@@ -269,6 +377,12 @@
|
||||
"moduleLicense": "The Apache Software License, Version 2.0",
|
||||
"moduleLicenseUrl": "/LICENSE.txt"
|
||||
},
|
||||
{
|
||||
"moduleName": "io.dropwizard.metrics:metrics-core",
|
||||
"moduleVersion": "4.2.25",
|
||||
"moduleLicense": "Apache License 2.0",
|
||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.html"
|
||||
},
|
||||
{
|
||||
"moduleName": "io.github.pixee:java-security-toolkit",
|
||||
"moduleUrl": "https://github.com/pixee/java-security-toolkit",
|
||||
@@ -286,7 +400,7 @@
|
||||
{
|
||||
"moduleName": "io.micrometer:micrometer-core",
|
||||
"moduleUrl": "https://github.com/micrometer-metrics/micrometer",
|
||||
"moduleVersion": "1.13.4",
|
||||
"moduleVersion": "1.13.6",
|
||||
"moduleLicense": "The Apache Software License, Version 2.0",
|
||||
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||
},
|
||||
@@ -422,6 +536,20 @@
|
||||
"moduleLicense": "GNU General Public License, version 2 with the GNU Classpath Exception",
|
||||
"moduleLicenseUrl": "https://www.gnu.org/software/classpath/license.html"
|
||||
},
|
||||
{
|
||||
"moduleName": "javax.activation:javax.activation-api",
|
||||
"moduleUrl": "http://www.oracle.com",
|
||||
"moduleVersion": "1.2.0",
|
||||
"moduleLicense": "COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0",
|
||||
"moduleLicenseUrl": "https://opensource.org/licenses/CDDL-1.0"
|
||||
},
|
||||
{
|
||||
"moduleName": "javax.xml.bind:jaxb-api",
|
||||
"moduleUrl": "http://www.oracle.com/",
|
||||
"moduleVersion": "2.3.1",
|
||||
"moduleLicense": "GPL2 w/ CPE",
|
||||
"moduleLicenseUrl": "https://oss.oracle.com/licenses/CDDL+GPL-1.1"
|
||||
},
|
||||
{
|
||||
"moduleName": "net.bytebuddy:byte-buddy",
|
||||
"moduleVersion": "1.14.19",
|
||||
@@ -442,6 +570,12 @@
|
||||
"moduleLicense": "The Apache Software License, Version 2.0",
|
||||
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||
},
|
||||
{
|
||||
"moduleName": "net.shibboleth.utilities:java-support",
|
||||
"moduleVersion": "8.4.2",
|
||||
"moduleLicense": "The Apache Software License, Version 2.0",
|
||||
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||
},
|
||||
{
|
||||
"moduleName": "org.antlr:antlr4-runtime",
|
||||
"moduleUrl": "https://www.antlr.org/",
|
||||
@@ -470,6 +604,20 @@
|
||||
"moduleLicense": "Apache-2.0",
|
||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||
},
|
||||
{
|
||||
"moduleName": "org.apache.httpcomponents:httpclient",
|
||||
"moduleUrl": "http://hc.apache.org/httpcomponents-client-ga",
|
||||
"moduleVersion": "4.5.14",
|
||||
"moduleLicense": "Apache License, Version 2.0",
|
||||
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||
},
|
||||
{
|
||||
"moduleName": "org.apache.httpcomponents:httpcore",
|
||||
"moduleUrl": "http://hc.apache.org/httpcomponents-core-ga",
|
||||
"moduleVersion": "4.4.16",
|
||||
"moduleLicense": "Apache License, Version 2.0",
|
||||
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||
},
|
||||
{
|
||||
"moduleName": "org.apache.logging.log4j:log4j-api",
|
||||
"moduleVersion": "2.23.1",
|
||||
@@ -516,6 +664,13 @@
|
||||
"moduleLicense": "Apache-2.0",
|
||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||
},
|
||||
{
|
||||
"moduleName": "org.apache.santuario:xmlsec",
|
||||
"moduleUrl": "https://www.apache.org/",
|
||||
"moduleVersion": "2.3.4",
|
||||
"moduleLicense": "Apache-2.0",
|
||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||
},
|
||||
{
|
||||
"moduleName": "org.apache.tomcat.embed:tomcat-embed-el",
|
||||
"moduleUrl": "https://tomcat.apache.org/",
|
||||
@@ -523,16 +678,23 @@
|
||||
"moduleLicense": "Apache License, Version 2.0",
|
||||
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||
},
|
||||
{
|
||||
"moduleName": "org.apache.velocity:velocity-engine-core",
|
||||
"moduleUrl": "https://www.apache.org/",
|
||||
"moduleVersion": "2.3",
|
||||
"moduleLicense": "Apache License, Version 2.0",
|
||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||
},
|
||||
{
|
||||
"moduleName": "org.apache.xmlgraphics:batik-all",
|
||||
"moduleVersion": "1.17",
|
||||
"moduleVersion": "1.18",
|
||||
"moduleLicense": "The Apache Software License, Version 2.0",
|
||||
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||
},
|
||||
{
|
||||
"moduleName": "org.apache.xmlgraphics:xmlgraphics-commons",
|
||||
"moduleUrl": "http://xmlgraphics.apache.org/commons/",
|
||||
"moduleVersion": "2.9",
|
||||
"moduleVersion": "2.10",
|
||||
"moduleLicense": "The Apache Software License, Version 2.0",
|
||||
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||
},
|
||||
@@ -571,6 +733,13 @@
|
||||
"moduleLicense": "Bouncy Castle Licence",
|
||||
"moduleLicenseUrl": "https://www.bouncycastle.org/licence.html"
|
||||
},
|
||||
{
|
||||
"moduleName": "org.checkerframework:checker-qual",
|
||||
"moduleUrl": "https://checkerframework.org",
|
||||
"moduleVersion": "3.12.0",
|
||||
"moduleLicense": "The MIT License",
|
||||
"moduleLicenseUrl": "http://opensource.org/licenses/MIT"
|
||||
},
|
||||
{
|
||||
"moduleName": "org.commonmark:commonmark",
|
||||
"moduleVersion": "0.23.0",
|
||||
@@ -583,6 +752,13 @@
|
||||
"moduleLicense": "BSD 2-Clause License",
|
||||
"moduleLicenseUrl": "https://opensource.org/licenses/BSD-2-Clause"
|
||||
},
|
||||
{
|
||||
"moduleName": "org.cryptacular:cryptacular",
|
||||
"moduleUrl": "http://www.cryptacular.org",
|
||||
"moduleVersion": "1.2.5",
|
||||
"moduleLicense": "GNU Lesser General Public License",
|
||||
"moduleLicenseUrl": "http://www.gnu.org/licenses/lgpl-3.0.txt"
|
||||
},
|
||||
{
|
||||
"moduleName": "org.eclipse.angus:angus-activation",
|
||||
"moduleUrl": "https://www.eclipse.org",
|
||||
@@ -828,6 +1004,78 @@
|
||||
"moduleLicense": "Public Domain, per Creative Commons CC0",
|
||||
"moduleLicenseUrl": "http://creativecommons.org/publicdomain/zero/1.0/"
|
||||
},
|
||||
{
|
||||
"moduleName": "org.opensaml:opensaml-core",
|
||||
"moduleVersion": "4.3.2",
|
||||
"moduleLicense": "The Apache Software License, Version 2.0",
|
||||
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||
},
|
||||
{
|
||||
"moduleName": "org.opensaml:opensaml-messaging-api",
|
||||
"moduleVersion": "4.3.2",
|
||||
"moduleLicense": "The Apache Software License, Version 2.0",
|
||||
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||
},
|
||||
{
|
||||
"moduleName": "org.opensaml:opensaml-profile-api",
|
||||
"moduleVersion": "4.3.2",
|
||||
"moduleLicense": "The Apache Software License, Version 2.0",
|
||||
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||
},
|
||||
{
|
||||
"moduleName": "org.opensaml:opensaml-saml-api",
|
||||
"moduleVersion": "4.3.2",
|
||||
"moduleLicense": "The Apache Software License, Version 2.0",
|
||||
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||
},
|
||||
{
|
||||
"moduleName": "org.opensaml:opensaml-saml-impl",
|
||||
"moduleVersion": "4.3.2",
|
||||
"moduleLicense": "The Apache Software License, Version 2.0",
|
||||
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||
},
|
||||
{
|
||||
"moduleName": "org.opensaml:opensaml-security-api",
|
||||
"moduleVersion": "4.3.2",
|
||||
"moduleLicense": "The Apache Software License, Version 2.0",
|
||||
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||
},
|
||||
{
|
||||
"moduleName": "org.opensaml:opensaml-security-impl",
|
||||
"moduleVersion": "4.3.2",
|
||||
"moduleLicense": "The Apache Software License, Version 2.0",
|
||||
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||
},
|
||||
{
|
||||
"moduleName": "org.opensaml:opensaml-soap-api",
|
||||
"moduleVersion": "4.3.2",
|
||||
"moduleLicense": "The Apache Software License, Version 2.0",
|
||||
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||
},
|
||||
{
|
||||
"moduleName": "org.opensaml:opensaml-soap-impl",
|
||||
"moduleVersion": "4.3.2",
|
||||
"moduleLicense": "The Apache Software License, Version 2.0",
|
||||
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||
},
|
||||
{
|
||||
"moduleName": "org.opensaml:opensaml-storage-api",
|
||||
"moduleVersion": "4.3.2",
|
||||
"moduleLicense": "The Apache Software License, Version 2.0",
|
||||
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||
},
|
||||
{
|
||||
"moduleName": "org.opensaml:opensaml-xmlsec-api",
|
||||
"moduleVersion": "4.3.2",
|
||||
"moduleLicense": "The Apache Software License, Version 2.0",
|
||||
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||
},
|
||||
{
|
||||
"moduleName": "org.opensaml:opensaml-xmlsec-impl",
|
||||
"moduleVersion": "4.3.2",
|
||||
"moduleLicense": "The Apache Software License, Version 2.0",
|
||||
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||
},
|
||||
{
|
||||
"moduleName": "org.ow2.asm:asm",
|
||||
"moduleUrl": "http://asm.ow2.org",
|
||||
@@ -1056,6 +1304,13 @@
|
||||
"moduleLicense": "Apache License, Version 2.0",
|
||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
||||
},
|
||||
{
|
||||
"moduleName": "org.springframework.security:spring-security-saml2-service-provider",
|
||||
"moduleUrl": "https://spring.io/projects/spring-security",
|
||||
"moduleVersion": "6.3.3",
|
||||
"moduleLicense": "Apache License, Version 2.0",
|
||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
||||
},
|
||||
{
|
||||
"moduleName": "org.springframework.security:spring-security-web",
|
||||
"moduleUrl": "https://spring.io/projects/spring-security",
|
||||
|
||||
@@ -283,7 +283,7 @@
|
||||
</script>
|
||||
<th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
|
||||
</div>
|
||||
<div th:if="${oAuth2Enabled}" class="modal fade" id="editUserModal" tabindex="-1" role="dialog" aria-labelledby="editUserModalLabel" aria-hidden="true">
|
||||
<div th:if="${altLogin}" class="modal fade" id="editUserModal" tabindex="-1" role="dialog" aria-labelledby="editUserModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<div class="d-flex justify-content-center">
|
||||
<ul class="list-unstyled d-flex">
|
||||
<li><a class="footer-link px-2" id="licenses" target="_blank" th:href="@{'/licenses'}" th:text="#{licenses.nav}">Licenses</a></li>
|
||||
<li><a class="footer-link px-2" id="survey" target="_blank" href="https://stirlingpdf.info/s/clwzgtfw7000gltkmwz1n212m" th:text="#{survey.nav}">Survey</a></li>
|
||||
<li><a class="footer-link px-2" id="survey" target="_blank" href="https://stirlingpdf.info/s/cm28y3niq000o56dv7liv8wsu" th:text="#{survey.nav}">Survey</a></li>
|
||||
<li th:if="${@privacyPolicy != ''}"><a class="footer-link px-2" target="_blank" th:href="${@privacyPolicy}" th:text="#{legal.privacy}">privacyPolicy</a></li>
|
||||
<li th:if="${@termsAndConditions != ''}"><a class="footer-link px-2" target="_blank" th:href="${@termsAndConditions}" th:text="#{legal.terms}">termsAndConditions</a></li>
|
||||
<li th:if="${@accessibilityStatement != ''}"><a class="footer-link px-2" target="_blank" th:href="${@accessibilityStatement}" th:text="#{legal.accessibility}">accessibilityStatement</a></li>
|
||||
|
||||
@@ -229,6 +229,9 @@
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry ('split-pdf-by-sections', 'grid_on', 'home.split-by-sections.title', 'home.split-by-sections.desc', 'split-by-sections.tags', 'advance')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry ('split-pdf-by-chapters', 'book', 'home.splitPdfByChapters.title', 'home.splitPdfByChapters.desc', 'splitPdfByChapters.tags', 'advance')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry ('split-by-size-or-count', 'vertical_split', 'home.autoSizeSplitPDF.title', 'home.autoSizeSplitPDF.desc', 'autoSizeSplitPDF.tags', 'advance')}">
|
||||
</div>
|
||||
|
||||
@@ -319,6 +319,9 @@
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='split-pdf-by-sections', cardTitle=#{home.split-by-sections.title}, cardText=#{home.split-by-sections.desc}, cardLink='split-pdf-by-sections', toolIcon='grid_on', tags=#{split-by-sections.tags}, toolGroup='advance')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='split-pdf-by-chapters', cardTitle=#{home.splitPdfByChapters.title}, cardText=#{home.splitPdfByChapters.desc}, cardLink='split-pdf-by-chapters', toolIcon='book', tags=#{splitPdfByChapters.tags}, toolGroup='advance')}">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -337,12 +340,12 @@
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p th:text="#{survey.changes}">Stirling-PDF has changed since the last survey! To find out more please check our blog post here:</h5>
|
||||
<a href="https://stirlingpdf.info/blog/stirling-pdf-survey-results" target="_blank" th:text="#{survey.changes2}">https://stirlingpdf.info/blog/stirling-pdf-survey-results</a>
|
||||
<p><span th:text="#{survey.changes}">Stirling-PDF has changed since the last survey! To find out more please check our blog post here: </span><a href="https://www.stirlingpdf.com/blog/stirling-pdf-future" target="_blank"> Stirling PDF</a></p>
|
||||
|
||||
<p th:text="#{survey.changes2}">With these changes we are getting paid business support and funding</p>
|
||||
<p th:text="#{survey.please}">Please consider taking our survey!</p>
|
||||
<p th:text="#{survey.disabled}">Survey popup will be disabled in following updates but available at foot of page)</p>
|
||||
<a href="https://stirlingpdf.info/s/clwzgtfw7000gltkmwz1n212m" target="_blank" class="btn btn-primary" id="takeSurvey"th:text="#{survey.button}" >Take Survey</a>
|
||||
<a href="https://stirlingpdf.info/s/cm28y3niq000o56dv7liv8wsu" target="_blank" class="btn btn-primary" id="takeSurvey"th:text="#{survey.button}" >Take Survey</a>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<div class="form-check mb-3">
|
||||
@@ -472,4 +475,4 @@
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
</html>
|
||||
|
||||
@@ -114,7 +114,7 @@
|
||||
<img class="my-4" th:src="@{'/favicon.svg'}" alt="favicon" width="144" height="144">
|
||||
|
||||
<h1 class="h1 mb-3 fw-normal" th:text="${@appName}">Stirling-PDF</h1>
|
||||
<div th:if="${oAuth2Enabled} and (${loginMethod} == 'all' or ${loginMethod} == 'oauth2')">
|
||||
<div th:if="${altLogin} and (${loginMethod} == 'all' or ${loginMethod} == 'oauth2')">
|
||||
<a href="#" class="w-100 btn btn-lg btn-primary" data-bs-toggle="modal" data-bs-target="#loginsModal" th:text="#{login.ssoSignIn}">Login Via SSO</a>
|
||||
<br>
|
||||
<br>
|
||||
@@ -168,7 +168,7 @@
|
||||
</main>
|
||||
<th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
|
||||
</div>
|
||||
<div th:if="${oAuth2Enabled}" class="modal fade" id="loginsModal" tabindex="-1" role="dialog" aria-labelledby="loginsModalLabel" aria-hidden="true">
|
||||
<div th:if="${altLogin}" class="modal fade" id="loginsModal" tabindex="-1" role="dialog" aria-labelledby="loginsModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
@@ -181,7 +181,7 @@
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="mb-3" th:each="provider : ${providerlist}">
|
||||
<a th:href="@{|/oauth2/authorization/${provider.key}|}" th:text="${provider.value}" class="w-100 btn btn-lg btn-primary">OpenID Connect</a>
|
||||
<a th:href="@{|${provider.key}|}" th:text="${provider.value}" class="w-100 btn btn-lg btn-primary">Login Provider</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
|
||||
48
test.sh
48
test.sh
@@ -73,28 +73,16 @@ main() {
|
||||
|
||||
|
||||
# Building Docker images
|
||||
docker build --no-cache --pull --build-arg VERSION_TAG=alpha -t frooodle/s-pdf:latest -f ./Dockerfile .
|
||||
docker build --no-cache --pull --build-arg VERSION_TAG=alpha -t frooodle/s-pdf:latest-ultra-lite -f ./Dockerfile-ultra-lite .
|
||||
# docker build --no-cache --pull --build-arg VERSION_TAG=alpha -t frooodle/s-pdf:latest -f ./Dockerfile .
|
||||
# docker build --no-cache --pull --build-arg VERSION_TAG=alpha -t frooodle/s-pdf:latest-ultra-lite -f ./Dockerfile-ultra-lite .
|
||||
|
||||
# Test each configuration
|
||||
run_tests "Stirling-PDF-Ultra-Lite" "./exampleYmlFiles/docker-compose-latest-ultra-lite.yml"
|
||||
docker-compose -f "./exampleYmlFiles/docker-compose-latest-ultra-lite.yml" down
|
||||
#run_tests "Stirling-PDF-Ultra-Lite" "./exampleYmlFiles/docker-compose-latest-ultra-lite.yml"
|
||||
#docker-compose -f "./exampleYmlFiles/docker-compose-latest-ultra-lite.yml" down
|
||||
|
||||
|
||||
run_tests "Stirling-PDF" "./exampleYmlFiles/docker-compose-latest.yml"
|
||||
if [ $? -eq 0 ]; then
|
||||
cd cucumber
|
||||
if behave; then
|
||||
passed_tests+=("Stirling-PDF-Regression")
|
||||
else
|
||||
failed_tests+=("Stirling-PDF-Regression")
|
||||
echo "Printing docker logs of failed regression"
|
||||
docker logs "Stirling-PDF"
|
||||
echo "Printed docker logs of failed regression"
|
||||
fi
|
||||
cd ..
|
||||
fi
|
||||
docker-compose -f "./exampleYmlFiles/docker-compose-latest.yml" down
|
||||
# run_tests "Stirling-PDF" "./exampleYmlFiles/docker-compose-latest.yml"
|
||||
#docker-compose -f "./exampleYmlFiles/docker-compose-latest.yml" down
|
||||
|
||||
export DOCKER_ENABLE_SECURITY=true
|
||||
# Run the gradlew build command and check if it fails
|
||||
@@ -105,18 +93,30 @@ main() {
|
||||
|
||||
|
||||
# Building Docker images with security enabled
|
||||
docker build --no-cache --pull --build-arg VERSION_TAG=alpha -t frooodle/s-pdf:latest -f ./Dockerfile .
|
||||
docker build --no-cache --pull --build-arg VERSION_TAG=alpha -t frooodle/s-pdf:latest-ultra-lite -f ./Dockerfile-ultra-lite .
|
||||
# docker build --no-cache --pull --build-arg VERSION_TAG=alpha -t frooodle/s-pdf:latest -f ./Dockerfile .
|
||||
# docker build --no-cache --pull --build-arg VERSION_TAG=alpha -t frooodle/s-pdf:latest-ultra-lite -f ./Dockerfile-ultra-lite .
|
||||
docker build --no-cache --pull --build-arg VERSION_TAG=alpha -t frooodle/s-pdf:latest-fat -f ./Dockerfile-fat .
|
||||
|
||||
|
||||
# Test each configuration with security
|
||||
run_tests "Stirling-PDF-Ultra-Lite-Security" "./exampleYmlFiles/docker-compose-latest-ultra-lite-security.yml"
|
||||
docker-compose -f "./exampleYmlFiles/docker-compose-latest-ultra-lite-security.yml" down
|
||||
run_tests "Stirling-PDF-Security" "./exampleYmlFiles/docker-compose-latest-security.yml"
|
||||
docker-compose -f "./exampleYmlFiles/docker-compose-latest-security.yml" down
|
||||
# run_tests "Stirling-PDF-Ultra-Lite-Security" "./exampleYmlFiles/docker-compose-latest-ultra-lite-security.yml"
|
||||
#docker-compose -f "./exampleYmlFiles/docker-compose-latest-ultra-lite-security.yml" down
|
||||
# run_tests "Stirling-PDF-Security" "./exampleYmlFiles/docker-compose-latest-security.yml"
|
||||
# docker-compose -f "./exampleYmlFiles/docker-compose-latest-security.yml" down
|
||||
|
||||
run_tests "Stirling-PDF-Security-Fat" "./exampleYmlFiles/docker-compose-latest-fat-security.yml"
|
||||
if [ $? -eq 0 ]; then
|
||||
cd cucumber
|
||||
if python -m behave; then
|
||||
passed_tests+=("Stirling-PDF-Regression")
|
||||
else
|
||||
failed_tests+=("Stirling-PDF-Regression")
|
||||
echo "Printing docker logs of failed regression"
|
||||
docker logs "Stirling-PDF-Security-Fat"
|
||||
echo "Printed docker logs of failed regression"
|
||||
fi
|
||||
cd ..
|
||||
fi
|
||||
docker-compose -f "./exampleYmlFiles/docker-compose-latest-fat-security.yml" down
|
||||
|
||||
# Report results
|
||||
|
||||
Reference in New Issue
Block a user