Compare commits
118 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2443ed2020 | ||
|
|
0dd91f209a | ||
|
|
869e2dc62d | ||
|
|
a28f14b70e | ||
|
|
b5de6a73cc | ||
|
|
45e2623b9b | ||
|
|
6d95bfdee0 | ||
|
|
f9111e556c | ||
|
|
fa746a2b51 | ||
|
|
e43292f4dd | ||
|
|
c56c5f80ab | ||
|
|
f2eb5dd7d3 | ||
|
|
ffe221b93c | ||
|
|
3f252e29a1 | ||
|
|
7c0fd02126 | ||
|
|
7109dd7905 | ||
|
|
e30665e7c8 | ||
|
|
514606789e | ||
|
|
dd1a441f92 | ||
|
|
31c48aec90 | ||
|
|
6709e0c46d | ||
|
|
10dd5e4a40 | ||
|
|
6fc9a2032a | ||
|
|
ffec5f7b54 | ||
|
|
b904a46bca | ||
|
|
26a457f9d0 | ||
|
|
e9042e0b7e | ||
|
|
521dff737f | ||
|
|
2968a696cd | ||
|
|
e0d3bbf13b | ||
|
|
89e763d959 | ||
|
|
1f9a0ed0e3 | ||
|
|
f203e07f55 | ||
|
|
56d4c02445 | ||
|
|
c20936b485 | ||
|
|
389323c190 | ||
|
|
f0dd48b3b1 | ||
|
|
b860146c93 | ||
|
|
23b662e5dc | ||
|
|
7160ba47b1 | ||
|
|
bdea990b18 | ||
|
|
1cbc6307c3 | ||
|
|
1e42f54ec7 | ||
|
|
44e85a1d38 | ||
|
|
54073767af | ||
|
|
3fa41e058a | ||
|
|
44f9313012 | ||
|
|
dcf13e9ade | ||
|
|
811c19e00d | ||
|
|
f2b7aeeb1c | ||
|
|
840694c527 | ||
|
|
21e5002d73 | ||
|
|
36d6c06237 | ||
|
|
29ec42bc35 | ||
|
|
425502b3e3 | ||
|
|
692a526900 | ||
|
|
3a27d97811 | ||
|
|
af91c73e7a | ||
|
|
526a30d033 | ||
|
|
bf8d6d2337 | ||
|
|
5628300f51 | ||
|
|
72ba97a00c | ||
|
|
1634987171 | ||
|
|
0f43723250 | ||
|
|
34e2128a39 | ||
|
|
0a0887aafc | ||
|
|
7c0c33ca63 | ||
|
|
8b2f24affd | ||
|
|
cbe750c76c | ||
|
|
5f6d24f805 | ||
|
|
be5d5fdf04 | ||
|
|
a04dc605df | ||
|
|
503acc9408 | ||
|
|
9b166da57d | ||
|
|
66e566555e | ||
|
|
f7aebf22c8 | ||
|
|
bb0b5f0528 | ||
|
|
9e3d5a5bc5 | ||
|
|
9ba5c6d4be | ||
|
|
00f7fe7ac3 | ||
|
|
f4fcede771 | ||
|
|
b69646d00b | ||
|
|
9e81b161c3 | ||
|
|
66ce7511ca | ||
|
|
d17db24aa9 | ||
|
|
ac5273244c | ||
|
|
27113f99cb | ||
|
|
fa31a4e340 | ||
|
|
4d53119390 | ||
|
|
303b8e032b | ||
|
|
d6b1fec69d | ||
|
|
5c572a7d89 | ||
|
|
04d1ff3822 | ||
|
|
eb8a494b5c | ||
|
|
4dfac2f46f | ||
|
|
547f231e29 | ||
|
|
38979dd362 | ||
|
|
890163053b | ||
|
|
fbbc71d7e6 | ||
|
|
4372536c17 | ||
|
|
7f577a6052 | ||
|
|
d7afc574a6 | ||
|
|
c622ee915b | ||
|
|
d0df392eef | ||
|
|
1c33500815 | ||
|
|
d730c6a12f | ||
|
|
b71f6f93b1 | ||
|
|
32dd328048 | ||
|
|
d9fa8f7b48 | ||
|
|
777e512e61 | ||
|
|
e7e3b34b37 | ||
|
|
6ed9e1c707 | ||
|
|
318076254d | ||
|
|
9402109663 | ||
|
|
a05cfd52cb | ||
|
|
ad0967f7d0 | ||
|
|
7e4d8f45f6 | ||
|
|
9dbc2712e7 |
3
.github/workflows/sync_files.yml
vendored
@@ -7,6 +7,7 @@ on:
|
||||
paths:
|
||||
- "build.gradle"
|
||||
- "src/main/resources/messages_*.properties"
|
||||
- "scripts/translation_status.toml"
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
@@ -58,6 +59,8 @@ jobs:
|
||||
uses: actions/setup-python@v5.1.0
|
||||
with:
|
||||
python-version: "3.x"
|
||||
- name: Install dependencies
|
||||
run: pip install tomlkit
|
||||
- name: Sync README
|
||||
run: python scripts/counter_translation.py
|
||||
- name: Set up git config
|
||||
|
||||
@@ -4,8 +4,8 @@ FROM alpine:20240329
|
||||
# Copy necessary files
|
||||
COPY scripts /scripts
|
||||
COPY pipeline /pipeline
|
||||
COPY src/main/resources/static/fonts/*.ttf /usr/share/fonts/opentype/noto
|
||||
COPY src/main/resources/static/fonts/*.otf /usr/share/fonts/opentype/noto
|
||||
COPY src/main/resources/static/fonts/*.ttf /usr/share/fonts/opentype/noto/
|
||||
#COPY src/main/resources/static/fonts/*.otf /usr/share/fonts/opentype/noto/
|
||||
COPY build/libs/*.jar app.jar
|
||||
|
||||
ARG VERSION_TAG
|
||||
@@ -34,7 +34,7 @@ RUN echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/main" | tee -a /et
|
||||
openssl-dev \
|
||||
bash \
|
||||
curl \
|
||||
openjdk17-jre \
|
||||
openjdk21-jre \
|
||||
su-exec \
|
||||
shadow \
|
||||
# Doc conversion
|
||||
|
||||
@@ -31,7 +31,7 @@ RUN mkdir /configs /logs /customFiles && \
|
||||
curl \
|
||||
su-exec \
|
||||
shadow \
|
||||
openjdk17-jre && \
|
||||
openjdk21-jre && \
|
||||
echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/main" | tee -a /etc/apk/repositories && \
|
||||
echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/community" | tee -a /etc/apk/repositories && \
|
||||
echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/testing" | tee -a /etc/apk/repositories && \
|
||||
|
||||
@@ -34,5 +34,18 @@ Then simply translate all property entries within that file and make a PR into m
|
||||
|
||||
If you do not have a java IDE i am happy to verify the changes worked once you raise PR (but won't be able to verify the translations themselves)
|
||||
|
||||
## Handling Untranslatable Strings
|
||||
|
||||
Sometimes, certain strings in the properties file may not require translation because they are the same in the target language or are universal (like names of protocols, certain terminologies, etc.). To ensure accurate statistics for language progress, these strings should be added to the `ignore_translation.toml` file located in the `scripts` directory. This will exclude them from the translation progress calculations.
|
||||
|
||||
For example, if the English string error=Error does not need translation in Polish, add it to the ignore_translation.toml under the Polish section:
|
||||
|
||||
```toml
|
||||
[pl_PL]
|
||||
ignore = [
|
||||
"language.direction", # Existing entries
|
||||
"error" # Add new entries here
|
||||
]
|
||||
```
|
||||
|
||||
Make sure to place the entry under the correct language section. This helps maintain the accuracy of translation progress statistics and ensures that the translation tool or scripts do not misinterpret the completion rate.
|
||||
|
||||
@@ -14,7 +14,7 @@ You could theoretically use a Distrobox/Toolbox, if your Distribution has old or
|
||||
|
||||
Install the following software, if not already installed:
|
||||
|
||||
- Java 17 or later
|
||||
- Java 17 or later (21 recommended)
|
||||
|
||||
- Gradle 7.0 or later (included within repo so not needed on server)
|
||||
|
||||
@@ -42,17 +42,25 @@ For Debian-based systems, you can use the following command:
|
||||
|
||||
```bash
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y git automake autoconf libtool libleptonica-dev pkg-config zlib1g-dev make g++ openjdk-17-jdk python3 python3-pip
|
||||
sudo apt-get install -y git automake autoconf libtool libleptonica-dev pkg-config zlib1g-dev make g++ openjdk-21-jdk python3 python3-pip
|
||||
```
|
||||
|
||||
For Fedora-based systems use this command:
|
||||
|
||||
```bash
|
||||
sudo dnf install -y git automake autoconf libtool leptonica-devel pkg-config zlib-devel make gcc-c++ java-17-openjdk python3 python3-pip
|
||||
sudo dnf install -y git automake autoconf libtool leptonica-devel pkg-config zlib-devel make gcc-c++ java-21-openjdk python3 python3-pip
|
||||
```
|
||||
|
||||
For non-root users with Nix Package Manager, use the following command:
|
||||
```bash
|
||||
nix-channel --update
|
||||
nix-env -iA nixpkgs.jdk21 nixpkgs.git nixpkgs.python38 nixpkgs.gnumake nixpkgs.libgcc nixpkgs.automake nixpkgs.autoconf nixpkgs.libtool nixpkgs.pkg-config nixpkgs.zlib nixpkgs.leptonica
|
||||
```
|
||||
|
||||
### Step 2: Clone and Build jbig2enc (Only required for certain OCR functionality)
|
||||
|
||||
For Debian and Fedora, you can build it from source using the following commands:
|
||||
|
||||
```bash
|
||||
mkdir ~/.git
|
||||
cd ~/.git &&\
|
||||
@@ -64,6 +72,11 @@ make &&\
|
||||
sudo make install
|
||||
```
|
||||
|
||||
For Nix, you will face `Leptonica not detected`. Bypass this by installing it directly using the following command:
|
||||
```bash
|
||||
nix-env -iA nixpkgs.jbig2enc
|
||||
```
|
||||
|
||||
### Step 3: Install Additional Software
|
||||
Next we need to install LibreOffice for conversions, ocrmypdf for OCR, and opencv for pattern recognition functionality.
|
||||
|
||||
@@ -105,6 +118,13 @@ sudo dnf install -y libreoffice-writer libreoffice-calc libreoffice-impress unpa
|
||||
pip3 install uno opencv-python-headless unoconv pngquant WeasyPrint
|
||||
```
|
||||
|
||||
For Nix:
|
||||
|
||||
```bash
|
||||
nix-env -iA nixpkgs.unpaper nixpkgs.libreoffice nixpkgs.ocrmypdf nixpkgs.poppler_utils
|
||||
pip3 install uno opencv-python-headless unoconv pngquant WeasyPrint
|
||||
```
|
||||
|
||||
### Step 4: Clone and Build Stirling-PDF
|
||||
|
||||
```bash
|
||||
@@ -115,13 +135,12 @@ chmod +x ./gradlew &&\
|
||||
./gradlew build
|
||||
```
|
||||
|
||||
|
||||
### Step 5: Move jar to desired location
|
||||
|
||||
After the build process, a `.jar` file will be generated in the `build/libs` directory.
|
||||
You can move this file to a desired location, for example, `/opt/Stirling-PDF/`.
|
||||
You must also move the Script folder within the Stirling-PDF repo that you have downloaded to this directory.
|
||||
This folder is required for the python scripts using OpenCV
|
||||
This folder is required for the python scripts using OpenCV.
|
||||
|
||||
```bash
|
||||
sudo mkdir /opt/Stirling-PDF &&\
|
||||
@@ -129,19 +148,25 @@ sudo mv ./build/libs/Stirling-PDF-*.jar /opt/Stirling-PDF/ &&\
|
||||
sudo mv scripts /opt/Stirling-PDF/ &&\
|
||||
echo "Scripts installed."
|
||||
```
|
||||
|
||||
For non-root users, you can just keep the jar in the main directory of Stirling-PDF using the following command:
|
||||
```bash
|
||||
mv ./build/libs/Stirling-PDF-*.jar ./Stirling-PDF-*.jar
|
||||
```
|
||||
|
||||
### Step 6: Other files
|
||||
#### OCR
|
||||
If you plan to use the OCR (Optical Character Recognition) functionality, you might need to install language packs for Tesseract if running non-english scanning.
|
||||
|
||||
##### Installing Language Packs
|
||||
Easiest is to use the langpacks provided by your repositories. Skip the other steps
|
||||
Easiest is to use the langpacks provided by your repositories. Skip the other steps.
|
||||
|
||||
Manual:
|
||||
|
||||
1. Download the desired language pack(s) by selecting the `.traineddata` file(s) for the language(s) you need.
|
||||
2. Place the `.traineddata` files in the Tesseract tessdata directory: `/usr/share/tessdata`
|
||||
3.
|
||||
Please view [OCRmyPDF install guide](https://ocrmypdf.readthedocs.io/en/latest/installation.html) for more info.
|
||||
3. Please view [OCRmyPDF install guide](https://ocrmypdf.readthedocs.io/en/latest/installation.html) for more info.
|
||||
|
||||
**IMPORTANT:** DO NOT REMOVE EXISTING `eng.traineddata`, IT'S REQUIRED.
|
||||
|
||||
Debian based systems, install languages with this command:
|
||||
@@ -171,14 +196,38 @@ dnf search -C tesseract-langpack-
|
||||
rpm -qa | grep tesseract-langpack | sed 's/tesseract-langpack-//g'
|
||||
```
|
||||
|
||||
Nix:
|
||||
|
||||
```bash
|
||||
nix-env -iA nixpkgs.tesseract
|
||||
```
|
||||
|
||||
**Note:** Nix Package Manager pre-installs almost all the language packs when tesseract is installed.
|
||||
|
||||
### Step 7: Run Stirling-PDF
|
||||
|
||||
Those who have pushed to the root directory, run the following commands:
|
||||
|
||||
```bash
|
||||
./gradlew bootRun
|
||||
or
|
||||
java -jar /opt/Stirling-PDF/Stirling-PDF-*.jar
|
||||
```
|
||||
|
||||
Since libreoffice, soffice, and conversion tools have their dbus_tmp_dir set as `dbus_tmp_dir="/run/user/$(id -u)/libreoffice-dbus"`, you might get the following error when using their endpoints:
|
||||
```
|
||||
[Thread-7] INFO s.s.SPDF.utils.ProcessExecutor - mkdir: cannot create directory ‘/run/user/1501’: Permission denied
|
||||
```
|
||||
To resolve this, before starting the Stirling-PDF, you have to set the environment variable to a directory you have write access to by using the following commands:
|
||||
|
||||
```bash
|
||||
mkdir temp
|
||||
export DBUS_SESSION_BUS_ADDRESS="unix:path=./temp"
|
||||
./gradlew bootRun
|
||||
or
|
||||
java -jar ./Stirling-PDF-*.jar
|
||||
```
|
||||
|
||||
### Step 8: Adding a Desktop icon
|
||||
|
||||
This will add a modified Appstarter to your Appmenu.
|
||||
@@ -202,7 +251,19 @@ EOF
|
||||
|
||||
Note: Currently the app will run in the background until manually closed.
|
||||
|
||||
### Optional: Run Stirling-PDF as a service
|
||||
### Optional: Changing the host and port of the application:
|
||||
|
||||
To override the default configuration, you can add the following to `/.git/Stirling-PDF/configs/custom_settings.yml` file:
|
||||
|
||||
```bash
|
||||
server:
|
||||
host: 0.0.0.0
|
||||
port: 3000
|
||||
```
|
||||
|
||||
**Note:** This file is created after the first application launch. To have it before that, you can create the directory and add the file yourself.
|
||||
|
||||
### Optional: Run Stirling-PDF as a service (requires root).
|
||||
|
||||
First create a .env file, where you can store environment variables:
|
||||
```
|
||||
@@ -239,6 +300,7 @@ WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
Notify systemd that it has to rebuild its internal service database (you have to run this command every time you make a change in the service file):
|
||||
|
||||
```
|
||||
sudo systemctl daemon-reload
|
||||
```
|
||||
|
||||
85
README.md
@@ -10,7 +10,7 @@
|
||||
|
||||
[](https://cloud.digitalocean.com/apps/new?repo=https://github.com/Stirling-Tools/Stirling-PDF/tree/digitalOcean&refcode=c3210994b1af)
|
||||
|
||||
This is a robust, locally hosted web-based PDF manipulation tool using Docker. It enables you to carry out various operations on PDF files, including splitting, merging, converting, reorganizing, adding images, rotating, compressing, and more. Originally developed entirely by ChatGPT, this locally hosted web application has evolved to encompass a comprehensive set of features, addressing all your PDF requirements.
|
||||
This is a robust, locally hosted web-based PDF manipulation tool using Docker. It enables you to carry out various operations on PDF files, including splitting, merging, converting, reorganizing, adding images, rotating, compressing, and more. This locally hosted web application has evolved to encompass a comprehensive set of features, addressing all your PDF requirements.
|
||||
|
||||
Stirling PDF does not initiate any outbound calls for record-keeping or tracking purposes.
|
||||
|
||||
@@ -165,31 +165,32 @@ Stirling PDF currently supports 27!
|
||||
| ------------------------------------------- | -------------------------------------- |
|
||||
| English (English) (en_GB) |  |
|
||||
| English (US) (en_US) |  |
|
||||
| Arabic (العربية) (ar_AR) |  |
|
||||
| German (Deutsch) (de_DE) |  |
|
||||
| French (Français) (fr_FR) |  |
|
||||
| Spanish (Español) (es_ES) |  |
|
||||
| Simplified Chinese (简体中文) (zh_CN) |  |
|
||||
| Traditional Chinese (繁體中文) (zh_TW) |  |
|
||||
| Catalan (Català) (ca_CA) |  |
|
||||
| Italian (Italiano) (it_IT) |  |
|
||||
| Swedish (Svenska) (sv_SE) |  |
|
||||
| Polish (Polski) (pl_PL) |  |
|
||||
| Romanian (Română) (ro_RO) |  |
|
||||
| Korean (한국어) (ko_KR) |  |
|
||||
| Portuguese Brazilian (Português) (pt_BR) |  |
|
||||
| Russian (Русский) (ru_RU) |  |
|
||||
| Basque (Euskara) (eu_ES) |  |
|
||||
| Japanese (日本語) (ja_JP) |  |
|
||||
| Dutch (Nederlands) (nl_NL) |  |
|
||||
| Greek (Ελληνικά) (el_GR) |  |
|
||||
| Turkish (Türkçe) (tr_TR) |  |
|
||||
| Indonesia (Bahasa Indonesia) (id_ID) |  |
|
||||
| Hindi (हिंदी) (hi_IN) |  |
|
||||
| Hungarian (Magyar) (hu_HU) |  |
|
||||
| Bulgarian (Български) (bg_BG) |  |
|
||||
| Sebian Latin alphabet (Srpski) (sr_LATN_RS) |  |
|
||||
| Ukrainian (Українська) (uk_UA) |  |
|
||||
| Arabic (العربية) (ar_AR) |  |
|
||||
| German (Deutsch) (de_DE) |  |
|
||||
| French (Français) (fr_FR) |  |
|
||||
| Spanish (Español) (es_ES) |  |
|
||||
| Simplified Chinese (简体中文) (zh_CN) |  |
|
||||
| Traditional Chinese (繁體中文) (zh_TW) |  |
|
||||
| Catalan (Català) (ca_CA) |  |
|
||||
| Italian (Italiano) (it_IT) |  |
|
||||
| Swedish (Svenska) (sv_SE) |  |
|
||||
| Polish (Polski) (pl_PL) |  |
|
||||
| Romanian (Română) (ro_RO) |  |
|
||||
| Korean (한국어) (ko_KR) |  |
|
||||
| Portuguese Brazilian (Português) (pt_BR) |  |
|
||||
| Russian (Русский) (ru_RU) |  |
|
||||
| Basque (Euskara) (eu_ES) |  |
|
||||
| Japanese (日本語) (ja_JP) |  |
|
||||
| Dutch (Nederlands) (nl_NL) |  |
|
||||
| Greek (Ελληνικά) (el_GR) |  |
|
||||
| Turkish (Türkçe) (tr_TR) |  |
|
||||
| Indonesia (Bahasa Indonesia) (id_ID) |  |
|
||||
| Hindi (हिंदी) (hi_IN) |  |
|
||||
| Hungarian (Magyar) (hu_HU) |  |
|
||||
| Bulgarian (Български) (bg_BG) |  |
|
||||
| Sebian Latin alphabet (Srpski) (sr_LATN_RS) |  |
|
||||
| Ukrainian (Українська) (uk_UA) |  |
|
||||
| Slovakian (Slovensky) (sk_SK) |  |
|
||||
|
||||
## Contributing (creating issues, translations, fixing bugs, etc.)
|
||||
|
||||
@@ -221,29 +222,45 @@ The Current list of settings is
|
||||
```yaml
|
||||
security:
|
||||
enableLogin: false # set to 'true' to enable login
|
||||
csrfDisabled: true
|
||||
csrfDisabled: true # Set to 'true' to disable CSRF protection (not recommended for production)
|
||||
loginAttemptCount: 5 # lock user account after 5 tries
|
||||
loginResetTimeMinutes : 120 # lock account for 2 hours after x attempts
|
||||
# initialLogin:
|
||||
# username: "admin" # Initial username for the first login (these are defaulted)
|
||||
# password: "stirling" # Initial password for the first login
|
||||
# oauth2:
|
||||
# enabled: false # set to 'true' to enable login (Note: enableLogin must also be 'true' for this to work)
|
||||
# issuer: "" # set to any provider that supports OpenID Connect Discovery (/.well-known/openid-configuration) end-point
|
||||
# clientId: "" # Client ID from your provider
|
||||
# clientSecret: "" # Client Secret from your provider
|
||||
# autoCreateUser: false # set to 'true' to allow auto-creation of non-existing users
|
||||
# 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'
|
||||
|
||||
system:
|
||||
defaultLocale: 'en-US' # Set the default language (e.g. 'de-DE', 'fr-FR', etc)
|
||||
googlevisibility: false # 'true' to allow Google visibility (via robots.txt), 'false' to disallow
|
||||
customStaticFilePath: '/customFiles/static/' # Directory path for custom static files
|
||||
enableAlphaFunctionality: false # Set to enable functionality which might need more testing before it fully goes live (This feature might make no changes)
|
||||
showUpdate: true # see when a new update is available
|
||||
showUpdateOnlyAdmin: false # Only admins can see when a new update is available, depending on showUpdate it must be set to 'true'
|
||||
customHTMLFiles: false # enable to have files placed in /customFiles/templates override the existing template html files
|
||||
|
||||
#ui:
|
||||
# appName: exampleAppName # Application's visible name
|
||||
# homeDescription: I am a description # Short description or tagline shown on homepage.
|
||||
# appNameNavbar: navbarName # Name displayed on the navigation bar
|
||||
ui:
|
||||
appName: null # Application's visible name
|
||||
homeDescription: null # Short description or tagline shown on homepage.
|
||||
appNameNavbar: null # Name displayed on the navigation bar
|
||||
|
||||
endpoints:
|
||||
toRemove: [] # List endpoints to disable (e.g. ['img-to-pdf', 'remove-pages'])
|
||||
groupsToRemove: [] # List groups to disable (e.g. ['LibreOffice'])
|
||||
|
||||
metrics:
|
||||
enabled: true # 'true' to enable Info APIs endpoints (view http://localhost:8080/swagger-ui/index.html#/API to learn more), 'false' to disable
|
||||
enabled: true # 'true' to enable Info APIs (`/api/*`) endpoints, 'false' to disable
|
||||
```
|
||||
|
||||
There is an additional config file ``/configs/custom_settings.yml`` were users familiar with java and spring application.properties can input their own settings on-top of Stirling-PDFs existing ones
|
||||
|
||||
### Extra notes
|
||||
|
||||
- Endpoints. Currently, the endpoints ENDPOINTS_TO_REMOVE and GROUPS_TO_REMOVE can include comma separate lists of endpoints and groups to disable as example ENDPOINTS_TO_REMOVE=img-to-pdf,remove-pages would disable both image-to-pdf and remove pages, GROUPS_TO_REMOVE=LibreOffice Would disable all things that use LibreOffice. You can see a list of all endpoints and groups [here](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/Endpoint-groups.md)
|
||||
@@ -269,7 +286,7 @@ For those wanting to use Stirling-PDFs backend API to link with their own custom
|
||||
### Prerequisites:
|
||||
|
||||
- User must have the folder ./configs volumed within docker so that it is retained during updates.
|
||||
- Docker uses must download the security jar version by setting ``DOCKER_ENABLE_SECURITY`` to ``true`` in environment variables.
|
||||
- Docker users must download the security jar version by setting ``DOCKER_ENABLE_SECURITY`` to ``true`` in environment variables.
|
||||
- Then either enable login via the settings.yml file or via setting ``SECURITY_ENABLE_LOGIN`` to ``true``
|
||||
- Now the initial user will be generated with username ``admin`` and password ``stirling``. On login you will be forced to change the password to a new one. You can also use the environment variables ``SECURITY_INITIALLOGIN_USERNAME`` and ``SECURITY_INITIALLOGIN_PASSWORD`` to set your own straight away (Recommended to remove them after user creation).
|
||||
|
||||
|
||||
13
build.gradle
@@ -12,7 +12,9 @@ plugins {
|
||||
import com.github.jk1.license.render.*
|
||||
|
||||
group = 'stirling.software'
|
||||
version = '0.23.1'
|
||||
version = '0.24.1'
|
||||
|
||||
//17 is lowest but we support and recommend 21
|
||||
sourceCompatibility = '17'
|
||||
|
||||
repositories {
|
||||
@@ -54,8 +56,8 @@ launch4j {
|
||||
headerType="console"
|
||||
jarTask = tasks.bootJar
|
||||
|
||||
errTitle="Encountered error, Do you have Java 17?"
|
||||
downloadUrl="https://download.oracle.com/java/17/latest/jdk-17_windows-x64_bin.exe"
|
||||
errTitle="Encountered error, Do you have Java 21?"
|
||||
downloadUrl="https://download.oracle.com/java/21/latest/jdk-21_windows-x64_bin.exe"
|
||||
variables=["BROWSER_OPEN=true", "ENDPOINTS_GROUPS_TO_REMOVE=CLI"]
|
||||
jreMinVersion="17"
|
||||
|
||||
@@ -64,8 +66,8 @@ launch4j {
|
||||
|
||||
messagesStartupError="An error occurred while starting Stirling-PDF"
|
||||
//messagesJreNotFoundError="This application requires a Java Runtime Environment, Please download Java 17."
|
||||
messagesJreVersionError="You are running the wrong version of Java, Please download Java 17."
|
||||
messagesLauncherError="Java is corrupted. Please uninstall and then install Java 17."
|
||||
messagesJreVersionError="You are running the wrong version of Java, Please download Java 21."
|
||||
messagesLauncherError="Java is corrupted. Please uninstall and then install Java 21."
|
||||
messagesInstanceAlreadyExists="Stirling-PDF is already running."
|
||||
}
|
||||
|
||||
@@ -99,6 +101,7 @@ dependencies {
|
||||
implementation 'org.springframework.boot:spring-boot-starter-security:3.2.4'
|
||||
implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity5:3.1.2.RELEASE'
|
||||
implementation "org.springframework.boot:spring-boot-starter-data-jpa:3.2.4"
|
||||
implementation 'org.springframework.boot:spring-boot-starter-oauth2-client:3.2.4'
|
||||
|
||||
//2.2.x requires rebuild of DB file.. need migration path
|
||||
implementation "com.h2database:h2:2.1.214"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
apiVersion: v2
|
||||
appVersion: 0.23.1
|
||||
appVersion: 0.24.0
|
||||
description: locally hosted web application that allows you to perform various operations
|
||||
on PDF files
|
||||
home: https://github.com/Stirling-Tools/Stirling-PDF
|
||||
|
||||
39
exampleYmlFiles/docker-compose-latest-security-with-sso.yml
Normal file
@@ -0,0 +1,39 @@
|
||||
version: '3.3'
|
||||
services:
|
||||
stirling-pdf:
|
||||
container_name: Stirling-PDF-Security
|
||||
image: frooodle/s-pdf:latest
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: 4G
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "curl -f http://localhost:8080/api/v1/info/status | grep -q 'UP' && curl -fL http://localhost:8080/ | grep -q 'Please sign in'"]
|
||||
interval: 5s
|
||||
timeout: 10s
|
||||
retries: 16
|
||||
ports:
|
||||
- 8080:8080
|
||||
volumes:
|
||||
- /stirling/latest/data:/usr/share/tessdata:rw
|
||||
- /stirling/latest/config:/configs:rw
|
||||
- /stirling/latest/logs:/logs:rw
|
||||
environment:
|
||||
DOCKER_ENABLE_SECURITY: "true"
|
||||
SECURITY_ENABLELOGIN: "true"
|
||||
SECURITY_OAUTH2_ENABLED: "true"
|
||||
SECURITY_OAUTH2_AUTOCREATEUSER: "true" # This is set to true to allow auto-creation of non-existing users in Striling-PDF
|
||||
SECURITY_OAUTH2_ISSUER: "https://accounts.google.com" # Change with any other provider that supports OpenID Connect Discovery (/.well-known/openid-configuration) end-point
|
||||
SECURITY_OAUTH2_CLIENTID: "<YOUR CLIENT ID>.apps.googleusercontent.com" # Client ID from your provider
|
||||
SECURITY_OAUTH2_CLIENTSECRET: "<YOUR CLIENT SECRET>" # Client Secret from your provider
|
||||
PUID: 1002
|
||||
PGID: 1002
|
||||
UMASK: "022"
|
||||
SYSTEM_DEFAULTLOCALE: en-US
|
||||
UI_APPNAME: Stirling-PDF
|
||||
UI_HOMEDESCRIPTION: Demo site for Stirling-PDF Latest with Security
|
||||
UI_APPNAMENAVBAR: Stirling-PDF Latest
|
||||
SYSTEM_MAXFILESIZE: "100"
|
||||
METRICS_ENABLED: "true"
|
||||
SYSTEM_GOOGLEVISIBILITY: "true"
|
||||
restart: on-failure:5
|
||||
@@ -10,49 +10,77 @@ Author: Ludy87
|
||||
Example:
|
||||
To use this script, simply run it from command line:
|
||||
$ python counter_translation.py
|
||||
"""
|
||||
import os
|
||||
""" # noqa: D205
|
||||
|
||||
import glob
|
||||
import os
|
||||
import re
|
||||
from typing import List, Tuple
|
||||
|
||||
import tomlkit
|
||||
import tomlkit.toml_file
|
||||
|
||||
|
||||
def write_readme(progress_list: List[Tuple[str, int]]) -> None:
|
||||
"""
|
||||
Updates the progress status in the README.md file based
|
||||
def convert_to_multiline(data: tomlkit.TOMLDocument) -> tomlkit.TOMLDocument:
|
||||
"""Converts 'ignore' and 'missing' arrays to multiline arrays and sorts the first-level keys of the TOML document.
|
||||
Enhances readability and consistency in the TOML file by ensuring arrays contain unique and sorted entries.
|
||||
|
||||
Parameters:
|
||||
data (tomlkit.TOMLDocument): The original TOML document containing the data.
|
||||
|
||||
Returns:
|
||||
tomlkit.TOMLDocument: A new TOML document with sorted keys and properly formatted arrays.
|
||||
""" # noqa: D205
|
||||
sorted_data = tomlkit.document()
|
||||
for key in sorted(data.keys()):
|
||||
value = data[key]
|
||||
if isinstance(value, dict):
|
||||
new_table = tomlkit.table()
|
||||
for subkey in ("ignore", "missing"):
|
||||
if subkey in value:
|
||||
# Convert the list to a set to remove duplicates, sort it, and convert to multiline for readability
|
||||
unique_sorted_array = sorted(set(value[subkey]))
|
||||
array = tomlkit.array()
|
||||
array.multiline(True)
|
||||
for item in unique_sorted_array:
|
||||
array.append(item)
|
||||
new_table[subkey] = array
|
||||
sorted_data[key] = new_table
|
||||
else:
|
||||
# Add other types of data unchanged
|
||||
sorted_data[key] = value
|
||||
return sorted_data
|
||||
|
||||
|
||||
def write_readme(progress_list: list[tuple[str, int]]) -> None:
|
||||
"""Updates the progress status in the README.md file based
|
||||
on the provided progress list.
|
||||
|
||||
Parameters:
|
||||
progress_list (List[Tuple[str, int]]): A list of tuples containing
|
||||
progress_list (list[tuple[str, int]]): A list of tuples containing
|
||||
language and progress percentage.
|
||||
|
||||
Returns:
|
||||
None
|
||||
"""
|
||||
with open("README.md", "r", encoding="utf-8") as file:
|
||||
content = file.read()
|
||||
""" # noqa: D205
|
||||
with open("README.md", encoding="utf-8") as file:
|
||||
content = file.readlines()
|
||||
|
||||
lines = content.split("\n")
|
||||
for i, line in enumerate(lines[2:], start=2):
|
||||
for i, line in enumerate(content[2:], start=2):
|
||||
for progress in progress_list:
|
||||
language, value = progress
|
||||
if language in line:
|
||||
match = re.search(r"\!\[(\d+(\.\d+)?)%\]\(.*\)", line)
|
||||
if match:
|
||||
lines[i] = line.replace(
|
||||
if match := re.search(r"\!\[(\d+(\.\d+)?)%\]\(.*\)", line):
|
||||
content[i] = line.replace(
|
||||
match.group(0),
|
||||
f"",
|
||||
)
|
||||
|
||||
new_content = "\n".join(lines)
|
||||
|
||||
with open("README.md", "w", encoding="utf-8") as file:
|
||||
file.write(new_content)
|
||||
file.writelines(content)
|
||||
|
||||
|
||||
def compare_files(default_file_path, files_directory) -> List[Tuple[str, int]]:
|
||||
"""
|
||||
Compares the default properties file with other
|
||||
def compare_files(default_file_path, file_paths, translation_status_file) -> list[tuple[str, int]]:
|
||||
"""Compares the default properties file with other
|
||||
properties files in the directory.
|
||||
|
||||
Parameters:
|
||||
@@ -60,20 +88,22 @@ def compare_files(default_file_path, files_directory) -> List[Tuple[str, int]]:
|
||||
files_directory (str): The directory containing other properties files.
|
||||
|
||||
Returns:
|
||||
List[Tuple[str, int]]: A list of tuples containing
|
||||
list[tuple[str, int]]: A list of tuples containing
|
||||
language and progress percentage.
|
||||
"""
|
||||
file_paths = glob.glob(os.path.join(files_directory, "messages_*.properties"))
|
||||
num_lines = sum(1 for _ in open(default_file_path, encoding="utf-8"))
|
||||
""" # noqa: D205
|
||||
num_lines = sum(
|
||||
1 for line in open(default_file_path, encoding="utf-8") if line.strip() and not line.strip().startswith("#")
|
||||
)
|
||||
|
||||
result_list = []
|
||||
sort_translation_status: tomlkit.TOMLDocument
|
||||
|
||||
# read toml
|
||||
with open(translation_status_file, encoding="utf-8") as f:
|
||||
sort_translation_status = tomlkit.parse(f.read())
|
||||
|
||||
for file_path in file_paths:
|
||||
language = (
|
||||
os.path.basename(file_path)
|
||||
.split("messages_", 1)[1]
|
||||
.split(".properties", 1)[0]
|
||||
)
|
||||
language = os.path.basename(file_path).split("messages_", 1)[1].split(".properties", 1)[0]
|
||||
|
||||
fails = 0
|
||||
if "en_GB" in language or "en_US" in language:
|
||||
@@ -81,9 +111,21 @@ def compare_files(default_file_path, files_directory) -> List[Tuple[str, int]]:
|
||||
result_list.append(("en_US", 100))
|
||||
continue
|
||||
|
||||
with open(default_file_path, "r", encoding="utf-8") as default_file, open(
|
||||
file_path, "r", encoding="utf-8"
|
||||
) as file:
|
||||
if language not in sort_translation_status:
|
||||
sort_translation_status[language] = tomlkit.table()
|
||||
|
||||
if (
|
||||
"ignore" not in sort_translation_status[language]
|
||||
or len(sort_translation_status[language].get("ignore", [])) < 1
|
||||
):
|
||||
sort_translation_status[language]["ignore"] = tomlkit.array(["language.direction"])
|
||||
|
||||
# if "missing" not in sort_translation_status[language]:
|
||||
# sort_translation_status[language]["missing"] = tomlkit.array()
|
||||
# elif "language.direction" in sort_translation_status[language]["missing"]:
|
||||
# sort_translation_status[language]["missing"].remove("language.direction")
|
||||
|
||||
with open(default_file_path, encoding="utf-8") as default_file, open(file_path, encoding="utf-8") as file:
|
||||
for _ in range(5):
|
||||
next(default_file)
|
||||
try:
|
||||
@@ -91,24 +133,47 @@ def compare_files(default_file_path, files_directory) -> List[Tuple[str, int]]:
|
||||
except StopIteration:
|
||||
fails = num_lines
|
||||
|
||||
for _, (line_default, line_file) in enumerate(
|
||||
zip(default_file, file), start=6
|
||||
):
|
||||
for line_num, (line_default, line_file) in enumerate(zip(default_file, file), start=6):
|
||||
try:
|
||||
# Ignoring empty lines and lines start with #
|
||||
if line_default.strip() == "" or line_default.startswith("#"):
|
||||
continue
|
||||
|
||||
default_key, default_value = line_default.split("=", 1)
|
||||
file_key, file_value = line_file.split("=", 1)
|
||||
if (
|
||||
line_default.split("=", 1)[1].strip()
|
||||
== line_file.split("=", 1)[1].strip()
|
||||
default_value.strip() == file_value.strip()
|
||||
and default_key.strip() not in sort_translation_status[language]["ignore"]
|
||||
):
|
||||
print(f"{language}: Line {line_num} is missing the translation.")
|
||||
# if default_key.strip() not in sort_translation_status[language]["missing"]:
|
||||
# missing_array = tomlkit.array()
|
||||
# missing_array.append(default_key.strip())
|
||||
# missing_array.multiline(True)
|
||||
# sort_translation_status[language]["missing"].extend(missing_array)
|
||||
fails += 1
|
||||
# elif default_key.strip() in sort_translation_status[language]["ignore"]:
|
||||
# if default_key.strip() in sort_translation_status[language]["missing"]:
|
||||
# sort_translation_status[language]["missing"].remove(default_key.strip())
|
||||
if default_value.strip() != file_value.strip():
|
||||
# if default_key.strip() in sort_translation_status[language]["missing"]:
|
||||
# sort_translation_status[language]["missing"].remove(default_key.strip())
|
||||
if default_key.strip() in sort_translation_status[language]["ignore"]:
|
||||
sort_translation_status[language]["ignore"].remove(default_key.strip())
|
||||
|
||||
except IndexError:
|
||||
pass
|
||||
|
||||
print(f"{language}: {fails} out of {num_lines} lines are not translated.")
|
||||
result_list.append(
|
||||
(
|
||||
language,
|
||||
int((num_lines - fails) * 100 / num_lines),
|
||||
)
|
||||
)
|
||||
translation_status = convert_to_multiline(sort_translation_status)
|
||||
with open(translation_status_file, "w", encoding="utf-8") as file:
|
||||
file.write(tomlkit.dumps(translation_status))
|
||||
|
||||
unique_data = list(set(result_list))
|
||||
unique_data.sort(key=lambda x: x[1], reverse=True)
|
||||
@@ -118,5 +183,10 @@ def compare_files(default_file_path, files_directory) -> List[Tuple[str, int]]:
|
||||
|
||||
if __name__ == "__main__":
|
||||
directory = os.path.join(os.getcwd(), "src", "main", "resources")
|
||||
messages_file_paths = glob.glob(os.path.join(directory, "messages_*.properties"))
|
||||
reference_file = os.path.join(directory, "messages_en_GB.properties")
|
||||
write_readme(compare_files(reference_file, directory))
|
||||
|
||||
scripts_directory = os.path.join(os.getcwd(), "scripts")
|
||||
translation_state_file = os.path.join(scripts_directory, "translation_status.toml")
|
||||
|
||||
write_readme(compare_files(reference_file, messages_file_paths, translation_state_file))
|
||||
|
||||
159
scripts/translation_status.toml
Normal file
@@ -0,0 +1,159 @@
|
||||
[ar_AR]
|
||||
ignore = [
|
||||
'language.direction',
|
||||
]
|
||||
|
||||
[bg_BG]
|
||||
ignore = [
|
||||
'language.direction',
|
||||
]
|
||||
|
||||
[ca_CA]
|
||||
ignore = [
|
||||
'language.direction',
|
||||
]
|
||||
|
||||
[de_DE]
|
||||
ignore = [
|
||||
'AddStampRequest.alphabet',
|
||||
'AddStampRequest.position',
|
||||
'PDFToBook.selectText.1',
|
||||
'PDFToText.tags',
|
||||
'addPageNumbers.selectText.3',
|
||||
'alphabet',
|
||||
'certSign.name',
|
||||
'language.direction',
|
||||
'licenses.version',
|
||||
'pipeline.title',
|
||||
'pipelineOptions.pipelineHeader',
|
||||
'sponsor',
|
||||
'text',
|
||||
'watermark.type.1',
|
||||
]
|
||||
|
||||
[el_GR]
|
||||
ignore = [
|
||||
'language.direction',
|
||||
]
|
||||
|
||||
[es_ES]
|
||||
ignore = [
|
||||
'adminUserSettings.roles',
|
||||
'color',
|
||||
'language.direction',
|
||||
'no',
|
||||
'showJS.tags',
|
||||
]
|
||||
|
||||
[eu_ES]
|
||||
ignore = [
|
||||
'language.direction',
|
||||
]
|
||||
|
||||
[fr_FR]
|
||||
ignore = [
|
||||
'language.direction',
|
||||
]
|
||||
|
||||
[hi_IN]
|
||||
ignore = [
|
||||
'language.direction',
|
||||
]
|
||||
|
||||
[hu_HU]
|
||||
ignore = [
|
||||
'language.direction',
|
||||
]
|
||||
|
||||
[id_ID]
|
||||
ignore = [
|
||||
'language.direction',
|
||||
]
|
||||
|
||||
[it_IT]
|
||||
ignore = [
|
||||
'font',
|
||||
'language.direction',
|
||||
'no',
|
||||
'password',
|
||||
'pipeline.title',
|
||||
'pipelineOptions.pipelineHeader',
|
||||
'removePassword.selectText.2',
|
||||
'showJS.tags',
|
||||
'sponsor',
|
||||
]
|
||||
|
||||
[ja_JP]
|
||||
ignore = [
|
||||
'language.direction',
|
||||
]
|
||||
|
||||
[ko_KR]
|
||||
ignore = [
|
||||
'language.direction',
|
||||
]
|
||||
|
||||
[nl_NL]
|
||||
ignore = [
|
||||
'language.direction',
|
||||
]
|
||||
|
||||
[pl_PL]
|
||||
ignore = [
|
||||
'language.direction',
|
||||
]
|
||||
|
||||
[pt_BR]
|
||||
ignore = [
|
||||
'language.direction',
|
||||
]
|
||||
|
||||
[pt_PT]
|
||||
ignore = [
|
||||
'language.direction',
|
||||
]
|
||||
|
||||
[ro_RO]
|
||||
ignore = [
|
||||
'language.direction',
|
||||
]
|
||||
|
||||
[ru_RU]
|
||||
ignore = [
|
||||
'language.direction',
|
||||
]
|
||||
|
||||
[sk_SK]
|
||||
ignore = [
|
||||
'language.direction',
|
||||
]
|
||||
|
||||
[sr_LATN_RS]
|
||||
ignore = [
|
||||
'language.direction',
|
||||
]
|
||||
|
||||
[sv_SE]
|
||||
ignore = [
|
||||
'language.direction',
|
||||
]
|
||||
|
||||
[tr_TR]
|
||||
ignore = [
|
||||
'language.direction',
|
||||
]
|
||||
|
||||
[uk_UA]
|
||||
ignore = [
|
||||
'language.direction',
|
||||
]
|
||||
|
||||
[zh_CN]
|
||||
ignore = [
|
||||
'language.direction',
|
||||
]
|
||||
|
||||
[zh_TW]
|
||||
ignore = [
|
||||
'language.direction',
|
||||
]
|
||||
@@ -5,6 +5,8 @@ import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -65,14 +67,36 @@ public class SPdfApplication {
|
||||
|
||||
SpringApplication app = new SpringApplication(SPdfApplication.class);
|
||||
app.addInitializers(new ConfigInitializer());
|
||||
Map<String, String> propertyFiles = new HashMap<>();
|
||||
|
||||
// stirling pdf settings file
|
||||
if (Files.exists(Paths.get("configs/settings.yml"))) {
|
||||
app.setDefaultProperties(
|
||||
Collections.singletonMap(
|
||||
"spring.config.additional-location", "file:configs/settings.yml"));
|
||||
propertyFiles.put("spring.config.additional-location", "file:configs/settings.yml");
|
||||
} else {
|
||||
logger.warn(
|
||||
"External configuration file 'configs/settings.yml' does not exist. Using default configuration and environment configuration instead.");
|
||||
}
|
||||
|
||||
// custom javs settings file
|
||||
if (Files.exists(Paths.get("configs/custom_settings.yml"))) {
|
||||
String existing = propertyFiles.getOrDefault("spring.config.additional-location", "");
|
||||
if (!existing.isEmpty()) {
|
||||
existing += ",";
|
||||
}
|
||||
propertyFiles.put(
|
||||
"spring.config.additional-location",
|
||||
existing + "file:configs/custom_settings.yml");
|
||||
} else {
|
||||
logger.warn("Custom configuration file 'configs/custom_settings.yml' does not exist.");
|
||||
}
|
||||
|
||||
if (!propertyFiles.isEmpty()) {
|
||||
app.setDefaultProperties(
|
||||
Collections.singletonMap(
|
||||
"spring.config.additional-location",
|
||||
propertyFiles.get("spring.config.additional-location")));
|
||||
}
|
||||
|
||||
app.run(args);
|
||||
|
||||
try {
|
||||
|
||||
@@ -15,7 +15,14 @@ public class CleanUrlInterceptor implements HandlerInterceptor {
|
||||
|
||||
private static final List<String> ALLOWED_PARAMS =
|
||||
Arrays.asList(
|
||||
"lang", "endpoint", "endpoints", "logout", "error", "file", "messageType");
|
||||
"lang",
|
||||
"endpoint",
|
||||
"endpoints",
|
||||
"logout",
|
||||
"error",
|
||||
"erroroauth",
|
||||
"file",
|
||||
"messageType");
|
||||
|
||||
@Override
|
||||
public boolean preHandle(
|
||||
|
||||
@@ -1,20 +1,18 @@
|
||||
package stirling.software.SPDF.config;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.context.ApplicationContextInitializer;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
@@ -26,12 +24,12 @@ public class ConfigInitializer
|
||||
public void initialize(ConfigurableApplicationContext applicationContext) {
|
||||
try {
|
||||
ensureConfigExists();
|
||||
} catch (IOException e) {
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Failed to initialize application configuration", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void ensureConfigExists() throws IOException {
|
||||
public void ensureConfigExists() throws IOException, URISyntaxException {
|
||||
// Define the path to the external config directory
|
||||
Path destPath = Paths.get("configs", "settings.yml");
|
||||
|
||||
@@ -51,170 +49,90 @@ public class ConfigInitializer
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// If user file exists, we need to merge it with the template from the classpath
|
||||
List<String> templateLines;
|
||||
try (InputStream in =
|
||||
getClass().getClassLoader().getResourceAsStream("settings.yml.template")) {
|
||||
templateLines =
|
||||
new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8))
|
||||
.lines()
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
Path templatePath =
|
||||
Paths.get(
|
||||
getClass()
|
||||
.getClassLoader()
|
||||
.getResource("settings.yml.template")
|
||||
.toURI());
|
||||
Path userPath = Paths.get("configs", "settings.yml");
|
||||
|
||||
mergeYamlFiles(templateLines, destPath, destPath);
|
||||
}
|
||||
}
|
||||
List<String> templateLines = Files.readAllLines(templatePath);
|
||||
List<String> userLines =
|
||||
Files.exists(userPath) ? Files.readAllLines(userPath) : new ArrayList<>();
|
||||
|
||||
public void mergeYamlFiles(List<String> templateLines, Path userFilePath, Path outputPath)
|
||||
throws IOException {
|
||||
List<String> userLines = Files.readAllLines(userFilePath);
|
||||
List<String> mergedLines = new ArrayList<>();
|
||||
boolean insideAutoGenerated = false;
|
||||
boolean beforeFirstKey = true;
|
||||
List<String> resultLines = new ArrayList<>();
|
||||
|
||||
Function<String, Boolean> isCommented = line -> line.trim().startsWith("#");
|
||||
Function<String, String> extractKey =
|
||||
line -> {
|
||||
String[] parts = line.split(":");
|
||||
return parts.length > 0 ? parts[0].trim().replace("#", "").trim() : "";
|
||||
};
|
||||
|
||||
Function<String, Integer> getIndentationLevel =
|
||||
line -> {
|
||||
int count = 0;
|
||||
for (char ch : line.toCharArray()) {
|
||||
if (ch == ' ') count++;
|
||||
else break;
|
||||
for (String templateLine : templateLines) {
|
||||
// Check if the line is a comment
|
||||
if (templateLine.trim().startsWith("#")) {
|
||||
String entry = templateLine.trim().substring(1).trim();
|
||||
if (!entry.isEmpty()) {
|
||||
// Check if this comment has been uncommented in userLines
|
||||
String key = entry.split(":")[0].trim();
|
||||
System.out.println("key=" + key + ", entry=" + entry );
|
||||
addLine(resultLines, userLines, templateLine, key);
|
||||
} else {
|
||||
resultLines.add(templateLine);
|
||||
}
|
||||
return count;
|
||||
};
|
||||
|
||||
Set<String> userKeys = userLines.stream().map(extractKey).collect(Collectors.toSet());
|
||||
|
||||
for (String line : templateLines) {
|
||||
String key = extractKey.apply(line);
|
||||
|
||||
if ("AutomaticallyGenerated:".equalsIgnoreCase(line.trim())) {
|
||||
insideAutoGenerated = true;
|
||||
mergedLines.add(line);
|
||||
continue;
|
||||
} else if (insideAutoGenerated && line.trim().isEmpty()) {
|
||||
insideAutoGenerated = false;
|
||||
mergedLines.add(line);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (beforeFirstKey && (isCommented.apply(line) || line.trim().isEmpty())) {
|
||||
// Handle top comments and empty lines before the first key.
|
||||
mergedLines.add(line);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!key.isEmpty()) beforeFirstKey = false;
|
||||
|
||||
if (userKeys.contains(key)) {
|
||||
// If user has any version (commented or uncommented) of this key, skip the
|
||||
// template line
|
||||
Optional<String> userValue =
|
||||
userLines.stream()
|
||||
.filter(
|
||||
l ->
|
||||
extractKey.apply(l).equalsIgnoreCase(key)
|
||||
&& !isCommented.apply(l))
|
||||
.findFirst();
|
||||
if (userValue.isPresent()) mergedLines.add(userValue.get());
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isCommented.apply(line) || line.trim().isEmpty() || !userKeys.contains(key)) {
|
||||
mergedLines.add(
|
||||
line); // If line is commented, empty or key not present in user's file,
|
||||
// retain the
|
||||
// template line
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Add any additional uncommented user lines that are not present in the
|
||||
// template
|
||||
for (String userLine : userLines) {
|
||||
String userKey = extractKey.apply(userLine);
|
||||
boolean isPresentInTemplate =
|
||||
templateLines.stream()
|
||||
.map(extractKey)
|
||||
.anyMatch(templateKey -> templateKey.equalsIgnoreCase(userKey));
|
||||
if (!isPresentInTemplate && !isCommented.apply(userLine)) {
|
||||
if (!childOfTemplateEntry(
|
||||
isCommented,
|
||||
extractKey,
|
||||
getIndentationLevel,
|
||||
userLines,
|
||||
userLine,
|
||||
templateLines)) {
|
||||
// check if userLine is a child of a entry within templateLines or not, if child
|
||||
// of parent in templateLines then dont add to mergedLines, if anything else
|
||||
// then add
|
||||
mergedLines.add(userLine);
|
||||
}
|
||||
// Check if the line is a key-value pair
|
||||
else if (templateLine.contains(":")) {
|
||||
String key = templateLine.split(":")[0].trim();
|
||||
addLine(resultLines, userLines, templateLine, key);
|
||||
}
|
||||
// Handle empty lines
|
||||
else if (templateLine.trim().length() == 0) {
|
||||
resultLines.add("");
|
||||
}
|
||||
}
|
||||
|
||||
// Write the result to the user settings file
|
||||
Files.write(userPath, resultLines);
|
||||
}
|
||||
|
||||
Files.write(outputPath, mergedLines, StandardCharsets.UTF_8);
|
||||
Path customSettingsPath = Paths.get("configs", "custom_settings.yml");
|
||||
if (!Files.exists(customSettingsPath)) {
|
||||
Files.createFile(customSettingsPath);
|
||||
}
|
||||
}
|
||||
|
||||
// New method to check if a userLine is a child of an entry in templateLines
|
||||
boolean childOfTemplateEntry(
|
||||
Function<String, Boolean> isCommented,
|
||||
Function<String, String> extractKey,
|
||||
Function<String, Integer> getIndentationLevel,
|
||||
List<String> userLines,
|
||||
String userLine,
|
||||
List<String> templateLines) {
|
||||
String userKey = extractKey.apply(userLine).trim();
|
||||
int userIndentation = getIndentationLevel.apply(userLine);
|
||||
|
||||
// Start by assuming the line is not a child of an entry in templateLines
|
||||
boolean isChild = false;
|
||||
|
||||
// Iterate backwards through userLines from the current line to find any parent
|
||||
for (int i = userLines.indexOf(userLine) - 1; i >= 0; i--) {
|
||||
String potentialParentLine = userLines.get(i);
|
||||
int parentIndentation = getIndentationLevel.apply(potentialParentLine);
|
||||
|
||||
// Check if we've reached a potential parent based on indentation
|
||||
if (parentIndentation < userIndentation) {
|
||||
String parentKey = extractKey.apply(potentialParentLine).trim();
|
||||
|
||||
// Now, check if this potential parent or any of its parents exist in templateLines
|
||||
boolean parentExistsInTemplate =
|
||||
templateLines.stream()
|
||||
.filter(line -> !isCommented.apply(line)) // Skip commented lines
|
||||
.anyMatch(
|
||||
templateLine -> {
|
||||
String templateKey =
|
||||
extractKey.apply(templateLine).trim();
|
||||
return parentKey.equalsIgnoreCase(templateKey);
|
||||
});
|
||||
|
||||
if (!parentExistsInTemplate) {
|
||||
// If the parent does not exist in template, check the next level parent
|
||||
userIndentation =
|
||||
parentIndentation; // Update userIndentation to the parent's indentation
|
||||
// for next iteration
|
||||
if (parentIndentation == 0) {
|
||||
// If we've reached the top-level parent and it's not in template, the
|
||||
// original line is considered not a child
|
||||
isChild = false;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// If any parent exists in template, the original line is considered a child
|
||||
isChild = true;
|
||||
|
||||
|
||||
|
||||
//TODO check parent value instead of just indent lines for duplicate keys (like enabled etc)
|
||||
private static void addLine(List<String> resultLines, List<String> userLines, String templateLine, String key) {
|
||||
boolean added = false;
|
||||
int templateIndentationLevel = getIndentationLevel(templateLine);
|
||||
for (String settingsLine : userLines) {
|
||||
if(settingsLine.contains("oauth2") || settingsLine.contains("enabled") )
|
||||
if (settingsLine.trim().startsWith(key + ":")) {
|
||||
int settingsIndentationLevel = getIndentationLevel(settingsLine);
|
||||
// Check if it is correct settingsLine and has the same parent as templateLine
|
||||
if (settingsIndentationLevel == templateIndentationLevel) {
|
||||
resultLines.add(settingsLine);
|
||||
added = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!added) {
|
||||
resultLines.add(templateLine);
|
||||
}
|
||||
}
|
||||
|
||||
return isChild; // Return true if the line is not a child of any entry in templateLines
|
||||
private static int getIndentationLevel(String line) {
|
||||
int indentationLevel = 0;
|
||||
String trimmedLine = line.trim();
|
||||
if (trimmedLine.startsWith("#")) {
|
||||
line = trimmedLine.substring(1);
|
||||
}
|
||||
for (char c : line.toCharArray()) {
|
||||
if (c == ' ') {
|
||||
indentationLevel++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return indentationLevel;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ public class FileFallbackTemplateResolver extends AbstractConfigurableTemplateRe
|
||||
return new FileTemplateResource(resource.getFile().getPath(), characterEncoding);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
|
||||
|
||||
}
|
||||
|
||||
return new ClassLoaderTemplateResource(
|
||||
|
||||
@@ -3,27 +3,31 @@ package stirling.software.SPDF.config.security;
|
||||
import java.io.IOException;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.security.authentication.BadCredentialsException;
|
||||
import org.springframework.security.authentication.InternalAuthenticationServiceException;
|
||||
import org.springframework.security.authentication.LockedException;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import stirling.software.SPDF.model.User;
|
||||
|
||||
@Component
|
||||
public class CustomAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler {
|
||||
|
||||
@Autowired private final LoginAttemptService loginAttemptService;
|
||||
private LoginAttemptService loginAttemptService;
|
||||
|
||||
@Autowired private final UserService userService; // Inject the UserService
|
||||
private UserService userService;
|
||||
|
||||
private static final Logger logger =
|
||||
LoggerFactory.getLogger(CustomAuthenticationFailureHandler.class);
|
||||
|
||||
public CustomAuthenticationFailureHandler(
|
||||
LoginAttemptService loginAttemptService, UserService userService) {
|
||||
final LoginAttemptService loginAttemptService, UserService userService) {
|
||||
this.loginAttemptService = loginAttemptService;
|
||||
this.userService = userService;
|
||||
}
|
||||
@@ -34,22 +38,33 @@ public class CustomAuthenticationFailureHandler extends SimpleUrlAuthenticationF
|
||||
HttpServletResponse response,
|
||||
AuthenticationException exception)
|
||||
throws IOException, ServletException {
|
||||
|
||||
String ip = request.getRemoteAddr();
|
||||
logger.error("Failed login attempt from IP: " + ip);
|
||||
logger.error("Failed login attempt from IP: {}", ip);
|
||||
|
||||
if (exception.getClass().isAssignableFrom(InternalAuthenticationServiceException.class)
|
||||
|| "Password must not be null".equalsIgnoreCase(exception.getMessage())) {
|
||||
response.sendRedirect("/login?error=oauth2AuthenticationError");
|
||||
return;
|
||||
}
|
||||
|
||||
String username = request.getParameter("username");
|
||||
if (!isDemoUser(username)) {
|
||||
if (loginAttemptService.loginAttemptCheck(username)) {
|
||||
setDefaultFailureUrl("/login?error=locked");
|
||||
|
||||
} else {
|
||||
if (exception.getClass().isAssignableFrom(LockedException.class)) {
|
||||
setDefaultFailureUrl("/login?error=locked");
|
||||
}
|
||||
if (username != null && !isDemoUser(username)) {
|
||||
logger.info(
|
||||
"Remaining attempts for user {}: {}",
|
||||
username,
|
||||
loginAttemptService.getRemainingAttempts(username));
|
||||
loginAttemptService.loginFailed(username);
|
||||
if (loginAttemptService.isBlocked(username)
|
||||
|| exception.getClass().isAssignableFrom(LockedException.class)) {
|
||||
response.sendRedirect("/login?error=locked");
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (exception.getClass().isAssignableFrom(BadCredentialsException.class)) {
|
||||
setDefaultFailureUrl("/login?error=badcredentials");
|
||||
if (exception.getClass().isAssignableFrom(BadCredentialsException.class)
|
||||
|| exception.getClass().isAssignableFrom(UsernameNotFoundException.class)) {
|
||||
response.sendRedirect("/login?error=badcredentials");
|
||||
return;
|
||||
}
|
||||
|
||||
super.onAuthenticationFailure(request, response, exception);
|
||||
|
||||
@@ -2,11 +2,9 @@ package stirling.software.SPDF.config.security;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
|
||||
import org.springframework.security.web.savedrequest.SavedRequest;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
@@ -14,25 +12,30 @@ import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.servlet.http.HttpSession;
|
||||
import stirling.software.SPDF.utils.RequestUriUtils;
|
||||
|
||||
@Component
|
||||
public class CustomAuthenticationSuccessHandler
|
||||
extends SavedRequestAwareAuthenticationSuccessHandler {
|
||||
|
||||
@Autowired private LoginAttemptService loginAttemptService;
|
||||
private LoginAttemptService loginAttemptService;
|
||||
|
||||
public CustomAuthenticationSuccessHandler(LoginAttemptService loginAttemptService) {
|
||||
this.loginAttemptService = loginAttemptService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAuthenticationSuccess(
|
||||
HttpServletRequest request, HttpServletResponse response, Authentication authentication)
|
||||
throws ServletException, IOException {
|
||||
String username = request.getParameter("username");
|
||||
loginAttemptService.loginSucceeded(username);
|
||||
|
||||
String userName = request.getParameter("username");
|
||||
loginAttemptService.loginSucceeded(userName);
|
||||
|
||||
// Get the saved request
|
||||
HttpSession session = request.getSession(false);
|
||||
SavedRequest savedRequest =
|
||||
session != null
|
||||
(session != null)
|
||||
? (SavedRequest) session.getAttribute("SPRING_SECURITY_SAVED_REQUEST")
|
||||
: null;
|
||||
|
||||
if (savedRequest != null
|
||||
&& !RequestUriUtils.isStaticResource(savedRequest.getRedirectUrl())) {
|
||||
// Redirect to the original destination
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
package stirling.software.SPDF.config.security;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.session.SessionRegistry;
|
||||
import org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler;
|
||||
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.servlet.http.HttpSession;
|
||||
|
||||
public class CustomLogoutSuccessHandler extends SimpleUrlLogoutSuccessHandler {
|
||||
|
||||
@Autowired SessionRegistry sessionRegistry;
|
||||
|
||||
@Override
|
||||
public void onLogoutSuccess(
|
||||
HttpServletRequest request, HttpServletResponse response, Authentication authentication)
|
||||
throws IOException, ServletException {
|
||||
HttpSession session = request.getSession(false);
|
||||
if (session != null) {
|
||||
String sessionId = session.getId();
|
||||
sessionRegistry.removeSessionInformation(sessionId);
|
||||
session.invalidate();
|
||||
logger.debug("Session invalidated: " + sessionId);
|
||||
}
|
||||
|
||||
response.sendRedirect(request.getContextPath() + "/login?logout=true");
|
||||
}
|
||||
}
|
||||
@@ -39,6 +39,10 @@ public class CustomUserDetailsService implements UserDetailsService {
|
||||
"Your account has been locked due to too many failed login attempts.");
|
||||
}
|
||||
|
||||
if (!user.hasPassword()) {
|
||||
throw new IllegalArgumentException("Password must not be null");
|
||||
}
|
||||
|
||||
return new org.springframework.security.core.userdetails.User(
|
||||
user.getUsername(),
|
||||
user.getPassword(),
|
||||
|
||||
@@ -7,6 +7,8 @@ import java.nio.file.Paths;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@@ -19,40 +21,67 @@ public class InitialSecuritySetup {
|
||||
|
||||
@Autowired private UserService userService;
|
||||
|
||||
@Autowired ApplicationProperties applicationProperties;
|
||||
@Autowired private ApplicationProperties applicationProperties;
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(InitialSecuritySetup.class);
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
if (!userService.hasUsers()) {
|
||||
|
||||
String initialUsername =
|
||||
applicationProperties.getSecurity().getInitialLogin().getUsername();
|
||||
String initialPassword =
|
||||
applicationProperties.getSecurity().getInitialLogin().getPassword();
|
||||
if (initialUsername != null && initialPassword != null) {
|
||||
userService.saveUser(initialUsername, initialPassword, Role.ADMIN.getRoleId());
|
||||
} else {
|
||||
initialUsername = "admin";
|
||||
initialPassword = "stirling";
|
||||
userService.saveUser(
|
||||
initialUsername, initialPassword, Role.ADMIN.getRoleId(), true);
|
||||
}
|
||||
initializeAdminUser();
|
||||
}
|
||||
initializeInternalApiUser();
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void initSecretKey() throws IOException {
|
||||
String secretKey = applicationProperties.getAutomaticallyGenerated().getKey();
|
||||
if (!isValidUUID(secretKey)) {
|
||||
secretKey = UUID.randomUUID().toString(); // Generating a random UUID as the secret key
|
||||
saveKeyToConfig(secretKey);
|
||||
}
|
||||
}
|
||||
|
||||
private void initializeAdminUser() {
|
||||
String initialUsername =
|
||||
applicationProperties.getSecurity().getInitialLogin().getUsername();
|
||||
String initialPassword =
|
||||
applicationProperties.getSecurity().getInitialLogin().getPassword();
|
||||
|
||||
if (initialUsername != null
|
||||
&& !initialUsername.isEmpty()
|
||||
&& initialPassword != null
|
||||
&& !initialPassword.isEmpty()
|
||||
&& !userService.findByUsernameIgnoreCase(initialUsername).isPresent()) {
|
||||
try {
|
||||
userService.saveUser(initialUsername, initialPassword, Role.ADMIN.getRoleId());
|
||||
logger.info("Admin user created: " + initialUsername);
|
||||
} catch (IllegalArgumentException e) {
|
||||
logger.error("Failed to initialize security setup", e);
|
||||
System.exit(1);
|
||||
}
|
||||
} else {
|
||||
createDefaultAdminUser();
|
||||
}
|
||||
}
|
||||
|
||||
private void createDefaultAdminUser() {
|
||||
String defaultUsername = "admin";
|
||||
String defaultPassword = "stirling";
|
||||
if (!userService.findByUsernameIgnoreCase(defaultUsername).isPresent()) {
|
||||
userService.saveUser(defaultUsername, defaultPassword, Role.ADMIN.getRoleId(), true);
|
||||
logger.info("Default admin user created: " + defaultUsername);
|
||||
}
|
||||
}
|
||||
|
||||
private void initializeInternalApiUser() {
|
||||
if (!userService.usernameExistsIgnoreCase(Role.INTERNAL_API_USER.getRoleId())) {
|
||||
userService.saveUser(
|
||||
Role.INTERNAL_API_USER.getRoleId(),
|
||||
UUID.randomUUID().toString(),
|
||||
Role.INTERNAL_API_USER.getRoleId());
|
||||
userService.addApiKeyToUser(Role.INTERNAL_API_USER.getRoleId());
|
||||
}
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void initSecretKey() throws IOException {
|
||||
String secretKey = applicationProperties.getAutomaticallyGenerated().getKey();
|
||||
if (secretKey == null || secretKey.isEmpty()) {
|
||||
secretKey = UUID.randomUUID().toString(); // Generating a random UUID as the secret key
|
||||
saveKeyToConfig(secretKey);
|
||||
logger.info("Internal API user created: " + Role.INTERNAL_API_USER.getRoleId());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,4 +114,16 @@ public class InitialSecuritySetup {
|
||||
// Write back to the file
|
||||
Files.write(path, lines);
|
||||
}
|
||||
|
||||
private boolean isValidUUID(String uuid) {
|
||||
if (uuid == null) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
UUID.fromString(uuid);
|
||||
return true;
|
||||
} catch (IllegalArgumentException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@ package stirling.software.SPDF.config.security;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@@ -15,44 +17,62 @@ public class LoginAttemptService {
|
||||
|
||||
@Autowired ApplicationProperties applicationProperties;
|
||||
|
||||
private int MAX_ATTEMPTS;
|
||||
private static final Logger logger = LoggerFactory.getLogger(LoginAttemptService.class);
|
||||
|
||||
private int MAX_ATTEMPT;
|
||||
private long ATTEMPT_INCREMENT_TIME;
|
||||
private ConcurrentHashMap<String, AttemptCounter> attemptsCache;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
MAX_ATTEMPTS = applicationProperties.getSecurity().getLoginAttemptCount();
|
||||
MAX_ATTEMPT = applicationProperties.getSecurity().getLoginAttemptCount();
|
||||
ATTEMPT_INCREMENT_TIME =
|
||||
TimeUnit.MINUTES.toMillis(
|
||||
applicationProperties.getSecurity().getLoginResetTimeMinutes());
|
||||
attemptsCache = new ConcurrentHashMap<>();
|
||||
}
|
||||
|
||||
private final ConcurrentHashMap<String, AttemptCounter> attemptsCache =
|
||||
new ConcurrentHashMap<>();
|
||||
|
||||
public void loginSucceeded(String key) {
|
||||
attemptsCache.remove(key);
|
||||
logger.info(key + " " + attemptsCache.mappingCount());
|
||||
if (key == null || key.trim().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
attemptsCache.remove(key.toLowerCase());
|
||||
}
|
||||
|
||||
public boolean loginAttemptCheck(String key) {
|
||||
attemptsCache.compute(
|
||||
key,
|
||||
(k, attemptCounter) -> {
|
||||
if (attemptCounter == null
|
||||
|| attemptCounter.shouldReset(ATTEMPT_INCREMENT_TIME)) {
|
||||
return new AttemptCounter();
|
||||
} else {
|
||||
attemptCounter.increment();
|
||||
return attemptCounter;
|
||||
}
|
||||
});
|
||||
return attemptsCache.get(key).getAttemptCount() >= MAX_ATTEMPTS;
|
||||
public void loginFailed(String key) {
|
||||
if (key == null || key.trim().isEmpty()) return;
|
||||
|
||||
AttemptCounter attemptCounter = attemptsCache.get(key.toLowerCase());
|
||||
if (attemptCounter == null) {
|
||||
attemptCounter = new AttemptCounter();
|
||||
attemptsCache.put(key.toLowerCase(), attemptCounter);
|
||||
} else {
|
||||
if (attemptCounter.shouldReset(ATTEMPT_INCREMENT_TIME)) {
|
||||
attemptCounter.reset();
|
||||
}
|
||||
attemptCounter.increment();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isBlocked(String key) {
|
||||
AttemptCounter attemptCounter = attemptsCache.get(key);
|
||||
if (attemptCounter != null) {
|
||||
return attemptCounter.getAttemptCount() >= MAX_ATTEMPTS;
|
||||
if (key == null || key.trim().isEmpty()) return false;
|
||||
AttemptCounter attemptCounter = attemptsCache.get(key.toLowerCase());
|
||||
if (attemptCounter == null) {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
|
||||
return attemptCounter.getAttemptCount() >= MAX_ATTEMPT;
|
||||
}
|
||||
|
||||
public int getRemainingAttempts(String key) {
|
||||
if (key == null || key.trim().isEmpty()) return MAX_ATTEMPT;
|
||||
|
||||
AttemptCounter attemptCounter = attemptsCache.get(key.toLowerCase());
|
||||
if (attemptCounter == null) {
|
||||
return MAX_ATTEMPT;
|
||||
}
|
||||
|
||||
return MAX_ATTEMPT - attemptCounter.getAttemptCount();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
package stirling.software.SPDF.config.security;
|
||||
|
||||
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;
|
||||
@@ -10,18 +13,31 @@ import org.springframework.security.config.annotation.method.configuration.Enabl
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
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.core.session.SessionRegistry;
|
||||
import org.springframework.security.core.session.SessionRegistryImpl;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
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.web.SecurityFilterChain;
|
||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
|
||||
import org.springframework.security.web.savedrequest.NullRequestCache;
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||
|
||||
import jakarta.servlet.http.HttpSession;
|
||||
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.model.ApplicationProperties;
|
||||
import stirling.software.SPDF.model.ApplicationProperties.Security.OAUTH2;
|
||||
import stirling.software.SPDF.model.User;
|
||||
import stirling.software.SPDF.repository.JPATokenRepositoryImpl;
|
||||
|
||||
@Configuration
|
||||
@@ -29,7 +45,7 @@ import stirling.software.SPDF.repository.JPATokenRepositoryImpl;
|
||||
@EnableMethodSecurity
|
||||
public class SecurityConfiguration {
|
||||
|
||||
@Autowired private UserDetailsService userDetailsService;
|
||||
@Autowired private CustomUserDetailsService userDetailsService;
|
||||
|
||||
@Bean
|
||||
public PasswordEncoder passwordEncoder() {
|
||||
@@ -42,6 +58,8 @@ public class SecurityConfiguration {
|
||||
@Qualifier("loginEnabled")
|
||||
public boolean loginEnabledValue;
|
||||
|
||||
@Autowired ApplicationProperties applicationProperties;
|
||||
|
||||
@Autowired private UserAuthenticationFilter userAuthenticationFilter;
|
||||
|
||||
@Autowired private LoginAttemptService loginAttemptService;
|
||||
@@ -76,7 +94,8 @@ public class SecurityConfiguration {
|
||||
formLogin
|
||||
.loginPage("/login")
|
||||
.successHandler(
|
||||
new CustomAuthenticationSuccessHandler())
|
||||
new CustomAuthenticationSuccessHandler(
|
||||
loginAttemptService))
|
||||
.defaultSuccessUrl("/")
|
||||
.failureHandler(
|
||||
new CustomAuthenticationFailureHandler(
|
||||
@@ -87,20 +106,9 @@ public class SecurityConfiguration {
|
||||
logout ->
|
||||
logout.logoutRequestMatcher(
|
||||
new AntPathRequestMatcher("/logout"))
|
||||
.logoutSuccessUrl("/login?logout=true")
|
||||
.logoutSuccessHandler(new CustomLogoutSuccessHandler())
|
||||
.invalidateHttpSession(true) // Invalidate session
|
||||
.deleteCookies("JSESSIONID", "remember-me")
|
||||
.addLogoutHandler(
|
||||
(request, response, authentication) -> {
|
||||
HttpSession session =
|
||||
request.getSession(false);
|
||||
if (session != null) {
|
||||
String sessionId = session.getId();
|
||||
sessionRegistry()
|
||||
.removeSessionInformation(
|
||||
sessionId);
|
||||
}
|
||||
}))
|
||||
.deleteCookies("JSESSIONID", "remember-me"))
|
||||
.rememberMe(
|
||||
rememberMeConfigurer ->
|
||||
rememberMeConfigurer // Use the configurator directly
|
||||
@@ -124,6 +132,7 @@ public class SecurityConfiguration {
|
||||
: uri;
|
||||
|
||||
return trimmedUri.startsWith("/login")
|
||||
|| trimmedUri.startsWith("/oauth")
|
||||
|| trimmedUri.endsWith(".svg")
|
||||
|| trimmedUri.startsWith(
|
||||
"/register")
|
||||
@@ -138,8 +147,44 @@ public class SecurityConfiguration {
|
||||
.permitAll()
|
||||
.anyRequest()
|
||||
.authenticated())
|
||||
.userDetailsService(userDetailsService)
|
||||
.authenticationProvider(authenticationProvider());
|
||||
|
||||
// Handle OAUTH2 Logins
|
||||
if (applicationProperties.getSecurity().getOAUTH2().getEnabled()) {
|
||||
|
||||
http.oauth2Login(
|
||||
oauth2 ->
|
||||
oauth2.loginPage("/oauth2")
|
||||
/*
|
||||
This Custom handler is used to check if the OAUTH2 user trying to log in, already exists in the database.
|
||||
If user exists, login proceeds as usual. If user does not exist, then it is autocreated but only if 'OAUTH2AutoCreateUser'
|
||||
is set as true, else login fails with an error message advising the same.
|
||||
*/
|
||||
.successHandler(
|
||||
new CustomOAuth2AuthenticationSuccessHandler(
|
||||
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(
|
||||
this.applicationProperties,
|
||||
sessionRegistry())));
|
||||
}
|
||||
} else {
|
||||
http.csrf(csrf -> csrf.disable())
|
||||
.authorizeHttpRequests(authz -> authz.anyRequest().permitAll());
|
||||
@@ -148,6 +193,70 @@ public class SecurityConfiguration {
|
||||
return http.build();
|
||||
}
|
||||
|
||||
// Client Registration Repository for OAUTH2 OIDC Login
|
||||
@Bean
|
||||
@ConditionalOnProperty(
|
||||
value = "security.oauth2.enabled",
|
||||
havingValue = "true",
|
||||
matchIfMissing = false)
|
||||
public ClientRegistrationRepository clientRegistrationRepository() {
|
||||
return new InMemoryClientRegistrationRepository(this.oidcClientRegistration());
|
||||
}
|
||||
|
||||
private ClientRegistration oidcClientRegistration() {
|
||||
OAUTH2 oauth = applicationProperties.getSecurity().getOAUTH2();
|
||||
return ClientRegistrations.fromIssuerLocation(oauth.getIssuer())
|
||||
.registrationId("oidc")
|
||||
.clientId(oauth.getClientId())
|
||||
.clientSecret(oauth.getClientSecret())
|
||||
.scope(oauth.getScopes())
|
||||
.userNameAttributeName(oauth.getUseAsUsername())
|
||||
.clientName("OIDC")
|
||||
.build();
|
||||
}
|
||||
|
||||
/*
|
||||
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
|
||||
public IPRateLimitingFilter rateLimitingFilter() {
|
||||
int maxRequestsPerIp = 1000000; // Example limit TODO add config level
|
||||
|
||||
@@ -20,6 +20,7 @@ import io.github.bucket4j.Bandwidth;
|
||||
import io.github.bucket4j.Bucket;
|
||||
import io.github.bucket4j.ConsumptionProbe;
|
||||
import io.github.bucket4j.Refill;
|
||||
import io.github.pixee.security.Newlines;
|
||||
|
||||
import jakarta.servlet.FilterChain;
|
||||
import jakarta.servlet.ServletException;
|
||||
@@ -125,12 +126,16 @@ public class UserBasedRateLimitingFilter extends OncePerRequestFilter {
|
||||
ConsumptionProbe probe = userBucket.tryConsumeAndReturnRemaining(1);
|
||||
|
||||
if (probe.isConsumed()) {
|
||||
response.setHeader("X-Rate-Limit-Remaining", Long.toString(probe.getRemainingTokens()));
|
||||
response.setHeader(
|
||||
"X-Rate-Limit-Remaining",
|
||||
Newlines.stripAll(Long.toString(probe.getRemainingTokens())));
|
||||
filterChain.doFilter(request, response);
|
||||
} else {
|
||||
long waitForRefill = probe.getNanosToWaitForRefill() / 1_000_000_000;
|
||||
response.setStatus(HttpStatus.TOO_MANY_REQUESTS.value());
|
||||
response.setHeader("X-Rate-Limit-Retry-After-Seconds", String.valueOf(waitForRefill));
|
||||
response.setHeader(
|
||||
"X-Rate-Limit-Retry-After-Seconds",
|
||||
Newlines.stripAll(String.valueOf(waitForRefill)));
|
||||
response.getWriter().write("Rate limit exceeded for POST requests.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,8 @@ import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.MessageSource;
|
||||
import org.springframework.context.i18n.LocaleContextHolder;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
@@ -18,9 +20,11 @@ import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import stirling.software.SPDF.controller.api.pipeline.UserServiceInterface;
|
||||
import stirling.software.SPDF.model.AuthenticationType;
|
||||
import stirling.software.SPDF.model.Authority;
|
||||
import stirling.software.SPDF.model.Role;
|
||||
import stirling.software.SPDF.model.User;
|
||||
import stirling.software.SPDF.repository.AuthorityRepository;
|
||||
import stirling.software.SPDF.repository.UserRepository;
|
||||
|
||||
@Service
|
||||
@@ -28,8 +32,28 @@ public class UserService implements UserServiceInterface {
|
||||
|
||||
@Autowired private UserRepository userRepository;
|
||||
|
||||
@Autowired private AuthorityRepository authorityRepository;
|
||||
|
||||
@Autowired private PasswordEncoder passwordEncoder;
|
||||
|
||||
@Autowired private MessageSource messageSource;
|
||||
|
||||
// Handle OAUTH2 login and user auto creation.
|
||||
public boolean processOAuth2PostLogin(String username, boolean autoCreateUser) {
|
||||
if (!isUsernameValid(username)) {
|
||||
return false;
|
||||
}
|
||||
Optional<User> existingUser = userRepository.findByUsernameIgnoreCase(username);
|
||||
if (existingUser.isPresent()) {
|
||||
return true;
|
||||
}
|
||||
if (autoCreateUser) {
|
||||
saveUser(username, AuthenticationType.OAUTH2);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public Authentication getAuthentication(String apiKey) {
|
||||
User user = getUserByApiKey(apiKey);
|
||||
if (user == null) {
|
||||
@@ -90,9 +114,8 @@ public class UserService implements UserServiceInterface {
|
||||
}
|
||||
|
||||
public UserDetails loadUserByApiKey(String apiKey) {
|
||||
User userOptional = userRepository.findByApiKey(apiKey);
|
||||
if (userOptional != null) {
|
||||
User user = userOptional;
|
||||
User user = userRepository.findByApiKey(apiKey);
|
||||
if (user != null) {
|
||||
// Convert your User entity to a UserDetails object with authorities
|
||||
return new org.springframework.security.core.userdetails.User(
|
||||
user.getUsername(),
|
||||
@@ -104,35 +127,53 @@ public class UserService implements UserServiceInterface {
|
||||
|
||||
public boolean validateApiKeyForUser(String username, String apiKey) {
|
||||
Optional<User> userOpt = userRepository.findByUsernameIgnoreCase(username);
|
||||
return userOpt.isPresent() && userOpt.get().getApiKey().equals(apiKey);
|
||||
return userOpt.isPresent() && apiKey.equals(userOpt.get().getApiKey());
|
||||
}
|
||||
|
||||
public void saveUser(String username, String password) {
|
||||
public void saveUser(String username, AuthenticationType authenticationType)
|
||||
throws IllegalArgumentException {
|
||||
if (!isUsernameValid(username)) {
|
||||
throw new IllegalArgumentException(getInvalidUsernameMessage());
|
||||
}
|
||||
User user = new User();
|
||||
user.setUsername(username);
|
||||
user.setEnabled(true);
|
||||
user.setFirstLogin(false);
|
||||
user.addAuthority(new Authority(Role.USER.getRoleId(), user));
|
||||
user.setAuthenticationType(authenticationType);
|
||||
userRepository.save(user);
|
||||
}
|
||||
|
||||
public void saveUser(String username, String password) throws IllegalArgumentException {
|
||||
if (!isUsernameValid(username)) {
|
||||
throw new IllegalArgumentException(getInvalidUsernameMessage());
|
||||
}
|
||||
User user = new User();
|
||||
user.setUsername(username);
|
||||
user.setPassword(passwordEncoder.encode(password));
|
||||
user.setEnabled(true);
|
||||
user.setAuthenticationType(AuthenticationType.WEB);
|
||||
userRepository.save(user);
|
||||
}
|
||||
|
||||
public void saveUser(String username, String password, String role, boolean firstLogin) {
|
||||
public void saveUser(String username, String password, String role, boolean firstLogin)
|
||||
throws IllegalArgumentException {
|
||||
if (!isUsernameValid(username)) {
|
||||
throw new IllegalArgumentException(getInvalidUsernameMessage());
|
||||
}
|
||||
User user = new User();
|
||||
user.setUsername(username);
|
||||
user.setPassword(passwordEncoder.encode(password));
|
||||
user.addAuthority(new Authority(role, user));
|
||||
user.setEnabled(true);
|
||||
user.setAuthenticationType(AuthenticationType.WEB);
|
||||
user.setFirstLogin(firstLogin);
|
||||
userRepository.save(user);
|
||||
}
|
||||
|
||||
public void saveUser(String username, String password, String role) {
|
||||
User user = new User();
|
||||
user.setUsername(username);
|
||||
user.setPassword(passwordEncoder.encode(password));
|
||||
user.addAuthority(new Authority(role, user));
|
||||
user.setEnabled(true);
|
||||
user.setFirstLogin(false);
|
||||
userRepository.save(user);
|
||||
public void saveUser(String username, String password, String role)
|
||||
throws IllegalArgumentException {
|
||||
saveUser(username, password, role, false);
|
||||
}
|
||||
|
||||
public void deleteUser(String username) {
|
||||
@@ -156,7 +197,13 @@ public class UserService implements UserServiceInterface {
|
||||
}
|
||||
|
||||
public boolean hasUsers() {
|
||||
return userRepository.count() > 0;
|
||||
long userCount = userRepository.count();
|
||||
if (userRepository
|
||||
.findByUsernameIgnoreCase(Role.INTERNAL_API_USER.getRoleId())
|
||||
.isPresent()) {
|
||||
userCount -= 1;
|
||||
}
|
||||
return userCount > 0;
|
||||
}
|
||||
|
||||
public void updateUserSettings(String username, Map<String, String> updates) {
|
||||
@@ -166,7 +213,7 @@ public class UserService implements UserServiceInterface {
|
||||
Map<String, String> settingsMap = user.getSettings();
|
||||
|
||||
if (settingsMap == null) {
|
||||
settingsMap = new HashMap<String, String>();
|
||||
settingsMap = new HashMap<>();
|
||||
}
|
||||
settingsMap.clear();
|
||||
settingsMap.putAll(updates);
|
||||
@@ -184,7 +231,14 @@ public class UserService implements UserServiceInterface {
|
||||
return userRepository.findByUsernameIgnoreCase(username);
|
||||
}
|
||||
|
||||
public void changeUsername(User user, String newUsername) {
|
||||
public Authority findRole(User user) {
|
||||
return authorityRepository.findByUserId(user.getId());
|
||||
}
|
||||
|
||||
public void changeUsername(User user, String newUsername) throws IllegalArgumentException {
|
||||
if (!isUsernameValid(newUsername)) {
|
||||
throw new IllegalArgumentException(getInvalidUsernameMessage());
|
||||
}
|
||||
user.setUsername(newUsername);
|
||||
userRepository.save(user);
|
||||
}
|
||||
@@ -199,11 +253,41 @@ public class UserService implements UserServiceInterface {
|
||||
userRepository.save(user);
|
||||
}
|
||||
|
||||
public void changeRole(User user, String newRole) {
|
||||
Authority userAuthority = this.findRole(user);
|
||||
userAuthority.setAuthority(newRole);
|
||||
authorityRepository.save(userAuthority);
|
||||
}
|
||||
|
||||
public boolean isPasswordCorrect(User user, String currentPassword) {
|
||||
return passwordEncoder.matches(currentPassword, user.getPassword());
|
||||
}
|
||||
|
||||
public boolean isUsernameValid(String username) {
|
||||
return username.matches("[a-zA-Z0-9]+");
|
||||
// Checks whether the simple username is formatted correctly
|
||||
boolean isValidSimpleUsername =
|
||||
username.matches("^[a-zA-Z0-9][a-zA-Z0-9@._+-]*[a-zA-Z0-9]$");
|
||||
// Checks whether the email address is formatted correctly
|
||||
boolean isValidEmail =
|
||||
username.matches(
|
||||
"^(?=.{1,64}@)[A-Za-z0-9]+(\\.[A-Za-z0-9_+.-]+)*@[^-][A-Za-z0-9-]+(\\.[A-Za-z0-9-]+)*(\\.[A-Za-z]{2,})$");
|
||||
return isValidSimpleUsername || isValidEmail;
|
||||
}
|
||||
|
||||
private String getInvalidUsernameMessage() {
|
||||
return messageSource.getMessage(
|
||||
"invalidUsernameMessage", null, LocaleContextHolder.getLocale());
|
||||
}
|
||||
|
||||
public boolean hasPassword(String username) {
|
||||
Optional<User> user = userRepository.findByUsernameIgnoreCase(username);
|
||||
return user.isPresent() && user.get().hasPassword();
|
||||
}
|
||||
|
||||
public boolean isAuthenticationTypeByUsername(
|
||||
String username, AuthenticationType authenticationType) {
|
||||
Optional<User> user = userRepository.findByUsernameIgnoreCase(username);
|
||||
return user.isPresent()
|
||||
&& authenticationType.name().equalsIgnoreCase(user.get().getAuthenticationType());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
package stirling.software.SPDF.config.security.oauth2;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.security.authentication.LockedException;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
|
||||
import org.springframework.security.oauth2.core.OAuth2Error;
|
||||
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
|
||||
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
|
||||
public class CustomOAuth2AuthenticationFailureHandler
|
||||
extends SimpleUrlAuthenticationFailureHandler {
|
||||
|
||||
private static final Logger logger =
|
||||
LoggerFactory.getLogger(CustomOAuth2AuthenticationFailureHandler.class);
|
||||
|
||||
@Override
|
||||
public void onAuthenticationFailure(
|
||||
HttpServletRequest request,
|
||||
HttpServletResponse response,
|
||||
AuthenticationException exception)
|
||||
throws IOException, ServletException {
|
||||
if (exception instanceof OAuth2AuthenticationException) {
|
||||
OAuth2Error error = ((OAuth2AuthenticationException) exception).getError();
|
||||
|
||||
String errorCode = error.getErrorCode();
|
||||
|
||||
if (error.getErrorCode().equals("Password must not be null")) {
|
||||
errorCode = "userAlreadyExistsWeb";
|
||||
}
|
||||
logger.error("OAuth2 Authentication error: " + errorCode);
|
||||
getRedirectStrategy()
|
||||
.sendRedirect(request, response, "/logout?erroroauth=" + errorCode);
|
||||
return;
|
||||
} else if (exception instanceof LockedException) {
|
||||
logger.error("Account locked: ", exception);
|
||||
getRedirectStrategy().sendRedirect(request, response, "/logout?error=locked");
|
||||
} else {
|
||||
logger.error("Unhandled authentication exception", exception);
|
||||
super.onAuthenticationFailure(request, response, exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
package stirling.software.SPDF.config.security.oauth2;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.security.authentication.LockedException;
|
||||
import org.springframework.security.core.Authentication;
|
||||
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 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;
|
||||
|
||||
public class CustomOAuth2AuthenticationSuccessHandler
|
||||
extends SavedRequestAwareAuthenticationSuccessHandler {
|
||||
|
||||
private LoginAttemptService loginAttemptService;
|
||||
|
||||
private static final Logger logger =
|
||||
LoggerFactory.getLogger(CustomOAuth2AuthenticationSuccessHandler.class);
|
||||
|
||||
private ApplicationProperties applicationProperties;
|
||||
private UserService userService;
|
||||
|
||||
public CustomOAuth2AuthenticationSuccessHandler(
|
||||
final LoginAttemptService loginAttemptService,
|
||||
ApplicationProperties applicationProperties,
|
||||
UserService userService) {
|
||||
this.applicationProperties = applicationProperties;
|
||||
this.userService = userService;
|
||||
this.loginAttemptService = loginAttemptService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAuthenticationSuccess(
|
||||
HttpServletRequest request, HttpServletResponse response, Authentication authentication)
|
||||
throws ServletException, IOException {
|
||||
|
||||
// Get the saved request
|
||||
HttpSession session = request.getSession(false);
|
||||
SavedRequest savedRequest =
|
||||
(session != null)
|
||||
? (SavedRequest) session.getAttribute("SPRING_SECURITY_SAVED_REQUEST")
|
||||
: null;
|
||||
|
||||
if (savedRequest != null
|
||||
&& !RequestUriUtils.isStaticResource(savedRequest.getRedirectUrl())) {
|
||||
// Redirect to the original destination
|
||||
super.onAuthenticationSuccess(request, response, authentication);
|
||||
} else {
|
||||
OAuth2User oauthUser = (OAuth2User) authentication.getPrincipal();
|
||||
OAUTH2 oAuth = applicationProperties.getSecurity().getOAUTH2();
|
||||
|
||||
String username = oauthUser.getName();
|
||||
|
||||
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(
|
||||
request.getContextPath() + "/logout?oauth2AuthenticationErrorWeb=true");
|
||||
return;
|
||||
} else {
|
||||
try {
|
||||
userService.processOAuth2PostLogin(username, oAuth.getAutoCreateUser());
|
||||
response.sendRedirect("/");
|
||||
return;
|
||||
} catch (IllegalArgumentException e) {
|
||||
response.sendRedirect("/logout?invalidUsername=true");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
package stirling.software.SPDF.config.security.oauth2;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.session.SessionRegistry;
|
||||
import org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler;
|
||||
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.servlet.http.HttpSession;
|
||||
import stirling.software.SPDF.model.ApplicationProperties;
|
||||
import stirling.software.SPDF.model.ApplicationProperties.Security.OAUTH2;
|
||||
|
||||
public class CustomOAuth2LogoutSuccessHandler extends SimpleUrlLogoutSuccessHandler {
|
||||
|
||||
private static final Logger logger =
|
||||
LoggerFactory.getLogger(CustomOAuth2LogoutSuccessHandler.class);
|
||||
|
||||
private final SessionRegistry sessionRegistry;
|
||||
private final ApplicationProperties applicationProperties;
|
||||
|
||||
public CustomOAuth2LogoutSuccessHandler(
|
||||
ApplicationProperties applicationProperties, SessionRegistry sessionRegistry) {
|
||||
this.sessionRegistry = sessionRegistry;
|
||||
this.applicationProperties = applicationProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLogoutSuccess(
|
||||
HttpServletRequest request, HttpServletResponse response, Authentication authentication)
|
||||
throws IOException, ServletException {
|
||||
|
||||
String param = "logout=true";
|
||||
|
||||
OAUTH2 oauth = applicationProperties.getSecurity().getOAUTH2();
|
||||
String provider = oauth.getProvider() != null ? oauth.getProvider() : "";
|
||||
|
||||
if (request.getParameter("oauth2AuthenticationErrorWeb") != null) {
|
||||
param = "erroroauth=oauth2AuthenticationErrorWeb";
|
||||
} else if (request.getParameter("error") != null) {
|
||||
param = "error=" + request.getParameter("error");
|
||||
} else if (request.getParameter("erroroauth") != null) {
|
||||
param = "erroroauth=" + request.getParameter("erroroauth");
|
||||
} else if (request.getParameter("oauth2AutoCreateDisabled") != null) {
|
||||
param = "error=oauth2AutoCreateDisabled";
|
||||
}
|
||||
|
||||
HttpSession session = request.getSession(false);
|
||||
if (session != null) {
|
||||
String sessionId = session.getId();
|
||||
sessionRegistry.removeSessionInformation(sessionId);
|
||||
session.invalidate();
|
||||
logger.debug("Session invalidated: " + sessionId);
|
||||
}
|
||||
|
||||
switch (provider) {
|
||||
case "keycloak":
|
||||
String logoutUrl =
|
||||
oauth.getIssuer()
|
||||
+ "/protocol/openid-connect/logout"
|
||||
+ "?client_id="
|
||||
+ oauth.getClientId()
|
||||
+ "&post_logout_redirect_uri="
|
||||
+ response.encodeRedirectURL(
|
||||
request.getScheme()
|
||||
+ "://"
|
||||
+ request.getHeader("host")
|
||||
+ "/login?"
|
||||
+ param);
|
||||
logger.debug("Redirecting to Keycloak logout URL: " + logoutUrl);
|
||||
response.sendRedirect(logoutUrl);
|
||||
break;
|
||||
case "google":
|
||||
// Add Google specific logout URL if needed
|
||||
default:
|
||||
String redirectUrl = request.getContextPath() + "/login?" + param;
|
||||
logger.debug("Redirecting to default logout URL: " + redirectUrl);
|
||||
response.sendRedirect(redirectUrl);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
package stirling.software.SPDF.config.security.oauth2;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.security.authentication.LockedException;
|
||||
import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserRequest;
|
||||
import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserService;
|
||||
import org.springframework.security.oauth2.client.userinfo.OAuth2UserService;
|
||||
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
|
||||
import org.springframework.security.oauth2.core.OAuth2Error;
|
||||
import org.springframework.security.oauth2.core.oidc.user.DefaultOidcUser;
|
||||
import org.springframework.security.oauth2.core.oidc.user.OidcUser;
|
||||
|
||||
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.User;
|
||||
|
||||
public class CustomOAuth2UserService implements OAuth2UserService<OidcUserRequest, OidcUser> {
|
||||
|
||||
private final OidcUserService delegate = new OidcUserService();
|
||||
|
||||
private UserService userService;
|
||||
|
||||
private LoginAttemptService loginAttemptService;
|
||||
|
||||
private ApplicationProperties applicationProperties;
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(CustomOAuth2UserService.class);
|
||||
|
||||
public CustomOAuth2UserService(
|
||||
ApplicationProperties applicationProperties,
|
||||
UserService userService,
|
||||
LoginAttemptService loginAttemptService) {
|
||||
this.applicationProperties = applicationProperties;
|
||||
this.userService = userService;
|
||||
this.loginAttemptService = loginAttemptService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OidcUser loadUser(OidcUserRequest userRequest) throws OAuth2AuthenticationException {
|
||||
String usernameAttribute =
|
||||
applicationProperties.getSecurity().getOAUTH2().getUseAsUsername();
|
||||
try {
|
||||
OidcUser user = delegate.loadUser(userRequest);
|
||||
String username = user.getUserInfo().getClaimAsString(usernameAttribute);
|
||||
Optional<User> duser = userService.findByUsernameIgnoreCase(username);
|
||||
if (duser.isPresent()) {
|
||||
if (loginAttemptService.isBlocked(username)) {
|
||||
throw new LockedException(
|
||||
"Your account has been locked due to too many failed login attempts.");
|
||||
}
|
||||
if (userService.hasPassword(username)) {
|
||||
throw new IllegalArgumentException("Password must not be null");
|
||||
}
|
||||
}
|
||||
// Return a new OidcUser with adjusted attributes
|
||||
return new DefaultOidcUser(
|
||||
user.getAuthorities(),
|
||||
userRequest.getIdToken(),
|
||||
user.getUserInfo(),
|
||||
usernameAttribute);
|
||||
} catch (java.lang.IllegalArgumentException e) {
|
||||
logger.error("Error loading OIDC user: {}", e.getMessage());
|
||||
throw new OAuth2AuthenticationException(new OAuth2Error(e.getMessage()), e);
|
||||
} catch (Exception e) {
|
||||
logger.error("Unexpected error loading OIDC user", e);
|
||||
throw new OAuth2AuthenticationException("Unexpected error during authentication");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package stirling.software.SPDF.config.security.oauth2;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserRequest;
|
||||
import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserService;
|
||||
import org.springframework.security.oauth2.client.userinfo.OAuth2UserService;
|
||||
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
|
||||
import org.springframework.security.oauth2.core.OAuth2Error;
|
||||
import org.springframework.security.oauth2.core.oidc.user.DefaultOidcUser;
|
||||
import org.springframework.security.oauth2.core.oidc.user.OidcUser;
|
||||
|
||||
import stirling.software.SPDF.model.ApplicationProperties;
|
||||
|
||||
public class CustomOAuthUserService implements OAuth2UserService<OidcUserRequest, OidcUser> {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(CustomOAuthUserService.class);
|
||||
|
||||
private final OidcUserService delegate = new OidcUserService();
|
||||
|
||||
private ApplicationProperties applicationProperties;
|
||||
|
||||
public CustomOAuthUserService(ApplicationProperties applicationProperties) {
|
||||
this.applicationProperties = applicationProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OidcUser loadUser(OidcUserRequest userRequest) throws OAuth2AuthenticationException {
|
||||
String usernameAttribute =
|
||||
applicationProperties.getSecurity().getOAUTH2().getUseAsUsername();
|
||||
try {
|
||||
|
||||
OidcUser user = delegate.loadUser(userRequest);
|
||||
Map<String, Object> attributes = new HashMap<>(user.getAttributes());
|
||||
|
||||
// Ensure the preferred username attribute is present
|
||||
if (!attributes.containsKey(usernameAttribute)) {
|
||||
attributes.put(usernameAttribute, attributes.getOrDefault("email", ""));
|
||||
usernameAttribute = "email";
|
||||
logger.info("Adjusted username attribute to use email");
|
||||
}
|
||||
|
||||
// Return a new OidcUser with adjusted attributes
|
||||
return new DefaultOidcUser(
|
||||
user.getAuthorities(),
|
||||
userRequest.getIdToken(),
|
||||
user.getUserInfo(),
|
||||
usernameAttribute);
|
||||
} catch (java.lang.IllegalArgumentException e) {
|
||||
throw new OAuth2AuthenticationException(
|
||||
new OAuth2Error(e.getMessage()), e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -47,8 +47,11 @@ public class UserController {
|
||||
model.addAttribute("error", "Username already exists");
|
||||
return "register";
|
||||
}
|
||||
|
||||
userService.saveUser(requestModel.getUsername(), requestModel.getPassword());
|
||||
try {
|
||||
userService.saveUser(requestModel.getUsername(), requestModel.getPassword());
|
||||
} catch (IllegalArgumentException e) {
|
||||
return "redirect:/login?messageType=invalidUsername";
|
||||
}
|
||||
return "redirect:/login?registered=true";
|
||||
}
|
||||
|
||||
@@ -92,7 +95,11 @@ public class UserController {
|
||||
}
|
||||
|
||||
if (newUsername != null && newUsername.length() > 0) {
|
||||
userService.changeUsername(user, newUsername);
|
||||
try {
|
||||
userService.changeUsername(user, newUsername);
|
||||
} catch (IllegalArgumentException e) {
|
||||
return new RedirectView("/account?messageType=invalidUsername");
|
||||
}
|
||||
}
|
||||
|
||||
// Logout using Spring's utility
|
||||
@@ -227,6 +234,45 @@ public class UserController {
|
||||
return new RedirectView("/addUsers"); // Redirect to account page after adding the user
|
||||
}
|
||||
|
||||
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||
@PostMapping("/admin/changeRole")
|
||||
public RedirectView changeRole(
|
||||
@RequestParam(name = "username") String username,
|
||||
@RequestParam(name = "role") String role,
|
||||
Authentication authentication) {
|
||||
|
||||
Optional<User> userOpt = userService.findByUsernameIgnoreCase(username);
|
||||
|
||||
if (!userOpt.isPresent()) {
|
||||
return new RedirectView("/addUsers?messageType=userNotFound");
|
||||
}
|
||||
if (!userService.usernameExistsIgnoreCase(username)) {
|
||||
return new RedirectView("/addUsers?messageType=userNotFound");
|
||||
}
|
||||
// Get the currently authenticated username
|
||||
String currentUsername = authentication.getName();
|
||||
|
||||
// Check if the provided username matches the current session's username
|
||||
if (currentUsername.equalsIgnoreCase(username)) {
|
||||
return new RedirectView("/addUsers?messageType=downgradeCurrentUser");
|
||||
}
|
||||
try {
|
||||
// Validate the role
|
||||
Role roleEnum = Role.fromString(role);
|
||||
if (roleEnum == Role.INTERNAL_API_USER) {
|
||||
// If the role is INTERNAL_API_USER, reject the request
|
||||
return new RedirectView("/addUsers?messageType=invalidRole");
|
||||
}
|
||||
} catch (IllegalArgumentException e) {
|
||||
// If the role ID is not valid, redirect with an error message
|
||||
return new RedirectView("/addUsers?messageType=invalidRole");
|
||||
}
|
||||
User user = userOpt.get();
|
||||
|
||||
userService.changeRole(user, role);
|
||||
return new RedirectView("/addUsers"); // Redirect to account page after adding the user
|
||||
}
|
||||
|
||||
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||
@PostMapping("/admin/deleteUser/{username}")
|
||||
public RedirectView deleteUser(
|
||||
|
||||
@@ -6,10 +6,6 @@ import java.net.URLConnection;
|
||||
import org.apache.pdfbox.rendering.ImageType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.core.io.ByteArrayResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||
@@ -39,8 +35,8 @@ public class ConvertImgPDFController {
|
||||
summary = "Convert PDF to image(s)",
|
||||
description =
|
||||
"This endpoint converts a PDF file to image(s) with the specified image format, color type, and DPI. Users can choose to get a single image or multiple images. Input:PDF Output:Image Type:SI-Conditional")
|
||||
public ResponseEntity<Resource> convertToImage(@ModelAttribute ConvertToImageRequest request)
|
||||
throws IOException {
|
||||
public ResponseEntity<byte[]> convertToImage(@ModelAttribute ConvertToImageRequest request)
|
||||
throws NumberFormatException, Exception {
|
||||
MultipartFile file = request.getFileInput();
|
||||
String imageFormat = request.getImageFormat();
|
||||
String singleOrMultiple = request.getSingleOrMultiple();
|
||||
@@ -60,38 +56,28 @@ public class ConvertImgPDFController {
|
||||
String filename =
|
||||
Filenames.toSimpleFileName(file.getOriginalFilename())
|
||||
.replaceFirst("[.][^.]+$", "");
|
||||
try {
|
||||
result =
|
||||
PdfUtils.convertFromPdf(
|
||||
pdfBytes,
|
||||
imageFormat.toUpperCase(),
|
||||
colorTypeResult,
|
||||
singleImage,
|
||||
Integer.valueOf(dpi),
|
||||
filename);
|
||||
} catch (IOException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
} catch (Exception e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
|
||||
result =
|
||||
PdfUtils.convertFromPdf(
|
||||
pdfBytes,
|
||||
imageFormat.toUpperCase(),
|
||||
colorTypeResult,
|
||||
singleImage,
|
||||
Integer.valueOf(dpi),
|
||||
filename);
|
||||
|
||||
|
||||
if(result == null || result.length == 0) {
|
||||
logger.error("resultant bytes for {} is null, error converting ", filename);
|
||||
}
|
||||
if (singleImage) {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.parseMediaType(getMediaType(imageFormat)));
|
||||
ResponseEntity<Resource> response =
|
||||
new ResponseEntity<>(new ByteArrayResource(result), headers, HttpStatus.OK);
|
||||
return response;
|
||||
String docName = filename + "." + imageFormat;
|
||||
MediaType mediaType = MediaType.parseMediaType(getMediaType(imageFormat));
|
||||
return WebResponseUtils.bytesToWebResponse(result, docName, mediaType);
|
||||
} else {
|
||||
ByteArrayResource resource = new ByteArrayResource(result);
|
||||
// return the Resource in the response
|
||||
return ResponseEntity.ok()
|
||||
.header(
|
||||
HttpHeaders.CONTENT_DISPOSITION,
|
||||
"attachment; filename=" + filename + "_convertedToImages.zip")
|
||||
.contentType(MediaType.APPLICATION_OCTET_STREAM)
|
||||
.contentLength(resource.contentLength())
|
||||
.body(resource);
|
||||
String zipFilename = filename + "_convertedToImages.zip";
|
||||
return WebResponseUtils.bytesToWebResponse(
|
||||
result, zipFilename, MediaType.APPLICATION_OCTET_STREAM);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
package stirling.software.SPDF.controller.api.misc;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.apache.pdfbox.Loader;
|
||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||
import org.apache.pdfbox.pdmodel.PDPage;
|
||||
import org.apache.pdfbox.pdmodel.PDPageContentStream;
|
||||
import org.apache.pdfbox.pdmodel.graphics.image.JPEGFactory;
|
||||
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
|
||||
import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm;
|
||||
import org.apache.pdfbox.rendering.ImageType;
|
||||
import org.apache.pdfbox.rendering.PDFRenderer;
|
||||
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.PdfMetadata;
|
||||
import stirling.software.SPDF.model.api.misc.FlattenRequest;
|
||||
import stirling.software.SPDF.utils.PdfUtils;
|
||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/misc")
|
||||
@Tag(name = "Misc", description = "Miscellaneous APIs")
|
||||
public class FlattenController {
|
||||
|
||||
@PostMapping(consumes = "multipart/form-data", value = "/flatten")
|
||||
@Operation(
|
||||
summary = "Flatten PDF form fields or full page",
|
||||
description =
|
||||
"Flattening just PDF form fields or converting each page to images to make text unselectable. Input: PDF, Output: PDF. Type: SISO")
|
||||
public ResponseEntity<byte[]> flatten(@ModelAttribute FlattenRequest request) throws Exception {
|
||||
MultipartFile file = request.getFileInput();
|
||||
|
||||
PDDocument document = Loader.loadPDF(file.getBytes());
|
||||
PdfMetadata metadata = PdfUtils.extractMetadataFromPdf(document);
|
||||
Boolean flattenOnlyForms = request.getFlattenOnlyForms();
|
||||
|
||||
if (Boolean.TRUE.equals(flattenOnlyForms)) {
|
||||
PDAcroForm acroForm = document.getDocumentCatalog().getAcroForm();
|
||||
if (acroForm != null) {
|
||||
acroForm.flatten();
|
||||
}
|
||||
return WebResponseUtils.pdfDocToWebResponse(
|
||||
document, Filenames.toSimpleFileName(file.getOriginalFilename()));
|
||||
} else {
|
||||
// flatten whole page aka convert each page to image and readd it (making text
|
||||
// unselectable)
|
||||
PDFRenderer pdfRenderer = new PDFRenderer(document);
|
||||
PDDocument newDocument = new PDDocument();
|
||||
int numPages = document.getNumberOfPages();
|
||||
for (int i = 0; i < numPages; i++) {
|
||||
try {
|
||||
BufferedImage image = pdfRenderer.renderImageWithDPI(i, 300, ImageType.RGB);
|
||||
PDPage page = new PDPage();
|
||||
page.setMediaBox(document.getPage(i).getMediaBox());
|
||||
newDocument.addPage(page);
|
||||
try (PDPageContentStream contentStream =
|
||||
new PDPageContentStream(newDocument, page)) {
|
||||
PDImageXObject pdImage = JPEGFactory.createFromImage(newDocument, image);
|
||||
float pageWidth = page.getMediaBox().getWidth();
|
||||
float pageHeight = page.getMediaBox().getHeight();
|
||||
|
||||
contentStream.drawImage(pdImage, 0, 0, pageWidth, pageHeight);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
PdfUtils.setMetadataToPdf(newDocument, metadata);
|
||||
return WebResponseUtils.pdfDocToWebResponse(
|
||||
newDocument, Filenames.toSimpleFileName(file.getOriginalFilename()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.oauth2.core.user.OAuth2User;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
@@ -19,6 +20,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import stirling.software.SPDF.model.ApplicationProperties;
|
||||
import stirling.software.SPDF.model.Authority;
|
||||
import stirling.software.SPDF.model.Role;
|
||||
import stirling.software.SPDF.model.User;
|
||||
@@ -28,17 +30,65 @@ import stirling.software.SPDF.repository.UserRepository;
|
||||
@Tag(name = "Account Security", description = "Account Security APIs")
|
||||
public class AccountWebController {
|
||||
|
||||
@Autowired ApplicationProperties applicationProperties;
|
||||
|
||||
@GetMapping("/login")
|
||||
public String login(HttpServletRequest request, Model model, Authentication authentication) {
|
||||
if (authentication != null && authentication.isAuthenticated()) {
|
||||
return "redirect:/";
|
||||
}
|
||||
|
||||
model.addAttribute(
|
||||
"oAuth2Enabled", applicationProperties.getSecurity().getOAUTH2().getEnabled());
|
||||
|
||||
model.addAttribute("currentPage", "login");
|
||||
|
||||
if (request.getParameter("error") != null) {
|
||||
String error = request.getParameter("error");
|
||||
if (error != null) {
|
||||
|
||||
model.addAttribute("error", request.getParameter("error"));
|
||||
switch (error) {
|
||||
case "badcredentials":
|
||||
error = "login.invalid";
|
||||
break;
|
||||
case "locked":
|
||||
error = "login.locked";
|
||||
break;
|
||||
case "oauth2AuthenticationError":
|
||||
error = "userAlreadyExistsOAuthMessage";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
model.addAttribute("error", error);
|
||||
}
|
||||
String erroroauth = request.getParameter("erroroauth");
|
||||
if (erroroauth != null) {
|
||||
|
||||
switch (erroroauth) {
|
||||
case "oauth2AutoCreateDisabled":
|
||||
erroroauth = "login.oauth2AutoCreateDisabled";
|
||||
break;
|
||||
case "invalidUsername":
|
||||
erroroauth = "login.invalid";
|
||||
break;
|
||||
case "userAlreadyExistsWeb":
|
||||
erroroauth = "userAlreadyExistsWebMessage";
|
||||
break;
|
||||
case "oauth2AuthenticationErrorWeb":
|
||||
erroroauth = "login.oauth2InvalidUserType";
|
||||
break;
|
||||
case "invalid_token_response":
|
||||
erroroauth = "login.oauth2InvalidTokenResponse";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
model.addAttribute("erroroauth", erroroauth);
|
||||
}
|
||||
if (request.getParameter("messageType") != null) {
|
||||
|
||||
model.addAttribute("messageType", "changedCredsMessage");
|
||||
}
|
||||
if (request.getParameter("logout") != null) {
|
||||
|
||||
@@ -53,7 +103,8 @@ public class AccountWebController {
|
||||
|
||||
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||
@GetMapping("/addUsers")
|
||||
public String showAddUserForm(Model model, Authentication authentication) {
|
||||
public String showAddUserForm(
|
||||
HttpServletRequest request, Model model, Authentication authentication) {
|
||||
List<User> allUsers = userRepository.findAll();
|
||||
Iterator<User> iterator = allUsers.iterator();
|
||||
Map<String, String> roleDetails = Role.getAllRoleDetails();
|
||||
@@ -71,6 +122,52 @@ public class AccountWebController {
|
||||
}
|
||||
}
|
||||
|
||||
String messageType = request.getParameter("messageType");
|
||||
|
||||
String deleteMessage = null;
|
||||
if (messageType != null) {
|
||||
switch (messageType) {
|
||||
case "deleteCurrentUser":
|
||||
deleteMessage = "deleteCurrentUserMessage";
|
||||
break;
|
||||
case "deleteUsernameExists":
|
||||
deleteMessage = "deleteUsernameExistsMessage";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
model.addAttribute("deleteMessage", deleteMessage);
|
||||
|
||||
String addMessage = null;
|
||||
switch (messageType) {
|
||||
case "usernameExists":
|
||||
addMessage = "usernameExistsMessage";
|
||||
break;
|
||||
case "invalidUsername":
|
||||
addMessage = "invalidUsernameMessage";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
model.addAttribute("addMessage", addMessage);
|
||||
}
|
||||
|
||||
String changeMessage = null;
|
||||
if (messageType != null) {
|
||||
switch (messageType) {
|
||||
case "userNotFound":
|
||||
changeMessage = "userNotFoundMessage";
|
||||
break;
|
||||
case "downgradeCurrentUser":
|
||||
changeMessage = "downgradeCurrentUserMessage";
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
model.addAttribute("changeMessage", changeMessage);
|
||||
}
|
||||
|
||||
model.addAttribute("users", allUsers);
|
||||
model.addAttribute("currentUsername", authentication.getName());
|
||||
model.addAttribute("roleDetails", roleDetails);
|
||||
@@ -85,14 +182,30 @@ public class AccountWebController {
|
||||
}
|
||||
if (authentication != null && authentication.isAuthenticated()) {
|
||||
Object principal = authentication.getPrincipal();
|
||||
String username = null;
|
||||
|
||||
if (principal instanceof UserDetails) {
|
||||
// Cast the principal object to UserDetails
|
||||
UserDetails userDetails = (UserDetails) principal;
|
||||
|
||||
// Retrieve username and other attributes
|
||||
String username = userDetails.getUsername();
|
||||
username = userDetails.getUsername();
|
||||
|
||||
// Add oAuth2 Login attributes to the model
|
||||
model.addAttribute("oAuth2Login", false);
|
||||
}
|
||||
if (principal instanceof OAuth2User) {
|
||||
// Cast the principal object to OAuth2User
|
||||
OAuth2User userDetails = (OAuth2User) principal;
|
||||
|
||||
// Retrieve username and other attributes
|
||||
username =
|
||||
userDetails.getAttribute(
|
||||
applicationProperties.getSecurity().getOAUTH2().getUseAsUsername());
|
||||
// Add oAuth2 Login attributes to the model
|
||||
model.addAttribute("oAuth2Login", true);
|
||||
}
|
||||
if (username != null) {
|
||||
// Fetch user details from the database
|
||||
Optional<User> user =
|
||||
userRepository.findByUsernameIgnoreCase(
|
||||
@@ -113,6 +226,30 @@ public class AccountWebController {
|
||||
return "redirect:/error"; // Example redirection in case of error
|
||||
}
|
||||
|
||||
String messageType = request.getParameter("messageType");
|
||||
if (messageType != null) {
|
||||
switch (messageType) {
|
||||
case "notAuthenticated":
|
||||
messageType = "notAuthenticatedMessage";
|
||||
break;
|
||||
case "userNotFound":
|
||||
messageType = "userNotFoundMessage";
|
||||
break;
|
||||
case "incorrectPassword":
|
||||
messageType = "incorrectPasswordMessage";
|
||||
break;
|
||||
case "usernameExists":
|
||||
messageType = "usernameExistsMessage";
|
||||
break;
|
||||
case "invalidUsername":
|
||||
messageType = "invalidUsernameMessage";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
model.addAttribute("messageType", messageType);
|
||||
}
|
||||
|
||||
// Add attributes to the model
|
||||
model.addAttribute("username", username);
|
||||
model.addAttribute("role", user.get().getRolesAsString());
|
||||
@@ -151,6 +288,28 @@ public class AccountWebController {
|
||||
// Handle error appropriately
|
||||
return "redirect:/error"; // Example redirection in case of error
|
||||
}
|
||||
|
||||
String messageType = request.getParameter("messageType");
|
||||
if (messageType != null) {
|
||||
switch (messageType) {
|
||||
case "notAuthenticated":
|
||||
messageType = "notAuthenticatedMessage";
|
||||
break;
|
||||
case "userNotFound":
|
||||
messageType = "userNotFoundMessage";
|
||||
break;
|
||||
case "incorrectPassword":
|
||||
messageType = "incorrectPasswordMessage";
|
||||
break;
|
||||
case "usernameExists":
|
||||
messageType = "usernameExistsMessage";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
model.addAttribute("messageType", messageType);
|
||||
}
|
||||
|
||||
// Add attributes to the model
|
||||
model.addAttribute("username", username);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
package stirling.software.SPDF.model;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@@ -118,6 +122,7 @@ public class ApplicationProperties {
|
||||
private Boolean enableLogin;
|
||||
private Boolean csrfDisabled;
|
||||
private InitialLogin initialLogin;
|
||||
private OAUTH2 oauth2;
|
||||
private int loginAttemptCount;
|
||||
private long loginResetTimeMinutes;
|
||||
|
||||
@@ -145,6 +150,14 @@ public class ApplicationProperties {
|
||||
this.initialLogin = initialLogin;
|
||||
}
|
||||
|
||||
public OAUTH2 getOAUTH2() {
|
||||
return oauth2 != null ? oauth2 : new OAUTH2();
|
||||
}
|
||||
|
||||
public void setOAUTH2(OAUTH2 oauth2) {
|
||||
this.oauth2 = oauth2;
|
||||
}
|
||||
|
||||
public Boolean getEnableLogin() {
|
||||
return enableLogin;
|
||||
}
|
||||
@@ -165,6 +178,8 @@ public class ApplicationProperties {
|
||||
public String toString() {
|
||||
return "Security [enableLogin="
|
||||
+ enableLogin
|
||||
+ ", oauth2="
|
||||
+ oauth2
|
||||
+ ", initialLogin="
|
||||
+ initialLogin
|
||||
+ ", csrfDisabled="
|
||||
@@ -202,14 +217,116 @@ public class ApplicationProperties {
|
||||
+ "]";
|
||||
}
|
||||
}
|
||||
|
||||
public static class OAUTH2 {
|
||||
|
||||
private boolean enabled;
|
||||
private String issuer;
|
||||
private String clientId;
|
||||
private String clientSecret;
|
||||
private boolean autoCreateUser;
|
||||
private String useAsUsername;
|
||||
private String provider;
|
||||
|
||||
private Collection<String> scopes = new ArrayList<String>();
|
||||
|
||||
public boolean getEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public String getIssuer() {
|
||||
return issuer;
|
||||
}
|
||||
|
||||
public void setIssuer(String issuer) {
|
||||
this.issuer = issuer;
|
||||
}
|
||||
|
||||
public String getClientId() {
|
||||
return clientId;
|
||||
}
|
||||
|
||||
public void setClientId(String clientId) {
|
||||
this.clientId = clientId;
|
||||
}
|
||||
|
||||
public String getClientSecret() {
|
||||
return clientSecret;
|
||||
}
|
||||
|
||||
public void setClientSecret(String clientSecret) {
|
||||
this.clientSecret = clientSecret;
|
||||
}
|
||||
|
||||
public boolean getAutoCreateUser() {
|
||||
return autoCreateUser;
|
||||
}
|
||||
|
||||
public void setAutoCreateUser(boolean autoCreateUser) {
|
||||
this.autoCreateUser = autoCreateUser;
|
||||
}
|
||||
|
||||
public String getUseAsUsername() {
|
||||
if (useAsUsername != null && useAsUsername.trim().length() > 0) {
|
||||
return useAsUsername;
|
||||
}
|
||||
return "email";
|
||||
}
|
||||
|
||||
public void setUseAsUsername(String useAsUsername) {
|
||||
this.useAsUsername = useAsUsername;
|
||||
}
|
||||
|
||||
public String getProvider() {
|
||||
return provider;
|
||||
}
|
||||
|
||||
public void setProvider(String provider) {
|
||||
this.provider = provider;
|
||||
}
|
||||
|
||||
public Collection<String> getScopes() {
|
||||
return scopes;
|
||||
}
|
||||
|
||||
public void setScopes(String scpoes) {
|
||||
List<String> scopesList =
|
||||
Arrays.stream(scpoes.split(","))
|
||||
.map(String::trim)
|
||||
.collect(Collectors.toList());
|
||||
this.scopes.addAll(scopesList);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "OAUTH2 [enabled="
|
||||
+ enabled
|
||||
+ ", issuer="
|
||||
+ issuer
|
||||
+ ", clientId="
|
||||
+ clientId
|
||||
+ ", clientSecret="
|
||||
+ (clientSecret != null && !clientSecret.isEmpty() ? "MASKED" : "NULL")
|
||||
+ ", autoCreateUser="
|
||||
+ autoCreateUser
|
||||
+ ", useAsUsername="
|
||||
+ useAsUsername
|
||||
+ ", provider"
|
||||
+ provider
|
||||
+ ", scopes="
|
||||
+ scopes
|
||||
+ "]";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class System {
|
||||
private String defaultLocale;
|
||||
private Boolean googlevisibility;
|
||||
private String rootURIPath;
|
||||
private String customStaticFilePath;
|
||||
private Integer maxFileSize;
|
||||
private boolean showUpdate;
|
||||
private Boolean showUpdateOnlyAdmin;
|
||||
private boolean customHTMLFiles;
|
||||
@@ -264,29 +381,8 @@ public class ApplicationProperties {
|
||||
this.googlevisibility = googlevisibility;
|
||||
}
|
||||
|
||||
public String getRootURIPath() {
|
||||
return rootURIPath;
|
||||
}
|
||||
|
||||
|
||||
public void setRootURIPath(String rootURIPath) {
|
||||
this.rootURIPath = rootURIPath;
|
||||
}
|
||||
|
||||
public String getCustomStaticFilePath() {
|
||||
return customStaticFilePath;
|
||||
}
|
||||
|
||||
public void setCustomStaticFilePath(String customStaticFilePath) {
|
||||
this.customStaticFilePath = customStaticFilePath;
|
||||
}
|
||||
|
||||
public Integer getMaxFileSize() {
|
||||
return maxFileSize;
|
||||
}
|
||||
|
||||
public void setMaxFileSize(Integer maxFileSize) {
|
||||
this.maxFileSize = maxFileSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
@@ -294,12 +390,6 @@ public class ApplicationProperties {
|
||||
+ defaultLocale
|
||||
+ ", googlevisibility="
|
||||
+ googlevisibility
|
||||
+ ", rootURIPath="
|
||||
+ rootURIPath
|
||||
+ ", customStaticFilePath="
|
||||
+ customStaticFilePath
|
||||
+ ", maxFileSize="
|
||||
+ maxFileSize
|
||||
+ ", enableAlphaFunctionality="
|
||||
+ enableAlphaFunctionality
|
||||
+ ", showUpdate="
|
||||
|
||||
@@ -5,7 +5,7 @@ public class AttemptCounter {
|
||||
private long lastAttemptTime;
|
||||
|
||||
public AttemptCounter() {
|
||||
this.attemptCount = 1;
|
||||
this.attemptCount = 0;
|
||||
this.lastAttemptTime = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
@@ -18,11 +18,16 @@ public class AttemptCounter {
|
||||
return attemptCount;
|
||||
}
|
||||
|
||||
public long getlastAttemptTime() {
|
||||
public long getLastAttemptTime() {
|
||||
return lastAttemptTime;
|
||||
}
|
||||
|
||||
public boolean shouldReset(long ATTEMPT_INCREMENT_TIME) {
|
||||
return System.currentTimeMillis() - lastAttemptTime > ATTEMPT_INCREMENT_TIME;
|
||||
public boolean shouldReset(long attemptIncrementTime) {
|
||||
return System.currentTimeMillis() - lastAttemptTime > attemptIncrementTime;
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
this.attemptCount = 0;
|
||||
this.lastAttemptTime = System.currentTimeMillis();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
package stirling.software.SPDF.model;
|
||||
|
||||
public enum AuthenticationType {
|
||||
WEB,
|
||||
OAUTH2
|
||||
}
|
||||
@@ -47,6 +47,9 @@ public class User {
|
||||
@Column(name = "roleName")
|
||||
private String roleName;
|
||||
|
||||
@Column(name = "authenticationtype")
|
||||
private String authenticationType;
|
||||
|
||||
@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy = "user")
|
||||
private Set<Authority> authorities = new HashSet<>();
|
||||
|
||||
@@ -116,6 +119,14 @@ public class User {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public void setAuthenticationType(AuthenticationType authenticationType) {
|
||||
this.authenticationType = authenticationType.toString().toLowerCase();
|
||||
}
|
||||
|
||||
public String getAuthenticationType() {
|
||||
return authenticationType;
|
||||
}
|
||||
|
||||
public Set<Authority> getAuthorities() {
|
||||
return authorities;
|
||||
}
|
||||
@@ -137,4 +148,8 @@ public class User {
|
||||
.map(Authority::getAuthority)
|
||||
.collect(Collectors.joining(", "));
|
||||
}
|
||||
|
||||
public boolean hasPassword() {
|
||||
return this.password != null && !this.password.isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
package stirling.software.SPDF.model.api.misc;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import stirling.software.SPDF.model.api.PDFFile;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class FlattenRequest extends PDFFile {
|
||||
|
||||
@Schema(
|
||||
description =
|
||||
"True to flatten only the forms, false to flatten full PDF (Convert page to image)")
|
||||
private Boolean flattenOnlyForms;
|
||||
}
|
||||
@@ -9,4 +9,6 @@ import stirling.software.SPDF.model.Authority;
|
||||
public interface AuthorityRepository extends JpaRepository<Authority, Long> {
|
||||
// Set<Authority> findByUsername(String username);
|
||||
Set<Authority> findByUser_Username(String username);
|
||||
|
||||
Authority findByUserId(long user_id);
|
||||
}
|
||||
|
||||
@@ -58,10 +58,10 @@ public class ProcessExecutor {
|
||||
long timeoutMinutes =
|
||||
switch (key) {
|
||||
case LIBRE_OFFICE -> 30;
|
||||
case PDFTOHTML -> 5;
|
||||
case PDFTOHTML -> 20;
|
||||
case OCR_MY_PDF -> 30;
|
||||
case PYTHON_OPENCV -> 30;
|
||||
case GHOSTSCRIPT -> 5;
|
||||
case GHOSTSCRIPT -> 30;
|
||||
case WEASYPRINT -> 30;
|
||||
case INSTALL_APP -> 60;
|
||||
case CALIBRE -> 30;
|
||||
|
||||
@@ -24,8 +24,8 @@ spring.devtools.livereload.enabled=true
|
||||
|
||||
spring.thymeleaf.encoding=UTF-8
|
||||
|
||||
server.connection-timeout=${SYSTEM_CONNECTIONTIMEOUTMINUTES:5m}
|
||||
spring.mvc.async.request-timeout=${SYSTEM_CONNECTIONTIMEOUTMILLISECONDS:300000}
|
||||
server.connection-timeout=${SYSTEM_CONNECTIONTIMEOUTMINUTES:20m}
|
||||
spring.mvc.async.request-timeout=${SYSTEM_CONNECTIONTIMEOUTMILLISECONDS:1200000}
|
||||
|
||||
spring.resources.static-locations=file:customFiles/static/
|
||||
#spring.thymeleaf.prefix=file:/customFiles/templates/,classpath:/templates/
|
||||
|
||||
@@ -54,9 +54,13 @@ notAuthenticatedMessage=User not authenticated.
|
||||
userNotFoundMessage=User not found.
|
||||
incorrectPasswordMessage=Current password is incorrect.
|
||||
usernameExistsMessage=New Username already exists.
|
||||
invalidUsernameMessage=Invalid username, Username must only contain alphabet characters and numbers.
|
||||
invalidUsernameMessage=Invalid username, username can only contain letters, numbers and the following special characters @._+- or must be a valid email address.
|
||||
deleteCurrentUserMessage=Cannot delete currently logged in user.
|
||||
deleteUsernameExistsMessage=The username does not exist and cannot be deleted.
|
||||
downgradeCurrentUserMessage=لا يمكن خفض دور المستخدم الحالي
|
||||
downgradeCurrentUserLongMessage=لا يمكن تخفيض دور المستخدم الحالي. وبالتالي، لن يظهر المستخدم الحالي.
|
||||
userAlreadyExistsOAuthMessage=The user already exists as an OAuth2 user.
|
||||
userAlreadyExistsWebMessage=The user already exists as an web user.
|
||||
error=Error
|
||||
oops=Oops!
|
||||
help=Help
|
||||
@@ -67,6 +71,7 @@ visitGithub=Visit Github Repository
|
||||
donate=Donate
|
||||
color=Color
|
||||
sponsor=Sponsor
|
||||
info=Info
|
||||
|
||||
|
||||
|
||||
@@ -100,12 +105,18 @@ pipelineOptions.validateButton=Validate
|
||||
#############
|
||||
# NAVBAR #
|
||||
#############
|
||||
navbar.convert=تحويل
|
||||
navbar.security=الأمان
|
||||
navbar.other=أخرى
|
||||
navbar.favorite=Favorites
|
||||
navbar.darkmode=الوضع الداكن
|
||||
navbar.pageOps=عمليات الصفحة
|
||||
navbar.language=Languages
|
||||
navbar.settings=إعدادات
|
||||
navbar.allTools=Tools
|
||||
navbar.multiTool=Multi Tools
|
||||
navbar.sections.organize=Organize
|
||||
navbar.sections.convertTo=Convert to PDF
|
||||
navbar.sections.convertFrom=Convert from PDF
|
||||
navbar.sections.security=Sign & Security
|
||||
navbar.sections.advance=Advanced
|
||||
navbar.sections.edit=View & Edit
|
||||
|
||||
#############
|
||||
# SETTINGS #
|
||||
@@ -162,7 +173,7 @@ adminUserSettings.header=Admin User Control Settings
|
||||
adminUserSettings.admin=Admin
|
||||
adminUserSettings.user=User
|
||||
adminUserSettings.addUser=Add New User
|
||||
adminUserSettings.usernameInfo=Username must only contain letters and numbers, no spaces or special characters.
|
||||
adminUserSettings.usernameInfo=Username can only contain letters, numbers and the following special characters @._+- or must be a valid email address.
|
||||
adminUserSettings.roles=Roles
|
||||
adminUserSettings.role=Role
|
||||
adminUserSettings.actions=Actions
|
||||
@@ -173,6 +184,8 @@ adminUserSettings.demoUser=Demo User (No custom settings)
|
||||
adminUserSettings.internalApiUser=Internal API User
|
||||
adminUserSettings.forceChange=Force user to change password on login
|
||||
adminUserSettings.submit=Save User
|
||||
adminUserSettings.changeUserRole=تغيير دور المستخدم
|
||||
adminUserSettings.authenticated=Authenticated
|
||||
|
||||
#############
|
||||
# HOME-PAGE #
|
||||
@@ -437,6 +450,8 @@ login.rememberme=Remember me
|
||||
login.invalid=Invalid username or password.
|
||||
login.locked=Your account has been locked.
|
||||
login.signinTitle=Please sign in
|
||||
login.ssoSignIn=تسجيل الدخول عبر تسجيل الدخول الأحادي
|
||||
login.oauth2AutoCreateDisabled=تم تعطيل مستخدم الإنشاء التلقائي لـ OAuth2
|
||||
|
||||
|
||||
#auto-redact
|
||||
@@ -689,6 +704,7 @@ repair.submit=الإصلاح
|
||||
#flatten
|
||||
flatten.title=تسطيح
|
||||
flatten.header=تسوية ملفات PDF
|
||||
flatten.flattenOnlyForms=Flatten only forms
|
||||
flatten.submit=تسطيح
|
||||
|
||||
|
||||
@@ -736,6 +752,7 @@ extractImages.submit=استخراج
|
||||
fileToPDF.title=ملف إلى PDF
|
||||
fileToPDF.header=تحويل أي ملف إلى PDF
|
||||
fileToPDF.credit=تستخدم هذه الخدمة ليبر أوفيس وأونوكونف لتحويل الملفات.
|
||||
fileToPDF.supportedFileTypesInfo=Supported File types
|
||||
fileToPDF.supportedFileTypes=يجب أن تتضمن أنواع الملفات المدعومة ما يلي ولكن للحصول على قائمة محدثة كاملة بالتنسيقات المدعومة ، يرجى الرجوع إلى وثائق LibreOffice
|
||||
fileToPDF.submit=تحويل إلى PDF
|
||||
|
||||
@@ -788,7 +805,7 @@ pdfOrganiser.placeholder=(e.g. 1,3,2 or 4-8,2,10-12 or 2n-1)
|
||||
#multiTool
|
||||
multiTool.title=أداة متعددة PDF
|
||||
multiTool.header=أداة متعددة PDF
|
||||
multiTool.uploadPrompts=Please Upload PDF
|
||||
multiTool.uploadPrompts=File Name
|
||||
|
||||
#view pdf
|
||||
viewPdf.title=View PDF
|
||||
@@ -1043,7 +1060,7 @@ licenses.version=Version
|
||||
licenses.license=License
|
||||
|
||||
|
||||
# error
|
||||
#error
|
||||
error.sorry=Sorry for the issue!
|
||||
error.needHelp=Need help / Found an issue?
|
||||
error.contactTip=If you're still having trouble, don't hesitate to reach out to us for help. You can submit a ticket on our GitHub page or contact us through Discord:
|
||||
|
||||
@@ -11,17 +11,17 @@ imgPrompt=Изберете изображение(я)
|
||||
genericSubmit=Подайте
|
||||
processTimeWarning=Предупреждение: Този процес може да отнеме до минута в зависимост от размера на файла
|
||||
pageOrderPrompt=Персонализиран ред на страниците (Въведете разделен със запетаи списък с номера на страници или функции като 2n+1):
|
||||
pageSelectionPrompt=Custom Page Selection (Enter a comma-separated list of page numbers 1,5,6 or Functions like 2n+1) :
|
||||
pageSelectionPrompt=Персонализиран избор на страница (Въведете списък с номера на страници 1,5,6, разделени със запетая, или функции като 2n+1) :
|
||||
goToPage=Давай
|
||||
true=Вярно
|
||||
false=Невярно
|
||||
unknown=Непознат
|
||||
save=Съхранете
|
||||
saveToBrowser=Save to Browser
|
||||
saveToBrowser=Съхраняване в браузъра
|
||||
close=Затворете
|
||||
filesSelected=избрани файлове
|
||||
noFavourites=Няма добавени любими
|
||||
downloadComplete=Download Complete
|
||||
downloadComplete=Свалянето завършено
|
||||
bored=Отекчени сте да чакате?
|
||||
alphabet=Азбука
|
||||
downloadPdf=Изтеглете PDF
|
||||
@@ -45,54 +45,59 @@ red=Червено
|
||||
green=Зелено
|
||||
blue=Синьо
|
||||
custom=Персонализиране...
|
||||
WorkInProgess=Work in progress, May not work or be buggy, Please report any problems!
|
||||
poweredBy=Powered by
|
||||
yes=Yes
|
||||
no=No
|
||||
WorkInProgess=Работата е в ход, може да не работи или да има грешки, моля, докладвайте за проблеми!
|
||||
poweredBy=Задвижван чрез
|
||||
yes=Да
|
||||
no=Не
|
||||
changedCredsMessage=Идентификационните данни са променени!
|
||||
notAuthenticatedMessage=Потребителят не е автентикиран.
|
||||
userNotFoundMessage=Потребителят не е намерен
|
||||
incorrectPasswordMessage=Текущата парола е неправилна.
|
||||
usernameExistsMessage=Новият потребител вече съществува.
|
||||
invalidUsernameMessage=Invalid username, Username must only contain alphabet characters and numbers.
|
||||
deleteCurrentUserMessage=Cannot delete currently logged in user.
|
||||
deleteUsernameExistsMessage=The username does not exist and cannot be deleted.
|
||||
error=Error
|
||||
oops=Oops!
|
||||
help=Help
|
||||
goHomepage=Go to Homepage
|
||||
joinDiscord=Join our Discord server
|
||||
seeDockerHub=See Docker Hub
|
||||
visitGithub=Visit Github Repository
|
||||
donate=Donate
|
||||
color=Color
|
||||
sponsor=Sponsor
|
||||
invalidUsernameMessage=Невалидно потребителско име, потребителското име може да съдържа само букви, цифри и следните специални знаци @._+- или трябва да е валиден имейл адрес.
|
||||
deleteCurrentUserMessage=Не може да се изтрие вписания в момента потребител.
|
||||
deleteUsernameExistsMessage=Потребителското име не съществува и не може да бъде изтрито.
|
||||
downgradeCurrentUserMessage=Не може да се понижи ролята на текущия потребител
|
||||
downgradeCurrentUserLongMessage=Не може да се понижи ролята на текущия потребител. Следователно текущият потребител няма да бъде показан.
|
||||
userAlreadyExistsOAuthMessage=The user already exists as an OAuth2 user.
|
||||
userAlreadyExistsWebMessage=The user already exists as an web user.
|
||||
error=Грешка
|
||||
oops=Опаа!
|
||||
help=Помощ
|
||||
goHomepage=Отидете на началната страница
|
||||
joinDiscord=Присъединете се към нашия Discord сървър
|
||||
seeDockerHub=Погледнете Docker Hub
|
||||
visitGithub=Посетете Github Repository
|
||||
donate=Направете дарение
|
||||
color=Цвят
|
||||
sponsor=Спонсор
|
||||
info=Info
|
||||
|
||||
|
||||
|
||||
###############
|
||||
# Pipeline #
|
||||
###############
|
||||
pipeline.header=Pipeline Menu (Beta)
|
||||
pipeline.uploadButton=Upload Custom
|
||||
pipeline.configureButton=Configure
|
||||
pipeline.defaultOption=Custom
|
||||
pipeline.submitButton=Submit
|
||||
pipeline.help=Pipeline Help
|
||||
pipeline.scanHelp=Folder Scanning Help
|
||||
pipeline.header=Pipeline Меню (Бета)
|
||||
pipeline.uploadButton=Качване на персонализиран
|
||||
pipeline.configureButton=Настройка
|
||||
pipeline.defaultOption=Персонализиран
|
||||
pipeline.submitButton=Подайте
|
||||
pipeline.help=Pipeline Помощ
|
||||
pipeline.scanHelp=Помощ за сканиране на папки
|
||||
|
||||
######################
|
||||
# Pipeline Options #
|
||||
######################
|
||||
pipelineOptions.header=Pipeline Configuration
|
||||
pipelineOptions.pipelineNameLabel=Pipeline Name
|
||||
pipelineOptions.saveSettings=Save Operation Settings
|
||||
pipelineOptions.pipelineNamePrompt=Enter pipeline name here
|
||||
pipelineOptions.selectOperation=Select Operation
|
||||
pipelineOptions.addOperationButton=Add operation
|
||||
pipelineOptions.header=Pipeline Конфигурация
|
||||
pipelineOptions.pipelineNameLabel=Pipeline име
|
||||
pipelineOptions.saveSettings=Запазете настройките за работа
|
||||
pipelineOptions.pipelineNamePrompt=Въведете името на pipeline тук
|
||||
pipelineOptions.selectOperation=Избор на операция
|
||||
pipelineOptions.addOperationButton=Добавяне на операция
|
||||
pipelineOptions.pipelineHeader=Pipeline:
|
||||
pipelineOptions.saveButton=Download
|
||||
pipelineOptions.validateButton=Validate
|
||||
pipelineOptions.saveButton=Изтегли
|
||||
pipelineOptions.validateButton=Валидирай
|
||||
|
||||
|
||||
|
||||
@@ -100,19 +105,25 @@ pipelineOptions.validateButton=Validate
|
||||
#############
|
||||
# NAVBAR #
|
||||
#############
|
||||
navbar.convert=Преобразуване
|
||||
navbar.security=Сигурност
|
||||
navbar.other=Разни
|
||||
navbar.favorite=Favorites
|
||||
navbar.darkmode=Тъмна тема
|
||||
navbar.pageOps=Операции със страници
|
||||
navbar.language=Languages
|
||||
navbar.settings=Настройки
|
||||
navbar.allTools=Tools
|
||||
navbar.multiTool=Multi Tools
|
||||
navbar.sections.organize=Organize
|
||||
navbar.sections.convertTo=Convert to PDF
|
||||
navbar.sections.convertFrom=Convert from PDF
|
||||
navbar.sections.security=Sign & Security
|
||||
navbar.sections.advance=Advanced
|
||||
navbar.sections.edit=View & Edit
|
||||
|
||||
#############
|
||||
# SETTINGS #
|
||||
#############
|
||||
settings.title=Настройки
|
||||
settings.update=Налична актуализация
|
||||
settings.updateAvailable={0} is the current installed version. A new version ({1}) is available.
|
||||
settings.updateAvailable={0} е текущата инсталирана версия. Налична е нова версия ({1}).
|
||||
settings.appVersion=Версия на приложението:
|
||||
settings.downloadOption.title=Изберете опция за изтегляне (за изтегляния на един файл без да е архивиран):
|
||||
settings.downloadOption.1=Отваряне в същия прозорец
|
||||
@@ -121,13 +132,13 @@ settings.downloadOption.3=Изтегли файл
|
||||
settings.zipThreshold=Архивирайте файловете, когато броят на изтеглените файлове надвишава
|
||||
settings.signOut=Изход
|
||||
settings.accountSettings=Настройки на акаунта
|
||||
settings.bored.help=Enables easter egg game
|
||||
settings.cacheInputs.name=Save form inputs
|
||||
settings.cacheInputs.help=Enable to store previously used inputs for future runs
|
||||
settings.bored.help=Активира игра с великденски яйца
|
||||
settings.cacheInputs.name=Запазете въведените формуляри
|
||||
settings.cacheInputs.help=Активирайте за съхраняване на предишни използвани въведени данни за бъдещи изпълнения
|
||||
|
||||
changeCreds.title=Промяна на идентификационните данни
|
||||
changeCreds.header=Актуализирайте данните за акаунта си
|
||||
changeCreds.changePassword=You are using default login credentials. Please enter a new password
|
||||
changeCreds.changePassword=Използвате идентификационни данни за вход по подразбиране. Моля, въведете нова парола
|
||||
changeCreds.newUsername=Ново потребителско име
|
||||
changeCreds.oldPassword=Текуща парола
|
||||
changeCreds.newPassword=Нова парола
|
||||
@@ -153,8 +164,8 @@ account.syncTitle=Синхронизиране на настройките на
|
||||
account.settingsCompare=Сравняване на настройките:
|
||||
account.property=Свойство
|
||||
account.webBrowserSettings=Уеб-браузър настройки
|
||||
account.syncToBrowser=Синхронизиране на акаунт -> Бразър
|
||||
account.syncToAccount=Синхронизиране на акаунт <- Бразър
|
||||
account.syncToBrowser=Синхронизиране на акаунт -> Браузър
|
||||
account.syncToAccount=Синхронизиране на акаунт <- Браузър
|
||||
|
||||
|
||||
adminUserSettings.title=Настройки за потребителски контрол
|
||||
@@ -162,28 +173,30 @@ adminUserSettings.header=Настройки за администраторск
|
||||
adminUserSettings.admin=Администратор
|
||||
adminUserSettings.user=Потребител
|
||||
adminUserSettings.addUser=Добавяне на нов потребител
|
||||
adminUserSettings.usernameInfo=Username must only contain letters and numbers, no spaces or special characters.
|
||||
adminUserSettings.usernameInfo=Потребителското име може да съдържа само букви, цифри и следните специални символи @._+- или трябва да е валиден имейл адрес.
|
||||
adminUserSettings.roles=Роли
|
||||
adminUserSettings.role=Роля
|
||||
adminUserSettings.actions=Действия
|
||||
adminUserSettings.apiUser=Ограничен API потребител
|
||||
adminUserSettings.extraApiUser=Additional Limited API User
|
||||
adminUserSettings.extraApiUser=Допълнителен ограничен API потребител
|
||||
adminUserSettings.webOnlyUser=Само за уеб-потребител
|
||||
adminUserSettings.demoUser=Demo User (No custom settings)
|
||||
adminUserSettings.internalApiUser=Internal API User
|
||||
adminUserSettings.demoUser=Демо потребител (без персонализирани настройки)
|
||||
adminUserSettings.internalApiUser=Вътрешен API потребител
|
||||
adminUserSettings.forceChange=Принудете потребителя да промени потребителското име/парола при влизане
|
||||
adminUserSettings.submit=Съхранете потребителя
|
||||
adminUserSettings.changeUserRole=Промяна на ролята на потребителя
|
||||
adminUserSettings.authenticated=Authenticated
|
||||
|
||||
#############
|
||||
# HOME-PAGE #
|
||||
#############
|
||||
home.desc=Вашето локално хоствано обслужване на едно място за всички ваши PDF нужди.
|
||||
home.searchBar=Search for features...
|
||||
home.searchBar=Търсене на функции...
|
||||
|
||||
|
||||
home.viewPdf.title=View PDF
|
||||
home.viewPdf.desc=View, annotate, add text or images
|
||||
viewPdf.tags=view,read,annotate,text,image
|
||||
home.viewPdf.title=Преглед на PDF
|
||||
home.viewPdf.desc=Преглеждайте, коментирайте, добавяйте текст или изображения
|
||||
viewPdf.tags=преглед,четене,анотиране,текст,изображение
|
||||
|
||||
home.multiTool.title=PDF Мулти инструмент
|
||||
home.multiTool.desc=Обединяване, завъртане, пренареждане и премахване на страници
|
||||
@@ -254,7 +267,7 @@ home.fileToPDF.desc=Преобразуване почти всеки файл к
|
||||
fileToPDF.tags=трансформация,формат,документ,изображение,слайд,текст,преобразуване,офис,документи,word,excel,powerpoint
|
||||
|
||||
home.ocr.title=OCR / Почистващи сканирания
|
||||
home.ocr.desc=Cleanup сканира и открива текст от изображения към PDF и го добавя отново като текст.
|
||||
home.ocr.desc=Почистване, сканира и открива текст от изображения към PDF и го добавя отново като текст.
|
||||
ocr.tags=разпознаване,текст,изображение,сканиране,четене,идентифициране,откриване,редактиране
|
||||
|
||||
|
||||
@@ -307,9 +320,9 @@ home.removeBlanks.title=Премахване на празни страници
|
||||
home.removeBlanks.desc=Открива и премахва празни страници от документ
|
||||
removeBlanks.tags=почистване,рационализиране,без съдържание,организиране
|
||||
|
||||
home.removeAnnotations.title=Remove Annotations
|
||||
home.removeAnnotations.desc=Removes all comments/annotations from a PDF
|
||||
removeAnnotations.tags=comments,highlight,notes,markup,remove
|
||||
home.removeAnnotations.title=Премахване на анотации
|
||||
home.removeAnnotations.desc=Премахва всички коментари/анотации от PDF
|
||||
removeAnnotations.tags=коментари, маркиране, бележки, маркиране, премахване
|
||||
|
||||
home.compare.title=Сравнете
|
||||
home.compare.desc=Сравнява и показва разликите между 2 PDF документа
|
||||
@@ -351,7 +364,7 @@ home.autoSplitPDF.title=Автоматично разделяне на стра
|
||||
home.autoSplitPDF.desc=Автоматично разделяне на сканиран PDF файл с QR код за разделяне на физически сканирани страници
|
||||
autoSplitPDF.tags=QR-базиран,отделен,сканиране-сегмент,организиране
|
||||
|
||||
home.sanitizePdf.title=Дезинфекцирай
|
||||
home.sanitizePdf.title=Дезинфенкцирам
|
||||
home.sanitizePdf.desc=Премахване на скриптове и други елементи от PDF файлове
|
||||
sanitizePdf.tags=чисти,сигурни,безопасни,премахване-заплахи
|
||||
|
||||
@@ -393,35 +406,35 @@ home.autoRedact.desc=Автоматично редактира (зачерняв
|
||||
autoRedact.tags=Редактиране,Скриване,затъмняване,черен,маркер,скрит
|
||||
|
||||
home.tableExtraxt.title=PDF to CSV
|
||||
home.tableExtraxt.desc=Extracts Tables from a PDF converting it to CSV
|
||||
tableExtraxt.tags=CSV,Table Extraction,extract,convert
|
||||
home.tableExtraxt.desc=Извлича таблици от PDF, като ги конвертира в CSV
|
||||
tableExtraxt.tags=CSV,извличане на таблица,извличане,конвертиране
|
||||
|
||||
|
||||
home.autoSizeSplitPDF.title=Auto Split by Size/Count
|
||||
home.autoSizeSplitPDF.desc=Split a single PDF into multiple documents based on size, page count, or document count
|
||||
autoSizeSplitPDF.tags=pdf,split,document,organization
|
||||
home.autoSizeSplitPDF.title=Автоматично разделяне по размер/брой
|
||||
home.autoSizeSplitPDF.desc=Разделете един PDF на множество документи въз основа на размер, брой страници или брой документи
|
||||
autoSizeSplitPDF.tags=pdf,разделяне,документ,организация
|
||||
|
||||
|
||||
home.overlay-pdfs.title=Overlay PDFs
|
||||
home.overlay-pdfs.desc=Overlays PDFs on-top of another PDF
|
||||
overlay-pdfs.tags=Overlay
|
||||
home.overlay-pdfs.title=Наслагване PDF-и
|
||||
home.overlay-pdfs.desc=Наслагва PDF файлове върху друг PDF
|
||||
overlay-pdfs.tags=Наслагване
|
||||
|
||||
home.split-by-sections.title=Split PDF by Sections
|
||||
home.split-by-sections.desc=Divide each page of a PDF into smaller horizontal and vertical sections
|
||||
split-by-sections.tags=Section Split, Divide, Customize
|
||||
home.split-by-sections.title=Разделяне на PDF по секции
|
||||
home.split-by-sections.desc=Разделете всяка страница от PDF на по-малки хоризонтални и вертикални секции
|
||||
split-by-sections.tags=Разделяне на секция,Разделяне,Персонализиране
|
||||
|
||||
home.AddStampRequest.title=Add Stamp to PDF
|
||||
home.AddStampRequest.desc=Add text or add image stamps at set locations
|
||||
AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Customize
|
||||
home.AddStampRequest.title=Добавяне на печат към PDF
|
||||
home.AddStampRequest.desc=Добавете текст или добавете печати с изображения на определени места
|
||||
AddStampRequest.tags=Печат,добавяне на изображение,централно изображение,воден знак,PDF,вграждане,персонализиране
|
||||
|
||||
|
||||
home.PDFToBook.title=PDF to Book
|
||||
home.PDFToBook.desc=Converts PDF to Book/Comic formats using calibre
|
||||
PDFToBook.tags=Book,Comic,Calibre,Convert,manga,amazon,kindle
|
||||
home.PDFToBook.title=PDF към книга
|
||||
home.PDFToBook.desc=Преобразува PDF във формати на книги/комикси с помощта на calibre
|
||||
PDFToBook.tags=Книга,комикс,calibre,конвертиране,манга,Amazon,Kindle
|
||||
|
||||
home.BookToPDF.title=Book to PDF
|
||||
home.BookToPDF.desc=Converts Books/Comics formats to PDF using calibre
|
||||
BookToPDF.tags=Book,Comic,Calibre,Convert,manga,amazon,kindle
|
||||
home.BookToPDF.title=Книга към PDF
|
||||
home.BookToPDF.desc=Преобразува формати на книги/комикси в PDF с помощта на calibre
|
||||
BookToPDF.tags=Книга,комикс,calibre,конвертиране,манга,Amazon,Kindle
|
||||
|
||||
|
||||
###########################
|
||||
@@ -437,6 +450,8 @@ login.rememberme=Запомни ме
|
||||
login.invalid=Невалидно потребителско име или парола.
|
||||
login.locked=Вашият акаунт е заключен.
|
||||
login.signinTitle=Моля впишете се
|
||||
login.ssoSignIn=Влизане чрез еднократно влизане
|
||||
login.oauth2AutoCreateDisabled=OAUTH2 Автоматично създаване на потребител е деактивирано
|
||||
|
||||
|
||||
#auto-redact
|
||||
@@ -466,9 +481,9 @@ pdfToSinglePage.submit=Преобразуване към единична стр
|
||||
|
||||
|
||||
#pageExtracter
|
||||
pageExtracter.title=Extract Pages
|
||||
pageExtracter.header=Extract Pages
|
||||
pageExtracter.submit=Extract
|
||||
pageExtracter.title=Извличане на страници
|
||||
pageExtracter.header=Извличане на страници
|
||||
pageExtracter.submit=Извличане
|
||||
pageExtracter.placeholder=(e.g. 1,2,8 or 4,7,12-16 or 2n-1)
|
||||
|
||||
|
||||
@@ -498,40 +513,40 @@ URLToPDF.credit=Използва WeasyPrint
|
||||
#html-to-pdf
|
||||
HTMLToPDF.title=HTML към PDF
|
||||
HTMLToPDF.header=HTML към PDF
|
||||
HTMLToPDF.help=Приема HTML файлове и ZIP файлове, съдържащи html/css/изображения и т.н
|
||||
HTMLToPDF.help=Приемане на HTML файлове и ZIP файлове, съдържащи html/css/изображения и т.н.
|
||||
HTMLToPDF.submit=Преобразуване
|
||||
HTMLToPDF.credit=Използва WeasyPrint
|
||||
HTMLToPDF.zoom=Zoom level for displaying the website.
|
||||
HTMLToPDF.pageWidth=Width of the page in centimeters. (Blank to default)
|
||||
HTMLToPDF.pageHeight=Height of the page in centimeters. (Blank to default)
|
||||
HTMLToPDF.marginTop=Top margin of the page in millimeters. (Blank to default)
|
||||
HTMLToPDF.marginBottom=Bottom margin of the page in millimeters. (Blank to default)
|
||||
HTMLToPDF.marginLeft=Left margin of the page in millimeters. (Blank to default)
|
||||
HTMLToPDF.marginRight=Right margin of the page in millimeters. (Blank to default)
|
||||
HTMLToPDF.printBackground=Render the background of websites.
|
||||
HTMLToPDF.defaultHeader=Enable Default Header (Name and page number)
|
||||
HTMLToPDF.cssMediaType=Change the CSS media type of the page.
|
||||
HTMLToPDF.none=None
|
||||
HTMLToPDF.print=Print
|
||||
HTMLToPDF.screen=Screen
|
||||
HTMLToPDF.zoom=Ниво на мащабиране за показване на уебсайта.
|
||||
HTMLToPDF.pageWidth=Ширина на страницата в сантиметри. (Празно по подразбиране)
|
||||
HTMLToPDF.pageHeight=Височина на страницата в сантиметри. (Празно по подразбиране)
|
||||
HTMLToPDF.marginTop=Горно поле на страницата в милиметри. (Празно по подразбиране)
|
||||
HTMLToPDF.marginBottom=Долно поле на страницата в милиметри. (Празно по подразбиране)
|
||||
HTMLToPDF.marginLeft=Ляво поле на страницата в милиметри. (Празно по подразбиране)
|
||||
HTMLToPDF.marginRight=Дясно поле на страницата в милиметри. (Празно по подразбиране)
|
||||
HTMLToPDF.printBackground=Изобразете фона на уебсайтове.
|
||||
HTMLToPDF.defaultHeader=Активиране на горния колонтитул по подразбиране (име и номер на страница)
|
||||
HTMLToPDF.cssMediaType=Променете CSS медийния тип на страницата.
|
||||
HTMLToPDF.none=Няма
|
||||
HTMLToPDF.print=Печат
|
||||
HTMLToPDF.screen=Екран
|
||||
|
||||
|
||||
#AddStampRequest
|
||||
AddStampRequest.header=Stamp PDF
|
||||
AddStampRequest.title=Stamp PDF
|
||||
AddStampRequest.stampType=Stamp Type
|
||||
AddStampRequest.stampText=Stamp Text
|
||||
AddStampRequest.stampImage=Stamp Image
|
||||
AddStampRequest.alphabet=Alphabet
|
||||
AddStampRequest.fontSize=Font/Image Size
|
||||
AddStampRequest.rotation=Rotation
|
||||
AddStampRequest.opacity=Opacity
|
||||
AddStampRequest.position=Position
|
||||
AddStampRequest.overrideX=Override X Coordinate
|
||||
AddStampRequest.overrideY=Override Y Coordinate
|
||||
AddStampRequest.customMargin=Custom Margin
|
||||
AddStampRequest.customColor=Custom Text Color
|
||||
AddStampRequest.submit=Submit
|
||||
AddStampRequest.header=Поставяне на печат на PDF
|
||||
AddStampRequest.title=Поставяне на печат на PDF
|
||||
AddStampRequest.stampType=Тип печат
|
||||
AddStampRequest.stampText=Поставяне на текст
|
||||
AddStampRequest.stampImage=Изображение с печат
|
||||
AddStampRequest.alphabet=Азбука
|
||||
AddStampRequest.fontSize=Размер на шрифта/изображението
|
||||
AddStampRequest.rotation=Ротация
|
||||
AddStampRequest.opacity=Непрозрачност
|
||||
AddStampRequest.position=Позиция
|
||||
AddStampRequest.overrideX=Замяна на X координата
|
||||
AddStampRequest.overrideY=Замяна на Y координата
|
||||
AddStampRequest.customMargin=Персонализиран марж
|
||||
AddStampRequest.customColor=Персонализиран цвят на текста
|
||||
AddStampRequest.submit=Изпращане
|
||||
|
||||
|
||||
#sanitizePDF
|
||||
@@ -620,11 +635,11 @@ scalePages.submit=Подайте
|
||||
certSign.title=Подписване на сертификат
|
||||
certSign.header=Подпишете PDF с вашия сертификат (В процес на работа)
|
||||
certSign.selectPDF=Изберете PDF файл за подписване:
|
||||
certSign.jksNote=Note: If your certificate type is not listed below, please convert it to a Java Keystore (.jks) file using the keytool command line tool. Then, choose the .jks file option below.
|
||||
certSign.jksNote=Забележка: Ако вашият тип сертификат не е в списъка по-долу, моля, конвертирайте го във файл на Java Keystore (.jks) с помощта на инструмента за команден ред keytool. След това изберете опцията за .jks файл по-долу.
|
||||
certSign.selectKey=Изберете вашия файл с личен ключ (формат PKCS#8, може да бъде .pem или .der):
|
||||
certSign.selectCert=Изберете вашия файл със сертификат (формат X.509, може да бъде .pem или .der):
|
||||
certSign.selectP12=Изберете вашия PKCS#12 Keystore файл (.p12 или .pfx) (По избор, ако е предоставен, трябва да съдържа вашия личен ключ и сертификат):
|
||||
certSign.selectJKS=Select Your Java Keystore File (.jks or .keystore):
|
||||
certSign.selectJKS=Изберете Вашия Java Keystore Файл (.jks или .keystore):
|
||||
certSign.certType=Тип сертификат
|
||||
certSign.password=Въведете вашата парола за Keystore за ключове или частен ключ (ако има):
|
||||
certSign.showSig=Показване на подпис
|
||||
@@ -645,9 +660,9 @@ removeBlanks.submit=Премахване на празни места
|
||||
|
||||
|
||||
#removeAnnotations
|
||||
removeAnnotations.title=Remove Annotations
|
||||
removeAnnotations.header=Remove Annotations
|
||||
removeAnnotations.submit=Remove
|
||||
removeAnnotations.title=Премахване на анотации
|
||||
removeAnnotations.header=Премахване на анотации
|
||||
removeAnnotations.submit=Премахване
|
||||
|
||||
|
||||
#compare
|
||||
@@ -658,17 +673,17 @@ compare.document.2=Документ 2
|
||||
compare.submit=Сравнявай
|
||||
|
||||
#BookToPDF
|
||||
BookToPDF.title=Books and Comics to PDF
|
||||
BookToPDF.header=Book to PDF
|
||||
BookToPDF.credit=Uses Calibre
|
||||
BookToPDF.submit=Convert
|
||||
BookToPDF.title=Книги и комикси в PDF
|
||||
BookToPDF.header=Книга в PDF
|
||||
BookToPDF.credit=Използва Calibre
|
||||
BookToPDF.submit=Конвертиране
|
||||
|
||||
#PDFToBook
|
||||
PDFToBook.title=PDF to Book
|
||||
PDFToBook.header=PDF to Book
|
||||
PDFToBook.selectText.1=Format
|
||||
PDFToBook.credit=Uses Calibre
|
||||
PDFToBook.submit=Convert
|
||||
PDFToBook.title=PDF към книга
|
||||
PDFToBook.header=PDF към книга
|
||||
PDFToBook.selectText.1=Формат
|
||||
PDFToBook.credit=Използва Calibre
|
||||
PDFToBook.submit=Конвертиране
|
||||
|
||||
#sign
|
||||
sign.title=Подпишете
|
||||
@@ -689,6 +704,7 @@ repair.submit=Поправи
|
||||
#flatten
|
||||
flatten.title=Изравнете
|
||||
flatten.header=Изравнете PDF-и
|
||||
flatten.flattenOnlyForms=Изравнете само форми
|
||||
flatten.submit=Изравнете
|
||||
|
||||
|
||||
@@ -736,6 +752,7 @@ extractImages.submit=Извличане
|
||||
fileToPDF.title=Файл към PDF
|
||||
fileToPDF.header=Конвертирайте всеки файл към PDF
|
||||
fileToPDF.credit=Тази услуга използва LibreOffice и Unoconv за преобразуване на файлове.
|
||||
fileToPDF.supportedFileTypesInfo=Supported File types
|
||||
fileToPDF.supportedFileTypes=Поддържаните типове файлове трябва да включват по-долу, но за пълен актуализиран списък на поддържаните формати, моля, вижте документацията на LibreOffice
|
||||
fileToPDF.submit=Преобразуване към PDF
|
||||
|
||||
@@ -748,7 +765,7 @@ compress.selectText.1=Ръчен режим - От 1 до 4
|
||||
compress.selectText.2=Ниво на оптимизация:
|
||||
compress.selectText.3=4 (Ужасно за текстови изображения)
|
||||
compress.selectText.4=Автоматичен режим - Автоматично настройва качеството, за да получи PDF точен размер
|
||||
compress.selectText.5=Очакван PDF размер (напр. 25MB, 10.8MB, 25KB)
|
||||
compress.selectText.5=Очакван PDF размер (напр. 25МБ, 10.8МБ, 25КБ)
|
||||
compress.submit=Компресиране
|
||||
|
||||
|
||||
@@ -772,27 +789,27 @@ merge.submit=Обединяване
|
||||
pdfOrganiser.title=Организатор на страници
|
||||
pdfOrganiser.header=Организатор на PDF страници
|
||||
pdfOrganiser.submit=Пренареждане на страниците
|
||||
pdfOrganiser.mode=Mode
|
||||
pdfOrganiser.mode.1=Custom Page Order
|
||||
pdfOrganiser.mode.2=Reverse Order
|
||||
pdfOrganiser.mode.3=Duplex Sort
|
||||
pdfOrganiser.mode.4=Booklet Sort
|
||||
pdfOrganiser.mode.5=Side Stitch Booklet Sort
|
||||
pdfOrganiser.mode.6=Odd-Even Split
|
||||
pdfOrganiser.mode.7=Remove First
|
||||
pdfOrganiser.mode.8=Remove Last
|
||||
pdfOrganiser.mode.9=Remove First and Last
|
||||
pdfOrganiser.placeholder=(e.g. 1,3,2 or 4-8,2,10-12 or 2n-1)
|
||||
pdfOrganiser.mode=Режим
|
||||
pdfOrganiser.mode.1=Персонализиран ред на страниците
|
||||
pdfOrganiser.mode.2=Обърнат ред
|
||||
pdfOrganiser.mode.3=Двустранно сортиране
|
||||
pdfOrganiser.mode.4=Сортиране на брошури
|
||||
pdfOrganiser.mode.5=Сортиране на брошури със страничен шев
|
||||
pdfOrganiser.mode.6=Четно-нечетно разделяне
|
||||
pdfOrganiser.mode.7=Премахни първо
|
||||
pdfOrganiser.mode.8=Премахване на последния
|
||||
pdfOrganiser.mode.9=Премахване на първия и последния
|
||||
pdfOrganiser.placeholder=(напр. 1,3,2 или 4-8,2,10-12 или 2n-1)
|
||||
|
||||
|
||||
#multiTool
|
||||
multiTool.title=PDF Мулти инструмент
|
||||
multiTool.header=PDF Мулти инструмент
|
||||
multiTool.uploadPrompts=Please Upload PDF
|
||||
multiTool.uploadPrompts=File Name
|
||||
|
||||
#view pdf
|
||||
viewPdf.title=View PDF
|
||||
viewPdf.header=View PDF
|
||||
viewPdf.title=Преглед на PDF
|
||||
viewPdf.header=Преглед на PDF
|
||||
|
||||
#pageRemover
|
||||
pageRemover.title=Премахване на страници
|
||||
@@ -940,8 +957,8 @@ pdfToPDFA.title=PDF към PDF/A
|
||||
pdfToPDFA.header=PDF към PDF/A
|
||||
pdfToPDFA.credit=Тази услуга използва OCRmyPDF за PDF/A преобразуване.
|
||||
pdfToPDFA.submit=Преобразуване
|
||||
pdfToPDFA.tip=Currently does not work for multiple inputs at once
|
||||
pdfToPDFA.outputFormat=Output format
|
||||
pdfToPDFA.tip=В момента не работи за няколко входа наведнъж
|
||||
pdfToPDFA.outputFormat=Изходен формат
|
||||
|
||||
|
||||
#PDFToWord
|
||||
@@ -984,75 +1001,75 @@ PDFToXML.submit=Преобразуване
|
||||
#PDFToCSV
|
||||
PDFToCSV.title=PDF ??? CSV
|
||||
PDFToCSV.header=PDF ??? CSV
|
||||
PDFToCSV.prompt=Choose page to extract table
|
||||
PDFToCSV.submit=????????
|
||||
PDFToCSV.prompt=Изберете страница за извличане на таблица
|
||||
PDFToCSV.submit=????
|
||||
|
||||
#split-by-size-or-count
|
||||
split-by-size-or-count.title=Split PDF by Size or Count
|
||||
split-by-size-or-count.header=Split PDF by Size or Count
|
||||
split-by-size-or-count.type.label=Select Split Type
|
||||
split-by-size-or-count.type.size=By Size
|
||||
split-by-size-or-count.type.pageCount=By Page Count
|
||||
split-by-size-or-count.type.docCount=By Document Count
|
||||
split-by-size-or-count.value.label=Enter Value
|
||||
split-by-size-or-count.value.placeholder=Enter size (e.g., 2MB or 3KB) or count (e.g., 5)
|
||||
split-by-size-or-count.submit=Submit
|
||||
split-by-size-or-count.title=Разделяне на PDF по размер или брой
|
||||
split-by-size-or-count.header=Разделяне на PDF по размер или брой
|
||||
split-by-size-or-count.type.label=Изберете тип разделяне
|
||||
split-by-size-or-count.type.size=По размер
|
||||
split-by-size-or-count.type.pageCount=По брой страници
|
||||
split-by-size-or-count.type.docCount=По брой документи
|
||||
split-by-size-or-count.value.label=Въведете стойност
|
||||
split-by-size-or-count.value.placeholder=Въведете размер (напр. 2МБ или 3КБ) или брой (напр. 5)
|
||||
split-by-size-or-count.submit=Изпращане
|
||||
|
||||
|
||||
#overlay-pdfs
|
||||
overlay-pdfs.header=Overlay PDF Files
|
||||
overlay-pdfs.baseFile.label=Select Base PDF File
|
||||
overlay-pdfs.overlayFiles.label=Select Overlay PDF Files
|
||||
overlay-pdfs.mode.label=Select Overlay Mode
|
||||
overlay-pdfs.mode.sequential=Sequential Overlay
|
||||
overlay-pdfs.mode.interleaved=Interleaved Overlay
|
||||
overlay-pdfs.mode.fixedRepeat=Fixed Repeat Overlay
|
||||
overlay-pdfs.counts.label=Overlay Counts (for Fixed Repeat Mode)
|
||||
overlay-pdfs.counts.placeholder=Enter comma-separated counts (e.g., 2,3,1)
|
||||
overlay-pdfs.position.label=Select Overlay Position
|
||||
overlay-pdfs.position.foreground=Foreground
|
||||
overlay-pdfs.position.background=Background
|
||||
overlay-pdfs.submit=Submit
|
||||
overlay-pdfs.header=Наслагване на PDF файлове
|
||||
overlay-pdfs.baseFile.label=Изберете Основен PDF файл
|
||||
overlay-pdfs.overlayFiles.label=Изберете наслагване на PDF файлове
|
||||
overlay-pdfs.mode.label=Изберете режим на наслагване
|
||||
overlay-pdfs.mode.sequential=Последователно наслагване
|
||||
overlay-pdfs.mode.interleaved=Преплетено наслагване
|
||||
overlay-pdfs.mode.fixedRepeat=Фиксирано наслагване при повторение
|
||||
overlay-pdfs.counts.label=Брой наслагвания (за режим на фиксирано повторение)
|
||||
overlay-pdfs.counts.placeholder=Въведете броя, разделени със запетая (напр. 2,3,1)
|
||||
overlay-pdfs.position.label=Изберете позиция на наслагване
|
||||
overlay-pdfs.position.foreground=Преден план
|
||||
overlay-pdfs.position.background=Фон
|
||||
overlay-pdfs.submit=Изпращане
|
||||
|
||||
|
||||
#split-by-sections
|
||||
split-by-sections.title=Split PDF by Sections
|
||||
split-by-sections.header=Split PDF into Sections
|
||||
split-by-sections.horizontal.label=Horizontal Divisions
|
||||
split-by-sections.vertical.label=Vertical Divisions
|
||||
split-by-sections.horizontal.placeholder=Enter number of horizontal divisions
|
||||
split-by-sections.vertical.placeholder=Enter number of vertical divisions
|
||||
split-by-sections.submit=Split PDF
|
||||
split-by-sections.merge=Merge Into One PDF
|
||||
split-by-sections.title=Разделяне на PDF по секции
|
||||
split-by-sections.header=Разделяне на PDF на секции
|
||||
split-by-sections.horizontal.label=Хоризонтални разделения
|
||||
split-by-sections.vertical.label=Вертикални разделения
|
||||
split-by-sections.horizontal.placeholder=Въведете брой хоризонтални деления
|
||||
split-by-sections.vertical.placeholder=Въведете брой вертикални деления
|
||||
split-by-sections.submit=Разделяне на PDF
|
||||
split-by-sections.merge=Сливане в един PDF
|
||||
|
||||
|
||||
#printFile
|
||||
printFile.title=Print File
|
||||
printFile.header=Print File to Printer
|
||||
printFile.selectText.1=Select File to Print
|
||||
printFile.selectText.2=Enter Printer Name
|
||||
printFile.submit=Print
|
||||
printFile.title=Печат на файл
|
||||
printFile.header=Печат на файл на принтер
|
||||
printFile.selectText.1=Изберете файл за печат
|
||||
printFile.selectText.2=Въведете име на принтер
|
||||
printFile.submit=Печат
|
||||
|
||||
|
||||
#licenses
|
||||
licenses.nav=Licenses
|
||||
licenses.title=3rd Party Licenses
|
||||
licenses.header=3rd Party Licenses
|
||||
licenses.module=Module
|
||||
licenses.version=Version
|
||||
licenses.license=License
|
||||
licenses.nav=Лицензи
|
||||
licenses.title=Лицензи на трети страни
|
||||
licenses.header=Лицензи на трети страни
|
||||
licenses.module=Модул
|
||||
licenses.version=Версия
|
||||
licenses.license=Лиценз
|
||||
|
||||
|
||||
# error
|
||||
error.sorry=Sorry for the issue!
|
||||
error.needHelp=Need help / Found an issue?
|
||||
error.contactTip=If you're still having trouble, don't hesitate to reach out to us for help. You can submit a ticket on our GitHub page or contact us through Discord:
|
||||
error.404.head=404 - Page Not Found | Oops, we tripped in the code!
|
||||
error.404.1=We can't seem to find the page you're looking for.
|
||||
error.404.2=Something went wrong
|
||||
error.github=Submit a ticket on GitHub
|
||||
error.showStack=Show Stack Trace
|
||||
error.copyStack=Copy Stack Trace
|
||||
error.githubSubmit=GitHub - Submit a ticket
|
||||
error.discordSubmit=Discord - Submit Support post
|
||||
#error
|
||||
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 - Изпратете запитване за поддръжка
|
||||
|
||||
|
||||
@@ -54,9 +54,13 @@ notAuthenticatedMessage=User not authenticated.
|
||||
userNotFoundMessage=User not found.
|
||||
incorrectPasswordMessage=Current password is incorrect.
|
||||
usernameExistsMessage=New Username already exists.
|
||||
invalidUsernameMessage=Invalid username, Username must only contain alphabet characters and numbers.
|
||||
invalidUsernameMessage=Invalid username, username can only contain letters, numbers and the following special characters @._+- or must be a valid email address.
|
||||
deleteCurrentUserMessage=Cannot delete currently logged in user.
|
||||
deleteUsernameExistsMessage=The username does not exist and cannot be deleted.
|
||||
downgradeCurrentUserMessage=No es pot reduir la funció de l'usuari actual
|
||||
downgradeCurrentUserLongMessage=No es pot baixar la funció de l'usuari actual. Per tant, no es mostrarà l'usuari actual.
|
||||
userAlreadyExistsOAuthMessage=The user already exists as an OAuth2 user.
|
||||
userAlreadyExistsWebMessage=The user already exists as an web user.
|
||||
error=Error
|
||||
oops=Oops!
|
||||
help=Help
|
||||
@@ -67,6 +71,7 @@ visitGithub=Visit Github Repository
|
||||
donate=Donate
|
||||
color=Color
|
||||
sponsor=Sponsor
|
||||
info=Info
|
||||
|
||||
|
||||
|
||||
@@ -100,12 +105,18 @@ pipelineOptions.validateButton=Validate
|
||||
#############
|
||||
# NAVBAR #
|
||||
#############
|
||||
navbar.convert=Converteix
|
||||
navbar.security=Seguretat
|
||||
navbar.other=Altres
|
||||
navbar.favorite=Favorites
|
||||
navbar.darkmode=Mode Fosc
|
||||
navbar.pageOps=Operacions de Pàgina
|
||||
navbar.language=Languages
|
||||
navbar.settings=Opcions
|
||||
navbar.allTools=Tools
|
||||
navbar.multiTool=Multi Tools
|
||||
navbar.sections.organize=Organize
|
||||
navbar.sections.convertTo=Convert to PDF
|
||||
navbar.sections.convertFrom=Convert from PDF
|
||||
navbar.sections.security=Sign & Security
|
||||
navbar.sections.advance=Advanced
|
||||
navbar.sections.edit=View & Edit
|
||||
|
||||
#############
|
||||
# SETTINGS #
|
||||
@@ -162,7 +173,7 @@ adminUserSettings.header=Usuari Admin Opcions Control
|
||||
adminUserSettings.admin=Admin
|
||||
adminUserSettings.user=Usuari
|
||||
adminUserSettings.addUser=Afegir Usuari
|
||||
adminUserSettings.usernameInfo=Username must only contain letters and numbers, no spaces or special characters.
|
||||
adminUserSettings.usernameInfo=Username can only contain letters, numbers and the following special characters @._+- or must be a valid email address.
|
||||
adminUserSettings.roles=Rols
|
||||
adminUserSettings.role=Rol
|
||||
adminUserSettings.actions=Accions
|
||||
@@ -173,6 +184,8 @@ adminUserSettings.demoUser=Demo User (No custom settings)
|
||||
adminUserSettings.internalApiUser=Internal API User
|
||||
adminUserSettings.forceChange=Force user to change password on login
|
||||
adminUserSettings.submit=Desar Usuari
|
||||
adminUserSettings.changeUserRole=Canvia el rol de l'usuari
|
||||
adminUserSettings.authenticated=Authenticated
|
||||
|
||||
#############
|
||||
# HOME-PAGE #
|
||||
@@ -437,6 +450,8 @@ login.rememberme=Recordar
|
||||
login.invalid=Nom usuari / password no vàlid
|
||||
login.locked=Compte bloquejat
|
||||
login.signinTitle=Autenticat
|
||||
login.ssoSignIn=Inicia sessió mitjançant l'inici de sessió ún
|
||||
login.oauth2AutoCreateDisabled=L'usuari de creació automàtica OAUTH2 està desactivat
|
||||
|
||||
|
||||
#auto-redact
|
||||
@@ -689,6 +704,7 @@ repair.submit=Reparar
|
||||
#flatten
|
||||
flatten.title=Aplanar
|
||||
flatten.header=Aplana els PDF
|
||||
flatten.flattenOnlyForms=Flatten only forms
|
||||
flatten.submit=Aplanar
|
||||
|
||||
|
||||
@@ -736,6 +752,7 @@ extractImages.submit=Extreu
|
||||
fileToPDF.title=Arxiu a PDF
|
||||
fileToPDF.header=Converteix arxiu a PDF
|
||||
fileToPDF.credit=Utilitza LibreOffice i Unoconv per a la conversió.
|
||||
fileToPDF.supportedFileTypesInfo=Supported File types
|
||||
fileToPDF.supportedFileTypes=Els tipus de fitxers admesos haurien d'incloure el següent, però per obtenir una llista completa actualitzada dels formats compatibles, consulteu la documentació de LibreOffice
|
||||
fileToPDF.submit=Converteix a PDF
|
||||
|
||||
@@ -788,7 +805,7 @@ pdfOrganiser.placeholder=(e.g. 1,3,2 or 4-8,2,10-12 or 2n-1)
|
||||
#multiTool
|
||||
multiTool.title=PDF Multi Tool
|
||||
multiTool.header=PDF Multi Tool
|
||||
multiTool.uploadPrompts=Please Upload PDF
|
||||
multiTool.uploadPrompts=File Name
|
||||
|
||||
#view pdf
|
||||
viewPdf.title=View PDF
|
||||
@@ -1043,7 +1060,7 @@ licenses.version=Version
|
||||
licenses.license=License
|
||||
|
||||
|
||||
# error
|
||||
#error
|
||||
error.sorry=Sorry for the issue!
|
||||
error.needHelp=Need help / Found an issue?
|
||||
error.contactTip=If you're still having trouble, don't hesitate to reach out to us for help. You can submit a ticket on our GitHub page or contact us through Discord:
|
||||
|
||||
@@ -46,7 +46,7 @@ green=Grün
|
||||
blue=Blau
|
||||
custom=benutzerdefiniert...
|
||||
WorkInProgess=In Arbeit, funktioniert möglicherweise nicht oder ist fehlerhaft. Bitte melden Sie alle Probleme!
|
||||
poweredBy=Powered by
|
||||
poweredBy=Unterstützt von
|
||||
yes=Ja
|
||||
no=Nein
|
||||
changedCredsMessage=Anmeldedaten geändert!
|
||||
@@ -54,9 +54,13 @@ notAuthenticatedMessage=Benutzer nicht authentifiziert.
|
||||
userNotFoundMessage=Benutzer nicht gefunden.
|
||||
incorrectPasswordMessage=Das Passwort ist falsch.
|
||||
usernameExistsMessage=Neuer Benutzername existiert bereits.
|
||||
invalidUsernameMessage=Ungültiger Benutzername. Der Benutzername darf nur Buchstaben und Zahlen enthalten.
|
||||
invalidUsernameMessage=Ungültiger Benutzername. Der Benutzername darf nur Buchstaben, Zahlen und die folgenden Sonderzeichen @._+- enthalten oder muss eine gültige E-Mail-Adresse sein.
|
||||
deleteCurrentUserMessage=Der aktuell angemeldete Benutzer kann nicht gelöscht werden.
|
||||
deleteUsernameExistsMessage=Der Benutzername existiert nicht und kann nicht gelöscht werden.
|
||||
downgradeCurrentUserMessage=Die Rolle des aktuellen Benutzers kann nicht herabgestuft werden
|
||||
downgradeCurrentUserLongMessage=Die Rolle des aktuellen Benutzers kann nicht herabgestuft werden. Daher wird der aktuelle Benutzer nicht angezeigt.
|
||||
userAlreadyExistsOAuthMessage=The user already exists as an OAuth2 user.
|
||||
userAlreadyExistsWebMessage=The user already exists as an web user.
|
||||
error=Fehler
|
||||
oops=Hoppla!
|
||||
help=Hilfe
|
||||
@@ -67,6 +71,7 @@ visitGithub=GitHub-Repository besuchen
|
||||
donate=Spenden
|
||||
color=Farbe
|
||||
sponsor=Sponsor
|
||||
info=Info
|
||||
|
||||
|
||||
|
||||
@@ -100,12 +105,18 @@ pipelineOptions.validateButton=Validieren
|
||||
#############
|
||||
# NAVBAR #
|
||||
#############
|
||||
navbar.convert=Konvertieren
|
||||
navbar.security=Sicherheit
|
||||
navbar.other=Anderes
|
||||
navbar.favorite=Favorites
|
||||
navbar.darkmode=Dunkler Modus
|
||||
navbar.pageOps=Seitenoperationen
|
||||
navbar.language=Languages
|
||||
navbar.settings=Einstellungen
|
||||
navbar.allTools=Tools
|
||||
navbar.multiTool=Multi Tools
|
||||
navbar.sections.organize=Organize
|
||||
navbar.sections.convertTo=Convert to PDF
|
||||
navbar.sections.convertFrom=Convert from PDF
|
||||
navbar.sections.security=Sign & Security
|
||||
navbar.sections.advance=Advanced
|
||||
navbar.sections.edit=View & Edit
|
||||
|
||||
#############
|
||||
# SETTINGS #
|
||||
@@ -121,9 +132,9 @@ settings.downloadOption.3=Datei herunterladen
|
||||
settings.zipThreshold=Dateien komprimieren, wenn die Anzahl der heruntergeladenen Dateien überschritten wird
|
||||
settings.signOut=Abmelden
|
||||
settings.accountSettings=Kontoeinstellungen
|
||||
settings.bored.help=Enables easter egg game
|
||||
settings.cacheInputs.name=Save form inputs
|
||||
settings.cacheInputs.help=Enable to store previously used inputs for future runs
|
||||
settings.bored.help=Aktiviert das Easter-Egg-Spiel
|
||||
settings.cacheInputs.name=Formulareingaben speichern
|
||||
settings.cacheInputs.help=Aktivieren, um zuvor verwendete Eingaben für zukünftige Durchläufe zu speichern
|
||||
|
||||
changeCreds.title=Anmeldeinformationen ändern
|
||||
changeCreds.header=Aktualisieren Sie Ihre Kontodaten
|
||||
@@ -162,7 +173,7 @@ adminUserSettings.header=Administrator-Benutzerkontrolle
|
||||
adminUserSettings.admin=Administrator
|
||||
adminUserSettings.user=Benutzer
|
||||
adminUserSettings.addUser=Neuen Benutzer hinzufügen
|
||||
adminUserSettings.usernameInfo=Der Benutzername darf nur Buchstaben und Zahlen enthalten, keine Leerzeichen oder Sonderzeichen.
|
||||
adminUserSettings.usernameInfo=Der Benutzername darf nur Buchstaben, Zahlen und die folgenden Sonderzeichen @._+- enthalten oder muss eine gültige E-Mail-Adresse sein.
|
||||
adminUserSettings.roles=Rollen
|
||||
adminUserSettings.role=Rolle
|
||||
adminUserSettings.actions=Aktion
|
||||
@@ -173,6 +184,8 @@ adminUserSettings.demoUser=Demo-Benutzer (Keine benutzerdefinierten Einstellunge
|
||||
adminUserSettings.internalApiUser=Interner API-Benutzer
|
||||
adminUserSettings.forceChange=Benutzer dazu zwingen, Benutzernamen/Passwort bei der Anmeldung zu ändern
|
||||
adminUserSettings.submit=Benutzer speichern
|
||||
adminUserSettings.changeUserRole=Benutzerrolle ändern
|
||||
adminUserSettings.authenticated=Authenticated
|
||||
|
||||
#############
|
||||
# HOME-PAGE #
|
||||
@@ -437,6 +450,8 @@ login.rememberme=Angemeldet bleiben
|
||||
login.invalid=Benutzername oder Passwort ungültig.
|
||||
login.locked=Ihr Konto wurde gesperrt.
|
||||
login.signinTitle=Bitte melden Sie sich an.
|
||||
login.ssoSignIn=Anmeldung per Single Sign-On
|
||||
login.oauth2AutoCreateDisabled=OAUTH2 Benutzer automatisch erstellen deaktiviert
|
||||
|
||||
|
||||
#auto-redact
|
||||
@@ -689,6 +704,7 @@ repair.submit=Reparieren
|
||||
#flatten
|
||||
flatten.title=Abflachen
|
||||
flatten.header=PDFs reduzieren
|
||||
flatten.flattenOnlyForms=Flatten only forms
|
||||
flatten.submit=Abflachen
|
||||
|
||||
|
||||
@@ -736,6 +752,7 @@ extractImages.submit=Extrahieren
|
||||
fileToPDF.title=Datei in PDF
|
||||
fileToPDF.header=Beliebige Dateien in PDF konvertieren
|
||||
fileToPDF.credit=Dieser Dienst verwendet LibreOffice und Unoconv für die Dateikonvertierung.
|
||||
fileToPDF.supportedFileTypesInfo=Supported File types
|
||||
fileToPDF.supportedFileTypes=Unterstützte Dateitypen sollten die folgenden enthalten, eine vollständige aktualisierte Liste der unterstützten Formate finden Sie jedoch in der LibreOffice-Dokumentation
|
||||
fileToPDF.submit=In PDF konvertieren
|
||||
|
||||
@@ -788,7 +805,7 @@ pdfOrganiser.placeholder=(z.B. 1,3,2 oder 4-8,2,10-12 oder 2n-1)
|
||||
#multiTool
|
||||
multiTool.title=PDF-Multitool
|
||||
multiTool.header=PDF-Multitool
|
||||
multiTool.uploadPrompts=Bitte PDF hochladen
|
||||
multiTool.uploadPrompts=File Name
|
||||
|
||||
#view pdf
|
||||
viewPdf.title=PDF anzeigen
|
||||
@@ -1043,7 +1060,7 @@ licenses.version=Version
|
||||
licenses.license=Lizenz
|
||||
|
||||
|
||||
# error
|
||||
#error
|
||||
error.sorry=Entschuldigung für das Problem!
|
||||
error.needHelp=Brauchst du Hilfe / Ein Problem gefunden?
|
||||
error.contactTip=Wenn du weiterhin Probleme hast, zögere nicht, uns um Hilfe zu bitten. Du kannst ein Ticket auf unserer GitHub-Seite einreichen oder uns über Discord kontaktieren:
|
||||
|
||||
@@ -54,9 +54,13 @@ notAuthenticatedMessage=Ο χρήστης δεν έχει αυθεντικοπο
|
||||
userNotFoundMessage=Ο χρήστης δεν βρέθηκε.
|
||||
incorrectPasswordMessage=Ο τρέχων κωδικός πρόσβασης είναι λανθασμένος.
|
||||
usernameExistsMessage=Το νέο όνομα χρήστη υπάρχει ήδη.
|
||||
invalidUsernameMessage=Μη έγκυρο όνομα χρήστη, το όνομα χρήστη πρέπει να περιέχει μόνο αλφαβητικούς χαρακτήρες και αριθμούς.
|
||||
invalidUsernameMessage=Μη έγκυρο όνομα χρήστη, όνομα χρήστη μπορεί να περιέχει μόνο γράμματα, αριθμούς και τους ακόλουθους ειδικούς χαρακτήρες @._+- ή πρέπει να είναι έγκυρη διεύθυνση email.
|
||||
deleteCurrentUserMessage=Δεν είναι δυνατή η διαγραφή του τρέχοντος συνδεδεμένου χρήστη.
|
||||
deleteUsernameExistsMessage=Το όνομα χρήστη δεν υπάρχει και δεν μπορεί να διαγραφεί.
|
||||
downgradeCurrentUserMessage=Δεν είναι δυνατή η υποβάθμιση του ρόλου του τρέχοντος χρήστη
|
||||
downgradeCurrentUserLongMessage=Δεν είναι δυνατή η υποβάθμιση του ρόλου του τρέχοντος χρήστη. Ως εκ τούτου, ο τρέχων χρήστης δεν θα εμφανίζεται.
|
||||
userAlreadyExistsOAuthMessage=The user already exists as an OAuth2 user.
|
||||
userAlreadyExistsWebMessage=The user already exists as an web user.
|
||||
error=Σφάλμα
|
||||
oops=Ωχ!
|
||||
help=Βοήθεια
|
||||
@@ -67,6 +71,7 @@ visitGithub=Επισκεφθείτε το Αποθετήριο του Github
|
||||
donate=Δωρισε
|
||||
color=Χρώμα
|
||||
sponsor=Yποστηρικτής
|
||||
info=Info
|
||||
|
||||
|
||||
|
||||
@@ -100,12 +105,18 @@ pipelineOptions.validateButton=Επικυρώνω
|
||||
#############
|
||||
# NAVBAR #
|
||||
#############
|
||||
navbar.convert=Μετατροπή
|
||||
navbar.security=Ασφάλεια
|
||||
navbar.other=Διάφορα
|
||||
navbar.favorite=Favorites
|
||||
navbar.darkmode=Μαύρο Θέμα
|
||||
navbar.pageOps=Λειτουργίες σελίδας
|
||||
navbar.language=Languages
|
||||
navbar.settings=Ρυθμίσεις
|
||||
navbar.allTools=Tools
|
||||
navbar.multiTool=Multi Tools
|
||||
navbar.sections.organize=Organize
|
||||
navbar.sections.convertTo=Convert to PDF
|
||||
navbar.sections.convertFrom=Convert from PDF
|
||||
navbar.sections.security=Sign & Security
|
||||
navbar.sections.advance=Advanced
|
||||
navbar.sections.edit=View & Edit
|
||||
|
||||
#############
|
||||
# SETTINGS #
|
||||
@@ -162,7 +173,7 @@ adminUserSettings.header=Ρυθμίσεις ελέγχου Διαχειριστ
|
||||
adminUserSettings.admin=Διαχειριστής
|
||||
adminUserSettings.user=Χρήστης
|
||||
adminUserSettings.addUser=Προσθήκη νέου Χρήστη
|
||||
adminUserSettings.usernameInfo=Username must only contain letters and numbers, no spaces or special characters.
|
||||
adminUserSettings.usernameInfo=Username can only contain letters, numbers and the following special characters @._+- or must be a valid email address.
|
||||
adminUserSettings.roles=Ρόλοι
|
||||
adminUserSettings.role=Ρόλος
|
||||
adminUserSettings.actions=Ενέργειες
|
||||
@@ -173,6 +184,8 @@ adminUserSettings.demoUser=Demo χρήστης (Χωρίς προσαρμοσμ
|
||||
adminUserSettings.internalApiUser=Εσωτερικός API χρήστης
|
||||
adminUserSettings.forceChange=Αναγκάστε τον χρήστη να αλλάξει το όνομα χρήστη/κωδικό πρόσβασης κατά τη σύνδεση
|
||||
adminUserSettings.submit=Αποθήκευση Χρήστη
|
||||
adminUserSettings.changeUserRole=Αλλαγή ρόλου χρήστη
|
||||
adminUserSettings.authenticated=Authenticated
|
||||
|
||||
#############
|
||||
# HOME-PAGE #
|
||||
@@ -437,6 +450,8 @@ login.rememberme=Να Με Θυμάσαι
|
||||
login.invalid=Λάθος όνομα χρήστη ή κωδικού πρόσβασης.
|
||||
login.locked=Ο λογαριασμός σας έχει κλειδωθεί.
|
||||
login.signinTitle=Παρακαλώ, συνδεθείτε
|
||||
login.ssoSignIn=Σύνδεση μέσω μοναδικής σύνδεσης
|
||||
login.oauth2AutoCreateDisabled=Απενεργοποιήθηκε ο χρήστης αυτόματης δημιουργίας OAUTH2
|
||||
|
||||
|
||||
#auto-redact
|
||||
@@ -689,6 +704,7 @@ repair.submit=Επιδιόρθωση
|
||||
#flatten
|
||||
flatten.title=Flatten
|
||||
flatten.header=Flatten PDFs
|
||||
flatten.flattenOnlyForms=Flatten only forms
|
||||
flatten.submit=Flatten
|
||||
|
||||
|
||||
@@ -736,6 +752,7 @@ extractImages.submit=Εξαγωγή
|
||||
fileToPDF.title=Αρχείο σε PDF
|
||||
fileToPDF.header=Μετατροπή οποιουδήποτε αρχείου σε PDF
|
||||
fileToPDF.credit=Αυτή η υπηρεσία χρησιμοποιεί LibreOffice και Unoconv για την μετατροπή των αρχείων.
|
||||
fileToPDF.supportedFileTypesInfo=Supported File types
|
||||
fileToPDF.supportedFileTypes=Οι υποστηριζόμενοι τύποι αρχείων θα πρέπει να περιλαμβάνουν τα παρακάτω, ωστόσο, για μια πλήρη ενημερωμένη λίστα με τις υποστηριζόμενες μορφές, ανατρέξτε στην τεκμηρίωση του LibreOffice
|
||||
fileToPDF.submit=Μετατροπή σε PDF
|
||||
|
||||
@@ -788,7 +805,7 @@ pdfOrganiser.placeholder=(π.χ. 1,3,2 ή 4-8,2,10-12 ή 2n-1)
|
||||
#multiTool
|
||||
multiTool.title=PDF Πολυεργαλείο
|
||||
multiTool.header=PDF Πολυεργαλείο
|
||||
multiTool.uploadPrompts=Ανεβάστε το PDF
|
||||
multiTool.uploadPrompts=File Name
|
||||
|
||||
#view pdf
|
||||
viewPdf.title=Προβολή PDF
|
||||
@@ -1043,7 +1060,7 @@ licenses.version=Εκδοχή
|
||||
licenses.license=Άδεια
|
||||
|
||||
|
||||
# error
|
||||
#error
|
||||
error.sorry=Συγγνώμη για το ζήτημα!
|
||||
error.needHelp=Χρειάζεστε βοήθεια / Βρήκατε πρόβλημα;
|
||||
error.contactTip=Εάν εξακολουθείτε να αντιμετωπίζετε προβλήματα, μη διστάσετε να επικοινωνήσετε μαζί μας για βοήθεια. Μπορείτε να υποβάλετε ένα ticket στη σελίδα μας στο GitHub ή να επικοινωνήσετε μαζί μας μέσω του Discord:
|
||||
|
||||
@@ -54,9 +54,13 @@ notAuthenticatedMessage=User not authenticated.
|
||||
userNotFoundMessage=User not found.
|
||||
incorrectPasswordMessage=Current password is incorrect.
|
||||
usernameExistsMessage=New Username already exists.
|
||||
invalidUsernameMessage=Invalid username, Username must only contain alphabet characters and numbers.
|
||||
invalidUsernameMessage=Invalid username, username can only contain letters, numbers and the following special characters @._+- or must be a valid email address.
|
||||
deleteCurrentUserMessage=Cannot delete currently logged in user.
|
||||
deleteUsernameExistsMessage=The username does not exist and cannot be deleted.
|
||||
downgradeCurrentUserMessage=Cannot downgrade current user's role
|
||||
downgradeCurrentUserLongMessage=Cannot downgrade current user's role. Hence, current user will not be shown.
|
||||
userAlreadyExistsOAuthMessage=The user already exists as an OAuth2 user.
|
||||
userAlreadyExistsWebMessage=The user already exists as an web user.
|
||||
error=Error
|
||||
oops=Oops!
|
||||
help=Help
|
||||
@@ -67,6 +71,7 @@ visitGithub=Visit Github Repository
|
||||
donate=Donate
|
||||
color=Color
|
||||
sponsor=Sponsor
|
||||
info=Info
|
||||
|
||||
|
||||
|
||||
@@ -100,12 +105,18 @@ pipelineOptions.validateButton=Validate
|
||||
#############
|
||||
# NAVBAR #
|
||||
#############
|
||||
navbar.convert=Convert
|
||||
navbar.security=Security
|
||||
navbar.other=Miscellaneous
|
||||
navbar.favorite=Favorites
|
||||
navbar.darkmode=Dark Mode
|
||||
navbar.pageOps=Page Operations
|
||||
navbar.language=Languages
|
||||
navbar.settings=Settings
|
||||
navbar.allTools=Tools
|
||||
navbar.multiTool=Multi Tools
|
||||
navbar.sections.organize=Organize
|
||||
navbar.sections.convertTo=Convert to PDF
|
||||
navbar.sections.convertFrom=Convert from PDF
|
||||
navbar.sections.security=Sign & Security
|
||||
navbar.sections.advance=Advanced
|
||||
navbar.sections.edit=View & Edit
|
||||
|
||||
#############
|
||||
# SETTINGS #
|
||||
@@ -162,7 +173,7 @@ adminUserSettings.header=Admin User Control Settings
|
||||
adminUserSettings.admin=Admin
|
||||
adminUserSettings.user=User
|
||||
adminUserSettings.addUser=Add New User
|
||||
adminUserSettings.usernameInfo=Username must only contain letters and numbers, no spaces or special characters.
|
||||
adminUserSettings.usernameInfo=Username can only contain letters, numbers and the following special characters @._+- or must be a valid email address.
|
||||
adminUserSettings.roles=Roles
|
||||
adminUserSettings.role=Role
|
||||
adminUserSettings.actions=Actions
|
||||
@@ -173,6 +184,8 @@ adminUserSettings.demoUser=Demo User (No custom settings)
|
||||
adminUserSettings.internalApiUser=Internal API User
|
||||
adminUserSettings.forceChange=Force user to change password on login
|
||||
adminUserSettings.submit=Save User
|
||||
adminUserSettings.changeUserRole=Change User's Role
|
||||
adminUserSettings.authenticated=Authenticated
|
||||
|
||||
#############
|
||||
# HOME-PAGE #
|
||||
@@ -437,6 +450,8 @@ login.rememberme=Remember me
|
||||
login.invalid=Invalid username or password.
|
||||
login.locked=Your account has been locked.
|
||||
login.signinTitle=Please sign in
|
||||
login.ssoSignIn=Login via Single Sign-on
|
||||
login.oauth2AutoCreateDisabled=OAUTH2 Auto-Create User Disabled
|
||||
|
||||
|
||||
#auto-redact
|
||||
@@ -688,7 +703,8 @@ repair.submit=Repair
|
||||
|
||||
#flatten
|
||||
flatten.title=Flatten
|
||||
flatten.header=Flatten PDFs
|
||||
flatten.header=Flatten PDF
|
||||
flatten.flattenOnlyForms=Flatten only forms
|
||||
flatten.submit=Flatten
|
||||
|
||||
|
||||
@@ -736,6 +752,7 @@ extractImages.submit=Extract
|
||||
fileToPDF.title=File to PDF
|
||||
fileToPDF.header=Convert any file to PDF
|
||||
fileToPDF.credit=This service uses LibreOffice and Unoconv for file conversion.
|
||||
fileToPDF.supportedFileTypesInfo=Supported File types
|
||||
fileToPDF.supportedFileTypes=Supported file types should include the below however for a full updated list of supported formats, please refer to the LibreOffice documentation
|
||||
fileToPDF.submit=Convert to PDF
|
||||
|
||||
@@ -788,7 +805,7 @@ pdfOrganiser.placeholder=(e.g. 1,3,2 or 4-8,2,10-12 or 2n-1)
|
||||
#multiTool
|
||||
multiTool.title=PDF Multi Tool
|
||||
multiTool.header=PDF Multi Tool
|
||||
multiTool.uploadPrompts=Please Upload PDF
|
||||
multiTool.uploadPrompts=File Name
|
||||
|
||||
#view pdf
|
||||
viewPdf.title=View PDF
|
||||
@@ -1043,7 +1060,7 @@ licenses.version=Version
|
||||
licenses.license=License
|
||||
|
||||
|
||||
# error
|
||||
#error
|
||||
error.sorry=Sorry for the issue!
|
||||
error.needHelp=Need help / Found an issue?
|
||||
error.contactTip=If you're still having trouble, don't hesitate to reach out to us for help. You can submit a ticket on our GitHub page or contact us through Discord:
|
||||
|
||||
@@ -54,9 +54,13 @@ notAuthenticatedMessage=User not authenticated.
|
||||
userNotFoundMessage=User not found.
|
||||
incorrectPasswordMessage=Current password is incorrect.
|
||||
usernameExistsMessage=New Username already exists.
|
||||
invalidUsernameMessage=Invalid username, Username must only contain alphabet characters and numbers.
|
||||
invalidUsernameMessage=Invalid username, username can only contain letters, numbers and the following special characters @._+- or must be a valid email address.
|
||||
deleteCurrentUserMessage=Cannot delete currently logged in user.
|
||||
deleteUsernameExistsMessage=The username does not exist and cannot be deleted.
|
||||
downgradeCurrentUserMessage=Cannot downgrade current user's role
|
||||
downgradeCurrentUserLongMessage=Cannot downgrade current user's role. Hence, current user will not be shown.
|
||||
userAlreadyExistsOAuthMessage=The user already exists as an OAuth2 user.
|
||||
userAlreadyExistsWebMessage=The user already exists as an web user.
|
||||
error=Error
|
||||
oops=Oops!
|
||||
help=Help
|
||||
@@ -67,6 +71,7 @@ visitGithub=Visit Github Repository
|
||||
donate=Donate
|
||||
color=Color
|
||||
sponsor=Sponsor
|
||||
info=Info
|
||||
|
||||
|
||||
|
||||
@@ -100,12 +105,18 @@ pipelineOptions.validateButton=Validate
|
||||
#############
|
||||
# NAVBAR #
|
||||
#############
|
||||
navbar.convert=Convert
|
||||
navbar.security=Security
|
||||
navbar.other=Miscellaneous
|
||||
navbar.favorite=Favorites
|
||||
navbar.darkmode=Dark Mode
|
||||
navbar.pageOps=Page Operations
|
||||
navbar.language=Languages
|
||||
navbar.settings=Settings
|
||||
navbar.allTools=Tools
|
||||
navbar.multiTool=Multi Tools
|
||||
navbar.sections.organize=Organize
|
||||
navbar.sections.convertTo=Convert to PDF
|
||||
navbar.sections.convertFrom=Convert from PDF
|
||||
navbar.sections.security=Sign & Security
|
||||
navbar.sections.advance=Advanced
|
||||
navbar.sections.edit=View & Edit
|
||||
|
||||
#############
|
||||
# SETTINGS #
|
||||
@@ -162,7 +173,7 @@ adminUserSettings.header=Admin User Control Settings
|
||||
adminUserSettings.admin=Admin
|
||||
adminUserSettings.user=User
|
||||
adminUserSettings.addUser=Add New User
|
||||
adminUserSettings.usernameInfo=Username must only contain letters and numbers, no spaces or special characters.
|
||||
adminUserSettings.usernameInfo=Username can only contain letters, numbers and the following special characters @._+- or must be a valid email address.
|
||||
adminUserSettings.roles=Roles
|
||||
adminUserSettings.role=Role
|
||||
adminUserSettings.actions=Actions
|
||||
@@ -173,6 +184,8 @@ adminUserSettings.demoUser=Demo User (No custom settings)
|
||||
adminUserSettings.internalApiUser=Internal API User
|
||||
adminUserSettings.forceChange=Force user to change password on login
|
||||
adminUserSettings.submit=Save User
|
||||
adminUserSettings.changeUserRole=Change User's Role
|
||||
adminUserSettings.authenticated=Authenticated
|
||||
|
||||
#############
|
||||
# HOME-PAGE #
|
||||
@@ -327,7 +340,7 @@ home.scalePages.title=Adjust page size/scale
|
||||
home.scalePages.desc=Change the size/scale of a page and/or its contents.
|
||||
scalePages.tags=resize,modify,dimension,adapt
|
||||
|
||||
home.pipeline.title=Pipeline (Advanced)
|
||||
home.pipeline.title=Pipeline
|
||||
home.pipeline.desc=Run multiple actions on PDFs by defining pipeline scripts
|
||||
pipeline.tags=automate,sequence,scripted,batch-process
|
||||
|
||||
@@ -379,7 +392,7 @@ home.extractPage.desc=Extracts select pages from PDF
|
||||
extractPage.tags=extract
|
||||
|
||||
|
||||
home.PdfToSinglePage.title=PDF to Single Large Page
|
||||
home.PdfToSinglePage.title=Single Large Page
|
||||
home.PdfToSinglePage.desc=Merges all PDF pages into one large single page
|
||||
PdfToSinglePage.tags=single page
|
||||
|
||||
@@ -437,6 +450,8 @@ login.rememberme=Remember me
|
||||
login.invalid=Invalid username or password.
|
||||
login.locked=Your account has been locked.
|
||||
login.signinTitle=Please sign in
|
||||
login.ssoSignIn=Login via Single Sign-on
|
||||
login.oauth2AutoCreateDisabled=OAUTH2 Auto-Create User Disabled
|
||||
|
||||
|
||||
#auto-redact
|
||||
@@ -689,6 +704,7 @@ repair.submit=Repair
|
||||
#flatten
|
||||
flatten.title=Flatten
|
||||
flatten.header=Flatten PDFs
|
||||
flatten.flattenOnlyForms=Flatten only forms
|
||||
flatten.submit=Flatten
|
||||
|
||||
|
||||
@@ -736,6 +752,7 @@ extractImages.submit=Extract
|
||||
fileToPDF.title=File to PDF
|
||||
fileToPDF.header=Convert any file to PDF
|
||||
fileToPDF.credit=This service uses LibreOffice and Unoconv for file conversion.
|
||||
fileToPDF.supportedFileTypesInfo=Supported File types
|
||||
fileToPDF.supportedFileTypes=Supported file types should include the below however for a full updated list of supported formats, please refer to the LibreOffice documentation
|
||||
fileToPDF.submit=Convert to PDF
|
||||
|
||||
@@ -788,7 +805,7 @@ pdfOrganiser.placeholder=(e.g. 1,3,2 or 4-8,2,10-12 or 2n-1)
|
||||
#multiTool
|
||||
multiTool.title=PDF Multi Tool
|
||||
multiTool.header=PDF Multi Tool
|
||||
multiTool.uploadPrompts=Please Upload PDF
|
||||
multiTool.uploadPrompts=File Name
|
||||
|
||||
#view pdf
|
||||
viewPdf.title=View PDF
|
||||
@@ -1043,7 +1060,7 @@ licenses.version=Version
|
||||
licenses.license=License
|
||||
|
||||
|
||||
# error
|
||||
#error
|
||||
error.sorry=Sorry for the issue!
|
||||
error.needHelp=Need help / Found an issue?
|
||||
error.contactTip=If you're still having trouble, don't hesitate to reach out to us for help. You can submit a ticket on our GitHub page or contact us through Discord:
|
||||
|
||||
@@ -54,9 +54,13 @@ notAuthenticatedMessage=Usuario no autentificado.
|
||||
userNotFoundMessage=Usuario no encontrado.
|
||||
incorrectPasswordMessage=La contraseña actual no es correcta.
|
||||
usernameExistsMessage=El nuevo nombre de usuario está en uso.
|
||||
invalidUsernameMessage=Nombre de usuario no válido, El nombre de ususario debe contener únicamente números y caracteres alfabéticos.
|
||||
invalidUsernameMessage=Nombre de usuario no válido, el nombre de usuario solo puede contener letras, números y los siguientes caracteres especiales @._+- o debe ser una dirección de correo electrónico válida.
|
||||
deleteCurrentUserMessage=No puede eliminar el usuario que tiene la sesión actualmente en uso.
|
||||
deleteUsernameExistsMessage=El usuario no existe y no puede eliminarse.
|
||||
downgradeCurrentUserMessage=No se puede degradar el rol del usuario actual
|
||||
downgradeCurrentUserLongMessage=No se puede degradar el rol del usuario actual. Por lo tanto, el usuario actual no se mostrará.
|
||||
userAlreadyExistsOAuthMessage=The user already exists as an OAuth2 user.
|
||||
userAlreadyExistsWebMessage=The user already exists as an web user.
|
||||
error=Error
|
||||
oops=Ups!
|
||||
help=Help
|
||||
@@ -67,6 +71,7 @@ visitGithub=Visitar Repositorio de Github
|
||||
donate=Donar
|
||||
color=Color
|
||||
sponsor=Patrocinador
|
||||
info=Info
|
||||
|
||||
|
||||
|
||||
@@ -100,12 +105,18 @@ pipelineOptions.validateButton=Validar
|
||||
#############
|
||||
# NAVBAR #
|
||||
#############
|
||||
navbar.convert=Convertir
|
||||
navbar.security=Seguridad
|
||||
navbar.other=Otro
|
||||
navbar.favorite=Favorites
|
||||
navbar.darkmode=Modo oscuro
|
||||
navbar.pageOps=Operaciones de página
|
||||
navbar.language=Languages
|
||||
navbar.settings=Configuración
|
||||
navbar.allTools=Tools
|
||||
navbar.multiTool=Multi Tools
|
||||
navbar.sections.organize=Organize
|
||||
navbar.sections.convertTo=Convert to PDF
|
||||
navbar.sections.convertFrom=Convert from PDF
|
||||
navbar.sections.security=Sign & Security
|
||||
navbar.sections.advance=Advanced
|
||||
navbar.sections.edit=View & Edit
|
||||
|
||||
#############
|
||||
# SETTINGS #
|
||||
@@ -162,7 +173,7 @@ adminUserSettings.header=Configuración de control de usuario administrador
|
||||
adminUserSettings.admin=Administrador
|
||||
adminUserSettings.user=Usuario
|
||||
adminUserSettings.addUser=Añadir Nuevo Usuario
|
||||
adminUserSettings.usernameInfo=El nombrede usuario debe contener únicamente letras y números, no espacios ni caracteres especiales.
|
||||
adminUserSettings.usernameInfo=El nombre de usuario solo puede contener letras, números y los siguientes caracteres especiales @._+- o debe ser una dirección de correo electrónico válida.
|
||||
adminUserSettings.roles=Roles
|
||||
adminUserSettings.role=Rol
|
||||
adminUserSettings.actions=Acciones
|
||||
@@ -173,6 +184,8 @@ adminUserSettings.demoUser=Usuario Demo (Sin ajustes personalizados)
|
||||
adminUserSettings.internalApiUser=Usuario interno de API
|
||||
adminUserSettings.forceChange=Forzar usuario a cambiar usuario/contraseña en el acceso
|
||||
adminUserSettings.submit=Guardar Usuario
|
||||
adminUserSettings.changeUserRole=Cambiar rol de usuario
|
||||
adminUserSettings.authenticated=Authenticated
|
||||
|
||||
#############
|
||||
# HOME-PAGE #
|
||||
@@ -437,6 +450,8 @@ login.rememberme=Recordarme
|
||||
login.invalid=Nombre de usuario o contraseña erróneos.
|
||||
login.locked=Su cuenta se ha bloqueado.
|
||||
login.signinTitle=Por favor, inicie sesión
|
||||
login.ssoSignIn=Iniciar sesión a través del inicio de sesión único
|
||||
login.oauth2AutoCreateDisabled=Usuario DE creación automática de OAUTH2 DESACTIVADO
|
||||
|
||||
|
||||
#auto-redact
|
||||
@@ -689,6 +704,7 @@ repair.submit=Reparar
|
||||
#flatten
|
||||
flatten.title=Aplanar
|
||||
flatten.header=Acoplar archivos PDF
|
||||
flatten.flattenOnlyForms=Flatten only forms
|
||||
flatten.submit=Aplanar
|
||||
|
||||
|
||||
@@ -736,6 +752,7 @@ extractImages.submit=Extraer
|
||||
fileToPDF.title=Archivo a PDF
|
||||
fileToPDF.header=Convertir cualquier archivo a PDF
|
||||
fileToPDF.credit=Este servicio usa LibreOffice y Unoconv para la conversión de archivos
|
||||
fileToPDF.supportedFileTypesInfo=Supported File types
|
||||
fileToPDF.supportedFileTypes=Los tipos de archivo soportados deben incluir los indicados a continuación; sin embargo, para una completa y acutualizada lista de formatos soportados, por favor consulte la documentación de LibreOffice
|
||||
fileToPDF.submit=Convertir a PDF
|
||||
|
||||
@@ -788,7 +805,7 @@ pdfOrganiser.placeholder=(por ej., 1,3,2 o 4-8,2,10-12 o 2n-1)
|
||||
#multiTool
|
||||
multiTool.title=Multi-herramienta PDF
|
||||
multiTool.header=Multi-herramienta PDF
|
||||
multiTool.uploadPrompts=Por favor, cargue PDF
|
||||
multiTool.uploadPrompts=File Name
|
||||
|
||||
#view pdf
|
||||
viewPdf.title=Ver PDF
|
||||
@@ -1043,7 +1060,7 @@ licenses.version=Versión
|
||||
licenses.license=Licencia
|
||||
|
||||
|
||||
# error
|
||||
#error
|
||||
error.sorry=¡Perdón por el fallo!
|
||||
error.needHelp=Necesita ayuda / Encontró un fallo?
|
||||
error.contactTip=Si sigue experimentando errores, no dude en contactarnos para solicitar soporte. Puede enviarnos un ticket en la página de GitHub o contactarnos mediante Discord:
|
||||
|
||||
@@ -54,9 +54,13 @@ notAuthenticatedMessage=User not authenticated.
|
||||
userNotFoundMessage=User not found.
|
||||
incorrectPasswordMessage=Current password is incorrect.
|
||||
usernameExistsMessage=New Username already exists.
|
||||
invalidUsernameMessage=Invalid username, Username must only contain alphabet characters and numbers.
|
||||
invalidUsernameMessage=Invalid username, username can only contain letters, numbers and the following special characters @._+- or must be a valid email address.
|
||||
deleteCurrentUserMessage=Cannot delete currently logged in user.
|
||||
deleteUsernameExistsMessage=The username does not exist and cannot be deleted.
|
||||
downgradeCurrentUserMessage=Ezin da uneko erabiltzailearen rola jaitsi
|
||||
downgradeCurrentUserLongMessage=Ezin da uneko erabiltzailearen rola jaitsi. Beraz, oraingo erabiltzailea ez da erakutsiko.
|
||||
userAlreadyExistsOAuthMessage=The user already exists as an OAuth2 user.
|
||||
userAlreadyExistsWebMessage=The user already exists as an web user.
|
||||
error=Error
|
||||
oops=Oops!
|
||||
help=Help
|
||||
@@ -67,6 +71,7 @@ visitGithub=Visit Github Repository
|
||||
donate=Donate
|
||||
color=Color
|
||||
sponsor=Sponsor
|
||||
info=Info
|
||||
|
||||
|
||||
|
||||
@@ -100,12 +105,18 @@ pipelineOptions.validateButton=Validate
|
||||
#############
|
||||
# NAVBAR #
|
||||
#############
|
||||
navbar.convert=Bihurtu
|
||||
navbar.security=Segurtasuna
|
||||
navbar.other=Beste bat
|
||||
navbar.favorite=Favorites
|
||||
navbar.darkmode=Modu iluna
|
||||
navbar.pageOps=Orrialde-eragiketak
|
||||
navbar.language=Languages
|
||||
navbar.settings=Ezarpenak
|
||||
navbar.allTools=Tools
|
||||
navbar.multiTool=Multi Tools
|
||||
navbar.sections.organize=Organize
|
||||
navbar.sections.convertTo=Convert to PDF
|
||||
navbar.sections.convertFrom=Convert from PDF
|
||||
navbar.sections.security=Sign & Security
|
||||
navbar.sections.advance=Advanced
|
||||
navbar.sections.edit=View & Edit
|
||||
|
||||
#############
|
||||
# SETTINGS #
|
||||
@@ -162,7 +173,7 @@ adminUserSettings.header=Admin Erabiltzailearen Ezarpenen Kontrolak
|
||||
adminUserSettings.admin=Admin
|
||||
adminUserSettings.user=Erabiltzaile
|
||||
adminUserSettings.addUser=Erabiltzaile berria
|
||||
adminUserSettings.usernameInfo=Username must only contain letters and numbers, no spaces or special characters.
|
||||
adminUserSettings.usernameInfo=Username can only contain letters, numbers and the following special characters @._+- or must be a valid email address.
|
||||
adminUserSettings.roles=Rolak
|
||||
adminUserSettings.role=Rol
|
||||
adminUserSettings.actions=Ekintzak
|
||||
@@ -173,6 +184,8 @@ adminUserSettings.demoUser=Demo User (No custom settings)
|
||||
adminUserSettings.internalApiUser=Internal API User
|
||||
adminUserSettings.forceChange=Force user to change password on login
|
||||
adminUserSettings.submit=Gorde Erabiltzailea
|
||||
adminUserSettings.changeUserRole=Erabiltzailearen rola aldatu
|
||||
adminUserSettings.authenticated=Authenticated
|
||||
|
||||
#############
|
||||
# HOME-PAGE #
|
||||
@@ -437,6 +450,8 @@ login.rememberme=Oroitu nazazu
|
||||
login.invalid=Okerreko erabiltzaile izena edo pasahitza.
|
||||
login.locked=Zure kontua blokeatu egin da.
|
||||
login.signinTitle=Mesedez, hasi saioa
|
||||
login.ssoSignIn=Hasi saioa Saioa hasteko modu bakarraren bidez
|
||||
login.oauth2AutoCreateDisabled=OAUTH2 Sortu automatikoki erabiltzailea desgaituta dago
|
||||
|
||||
|
||||
#auto-redact
|
||||
@@ -689,6 +704,7 @@ repair.submit=Konpondu
|
||||
#flatten
|
||||
flatten.title=Lautu
|
||||
flatten.header=Akoplatu PDF fitxategiak
|
||||
flatten.flattenOnlyForms=Flatten only forms
|
||||
flatten.submit=Lautu
|
||||
|
||||
|
||||
@@ -736,6 +752,7 @@ extractImages.submit=Atera
|
||||
fileToPDF.title=Fitxategia PDF bihurtu
|
||||
fileToPDF.header=Edozein fitxategi PDF bihurtu
|
||||
fileToPDF.credit=Zerbitzu honek LibreOffice eta Unoconv erabiltzen ditu fitxategiak bihurtzeko
|
||||
fileToPDF.supportedFileTypesInfo=Supported File types
|
||||
fileToPDF.supportedFileTypes=Jasandako fitxategi-motek behekoak barne hartu behar dituzte; hala ere, jasandako formatuen zerrenda osoa eta eguneratua izateko, kontsultatu, mesedez, LibreOffice-en dokumentazioa
|
||||
fileToPDF.submit=PDF bihurtu
|
||||
|
||||
@@ -788,7 +805,7 @@ pdfOrganiser.placeholder=(e.g. 1,3,2 or 4-8,2,10-12 or 2n-1)
|
||||
#multiTool
|
||||
multiTool.title=PDF erabilera anitzeko tresna
|
||||
multiTool.header=PDF erabilera anitzeko tresna
|
||||
multiTool.uploadPrompts=Please Upload PDF
|
||||
multiTool.uploadPrompts=File Name
|
||||
|
||||
#view pdf
|
||||
viewPdf.title=View PDF
|
||||
@@ -1043,7 +1060,7 @@ licenses.version=Version
|
||||
licenses.license=License
|
||||
|
||||
|
||||
# error
|
||||
#error
|
||||
error.sorry=Sorry for the issue!
|
||||
error.needHelp=Need help / Found an issue?
|
||||
error.contactTip=If you're still having trouble, don't hesitate to reach out to us for help. You can submit a ticket on our GitHub page or contact us through Discord:
|
||||
|
||||
@@ -54,9 +54,13 @@ notAuthenticatedMessage=Utilisateur non authentifié.
|
||||
userNotFoundMessage=Utilisateur non trouvé.
|
||||
incorrectPasswordMessage=Le mot de passe actuel est incorrect.
|
||||
usernameExistsMessage=Le nouveau nom d’utilisateur existe déjà.
|
||||
invalidUsernameMessage=Nom d’utilisateur invalide, le nom d’utilisateur ne peut contenir que des chiffres et des lettres.
|
||||
invalidUsernameMessage=Nom d’utilisateur invalide, le nom d’utilisateur ne peut contenir que des lettres, des chiffres et les caractères spéciaux suivants @._+- ou doit être une adresse e-mail valide.
|
||||
deleteCurrentUserMessage=Impossible de supprimer l’utilisateur actuellement connecté.
|
||||
deleteUsernameExistsMessage=Le nom d’utilisateur n’existe pas et ne peut pas être supprimé.
|
||||
downgradeCurrentUserMessage=Impossible de rétrograder le rôle de l'utilisateur actuel
|
||||
downgradeCurrentUserLongMessage=Impossible de rétrograder le rôle de l'utilisateur actuel. Par conséquent, l'utilisateur actuel ne sera pas affiché.
|
||||
userAlreadyExistsOAuthMessage=The user already exists as an OAuth2 user.
|
||||
userAlreadyExistsWebMessage=The user already exists as an web user.
|
||||
error=Erreur
|
||||
oops=Oups !
|
||||
help=Aide
|
||||
@@ -67,6 +71,7 @@ visitGithub=Visiter le dépôt Github
|
||||
donate=Faire un don
|
||||
color=Couleur
|
||||
sponsor=Sponsor
|
||||
info=Info
|
||||
|
||||
|
||||
|
||||
@@ -100,12 +105,18 @@ pipelineOptions.validateButton=Valider
|
||||
#############
|
||||
# NAVBAR #
|
||||
#############
|
||||
navbar.convert=Convertir
|
||||
navbar.security=Sécurité
|
||||
navbar.other=Autre
|
||||
navbar.favorite=Favorites
|
||||
navbar.darkmode=Mode sombre
|
||||
navbar.pageOps=Opérations sur les pages
|
||||
navbar.language=Languages
|
||||
navbar.settings=Paramètres
|
||||
navbar.allTools=Tools
|
||||
navbar.multiTool=Multi Tools
|
||||
navbar.sections.organize=Organize
|
||||
navbar.sections.convertTo=Convert to PDF
|
||||
navbar.sections.convertFrom=Convert from PDF
|
||||
navbar.sections.security=Sign & Security
|
||||
navbar.sections.advance=Advanced
|
||||
navbar.sections.edit=View & Edit
|
||||
|
||||
#############
|
||||
# SETTINGS #
|
||||
@@ -162,7 +173,7 @@ adminUserSettings.header=Administration des paramètres des utilisateurs
|
||||
adminUserSettings.admin=Administateur
|
||||
adminUserSettings.user=Utilisateur
|
||||
adminUserSettings.addUser=Ajouter un utilisateur
|
||||
adminUserSettings.usernameInfo=Le nom d’utilisateur ne doit contenir que des lettres et des chiffres, sans espaces ni caractères spéciaux.
|
||||
adminUserSettings.usernameInfo=Le nom d'utilisateur ne peut contenir que des lettres, des chiffres et les caractères spéciaux suivants @._+- ou doit être une adresse e-mail valide.
|
||||
adminUserSettings.roles=Rôles
|
||||
adminUserSettings.role=Rôle
|
||||
adminUserSettings.actions=Actions
|
||||
@@ -173,6 +184,8 @@ adminUserSettings.demoUser=Demo User (Paramètres par défaut)
|
||||
adminUserSettings.internalApiUser=Internal API User
|
||||
adminUserSettings.forceChange=Forcer l’utilisateur à changer son nom d’utilisateur/mot de passe lors de la connexion
|
||||
adminUserSettings.submit=Ajouter
|
||||
adminUserSettings.changeUserRole=Changer le rôle de l'utilisateur
|
||||
adminUserSettings.authenticated=Authenticated
|
||||
|
||||
#############
|
||||
# HOME-PAGE #
|
||||
@@ -437,6 +450,8 @@ login.rememberme=Se souvenir de moi
|
||||
login.invalid=Nom d’utilisateur ou mot de passe invalide.
|
||||
login.locked=Votre compte a été verrouillé.
|
||||
login.signinTitle=Veuillez vous connecter
|
||||
login.ssoSignIn=Se connecter via l'authentification unique
|
||||
login.oauth2AutoCreateDisabled=OAUTH2 Création automatique d'utilisateur désactivée
|
||||
|
||||
|
||||
#auto-redact
|
||||
@@ -689,6 +704,7 @@ repair.submit=Réparer
|
||||
#flatten
|
||||
flatten.title=Rendre inerte
|
||||
flatten.header=Rendre inerte
|
||||
flatten.flattenOnlyForms=Flatten only forms
|
||||
flatten.submit=Rendre inerte
|
||||
|
||||
|
||||
@@ -736,6 +752,7 @@ extractImages.submit=Extraire
|
||||
fileToPDF.title=Fichier en PDF
|
||||
fileToPDF.header=Convertir un fichier en PDF
|
||||
fileToPDF.credit=Ce service utilise LibreOffice et Unoconv pour la conversion de fichiers.
|
||||
fileToPDF.supportedFileTypesInfo=Supported File types
|
||||
fileToPDF.supportedFileTypes=Les types de fichiers pris en charge doivent inclure les éléments ci-dessous, mais pour une liste complète et mise à jour des formats pris en charge, veuillez vous reporter à la documentation de LibreOffice.
|
||||
fileToPDF.submit=Convertir
|
||||
|
||||
@@ -788,7 +805,7 @@ pdfOrganiser.placeholder=(e.g. 1,3,2 or 4-8,2,10-12 or 2n-1)
|
||||
#multiTool
|
||||
multiTool.title=Outil multifonction PDF
|
||||
multiTool.header=Outil multifonction PDF
|
||||
multiTool.uploadPrompts=Please Upload PDF
|
||||
multiTool.uploadPrompts=File Name
|
||||
|
||||
#view pdf
|
||||
viewPdf.title=Visualiser un PDF
|
||||
@@ -1043,7 +1060,7 @@ licenses.version=Version
|
||||
licenses.license=Licence
|
||||
|
||||
|
||||
# error
|
||||
#error
|
||||
error.sorry=Désolé pour ce problème !
|
||||
error.needHelp=Besoin d’aide / Vous avez trouvé un problème ?
|
||||
error.contactTip=Si vous avez encore des problèmes, n’hésitez pas à nous contacter pour obtenir de l’aide. Vous pouvez soumettre un ticket sur notre page GitHub ou nous contacter via Discord :
|
||||
|
||||
@@ -54,9 +54,13 @@ notAuthenticatedMessage=उपयोगकर्ता प्रमाणित
|
||||
userNotFoundMessage=उपयोगकर्ता नहीं मिला।
|
||||
incorrectPasswordMessage=वर्तमान पासवर्ड गलत है।
|
||||
usernameExistsMessage=नया उपयोगकर्ता नाम पहले से मौजूद है।
|
||||
invalidUsernameMessage=Invalid username, Username must only contain alphabet characters and numbers.
|
||||
invalidUsernameMessage=Invalid username, username can only contain letters, numbers and the following special characters @._+- or must be a valid email address.
|
||||
deleteCurrentUserMessage=Cannot delete currently logged in user.
|
||||
deleteUsernameExistsMessage=The username does not exist and cannot be deleted.
|
||||
downgradeCurrentUserMessage=मौजूदा यूज़र की भूमिका को डाउनग्रेड नहीं किया जा सकता
|
||||
downgradeCurrentUserLongMessage=मौजूदा यूज़र की भूमिका को डाउनग्रेड नहीं किया जा सकता। इसलिए, वर्तमान उपयोगकर्ता को नहीं दिखाया जाएगा।
|
||||
userAlreadyExistsOAuthMessage=The user already exists as an OAuth2 user.
|
||||
userAlreadyExistsWebMessage=The user already exists as an web user.
|
||||
error=Error
|
||||
oops=Oops!
|
||||
help=Help
|
||||
@@ -67,6 +71,7 @@ visitGithub=Visit Github Repository
|
||||
donate=Donate
|
||||
color=Color
|
||||
sponsor=Sponsor
|
||||
info=Info
|
||||
|
||||
|
||||
|
||||
@@ -100,12 +105,18 @@ pipelineOptions.validateButton=Validate
|
||||
#############
|
||||
# NAVBAR #
|
||||
#############
|
||||
navbar.convert=कनवर्ट
|
||||
navbar.security=सुरक्षा
|
||||
navbar.other=विविध
|
||||
navbar.favorite=Favorites
|
||||
navbar.darkmode=डार्क मोड
|
||||
navbar.pageOps=पेज कार्य
|
||||
navbar.language=Languages
|
||||
navbar.settings=सेटिंग्स
|
||||
navbar.allTools=Tools
|
||||
navbar.multiTool=Multi Tools
|
||||
navbar.sections.organize=Organize
|
||||
navbar.sections.convertTo=Convert to PDF
|
||||
navbar.sections.convertFrom=Convert from PDF
|
||||
navbar.sections.security=Sign & Security
|
||||
navbar.sections.advance=Advanced
|
||||
navbar.sections.edit=View & Edit
|
||||
|
||||
#############
|
||||
# SETTINGS #
|
||||
@@ -162,7 +173,7 @@ adminUserSettings.header=व्यवस्थापक उपयोगकर्
|
||||
adminUserSettings.admin=व्यवस्थापक
|
||||
adminUserSettings.user=उपयोगकर्ता
|
||||
adminUserSettings.addUser=नया उपयोगकर्ता जोड़ें
|
||||
adminUserSettings.usernameInfo=Username must only contain letters and numbers, no spaces or special characters.
|
||||
adminUserSettings.usernameInfo=Username can only contain letters, numbers and the following special characters @._+- or must be a valid email address.
|
||||
adminUserSettings.roles=रोल्स
|
||||
adminUserSettings.role=रोल
|
||||
adminUserSettings.actions=क्रियाएँ
|
||||
@@ -173,6 +184,8 @@ adminUserSettings.demoUser=Demo User (No custom settings)
|
||||
adminUserSettings.internalApiUser=Internal API User
|
||||
adminUserSettings.forceChange=उपयोगकर्ता को लॉगिन पर उपयोगकर्ता नाम/पासवर्ड बदलने के लिए मजबूर करें
|
||||
adminUserSettings.submit=उपयोगकर्ता को सहेजें
|
||||
adminUserSettings.changeUserRole=यूज़र की भूमिका बदलें
|
||||
adminUserSettings.authenticated=Authenticated
|
||||
|
||||
#############
|
||||
# HOME-PAGE #
|
||||
@@ -437,6 +450,8 @@ login.rememberme=मुझे याद रखें
|
||||
login.invalid=अमान्य उपयोगकर्ता नाम या पासवर्ड।
|
||||
login.locked=आपका खाता लॉक कर दिया गया है।
|
||||
login.signinTitle=कृपया साइन इन करें
|
||||
login.ssoSignIn=सिंगल साइन - ऑन के ज़रिए लॉग इन करें
|
||||
login.oauth2AutoCreateDisabled=OAUTH2 ऑटो - क्रिएट यूज़र अक्षम किया गया
|
||||
|
||||
|
||||
#auto-redact
|
||||
@@ -689,6 +704,7 @@ repair.submit=मरम्मत
|
||||
#flatten
|
||||
flatten.title=समतल करें
|
||||
flatten.header=पीडीएफ़ समतल करें
|
||||
flatten.flattenOnlyForms=Flatten only forms
|
||||
flatten.submit=समतल करें
|
||||
|
||||
|
||||
@@ -736,6 +752,7 @@ extractImages.submit=निकालें
|
||||
fileToPDF.title=फ़ाइल से पीडीएफ़
|
||||
fileToPDF.header=किसी भी फ़ाइल को पीडीएफ़ में बदलें
|
||||
fileToPDF.credit=यह सेवा फ़ाइल परिवर्तन के लिए LibreOffice और Unoconv का उपयोग करती है।
|
||||
fileToPDF.supportedFileTypesInfo=Supported File types
|
||||
fileToPDF.supportedFileTypes=समर्थित फ़ाइल प्रकार नीचे दिए गए होने चाहिए हालांकि समर्थित प्रारूपों की पूरी अद्यतन सूची के लिए कृपया LibreOffice दस्तावेज़ीकरण से संदर्भित करें
|
||||
fileToPDF.submit=पीडीएफ़ में बदलें
|
||||
|
||||
@@ -788,7 +805,7 @@ pdfOrganiser.placeholder=(e.g. 1,3,2 or 4-8,2,10-12 or 2n-1)
|
||||
#multiTool
|
||||
multiTool.title=पीडीएफ मल्टी टूल
|
||||
multiTool.header=पीडीएफ मल्टी टूल
|
||||
multiTool.uploadPrompts=Please Upload PDF
|
||||
multiTool.uploadPrompts=File Name
|
||||
|
||||
#view pdf
|
||||
viewPdf.title=पीडीएफ देखें
|
||||
@@ -1043,7 +1060,7 @@ licenses.version=Version
|
||||
licenses.license=License
|
||||
|
||||
|
||||
# error
|
||||
#error
|
||||
error.sorry=Sorry for the issue!
|
||||
error.needHelp=Need help / Found an issue?
|
||||
error.contactTip=If you're still having trouble, don't hesitate to reach out to us for help. You can submit a ticket on our GitHub page or contact us through Discord:
|
||||
|
||||
@@ -54,9 +54,13 @@ notAuthenticatedMessage=Felhasználó nincs hitelesítve.
|
||||
userNotFoundMessage=A felhasználó nem található.
|
||||
incorrectPasswordMessage=A jelenlegi jelszó helytelen.
|
||||
usernameExistsMessage=Az új felhasználónév már létezik.
|
||||
invalidUsernameMessage=Invalid username, Username must only contain alphabet characters and numbers.
|
||||
invalidUsernameMessage=Invalid username, username can only contain letters, numbers and the following special characters @._+- or must be a valid email address.
|
||||
deleteCurrentUserMessage=Cannot delete currently logged in user.
|
||||
deleteUsernameExistsMessage=The username does not exist and cannot be deleted.
|
||||
downgradeCurrentUserMessage=A jelenlegi felhasználó szerepkörét nem lehet visszaminősíteni
|
||||
downgradeCurrentUserLongMessage=Az aktuális felhasználó szerepkörét nem lehet visszaminősíteni. Ezért az aktuális felhasználó nem jelenik meg.
|
||||
userAlreadyExistsOAuthMessage=The user already exists as an OAuth2 user.
|
||||
userAlreadyExistsWebMessage=The user already exists as an web user.
|
||||
error=Error
|
||||
oops=Oops!
|
||||
help=Help
|
||||
@@ -67,6 +71,7 @@ visitGithub=Visit Github Repository
|
||||
donate=Donate
|
||||
color=Color
|
||||
sponsor=Sponsor
|
||||
info=Info
|
||||
|
||||
|
||||
|
||||
@@ -100,12 +105,18 @@ pipelineOptions.validateButton=Validate
|
||||
#############
|
||||
# NAVBAR #
|
||||
#############
|
||||
navbar.convert=Átalakítás
|
||||
navbar.security=Biztonság
|
||||
navbar.other=Egyéb
|
||||
navbar.favorite=Favorites
|
||||
navbar.darkmode=Sötét mód
|
||||
navbar.pageOps=Lap műveletek
|
||||
navbar.language=Languages
|
||||
navbar.settings=Beállítások
|
||||
navbar.allTools=Tools
|
||||
navbar.multiTool=Multi Tools
|
||||
navbar.sections.organize=Organize
|
||||
navbar.sections.convertTo=Convert to PDF
|
||||
navbar.sections.convertFrom=Convert from PDF
|
||||
navbar.sections.security=Sign & Security
|
||||
navbar.sections.advance=Advanced
|
||||
navbar.sections.edit=View & Edit
|
||||
|
||||
#############
|
||||
# SETTINGS #
|
||||
@@ -162,7 +173,7 @@ adminUserSettings.header=Adminisztrátori Felhasználói Vezérlési Beállítá
|
||||
adminUserSettings.admin=Adminisztrátor
|
||||
adminUserSettings.user=Felhasználó
|
||||
adminUserSettings.addUser=Új felhasználó hozzáadása
|
||||
adminUserSettings.usernameInfo=Username must only contain letters and numbers, no spaces or special characters.
|
||||
adminUserSettings.usernameInfo=Username can only contain letters, numbers and the following special characters @._+- or must be a valid email address.
|
||||
adminUserSettings.roles=Szerepek
|
||||
adminUserSettings.role=Szerep
|
||||
adminUserSettings.actions=Műveletek
|
||||
@@ -173,6 +184,8 @@ adminUserSettings.demoUser=Demo User (No custom settings)
|
||||
adminUserSettings.internalApiUser=Internal API User
|
||||
adminUserSettings.forceChange=Kényszerítse a felhasználót a felhasználónév/jelszó megváltoztatására bejelentkezéskor
|
||||
adminUserSettings.submit=Felhasználó mentése
|
||||
adminUserSettings.changeUserRole=Felhasználó szerepkörének módosítása
|
||||
adminUserSettings.authenticated=Authenticated
|
||||
|
||||
#############
|
||||
# HOME-PAGE #
|
||||
@@ -437,6 +450,8 @@ login.rememberme=Emlékezz rám
|
||||
login.invalid=Érvénytelen felhasználónév vagy jelszó!
|
||||
login.locked=A fiókja zárolva lett!
|
||||
login.signinTitle=Kérjük, jelentkezzen be!
|
||||
login.ssoSignIn=Bejelentkezés egyszeri bejelentkezéssel
|
||||
login.oauth2AutoCreateDisabled=OAUTH2 Felhasználó automatikus létrehozása letiltva
|
||||
|
||||
|
||||
#auto-redact
|
||||
@@ -689,6 +704,7 @@ repair.submit=Javítás
|
||||
#flatten
|
||||
flatten.title=Kiegyenlítés
|
||||
flatten.header=PDF-ek kiegyenlítése
|
||||
flatten.flattenOnlyForms=Flatten only forms
|
||||
flatten.submit=Kiegyenlítés
|
||||
|
||||
|
||||
@@ -736,6 +752,7 @@ extractImages.submit=Kinyerés
|
||||
fileToPDF.title=Fájl PDF dokumentummá alakítása
|
||||
fileToPDF.header=Konvertáljon bármilyen fájlt PDF dokumentummá
|
||||
fileToPDF.credit=Ez a szolgáltatás a LibreOffice-t és az Unoconv-ot használja a fájlkonverzióhoz.
|
||||
fileToPDF.supportedFileTypesInfo=Supported File types
|
||||
fileToPDF.supportedFileTypes=A funkció az alábbi fájltípusokat támogatja, azonban a teljesen friss támogatott formátumok listájáért kérjük, tekintse meg a LibreOffice dokumentációját
|
||||
fileToPDF.submit=Konvertálás PDF dokumentummá
|
||||
|
||||
@@ -788,7 +805,7 @@ pdfOrganiser.placeholder=(e.g. 1,3,2 or 4-8,2,10-12 or 2n-1)
|
||||
#multiTool
|
||||
multiTool.title=PDF többfunkciós eszköz
|
||||
multiTool.header=PDF többfunkciós eszköz
|
||||
multiTool.uploadPrompts=Please Upload PDF
|
||||
multiTool.uploadPrompts=File Name
|
||||
|
||||
#view pdf
|
||||
viewPdf.title=PDF megtekintése
|
||||
@@ -1043,7 +1060,7 @@ licenses.version=Version
|
||||
licenses.license=License
|
||||
|
||||
|
||||
# error
|
||||
#error
|
||||
error.sorry=Sorry for the issue!
|
||||
error.needHelp=Need help / Found an issue?
|
||||
error.contactTip=If you're still having trouble, don't hesitate to reach out to us for help. You can submit a ticket on our GitHub page or contact us through Discord:
|
||||
|
||||
@@ -54,9 +54,13 @@ notAuthenticatedMessage=Pengguna tidak ter-autentikasi.
|
||||
userNotFoundMessage=Pengguna tidak ditemukan.
|
||||
incorrectPasswordMessage=Kata sandi saat ini salah.
|
||||
usernameExistsMessage=Nama pengguna baru sudah ada.
|
||||
invalidUsernameMessage=Invalid username, Username must only contain alphabet characters and numbers.
|
||||
invalidUsernameMessage=Invalid username, username can only contain letters, numbers and the following special characters @._+- or must be a valid email address.
|
||||
deleteCurrentUserMessage=Cannot delete currently logged in user.
|
||||
deleteUsernameExistsMessage=The username does not exist and cannot be deleted.
|
||||
downgradeCurrentUserMessage=Tidak dapat menurunkan peran pengguna saat ini
|
||||
downgradeCurrentUserLongMessage=Tidak dapat menurunkan peran pengguna saat ini. Oleh karena itu, pengguna saat ini tidak akan ditampilkan.
|
||||
userAlreadyExistsOAuthMessage=The user already exists as an OAuth2 user.
|
||||
userAlreadyExistsWebMessage=The user already exists as an web user.
|
||||
error=Error
|
||||
oops=Oops!
|
||||
help=Help
|
||||
@@ -67,6 +71,7 @@ visitGithub=Visit Github Repository
|
||||
donate=Donate
|
||||
color=Color
|
||||
sponsor=Sponsor
|
||||
info=Info
|
||||
|
||||
|
||||
|
||||
@@ -100,12 +105,18 @@ pipelineOptions.validateButton=Validate
|
||||
#############
|
||||
# NAVBAR #
|
||||
#############
|
||||
navbar.convert=Konversi
|
||||
navbar.security=Keamanan
|
||||
navbar.other=Lain-lain
|
||||
navbar.favorite=Favorites
|
||||
navbar.darkmode=Mode Gelap
|
||||
navbar.pageOps=Operasi Halaman
|
||||
navbar.language=Languages
|
||||
navbar.settings=Pengaturan
|
||||
navbar.allTools=Tools
|
||||
navbar.multiTool=Multi Tools
|
||||
navbar.sections.organize=Organize
|
||||
navbar.sections.convertTo=Convert to PDF
|
||||
navbar.sections.convertFrom=Convert from PDF
|
||||
navbar.sections.security=Sign & Security
|
||||
navbar.sections.advance=Advanced
|
||||
navbar.sections.edit=View & Edit
|
||||
|
||||
#############
|
||||
# SETTINGS #
|
||||
@@ -162,7 +173,7 @@ adminUserSettings.header=Pengaturan Kontrol Admin
|
||||
adminUserSettings.admin=Admin
|
||||
adminUserSettings.user=Pengguna
|
||||
adminUserSettings.addUser=Tambahkan Pengguna Baru
|
||||
adminUserSettings.usernameInfo=Username must only contain letters and numbers, no spaces or special characters.
|
||||
adminUserSettings.usernameInfo=Username can only contain letters, numbers and the following special characters @._+- or must be a valid email address.
|
||||
adminUserSettings.roles=Peran
|
||||
adminUserSettings.role=Peran
|
||||
adminUserSettings.actions=Tindakan
|
||||
@@ -173,6 +184,8 @@ adminUserSettings.demoUser=Demo User (No custom settings)
|
||||
adminUserSettings.internalApiUser=Internal API User
|
||||
adminUserSettings.forceChange=Memaksa pengguna untuk mengubah nama pengguna/kata sandi saat masuk
|
||||
adminUserSettings.submit=Simpan Pengguna
|
||||
adminUserSettings.changeUserRole=Ubah Peran Pengguna
|
||||
adminUserSettings.authenticated=Authenticated
|
||||
|
||||
#############
|
||||
# HOME-PAGE #
|
||||
@@ -437,6 +450,8 @@ login.rememberme=Ingat saya
|
||||
login.invalid=Nama pengguna atau kata sandi tidak valid.
|
||||
login.locked=Akun Anda telah dikunci.
|
||||
login.signinTitle=Silakan masuk
|
||||
login.ssoSignIn=Masuk melalui Single Sign - on
|
||||
login.oauth2AutoCreateDisabled=OAUTH2 Buat Otomatis Pengguna Dinonaktifkan
|
||||
|
||||
|
||||
#auto-redact
|
||||
@@ -689,6 +704,7 @@ repair.submit=Perbaiki
|
||||
#flatten
|
||||
flatten.title=Ratakan
|
||||
flatten.header=Ratakan PDF
|
||||
flatten.flattenOnlyForms=Flatten only forms
|
||||
flatten.submit=Ratakan
|
||||
|
||||
|
||||
@@ -736,6 +752,7 @@ extractImages.submit=Ekstrak
|
||||
fileToPDF.title=Berkas ke PDF
|
||||
fileToPDF.header=Mengonversi berkas apa pun ke PDF
|
||||
fileToPDF.credit=Layanan ini menggunakan LibreOffice dan Unoconv untuk konversi berkas.
|
||||
fileToPDF.supportedFileTypesInfo=Supported File types
|
||||
fileToPDF.supportedFileTypes=Jenis berkas yang didukung harus mencakup yang di bawah ini, namun untuk daftar lengkap format yang didukung, silakan lihat dokumentasi LibreOffice
|
||||
fileToPDF.submit=Konversi ke PDF
|
||||
|
||||
@@ -788,7 +805,7 @@ pdfOrganiser.placeholder=(e.g. 1,3,2 or 4-8,2,10-12 or 2n-1)
|
||||
#multiTool
|
||||
multiTool.title=Alat Multi PDF
|
||||
multiTool.header=Alat Multi PDF
|
||||
multiTool.uploadPrompts=Please Upload PDF
|
||||
multiTool.uploadPrompts=File Name
|
||||
|
||||
#view pdf
|
||||
viewPdf.title=Lihat PDF
|
||||
@@ -1043,7 +1060,7 @@ licenses.version=Version
|
||||
licenses.license=License
|
||||
|
||||
|
||||
# error
|
||||
#error
|
||||
error.sorry=Sorry for the issue!
|
||||
error.needHelp=Need help / Found an issue?
|
||||
error.contactTip=If you're still having trouble, don't hesitate to reach out to us for help. You can submit a ticket on our GitHub page or contact us through Discord:
|
||||
|
||||
@@ -54,9 +54,13 @@ notAuthenticatedMessage=Utente non autenticato.
|
||||
userNotFoundMessage=Utente non trovato.
|
||||
incorrectPasswordMessage=La password attuale non è corretta.
|
||||
usernameExistsMessage=Il nuovo nome utente esiste già.
|
||||
invalidUsernameMessage=Nome utente non valido, il nome utente deve contenere solo caratteri alfabetici e numeri.
|
||||
invalidUsernameMessage=Nome utente non valido, il nome utente può contenere solo lettere, numeri e i seguenti caratteri speciali @._+- o deve essere un indirizzo email valido.
|
||||
deleteCurrentUserMessage=Impossibile eliminare l'utente attualmente connesso.
|
||||
deleteUsernameExistsMessage=Il nome utente non esiste e non può essere eliminato.
|
||||
downgradeCurrentUserMessage=Impossibile declassare il ruolo dell'utente corrente
|
||||
downgradeCurrentUserLongMessage=Impossibile declassare il ruolo dell'utente corrente. Pertanto, l'utente corrente non verrà visualizzato.
|
||||
userAlreadyExistsOAuthMessage=L'utente esiste già come utente OAuth2.
|
||||
userAlreadyExistsWebMessage=L'utente esiste già come utente web.
|
||||
error=Errore
|
||||
oops=Oops!
|
||||
help=Aiuto
|
||||
@@ -67,6 +71,7 @@ visitGithub=Visita il repository Github
|
||||
donate=Donazione
|
||||
color=Colore
|
||||
sponsor=Sponsor
|
||||
info=Info
|
||||
|
||||
|
||||
|
||||
@@ -100,19 +105,25 @@ pipelineOptions.validateButton=Convalidare
|
||||
#############
|
||||
# NAVBAR #
|
||||
#############
|
||||
navbar.convert=Converti
|
||||
navbar.security=Sicurezza
|
||||
navbar.other=Altro
|
||||
navbar.favorite=Preferiti
|
||||
navbar.darkmode=Modalità Scura
|
||||
navbar.pageOps=Modifica pagine
|
||||
navbar.language=Lingue
|
||||
navbar.settings=Impostazioni
|
||||
navbar.allTools=Strumenti
|
||||
navbar.multiTool=Strumenti multipli
|
||||
navbar.sections.organize=Organizza
|
||||
navbar.sections.convertTo=Converti in PDF
|
||||
navbar.sections.convertFrom=Converti da PDF
|
||||
navbar.sections.security=Firma Firma & Sicurezza
|
||||
navbar.sections.advance=Avanzate
|
||||
navbar.sections.edit=Visualizza & Modifica
|
||||
|
||||
#############
|
||||
# SETTINGS #
|
||||
#############
|
||||
settings.title=Impostazioni
|
||||
settings.update=Aggiornamento disponibile
|
||||
settings.updateAvailable={0} is the current installed version. A new version ({1}) is available.
|
||||
settings.updateAvailable={0} è la versione attualmente installata. Una nuova versione ({1}) è disponibile.
|
||||
settings.appVersion=Versione App:
|
||||
settings.downloadOption.title=Scegli opzione di download (Per file singoli non compressi):
|
||||
settings.downloadOption.1=Apri in questa finestra
|
||||
@@ -162,7 +173,7 @@ adminUserSettings.header=Impostazioni di controllo utente amministratore
|
||||
adminUserSettings.admin=Amministratore
|
||||
adminUserSettings.user=Utente
|
||||
adminUserSettings.addUser=Aggiungi un nuovo Utente
|
||||
adminUserSettings.usernameInfo=Il nome utente deve contenere solo lettere e numeri, senza spazi o caratteri speciali.
|
||||
adminUserSettings.usernameInfo=Il nome utente può contenere solo lettere, numeri e i seguenti caratteri speciali @._+- oppure deve essere un indirizzo email valido.
|
||||
adminUserSettings.roles=Ruoli
|
||||
adminUserSettings.role=Ruolo
|
||||
adminUserSettings.actions=Azioni
|
||||
@@ -173,6 +184,8 @@ adminUserSettings.demoUser=Utente demo (nessuna impostazione personalizzata)
|
||||
adminUserSettings.internalApiUser=API utente interna
|
||||
adminUserSettings.forceChange=Forza l'utente a cambiare nome username/password all'accesso
|
||||
adminUserSettings.submit=Salva utente
|
||||
adminUserSettings.changeUserRole=Cambia il ruolo dell'utente
|
||||
adminUserSettings.authenticated=Autenticato
|
||||
|
||||
#############
|
||||
# HOME-PAGE #
|
||||
@@ -437,6 +450,8 @@ login.rememberme=Ricordami
|
||||
login.invalid=Nome utente o password errati.
|
||||
login.locked=Il tuo account è stato bloccato.
|
||||
login.signinTitle=Per favore accedi
|
||||
login.ssoSignIn=Accedi tramite Single Sign-on
|
||||
login.oauth2AutoCreateDisabled=Creazione automatica utente OAUTH2 DISABILITATA
|
||||
|
||||
|
||||
#auto-redact
|
||||
@@ -687,8 +702,9 @@ repair.submit=Ripara
|
||||
|
||||
|
||||
#flatten
|
||||
flatten.title=Appiattisci
|
||||
flatten.title=Appiattire
|
||||
flatten.header=Appiattisci PDF
|
||||
flatten.flattenOnlyForms=Appiattisci solo i moduli
|
||||
flatten.submit=Appiattisci
|
||||
|
||||
|
||||
@@ -736,6 +752,7 @@ extractImages.submit=Estrai
|
||||
fileToPDF.title=Converti file in PDF
|
||||
fileToPDF.header=Converti qualsiasi file in PDF
|
||||
fileToPDF.credit=Questo servizio utilizza LibreOffice e Unoconv per la conversione dei file.
|
||||
fileToPDF.supportedFileTypesInfo=Tipi di file supportati
|
||||
fileToPDF.supportedFileTypes=I formati file supportati dovrebbero includere quelli sottostanti. Tuttavia, per una lista aggiornata controlla la documentazione di LibreOffice
|
||||
fileToPDF.submit=Converti in PDF
|
||||
|
||||
@@ -788,7 +805,7 @@ pdfOrganiser.placeholder=(ad es. 1,3,2 o 4-8,2,10-12 o 2n-1)
|
||||
#multiTool
|
||||
multiTool.title=Multifunzione PDF
|
||||
multiTool.header=Multifunzione PDF
|
||||
multiTool.uploadPrompts=Caricare il PDF
|
||||
multiTool.uploadPrompts=Nome file
|
||||
|
||||
#view pdf
|
||||
viewPdf.title=Visualizza PDF
|
||||
@@ -941,7 +958,7 @@ pdfToPDFA.header=Da PDF a PDF/A
|
||||
pdfToPDFA.credit=Questo servizio utilizza OCRmyPDF per la conversione in PDF/A.
|
||||
pdfToPDFA.submit=Converti
|
||||
pdfToPDFA.tip=Attualmente non funziona per più input contemporaneamente
|
||||
pdfToPDFA.outputFormat=Output format
|
||||
pdfToPDFA.outputFormat=Formato di output
|
||||
|
||||
|
||||
#PDFToWord
|
||||
@@ -1043,7 +1060,7 @@ licenses.version=Versione
|
||||
licenses.license=Licenza
|
||||
|
||||
|
||||
# error
|
||||
#error
|
||||
error.sorry=Ci scusiamo per il problema!
|
||||
error.needHelp=Hai bisogno di aiuto / trovato un problema?
|
||||
error.contactTip=Se i problemi persistono, non esitare a contattarci per chiedere aiuto. Puoi inviare un ticket sulla nostra pagina GitHub o contattarci tramite Discord:
|
||||
|
||||
@@ -54,9 +54,13 @@ notAuthenticatedMessage=ユーザーが認証されていません。
|
||||
userNotFoundMessage=ユーザーが見つかりません。
|
||||
incorrectPasswordMessage=現在のパスワードが正しくありません。
|
||||
usernameExistsMessage=新しいユーザー名はすでに存在します。
|
||||
invalidUsernameMessage=ユーザー名が無効です。ユーザー名にはアルファベットと数字のみを使用してください。
|
||||
invalidUsernameMessage=ユーザー名が無効です。ユーザー名には文字、数字、およびそれに続く特殊文字 @._+- のみを含めることができます。または、有効な電子メール アドレスである必要があります。
|
||||
deleteCurrentUserMessage=現在ログインしているユーザーは削除できません。
|
||||
deleteUsernameExistsMessage=そのユーザー名は存在しないため削除できません。
|
||||
downgradeCurrentUserMessage=現在のユーザーの役割をダウングレードできません
|
||||
downgradeCurrentUserLongMessage=現在のユーザーの役割をダウングレードできません。したがって、現在のユーザーは表示されません。
|
||||
userAlreadyExistsOAuthMessage=The user already exists as an OAuth2 user.
|
||||
userAlreadyExistsWebMessage=The user already exists as an web user.
|
||||
error=エラー
|
||||
oops=おっと!
|
||||
help=ヘルプ
|
||||
@@ -67,6 +71,7 @@ visitGithub=Githubリポジトリを訪問する
|
||||
donate=寄付する
|
||||
color=色
|
||||
sponsor=スポンサー
|
||||
info=Info
|
||||
|
||||
|
||||
|
||||
@@ -100,12 +105,18 @@ pipelineOptions.validateButton=検証
|
||||
#############
|
||||
# NAVBAR #
|
||||
#############
|
||||
navbar.convert=変換
|
||||
navbar.security=セキュリティ
|
||||
navbar.other=その他
|
||||
navbar.favorite=Favorites
|
||||
navbar.darkmode=ダークモード
|
||||
navbar.pageOps=ページ操作
|
||||
navbar.language=Languages
|
||||
navbar.settings=設定
|
||||
navbar.allTools=Tools
|
||||
navbar.multiTool=Multi Tools
|
||||
navbar.sections.organize=Organize
|
||||
navbar.sections.convertTo=Convert to PDF
|
||||
navbar.sections.convertFrom=Convert from PDF
|
||||
navbar.sections.security=Sign & Security
|
||||
navbar.sections.advance=Advanced
|
||||
navbar.sections.edit=View & Edit
|
||||
|
||||
#############
|
||||
# SETTINGS #
|
||||
@@ -162,7 +173,7 @@ adminUserSettings.header=管理者ユーザー制御設定
|
||||
adminUserSettings.admin=管理者
|
||||
adminUserSettings.user=ユーザー
|
||||
adminUserSettings.addUser=新しいユーザを追加
|
||||
adminUserSettings.usernameInfo=ユーザー名には文字と数字のみが使用でき、スペースや特殊文字は使用できません。
|
||||
adminUserSettings.usernameInfo=ユーザー名には、文字、数字、および次の特殊文字 @._+- のみを含めることができます。または、有効な電子メール アドレスである必要があります。
|
||||
adminUserSettings.roles=役割
|
||||
adminUserSettings.role=役割
|
||||
adminUserSettings.actions=アクション
|
||||
@@ -173,6 +184,8 @@ adminUserSettings.demoUser=デモユーザー (カスタム設定なし)
|
||||
adminUserSettings.internalApiUser=内部APIユーザー
|
||||
adminUserSettings.forceChange=ログイン時にユーザー名/パスワードを強制的に変更する
|
||||
adminUserSettings.submit=ユーザーの保存
|
||||
adminUserSettings.changeUserRole=ユーザーの役割を変更する
|
||||
adminUserSettings.authenticated=Authenticated
|
||||
|
||||
#############
|
||||
# HOME-PAGE #
|
||||
@@ -437,6 +450,8 @@ login.rememberme=サインイン状態を記憶する
|
||||
login.invalid=ユーザー名かパスワードが無効です。
|
||||
login.locked=あなたのアカウントはロックされています。
|
||||
login.signinTitle=サインインしてください
|
||||
login.ssoSignIn=シングルサインオンでログイン
|
||||
login.oauth2AutoCreateDisabled=OAuth 2自動作成ユーザーが無効
|
||||
|
||||
|
||||
#auto-redact
|
||||
@@ -689,6 +704,7 @@ repair.submit=修復
|
||||
#flatten
|
||||
flatten.title=平坦化
|
||||
flatten.header=PDFを平坦化する
|
||||
flatten.flattenOnlyForms=Flatten only forms
|
||||
flatten.submit=平坦化
|
||||
|
||||
|
||||
@@ -736,6 +752,7 @@ extractImages.submit=抽出
|
||||
fileToPDF.title=ファイルをPDFに変換
|
||||
fileToPDF.header=あらゆるファイルをPDFに変換
|
||||
fileToPDF.credit=本サービスはファイル変換にLibreOfficeとUnoconvを使用しています。
|
||||
fileToPDF.supportedFileTypesInfo=Supported File types
|
||||
fileToPDF.supportedFileTypes=サポートされるファイル形式には以下が含まれますが、完全な更新リストについてはLibreOfficeのドキュメントを参照してください。
|
||||
fileToPDF.submit=PDFを変換
|
||||
|
||||
@@ -788,7 +805,7 @@ pdfOrganiser.placeholder=(例:1,3,2または4-8,2,10-12または2n-1)
|
||||
#multiTool
|
||||
multiTool.title=PDFマルチツール
|
||||
multiTool.header=PDFマルチツール
|
||||
multiTool.uploadPrompts=Please Upload PDF
|
||||
multiTool.uploadPrompts=File Name
|
||||
|
||||
#view pdf
|
||||
viewPdf.title=PDFを表示
|
||||
@@ -1043,7 +1060,7 @@ licenses.version=バージョン
|
||||
licenses.license=ライセンス
|
||||
|
||||
|
||||
# error
|
||||
#error
|
||||
error.sorry=問題が発生したことをお詫び申し上げます!
|
||||
error.needHelp=助けが必要/問題が見つかりましたか?
|
||||
error.contactTip=まだ問題が解決していない場合は、お手数ですが、GitHubページでチケットを提出するか、Discordで私たちに連絡してください:
|
||||
|
||||
@@ -54,9 +54,13 @@ notAuthenticatedMessage=사용자가 인증되지 않았습니다.
|
||||
userNotFoundMessage=사용자를 찾을 수 없습니다.
|
||||
incorrectPasswordMessage=현재 비밀번호가 틀립니다.
|
||||
usernameExistsMessage=새 사용자명이 이미 존재합니다.
|
||||
invalidUsernameMessage=사용자 이름이 잘못되었습니다. 사용자 이름에는 알파벳 문자와 숫자만 포함되어야 합니다.
|
||||
invalidUsernameMessage=잘못된 사용자 이름입니다. 사용자 이름에는 문자, 숫자 및 다음 특수 문자(@._+-)만 포함할 수 있거나 유효한 이메일 주소여야 합니다.
|
||||
deleteCurrentUserMessage=현재 로그인한 사용자를 삭제할 수 없습니다.
|
||||
deleteUsernameExistsMessage=사용자 이름이 존재하지 않으며 삭제할 수 없습니다.
|
||||
downgradeCurrentUserMessage=현재 사용자의 역할을 다운그레이드할 수 없습니다
|
||||
downgradeCurrentUserLongMessage=현재 사용자의 역할을 다운그레이드할 수 없습니다. 따라서 현재 사용자는 표시되지 않습니다.
|
||||
userAlreadyExistsOAuthMessage=The user already exists as an OAuth2 user.
|
||||
userAlreadyExistsWebMessage=The user already exists as an web user.
|
||||
error=오류
|
||||
oops=어머나!
|
||||
help=도움말
|
||||
@@ -67,6 +71,7 @@ visitGithub=GitHub 저장소 방문하기
|
||||
donate=기부하기
|
||||
color=색상
|
||||
sponsor=스폰서
|
||||
info=Info
|
||||
|
||||
|
||||
|
||||
@@ -100,12 +105,18 @@ pipelineOptions.validateButton=확인
|
||||
#############
|
||||
# NAVBAR #
|
||||
#############
|
||||
navbar.convert=변환
|
||||
navbar.security=보안
|
||||
navbar.other=기타
|
||||
navbar.favorite=Favorites
|
||||
navbar.darkmode=다크 모드
|
||||
navbar.pageOps=페이지 편집
|
||||
navbar.language=Languages
|
||||
navbar.settings=설정
|
||||
navbar.allTools=Tools
|
||||
navbar.multiTool=Multi Tools
|
||||
navbar.sections.organize=Organize
|
||||
navbar.sections.convertTo=Convert to PDF
|
||||
navbar.sections.convertFrom=Convert from PDF
|
||||
navbar.sections.security=Sign & Security
|
||||
navbar.sections.advance=Advanced
|
||||
navbar.sections.edit=View & Edit
|
||||
|
||||
#############
|
||||
# SETTINGS #
|
||||
@@ -162,7 +173,7 @@ adminUserSettings.header=사용자 관리
|
||||
adminUserSettings.admin=관리자
|
||||
adminUserSettings.user=사용자
|
||||
adminUserSettings.addUser=새 사용자 추가
|
||||
adminUserSettings.usernameInfo=사용자 이름은 문자와 숫자만 포함해야 하며 공백이나 특수 문자는 포함할 수 없습니다.
|
||||
adminUserSettings.usernameInfo=사용자 이름은 문자, 숫자, 특수 문자 @._+-만 포함할 수 있으며 유효한 이메일 주소여야 합니다.
|
||||
adminUserSettings.roles=역할
|
||||
adminUserSettings.role=역할
|
||||
adminUserSettings.actions=동작
|
||||
@@ -173,6 +184,8 @@ adminUserSettings.demoUser=데모 사용자(사용자 지정 설정 없음)
|
||||
adminUserSettings.internalApiUser=내부 API 사용자
|
||||
adminUserSettings.forceChange=다음 로그인 때 사용자명과 비밀번호를 변경하도록 강제
|
||||
adminUserSettings.submit=사용자 저장
|
||||
adminUserSettings.changeUserRole=사용자의 역할 변경
|
||||
adminUserSettings.authenticated=Authenticated
|
||||
|
||||
#############
|
||||
# HOME-PAGE #
|
||||
@@ -437,6 +450,8 @@ login.rememberme=로그인 유지
|
||||
login.invalid=사용자 이름이나 비밀번호가 틀립니다.
|
||||
login.locked=계정이 잠겼습니다.
|
||||
login.signinTitle=로그인해 주세요.
|
||||
login.ssoSignIn=싱글사인온을 통한 로그인
|
||||
login.oauth2AutoCreateDisabled=OAUTH2 사용자 자동 생성 비활성화됨
|
||||
|
||||
|
||||
#auto-redact
|
||||
@@ -689,6 +704,7 @@ repair.submit=복구
|
||||
#flatten
|
||||
flatten.title=평탄화
|
||||
flatten.header=PDF 문서의 레이어 평탄화
|
||||
flatten.flattenOnlyForms=Flatten only forms
|
||||
flatten.submit=평탄화
|
||||
|
||||
|
||||
@@ -736,6 +752,7 @@ extractImages.submit=추출
|
||||
fileToPDF.title=File to PDF
|
||||
fileToPDF.header=다양한 파일을 PDF로 변환
|
||||
fileToPDF.credit=이 서비스는 파일 변환에 LibreOffice와 Unoconv를 사용합니다.
|
||||
fileToPDF.supportedFileTypesInfo=Supported File types
|
||||
fileToPDF.supportedFileTypes=지원되는 파일 형식은 아래와 같습니다. 지원되는 형식의 전체 업데이트 목록은 LibreOffice 설명서를 참조합니다.
|
||||
fileToPDF.submit=PDF로 변환
|
||||
|
||||
@@ -788,7 +805,7 @@ pdfOrganiser.placeholder=(예: 1,3,2 또는 4-8,2,10-12 또는 2n-1)
|
||||
#multiTool
|
||||
multiTool.title=PDF 멀티툴
|
||||
multiTool.header=PDF 멀티툴
|
||||
multiTool.uploadPrompts=PDF를 업로드하십시오
|
||||
multiTool.uploadPrompts=File Name
|
||||
|
||||
#view pdf
|
||||
viewPdf.title=PDF 뷰어
|
||||
@@ -1043,7 +1060,7 @@ licenses.version=버전
|
||||
licenses.license=라이센스
|
||||
|
||||
|
||||
# error
|
||||
#error
|
||||
error.sorry=문제를 끼친 점 죄송합니다!
|
||||
error.needHelp=도움이 필요하신가요 / 문제가 있으신가요?
|
||||
error.contactTip=여전히 문제가 해결되지 않는다면 망설이지 마시고 도움을 요청하십시오. GitHub 페이지에서 티켓을 제출하거나 Discord를 통해 우리에게 연락하실 수 있습니다:
|
||||
|
||||
@@ -54,9 +54,13 @@ notAuthenticatedMessage=Gebruiker niet ingelogd.
|
||||
userNotFoundMessage=Gebruiker niet gevonden.
|
||||
incorrectPasswordMessage=Huidige wachtwoord is onjuist.
|
||||
usernameExistsMessage=Nieuwe gebruikersnaam bestaat al.
|
||||
invalidUsernameMessage=Invalid username, Username must only contain alphabet characters and numbers.
|
||||
invalidUsernameMessage=Invalid username, username can only contain letters, numbers and the following special characters @._+- or must be a valid email address.
|
||||
deleteCurrentUserMessage=Cannot delete currently logged in user.
|
||||
deleteUsernameExistsMessage=The username does not exist and cannot be deleted.
|
||||
downgradeCurrentUserMessage=Kan de rol van de huidige gebruiker niet downgraden
|
||||
downgradeCurrentUserLongMessage=Kan de rol van de huidige gebruiker niet downgraden. Huidige gebruiker wordt dus niet weergegeven.
|
||||
userAlreadyExistsOAuthMessage=The user already exists as an OAuth2 user.
|
||||
userAlreadyExistsWebMessage=The user already exists as an web user.
|
||||
error=Error
|
||||
oops=Oops!
|
||||
help=Help
|
||||
@@ -67,6 +71,7 @@ visitGithub=Visit Github Repository
|
||||
donate=Donate
|
||||
color=Color
|
||||
sponsor=Sponsor
|
||||
info=Info
|
||||
|
||||
|
||||
|
||||
@@ -100,12 +105,18 @@ pipelineOptions.validateButton=Valideren
|
||||
#############
|
||||
# NAVBAR #
|
||||
#############
|
||||
navbar.convert=Converteren
|
||||
navbar.security=Beveiliging
|
||||
navbar.other=Overige
|
||||
navbar.favorite=Favorites
|
||||
navbar.darkmode=Donkere modus
|
||||
navbar.pageOps=Pagina bewerkingen
|
||||
navbar.language=Languages
|
||||
navbar.settings=Instellingen
|
||||
navbar.allTools=Tools
|
||||
navbar.multiTool=Multi Tools
|
||||
navbar.sections.organize=Organize
|
||||
navbar.sections.convertTo=Convert to PDF
|
||||
navbar.sections.convertFrom=Convert from PDF
|
||||
navbar.sections.security=Sign & Security
|
||||
navbar.sections.advance=Advanced
|
||||
navbar.sections.edit=View & Edit
|
||||
|
||||
#############
|
||||
# SETTINGS #
|
||||
@@ -162,7 +173,7 @@ adminUserSettings.header=Beheer gebruikers
|
||||
adminUserSettings.admin=Beheerder
|
||||
adminUserSettings.user=Gebruiker
|
||||
adminUserSettings.addUser=Voeg nieuwe gebruiker toe
|
||||
adminUserSettings.usernameInfo=Username must only contain letters and numbers, no spaces or special characters.
|
||||
adminUserSettings.usernameInfo=Username can only contain letters, numbers and the following special characters @._+- or must be a valid email address.
|
||||
adminUserSettings.roles=Rollen
|
||||
adminUserSettings.role=Rol
|
||||
adminUserSettings.actions=Acties
|
||||
@@ -173,6 +184,8 @@ adminUserSettings.demoUser=Demogebruiker (geen aangepaste instellingen)
|
||||
adminUserSettings.internalApiUser=Internal API User
|
||||
adminUserSettings.forceChange=Forceer gebruiker om gebruikersnaam/wachtwoord te wijzigen bij inloggen
|
||||
adminUserSettings.submit=Gebruiker opslaan
|
||||
adminUserSettings.changeUserRole=De rol van de gebruiker wijzigen
|
||||
adminUserSettings.authenticated=Authenticated
|
||||
|
||||
#############
|
||||
# HOME-PAGE #
|
||||
@@ -437,6 +450,8 @@ login.rememberme=Onthoud mij
|
||||
login.invalid=Ongeldige gebruikersnaam of wachtwoord.
|
||||
login.locked=Je account is geblokkeerd.
|
||||
login.signinTitle=Gelieve in te loggen
|
||||
login.ssoSignIn=Inloggen via Single Sign-on
|
||||
login.oauth2AutoCreateDisabled=OAUTH2 Automatisch aanmaken gebruiker uitgeschakeld
|
||||
|
||||
|
||||
#auto-redact
|
||||
@@ -689,6 +704,7 @@ repair.submit=Repareren
|
||||
#flatten
|
||||
flatten.title=Afvlakken
|
||||
flatten.header=PDF's afvlakken
|
||||
flatten.flattenOnlyForms=Flatten only forms
|
||||
flatten.submit=Afvlakken
|
||||
|
||||
|
||||
@@ -736,6 +752,7 @@ extractImages.submit=Extraheer
|
||||
fileToPDF.title=Bestand naar PDF
|
||||
fileToPDF.header=Zet elk bestand om naar PDF
|
||||
fileToPDF.credit=Deze service gebruikt LibreOffice en Unoconv voor bestandsconversie.
|
||||
fileToPDF.supportedFileTypesInfo=Supported File types
|
||||
fileToPDF.supportedFileTypes=Ondersteunde bestandstypen zijn hieronder opgenomen, maar raadpleeg voor een volledige lijst met ondersteunde formaten de LibreOffice-documentatie
|
||||
fileToPDF.submit=Omzetten naar PDF
|
||||
|
||||
@@ -788,7 +805,7 @@ pdfOrganiser.placeholder=(e.g. 1,3,2 or 4-8,2,10-12 or 2n-1)
|
||||
#multiTool
|
||||
multiTool.title=PDF Multitool
|
||||
multiTool.header=PDF Multitool
|
||||
multiTool.uploadPrompts=Please Upload PDF
|
||||
multiTool.uploadPrompts=File Name
|
||||
|
||||
#view pdf
|
||||
viewPdf.title=PDF bekijken
|
||||
@@ -1043,7 +1060,7 @@ licenses.version=Versie
|
||||
licenses.license=Licentie
|
||||
|
||||
|
||||
# error
|
||||
#error
|
||||
error.sorry=Sorry for the issue!
|
||||
error.needHelp=Need help / Found an issue?
|
||||
error.contactTip=If you're still having trouble, don't hesitate to reach out to us for help. You can submit a ticket on our GitHub page or contact us through Discord:
|
||||
|
||||
@@ -54,9 +54,13 @@ notAuthenticatedMessage=User not authenticated.
|
||||
userNotFoundMessage=User not found.
|
||||
incorrectPasswordMessage=Current password is incorrect.
|
||||
usernameExistsMessage=New Username already exists.
|
||||
invalidUsernameMessage=Invalid username, Username must only contain alphabet characters and numbers.
|
||||
invalidUsernameMessage=Invalid username, username can only contain letters, numbers and the following special characters @._+- or must be a valid email address.
|
||||
deleteCurrentUserMessage=Cannot delete currently logged in user.
|
||||
deleteUsernameExistsMessage=The username does not exist and cannot be deleted.
|
||||
downgradeCurrentUserMessage=Nie można obniżyć roli bieżącego użytkownika
|
||||
downgradeCurrentUserLongMessage=Nie można obniżyć roli bieżącego użytkownika. W związku z tym bieżący użytkownik nie zostanie wyświetlony.
|
||||
userAlreadyExistsOAuthMessage=The user already exists as an OAuth2 user.
|
||||
userAlreadyExistsWebMessage=The user already exists as an web user.
|
||||
error=Error
|
||||
oops=Oops!
|
||||
help=Help
|
||||
@@ -67,6 +71,7 @@ visitGithub=Visit Github Repository
|
||||
donate=Donate
|
||||
color=Color
|
||||
sponsor=Sponsor
|
||||
info=Info
|
||||
|
||||
|
||||
|
||||
@@ -100,12 +105,18 @@ pipelineOptions.validateButton=Validate
|
||||
#############
|
||||
# NAVBAR #
|
||||
#############
|
||||
navbar.convert=Konwertuj
|
||||
navbar.security=Bezpieczeństwo
|
||||
navbar.other=Inne
|
||||
navbar.favorite=Favorites
|
||||
navbar.darkmode=Tryb nocny
|
||||
navbar.pageOps=Strony
|
||||
navbar.language=Languages
|
||||
navbar.settings=Ustawienia
|
||||
navbar.allTools=Tools
|
||||
navbar.multiTool=Multi Tools
|
||||
navbar.sections.organize=Organize
|
||||
navbar.sections.convertTo=Convert to PDF
|
||||
navbar.sections.convertFrom=Convert from PDF
|
||||
navbar.sections.security=Sign & Security
|
||||
navbar.sections.advance=Advanced
|
||||
navbar.sections.edit=View & Edit
|
||||
|
||||
#############
|
||||
# SETTINGS #
|
||||
@@ -162,7 +173,7 @@ adminUserSettings.header=Admin User Control Settings
|
||||
adminUserSettings.admin=Admin
|
||||
adminUserSettings.user=User
|
||||
adminUserSettings.addUser=Add New User
|
||||
adminUserSettings.usernameInfo=Username must only contain letters and numbers, no spaces or special characters.
|
||||
adminUserSettings.usernameInfo=Username can only contain letters, numbers and the following special characters @._+- or must be a valid email address.
|
||||
adminUserSettings.roles=Roles
|
||||
adminUserSettings.role=Role
|
||||
adminUserSettings.actions=Actions
|
||||
@@ -173,6 +184,8 @@ adminUserSettings.demoUser=Demo User (No custom settings)
|
||||
adminUserSettings.internalApiUser=Internal API User
|
||||
adminUserSettings.forceChange=Force user to change password on login
|
||||
adminUserSettings.submit=Save User
|
||||
adminUserSettings.changeUserRole=Zmień rolę użytkownika
|
||||
adminUserSettings.authenticated=Authenticated
|
||||
|
||||
#############
|
||||
# HOME-PAGE #
|
||||
@@ -437,6 +450,8 @@ login.rememberme=Remember me
|
||||
login.invalid=Invalid username or password.
|
||||
login.locked=Your account has been locked.
|
||||
login.signinTitle=Please sign in
|
||||
login.ssoSignIn=Zaloguj się za pomocą logowania jednokrotnego
|
||||
login.oauth2AutoCreateDisabled=Wyłączono automatyczne tworzenie użytkownika OAUTH2
|
||||
|
||||
|
||||
#auto-redact
|
||||
@@ -689,6 +704,7 @@ repair.submit=Napraw
|
||||
#flatten
|
||||
flatten.title=Spłaszcz
|
||||
flatten.header=Spłaszcz dokument(y) PDF
|
||||
flatten.flattenOnlyForms=Flatten only forms
|
||||
flatten.submit=Spłaszcz
|
||||
|
||||
|
||||
@@ -736,6 +752,7 @@ extractImages.submit=Wyodrębnij
|
||||
fileToPDF.title=Plik na PDF
|
||||
fileToPDF.header=Konwertuj dowolny plik na dokument PDF
|
||||
fileToPDF.credit=Ta usługa używa LibreOffice i Unoconv do konwersji plików.
|
||||
fileToPDF.supportedFileTypesInfo=Supported File types
|
||||
fileToPDF.supportedFileTypes=Obsługiwane typy plików powinny być zgodne z poniższymi, jednak pełną zaktualizowaną listę obsługiwanych formatów można znaleźć w dokumentacji LibreOffice
|
||||
fileToPDF.submit=Konwertuj na PDF
|
||||
|
||||
@@ -788,7 +805,7 @@ pdfOrganiser.placeholder=(e.g. 1,3,2 or 4-8,2,10-12 or 2n-1)
|
||||
#multiTool
|
||||
multiTool.title=Multi narzędzie PDF
|
||||
multiTool.header=Multi narzędzie PDF
|
||||
multiTool.uploadPrompts=Please Upload PDF
|
||||
multiTool.uploadPrompts=File Name
|
||||
|
||||
#view pdf
|
||||
viewPdf.title=View PDF
|
||||
@@ -1043,7 +1060,7 @@ licenses.version=Version
|
||||
licenses.license=License
|
||||
|
||||
|
||||
# error
|
||||
#error
|
||||
error.sorry=Sorry for the issue!
|
||||
error.needHelp=Need help / Found an issue?
|
||||
error.contactTip=If you're still having trouble, don't hesitate to reach out to us for help. You can submit a ticket on our GitHub page or contact us through Discord:
|
||||
|
||||
@@ -54,9 +54,13 @@ notAuthenticatedMessage=User not authenticated.
|
||||
userNotFoundMessage=User not found.
|
||||
incorrectPasswordMessage=Current password is incorrect.
|
||||
usernameExistsMessage=New Username already exists.
|
||||
invalidUsernameMessage=Invalid username, Username must only contain alphabet characters and numbers.
|
||||
invalidUsernameMessage=Invalid username, username can only contain letters, numbers and the following special characters @._+- or must be a valid email address.
|
||||
deleteCurrentUserMessage=Cannot delete currently logged in user.
|
||||
deleteUsernameExistsMessage=The username does not exist and cannot be deleted.
|
||||
downgradeCurrentUserMessage=Não é possível fazer downgrade da função do usuário atual
|
||||
downgradeCurrentUserLongMessage=Não é possível fazer downgrade da função do usuário atual. Portanto, o usuário atual não será mostrado.
|
||||
userAlreadyExistsOAuthMessage=The user already exists as an OAuth2 user.
|
||||
userAlreadyExistsWebMessage=The user already exists as an web user.
|
||||
error=Error
|
||||
oops=Oops!
|
||||
help=Help
|
||||
@@ -67,6 +71,7 @@ visitGithub=Visit Github Repository
|
||||
donate=Donate
|
||||
color=Color
|
||||
sponsor=Sponsor
|
||||
info=Info
|
||||
|
||||
|
||||
|
||||
@@ -100,12 +105,18 @@ pipelineOptions.validateButton=Validate
|
||||
#############
|
||||
# NAVBAR #
|
||||
#############
|
||||
navbar.convert=Converter
|
||||
navbar.security=Segurança
|
||||
navbar.other=Outro
|
||||
navbar.favorite=Favorites
|
||||
navbar.darkmode=Modo Escuro
|
||||
navbar.pageOps=Operações de página
|
||||
navbar.language=Languages
|
||||
navbar.settings=Configurações
|
||||
navbar.allTools=Tools
|
||||
navbar.multiTool=Multi Tools
|
||||
navbar.sections.organize=Organize
|
||||
navbar.sections.convertTo=Convert to PDF
|
||||
navbar.sections.convertFrom=Convert from PDF
|
||||
navbar.sections.security=Sign & Security
|
||||
navbar.sections.advance=Advanced
|
||||
navbar.sections.edit=View & Edit
|
||||
|
||||
#############
|
||||
# SETTINGS #
|
||||
@@ -162,7 +173,7 @@ adminUserSettings.header=Admin User Control Settings
|
||||
adminUserSettings.admin=Admin
|
||||
adminUserSettings.user=User
|
||||
adminUserSettings.addUser=Add New User
|
||||
adminUserSettings.usernameInfo=Username must only contain letters and numbers, no spaces or special characters.
|
||||
adminUserSettings.usernameInfo=Username can only contain letters, numbers and the following special characters @._+- or must be a valid email address.
|
||||
adminUserSettings.roles=Roles
|
||||
adminUserSettings.role=Role
|
||||
adminUserSettings.actions=Actions
|
||||
@@ -173,6 +184,8 @@ adminUserSettings.demoUser=Demo User (No custom settings)
|
||||
adminUserSettings.internalApiUser=Internal API User
|
||||
adminUserSettings.forceChange=Force user to change password on login
|
||||
adminUserSettings.submit=Save User
|
||||
adminUserSettings.changeUserRole=Alterar Função de Usuário
|
||||
adminUserSettings.authenticated=Authenticated
|
||||
|
||||
#############
|
||||
# HOME-PAGE #
|
||||
@@ -437,6 +450,8 @@ login.rememberme=Remember me
|
||||
login.invalid=Invalid username or password.
|
||||
login.locked=Your account has been locked.
|
||||
login.signinTitle=Please sign in
|
||||
login.ssoSignIn=Iniciar sessão através de início de sessão único
|
||||
login.oauth2AutoCreateDisabled=OAUTH2 Auto-Criar Usuário Desativado
|
||||
|
||||
|
||||
#auto-redact
|
||||
@@ -689,6 +704,7 @@ repair.submit=Reparar
|
||||
#flatten
|
||||
flatten.title=Achatar
|
||||
flatten.header=Achatar PDFs
|
||||
flatten.flattenOnlyForms=Flatten only forms
|
||||
flatten.submit=Achatar
|
||||
|
||||
|
||||
@@ -736,6 +752,7 @@ extractImages.submit=Extrair
|
||||
fileToPDF.title=Arquivo para PDF
|
||||
fileToPDF.header=Converter Qualquer Arquivo para PDF
|
||||
fileToPDF.credit=Este serviço usa o LibreOffice e o Unoconv para conversão de arquivos.
|
||||
fileToPDF.supportedFileTypesInfo=Supported File types
|
||||
fileToPDF.supportedFileTypes=Os tipos de arquivo suportados devem incluir os listados abaixo. No entanto, para obter uma lista atualizada completa dos formatos suportados, consulte a documentação do LibreOffice.
|
||||
fileToPDF.submit=Converter para PDF
|
||||
|
||||
@@ -788,7 +805,7 @@ pdfOrganiser.placeholder=(e.g. 1,3,2 or 4-8,2,10-12 or 2n-1)
|
||||
#multiTool
|
||||
multiTool.title=Multiferramenta de PDF
|
||||
multiTool.header=Multiferramenta de PDF
|
||||
multiTool.uploadPrompts=Please Upload PDF
|
||||
multiTool.uploadPrompts=File Name
|
||||
|
||||
#view pdf
|
||||
viewPdf.title=View PDF
|
||||
@@ -1043,7 +1060,7 @@ licenses.version=Version
|
||||
licenses.license=License
|
||||
|
||||
|
||||
# error
|
||||
#error
|
||||
error.sorry=Sorry for the issue!
|
||||
error.needHelp=Need help / Found an issue?
|
||||
error.contactTip=If you're still having trouble, don't hesitate to reach out to us for help. You can submit a ticket on our GitHub page or contact us through Discord:
|
||||
|
||||
@@ -54,9 +54,13 @@ notAuthenticatedMessage=Utilizador não autenticado.
|
||||
userNotFoundMessage=Utilizador inexistente.
|
||||
incorrectPasswordMessage=Senha incorreta.
|
||||
usernameExistsMessage=Esse utilizador já existe.
|
||||
invalidUsernameMessage=Invalid username, Username must only contain alphabet characters and numbers.
|
||||
invalidUsernameMessage=Invalid username, username can only contain letters, numbers and the following special characters @._+- or must be a valid email address.
|
||||
deleteCurrentUserMessage=Cannot delete currently logged in user.
|
||||
deleteUsernameExistsMessage=The username does not exist and cannot be deleted.
|
||||
downgradeCurrentUserMessage=Não é possível fazer downgrade da função do utilizador atual
|
||||
downgradeCurrentUserLongMessage=Não é possível fazer downgrade da função do utilizador atual. Portanto, o utilizador atual não será mostrado.
|
||||
userAlreadyExistsOAuthMessage=The user already exists as an OAuth2 user.
|
||||
userAlreadyExistsWebMessage=The user already exists as an web user.
|
||||
error=Error
|
||||
oops=Oops!
|
||||
help=Help
|
||||
@@ -67,6 +71,7 @@ visitGithub=Visit Github Repository
|
||||
donate=Donate
|
||||
color=Color
|
||||
sponsor=Sponsor
|
||||
info=Info
|
||||
|
||||
|
||||
|
||||
@@ -100,12 +105,18 @@ pipelineOptions.validateButton=Validar
|
||||
#############
|
||||
# NAVBAR #
|
||||
#############
|
||||
navbar.convert=Converter
|
||||
navbar.security=Segurança
|
||||
navbar.other=Outro
|
||||
navbar.favorite=Favorites
|
||||
navbar.darkmode=Modo Escuro
|
||||
navbar.pageOps=Operações de página
|
||||
navbar.language=Languages
|
||||
navbar.settings=Configurações
|
||||
navbar.allTools=Tools
|
||||
navbar.multiTool=Multi Tools
|
||||
navbar.sections.organize=Organize
|
||||
navbar.sections.convertTo=Convert to PDF
|
||||
navbar.sections.convertFrom=Convert from PDF
|
||||
navbar.sections.security=Sign & Security
|
||||
navbar.sections.advance=Advanced
|
||||
navbar.sections.edit=View & Edit
|
||||
|
||||
#############
|
||||
# SETTINGS #
|
||||
@@ -162,7 +173,7 @@ adminUserSettings.header=Admin User Control Settings
|
||||
adminUserSettings.admin=Admin
|
||||
adminUserSettings.user=User
|
||||
adminUserSettings.addUser=Add New User
|
||||
adminUserSettings.usernameInfo=Username must only contain letters and numbers, no spaces or special characters.
|
||||
adminUserSettings.usernameInfo=Username can only contain letters, numbers and the following special characters @._+- or must be a valid email address.
|
||||
adminUserSettings.roles=Roles
|
||||
adminUserSettings.role=Role
|
||||
adminUserSettings.actions=Actions
|
||||
@@ -173,6 +184,8 @@ adminUserSettings.demoUser=Demo User (No custom settings)
|
||||
adminUserSettings.internalApiUser=Internal API User
|
||||
adminUserSettings.forceChange=Force user to change password on login
|
||||
adminUserSettings.submit=Save User
|
||||
adminUserSettings.changeUserRole=Alterar usuário
|
||||
adminUserSettings.authenticated=Authenticated
|
||||
|
||||
#############
|
||||
# HOME-PAGE #
|
||||
@@ -437,6 +450,8 @@ login.rememberme=Lembrar dados
|
||||
login.invalid=Utilizador ou senha inválidos.
|
||||
login.locked=A sua conta foi bloqueada.
|
||||
login.signinTitle=Introduza os seus dados de acesso
|
||||
login.ssoSignIn=Iniciar sessão através de início de sessão único
|
||||
login.oauth2AutoCreateDisabled=OAUTH2 Criação Automática de Utilizador Desativada
|
||||
|
||||
|
||||
#auto-redact
|
||||
@@ -689,6 +704,7 @@ repair.submit=Reparar
|
||||
#flatten
|
||||
flatten.title=Achatar
|
||||
flatten.header=Achatar PDFs
|
||||
flatten.flattenOnlyForms=Flatten only forms
|
||||
flatten.submit=Achatar
|
||||
|
||||
|
||||
@@ -736,6 +752,7 @@ extractImages.submit=Extrair
|
||||
fileToPDF.title=Ficheiro para PDF
|
||||
fileToPDF.header=Converter Qualquer ficheiro para PDF
|
||||
fileToPDF.credit=Este serviço usa o LibreOffice e o Unoconv para conversão de ficheiros.
|
||||
fileToPDF.supportedFileTypesInfo=Supported File types
|
||||
fileToPDF.supportedFileTypes=Os tipos de ficheiro suportados devem incluir os listados abaixo. No entanto, para obter uma lista atualizada completa dos formatos suportados, consulte a documentação do LibreOffice.
|
||||
fileToPDF.submit=Converter para PDF
|
||||
|
||||
@@ -788,7 +805,7 @@ pdfOrganiser.placeholder=(e.g. 1,3,2 or 4-8,2,10-12 or 2n-1)
|
||||
#multiTool
|
||||
multiTool.title=Multiferramenta de PDF
|
||||
multiTool.header=Multiferramenta de PDF
|
||||
multiTool.uploadPrompts=Please Upload PDF
|
||||
multiTool.uploadPrompts=File Name
|
||||
|
||||
#view pdf
|
||||
viewPdf.title=View PDF
|
||||
@@ -1043,7 +1060,7 @@ licenses.version=Versão
|
||||
licenses.license=Licença
|
||||
|
||||
|
||||
# error
|
||||
#error
|
||||
error.sorry=Sorry for the issue!
|
||||
error.needHelp=Need help / Found an issue?
|
||||
error.contactTip=If you're still having trouble, don't hesitate to reach out to us for help. You can submit a ticket on our GitHub page or contact us through Discord:
|
||||
|
||||
@@ -54,9 +54,13 @@ notAuthenticatedMessage=User not authenticated.
|
||||
userNotFoundMessage=User not found.
|
||||
incorrectPasswordMessage=Current password is incorrect.
|
||||
usernameExistsMessage=New Username already exists.
|
||||
invalidUsernameMessage=Invalid username, Username must only contain alphabet characters and numbers.
|
||||
invalidUsernameMessage=Invalid username, username can only contain letters, numbers and the following special characters @._+- or must be a valid email address.
|
||||
deleteCurrentUserMessage=Cannot delete currently logged in user.
|
||||
deleteUsernameExistsMessage=The username does not exist and cannot be deleted.
|
||||
downgradeCurrentUserMessage=Rolul utilizatorului curent nu poate fi retrogradat
|
||||
downgradeCurrentUserLongMessage=Rolul utilizatorului curent nu poate fi retrogradat. Prin urmare, utilizatorul curent nu va fi afișat.
|
||||
userAlreadyExistsOAuthMessage=The user already exists as an OAuth2 user.
|
||||
userAlreadyExistsWebMessage=The user already exists as an web user.
|
||||
error=Error
|
||||
oops=Oops!
|
||||
help=Help
|
||||
@@ -67,6 +71,7 @@ visitGithub=Visit Github Repository
|
||||
donate=Donate
|
||||
color=Color
|
||||
sponsor=Sponsor
|
||||
info=Info
|
||||
|
||||
|
||||
|
||||
@@ -100,12 +105,18 @@ pipelineOptions.validateButton=Validate
|
||||
#############
|
||||
# NAVBAR #
|
||||
#############
|
||||
navbar.convert=Converteste
|
||||
navbar.security=Securitate
|
||||
navbar.other=Altele
|
||||
navbar.favorite=Favorites
|
||||
navbar.darkmode=Mod întunecat
|
||||
navbar.pageOps=Operații pe pagină
|
||||
navbar.language=Languages
|
||||
navbar.settings=Setări
|
||||
navbar.allTools=Tools
|
||||
navbar.multiTool=Multi Tools
|
||||
navbar.sections.organize=Organize
|
||||
navbar.sections.convertTo=Convert to PDF
|
||||
navbar.sections.convertFrom=Convert from PDF
|
||||
navbar.sections.security=Sign & Security
|
||||
navbar.sections.advance=Advanced
|
||||
navbar.sections.edit=View & Edit
|
||||
|
||||
#############
|
||||
# SETTINGS #
|
||||
@@ -162,7 +173,7 @@ adminUserSettings.header=Admin User Control Settings
|
||||
adminUserSettings.admin=Admin
|
||||
adminUserSettings.user=User
|
||||
adminUserSettings.addUser=Add New User
|
||||
adminUserSettings.usernameInfo=Username must only contain letters and numbers, no spaces or special characters.
|
||||
adminUserSettings.usernameInfo=Username can only contain letters, numbers and the following special characters @._+- or must be a valid email address.
|
||||
adminUserSettings.roles=Roles
|
||||
adminUserSettings.role=Role
|
||||
adminUserSettings.actions=Actions
|
||||
@@ -173,6 +184,8 @@ adminUserSettings.demoUser=Demo User (No custom settings)
|
||||
adminUserSettings.internalApiUser=Internal API User
|
||||
adminUserSettings.forceChange=Force user to change password on login
|
||||
adminUserSettings.submit=Save User
|
||||
adminUserSettings.changeUserRole=Schimbați rolul utilizatorului
|
||||
adminUserSettings.authenticated=Authenticated
|
||||
|
||||
#############
|
||||
# HOME-PAGE #
|
||||
@@ -437,6 +450,8 @@ login.rememberme=Remember me
|
||||
login.invalid=Invalid username or password.
|
||||
login.locked=Your account has been locked.
|
||||
login.signinTitle=Please sign in
|
||||
login.ssoSignIn=Conectare prin conectare unică
|
||||
login.oauth2AutoCreateDisabled=OAUTH2 Creare automată utilizator dezactivată
|
||||
|
||||
|
||||
#auto-redact
|
||||
@@ -689,6 +704,7 @@ repair.submit=Repară
|
||||
#flatten
|
||||
flatten.title=Nivelare
|
||||
flatten.header=Nivelează documente PDF
|
||||
flatten.flattenOnlyForms=Flatten only forms
|
||||
flatten.submit=Nivelează
|
||||
|
||||
|
||||
@@ -736,6 +752,7 @@ extractImages.submit=Extrage
|
||||
fileToPDF.title=Fișier în PDF
|
||||
fileToPDF.header=Convertiți orice fișier în PDF
|
||||
fileToPDF.credit=Acest serviciu utilizează LibreOffice și Unoconv pentru conversia fișierelor.
|
||||
fileToPDF.supportedFileTypesInfo=Supported File types
|
||||
fileToPDF.supportedFileTypes=Tipurile de fișiere suportate ar trebui să includă cele de mai jos. Pentru o listă completă și actualizată a formatelor suportate, consultați documentația LibreOffice.
|
||||
fileToPDF.submit=Convertiți în PDF
|
||||
|
||||
@@ -788,7 +805,7 @@ pdfOrganiser.placeholder=(e.g. 1,3,2 or 4-8,2,10-12 or 2n-1)
|
||||
#multiTool
|
||||
multiTool.title=Instrument PDF multiplu
|
||||
multiTool.header=Instrument PDF multiplu
|
||||
multiTool.uploadPrompts=Please Upload PDF
|
||||
multiTool.uploadPrompts=File Name
|
||||
|
||||
#view pdf
|
||||
viewPdf.title=View PDF
|
||||
@@ -1043,7 +1060,7 @@ licenses.version=Version
|
||||
licenses.license=License
|
||||
|
||||
|
||||
# error
|
||||
#error
|
||||
error.sorry=Sorry for the issue!
|
||||
error.needHelp=Need help / Found an issue?
|
||||
error.contactTip=If you're still having trouble, don't hesitate to reach out to us for help. You can submit a ticket on our GitHub page or contact us through Discord:
|
||||
|
||||
@@ -54,9 +54,13 @@ notAuthenticatedMessage=Пользователь не прошел провер
|
||||
userNotFoundMessage=Пользователь не найден.
|
||||
incorrectPasswordMessage=Текущий пароль неверен.
|
||||
usernameExistsMessage=Новое имя пользователя уже существует.
|
||||
invalidUsernameMessage=Недопустимое имя пользователя, Имя пользователя должно содержать только буквы алфавита и цифры.
|
||||
invalidUsernameMessage=Неверное имя пользователя. Имя пользователя может содержать только буквы, цифры и следующие специальные символы @._+- или должно быть действительным адресом электронной почты.
|
||||
deleteCurrentUserMessage=Невозможно удалить пользователя, вошедшего в систему.
|
||||
deleteUsernameExistsMessage=Имя пользователя не существует и не может быть удалено.
|
||||
downgradeCurrentUserMessage=Невозможно понизить роль текущего пользователя
|
||||
downgradeCurrentUserLongMessage=Невозможно понизить роль текущего пользователя. Следовательно, текущий пользователь не будет отображаться.
|
||||
userAlreadyExistsOAuthMessage=The user already exists as an OAuth2 user.
|
||||
userAlreadyExistsWebMessage=The user already exists as an web user.
|
||||
error=Ошибка
|
||||
oops=Ой!
|
||||
help=Помощь
|
||||
@@ -67,6 +71,7 @@ visitGithub=Посетить репозиторий на GitHub
|
||||
donate=Пожертвовать
|
||||
color=Цвет
|
||||
sponsor=Спонсор
|
||||
info=Info
|
||||
|
||||
|
||||
|
||||
@@ -100,12 +105,18 @@ pipelineOptions.validateButton=Проверить
|
||||
#############
|
||||
# NAVBAR #
|
||||
#############
|
||||
navbar.convert=Конвертировать
|
||||
navbar.security=Безопасность
|
||||
navbar.other=Другое
|
||||
navbar.favorite=Favorites
|
||||
navbar.darkmode=Темный режим
|
||||
navbar.pageOps=Операции с страницей
|
||||
navbar.language=Languages
|
||||
navbar.settings=Настройки
|
||||
navbar.allTools=Tools
|
||||
navbar.multiTool=Multi Tools
|
||||
navbar.sections.organize=Organize
|
||||
navbar.sections.convertTo=Convert to PDF
|
||||
navbar.sections.convertFrom=Convert from PDF
|
||||
navbar.sections.security=Sign & Security
|
||||
navbar.sections.advance=Advanced
|
||||
navbar.sections.edit=View & Edit
|
||||
|
||||
#############
|
||||
# SETTINGS #
|
||||
@@ -162,7 +173,7 @@ adminUserSettings.header=Настройки контроля пользоват
|
||||
adminUserSettings.admin=Администратор
|
||||
adminUserSettings.user=Пользователь
|
||||
adminUserSettings.addUser=Добавить нового пользователя
|
||||
adminUserSettings.usernameInfo=Имя пользователя должно содержать только буквы и цифры, без пробелов и специальных символов.
|
||||
adminUserSettings.usernameInfo=Имя пользователя может содержать только буквы, цифры и следующие специальные символы @._+- или должно быть действительным адресом электронной почты.
|
||||
adminUserSettings.roles=Роли
|
||||
adminUserSettings.role=Роль
|
||||
adminUserSettings.actions=Действия
|
||||
@@ -173,6 +184,8 @@ adminUserSettings.demoUser=Демо-пользователь (без настр
|
||||
adminUserSettings.internalApiUser=Внутренний пользователь API
|
||||
adminUserSettings.forceChange=Просить пользователя изменить пароль при входе в систему
|
||||
adminUserSettings.submit=Сохранить пользователя
|
||||
adminUserSettings.changeUserRole=Изменить роль пользователя
|
||||
adminUserSettings.authenticated=Authenticated
|
||||
|
||||
#############
|
||||
# HOME-PAGE #
|
||||
@@ -437,6 +450,8 @@ login.rememberme=Запомнить меня
|
||||
login.invalid=Недействительное имя пользователя или пароль.
|
||||
login.locked=Ваша учетная запись заблокирована.
|
||||
login.signinTitle=Пожалуйста, войдите
|
||||
login.ssoSignIn=Вход через единый вход
|
||||
login.oauth2AutoCreateDisabled=OAUTH2 Автоматическое создание пользователя отключено
|
||||
|
||||
|
||||
#auto-redact
|
||||
@@ -689,6 +704,7 @@ repair.submit=Ремонт
|
||||
#flatten
|
||||
flatten.title=Сглаживание
|
||||
flatten.header=Сглаживание PDF ов
|
||||
flatten.flattenOnlyForms=Flatten only forms
|
||||
flatten.submit=Сгладить
|
||||
|
||||
|
||||
@@ -736,6 +752,7 @@ extractImages.submit=Извлечь
|
||||
fileToPDF.title=Файл в PDF
|
||||
fileToPDF.header=Конвертировать любой файл в PDF
|
||||
fileToPDF.credit=Этот сервис использует LibreOffice и Unoconv для преобразования файлов.
|
||||
fileToPDF.supportedFileTypesInfo=Supported File types
|
||||
fileToPDF.supportedFileTypes=Поддерживаемые типы файлов должны включать приведенные ниже, однако полный обновленный список поддерживаемых форматов см. в документации LibreOffice.
|
||||
fileToPDF.submit=Преобразовать в PDF
|
||||
|
||||
@@ -788,7 +805,7 @@ pdfOrganiser.placeholder=(например, 1,3,2 или 4-8,2,10-12 или 2n-1
|
||||
#multiTool
|
||||
multiTool.title=Мультиинструмент PDF
|
||||
multiTool.header=Мультиинструмент PDF
|
||||
multiTool.uploadPrompts=Пожалуйста, загрузите PDF
|
||||
multiTool.uploadPrompts=File Name
|
||||
|
||||
#view pdf
|
||||
viewPdf.title=Просмотреть PDF
|
||||
@@ -1043,7 +1060,7 @@ licenses.version=Версия
|
||||
licenses.license=Лицензия
|
||||
|
||||
|
||||
# error
|
||||
#error
|
||||
error.sorry=Извините за проблему!
|
||||
error.needHelp=Нужна помощь / Нашли проблему?
|
||||
error.contactTip=Если у вас все еще есть проблемы, не стесняйтесь обращаться к нам за помощью. Вы можете отправить заявку на нашей странице GitHub или связаться с нами через Discord:
|
||||
|
||||
1075
src/main/resources/messages_sk_SK.properties
Normal file
@@ -54,9 +54,13 @@ notAuthenticatedMessage=Korisnik nije autentifikovan.
|
||||
userNotFoundMessage=Korisnik nije pronađen.
|
||||
incorrectPasswordMessage=Trenutna šifra je netačna.
|
||||
usernameExistsMessage=Novi korisnik već postoji
|
||||
invalidUsernameMessage=Invalid username, Username must only contain alphabet characters and numbers.
|
||||
invalidUsernameMessage=Invalid username, username can only contain letters, numbers and the following special characters @._+- or must be a valid email address.
|
||||
deleteCurrentUserMessage=Cannot delete currently logged in user.
|
||||
deleteUsernameExistsMessage=The username does not exist and cannot be deleted.
|
||||
downgradeCurrentUserMessage=Nije moguće degradirati ulogu trenutnog korisnika
|
||||
downgradeCurrentUserLongMessage=Nije moguće unazaditi ulogu trenutnog korisnika. Dakle, trenutni korisnik neće biti prikazan.
|
||||
userAlreadyExistsOAuthMessage=The user already exists as an OAuth2 user.
|
||||
userAlreadyExistsWebMessage=The user already exists as an web user.
|
||||
error=Error
|
||||
oops=Oops!
|
||||
help=Help
|
||||
@@ -67,6 +71,7 @@ visitGithub=Visit Github Repository
|
||||
donate=Donate
|
||||
color=Color
|
||||
sponsor=Sponsor
|
||||
info=Info
|
||||
|
||||
|
||||
|
||||
@@ -100,12 +105,18 @@ pipelineOptions.validateButton=Proveri
|
||||
#############
|
||||
# NAVBAR #
|
||||
#############
|
||||
navbar.convert=Konvertuj
|
||||
navbar.security=Bezbednost
|
||||
navbar.other=Razno
|
||||
navbar.favorite=Favorites
|
||||
navbar.darkmode=Tamni režim
|
||||
navbar.pageOps=Operacije stranice
|
||||
navbar.language=Languages
|
||||
navbar.settings=Podešavanja
|
||||
navbar.allTools=Tools
|
||||
navbar.multiTool=Multi Tools
|
||||
navbar.sections.organize=Organize
|
||||
navbar.sections.convertTo=Convert to PDF
|
||||
navbar.sections.convertFrom=Convert from PDF
|
||||
navbar.sections.security=Sign & Security
|
||||
navbar.sections.advance=Advanced
|
||||
navbar.sections.edit=View & Edit
|
||||
|
||||
#############
|
||||
# SETTINGS #
|
||||
@@ -162,7 +173,7 @@ adminUserSettings.header=Podešavanja kontrole korisnika za administratora
|
||||
adminUserSettings.admin=Administrator
|
||||
adminUserSettings.user=Korisnik
|
||||
adminUserSettings.addUser=Dodaj novog korisnika
|
||||
adminUserSettings.usernameInfo=Username must only contain letters and numbers, no spaces or special characters.
|
||||
adminUserSettings.usernameInfo=Username can only contain letters, numbers and the following special characters @._+- or must be a valid email address.
|
||||
adminUserSettings.roles=Uloge
|
||||
adminUserSettings.role=Uloga
|
||||
adminUserSettings.actions=Akcije
|
||||
@@ -173,6 +184,8 @@ adminUserSettings.demoUser=Demo korisnik (Bez prilagođenih podešavanja)
|
||||
adminUserSettings.internalApiUser=Internal API User
|
||||
adminUserSettings.forceChange=Prisili korisnika da promeni korisničko ime/lozinku pri prijavi
|
||||
adminUserSettings.submit=Sačuvaj korisnika
|
||||
adminUserSettings.changeUserRole=Promenite ulogu korisnika
|
||||
adminUserSettings.authenticated=Authenticated
|
||||
|
||||
#############
|
||||
# HOME-PAGE #
|
||||
@@ -437,6 +450,8 @@ login.rememberme=Zapamti me
|
||||
login.invalid=Neispravno korisničko ime ili lozinka.
|
||||
login.locked=Vaš nalog je zaključan.
|
||||
login.signinTitle=Molimo vas da se prijavite
|
||||
login.ssoSignIn=Prijavite se putem jedinstvene prijave
|
||||
login.oauth2AutoCreateDisabled=OAUTH2 automatsko kreiranje korisnika je onemogućeno
|
||||
|
||||
|
||||
#auto-redact
|
||||
@@ -689,6 +704,7 @@ repair.submit=Popravi
|
||||
#flatten
|
||||
flatten.title=Ravnanje
|
||||
flatten.header=Ravnanje PDF fajlova
|
||||
flatten.flattenOnlyForms=Flatten only forms
|
||||
flatten.submit=Ravnanje
|
||||
|
||||
|
||||
@@ -736,6 +752,7 @@ extractImages.submit=Izdvajanje
|
||||
fileToPDF.title=Fajl u PDF
|
||||
fileToPDF.header=Konvertuj bilo koji fajl u PDF
|
||||
fileToPDF.credit=Ova usluga koristi LibreOffice i Unoconv za konverziju fajla.
|
||||
fileToPDF.supportedFileTypesInfo=Supported File types
|
||||
fileToPDF.supportedFileTypes=Podržani tipovi fajlova bi trebali uključivati navedeno, ali za punu ažuriranu listu podržanih formata, molimo pogledajte LibreOffice dokumentaciju
|
||||
fileToPDF.submit=Konvertuj u PDF
|
||||
|
||||
@@ -788,7 +805,7 @@ pdfOrganiser.placeholder=(e.g. 1,3,2 or 4-8,2,10-12 or 2n-1)
|
||||
#multiTool
|
||||
multiTool.title=PDF Multi Alatka
|
||||
multiTool.header=PDF Multi Alatka
|
||||
multiTool.uploadPrompts=Please Upload PDF
|
||||
multiTool.uploadPrompts=File Name
|
||||
|
||||
#view pdf
|
||||
viewPdf.title=Prikaz
|
||||
@@ -1043,7 +1060,7 @@ licenses.version=Version
|
||||
licenses.license=License
|
||||
|
||||
|
||||
# error
|
||||
#error
|
||||
error.sorry=Sorry for the issue!
|
||||
error.needHelp=Need help / Found an issue?
|
||||
error.contactTip=If you're still having trouble, don't hesitate to reach out to us for help. You can submit a ticket on our GitHub page or contact us through Discord:
|
||||
|
||||
@@ -54,9 +54,13 @@ notAuthenticatedMessage=User not authenticated.
|
||||
userNotFoundMessage=User not found.
|
||||
incorrectPasswordMessage=Current password is incorrect.
|
||||
usernameExistsMessage=New Username already exists.
|
||||
invalidUsernameMessage=Invalid username, Username must only contain alphabet characters and numbers.
|
||||
invalidUsernameMessage=Invalid username, username can only contain letters, numbers and the following special characters @._+- or must be a valid email address.
|
||||
deleteCurrentUserMessage=Cannot delete currently logged in user.
|
||||
deleteUsernameExistsMessage=The username does not exist and cannot be deleted.
|
||||
downgradeCurrentUserMessage=Kan inte nedgradera nuvarande användares roll
|
||||
downgradeCurrentUserLongMessage=Kan inte nedgradera nuvarande användares roll. Därför kommer den aktuella användaren inte att visas.
|
||||
userAlreadyExistsOAuthMessage=The user already exists as an OAuth2 user.
|
||||
userAlreadyExistsWebMessage=The user already exists as an web user.
|
||||
error=Error
|
||||
oops=Oops!
|
||||
help=Help
|
||||
@@ -67,6 +71,7 @@ visitGithub=Visit Github Repository
|
||||
donate=Donate
|
||||
color=Color
|
||||
sponsor=Sponsor
|
||||
info=Info
|
||||
|
||||
|
||||
|
||||
@@ -100,12 +105,18 @@ pipelineOptions.validateButton=Validate
|
||||
#############
|
||||
# NAVBAR #
|
||||
#############
|
||||
navbar.convert=Konvertera
|
||||
navbar.security=Säkerhet
|
||||
navbar.other=Annat
|
||||
navbar.favorite=Favorites
|
||||
navbar.darkmode=Mörkt läge
|
||||
navbar.pageOps=Sidoperationer
|
||||
navbar.language=Languages
|
||||
navbar.settings=Inställningar
|
||||
navbar.allTools=Tools
|
||||
navbar.multiTool=Multi Tools
|
||||
navbar.sections.organize=Organize
|
||||
navbar.sections.convertTo=Convert to PDF
|
||||
navbar.sections.convertFrom=Convert from PDF
|
||||
navbar.sections.security=Sign & Security
|
||||
navbar.sections.advance=Advanced
|
||||
navbar.sections.edit=View & Edit
|
||||
|
||||
#############
|
||||
# SETTINGS #
|
||||
@@ -162,7 +173,7 @@ adminUserSettings.header=Admin User Control Settings
|
||||
adminUserSettings.admin=Admin
|
||||
adminUserSettings.user=User
|
||||
adminUserSettings.addUser=Add New User
|
||||
adminUserSettings.usernameInfo=Username must only contain letters and numbers, no spaces or special characters.
|
||||
adminUserSettings.usernameInfo=Username can only contain letters, numbers and the following special characters @._+- or must be a valid email address.
|
||||
adminUserSettings.roles=Roles
|
||||
adminUserSettings.role=Role
|
||||
adminUserSettings.actions=Actions
|
||||
@@ -173,6 +184,8 @@ adminUserSettings.demoUser=Demo User (No custom settings)
|
||||
adminUserSettings.internalApiUser=Internal API User
|
||||
adminUserSettings.forceChange=Force user to change password on login
|
||||
adminUserSettings.submit=Save User
|
||||
adminUserSettings.changeUserRole=Ändra användarens roll
|
||||
adminUserSettings.authenticated=Authenticated
|
||||
|
||||
#############
|
||||
# HOME-PAGE #
|
||||
@@ -437,6 +450,8 @@ login.rememberme=Remember me
|
||||
login.invalid=Invalid username or password.
|
||||
login.locked=Your account has been locked.
|
||||
login.signinTitle=Please sign in
|
||||
login.ssoSignIn=Logga in via enkel inloggning
|
||||
login.oauth2AutoCreateDisabled=OAUTH2 Auto-Create User inaktiverad
|
||||
|
||||
|
||||
#auto-redact
|
||||
@@ -689,6 +704,7 @@ repair.submit=Reparera
|
||||
#flatten
|
||||
flatten.title=Platta till
|
||||
flatten.header=Placera PDF-filer
|
||||
flatten.flattenOnlyForms=Flatten only forms
|
||||
flatten.submit=Platta till
|
||||
|
||||
|
||||
@@ -736,6 +752,7 @@ extractImages.submit=Extrahera
|
||||
fileToPDF.title=Fil till PDF
|
||||
fileToPDF.header=Konvertera valfri fil till PDF
|
||||
fileToPDF.credit=Denna tjänst använder LibreOffice och Unoconv för filkonvertering.
|
||||
fileToPDF.supportedFileTypesInfo=Supported File types
|
||||
fileToPDF.supportedFileTypes=Filtyper som stöds bör inkludera nedanstående men för en fullständig uppdaterad lista över format som stöds, se LibreOffice-dokumentationen
|
||||
fileToPDF.submit=Konvertera till PDF
|
||||
|
||||
@@ -788,7 +805,7 @@ pdfOrganiser.placeholder=(e.g. 1,3,2 or 4-8,2,10-12 or 2n-1)
|
||||
#multiTool
|
||||
multiTool.title=PDF-multiverktyg
|
||||
multiTool.header=PDF Multi-verktyg
|
||||
multiTool.uploadPrompts=Please Upload PDF
|
||||
multiTool.uploadPrompts=File Name
|
||||
|
||||
#view pdf
|
||||
viewPdf.title=View PDF
|
||||
@@ -1043,7 +1060,7 @@ licenses.version=Version
|
||||
licenses.license=License
|
||||
|
||||
|
||||
# error
|
||||
#error
|
||||
error.sorry=Sorry for the issue!
|
||||
error.needHelp=Need help / Found an issue?
|
||||
error.contactTip=If you're still having trouble, don't hesitate to reach out to us for help. You can submit a ticket on our GitHub page or contact us through Discord:
|
||||
|
||||
@@ -54,9 +54,13 @@ notAuthenticatedMessage=Kullanıcı doğrulanmadı.
|
||||
userNotFoundMessage=Kullanıcı bulunamadı.
|
||||
incorrectPasswordMessage=Mevcut şifre yanlış.
|
||||
usernameExistsMessage=Yeni Kullanıcı Adı zaten var.
|
||||
invalidUsernameMessage=Geçersiz kullanıcı adı, Kullanıcı adı yalnızca alfabe karakterleri ve sayılar içermelidir.
|
||||
invalidUsernameMessage=Geçersiz kullanıcı adı, kullanıcı adı yalnızca harf, rakam ve aşağıdaki özel karakterleri @._+- içerebilir veya geçerli bir e-posta adresi olmalıdır.
|
||||
deleteCurrentUserMessage=Şu anda oturum açmış olan kullanıcı silinemiyor.
|
||||
deleteUsernameExistsMessage=Kullanıcı adı mevcut değil ve silinemez.
|
||||
downgradeCurrentUserMessage=Mevcut kullanıcının rolü düşürülemiyor
|
||||
downgradeCurrentUserLongMessage=Mevcut kullanıcının rolü düşürülemiyor. Bu nedenle, mevcut kullanıcı gösterilmeyecektir.
|
||||
userAlreadyExistsOAuthMessage=The user already exists as an OAuth2 user.
|
||||
userAlreadyExistsWebMessage=The user already exists as an web user.
|
||||
error=Hata
|
||||
oops=Tüh!
|
||||
help=Yardım
|
||||
@@ -67,6 +71,7 @@ visitGithub=Github Deposunu Ziyaret Edin
|
||||
donate=Bağış Yapın
|
||||
color=Renk
|
||||
sponsor=Bağış
|
||||
info=Info
|
||||
|
||||
|
||||
|
||||
@@ -100,12 +105,18 @@ pipelineOptions.validateButton=Doğrula
|
||||
#############
|
||||
# NAVBAR #
|
||||
#############
|
||||
navbar.convert=Dönüştür
|
||||
navbar.security=Güvenlik
|
||||
navbar.other=Çeşitli
|
||||
navbar.favorite=Favorites
|
||||
navbar.darkmode=Karanlık Mod
|
||||
navbar.pageOps=Sayfa İşlemleri
|
||||
navbar.language=Languages
|
||||
navbar.settings=Ayarlar
|
||||
navbar.allTools=Tools
|
||||
navbar.multiTool=Multi Tools
|
||||
navbar.sections.organize=Organize
|
||||
navbar.sections.convertTo=Convert to PDF
|
||||
navbar.sections.convertFrom=Convert from PDF
|
||||
navbar.sections.security=Sign & Security
|
||||
navbar.sections.advance=Advanced
|
||||
navbar.sections.edit=View & Edit
|
||||
|
||||
#############
|
||||
# SETTINGS #
|
||||
@@ -162,7 +173,7 @@ adminUserSettings.header=Yönetici Kullanıcı Kontrol Ayarları
|
||||
adminUserSettings.admin=Yönetici
|
||||
adminUserSettings.user=Kullanıcı
|
||||
adminUserSettings.addUser=Yeni Kullanıcı Ekle
|
||||
adminUserSettings.usernameInfo=Kullanıcı adı yalnızca harf ve rakamlardan oluşmalı, boşluk veya özel karakter içermemelidir.
|
||||
adminUserSettings.usernameInfo=Kullanıcı adı yalnızca harf, rakam ve aşağıdaki özel karakterleri @._+- içerebilir veya geçerli bir e-posta adresi olmalıdır.
|
||||
adminUserSettings.roles=Roller
|
||||
adminUserSettings.role=Rol
|
||||
adminUserSettings.actions=Eylemler
|
||||
@@ -173,6 +184,8 @@ adminUserSettings.demoUser=Demo Kullanıcısı (Özel ayar yok)
|
||||
adminUserSettings.internalApiUser=Dahili API Kullanıcısı
|
||||
adminUserSettings.forceChange=Kullanıcının girişte kullanıcı adı/şifre değiştirmesini zorla
|
||||
adminUserSettings.submit=Kullanıcıyı Kaydet
|
||||
adminUserSettings.changeUserRole=Kullanıcı rolünü değiştir
|
||||
adminUserSettings.authenticated=Authenticated
|
||||
|
||||
#############
|
||||
# HOME-PAGE #
|
||||
@@ -437,6 +450,8 @@ login.rememberme=Beni hatırla
|
||||
login.invalid=Geçersiz kullanıcı adı veya şifre.
|
||||
login.locked=Hesabınız kilitlendi.
|
||||
login.signinTitle=Lütfen giriş yapınız.
|
||||
login.ssoSignIn=Tek Oturum Açma ile Giriş Yap
|
||||
login.oauth2AutoCreateDisabled=OAUTH2 Otomatik Oluşturma Kullanıcı Devre Dışı Bırakıldı
|
||||
|
||||
|
||||
#auto-redact
|
||||
@@ -689,6 +704,7 @@ repair.submit=Onar
|
||||
#flatten
|
||||
flatten.title=Düzleştir
|
||||
flatten.header=PDF'leri Düzleştir
|
||||
flatten.flattenOnlyForms=Flatten only forms
|
||||
flatten.submit=Düzleştir
|
||||
|
||||
|
||||
@@ -736,6 +752,7 @@ extractImages.submit=Çıkar
|
||||
fileToPDF.title=Dosyadan PDF'e
|
||||
fileToPDF.header=Herhangi bir dosyayı PDF'e dönüştür
|
||||
fileToPDF.credit=Bu hizmet dosya dönüşümü için LibreOffice ve Unoconv'u kullanır.
|
||||
fileToPDF.supportedFileTypesInfo=Supported File types
|
||||
fileToPDF.supportedFileTypes=Desteklenen dosya türleri aşağıdakileri içermelidir ancak desteklenen formatların tam güncellenmiş listesi için lütfen LibreOffice dokümantasyonuna başvurun
|
||||
fileToPDF.submit=PDF'e Dönüştür
|
||||
|
||||
@@ -788,7 +805,7 @@ pdfOrganiser.placeholder=(örn. 1,3,2 veya 4-8,2,10-12 veya 2n-1)
|
||||
#multiTool
|
||||
multiTool.title=PDF Çoklu Araç
|
||||
multiTool.header=PDF Çoklu Araç
|
||||
multiTool.uploadPrompts=Lütfen PDF Yükleyin
|
||||
multiTool.uploadPrompts=File Name
|
||||
|
||||
#view pdf
|
||||
viewPdf.title=PDF Görüntüle
|
||||
@@ -1043,7 +1060,7 @@ licenses.version=Versiyon
|
||||
licenses.license=Lisans
|
||||
|
||||
|
||||
# error
|
||||
#error
|
||||
error.sorry=Sorun için özür dileriz!
|
||||
error.needHelp=Yardıma mı ihtiyacınız var / Bir sorun mu buldunuz?
|
||||
error.contactTip=Hala sorun yaşıyorsanız, yardım için bize ulaşmaktan çekinmeyin. GitHub sayfamızdan bir bilet gönderebilir veya Discord üzerinden bizimle iletişime geçebilirsiniz:
|
||||
|
||||
@@ -54,9 +54,13 @@ notAuthenticatedMessage=Користувач не пройшов перевір
|
||||
userNotFoundMessage=Користувача не знайдено.
|
||||
incorrectPasswordMessage=Поточний пароль невірний.
|
||||
usernameExistsMessage=Нове ім'я користувача вже існує.
|
||||
invalidUsernameMessage=Недійсне ім'я користувача, Ім'я користувача повинно містити тільки літери алфавіту та цифри.
|
||||
invalidUsernameMessage=Недійсне ім’я користувача, ім’я користувача може містити лише літери, цифри та наступні спеціальні символи @._+- або має бути дійсною електронною адресою.
|
||||
deleteCurrentUserMessage=Неможливо видалити користувача, який увійшов в систему.
|
||||
deleteUsernameExistsMessage=Ім'я користувача не існує і не може бути видалено.
|
||||
downgradeCurrentUserMessage=Неможливо понизити роль поточного користувача
|
||||
downgradeCurrentUserLongMessage=Неможливо понизити роль поточного користувача. Отже, поточний користувач не відображатиметься.
|
||||
userAlreadyExistsOAuthMessage=The user already exists as an OAuth2 user.
|
||||
userAlreadyExistsWebMessage=The user already exists as an web user.
|
||||
error=Error
|
||||
oops=Oops!
|
||||
help=Help
|
||||
@@ -67,6 +71,7 @@ visitGithub=Visit Github Repository
|
||||
donate=Donate
|
||||
color=Color
|
||||
sponsor=Sponsor
|
||||
info=Info
|
||||
|
||||
|
||||
|
||||
@@ -100,12 +105,18 @@ pipelineOptions.validateButton=Перевірити
|
||||
#############
|
||||
# NAVBAR #
|
||||
#############
|
||||
navbar.convert=Конвертувати
|
||||
navbar.security=Безпека
|
||||
navbar.other=Інше
|
||||
navbar.favorite=Favorites
|
||||
navbar.darkmode=Темний режим
|
||||
navbar.pageOps=Операції зі сторінкою
|
||||
navbar.language=Languages
|
||||
navbar.settings=Налаштування
|
||||
navbar.allTools=Tools
|
||||
navbar.multiTool=Multi Tools
|
||||
navbar.sections.organize=Organize
|
||||
navbar.sections.convertTo=Convert to PDF
|
||||
navbar.sections.convertFrom=Convert from PDF
|
||||
navbar.sections.security=Sign & Security
|
||||
navbar.sections.advance=Advanced
|
||||
navbar.sections.edit=View & Edit
|
||||
|
||||
#############
|
||||
# SETTINGS #
|
||||
@@ -162,7 +173,7 @@ adminUserSettings.header=Налаштування контролю корист
|
||||
adminUserSettings.admin=Адміністратор
|
||||
adminUserSettings.user=Користувач
|
||||
adminUserSettings.addUser=Додати нового користувача
|
||||
adminUserSettings.usernameInfo=Ім'я користувача має містити тільки літери та цифри, без пробілів та спеціальних символів.
|
||||
adminUserSettings.usernameInfo=Ім’я користувача може містити лише літери, цифри та наступні спеціальні символи @._+- або має бути дійсною електронною адресою.
|
||||
adminUserSettings.roles=Ролі
|
||||
adminUserSettings.role=Роль
|
||||
adminUserSettings.actions=Дії
|
||||
@@ -173,6 +184,8 @@ adminUserSettings.demoUser=Демо-користувач (без налашто
|
||||
adminUserSettings.internalApiUser=Внутрішній користувач API
|
||||
adminUserSettings.forceChange=Примусити користувача змінити пароль при вході в систему
|
||||
adminUserSettings.submit=Зберегти користувача
|
||||
adminUserSettings.changeUserRole=Змінити роль користувача
|
||||
adminUserSettings.authenticated=Authenticated
|
||||
|
||||
#############
|
||||
# HOME-PAGE #
|
||||
@@ -437,6 +450,8 @@ login.rememberme=Запам'ятати мене
|
||||
login.invalid=Недійсне ім'я користувача або пароль.
|
||||
login.locked=Ваш обліковий запис заблоковано.
|
||||
login.signinTitle=Будь ласка, увійдіть
|
||||
login.ssoSignIn=Увійти через єдиний вхід
|
||||
login.oauth2AutoCreateDisabled=Автоматичне створення користувача OAUTH2 ВИМКНЕНО
|
||||
|
||||
|
||||
#auto-redact
|
||||
@@ -689,6 +704,7 @@ repair.submit=Ремонтувати
|
||||
#flatten
|
||||
flatten.title=Згладжування
|
||||
flatten.header=Згладжування PDF
|
||||
flatten.flattenOnlyForms=Flatten only forms
|
||||
flatten.submit=Згладити
|
||||
|
||||
|
||||
@@ -736,6 +752,7 @@ extractImages.submit=Витягнути
|
||||
fileToPDF.title=Файл у PDF
|
||||
fileToPDF.header=Конвертувати будь-який файл у PDF
|
||||
fileToPDF.credit=Цей сервіс використовує LibreOffice та Unoconv для перетворення файлів.
|
||||
fileToPDF.supportedFileTypesInfo=Supported File types
|
||||
fileToPDF.supportedFileTypes=Підтримувані типи файлів повинні включати нижченаведені, однак повний оновлений список підтримуваних форматів дивіться у документації LibreOffice.
|
||||
fileToPDF.submit=Перетворити у PDF
|
||||
|
||||
@@ -788,7 +805,7 @@ pdfOrganiser.placeholder=(наприклад, 1,3,2 або 4-8,2,10-12 або 2n
|
||||
#multiTool
|
||||
multiTool.title=Мультіінструмент PDF
|
||||
multiTool.header=Мультіінструмент PDF
|
||||
multiTool.uploadPrompts=Будь ласка, завантажте PDF
|
||||
multiTool.uploadPrompts=File Name
|
||||
|
||||
#view pdf
|
||||
viewPdf.title=Переглянути PDF
|
||||
@@ -1043,7 +1060,7 @@ licenses.version=Версія
|
||||
licenses.license=Ліцензія
|
||||
|
||||
|
||||
# error
|
||||
#error
|
||||
error.sorry=Вибачте за незручності!
|
||||
error.needHelp=Потрібна допомога / Знайшли проблему?
|
||||
error.contactTip=Якщо у вас досі виникають проблеми, не соромтеся звертатися до нас за допомогою. Ви можете надіслати запит на нашій сторінці GitHub або зв'язатися з нами через Discord:
|
||||
|
||||
@@ -54,9 +54,13 @@ notAuthenticatedMessage=用户未经过身份验证。
|
||||
userNotFoundMessage=未找到用户。
|
||||
incorrectPasswordMessage=当前密码不正确。
|
||||
usernameExistsMessage=新用户名已存在。
|
||||
invalidUsernameMessage=用户名无效,用户名只能由字母字符和数字组成。
|
||||
invalidUsernameMessage=用户名无效,用户名只能包含字母、数字和以下特殊字符@._+- 或必须是有效的电子邮件地址。
|
||||
deleteCurrentUserMessage=无法删除当前登录的用户。
|
||||
deleteUsernameExistsMessage=用户名不存在,无法删除。
|
||||
downgradeCurrentUserMessage=无法降级当前用户的角色
|
||||
downgradeCurrentUserLongMessage=无法降级当前用户的角色。因此,当前用户将不会显示。
|
||||
userAlreadyExistsOAuthMessage=The user already exists as an OAuth2 user.
|
||||
userAlreadyExistsWebMessage=The user already exists as an web user.
|
||||
error=错误
|
||||
oops=哎呀!
|
||||
help=帮助
|
||||
@@ -67,6 +71,7 @@ visitGithub=访问Github仓库
|
||||
donate=捐款
|
||||
color=颜色
|
||||
sponsor=赞助
|
||||
info=Info
|
||||
|
||||
|
||||
|
||||
@@ -100,12 +105,18 @@ pipelineOptions.validateButton=验证
|
||||
#############
|
||||
# NAVBAR #
|
||||
#############
|
||||
navbar.convert=转换
|
||||
navbar.security=安全
|
||||
navbar.other=其他
|
||||
navbar.favorite=Favorites
|
||||
navbar.darkmode=暗模式
|
||||
navbar.pageOps=页面操作
|
||||
navbar.language=Languages
|
||||
navbar.settings=设置
|
||||
navbar.allTools=Tools
|
||||
navbar.multiTool=Multi Tools
|
||||
navbar.sections.organize=Organize
|
||||
navbar.sections.convertTo=Convert to PDF
|
||||
navbar.sections.convertFrom=Convert from PDF
|
||||
navbar.sections.security=Sign & Security
|
||||
navbar.sections.advance=Advanced
|
||||
navbar.sections.edit=View & Edit
|
||||
|
||||
#############
|
||||
# SETTINGS #
|
||||
@@ -162,7 +173,7 @@ adminUserSettings.header=管理员用户控制设置
|
||||
adminUserSettings.admin=管理员
|
||||
adminUserSettings.user=用户
|
||||
adminUserSettings.addUser=添加新用户
|
||||
adminUserSettings.usernameInfo=用户名只能由字母和数字组成,不能包含空格或特殊字符。
|
||||
adminUserSettings.usernameInfo=用户名只能包含字母、数字和以下特殊字符@._+-,或者必须是有效的电子邮件地址。
|
||||
adminUserSettings.roles=角色
|
||||
adminUserSettings.role=角色
|
||||
adminUserSettings.actions=操作
|
||||
@@ -173,6 +184,8 @@ adminUserSettings.demoUser=演示用户(无自定义设置)
|
||||
adminUserSettings.internalApiUser=内部API用户
|
||||
adminUserSettings.forceChange=强制用户在登录时更改用户名/密码
|
||||
adminUserSettings.submit=保存用户
|
||||
adminUserSettings.changeUserRole=更改用户角色
|
||||
adminUserSettings.authenticated=Authenticated
|
||||
|
||||
#############
|
||||
# HOME-PAGE #
|
||||
@@ -437,6 +450,8 @@ login.rememberme=记住我
|
||||
login.invalid=用户名或密码无效。
|
||||
login.locked=您的账户已被锁定。
|
||||
login.signinTitle=请登录
|
||||
login.ssoSignIn=通过单点登录登录
|
||||
login.oauth2AutoCreateDisabled=OAUTH2自动创建用户已禁用
|
||||
|
||||
|
||||
#auto-redact
|
||||
@@ -689,6 +704,7 @@ repair.submit=修复
|
||||
#flatten
|
||||
flatten.title=展平
|
||||
flatten.header=展平 PDF
|
||||
flatten.flattenOnlyForms=Flatten only forms
|
||||
flatten.submit=展平
|
||||
|
||||
|
||||
@@ -736,6 +752,7 @@ extractImages.submit=提取
|
||||
fileToPDF.title=文件转换为PDF
|
||||
fileToPDF.header=将任何文件转换为PDF。
|
||||
fileToPDF.credit=此服务使用LibreOffice和Unoconv进行文件转换。
|
||||
fileToPDF.supportedFileTypesInfo=Supported File types
|
||||
fileToPDF.supportedFileTypes=支持的文件类型应该包括以下几种,但是,对于支持的格式的完整更新列表,请参考LibreOffice文档。
|
||||
fileToPDF.submit=转换为 PDF
|
||||
|
||||
@@ -788,7 +805,7 @@ pdfOrganiser.placeholder=(例如 1,3,2 或 4-8,2,10-12 或 2n-1)
|
||||
#multiTool
|
||||
multiTool.title=PDF多功能工具
|
||||
multiTool.header=PDF多功能工具
|
||||
multiTool.uploadPrompts=上传PDF
|
||||
multiTool.uploadPrompts=File Name
|
||||
|
||||
#view pdf
|
||||
viewPdf.title=浏览PDF
|
||||
@@ -1043,7 +1060,7 @@ licenses.version=版本
|
||||
licenses.license=许可证
|
||||
|
||||
|
||||
# error
|
||||
#error
|
||||
error.sorry=对此问题感到抱歉!
|
||||
error.needHelp=需要帮助 / 发现问题?
|
||||
error.contactTip=如果你仍然遇到问题,不要犹豫,向我们寻求帮助。你可以在我们的GitHub页面上提交工单,或者通过Discord与我们联系:
|
||||
|
||||
@@ -54,9 +54,13 @@ notAuthenticatedMessage=使用者未認證。
|
||||
userNotFoundMessage=找不到使用者。
|
||||
incorrectPasswordMessage=目前密碼不正確。
|
||||
usernameExistsMessage=新使用者名稱已存在。
|
||||
invalidUsernameMessage=使用者名無效,使用者名只能包含字母字元和數位。
|
||||
invalidUsernameMessage=使用者名稱無效,使用者名稱只能包含字母、數字和以下特殊字元@._+- 或必須是有效的電子郵件地址。
|
||||
deleteCurrentUserMessage=無法刪除目前登錄的使用者。
|
||||
deleteUsernameExistsMessage=使用者名不存在,無法刪除。
|
||||
downgradeCurrentUserMessage=無法降級目前使用者的角色
|
||||
downgradeCurrentUserLongMessage=無法降級目前使用者的角色。因此,不會顯示目前的使用者。
|
||||
userAlreadyExistsOAuthMessage=The user already exists as an OAuth2 user.
|
||||
userAlreadyExistsWebMessage=The user already exists as an web user.
|
||||
error=錯誤
|
||||
oops=哎呀!
|
||||
help=幫助
|
||||
@@ -67,6 +71,7 @@ visitGithub=訪問Github存儲庫
|
||||
donate=捐贈
|
||||
color=顏色
|
||||
sponsor=贊助
|
||||
info=Info
|
||||
|
||||
|
||||
|
||||
@@ -100,12 +105,18 @@ pipelineOptions.validateButton=驗證
|
||||
#############
|
||||
# NAVBAR #
|
||||
#############
|
||||
navbar.convert=轉換
|
||||
navbar.security=安全
|
||||
navbar.other=其他
|
||||
navbar.favorite=Favorites
|
||||
navbar.darkmode=暗黑模式
|
||||
navbar.pageOps=頁面操作
|
||||
navbar.language=Languages
|
||||
navbar.settings=設定
|
||||
navbar.allTools=Tools
|
||||
navbar.multiTool=Multi Tools
|
||||
navbar.sections.organize=Organize
|
||||
navbar.sections.convertTo=Convert to PDF
|
||||
navbar.sections.convertFrom=Convert from PDF
|
||||
navbar.sections.security=Sign & Security
|
||||
navbar.sections.advance=Advanced
|
||||
navbar.sections.edit=View & Edit
|
||||
|
||||
#############
|
||||
# SETTINGS #
|
||||
@@ -162,7 +173,7 @@ adminUserSettings.header=管理使用者控制設定
|
||||
adminUserSettings.admin=管理員
|
||||
adminUserSettings.user=使用者
|
||||
adminUserSettings.addUser=新增使用者
|
||||
adminUserSettings.usernameInfo=使用者名只能包含字母和數位,不能包含空格或特殊字元。
|
||||
adminUserSettings.usernameInfo=使用者名稱只能包含字母、數字和以下特殊字元@._+-,或必須是有效的電子郵件地址。
|
||||
adminUserSettings.roles=角色
|
||||
adminUserSettings.role=角色
|
||||
adminUserSettings.actions=操作
|
||||
@@ -173,6 +184,8 @@ adminUserSettings.demoUser=示範用途的使用者(無自訂設定)
|
||||
adminUserSettings.internalApiUser=內部 API 使用者
|
||||
adminUserSettings.forceChange=強制使用者在登入時修改使用者名稱/密碼
|
||||
adminUserSettings.submit=儲存
|
||||
adminUserSettings.changeUserRole=更改使用者身份
|
||||
adminUserSettings.authenticated=Authenticated
|
||||
|
||||
#############
|
||||
# HOME-PAGE #
|
||||
@@ -437,6 +450,8 @@ login.rememberme=記住我
|
||||
login.invalid=使用者名稱或密碼無效。
|
||||
login.locked=您的帳戶已被鎖定。
|
||||
login.signinTitle=請登入
|
||||
login.ssoSignIn=透過織網單一簽入
|
||||
login.oauth2AutoCreateDisabled=OAUTH2自動建立使用者已停用
|
||||
|
||||
|
||||
#auto-redact
|
||||
@@ -689,6 +704,7 @@ repair.submit=修復
|
||||
#flatten
|
||||
flatten.title=平坦化
|
||||
flatten.header=PDF 平坦化
|
||||
flatten.flattenOnlyForms=Flatten only forms
|
||||
flatten.submit=平坦化
|
||||
|
||||
|
||||
@@ -736,6 +752,7 @@ extractImages.submit=提取
|
||||
fileToPDF.title=檔案轉 PDF
|
||||
fileToPDF.header=將任何檔案轉換為 PDF
|
||||
fileToPDF.credit=此服務使用 LibreOffice 和 Unoconv 進行檔案轉換。
|
||||
fileToPDF.supportedFileTypesInfo=Supported File types
|
||||
fileToPDF.supportedFileTypes=支援的檔案類型應包括以下內容,但要獲得完整的更新支援格式列表,請參閱 LibreOffice 的文件
|
||||
fileToPDF.submit=轉換為 PDF
|
||||
|
||||
@@ -788,7 +805,7 @@ pdfOrganiser.placeholder=(例如 1,3,2 或 4-8,2,10-12 或 2n-1)
|
||||
#multiTool
|
||||
multiTool.title=PDF 多工具
|
||||
multiTool.header=PDF 多工具
|
||||
multiTool.uploadPrompts=Please Upload PDF
|
||||
multiTool.uploadPrompts=File Name
|
||||
|
||||
#view pdf
|
||||
viewPdf.title=檢視 PDF
|
||||
@@ -1043,7 +1060,7 @@ licenses.version=版本
|
||||
licenses.license=許可證
|
||||
|
||||
|
||||
# error
|
||||
#error
|
||||
error.sorry=對於這個問題,我們感到抱歉!
|
||||
error.needHelp=需要幫助/發現了一個問題?
|
||||
error.contactTip=如果你仍然遇到問題,請不要猶豫,隨時向我們尋求幫助。你可以在我們的GitHub頁面提交工單,或通過Discord與我們聯繋:
|
||||
|
||||
@@ -4,9 +4,21 @@
|
||||
|
||||
security:
|
||||
enableLogin: false # set to 'true' to enable login
|
||||
csrfDisabled: true
|
||||
csrfDisabled: true # Set to 'true' to disable CSRF protection (not recommended for production)
|
||||
loginAttemptCount: 5 # lock user account after 5 tries
|
||||
loginResetTimeMinutes : 120 # lock account for 2 hours after x attempts
|
||||
# initialLogin:
|
||||
# username: "admin" # Initial username for the first login
|
||||
# password: "stirling" # Initial password for the first login
|
||||
# oauth2:
|
||||
# enabled: false # set to 'true' to enable login (Note: enableLogin must also be 'true' for this to work)
|
||||
# issuer: "" # set to any provider that supports OpenID Connect Discovery (/.well-known/openid-configuration) end-point
|
||||
# clientId: "" # Client ID from your provider
|
||||
# clientSecret: "" # Client Secret from your provider
|
||||
# autoCreateUser: false # set to 'true' to allow auto-creation of non-existing users
|
||||
# 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'
|
||||
|
||||
system:
|
||||
defaultLocale: 'en-US' # Set the default language (e.g. 'de-DE', 'fr-FR', etc)
|
||||
@@ -14,12 +26,12 @@ system:
|
||||
enableAlphaFunctionality: false # Set to enable functionality which might need more testing before it fully goes live (This feature might make no changes)
|
||||
showUpdate: true # see when a new update is available
|
||||
showUpdateOnlyAdmin: false # Only admins can see when a new update is available, depending on showUpdate it must be set to 'true'
|
||||
customHTMLFiles: false # Enable to have files placed in /customFiles/templates override the existing template html files
|
||||
|
||||
#ui:
|
||||
# appName: exampleAppName # Application's visible name
|
||||
# homeDescription: I am a description # Short description or tagline shown on homepage.
|
||||
# appNameNavbar: navbarName # Name displayed on the navigation bar
|
||||
customHTMLFiles: false # enable to have files placed in /customFiles/templates override the existing template html files
|
||||
|
||||
ui:
|
||||
appName: null # Application's visible name
|
||||
homeDescription: null # Short description or tagline shown on homepage.
|
||||
appNameNavbar: null # Name displayed on the navigation bar
|
||||
|
||||
endpoints:
|
||||
toRemove: [] # List endpoints to disable (e.g. ['img-to-pdf', 'remove-pages'])
|
||||
@@ -27,3 +39,7 @@ endpoints:
|
||||
|
||||
metrics:
|
||||
enabled: true # 'true' to enable Info APIs (`/api/*`) endpoints, 'false' to disable
|
||||
|
||||
# Automatically Generated Settings (Do Not Edit Directly)
|
||||
AutomaticallyGenerated:
|
||||
key: example
|
||||
@@ -81,6 +81,13 @@
|
||||
"moduleLicense": "GNU Lesser General Public License v3 (LGPL-v3)",
|
||||
"moduleLicenseUrl": "http://www.gnu.org/licenses/lgpl-3.0.html"
|
||||
},
|
||||
{
|
||||
"moduleName": "com.github.stephenc.jcip:jcip-annotations",
|
||||
"moduleUrl": "http://stephenc.github.com/jcip-annotations",
|
||||
"moduleVersion": "1.0-1",
|
||||
"moduleLicense": "Apache License, Version 2.0",
|
||||
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||
},
|
||||
{
|
||||
"moduleName": "com.github.vladimir-bukhtoyarov:bucket4j-core",
|
||||
"moduleUrl": "http://github.com/vladimir-bukhtoyarov/bucket4j/bucket4j-core",
|
||||
@@ -109,6 +116,34 @@
|
||||
"moduleLicense": "LGPL",
|
||||
"moduleLicenseUrl": "http://www.martiansoftware.com/jsap/license.html"
|
||||
},
|
||||
{
|
||||
"moduleName": "com.nimbusds:content-type",
|
||||
"moduleUrl": "https://connect2id.com",
|
||||
"moduleVersion": "2.2",
|
||||
"moduleLicense": "The Apache Software License, Version 2.0",
|
||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||
},
|
||||
{
|
||||
"moduleName": "com.nimbusds:lang-tag",
|
||||
"moduleUrl": "https://connect2id.com/",
|
||||
"moduleVersion": "1.7",
|
||||
"moduleLicense": "The Apache Software License, Version 2.0",
|
||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||
},
|
||||
{
|
||||
"moduleName": "com.nimbusds:nimbus-jose-jwt",
|
||||
"moduleUrl": "https://connect2id.com",
|
||||
"moduleVersion": "9.24.4",
|
||||
"moduleLicense": "The Apache Software License, Version 2.0",
|
||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||
},
|
||||
{
|
||||
"moduleName": "com.nimbusds:oauth2-oidc-sdk",
|
||||
"moduleUrl": "https://bitbucket.org/connect2id/oauth-2.0-sdk-with-openid-connect-extensions",
|
||||
"moduleVersion": "9.43.3",
|
||||
"moduleLicense": "Apache License, version 2.0",
|
||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.html"
|
||||
},
|
||||
{
|
||||
"moduleName": "com.opencsv:opencsv",
|
||||
"moduleUrl": "http://opencsv.sf.net",
|
||||
@@ -335,6 +370,20 @@
|
||||
"moduleLicense": "Apache License, Version 2.0",
|
||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||
},
|
||||
{
|
||||
"moduleName": "net.minidev:accessors-smart",
|
||||
"moduleUrl": "https://urielch.github.io/",
|
||||
"moduleVersion": "2.5.0",
|
||||
"moduleLicense": "The Apache Software License, Version 2.0",
|
||||
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||
},
|
||||
{
|
||||
"moduleName": "net.minidev:json-smart",
|
||||
"moduleUrl": "https://urielch.github.io/",
|
||||
"moduleVersion": "2.5.0",
|
||||
"moduleLicense": "The Apache Software License, Version 2.0",
|
||||
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||
},
|
||||
{
|
||||
"moduleName": "org.antlr:antlr4-runtime",
|
||||
"moduleUrl": "https://www.antlr.org/",
|
||||
@@ -547,6 +596,13 @@
|
||||
"moduleLicense": "Public Domain, per Creative Commons CC0",
|
||||
"moduleLicenseUrl": "http://creativecommons.org/publicdomain/zero/1.0/"
|
||||
},
|
||||
{
|
||||
"moduleName": "org.ow2.asm:asm",
|
||||
"moduleUrl": "http://asm.ow2.org",
|
||||
"moduleVersion": "9.3",
|
||||
"moduleLicense": "The Apache Software License, Version 2.0",
|
||||
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||
},
|
||||
{
|
||||
"moduleName": "org.slf4j:jul-to-slf4j",
|
||||
"moduleUrl": "http://www.slf4j.org",
|
||||
@@ -663,6 +719,13 @@
|
||||
"moduleLicense": "Apache License, Version 2.0",
|
||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
||||
},
|
||||
{
|
||||
"moduleName": "org.springframework.boot:spring-boot-starter-oauth2-client",
|
||||
"moduleUrl": "https://spring.io/projects/spring-boot",
|
||||
"moduleVersion": "3.2.4",
|
||||
"moduleLicense": "Apache License, Version 2.0",
|
||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
||||
},
|
||||
{
|
||||
"moduleName": "org.springframework.boot:spring-boot-starter-security",
|
||||
"moduleUrl": "https://spring.io/projects/spring-boot",
|
||||
@@ -726,6 +789,27 @@
|
||||
"moduleLicense": "Apache License, Version 2.0",
|
||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
||||
},
|
||||
{
|
||||
"moduleName": "org.springframework.security:spring-security-oauth2-client",
|
||||
"moduleUrl": "https://spring.io/projects/spring-security",
|
||||
"moduleVersion": "6.2.3",
|
||||
"moduleLicense": "Apache License, Version 2.0",
|
||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
||||
},
|
||||
{
|
||||
"moduleName": "org.springframework.security:spring-security-oauth2-core",
|
||||
"moduleUrl": "https://spring.io/projects/spring-security",
|
||||
"moduleVersion": "6.2.3",
|
||||
"moduleLicense": "Apache License, Version 2.0",
|
||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
||||
},
|
||||
{
|
||||
"moduleName": "org.springframework.security:spring-security-oauth2-jose",
|
||||
"moduleUrl": "https://spring.io/projects/spring-security",
|
||||
"moduleVersion": "6.2.3",
|
||||
"moduleLicense": "Apache License, Version 2.0",
|
||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
||||
},
|
||||
{
|
||||
"moduleName": "org.springframework.security:spring-security-web",
|
||||
"moduleUrl": "https://spring.io/projects/spring-security",
|
||||
|
||||
@@ -1,141 +0,0 @@
|
||||
/* Dark Mode Styles */
|
||||
body,
|
||||
select,
|
||||
textarea {
|
||||
--body-background-color: 51, 51, 51;
|
||||
--base-font-color: 255, 255, 255;
|
||||
background-color: rgb(var(--body-background-color)) !important;
|
||||
color: rgb(var(--base-font-color)) !important;
|
||||
}
|
||||
.card {
|
||||
background-color: rgb(var(--body-background-color)) !important;
|
||||
border: 1px solid #999;
|
||||
color: rgb(var(--base-font-color)) !important;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #add8e6;
|
||||
}
|
||||
a:hover {
|
||||
color: #87ceeb; /* Slightly brighter blue on hover for accessibility */
|
||||
}
|
||||
|
||||
.dark-card {
|
||||
background-color: rgb(var(--body-background-color)) !important;
|
||||
color: rgb(var(--base-font-color)) !important;
|
||||
}
|
||||
.jumbotron {
|
||||
background-color: #222; /* or any other dark color */
|
||||
color: rgb(var(--base-font-color)) !important; /* or any other light color */
|
||||
}
|
||||
|
||||
.list-group {
|
||||
background-color: #222 !important;
|
||||
color: rgb(var(--base-font-color)) !important;
|
||||
}
|
||||
.list-group-item {
|
||||
background-color: #222 !important;
|
||||
color: rgb(var(--base-font-color)) !important;
|
||||
}
|
||||
#support-section {
|
||||
background-color: #444 !important;
|
||||
}
|
||||
|
||||
#pages-container-wrapper {
|
||||
--background-color: rgba(255, 255, 255, 0.046) !important;
|
||||
--scroll-bar-color: #4c4c4c !important;
|
||||
--scroll-bar-thumb: #d3d3d3 !important;
|
||||
--scroll-bar-thumb-hover: rgb(var(--base-font-color)) !important;
|
||||
}
|
||||
|
||||
.favorite-icon img {
|
||||
filter: brightness(0) invert(1) !important;
|
||||
}
|
||||
table thead {
|
||||
background-color: #333 !important;
|
||||
border: 1px solid #444;
|
||||
}
|
||||
table th,
|
||||
table td {
|
||||
border: 1px solid #444 !important;
|
||||
color: white;
|
||||
}
|
||||
.btn {
|
||||
background-color: #444 !important;
|
||||
border: none;
|
||||
color: #fff !important;
|
||||
}
|
||||
.btn-primary {
|
||||
background-color: #007bff !important;
|
||||
border: none;
|
||||
color: #fff !important;
|
||||
}
|
||||
.btn-secondary {
|
||||
background-color: #6c757d !important;
|
||||
border: none;
|
||||
color: #fff !important;
|
||||
}
|
||||
.btn-info {
|
||||
background-color: #17a2b8 !important;
|
||||
border: none;
|
||||
color: #fff !important;
|
||||
}
|
||||
.btn-danger {
|
||||
background-color: #dc3545 !important;
|
||||
border: none;
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
.btn-warning {
|
||||
background-color: #ffc107 !important;
|
||||
border: none;
|
||||
color: #000 !important;
|
||||
}
|
||||
|
||||
.btn-outline-secondary {
|
||||
color: #fff !important;
|
||||
border-color: #fff;
|
||||
}
|
||||
.btn-outline-secondary:hover {
|
||||
background-color: #444 !important;
|
||||
color: #007bff !important;
|
||||
border-color: #007bff;
|
||||
}
|
||||
.blackwhite-icon {
|
||||
filter: brightness(0) invert(1);
|
||||
}
|
||||
hr {
|
||||
border-color: rgba(255, 255, 255, 0.6); /* semi-transparent white */
|
||||
background-color: rgba(255, 255, 255, 0.6); /* for some browsers that might use background instead of border for <hr> */
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
color: #fff !important;
|
||||
border-color: #fff;
|
||||
}
|
||||
|
||||
.global-buttons-container input {
|
||||
background-color: #323948;
|
||||
caret-color: #ffffff;
|
||||
color: #ffffff;
|
||||
}
|
||||
.global-buttons-container input::placeholder {
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.global-buttons-container input:disabled::-webkit-input-placeholder {
|
||||
/* WebKit browsers */
|
||||
color: #6e6865;
|
||||
}
|
||||
.global-buttons-container input:disabled:-moz-placeholder {
|
||||
/* Mozilla Firefox 4 to 18 */
|
||||
color: #6e6865;
|
||||
}
|
||||
.global-buttons-container input:disabled::-moz-placeholder {
|
||||
/* Mozilla Firefox 19+ */
|
||||
color: #6e6865;
|
||||
}
|
||||
.global-buttons-container input:disabled:-ms-input-placeholder {
|
||||
/* Internet Explorer 10+ */
|
||||
color: #6e6865;
|
||||
}
|
||||
@@ -1,17 +1,8 @@
|
||||
h1 {
|
||||
text-align: center;
|
||||
margin-top: 10%;
|
||||
}
|
||||
|
||||
p {
|
||||
text-align: center;
|
||||
margin-top: 2em;
|
||||
}
|
||||
|
||||
.button:hover {
|
||||
background-color: #005b7f;
|
||||
}
|
||||
|
||||
.features-container {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(21rem, 3fr));
|
||||
@@ -31,58 +22,21 @@ p {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
#support-section {
|
||||
background-color: #f9f9f9;
|
||||
padding: 4rem;
|
||||
margin-top: 1rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#support-section h1 {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
#support-section p {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
#button-group {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
#home-button,
|
||||
#github-button,
|
||||
#discord-button {
|
||||
display: inline-block;
|
||||
padding: 1rem 2rem;
|
||||
margin: 1rem;
|
||||
background-color: #008cba;
|
||||
color: #fff;
|
||||
font-size: 1.2rem;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
border-radius: 3rem;
|
||||
transition: all 0.3s ease-in-out;
|
||||
}
|
||||
|
||||
#github-button:hover,
|
||||
#discord-button:hover,
|
||||
.home-button:hover {
|
||||
background-color: #005b7f;
|
||||
}
|
||||
|
||||
.home-button {
|
||||
display: block;
|
||||
width: 200px;
|
||||
height: 50px;
|
||||
margin: 2em auto;
|
||||
background-color: #008cba;
|
||||
color: white;
|
||||
text-align: center;
|
||||
line-height: 50px;
|
||||
text-decoration: none;
|
||||
font-weight: bold;
|
||||
border-radius: 25px;
|
||||
transition: all 0.3s ease-in-out;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
#errorContainer {
|
||||
margin: 20px; /* adjust this value as needed */
|
||||
margin: 1rem 0rem 2rem;
|
||||
border-radius: 3rem;
|
||||
}
|
||||
|
||||
#helpModalDialog {
|
||||
@@ -18,7 +19,7 @@
|
||||
}
|
||||
|
||||
#helpModal .button:hover {
|
||||
background-color: #005b7f;
|
||||
background-color: var(--md-sys-color-primary);
|
||||
}
|
||||
|
||||
#helpModal .features-container {
|
||||
@@ -40,58 +41,21 @@
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
#support-section {
|
||||
background-color: #f9f9f9;
|
||||
padding: 4rem;
|
||||
margin-top: 1rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#support-section h1 {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
#support-section p {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
#button-group {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
#home-button,
|
||||
#github-button,
|
||||
#discord-button {
|
||||
display: inline-block;
|
||||
padding: 1rem 2rem;
|
||||
margin: 1rem;
|
||||
background-color: #008cba;
|
||||
color: #fff;
|
||||
font-size: 1.2rem;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
border-radius: 3rem;
|
||||
transition: all 0.3s ease-in-out;
|
||||
}
|
||||
|
||||
#github-button:hover,
|
||||
#discord-button:hover,
|
||||
.home-button:hover {
|
||||
background-color: #005b7f;
|
||||
}
|
||||
|
||||
.home-button {
|
||||
display: block;
|
||||
width: 200px;
|
||||
height: 50px;
|
||||
margin: 2em auto;
|
||||
background-color: #008cba;
|
||||
color: white;
|
||||
text-align: center;
|
||||
line-height: 50px;
|
||||
text-decoration: none;
|
||||
font-weight: bold;
|
||||
border-radius: 25px;
|
||||
transition: all 0.3s ease-in-out;
|
||||
}
|
||||
}
|
||||
@@ -10,11 +10,15 @@
|
||||
display: flex;
|
||||
align-items: center; /* Center children horizontally */
|
||||
flex-grow: 1;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.footer-powered-by {
|
||||
margin-top: auto; /* Pushes the text to the bottom */
|
||||
color: grey;
|
||||
text-align: center; /* Centers the text inside the div */
|
||||
width: 100%; /* Full width to center the text properly */
|
||||
}
|
||||
|
||||
.footer-icon {
|
||||
font-size: 2rem;
|
||||
}
|
||||
@@ -1,18 +1,19 @@
|
||||
#searchBar {
|
||||
background-image: url("../images/search.svg");
|
||||
background-position: 16px 16px;
|
||||
background-repeat: no-repeat;
|
||||
color: var(--md-sys-color-on-surface);
|
||||
background-color: var(--md-sys-color-surface-container-low);
|
||||
width: 100%;
|
||||
font-size: 16px;
|
||||
margin-bottom: 12px;
|
||||
padding: 12px 20px 12px 40px;
|
||||
border: 1px solid #ddd;
|
||||
margin-bottom: 2rem;
|
||||
padding: 0.75rem 3.5rem;
|
||||
border: 0.1rem solid var(--md-sys-color-outline-variant);
|
||||
border-radius: 3rem;
|
||||
outline-color: var(--md-sys-color-outline-variant);
|
||||
}
|
||||
.dark-mode-search {
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' hei… 0 0-.115-.1zM12 6.5a5.5 5.5 0 1 1-11 0 5.5 5.5 0 0 1 11 0z'/%3E%3C/svg%3E") !important;
|
||||
color: #f8f9fa !important;
|
||||
background-color: #212529 !important;
|
||||
border-color: #343a40 !important;
|
||||
|
||||
.search-icon {
|
||||
position: absolute;
|
||||
margin: 0.75rem 1rem;
|
||||
border: 0.1rem solid transparent;
|
||||
}
|
||||
|
||||
.features-container {
|
||||
@@ -22,23 +23,23 @@
|
||||
}
|
||||
|
||||
.feature-card {
|
||||
border: 2px solid rgba(0, 0, 0, 0.25);
|
||||
border-radius: 0.25rem;
|
||||
border: 2px solid var(--md-sys-color-surface-5);
|
||||
border-radius: 2rem;
|
||||
padding: 1.25rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
background: rgba(13, 110, 253, 0.05);
|
||||
background: var(--md-sys-color-surface-5);
|
||||
transition:
|
||||
transform 0.3s,
|
||||
border 0.3s;
|
||||
transform-origin: center center;
|
||||
outline: 2px solid transparent;
|
||||
outline: 0px solid transparent;
|
||||
}
|
||||
|
||||
.feature-card a {
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
color: var(--md-sys-color-on-surface);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
@@ -50,44 +51,53 @@
|
||||
}
|
||||
|
||||
.feature-card:hover {
|
||||
outline: 1px solid rgba(0, 0, 0, 0.5);
|
||||
cursor: pointer;
|
||||
transform: scale(1.1);
|
||||
box-shadow: var(--md-sys-elevation-3);
|
||||
}
|
||||
|
||||
.feature-card:hover .card-title {
|
||||
text-decoration: underline;
|
||||
}
|
||||
.card-title.text-primary {
|
||||
color: #000; /* Replace with your desired shade of blue */
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.home-card-icon {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
width: 3rem;
|
||||
height: 3rem;
|
||||
transform: translateY(-5px);
|
||||
}
|
||||
.home-card-icon-colour {
|
||||
filter: invert(0.2) sepia(2) saturate(50) hue-rotate(190deg);
|
||||
}
|
||||
|
||||
.favorite-icon {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
color: var(--md-sys-color-secondary);
|
||||
}
|
||||
|
||||
#tool-icon {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#tool-text {
|
||||
margin: 0.5rem 0.5rem 0rem;
|
||||
}
|
||||
|
||||
.card-title {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
/* Only show the favorite icons when the parent card is being hovered over */
|
||||
.feature-card:hover .favorite-icon {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.favorite-icon img {
|
||||
filter: brightness(0);
|
||||
filter: brightness(0) invert(var(--md-theme-filter-color));
|
||||
}
|
||||
|
||||
.jumbotron {
|
||||
padding: 3rem 3rem; /* Reduce vertical padding */
|
||||
padding: 3rem 3rem;
|
||||
/* Reduce vertical padding */
|
||||
}
|
||||
|
||||
.lookatme {
|
||||
@@ -124,3 +134,21 @@
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.update-notice {
|
||||
animation: scale 1s infinite alternate;
|
||||
}
|
||||
|
||||
@keyframes scale {
|
||||
0% {
|
||||
transform: scale(0.96);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
.hidden {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
/* Dark Mode Styles */
|
||||
body {
|
||||
--body-background-color: 255, 255, 255;
|
||||
--base-font-color: 33, 37, 41;
|
||||
}
|
||||
|
||||
.global-buttons-container input {
|
||||
background-color: #ffffff;
|
||||
/*caret-color: #ffffff;*/
|
||||
/*color: #ffffff;*/
|
||||
}
|
||||
/*.global-buttons-container input:disabled::-webkit-input-placeholder { !* WebKit browsers *!*/
|
||||
/* color: #98A0AB;*/
|
||||
/*}*/
|
||||
/*.global-buttons-container input:disabled:-moz-placeholder { !* Mozilla Firefox 4 to 18 *!*/
|
||||
/* color: #98A0AB;*/
|
||||
/*}*/
|
||||
/*.global-buttons-container input:disabled::-moz-placeholder { !* Mozilla Firefox 19+ *!*/
|
||||
/* color: #98A0AB;*/
|
||||
/*}*/
|
||||
/*.global-buttons-container input:disabled:-ms-input-placeholder { !* Internet Explorer 10+ *!*/
|
||||
/* color: #98A0AB;*/
|
||||
/*}*/
|
||||
@@ -8,7 +8,6 @@ body {
|
||||
align-items: center;
|
||||
padding-top: 40px;
|
||||
padding-bottom: 40px;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
.form-signin {
|
||||
@@ -37,6 +36,7 @@ body {
|
||||
border-top-left-radius: 0;
|
||||
border-top-right-radius: 0;
|
||||
}
|
||||
|
||||
.container-flex {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -44,41 +44,22 @@ body {
|
||||
width: 100%; /* Set width to 100% */
|
||||
align-items: center; /* Center its children horizontally */
|
||||
}
|
||||
|
||||
.footer-bottom {
|
||||
margin-top: auto;
|
||||
}
|
||||
body.light-mode input:-webkit-autofill,
|
||||
body.light-mode input:-webkit-autofill:hover,
|
||||
body.light-mode input:-webkit-autofill:focus,
|
||||
body.light-mode input:-webkit-autofill:active {
|
||||
-webkit-text-fill-color: #212529; /* Dark font color */
|
||||
-webkit-box-shadow: 0 0 0 1000px #f8f9fa inset; /* Light background color */
|
||||
|
||||
.form-control {
|
||||
border-radius: 1.25rem !important;
|
||||
}
|
||||
|
||||
/* Dark Mode */
|
||||
body.dark-mode input:-webkit-autofill,
|
||||
body.dark-mode input:-webkit-autofill:hover,
|
||||
body.dark-mode input:-webkit-autofill:focus,
|
||||
body.dark-mode input:-webkit-autofill:active {
|
||||
-webkit-text-fill-color: #f8f9fa; /* Light font color */
|
||||
-webkit-box-shadow: 0 0 0 1000px #212529 inset; /* Dark background color */
|
||||
}
|
||||
/* Light Mode */
|
||||
body.light-mode .form-floating > input:focus + label {
|
||||
color: #212529 !important; /* Dark text for light background */
|
||||
.form-signin .form-floating {
|
||||
margin: 1rem 0px;
|
||||
}
|
||||
|
||||
/* Dark Mode */
|
||||
body.dark-mode .form-floating > input:focus + label {
|
||||
color: #fff !important; /* Light text for dark background */
|
||||
}
|
||||
|
||||
body.light-mode .form-floating > label {
|
||||
color: #212529 !important; /* Dark text for light background */
|
||||
}
|
||||
|
||||
body.dark-mode .form-floating > label {
|
||||
color: #fff !important; /* Light text for dark background */
|
||||
input[type="checkbox" i] {
|
||||
margin: 0px 5px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
/* Removing default styles for ul and li */
|
||||
|
||||
@@ -3,43 +3,80 @@
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.global-buttons-container {
|
||||
label {
|
||||
text-align: left;
|
||||
display: block;
|
||||
padding: 0rem 0.25rem;
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
|
||||
.form-control {
|
||||
border-radius: 16px !important;
|
||||
padding: 0.75rem;
|
||||
border: 1px solid var(--theme-color-outline-variant);
|
||||
}
|
||||
|
||||
.mt-action-bar {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
align-items: start;
|
||||
|
||||
background-color: rgba(13, 110, 253, 0.1);
|
||||
border: 1px solid rgba(0, 0, 0, 0.25);
|
||||
background-color: var(--md-sys-color-surface-5);
|
||||
border: none;
|
||||
backdrop-filter: blur(2px);
|
||||
|
||||
top: 10px;
|
||||
z-index: 10;
|
||||
padding: 10px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
.global-buttons-container > * {
|
||||
padding: 0.6rem 0.75rem;
|
||||
padding: 1.25rem;
|
||||
border-radius: 2rem;
|
||||
margin: 0px 25px;
|
||||
}
|
||||
|
||||
.global-buttons-container svg {
|
||||
.mt-action-bar>* {
|
||||
padding-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.mt-action-bar svg,
|
||||
.mt-action-btn svg {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
.mt-action-bar .mt-filename {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.mt-action-btn {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
align-items: start;
|
||||
top: 10px;
|
||||
z-index: 10;
|
||||
padding: 12px 0px 0px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.mt-action-btn .btn {
|
||||
width: 3rem;
|
||||
height: 3rem;
|
||||
border-radius: 20px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#export-button {
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.bg-card {
|
||||
background-color: var(--md-sys-color-surface-5);
|
||||
border-radius: 3rem;
|
||||
padding: 25px 0 0;
|
||||
}
|
||||
|
||||
#pages-container-wrapper {
|
||||
--background-color: rgba(0, 0, 0, 0.025);
|
||||
--scroll-bar-color: #f1f1f1;
|
||||
--scroll-bar-thumb: #888;
|
||||
--scroll-bar-thumb-hover: #555;
|
||||
background-color: var(--background-color);
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 10px 25px;
|
||||
border-radius: 10px;
|
||||
padding: 1rem;
|
||||
border-radius: 25px;
|
||||
overflow-y: hidden;
|
||||
overflow-x: auto;
|
||||
min-height: 275px;
|
||||
@@ -47,11 +84,11 @@
|
||||
}
|
||||
|
||||
#pages-container {
|
||||
margin: auto;
|
||||
gap: 0px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
margin-left: -15px;
|
||||
margin-right: -15px;
|
||||
}
|
||||
|
||||
/* width */
|
||||
@@ -86,6 +123,58 @@
|
||||
position: relative;
|
||||
user-select: none;
|
||||
transition: width 1s linear;
|
||||
margin-top: 16px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
/* Pushes the last item to the left */
|
||||
.page-container:last-child {
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.page-container:last-child:lang(ar),
|
||||
/* Arabic */
|
||||
.page-container:last-child:lang(he),
|
||||
/* Hebrew */
|
||||
.page-container:last-child:lang(fa),
|
||||
/* Persian */
|
||||
.page-container:last-child:lang(ur),
|
||||
/* Urdu */
|
||||
.page-container:last-child:lang(ckb),
|
||||
/* Sorani Kurdish */
|
||||
.page-container:last-child:lang(ks),
|
||||
/* Kashmiri */
|
||||
.page-container:last-child:lang(kk),
|
||||
/* Kazakh */
|
||||
.page-container:last-child:lang(uz),
|
||||
/* Uzbek */
|
||||
.page-container:last-child:lang(ky),
|
||||
/* Kyrgyz */
|
||||
.page-container:last-child:lang(bal),
|
||||
/* Baluchi */
|
||||
.page-container:last-child:lang(dv),
|
||||
/* Divehi */
|
||||
.page-container:last-child:lang(ps),
|
||||
/* Pashto */
|
||||
.page-container:last-child:lang(sdg),
|
||||
/* Southern Kurdish */
|
||||
.page-container:last-child:lang(syr),
|
||||
/* Syriac */
|
||||
.page-container:last-child:lang(mzn),
|
||||
/* Mazanderani */
|
||||
.page-container:last-child:lang(tgl),
|
||||
/* Tagalog */
|
||||
.page-container:last-child:lang(pnb),
|
||||
/* Western Punjabi */
|
||||
.page-container:last-child:lang(ug),
|
||||
/* Uyghur */
|
||||
.page-container:last-child:lang(nqo),
|
||||
/* N'Ko */
|
||||
.page-container:last-child:lang(bqi)
|
||||
/* Bakhtiari */
|
||||
{
|
||||
margin-left: auto !important;
|
||||
margin-right: 0 !important;
|
||||
}
|
||||
|
||||
.page-container img {
|
||||
@@ -109,11 +198,15 @@
|
||||
.page-number {
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
right: 5px;
|
||||
color: white;
|
||||
background-color: #007bff; /* Primary blue color */
|
||||
padding: 3px 6px;
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
right: 0px;
|
||||
color: var(--md-sys-color-on-surface);
|
||||
background-color: var(--md-sys-color-surface-5);
|
||||
padding: 6px 8px;
|
||||
border-radius: 8px;
|
||||
font-size: 16px;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.tool-header {
|
||||
margin: 0.5rem 1rem 2rem;
|
||||
}
|
||||
@@ -7,28 +7,18 @@
|
||||
}
|
||||
|
||||
#navbarSearch.show {
|
||||
max-height: 300px; /* Adjust this to your desired max height */
|
||||
}
|
||||
|
||||
#searchForm {
|
||||
width: 200px; /* Adjust this value as needed */
|
||||
}
|
||||
|
||||
/* Style the search results to match the navbar */
|
||||
#searchResults {
|
||||
max-height: 200px; /* Adjust this value as needed */
|
||||
overflow-y: auto;
|
||||
width: 100%;
|
||||
max-width: 300px; /* Adjust to your preferred width */
|
||||
transition: height 0.3s ease; /* Smooth height transition */
|
||||
max-height: 300px;
|
||||
/* Adjust this to your desired max height */
|
||||
}
|
||||
|
||||
#searchResults .dropdown-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
white-space: nowrap;
|
||||
height: 50px; /* Fixed height */
|
||||
overflow: hidden; /* Hide overflow */
|
||||
height: 50px;
|
||||
/* Fixed height */
|
||||
overflow: hidden;
|
||||
/* Hide overflow */
|
||||
}
|
||||
|
||||
#searchResults .icon {
|
||||
@@ -37,40 +27,34 @@
|
||||
|
||||
#searchResults .icon-text {
|
||||
display: inline;
|
||||
overflow: hidden; /* Hide overflow */
|
||||
text-overflow: ellipsis; /* Add ellipsis for long text */
|
||||
overflow: hidden;
|
||||
/* Hide overflow */
|
||||
text-overflow: ellipsis;
|
||||
/* Add ellipsis for long text */
|
||||
}
|
||||
|
||||
#search-icon i {
|
||||
font-size: 24px; /* Adjust this to your desired size */
|
||||
font-size: 24px;
|
||||
/* Adjust this to your desired size */
|
||||
transition: color 0.3s;
|
||||
}
|
||||
|
||||
#search-icon:hover i {
|
||||
color: #666; /* Adjust this to your hover color */
|
||||
color: #666;
|
||||
/* Adjust this to your hover color */
|
||||
}
|
||||
|
||||
.search-input {
|
||||
transition:
|
||||
border 0.3s,
|
||||
box-shadow 0.3s;
|
||||
transition: border 0.3s, box-shadow 0.3s;
|
||||
}
|
||||
|
||||
.search-input:focus {
|
||||
border-color: #666; /* Adjust this to your focus color */
|
||||
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); /* Adjust this to your desired shadow */
|
||||
border-color: #666;
|
||||
/* Adjust this to your focus color */
|
||||
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
||||
/* Adjust this to your desired shadow */
|
||||
}
|
||||
|
||||
/* Set a fixed height and styling for each search result item */
|
||||
.search-results a {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px; /* space between icon and text */
|
||||
height: 40px; /* Adjust based on your design */
|
||||
overflow: hidden; /* Prevent content from overflowing */
|
||||
white-space: nowrap; /* Prevent text from wrapping to next line */
|
||||
text-overflow: ellipsis; /* Truncate text if it's too long */
|
||||
}
|
||||
|
||||
.main-icon {
|
||||
width: 36px;
|
||||
@@ -79,34 +63,59 @@
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
.nav-icon {
|
||||
vertical-align: middle;
|
||||
transform: translateY(-2px);
|
||||
font-size: 2rem !important;
|
||||
padding: 0.25rem;
|
||||
border-radius: 1rem;
|
||||
}
|
||||
|
||||
.icon + .icon {
|
||||
.icon+.icon {
|
||||
margin-left: -4px;
|
||||
}
|
||||
|
||||
.icon-text {
|
||||
margin-left: 4px;
|
||||
margin-right: 4px;
|
||||
display: inline-flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.dropdown-item .icon-text {
|
||||
text-wrap: wrap;
|
||||
word-break: break-word;
|
||||
width: 80%;
|
||||
}
|
||||
|
||||
span.icon-text::after {
|
||||
content: attr(data-text);
|
||||
content: attr(data-text) / "";
|
||||
font-weight: 600;
|
||||
height: 0;
|
||||
visibility: hidden;
|
||||
overflow: hidden;
|
||||
user-select: none;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.nav-item-separator {
|
||||
position: relative;
|
||||
margin: 0 4px; /* Adjust the margin as needed */
|
||||
margin: 0 4px;
|
||||
/* Adjust the margin as needed */
|
||||
}
|
||||
|
||||
.nav-item-separator::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 10%; /* Adjust the top and bottom margins as needed */
|
||||
top: 10%;
|
||||
/* Adjust the top and bottom margins as needed */
|
||||
bottom: 10%;
|
||||
width: 1px;
|
||||
background-color: #ccc; /* Adjust the color as needed */
|
||||
background-color: #ccc;
|
||||
/* Adjust the color as needed */
|
||||
}
|
||||
|
||||
.navbar-icon {
|
||||
@@ -114,3 +123,170 @@
|
||||
height: 20px;
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.navbar-toggler {
|
||||
color: var(--md-sys-color-on-surface-variant);
|
||||
}
|
||||
|
||||
.dropdown-menu.scrollable-y {
|
||||
overflow-y: scroll;
|
||||
height: 360px;
|
||||
}
|
||||
|
||||
/* Dropdown Scrollbar*/
|
||||
.scrollable-y {
|
||||
overflow-y: scroll;
|
||||
height: 360px;
|
||||
}
|
||||
|
||||
.scrollable-y::-webkit-scrollbar {
|
||||
background: transparent;
|
||||
width: 0.7rem;
|
||||
}
|
||||
|
||||
.scrollable-y::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.scrollable-y::-webkit-scrollbar-thumb {
|
||||
border-radius: 2rem;
|
||||
background-color: var(--md-sys-color-surface-5);
|
||||
border: 3px solid var(--md-sys-color-surface-5);
|
||||
}
|
||||
|
||||
/* Mega Menu */
|
||||
.dropdown-mega .dropdown-menu {
|
||||
width: 98%;
|
||||
}
|
||||
|
||||
.dropdown-mega .title {
|
||||
padding-bottom: 1rem;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.dropdown-menu .list-group {
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.mega-content .dropdown-item:focus .nav-icon,
|
||||
.mega-content .dropdown-item:hover .nav-icon,
|
||||
.mega-content .dropdown-item.active .nav-icon {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.dropdown-item:focus.sign,
|
||||
.dropdown-item:hover.sign,
|
||||
.dropdown-item.active.sign {
|
||||
color: var(--md-nav-on-section-color-sign);
|
||||
background-color: var(--md-nav-section-color-sign);
|
||||
}
|
||||
|
||||
.dropdown-item:focus.organize,
|
||||
.dropdown-item:hover.organize,
|
||||
.dropdown-item.active.organize {
|
||||
color: var(--md-nav-on-section-color-organize);
|
||||
background-color: var(--md-nav-section-color-organize);
|
||||
}
|
||||
|
||||
.dropdown-item:focus.convert,
|
||||
.dropdown-item:hover.convert,
|
||||
.dropdown-item.active.convert {
|
||||
color: var(--md-nav-on-section-color-convert);
|
||||
background-color: var(--md-nav-section-color-convert);
|
||||
}
|
||||
|
||||
.dropdown-item:focus.image,
|
||||
.dropdown-item:hover.image,
|
||||
.dropdown-item.active.image {
|
||||
color: var(--md-nav-on-section-color-image);
|
||||
background-color: var(--md-nav-section-color-image);
|
||||
}
|
||||
|
||||
.dropdown-item:focus.word,
|
||||
.dropdown-item:hover.word,
|
||||
.dropdown-item.active.word {
|
||||
color: var(--md-nav-on-section-color-word);
|
||||
background-color: var(--md-nav-section-color-word);
|
||||
}
|
||||
|
||||
.dropdown-item:focus.ppt,
|
||||
.dropdown-item:hover.ppt,
|
||||
.dropdown-item.active.ppt {
|
||||
color: var(--md-nav-on-section-color-ppt);
|
||||
background-color: var(--md-nav-section-color-ppt);
|
||||
}
|
||||
|
||||
.dropdown-item:focus.security,
|
||||
.dropdown-item:hover.security,
|
||||
.dropdown-item.active.security {
|
||||
color: var(--md-nav-on-section-color-security);
|
||||
background-color: var(--md-nav-section-color-security);
|
||||
}
|
||||
|
||||
.dropdown-item:focus.other,
|
||||
.dropdown-item:hover.other,
|
||||
.dropdown-item.active.other {
|
||||
color: var(--md-nav-on-section-color-other);
|
||||
background-color: var(--md-nav-section-color-other);
|
||||
}
|
||||
|
||||
.dropdown-item:focus.advance,
|
||||
.dropdown-item:hover.advance,
|
||||
.dropdown-item.active.advance {
|
||||
color: var(--md-nav-on-section-color-advance);
|
||||
background-color: var(--md-nav-section-color-advance);
|
||||
}
|
||||
|
||||
/* Dropdown min-width */
|
||||
.dropdown-mw-28 {
|
||||
min-width: 280px;
|
||||
}
|
||||
|
||||
.dropdown-mw-20 {
|
||||
min-width: 200px;
|
||||
}
|
||||
|
||||
/* Dropdown open on hover */
|
||||
.dropdown-menu {
|
||||
padding-top: 0.5rem;
|
||||
top: auto;
|
||||
left: auto;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.dropdown-menu[data-bs-popper] {
|
||||
top: auto;
|
||||
left: auto;
|
||||
right: 0;
|
||||
margin-top: 0 !important;
|
||||
}
|
||||
|
||||
.dropdown-menu-wrapper {
|
||||
padding: 1.5rem 0;
|
||||
border-radius: 1rem;
|
||||
color: var(--md-sys-color-on-surface);
|
||||
background-color: var(--md-sys-color-surface-container);
|
||||
border: 1px solid var(--md-sys-color-surface-5);
|
||||
box-shadow: var(--md-sys-elevation-2);
|
||||
}
|
||||
|
||||
.dropdown-menu-tp {
|
||||
color: transparent;
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.icon-hide {
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
@media (min-width:992px) {
|
||||
.dropdown:hover .dropdown-menu {
|
||||
display: block;
|
||||
margin-top: 0;
|
||||
}
|
||||
.icon-hide {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
@@ -9,19 +9,33 @@
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.pdf-actions_button-container > * {
|
||||
.pdf-actions_button-container>* {
|
||||
padding: 0.25rem 0.5rem;
|
||||
margin: 3px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.pdf-actions_button-container>*:focus {
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
.pdf-actions_button-container .btn {
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
.pdf-actions_button-container> :first-child,
|
||||
.pdf-actions_container:first-child>.pdf-actions_button-container> :first-child+* {
|
||||
border-radius: 12px 0px 0px 12px;
|
||||
}
|
||||
|
||||
.pdf-actions_container svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.pdf-actions_container:nth-child(1) .pdf-actions_move-left-button {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.pdf-actions_container:last-child .pdf-actions_move-right-button {
|
||||
display: none;
|
||||
}
|
||||
@@ -37,6 +51,25 @@
|
||||
transition: opacity 0.2s;
|
||||
}
|
||||
|
||||
.pdf-actions_insert-file-button-container button .material-symbols-rounded {
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.pdf-actions_insert-file-button-container.left button,
|
||||
.pdf-actions_insert-file-button-container.right button {
|
||||
padding: 0.45rem;
|
||||
}
|
||||
|
||||
.pdf-actions_button-container button .material-symbols-rounded {
|
||||
font-size: 1.25rem;
|
||||
vertical-align: sub;
|
||||
}
|
||||
|
||||
.pdf-actions_insert-file-button {
|
||||
padding: 0;
|
||||
vertical-align: sub;
|
||||
}
|
||||
|
||||
.pdf-actions_insert-file-button-container.left {
|
||||
left: -20px;
|
||||
}
|
||||
@@ -63,11 +96,11 @@ html[dir="rtl"] .pdf-actions_insert-file-button-container.left {
|
||||
translate: 0 -50%;
|
||||
}
|
||||
|
||||
html[dir="ltr"] .pdf-actions_container:last-child > .pdf-actions_insert-file-button-container.right {
|
||||
html[dir="ltr"] .pdf-actions_container:last-child>.pdf-actions_insert-file-button-container.right {
|
||||
display: block;
|
||||
}
|
||||
|
||||
html[dir="rtl"] .pdf-actions_container:last-child > .pdf-actions_insert-file-button-container.left {
|
||||
html[dir="rtl"] .pdf-actions_container:last-child>.pdf-actions_insert-file-button-container.left {
|
||||
display: block;
|
||||
}
|
||||
|
||||
@@ -75,6 +108,7 @@ html[dir="rtl"] .pdf-actions_container:last-child > .pdf-actions_insert-file-but
|
||||
opacity: 1;
|
||||
transition: opacity 0.05s;
|
||||
}
|
||||
|
||||
.pdf-actions_insert-file-button {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
@@ -82,4 +116,4 @@ html[dir="rtl"] .pdf-actions_container:last-child > .pdf-actions_insert-file-but
|
||||
translate: 50% -50%;
|
||||
aspect-ratio: 1;
|
||||
border-radius: 100px;
|
||||
}
|
||||
}
|
||||
@@ -4,18 +4,23 @@
|
||||
|
||||
.bordered-box {
|
||||
border: 1px solid #ddd;
|
||||
padding: 20px;
|
||||
margin: 20px;
|
||||
padding: 2rem;
|
||||
margin: 2rem;
|
||||
width: 70%;
|
||||
}
|
||||
|
||||
.center-element {
|
||||
width: 80%;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
margin: auto;
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
.element-margin {
|
||||
margin: 10px 0;
|
||||
margin: 1rem 0;
|
||||
/* Adjust this value to increase/decrease the margin as needed */
|
||||
}
|
||||
|
||||
#pipelineList {
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
917
src/main/resources/static/css/theme/componentes.css
Normal file
@@ -0,0 +1,917 @@
|
||||
/* Dark Mode Styles */
|
||||
body,
|
||||
select,
|
||||
textarea {
|
||||
background-color: var(--md-sys-color-surface);
|
||||
color: var(--md-sys-color-on-surface);
|
||||
}
|
||||
|
||||
.transition-theme {
|
||||
transition: background 0.5s ease, color 0.5s ease, border 0.5s ease;
|
||||
}
|
||||
|
||||
|
||||
/*.global-buttons-container input:disabled::-webkit-input-placeholder { !* WebKit browsers *!*/
|
||||
/* color: #98A0AB;*/
|
||||
/*}*/
|
||||
/*.global-buttons-container input:disabled:-moz-placeholder { !* Mozilla Firefox 4 to 18 *!*/
|
||||
/* color: #98A0AB;*/
|
||||
/*}*/
|
||||
/*.global-buttons-container input:disabled::-moz-placeholder { !* Mozilla Firefox 19+ *!*/
|
||||
/* color: #98A0AB;*/
|
||||
/*}*/
|
||||
/*.global-buttons-container input:disabled:-ms-input-placeholder { !* Internet Explorer 10+ *!*/
|
||||
/* color: #98A0AB;*/
|
||||
/*}*/
|
||||
/* Scrollbar */
|
||||
*::-webkit-scrollbar {
|
||||
background: var(--md-sys-color-surface);
|
||||
width: 1rem;
|
||||
}
|
||||
|
||||
*::-webkit-scrollbar-track {
|
||||
background: var(--md-sys-color-surface);
|
||||
}
|
||||
|
||||
*::-webkit-scrollbar-thumb {
|
||||
border-radius: 2rem;
|
||||
background-color: var(--md-sys-color-surface-5);
|
||||
border: 5px solid var(--md-sys-color-surface-5);
|
||||
}
|
||||
|
||||
/* Alerts */
|
||||
.alert {
|
||||
border-radius: 3rem;
|
||||
}
|
||||
|
||||
/* Table */
|
||||
td {
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.input-group-append {
|
||||
margin: 0rem 0.5rem !important;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
background-color: transparent;
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.bg-card {
|
||||
background-color: var(--md-sys-color-surface-5);
|
||||
border-radius: 3rem;
|
||||
padding: 2.5rem;
|
||||
}
|
||||
|
||||
.card {
|
||||
padding: 1.25rem;
|
||||
border-radius: 2rem;
|
||||
background-color: var(--md-sys-color-surface-5);
|
||||
border: none;
|
||||
}
|
||||
|
||||
/* Modal */
|
||||
.modal-content {
|
||||
background-color: var(--md-sys-color-surface);
|
||||
border-radius: 2rem;
|
||||
border: transparent;
|
||||
}
|
||||
|
||||
.modal-header,
|
||||
.modal-body,
|
||||
.modal-footer {
|
||||
background-color: var(--md-sys-color-surface-5);
|
||||
padding: 1.5rem 2rem;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.modal-header {
|
||||
border-radius: 2rem 2rem 0rem 0rem;
|
||||
}
|
||||
|
||||
.modal-footer {
|
||||
border-radius: 0rem 0rem 2rem 2rem;
|
||||
}
|
||||
|
||||
/* Icon fill */
|
||||
.material-symbols-rounded {
|
||||
vertical-align: text-top;
|
||||
}
|
||||
|
||||
/* Navbar Icon*/
|
||||
.nav-icon {
|
||||
color: var(--md-sys-color-surface);
|
||||
}
|
||||
|
||||
.sign .nav-icon,
|
||||
.sign.tool-header-icon {
|
||||
color: var(--md-nav-on-section-color-sign);
|
||||
background-color: var(--md-nav-section-color-sign);
|
||||
}
|
||||
|
||||
.organize .nav-icon,
|
||||
.organize.tool-header-icon {
|
||||
color: var(--md-nav-on-section-color-organize);
|
||||
background-color: var(--md-nav-section-color-organize);
|
||||
}
|
||||
|
||||
.convert .nav-icon,
|
||||
.convert.tool-header-icon {
|
||||
color: var(--md-nav-on-section-color-convert);
|
||||
background-color: var(--md-nav-section-color-convert);
|
||||
}
|
||||
|
||||
.security .nav-icon,
|
||||
.security.tool-header-icon {
|
||||
color: var(--md-nav-on-section-color-security);
|
||||
background-color: var(--md-nav-section-color-security);
|
||||
}
|
||||
|
||||
.other .nav-icon,
|
||||
.other.tool-header-icon {
|
||||
color: var(--md-nav-on-section-color-other);
|
||||
background-color: var(--md-nav-section-color-other);
|
||||
}
|
||||
|
||||
.advance .nav-icon,
|
||||
.advance.tool-header-icon {
|
||||
color: var(--md-nav-on-section-color-advance);
|
||||
background-color: var(--md-nav-section-color-advance);
|
||||
}
|
||||
|
||||
.image .nav-icon,
|
||||
.image.tool-header-icon {
|
||||
color: var(--md-nav-on-section-color-image);
|
||||
background-color: var(--md-nav-section-color-image);
|
||||
}
|
||||
|
||||
.word .nav-icon,
|
||||
.word.tool-header-icon {
|
||||
color: var(--md-nav-on-section-color-word);
|
||||
background-color: var(--md-nav-section-color-word);
|
||||
}
|
||||
|
||||
.ppt .nav-icon,
|
||||
.ppt.tool-header-icon {
|
||||
color: var(--md-nav-on-section-color-ppt);
|
||||
background-color: var(--md-nav-section-color-ppt);
|
||||
}
|
||||
|
||||
/* Tool Page Header*/
|
||||
.tool-header {
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.tool-header .tool-header-icon {
|
||||
margin: 0px 1rem;
|
||||
height: 4rem;
|
||||
width: 4rem;
|
||||
border-radius: 25px;
|
||||
font-size: 3rem;
|
||||
padding: 0.5rem;
|
||||
vertical-align: middle;
|
||||
pointer-events: none;
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
-webkit-tap-highlight-color: rgb(0 0 0 / 0%);
|
||||
}
|
||||
|
||||
.tool-header .tool-header-text {
|
||||
font-size: 2.5rem;
|
||||
font-weight: 400;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
/* Home Card Colors*/
|
||||
.feature-card .nav-icon {
|
||||
vertical-align: middle;
|
||||
font-size: 2rem !important;
|
||||
padding: 0.5rem;
|
||||
border-radius: 1.25rem;
|
||||
color: var(--md-sys-color-surface);
|
||||
}
|
||||
|
||||
.feature-card .sign .nav-icon {
|
||||
color: var(--md-nav-on-section-color-sign);
|
||||
background-color: var(--md-nav-section-color-sign);
|
||||
}
|
||||
|
||||
.feature-card .organize .nav-icon {
|
||||
color: var(--md-nav-on-section-color-organize);
|
||||
background-color: var(--md-nav-section-color-organize);
|
||||
}
|
||||
|
||||
.feature-card .convert .nav-icon {
|
||||
color: var(--md-nav-on-section-color-convert);
|
||||
background-color: var(--md-nav-section-color-convert);
|
||||
}
|
||||
|
||||
.feature-card .security .nav-icon {
|
||||
color: var(--md-nav-on-section-color-security);
|
||||
background-color: var(--md-nav-section-color-security);
|
||||
}
|
||||
|
||||
.feature-card .other .nav-icon {
|
||||
color: var(--md-nav-on-section-color-other);
|
||||
background-color: var(--md-nav-section-color-other);
|
||||
}
|
||||
|
||||
.feature-card .advance .nav-icon {
|
||||
color: var(--md-nav-on-section-color-advance);
|
||||
background-color: var(--md-nav-section-color-advance);
|
||||
}
|
||||
|
||||
.feature-card .image .nav-icon {
|
||||
color: var(--md-nav-on-section-color-image);
|
||||
background-color: var(--md-nav-section-color-image);
|
||||
}
|
||||
|
||||
.feature-card .word .nav-icon {
|
||||
color: var(--md-nav-on-section-color-word);
|
||||
background-color: var(--md-nav-section-color-word);
|
||||
}
|
||||
|
||||
.feature-card .ppt .nav-icon {
|
||||
color: var(--md-nav-on-section-color-ppt);
|
||||
background-color: var(--md-nav-section-color-ppt);
|
||||
}
|
||||
|
||||
/* Buttons Components */
|
||||
.btn {
|
||||
border-radius: 1.25rem;
|
||||
}
|
||||
|
||||
.btn-close {
|
||||
width: auto;
|
||||
height: auto;
|
||||
color: var(--md-sys-color-on-surface);
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.btn-close:hover {
|
||||
color: var(--md-sys-color-on-surface);
|
||||
}
|
||||
|
||||
.modal-header .btn-close {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* Primary btn */
|
||||
.btn-primary {
|
||||
color: var(--md-sys-color-on-primary);
|
||||
background-color: var(--md-sys-color-primary);
|
||||
border-color: var(--md-sys-color-primary);
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
.btn-primary.disabled,
|
||||
.btn-primary:disabled {
|
||||
color: var(--md-sys-color-on-primary);
|
||||
background-color: var(--md-sys-color-primary);
|
||||
border-color: var(--md-sys-color-primary);
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
color: var(--md-sys-color-on-primary);
|
||||
background-color: var(--md-sys-color-primary);
|
||||
border-color: var(--md-sys-color-primary);
|
||||
box-shadow: var(--md-sys-elevation-3) !important;
|
||||
}
|
||||
|
||||
.btn-check:active+.btn-primary,
|
||||
.btn-check:checked+.btn-primary,
|
||||
.btn-primary.active,
|
||||
.btn-primary:active,
|
||||
.show>.btn-primary.dropdown-toggle {
|
||||
color: var(--md-sys-color-on-primary);
|
||||
background-color: var(--md-sys-color-primary);
|
||||
border-color: var(--md-sys-color-primary);
|
||||
box-shadow: var(--md-sys-elevation-3) !important;
|
||||
}
|
||||
|
||||
.btn-check:focus+.btn-primary,
|
||||
.btn-primary:focus {
|
||||
color: var(--md-sys-color-on-primary);
|
||||
background-color: var(--md-sys-color-primary);
|
||||
border-color: var(--md-sys-color-primary);
|
||||
box-shadow: var(--md-sys-elevation-3) !important;
|
||||
}
|
||||
|
||||
/* Secondary btn */
|
||||
.btn-secondary {
|
||||
color: var(--md-sys-color-on-secondary);
|
||||
background-color: var(--md-sys-color-secondary);
|
||||
border-color: var(--md-sys-color-secondary);
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
.btn-secondary.disabled,
|
||||
.btn-secondary:disabled {
|
||||
color: var(--md-sys-color-on-secondary);
|
||||
background-color: var(--md-sys-color-secondary);
|
||||
border-color: var(--md-sys-color-secondary);
|
||||
}
|
||||
|
||||
.btn-secondary:hover {
|
||||
color: var(--md-sys-color-on-secondary);
|
||||
background-color: var(--md-sys-color-secondary);
|
||||
border-color: var(--md-sys-color-secondary);
|
||||
box-shadow: var(--md-sys-elevation-3) !important;
|
||||
}
|
||||
|
||||
.btn-check:active+.btn-secondary,
|
||||
.btn-check:checked+.btn-secondary,
|
||||
.btn-secondary.active,
|
||||
.btn-secondary:active,
|
||||
.show>.btn-secondary.dropdown-toggle {
|
||||
color: var(--md-sys-color-on-secondary);
|
||||
background-color: var(--md-sys-color-secondary);
|
||||
border-color: var(--md-sys-color-secondary);
|
||||
box-shadow: var(--md-sys-elevation-3) !important;
|
||||
}
|
||||
|
||||
.btn-check:focus+.btn-secondary,
|
||||
.btn-secondary:focus {
|
||||
color: var(--md-sys-color-on-secondary);
|
||||
background-color: var(--md-sys-color-secondary);
|
||||
border-color: var(--md-sys-color-secondary);
|
||||
box-shadow: var(--md-sys-elevation-3) !important;
|
||||
}
|
||||
|
||||
/* Danger btn */
|
||||
.btn-danger {
|
||||
color: var(--md-sys-color-on-error);
|
||||
background-color: var(--md-sys-color-error);
|
||||
border-color: var(--md-sys-color-error);
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
.btn-danger.disabled,
|
||||
.btn-danger:disabled {
|
||||
color: var(--md-sys-color-on-error);
|
||||
background-color: var(--md-sys-color-error);
|
||||
border-color: var(--md-sys-color-error);
|
||||
}
|
||||
|
||||
.btn-danger:hover {
|
||||
color: var(--md-sys-color-on-error);
|
||||
background-color: var(--md-sys-color-error);
|
||||
border-color: var(--md-sys-color-error);
|
||||
box-shadow: var(--md-sys-elevation-3) !important;
|
||||
}
|
||||
|
||||
.btn-check:active+.btn-danger,
|
||||
.btn-check:checked+.btn-danger,
|
||||
.btn-danger.active,
|
||||
.btn-danger:active,
|
||||
.show>.btn-danger.dropdown-toggle {
|
||||
color: var(--md-sys-color-on-error);
|
||||
background-color: var(--md-sys-color-error);
|
||||
border-color: var(--md-sys-color-error);
|
||||
box-shadow: var(--md-sys-elevation-3) !important;
|
||||
}
|
||||
|
||||
.btn-check:focus+.btn-danger,
|
||||
.btn-danger:focus {
|
||||
color: var(--md-sys-color-on-error);
|
||||
background-color: var(--md-sys-color-error);
|
||||
border-color: var(--md-sys-color-error);
|
||||
box-shadow: var(--md-sys-elevation-3) !important;
|
||||
}
|
||||
|
||||
/* Info btn */
|
||||
.btn-info {
|
||||
color: var(--md-sys-color-on-tertiary);
|
||||
background-color: var(--md-sys-color-tertiary);
|
||||
border-color: var(--md-sys-color-tertiary);
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
.btn-info .disabled,
|
||||
.btn-info:disabled {
|
||||
color: var(--md-sys-color-on-tertiary);
|
||||
background-color: var(--md-sys-color-tertiary);
|
||||
border-color: var(--md-sys-color-tertiary);
|
||||
}
|
||||
|
||||
.btn-info:hover {
|
||||
color: var(--md-sys-color-on-tertiary);
|
||||
background-color: var(--md-sys-color-tertiary);
|
||||
border-color: var(--md-sys-color-tertiary);
|
||||
box-shadow: var(--md-sys-elevation-3) !important;
|
||||
}
|
||||
|
||||
.btn-check:active+.btn-info,
|
||||
.btn-check:checked+.btn-info,
|
||||
.btn-info .active,
|
||||
.btn-info:active,
|
||||
.show>.btn-info.dropdown-toggle {
|
||||
color: var(--md-sys-color-on-tertiary);
|
||||
background-color: var(--md-sys-color-tertiary);
|
||||
border-color: var(--md-sys-color-tertiary);
|
||||
box-shadow: var(--md-sys-elevation-3) !important;
|
||||
}
|
||||
|
||||
.btn-check:focus+.btn-info,
|
||||
.btn-info:focus {
|
||||
color: var(--md-sys-color-on-tertiary);
|
||||
background-color: var(--md-sys-color-tertiary);
|
||||
border-color: var(--md-sys-color-tertiary);
|
||||
box-shadow: var(--md-sys-elevation-3) !important;
|
||||
}
|
||||
|
||||
/* Info btn */
|
||||
.btn-success {
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
.btn-success:hover,
|
||||
.btn-check:active+.btn-success,
|
||||
.btn-check:checked+.btn-success,
|
||||
.btn-success .active,
|
||||
.btn-success:active,
|
||||
.show>.btn-success.dropdown-toggle,
|
||||
.btn-check:focus+.btn-success,
|
||||
.btn-success:focus {
|
||||
box-shadow: var(--md-sys-elevation-3) !important;
|
||||
}
|
||||
|
||||
/* Warning btn */
|
||||
.btn-warning {
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
.btn-warning:hover,
|
||||
.btn-check:active+.btn-warning,
|
||||
.btn-check:checked+.btn-warning,
|
||||
.btn-warning .active,
|
||||
.btn-warning:active,
|
||||
.show>.btn-warning.dropdown-toggle,
|
||||
.btn-check:focus+.btn-warning,
|
||||
.btn-warning:focus {
|
||||
box-shadow: var(--md-sys-elevation-3) !important;
|
||||
}
|
||||
|
||||
/* Outline Primary btn */
|
||||
.btn-outline-primary {
|
||||
color: var(--md-sys-color-primary);
|
||||
background-color: transparent;
|
||||
border-color: var(--md-sys-color-primary);
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
.btn-outline-primary .disabled,
|
||||
.btn-outline-primary:disabled {
|
||||
color: var(--md-sys-color-primary);
|
||||
background-color: transparent;
|
||||
border-color: var(--md-sys-color-primary);
|
||||
}
|
||||
|
||||
.btn-outline-primary:hover {
|
||||
color: var(--md-sys-color-on-primary);
|
||||
background-color: var(--md-sys-color-primary);
|
||||
border-color: var(--md-sys-color-primary);
|
||||
}
|
||||
|
||||
.btn-check:active+.btn-outline-primary,
|
||||
.btn-check:checked+.btn-outline-primary,
|
||||
.btn-outline-primary .active,
|
||||
.btn-outline-primary:active,
|
||||
.show>.btn-outline-primary.dropdown-toggle {
|
||||
color: var(--md-sys-color-on-primary);
|
||||
background-color: var(--md-sys-color-primary);
|
||||
border-color: var(--md-sys-color-primary);
|
||||
}
|
||||
|
||||
.btn-check:focus+.btn-outline-primary,
|
||||
.btn-outline-primary:focus {
|
||||
color: var(--md-sys-color-on-primary);
|
||||
background-color: var(--md-sys-color-primary);
|
||||
border-color: var(--md-sys-color-primary);
|
||||
}
|
||||
|
||||
/* Outline Secondary btn */
|
||||
.btn-outline-secondary {
|
||||
color: var(--md-sys-color-secondary);
|
||||
background-color: transparent;
|
||||
border-color: var(--md-sys-color-secondary);
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
.btn-outline-secondary .disabled,
|
||||
.btn-outline-secondary:disabled {
|
||||
color: var(--md-sys-color-secondary);
|
||||
background-color: transparent;
|
||||
border-color: var(--md-sys-color-secondary);
|
||||
}
|
||||
|
||||
.btn-outline-secondary:hover {
|
||||
color: var(--md-sys-color-on-secondary);
|
||||
background-color: var(--md-sys-color-secondary);
|
||||
border-color: var(--md-sys-color-secondary);
|
||||
}
|
||||
|
||||
.btn-check:active+.btn-outline-secondary,
|
||||
.btn-check:checked+.btn-outline-secondary,
|
||||
.btn-outline-secondary .active,
|
||||
.btn-outline-secondary:active,
|
||||
.show>.btn-outline-secondary.dropdown-toggle {
|
||||
color: var(--md-sys-color-on-secondary);
|
||||
background-color: var(--md-sys-color-secondary);
|
||||
border-color: var(--md-sys-color-secondary);
|
||||
}
|
||||
|
||||
.btn-check:focus+.btn-outline-secondary,
|
||||
.btn-outline-secondary:focus {
|
||||
color: var(--md-sys-color-on-secondary);
|
||||
background-color: var(--md-sys-color-secondary);
|
||||
border-color: var(--md-sys-color-secondary);
|
||||
}
|
||||
|
||||
/* Disabled btn */
|
||||
.btn.disabled,
|
||||
.btn:disabled,
|
||||
fieldset:disabled .btn {
|
||||
pointer-events: none;
|
||||
opacity: 0.65;
|
||||
}
|
||||
|
||||
/* Range Slider */
|
||||
.form-range:focus::-webkit-slider-thumb {
|
||||
box-shadow: 0 0 0 1px var(--md-sys-color-surface), 0 0 0 .25rem var(--md-sys-color-primary)
|
||||
}
|
||||
|
||||
.form-range:focus::-moz-range-thumb {
|
||||
box-shadow: 0 0 0 1px var(--md-sys-color-surface), 0 0 0 .25rem var(--md-sys-color-primary)
|
||||
}
|
||||
|
||||
.form-range::-webkit-slider-thumb {
|
||||
background-color: var(--md-sys-color-primary);
|
||||
}
|
||||
|
||||
|
||||
.form-range::-webkit-slider-thumb:active {
|
||||
background-color: var(--md-sys-color-primary)
|
||||
}
|
||||
|
||||
.form-range::-webkit-slider-runnable-track {
|
||||
background-color: var(--md-sys-color-on-primary)
|
||||
}
|
||||
|
||||
.form-range::-moz-range-thumb {
|
||||
background-color: var(--md-sys-color-primary);
|
||||
}
|
||||
|
||||
|
||||
/* checkbox */
|
||||
.form-check {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.form-check-label {
|
||||
margin-left: 0.5rem;
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
|
||||
.form-check-input {
|
||||
width: 1.5rem;
|
||||
height: 1.5rem;
|
||||
margin: 0;
|
||||
background-color: var(--md-sys-color-surface);
|
||||
border: 2px solid var(--md-sys-color-outline-variant);
|
||||
}
|
||||
|
||||
.form-check-input:checked {
|
||||
background-color: var(--md-sys-color-primary);
|
||||
border-color: var(--md-sys-color-outline-variant);
|
||||
border: none;
|
||||
}
|
||||
|
||||
.form-check-input:focus {
|
||||
border-color: var(--md-sys-color-outline-variant);
|
||||
outline: 0;
|
||||
box-shadow: 0 0 0 .25rem var(--md-sys-color-outline-variant);
|
||||
}
|
||||
|
||||
.form-check-input:checked[type=checkbox] {
|
||||
background-image: none;
|
||||
}
|
||||
|
||||
.form-check input[type="checkbox"]:checked+span.material-symbols-rounded {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.form-check span.material-symbols-rounded {
|
||||
display: none;
|
||||
color: var(--md-sys-color-surface);
|
||||
position: absolute;
|
||||
margin-left: -1.5rem;
|
||||
margin-right: -1.5rem;
|
||||
pointer-events: none;
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
-webkit-tap-highlight-color: rgb(0 0 0 / 0%);
|
||||
}
|
||||
|
||||
.form-check {
|
||||
min-height: 22px;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.form-check > label {
|
||||
padding-left: 29px !important;
|
||||
min-height: 22px;
|
||||
line-height: 22px;
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
vertical-align: top;
|
||||
margin-bottom: 0;
|
||||
font-weight: normal;
|
||||
cursor: pointer;
|
||||
padding-right: 29px !important;
|
||||
}
|
||||
|
||||
.form-check > input:first-child {
|
||||
position: absolute !important;
|
||||
opacity: 0;
|
||||
margin: 0;
|
||||
background-color: var(--md-sys-state-hover-opacity);
|
||||
border-radius: 50%;
|
||||
appearance: none;
|
||||
-moz-appearance: none;
|
||||
-webkit-appearance: none;
|
||||
-ms-appearance: none;
|
||||
display: block;
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
outline: none;
|
||||
transform: scale(1.65);
|
||||
-ms-transform: scale(1.65);
|
||||
transition: opacity .3s;
|
||||
}
|
||||
|
||||
.form-check > input:first-child:hover {
|
||||
opacity: 1;
|
||||
transform: scale(1.65);
|
||||
-ms-transform: scale(1.65);
|
||||
}
|
||||
|
||||
.form-check > input:first-child:disabled {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.form-check > input:first-child:disabled + label,
|
||||
.form-check > input:first-child:disabled + input[type="hidden"] + label,
|
||||
.form-check > input:first-child:disabled + label::before,
|
||||
.form-check > input:first-child:disabled + input[type="hidden"] + label::before {
|
||||
pointer-events: none;
|
||||
cursor: default;
|
||||
filter: alpha(opacity=65);
|
||||
-webkit-box-shadow: none;
|
||||
box-shadow: none;
|
||||
opacity: .65;
|
||||
}
|
||||
|
||||
.form-check > input:first-child + label::before,
|
||||
.form-check > input:first-child + input[type="hidden"] + label::before {
|
||||
content: "";
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
border: 2px solid var(--md-sys-color-on-surface-variant);
|
||||
border-radius: 3px;
|
||||
margin-left: -29px;
|
||||
box-sizing: border-box;
|
||||
margin-right: -29px;
|
||||
}
|
||||
|
||||
.form-check > input:first-child:checked + label::after,
|
||||
.form-check > input:first-child:checked + input[type="hidden"] + label::after {
|
||||
content: "";
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 7px;
|
||||
height: 10px;
|
||||
border: solid 2px;
|
||||
border-left: none;
|
||||
border-top: none;
|
||||
transform: translate(7.75px, 4.5px) rotate(45deg);
|
||||
-ms-transform: translate(7.75px, 4.5px) rotate(45deg);
|
||||
box-sizing: border-box;
|
||||
right: 0;
|
||||
margin-right: 14px;
|
||||
border-bottom-color: var(--md-sys-color-on-primary);
|
||||
border-right-color: var(--md-sys-color-on-primary);
|
||||
}
|
||||
|
||||
.form-check > input:first-child::-ms-check {
|
||||
opacity: 0;
|
||||
border-radius: 50%;
|
||||
background-color: var(--md-sys-color-primary);
|
||||
}
|
||||
|
||||
.form-check > input:first-child:active {
|
||||
transform: scale(0);
|
||||
-ms-transform: scale(0);
|
||||
opacity: 1;
|
||||
transition: opacity 0s, transform 0s;
|
||||
}
|
||||
|
||||
.form-check > input[type="radio"]:first-child + label::before,
|
||||
.form-check > input[type="radio"]:first-child + input[type="hidden"] + label::before {
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.form-check > input[type="radio"]:first-child:checked + label::before,
|
||||
.form-check > input[type="radio"]:first-child:checked + input[type="hidden"] + label::before {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.form-check > input[type="radio"]:first-child:checked + label::after,
|
||||
.form-check > input[type="radio"]:first-child:checked + input[type="hidden"] + label::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 50%;
|
||||
border: none;
|
||||
top: 6px;
|
||||
left: 6px;
|
||||
transform: none;
|
||||
-ms-transform: none;
|
||||
}
|
||||
|
||||
.form-check > input[type="checkbox"]:first-child:checked + label::after,
|
||||
.form-check > input[type="checkbox"]:first-child:checked + input[type="hidden"] + label::after {
|
||||
width: 8px;
|
||||
height: 14px;
|
||||
transform: translate(7px, 2px) rotate(45deg);
|
||||
-ms-transform: translate(7px, 2px) rotate(45deg);
|
||||
}
|
||||
|
||||
.form-check-inline {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.form-check-inline + .form-check-inline {
|
||||
margin-left: .75rem;
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
.form-check > input:first-child:checked + label::before,
|
||||
.form-check > input:first-child:checked + input[type="hidden"] + label::before {
|
||||
background-color: var(--md-sys-color-primary);
|
||||
border-color: var(--md-sys-color-primary);
|
||||
}
|
||||
|
||||
/* Forms */
|
||||
textarea.form-control {
|
||||
border-radius: 1.5rem !important;
|
||||
}
|
||||
|
||||
.form-control,
|
||||
.form-select,
|
||||
.form-control:disabled,
|
||||
.form-control[readonly] {
|
||||
color: var(--md-sys-color-on-surface);
|
||||
background-color: var(--md-sys-color-surface-container-low);
|
||||
border-color: var(--md-sys-color-outline-variant);
|
||||
border-radius: 3rem !important;
|
||||
}
|
||||
|
||||
.form-control:focus,
|
||||
.form-select:focus {
|
||||
color: var(--md-sys-color-on-surface);
|
||||
background-color: var(--md-sys-color-surface-container-lowest);
|
||||
border-color: var(--md-sys-color-outline-variant);
|
||||
outline: 0;
|
||||
box-shadow: 0 0 0 0.25rem var(--md-sys-color-outline-variant);
|
||||
}
|
||||
|
||||
/* Navbar Components */
|
||||
.navbar-brand {
|
||||
color: var(--md-sys-color-on-surface) !important;
|
||||
}
|
||||
|
||||
.nav-link {
|
||||
transition: none !important;
|
||||
padding: 0.5rem 1rem !important;
|
||||
border: 1px transparent;
|
||||
}
|
||||
|
||||
.navbar-nav li {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.navbar-nav .nav-link {
|
||||
color: var(--md-sys-color-on-surface-variant);
|
||||
}
|
||||
|
||||
.navbar-nav .nav-link:focus,
|
||||
.navbar-nav .nav-link:hover {
|
||||
color: var(--md-sys-color-on-secondary-container);
|
||||
background-color: var(--md-sys-color-surface-3);
|
||||
border-radius: 3rem;
|
||||
font-weight: 500;
|
||||
font-variation-settings: var(--md-sys-icon-fill-1);
|
||||
}
|
||||
|
||||
.navbar-nav .nav-link.active,
|
||||
.navbar-nav .show>.nav-link {
|
||||
color: var(--md-sys-color-on-secondary-container);
|
||||
background-color: var(--md-sys-color-surface-5);
|
||||
border-radius: 3rem;
|
||||
font-weight: 500;
|
||||
font-variation-settings: var(--md-sys-icon-fill-1);
|
||||
}
|
||||
|
||||
.menu-title {
|
||||
padding: 0 1rem;
|
||||
}
|
||||
|
||||
.dropdown-menu {
|
||||
margin: 0 1%;
|
||||
padding: 1.5rem 0;
|
||||
border-radius: 1rem;
|
||||
color: var(--md-sys-color-on-surface);
|
||||
background-color: var(--md-sys-color-surface-container);
|
||||
border: 1px solid var(--md-sys-color-surface-5);
|
||||
box-shadow: var(--md-sys-elevation-2);
|
||||
}
|
||||
|
||||
.dropdown-item {
|
||||
color: var(--md-sys-color-on-surface);
|
||||
padding: 0.25rem 1rem;
|
||||
}
|
||||
|
||||
.dropdown-item:focus,
|
||||
.dropdown-item:hover {
|
||||
color: var(--md-sys-color-on-surface);
|
||||
background-color: var(--md-sys-color-surface-5);
|
||||
border-radius: 3rem;
|
||||
font-weight: 500;
|
||||
font-variation-settings: var(--md-sys-icon-fill-1);
|
||||
}
|
||||
|
||||
.dropdown-item.active,
|
||||
.dropdown-item:active {
|
||||
color: var(--md-sys-color-on-surface);
|
||||
background-color: var(--md-sys-color-surface-5);
|
||||
border-radius: 3rem;
|
||||
font-weight: 500;
|
||||
font-variation-settings: var(--md-sys-icon-fill-1);
|
||||
}
|
||||
|
||||
/* list-group-item */
|
||||
.list-group-item {
|
||||
color: var(--md-sys-color-on-surface);
|
||||
background-color: var(--md-sys-color-surface-5);
|
||||
border: 1px solid var(--md-sys-color-outline-variant);
|
||||
}
|
||||
|
||||
.list-group-item:first-child {
|
||||
border-radius: 1rem 1rem 0rem 0rem;
|
||||
}
|
||||
|
||||
.list-group-item:last-child {
|
||||
border-radius: 0rem 0rem 1rem 1rem;
|
||||
}
|
||||
|
||||
.list-group-item:only-child {
|
||||
border-radius: 1rem 1rem 1rem 1rem;
|
||||
}
|
||||
|
||||
.list-group-item .btn {
|
||||
padding: .375rem .5rem;
|
||||
}
|
||||
|
||||
/*Alert */
|
||||
.alert-container {
|
||||
padding: 2rem 3rem;
|
||||
border-radius: 3rem;
|
||||
margin: 1rem 0rem 2rem;
|
||||
}
|
||||
|
||||
.alert-header {
|
||||
display: flex !important;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.alert-heading {
|
||||
font-size: calc(1.275rem + .3vw);
|
||||
}
|
||||
|
||||
.alert-dismissible .btn-close {
|
||||
position: relative;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.alert-danger {
|
||||
color: var(--md-sys-color-on-error-container);
|
||||
background-color: var(--md-sys-color-error-container);
|
||||
border-color: transparent;
|
||||
}
|
||||
22
src/main/resources/static/css/theme/font.css
Normal file
@@ -0,0 +1,22 @@
|
||||
@font-face {
|
||||
font-family: 'Material Symbols Rounded';
|
||||
font-style: normal;
|
||||
font-weight: 100 700;
|
||||
src: url(../../fonts/google-symbol.woff2) format('woff2');
|
||||
}
|
||||
|
||||
.material-symbols-rounded {
|
||||
font-family: 'Material Symbols Rounded';
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
font-size: 24px;
|
||||
line-height: 1;
|
||||
letter-spacing: normal;
|
||||
text-transform: none;
|
||||
display: inline-block;
|
||||
white-space: nowrap;
|
||||
word-wrap: normal;
|
||||
direction: ltr;
|
||||
-webkit-font-feature-settings: 'liga';
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
34
src/main/resources/static/css/theme/theme.css
Normal file
@@ -0,0 +1,34 @@
|
||||
:where(html, .light-theme, .dark-theme),
|
||||
.tokens,
|
||||
:host {
|
||||
/* Define surface colors based on primary color */
|
||||
--md-sys-color-surface-1: color-mix(in srgb, var(--md-sys-color-primary) 13%, rgba(0, 0, 0, 0.05) 5%);
|
||||
--md-sys-color-surface-2: color-mix(in srgb, var(--md-sys-color-primary) 13%, rgba(0, 0, 0, 0.08) 5%);
|
||||
--md-sys-color-surface-3: color-mix(in srgb, var(--md-sys-color-primary) 13%, rgba(0, 0, 0, 0.11) 5%);
|
||||
--md-sys-color-surface-4: color-mix(in srgb, var(--md-sys-color-primary) 13%, rgba(0, 0, 0, 0.12) 5%);
|
||||
--md-sys-color-surface-5: color-mix(in srgb, var(--md-sys-color-primary) 13%, rgba(0, 0, 0, 0.14) 5%);
|
||||
/* Icon fill */
|
||||
--md-sys-icon-fill-0: 'FILL' 0, 'wght' 500;
|
||||
--md-sys-icon-fill-1: 'FILL' 1, 'wght' 500;
|
||||
/* Hover Color */
|
||||
--md-sys-state-hover-opacity: color-mix(in srgb, var(--md-sys-color-primary), rgba(0, 0, 0, 0) 80%);
|
||||
/* Shadow */
|
||||
--md-sys-color-shadow: #000000;
|
||||
--md-elevation-shadow-color-rgb: 0, 0, 0;
|
||||
--md-elevation-shadow-color: var(--md-elevation-shadow-color-rgb);
|
||||
/* Shadow Elevation*/
|
||||
--md-sys-elevation-0: 0px 0px 0px 0px rgb(var(--md-elevation-shadow-color), 0.2), 0px 0px 0px 0px rgb(var(--md-elevation-shadow-color), 0.14), 0px 0px 0px 0px rgb(var(--md-elevation-shadow-color), 0.12);
|
||||
--md-sys-elevation-1: 0px 3px 1px -2px rgb(var(--md-elevation-shadow-color), 0.2), 0px 2px 2px 0px rgb(var(--md-elevation-shadow-color), 0.14), 0px 1px 5px 0px rgb(var(--md-elevation-shadow-color), 0.12);
|
||||
--md-sys-elevation-2: 0px 2px 4px -1px rgb(var(--md-elevation-shadow-color), 0.2), 0px 4px 5px 0px rgb(var(--md-elevation-shadow-color), 0.14), 0px 1px 10px 0px rgb(var(--md-elevation-shadow-color), 0.12);
|
||||
--md-sys-elevation-3: 0px 5px 5px -3px rgb(var(--md-elevation-shadow-color), 0.2), 0px 8px 10px 1px rgb(var(--md-elevation-shadow-color), 0.14), 0px 3px 14px 2px rgb(var(--md-elevation-shadow-color), 0.12);
|
||||
--md-sys-elevation-4: 0px 5px 5px -3px rgb(var(--md-elevation-shadow-color) / 0.2), 0px 8px 10px 1px rgb(var(--md-elevation-shadow-color), 0.14), 0px 3px 14px 2px rgb(var(--md-elevation-shadow-color), 0.12);
|
||||
--md-sys-elevation-5: 0px 8px 10px -6px rgb(var(--md-elevation-shadow-color), 0.2), 0px 16px 24px 2px rgb(var(--md-elevation-shadow-color), 0.14), 0px 6px 30px 5px rgb(var(--md-elevation-shadow-color), 0.12);
|
||||
}
|
||||
|
||||
.fill {
|
||||
font-variation-settings: var(--md-sys-icon-fill-1);
|
||||
}
|
||||
|
||||
.no-fill {
|
||||
font-variation-settings: var(--md-sys-icon-fill-0);
|
||||
}
|
||||
73
src/main/resources/static/css/theme/theme.dark.css
Normal file
@@ -0,0 +1,73 @@
|
||||
:root {
|
||||
/* Colors */
|
||||
--md-sys-color-primary: rgb(162 201 255);
|
||||
--md-sys-color-surface-tint: rgb(162 201 255);
|
||||
--md-sys-color-on-primary: rgb(0 49 92);
|
||||
--md-sys-color-primary-container: rgb(0 118 208);
|
||||
--md-sys-color-on-primary-container: rgb(255 255 255);
|
||||
--md-sys-color-secondary: rgb(169 201 246);
|
||||
--md-sys-color-on-secondary: rgb(12 49 87);
|
||||
--md-sys-color-secondary-container: rgb(29 62 100);
|
||||
--md-sys-color-on-secondary-container: rgb(180 210 255);
|
||||
--md-sys-color-tertiary: rgb(193 194 248);
|
||||
--md-sys-color-on-tertiary: rgb(42 44 88);
|
||||
--md-sys-color-tertiary-container: rgb(110 112 161);
|
||||
--md-sys-color-on-tertiary-container: rgb(255 255 255);
|
||||
--md-sys-color-error: rgb(255 180 171);
|
||||
--md-sys-color-on-error: rgb(105 0 5);
|
||||
--md-sys-color-error-container: rgb(147 0 10);
|
||||
--md-sys-color-on-error-container: rgb(255 218 214);
|
||||
--md-sys-color-background: rgb(15 20 26);
|
||||
--md-sys-color-on-background: rgb(223 226 235);
|
||||
--md-sys-color-surface: rgb(15 20 26);
|
||||
--md-sys-color-on-surface: rgb(223 226 235);
|
||||
--md-sys-color-surface-variant: rgb(64 71 83);
|
||||
--md-sys-color-on-surface-variant: rgb(192 199 213);
|
||||
--md-sys-color-outline: rgb(138 145 158);
|
||||
--md-sys-color-outline-variant: rgb(64 71 83);
|
||||
--md-sys-color-shadow: rgb(0 0 0);
|
||||
--md-sys-color-scrim: rgb(0 0 0);
|
||||
--md-sys-color-inverse-surface: rgb(223 226 235);
|
||||
--md-sys-color-inverse-on-surface: rgb(45 49 55);
|
||||
--md-sys-color-inverse-primary: rgb(0 96 170);
|
||||
--md-sys-color-primary-fixed: rgb(211 228 255);
|
||||
--md-sys-color-on-primary-fixed: rgb(0 28 56);
|
||||
--md-sys-color-primary-fixed-dim: rgb(162 201 255);
|
||||
--md-sys-color-on-primary-fixed-variant: rgb(0 72 130);
|
||||
--md-sys-color-secondary-fixed: rgb(211 228 255);
|
||||
--md-sys-color-on-secondary-fixed: rgb(0 28 56);
|
||||
--md-sys-color-secondary-fixed-dim: rgb(169 201 246);
|
||||
--md-sys-color-on-secondary-fixed-variant: rgb(40 72 111);
|
||||
--md-sys-color-tertiary-fixed: rgb(225 224 255);
|
||||
--md-sys-color-on-tertiary-fixed: rgb(20 22 66);
|
||||
--md-sys-color-tertiary-fixed-dim: rgb(193 194 248);
|
||||
--md-sys-color-on-tertiary-fixed-variant: rgb(64 67 112);
|
||||
--md-sys-color-surface-dim: rgb(15 20 26);
|
||||
--md-sys-color-surface-bright: rgb(53 57 64);
|
||||
--md-sys-color-surface-container-lowest: rgb(10 14 20);
|
||||
--md-sys-color-surface-container-low: rgb(24 28 34);
|
||||
--md-sys-color-surface-container: rgb(28 32 38);
|
||||
--md-sys-color-surface-container-high: rgb(38 42 49);
|
||||
--md-sys-color-surface-container-highest: rgb(49 53 60);
|
||||
/* Tools Color */
|
||||
--md-nav-section-color-opacity: 1;
|
||||
--md-nav-on-section-color-opacity: 1;
|
||||
--md-nav-section-color-sign: rgba(25, 101, 212, var(--md-nav-section-color-opacity));
|
||||
--md-nav-on-section-color-sign: rgba(28, 27, 31, var(--md-nav-on-section-color-opacity));
|
||||
--md-nav-section-color-organize: rgba(120, 130, 255, var(--md-nav-section-color-opacity));
|
||||
--md-nav-on-section-color-organize: rgba(28, 27, 31, var(--md-nav-on-section-color-opacity));
|
||||
--md-nav-section-color-convert: rgba(25, 177, 212, var(--md-nav-section-color-opacity));
|
||||
--md-nav-on-section-color-convert: rgba(28, 27, 31, var(--md-nav-on-section-color-opacity));
|
||||
--md-nav-section-color-security: rgba(255, 120, 146, var(--md-nav-section-color-opacity));
|
||||
--md-nav-on-section-color-security: rgba(28, 27, 31, var(--md-nav-on-section-color-opacity));
|
||||
--md-nav-section-color-other: rgba(72, 189, 84, var(--md-nav-section-color-opacity));
|
||||
--md-nav-on-section-color-other: rgba(28, 27, 31, var(--md-nav-on-section-color-opacity));
|
||||
--md-nav-section-color-advance: rgba(245, 84, 84, var(--md-nav-section-color-opacity));
|
||||
--md-nav-on-section-color-advance: rgba(28, 27, 31, var(--md-nav-on-section-color-opacity));
|
||||
--md-nav-section-color-image: rgba(212, 172, 25, var(--md-nav-section-color-opacity));
|
||||
--md-nav-on-section-color-image: rgba(28, 27, 31, var(--md-nav-on-section-color-opacity));
|
||||
--md-nav-section-color-word: rgba(61, 153, 245, var(--md-nav-section-color-opacity));
|
||||
--md-nav-on-section-color-word: rgba(28, 27, 31, var(--md-nav-on-section-color-opacity));
|
||||
--md-nav-section-color-ppt: rgba(255, 128, 0, var(--md-nav-section-color-opacity));
|
||||
--md-nav-on-section-color-ppt: rgba(28, 27, 31, var(--md-nav-on-section-color-opacity));
|
||||
}
|
||||
73
src/main/resources/static/css/theme/theme.light.css
Normal file
@@ -0,0 +1,73 @@
|
||||
:root {
|
||||
/* Colors */
|
||||
--md-sys-color-primary: rgb(0 96 170);
|
||||
--md-sys-color-surface-tint: rgb(0 96 170);
|
||||
--md-sys-color-on-primary: rgb(255 255 255);
|
||||
--md-sys-color-primary-container: rgb(80 163 255);
|
||||
--md-sys-color-on-primary-container: rgb(0 20 43);
|
||||
--md-sys-color-secondary: rgb(65 96 136);
|
||||
--md-sys-color-on-secondary: rgb(255 255 255);
|
||||
--md-sys-color-secondary-container: rgb(188 215 255);
|
||||
--md-sys-color-on-secondary-container: rgb(32 65 103);
|
||||
--md-sys-color-tertiary: rgb(88 90 138);
|
||||
--md-sys-color-on-tertiary: rgb(255 255 255);
|
||||
--md-sys-color-tertiary-container: rgb(151 153 205);
|
||||
--md-sys-color-on-tertiary-container: rgb(7 9 55);
|
||||
--md-sys-color-error: rgb(186 26 26);
|
||||
--md-sys-color-on-error: rgb(255 255 255);
|
||||
--md-sys-color-error-container: rgb(255 218 214);
|
||||
--md-sys-color-on-error-container: rgb(65 0 2);
|
||||
--md-sys-color-background: rgb(248 249 255);
|
||||
--md-sys-color-on-background: rgb(24 28 34);
|
||||
--md-sys-color-surface: rgb(248 249 255);
|
||||
--md-sys-color-on-surface: rgb(24 28 34);
|
||||
--md-sys-color-surface-variant: rgb(220 227 241);
|
||||
--md-sys-color-on-surface-variant: rgb(64 71 83);
|
||||
--md-sys-color-outline: rgb(112 119 132);
|
||||
--md-sys-color-outline-variant: rgb(192 199 213);
|
||||
--md-sys-color-shadow: rgb(0 0 0);
|
||||
--md-sys-color-scrim: rgb(0 0 0);
|
||||
--md-sys-color-inverse-surface: rgb(45 49 55);
|
||||
--md-sys-color-inverse-on-surface: rgb(238 241 250);
|
||||
--md-sys-color-inverse-primary: rgb(162 201 255);
|
||||
--md-sys-color-primary-fixed: rgb(211 228 255);
|
||||
--md-sys-color-on-primary-fixed: rgb(0 28 56);
|
||||
--md-sys-color-primary-fixed-dim: rgb(162 201 255);
|
||||
--md-sys-color-on-primary-fixed-variant: rgb(0 72 130);
|
||||
--md-sys-color-secondary-fixed: rgb(211 228 255);
|
||||
--md-sys-color-on-secondary-fixed: rgb(0 28 56);
|
||||
--md-sys-color-secondary-fixed-dim: rgb(169 201 246);
|
||||
--md-sys-color-on-secondary-fixed-variant: rgb(40 72 111);
|
||||
--md-sys-color-tertiary-fixed: rgb(225 224 255);
|
||||
--md-sys-color-on-tertiary-fixed: rgb(20 22 66);
|
||||
--md-sys-color-tertiary-fixed-dim: rgb(193 194 248);
|
||||
--md-sys-color-on-tertiary-fixed-variant: rgb(64 67 112);
|
||||
--md-sys-color-surface-dim: rgb(215 218 227);
|
||||
--md-sys-color-surface-bright: rgb(248 249 255);
|
||||
--md-sys-color-surface-container-lowest: rgb(255 255 255);
|
||||
--md-sys-color-surface-container-low: rgb(241 243 253);
|
||||
--md-sys-color-surface-container: rgb(235 238 247);
|
||||
--md-sys-color-surface-container-high: rgb(229 232 241);
|
||||
--md-sys-color-surface-container-highest: rgb(223 226 235);
|
||||
/* Tools Color */
|
||||
--md-nav-section-color-opacity: 1;
|
||||
--md-nav-on-section-color-opacity: 1;
|
||||
--md-nav-section-color-sign: rgba(25, 101, 212, var(--md-nav-section-color-opacity));
|
||||
--md-nav-on-section-color-sign: rgba(255, 251, 254, var(--md-nav-on-section-color-opacity));
|
||||
--md-nav-section-color-organize: rgba(120, 130, 255, var(--md-nav-section-color-opacity));
|
||||
--md-nav-on-section-color-organize: rgba(255, 251, 254, var(--md-nav-on-section-color-opacity));
|
||||
--md-nav-section-color-convert: rgba(25, 177, 212, var(--md-nav-section-color-opacity));
|
||||
--md-nav-on-section-color-convert: rgba(255, 251, 254, var(--md-nav-on-section-color-opacity));
|
||||
--md-nav-section-color-security: rgba(255, 120, 146, var(--md-nav-section-color-opacity));
|
||||
--md-nav-on-section-color-security: rgba(255, 251, 254, var(--md-nav-on-section-color-opacity));
|
||||
--md-nav-section-color-other: rgba(72, 189, 84, var(--md-nav-section-color-opacity));
|
||||
--md-nav-on-section-color-other: rgba(255, 251, 254, var(--md-nav-on-section-color-opacity));
|
||||
--md-nav-section-color-advance: rgba(245, 84, 84, var(--md-nav-section-color-opacity));
|
||||
--md-nav-on-section-color-advance: rgba(255, 251, 254, var(--md-nav-on-section-color-opacity));
|
||||
--md-nav-section-color-image: rgba(212, 172, 25, var(--md-nav-section-color-opacity));
|
||||
--md-nav-on-section-color-image: rgba(255, 251, 254, var(--md-nav-on-section-color-opacity));
|
||||
--md-nav-section-color-word: rgba(61, 153, 245, var(--md-nav-section-color-opacity));
|
||||
--md-nav-on-section-color-word: rgba(255, 251, 254, var(--md-nav-on-section-color-opacity));
|
||||
--md-nav-section-color-ppt: rgba(255, 128, 0, var(--md-nav-section-color-opacity));
|
||||
--md-nav-on-section-color-ppt: rgba(255, 251, 254, var(--md-nav-on-section-color-opacity));
|
||||
}
|
||||
BIN
src/main/resources/static/fonts/google-symbol.woff2
Normal file
@@ -1,3 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-123" viewBox="0 0 16 16">
|
||||
<path d="M2.873 11.297V4.142H1.699L0 5.379v1.137l1.64-1.18h.06v5.961h1.174Zm3.213-5.09v-.063c0-.618.44-1.169 1.196-1.169.676 0 1.174.44 1.174 1.106 0 .624-.42 1.101-.807 1.526L4.99 10.553v.744h4.78v-.99H6.643v-.069L8.41 8.252c.65-.724 1.237-1.332 1.237-2.27C9.646 4.849 8.723 4 7.308 4c-1.573 0-2.36 1.064-2.36 2.15v.057h1.138Zm6.559 1.883h.786c.823 0 1.374.481 1.379 1.179.01.707-.55 1.216-1.421 1.21-.77-.005-1.326-.419-1.379-.953h-1.095c.042 1.053.938 1.918 2.464 1.918 1.478 0 2.642-.839 2.62-2.144-.02-1.143-.922-1.651-1.551-1.714v-.063c.535-.09 1.347-.66 1.326-1.678-.026-1.053-.933-1.855-2.359-1.845-1.5.005-2.317.88-2.348 1.898h1.116c.032-.498.498-.944 1.206-.944.703 0 1.206.435 1.206 1.07.005.64-.504 1.106-1.2 1.106h-.75v.96Z"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 870 B |
@@ -1,4 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-palette" viewBox="0 0 16 16">
|
||||
<path d="M8 5a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3zm4 3a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3zM5.5 7a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0zm.5 6a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3z"/>
|
||||
<path d="M16 8c0 3.15-1.866 2.585-3.567 2.07C11.42 9.763 10.465 9.473 10 10c-.603.683-.475 1.819-.351 2.92C9.826 14.495 9.996 16 8 16a8 8 0 1 1 8-8zm-8 7c.611 0 .654-.171.655-.176.078-.146.124-.464.07-1.119-.014-.168-.037-.37-.061-.591-.052-.464-.112-1.005-.118-1.462-.01-.707.083-1.61.704-2.314.369-.417.845-.578 1.272-.618.404-.038.812.026 1.16.104.343.077.702.186 1.025.284l.028.008c.346.105.658.199.953.266.653.148.904.083.991.024C14.717 9.38 15 9.161 15 8a7 7 0 1 0-7 7z"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 795 B |
@@ -1,4 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-arrow-clockwise" viewBox="0 0 16 16">
|
||||
<path fill-rule="evenodd" d="M8 3a5 5 0 1 0 4.546 2.914.5.5 0 0 1 .908-.417A6 6 0 1 1 8 2v1z"/>
|
||||
<path d="M8 4.466V.534a.25.25 0 0 1 .41-.192l2.36 1.966c.12.1.12.284 0 .384L8.41 4.658A.25.25 0 0 1 8 4.466z"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 352 B |
@@ -1,3 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-arrow-left-right" viewBox="0 0 16 16">
|
||||
<path fill-rule="evenodd" d="M1 11.5a.5.5 0 0 0 .5.5h11.793l-3.147 3.146a.5.5 0 0 0 .708.708l4-4a.5.5 0 0 0 0-.708l-4-4a.5.5 0 0 0-.708.708L13.293 11H1.5a.5.5 0 0 0-.5.5zm14-7a.5.5 0 0 1-.5.5H2.707l3.147 3.146a.5.5 0 1 1-.708.708l-4-4a.5.5 0 0 1 0-.708l4-4a.5.5 0 1 1 .708.708L2.707 4H14.5a.5.5 0 0 1 .5.5z"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 453 B |
@@ -1,4 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-award" viewBox="0 0 16 16">
|
||||
<path d="M9.669.864 8 0 6.331.864l-1.858.282-.842 1.68-1.337 1.32L2.6 6l-.306 1.854 1.337 1.32.842 1.68 1.858.282L8 12l1.669-.864 1.858-.282.842-1.68 1.337-1.32L13.4 6l.306-1.854-1.337-1.32-.842-1.68L9.669.864zm1.196 1.193.684 1.365 1.086 1.072L12.387 6l.248 1.506-1.086 1.072-.684 1.365-1.51.229L8 10.874l-1.355-.702-1.51-.229-.684-1.365-1.086-1.072L3.614 6l-.25-1.506 1.087-1.072.684-1.365 1.51-.229L8 1.126l1.356.702 1.509.229z"/>
|
||||
<path d="M4 11.794V16l4-1 4 1v-4.206l-2.018.306L8 13.126 6.018 12.1 4 11.794z"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 649 B |
@@ -1,3 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-file" viewBox="0 0 16 16">
|
||||
<path d="M4 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2H4zm0 1h8a1 1 0 0 1 1 1v12a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1z"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 284 B |
@@ -1,18 +0,0 @@
|
||||
<svg fill="#000000" version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg"
|
||||
width="800px" height="800px" viewBox="0 0 318.336 318.336"
|
||||
xml:space="preserve">
|
||||
<g>
|
||||
<g>
|
||||
<path d="M302.137,74.432h-21.031c-30.496-13.614-56.389-20.611-77.028-20.611c-26.731,0-39.245,11.649-44.906,20.535
|
||||
c-5.658-8.886-18.17-20.535-44.906-20.535c-20.638,0-46.533,7.003-77.037,20.611H16.2c-8.946,0-16.2,7.253-16.2,16.2v157.684
|
||||
c0,8.949,7.254,16.2,16.2,16.2h285.937c8.948,0,16.199-7.251,16.199-16.2V90.632C318.336,81.686,311.085,74.432,302.137,74.432z
|
||||
M154.786,84.265c-0.048,0.25-0.069,0.503-0.069,0.757V233.74c-7.084-8.18-18.95-14.438-38.804-14.438
|
||||
c-35.44,0-79.927,19.432-95.813,26.947V91.528c13.608-6.927,26.31-12.587,38.156-17.096c21.745-8.271,40.526-12.511,56.004-12.511
|
||||
c18.992,0,29.37,6.354,34.986,12.511c3.241,3.554,4.91,7.038,5.698,9.192C154.852,83.985,154.791,84.243,154.786,84.265z
|
||||
M298.234,246.249c-15.884-7.516-60.371-26.947-95.809-26.947c-19.859,0-31.72,6.254-38.805,14.438
|
||||
c-0.261,0.3-0.562,0.58-0.804,0.886V85.48c0.084-0.351,0.269-0.981,0.583-1.825c0.799-2.149,2.499-5.647,5.776-9.218
|
||||
c5.648-6.157,16.026-12.512,34.9-12.512c15.478,0,34.251,4.24,56.004,12.512c11.854,4.509,24.548,10.17,38.153,17.097V246.249
|
||||
L298.234,246.249z"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.2 KiB |
@@ -1,4 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-card-list" viewBox="0 0 16 16">
|
||||
<path d="M14.5 3a.5.5 0 0 1 .5.5v9a.5.5 0 0 1-.5.5h-13a.5.5 0 0 1-.5-.5v-9a.5.5 0 0 1 .5-.5h13zm-13-1A1.5 1.5 0 0 0 0 3.5v9A1.5 1.5 0 0 0 1.5 14h13a1.5 1.5 0 0 0 1.5-1.5v-9A1.5 1.5 0 0 0 14.5 2h-13z"/>
|
||||
<path d="M5 8a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7A.5.5 0 0 1 5 8zm0-2.5a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7a.5.5 0 0 1-.5-.5zm0 5a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7a.5.5 0 0 1-.5-.5zm-1-5a.5.5 0 1 1-1 0 .5.5 0 0 1 1 0zM4 8a.5.5 0 1 1-1 0 .5.5 0 0 1 1 0zm0 2.5a.5.5 0 1 1-1 0 .5.5 0 0 1 1 0z"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 638 B |
@@ -1,5 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-clipboard-data" viewBox="0 0 16 16">
|
||||
<path d="M4 11a1 1 0 1 1 2 0v1a1 1 0 1 1-2 0v-1zm6-4a1 1 0 1 1 2 0v5a1 1 0 1 1-2 0V7zM7 9a1 1 0 0 1 2 0v3a1 1 0 1 1-2 0V9z"/>
|
||||
<path d="M4 1.5H3a2 2 0 0 0-2 2V14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3.5a2 2 0 0 0-2-2h-1v1h1a1 1 0 0 1 1 1V14a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V3.5a1 1 0 0 1 1-1h1v-1z"/>
|
||||
<path d="M9.5 1a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-.5.5h-3a.5.5 0 0 1-.5-.5v-1a.5.5 0 0 1 .5-.5h3zm-3-1A1.5 1.5 0 0 0 5 1.5v1A1.5 1.5 0 0 0 6.5 4h3A1.5 1.5 0 0 0 11 2.5v-1A1.5 1.5 0 0 0 9.5 0h-3z"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 629 B |
@@ -1,3 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-crop" viewBox="0 0 16 16">
|
||||
<path d="M3.5.5A.5.5 0 0 1 4 1v13h13a.5.5 0 0 1 0 1h-2v2a.5.5 0 0 1-1 0v-2H3.5a.5.5 0 0 1-.5-.5V4H1a.5.5 0 0 1 0-1h2V1a.5.5 0 0 1 .5-.5zm2.5 3a.5.5 0 0 1 .5-.5h8a.5.5 0 0 1 .5.5v8a.5.5 0 0 1-1 0V4H6.5a.5.5 0 0 1-.5-.5z"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 353 B |
@@ -1,4 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-droplet" viewBox="0 0 16 16">
|
||||
<path fill-rule="evenodd" d="M7.21.8C7.69.295 8 0 8 0c.109.363.234.708.371 1.038.812 1.946 2.073 3.35 3.197 4.6C12.878 7.096 14 8.345 14 10a6 6 0 0 1-12 0C2 6.668 5.58 2.517 7.21.8zm.413 1.021A31.25 31.25 0 0 0 5.794 3.99c-.726.95-1.436 2.008-1.96 3.07C3.304 8.133 3 9.138 3 10a5 5 0 0 0 10 0c0-1.201-.796-2.157-2.181-3.7l-.03-.032C9.75 5.11 8.5 3.72 7.623 1.82z"/>
|
||||
<path fill-rule="evenodd" d="M4.553 7.776c.82-1.641 1.717-2.753 2.093-3.13l.708.708c-.29.29-1.128 1.311-1.907 2.87l-.894-.448z"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 632 B |