mirror of
https://github.com/gotson/komga.git
synced 2026-07-10 00:14:33 +00:00
Compare commits
114 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1c217cbbd4 | ||
|
|
f35f362265 | ||
|
|
4efb161ef0 | ||
|
|
275cb9251a | ||
|
|
bd8b7731dc | ||
|
|
5da5226b35 | ||
|
|
910512c73c | ||
|
|
86362b1ae8 | ||
|
|
f9f402ed55 | ||
|
|
9a3bbdd878 | ||
|
|
3e9a0eaf2c | ||
|
|
5682a37d0d | ||
|
|
ba628f9b4e | ||
|
|
be5f88c50e | ||
|
|
0bd8edba9d | ||
|
|
737cc56d03 | ||
|
|
ba6cb76b71 | ||
|
|
3d7615e7b4 | ||
|
|
9c84690a07 | ||
|
|
5d14057736 | ||
|
|
e3a8cc6b01 | ||
|
|
bb60a797e8 | ||
|
|
ddfe65dde1 | ||
|
|
4a7d9a6510 | ||
|
|
85edd8b63f | ||
|
|
63de6aa9b1 | ||
|
|
717ef82a3d | ||
|
|
7c00661365 | ||
|
|
6c2621b538 | ||
|
|
5fc0b7ef30 | ||
|
|
dd9c3facd7 | ||
|
|
b77554fa17 | ||
|
|
7e0d680bdf | ||
|
|
5620e3fd67 | ||
|
|
3ca9806e86 | ||
|
|
263d3dd893 | ||
|
|
328a22064d | ||
|
|
40dadcb8ca | ||
|
|
b8ea79eaf8 | ||
|
|
9033dc73ba | ||
|
|
da981bed0f | ||
|
|
92a61debea | ||
|
|
c00aaebef1 | ||
|
|
0013a65306 | ||
|
|
df5e90e6e3 | ||
|
|
c79008d167 | ||
|
|
4fa9422a3d | ||
|
|
90d3a1dbc3 | ||
|
|
457a7247d5 | ||
|
|
de25e4903c | ||
|
|
b91919a1f5 | ||
|
|
7ad2bd5c65 | ||
|
|
322cf23ad9 | ||
|
|
a584f4cf12 | ||
|
|
25ccf5a25f | ||
|
|
30ed01505a | ||
|
|
fd841253dc | ||
|
|
112c442af6 | ||
|
|
dfdcd08a3c | ||
|
|
de849a5afd | ||
|
|
8b542b86e3 | ||
|
|
034ab23b02 | ||
|
|
7e83afde10 | ||
|
|
3d52eab1bf | ||
|
|
22fdc2ed0c | ||
|
|
0400b8f265 | ||
|
|
bcc443806a | ||
|
|
45f39b04af | ||
|
|
6305cae0b5 | ||
|
|
4ce8f27707 | ||
|
|
966dceb10f | ||
|
|
80e5432bee | ||
|
|
7e2798b2b4 | ||
|
|
deece74f53 | ||
|
|
f990b9a331 | ||
|
|
ecf6708e74 | ||
|
|
4f94365735 | ||
|
|
58cb44583e | ||
|
|
512492b72e | ||
|
|
525b37fce7 | ||
|
|
a4958b001f | ||
|
|
2ff8ea15b0 | ||
|
|
e6560e0c81 | ||
|
|
13761f67ef | ||
|
|
4911cc8c92 | ||
|
|
2e268b4032 | ||
|
|
62b4154156 | ||
|
|
7d1c9b8cab | ||
|
|
361d20df2c | ||
|
|
ced89c5c54 | ||
|
|
a5548a5429 | ||
|
|
8f8d20a324 | ||
|
|
0f69a3a4cb | ||
|
|
9d10ed31a7 | ||
|
|
dde0169f2a | ||
|
|
a2ed7d319d | ||
|
|
475f026749 | ||
|
|
a03f1bdf7b | ||
|
|
b43046fbeb | ||
|
|
3739951b36 | ||
|
|
0f25453949 | ||
|
|
cd47fc777a | ||
|
|
f138fe31e7 | ||
|
|
454c6c7202 | ||
|
|
ce3ad4c1c7 | ||
|
|
b925f3e19d | ||
|
|
9a56b30b6c | ||
|
|
6b07fda273 | ||
|
|
727fe39e6d | ||
|
|
f8ca936ee7 | ||
|
|
fe40ede34a | ||
|
|
c23f2d3810 | ||
|
|
af66144060 | ||
|
|
ba7b82631f |
58 changed files with 5784 additions and 3326 deletions
2
.github/workflows/browserlist-update.yml
vendored
2
.github/workflows/browserlist-update.yml
vendored
|
|
@ -14,7 +14,7 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Configure git
|
||||
|
|
|
|||
2
.github/workflows/lock.yml
vendored
2
.github/workflows/lock.yml
vendored
|
|
@ -12,7 +12,7 @@ jobs:
|
|||
lock:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: dessant/lock-threads@v5
|
||||
- uses: dessant/lock-threads@v6
|
||||
with:
|
||||
github-token: ${{ github.token }}
|
||||
issue-inactive-days: '30'
|
||||
|
|
|
|||
36
.github/workflows/release.yml
vendored
36
.github/workflows/release.yml
vendored
|
|
@ -43,14 +43,14 @@ jobs:
|
|||
version_next: ${{ steps.versions.outputs.version_next }}
|
||||
should_release: ${{ steps.versions.outputs.should_release }}
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@v7
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Set up Homebrew
|
||||
id: set-up-homebrew
|
||||
uses: Homebrew/actions/setup-homebrew@master
|
||||
uses: Homebrew/actions/setup-homebrew@main
|
||||
- name: Install svu
|
||||
run: brew install caarlos0/tap/svu
|
||||
run: brew install --cask caarlos0/tap/svu
|
||||
- name: Compute next version for release
|
||||
run: |
|
||||
echo "VERSION_NEXT=`svu ${{ inputs.bump }}`" | tee -a $GITHUB_ENV
|
||||
|
|
@ -72,7 +72,7 @@ jobs:
|
|||
sudo rm -rf /usr/share/dotnet
|
||||
sudo rm -rf "$AGENT_TOOLSDIRECTORY"
|
||||
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@v7
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
|
|
@ -84,7 +84,7 @@ jobs:
|
|||
if: needs.version.outputs.should_release #only redo if the version changed
|
||||
run: sed -i -e "s/version=.*/version=${{ needs.version.outputs.version_next }}/" gradle.properties
|
||||
|
||||
- uses: actions/setup-node@v5
|
||||
- uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
cache: 'npm'
|
||||
|
|
@ -98,26 +98,26 @@ jobs:
|
|||
distribution: 'temurin'
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
uses: docker/setup-qemu-action@v4
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
uses: docker/setup-buildx-action@v4
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
uses: docker/login-action@v4
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
uses: docker/login-action@v4
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Setup Gradle
|
||||
uses: gradle/actions/setup-gradle@v5
|
||||
uses: gradle/actions/setup-gradle@v6
|
||||
|
||||
- name: Build
|
||||
run: ./gradlew :komga:prepareThymeLeaf :komga:bootJar :komga-tray:jar
|
||||
|
|
@ -143,7 +143,7 @@ jobs:
|
|||
JRELEASER_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: JReleaser Changelog output
|
||||
if: always() && needs.version.outputs.should_release
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: jreleaser-changelog
|
||||
path: |
|
||||
|
|
@ -151,7 +151,7 @@ jobs:
|
|||
build/jreleaser/output.properties
|
||||
|
||||
- name: Release commit and push
|
||||
uses: EndBug/add-and-commit@v9
|
||||
uses: EndBug/add-and-commit@v10
|
||||
if: needs.version.outputs.should_release #only redo if the version changed
|
||||
with:
|
||||
message: 'chore(release): ${{ needs.version.outputs.version_next }} [skip ci]'
|
||||
|
|
@ -167,7 +167,7 @@ jobs:
|
|||
echo $APPLE_PRIVATE_KEY | base64 --decode > ./secret/apple_private_key.p8
|
||||
|
||||
- name: Conveyor make copied-site
|
||||
uses: hydraulic-software/conveyor/actions/build@v20.0
|
||||
uses: hydraulic-software/conveyor/actions/build@v22.0
|
||||
if: inputs.conveyor-copied-site
|
||||
with:
|
||||
command: --cache-limit=2.0 -f conveyor.ci.conf make copied-site -o ./output/site
|
||||
|
|
@ -182,7 +182,7 @@ jobs:
|
|||
AWS_SECRET_ACCESS_KEY: ${{ secrets.B2_SECRET_ACCESS_KEY }}
|
||||
- name: Upload Conveyor log
|
||||
if: always() && inputs.conveyor-copied-site
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: conveyor-make-copied-site
|
||||
path: ~/.cache/hydraulic/conveyor/logs/log.latest.txt
|
||||
|
|
@ -194,7 +194,7 @@ jobs:
|
|||
JRELEASER_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: JReleaser Release output
|
||||
if: always() && inputs.github_release
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: jreleaser-release
|
||||
path: |
|
||||
|
|
@ -212,7 +212,7 @@ jobs:
|
|||
JRELEASER_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: JReleaser Publish output
|
||||
if: always() && inputs.docker_release
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: jreleaser-publish
|
||||
path: |
|
||||
|
|
@ -220,7 +220,7 @@ jobs:
|
|||
build/jreleaser/output.properties
|
||||
|
||||
- name: Conveyor - publish to Microsoft Store
|
||||
uses: hydraulic-software/conveyor/actions/build@v20.0
|
||||
uses: hydraulic-software/conveyor/actions/build@v22.0
|
||||
if: inputs.msstore_release
|
||||
with:
|
||||
command: --cache-limit=2.0 -f conveyor.msstore.ci.conf make ms-store-release -o ./output/msstore
|
||||
|
|
@ -236,7 +236,7 @@ jobs:
|
|||
AWS_SECRET_ACCESS_KEY: ${{ secrets.B2_SECRET_ACCESS_KEY }}
|
||||
- name: Upload Conveyor log
|
||||
if: always() && inputs.msstore_release
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: conveyor-ms-store-release
|
||||
path: ~/.cache/hydraulic/conveyor/logs/log.latest.txt
|
||||
|
|
|
|||
18
.github/workflows/tests.yml
vendored
18
.github/workflows/tests.yml
vendored
|
|
@ -19,7 +19,7 @@ jobs:
|
|||
fail-fast: false
|
||||
name: Test server - ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@v7
|
||||
- name: Setup Java 21
|
||||
uses: actions/setup-java@v5
|
||||
with:
|
||||
|
|
@ -28,27 +28,27 @@ jobs:
|
|||
distribution: 'temurin'
|
||||
|
||||
- name: Setup Gradle
|
||||
uses: gradle/actions/setup-gradle@v5
|
||||
uses: gradle/actions/setup-gradle@v6
|
||||
|
||||
- name: Build
|
||||
run: ./gradlew build :komga-tray:jar
|
||||
|
||||
- name: Upload Unit Test Results
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: test-results-${{ matrix.os }}
|
||||
path: komga/build/test-results/
|
||||
|
||||
- name: Upload Unit Test Reports
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: test-reports-${{ matrix.os }}
|
||||
path: komga/build/reports/tests/
|
||||
|
||||
- name: Publish Test Report
|
||||
uses: mikepenz/action-junit-report@v5
|
||||
uses: mikepenz/action-junit-report@v6
|
||||
if: always()
|
||||
with:
|
||||
report_paths: '**/build/test-results/test/TEST-*.xml'
|
||||
|
|
@ -56,7 +56,7 @@ jobs:
|
|||
|
||||
- name: Conveyor - compute JDK module list
|
||||
if: github.event_name == 'push' && github.repository_owner == 'gotson' && contains(matrix.os, 'ubuntu')
|
||||
uses: hydraulic-software/conveyor/actions/build@v20.0
|
||||
uses: hydraulic-software/conveyor/actions/build@v22.0
|
||||
with:
|
||||
command: -f conveyor.detect.conf -Kapp.machines=mac.aarch64 make processed-jars
|
||||
signing_key: ${{ secrets.CONVEYOR_SIGNING_KEY }}
|
||||
|
|
@ -69,7 +69,7 @@ jobs:
|
|||
|
||||
- name: Upload JDK required modules
|
||||
if: steps.conveyor_compare.outcome == 'failure'
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: conveyor-required-jdk-modules
|
||||
path: ./output/required-jdk-modules.txt
|
||||
|
|
@ -78,8 +78,8 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
name: Test webui builds
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/setup-node@v5
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
cache: 'npm'
|
||||
|
|
|
|||
235
CHANGELOG.md
235
CHANGELOG.md
|
|
@ -1,3 +1,238 @@
|
|||
# [1.25.0](https://github.com/gotson/komga/compare/1.24.4...1.25.0) (2026-06-30)
|
||||
## 🚀 Features
|
||||
**komga**
|
||||
- add support for solid rar4 archives ([5682a37](https://github.com/gotson/komga/commits/5682a37))
|
||||
|
||||
## 🐛 Fixes
|
||||
**kobo**
|
||||
- enfore content restriction ([bd8b773](https://github.com/gotson/komga/commits/bd8b773))
|
||||
|
||||
**openapi**
|
||||
- flatten hierchical schemas ([275cb92](https://github.com/gotson/komga/commits/275cb92))
|
||||
|
||||
## 🛠 Build
|
||||
**openapi**
|
||||
- increase timeout for openapi generation ([4efb161](https://github.com/gotson/komga/commits/4efb161))
|
||||
|
||||
**webui**
|
||||
- update Browserslist db ([9a3bbdd](https://github.com/gotson/komga/commits/9a3bbdd))
|
||||
- update Browserslist db ([ba6cb76](https://github.com/gotson/komga/commits/ba6cb76))
|
||||
|
||||
## ⚙️ Dependencies
|
||||
**ci**
|
||||
- bump actions/checkout from 6 to 7 ([5da5226](https://github.com/gotson/komga/commits/5da5226))
|
||||
|
||||
**komga**
|
||||
- bump junrar to 7.6.0 ([ba628f9](https://github.com/gotson/komga/commits/ba628f9))
|
||||
|
||||
**webui**
|
||||
- bump launch-editor from 2.6.0 to 2.14.1 in /komga-webui ([910512c](https://github.com/gotson/komga/commits/910512c))
|
||||
- bump axios from 1.15.2 to 1.16.0 in /komga-webui ([86362b1](https://github.com/gotson/komga/commits/86362b1))
|
||||
- bump qs from 6.14.2 to 6.15.2 in /komga-webui ([f9f402e](https://github.com/gotson/komga/commits/f9f402e))
|
||||
- bump js-cookie from 3.0.5 to 3.0.7 in /komga-webui ([3e9a0ea](https://github.com/gotson/komga/commits/3e9a0ea))
|
||||
- bump fast-uri from 3.1.0 to 3.1.2 in /komga-webui ([be5f88c](https://github.com/gotson/komga/commits/be5f88c))
|
||||
- bump @babel/plugin-transform-modules-systemjs ([0bd8edb](https://github.com/gotson/komga/commits/0bd8edb))
|
||||
- bump axios from 1.15.0 to 1.15.2 in /komga-webui ([737cc56](https://github.com/gotson/komga/commits/737cc56))
|
||||
|
||||
**unscoped**
|
||||
- upgrade Spring Boot to 3.5.14 ([3d7615e](https://github.com/gotson/komga/commits/3d7615e))
|
||||
|
||||
# [1.24.4](https://github.com/gotson/komga/compare/1.24.3...1.24.4) (2026-04-24)
|
||||
## 🐛 Fixes
|
||||
**api**
|
||||
- omit UserDto.ageRestriction instead of returning null ([e3a8cc6](https://github.com/gotson/komga/commits/e3a8cc6))
|
||||
|
||||
**epub**
|
||||
- some TOC may not be parsed correctly ([5fc0b7e](https://github.com/gotson/komga/commits/5fc0b7e))
|
||||
|
||||
**kobo**
|
||||
- proxy raw request body to kobo store ([4a7d9a6](https://github.com/gotson/komga/commits/4a7d9a6)), closes [#2289](https://github.com/gotson/komga/issues/2289)
|
||||
|
||||
**koreader**
|
||||
- also accept application/json on Accept header ([ddfe65d](https://github.com/gotson/komga/commits/ddfe65d))
|
||||
|
||||
**opds2**
|
||||
- incorrect latest series navigation links ([717ef82](https://github.com/gotson/komga/commits/717ef82)), closes [#2285](https://github.com/gotson/komga/issues/2285)
|
||||
- auth logo issue when using base url ([7c00661](https://github.com/gotson/komga/commits/7c00661)), closes [#2285](https://github.com/gotson/komga/issues/2285)
|
||||
|
||||
## 🛠 Build
|
||||
**docker**
|
||||
- update base image to Ubuntu 26.04 for amd64 and arm64 ([5d14057](https://github.com/gotson/komga/commits/5d14057))
|
||||
|
||||
**webui**
|
||||
- update Browserslist db ([7e0d680](https://github.com/gotson/komga/commits/7e0d680))
|
||||
|
||||
**unscoped**
|
||||
- update homebrew action ([6c2621b](https://github.com/gotson/komga/commits/6c2621b))
|
||||
|
||||
## ⚙️ Dependencies
|
||||
**ci**
|
||||
- bump gradle/actions from 5 to 6 ([3ca9806](https://github.com/gotson/komga/commits/3ca9806))
|
||||
|
||||
**webui**
|
||||
- bump @xmldom/xmldom from 0.8.12 to 0.8.13 in /komga-webui ([bb60a79](https://github.com/gotson/komga/commits/bb60a79))
|
||||
- bump axios from 1.13.5 to 1.15.0 in /komga-webui ([85edd8b](https://github.com/gotson/komga/commits/85edd8b))
|
||||
- bump follow-redirects in /komga-webui ([63de6aa](https://github.com/gotson/komga/commits/63de6aa))
|
||||
- bump lodash from 4.17.23 to 4.18.1 in /komga-webui ([b77554f](https://github.com/gotson/komga/commits/b77554f))
|
||||
- bump @xmldom/xmldom from 0.8.10 to 0.8.12 in /komga-webui ([5620e3f](https://github.com/gotson/komga/commits/5620e3f))
|
||||
- bump brace-expansion from 1.1.12 to 1.1.13 in /komga-webui ([263d3dd](https://github.com/gotson/komga/commits/263d3dd))
|
||||
|
||||
**unscoped**
|
||||
- bump gradle-git-properties plugin from 2.5.2 to 2.5.7 ([dd9c3fa](https://github.com/gotson/komga/commits/dd9c3fa))
|
||||
|
||||
# [1.24.3](https://github.com/gotson/komga/compare/1.24.2...1.24.3) (2026-03-27)
|
||||
## 🐛 Fixes
|
||||
**webui**
|
||||
- epub reader would not load ([b8ea79e](https://github.com/gotson/komga/commits/b8ea79e))
|
||||
|
||||
## ⚙️ Dependencies
|
||||
**webui**
|
||||
- bump node-forge from 1.3.2 to 1.4.0 in /komga-webui ([40dadcb](https://github.com/gotson/komga/commits/40dadcb))
|
||||
|
||||
# [1.24.2](https://github.com/gotson/komga/compare/1.24.1...1.24.2) (2026-03-26)
|
||||
## 🐛 Fixes
|
||||
**docker**
|
||||
- remove anonymous /tmp volume ([45f39b0](https://github.com/gotson/komga/commits/45f39b0)), closes [#2191](https://github.com/gotson/komga/issues/2191)
|
||||
|
||||
**epub**
|
||||
- fallback on epub2 toc if epub3 is present but invalid ([4ce8f27](https://github.com/gotson/komga/commits/4ce8f27))
|
||||
|
||||
**unscoped**
|
||||
- epub extension could get lost during book restoration ([90d3a1d](https://github.com/gotson/komga/commits/90d3a1d))
|
||||
|
||||
## 🔄️ Changes
|
||||
**docker**
|
||||
- fix small warnings when builing ([bcc4438](https://github.com/gotson/komga/commits/bcc4438))
|
||||
|
||||
## 🛠 Build
|
||||
**webui**
|
||||
- update Browserslist db ([de849a5](https://github.com/gotson/komga/commits/de849a5))
|
||||
- update Browserslist db ([6305cae](https://github.com/gotson/komga/commits/6305cae))
|
||||
|
||||
## 📝 Documentation
|
||||
|
||||
- rename sponsors ([034ab23](https://github.com/gotson/komga/commits/034ab23))
|
||||
|
||||
## 🌐 Translation
|
||||
**webui**
|
||||
- translated using Weblate (Chinese (Simplified Han script)) ([da981be](https://github.com/gotson/komga/commits/da981be))
|
||||
- translated using Weblate (Korean) ([92a61de](https://github.com/gotson/komga/commits/92a61de))
|
||||
- translated using Weblate (Croatian) ([c00aaeb](https://github.com/gotson/komga/commits/c00aaeb))
|
||||
- translated using Weblate (Bulgarian) ([0013a65](https://github.com/gotson/komga/commits/0013a65))
|
||||
- translated using Weblate (German) ([df5e90e](https://github.com/gotson/komga/commits/df5e90e))
|
||||
- translated using Weblate (Portuguese (Brazil)) ([c79008d](https://github.com/gotson/komga/commits/c79008d))
|
||||
- translated using Weblate (Tamil) ([4fa9422](https://github.com/gotson/komga/commits/4fa9422))
|
||||
|
||||
## ⚙️ Dependencies
|
||||
**ci**
|
||||
- bump hydraulic-software/conveyor from 21.1 to 22.0 ([de25e49](https://github.com/gotson/komga/commits/de25e49))
|
||||
- bump EndBug/add-and-commit from 9 to 10 ([b91919a](https://github.com/gotson/komga/commits/b91919a))
|
||||
- bump docker/setup-buildx-action from 3 to 4 ([a584f4c](https://github.com/gotson/komga/commits/a584f4c))
|
||||
- bump docker/login-action from 3 to 4 ([25ccf5a](https://github.com/gotson/komga/commits/25ccf5a))
|
||||
- bump docker/setup-qemu-action from 3 to 4 ([30ed015](https://github.com/gotson/komga/commits/30ed015))
|
||||
- bump actions/upload-artifact from 6 to 7 ([dfdcd08](https://github.com/gotson/komga/commits/dfdcd08))
|
||||
|
||||
**webui**
|
||||
- bump picomatch from 2.3.1 to 2.3.2 in /komga-webui ([457a724](https://github.com/gotson/komga/commits/457a724))
|
||||
- bump flatted from 3.2.7 to 3.4.2 in /komga-webui ([7ad2bd5](https://github.com/gotson/komga/commits/7ad2bd5))
|
||||
- bump yauzl and r2-utils-js in /komga-webui ([322cf23](https://github.com/gotson/komga/commits/322cf23))
|
||||
- bump svgo from 2.8.0 to 2.8.2 in /komga-webui ([fd84125](https://github.com/gotson/komga/commits/fd84125))
|
||||
- bump immutable from 4.3.4 to 4.3.8 in /komga-webui ([112c442](https://github.com/gotson/komga/commits/112c442))
|
||||
- bump minimatch in /komga-webui ([8b542b8](https://github.com/gotson/komga/commits/8b542b8))
|
||||
- bump ajv from 6.12.6 to 6.14.0 in /komga-webui ([7e83afd](https://github.com/gotson/komga/commits/7e83afd))
|
||||
- bump qs from 6.14.1 to 6.14.2 in /komga-webui ([3d52eab](https://github.com/gotson/komga/commits/3d52eab))
|
||||
- bump axios from 1.12.0 to 1.13.5 in /komga-webui ([22fdc2e](https://github.com/gotson/komga/commits/22fdc2e))
|
||||
- bump webpack from 5.94.0 to 5.105.0 in /komga-webui ([0400b8f](https://github.com/gotson/komga/commits/0400b8f))
|
||||
|
||||
# [1.24.1](https://github.com/gotson/komga/compare/1.24.0...1.24.1) (2026-01-29)
|
||||
## 🐛 Fixes
|
||||
**epub**
|
||||
- more lenient fixed-layout detection ([4f94365](https://github.com/gotson/komga/commits/4f94365))
|
||||
|
||||
## 🌐 Translation
|
||||
**webui**
|
||||
- translated using Weblate (Chinese (Simplified Han script)) ([80e5432](https://github.com/gotson/komga/commits/80e5432))
|
||||
- translated using Weblate (Swedish) ([7e2798b](https://github.com/gotson/komga/commits/7e2798b))
|
||||
- translated using Weblate (Russian) ([deece74](https://github.com/gotson/komga/commits/deece74))
|
||||
- translated using Weblate (German) ([f990b9a](https://github.com/gotson/komga/commits/f990b9a))
|
||||
- translated using Weblate (Galician) ([ecf6708](https://github.com/gotson/komga/commits/ecf6708))
|
||||
|
||||
# [1.24.0](https://github.com/gotson/komga/compare/1.23.6...1.24.0) (2026-01-28)
|
||||
## 🚀 Features
|
||||
**api**
|
||||
- add heartbeat event to SSE connections ([512492b](https://github.com/gotson/komga/commits/512492b)), closes [#2205](https://github.com/gotson/komga/issues/2205)
|
||||
|
||||
**unscoped**
|
||||
- support epub with images in spine ([525b37f](https://github.com/gotson/komga/commits/525b37f))
|
||||
|
||||
## 🛠 Build
|
||||
**webui**
|
||||
- update Browserslist db ([e6560e0](https://github.com/gotson/komga/commits/e6560e0))
|
||||
- update Browserslist db ([361d20d](https://github.com/gotson/komga/commits/361d20d))
|
||||
|
||||
## ⚙️ Dependencies
|
||||
**ci**
|
||||
- bump hydraulic-software/conveyor from 21.0 to 21.1 ([2ff8ea1](https://github.com/gotson/komga/commits/2ff8ea1))
|
||||
- bump actions/upload-artifact from 5 to 6 ([4911cc8](https://github.com/gotson/komga/commits/4911cc8))
|
||||
- bump dessant/lock-threads from 5 to 6 ([2e268b4](https://github.com/gotson/komga/commits/2e268b4))
|
||||
- bump hydraulic-software/conveyor from 20.0 to 21.0 ([7d1c9b8](https://github.com/gotson/komga/commits/7d1c9b8))
|
||||
|
||||
**webui**
|
||||
- bump lodash from 4.17.21 to 4.17.23 in /komga-webui ([a4958b0](https://github.com/gotson/komga/commits/a4958b0))
|
||||
- bump qs from 6.13.0 to 6.14.1 in /komga-webui ([13761f6](https://github.com/gotson/komga/commits/13761f6))
|
||||
- update package name for isbn-verify ([62b4154](https://github.com/gotson/komga/commits/62b4154))
|
||||
|
||||
# [1.23.6](https://github.com/gotson/komga/compare/1.23.5...1.23.6) (2025-11-28)
|
||||
## 🐛 Fixes
|
||||
**kobo**
|
||||
- proxy 401 errors on initialization ([3739951](https://github.com/gotson/komga/commits/3739951))
|
||||
- prevent double URL encoding when proxying ([ce3ad4c](https://github.com/gotson/komga/commits/ce3ad4c)), closes [#2130](https://github.com/gotson/komga/issues/2130)
|
||||
- proxy Content-Type headers for kobo ([b925f3e](https://github.com/gotson/komga/commits/b925f3e)), closes [#2074](https://github.com/gotson/komga/issues/2074)
|
||||
|
||||
**unscoped**
|
||||
- properly decode cover href when generating epub cover ([f8ca936](https://github.com/gotson/komga/commits/f8ca936)), closes [#2118](https://github.com/gotson/komga/issues/2118)
|
||||
|
||||
## 🔄️ Changes
|
||||
**kobo**
|
||||
- log error responses ([454c6c7](https://github.com/gotson/komga/commits/454c6c7))
|
||||
|
||||
## 🛠 Build
|
||||
**docker**
|
||||
- use old-releases apt repo ([ba7b826](https://github.com/gotson/komga/commits/ba7b826))
|
||||
|
||||
**webui**
|
||||
- update Browserslist db ([727fe39](https://github.com/gotson/komga/commits/727fe39))
|
||||
|
||||
**unscoped**
|
||||
- fix svu install ([9a56b30](https://github.com/gotson/komga/commits/9a56b30))
|
||||
|
||||
## 📝 Documentation
|
||||
**api**
|
||||
- fix mediatype ([af66144](https://github.com/gotson/komga/commits/af66144))
|
||||
|
||||
## 🌐 Translation
|
||||
**komga-tray**
|
||||
- translated using Weblate (Arabic) ([a5548a5](https://github.com/gotson/komga/commits/a5548a5))
|
||||
- translated using Weblate (Russian) ([8f8d20a](https://github.com/gotson/komga/commits/8f8d20a))
|
||||
- translated using Weblate (Galician) ([0f69a3a](https://github.com/gotson/komga/commits/0f69a3a))
|
||||
|
||||
**webui**
|
||||
- translated using Weblate (Croatian) ([dde0169](https://github.com/gotson/komga/commits/dde0169))
|
||||
- translated using Weblate (Russian) ([a2ed7d3](https://github.com/gotson/komga/commits/a2ed7d3))
|
||||
- translated using Weblate (Portuguese (Brazil)) ([475f026](https://github.com/gotson/komga/commits/475f026))
|
||||
- translated using Weblate (Thai) ([a03f1bd](https://github.com/gotson/komga/commits/a03f1bd))
|
||||
|
||||
## ⚙️ Dependencies
|
||||
**ci**
|
||||
- bump actions/checkout from 5 to 6 ([f138fe3](https://github.com/gotson/komga/commits/f138fe3))
|
||||
- bump mikepenz/action-junit-report from 5 to 6 ([6b07fda](https://github.com/gotson/komga/commits/6b07fda))
|
||||
- bump actions/upload-artifact from 4 to 5 ([fe40ede](https://github.com/gotson/komga/commits/fe40ede))
|
||||
- bump actions/setup-node from 5 to 6 ([c23f2d3](https://github.com/gotson/komga/commits/c23f2d3))
|
||||
|
||||
**webui**
|
||||
- bump node-forge from 1.3.1 to 1.3.2 in /komga-webui ([0f25453](https://github.com/gotson/komga/commits/0f25453))
|
||||
- bump js-yaml from 3.14.1 to 3.14.2 in /komga-webui ([cd47fc7](https://github.com/gotson/komga/commits/cd47fc7))
|
||||
|
||||
# [1.23.5](https://github.com/gotson/komga/compare/1.23.4...1.23.5) (2025-10-08)
|
||||
## 🚀 Features
|
||||
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ Check the [development guidelines](./DEVELOPING.md).
|
|||
|
||||
[](https://hosted.weblate.org/engage/komga/)
|
||||
|
||||
## Sponsors
|
||||
## Powered by
|
||||
|
||||
[](https://www.jetbrains.com/?from=Komga)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,2 +1,2 @@
|
|||
version=1.23.5
|
||||
version=1.25.0
|
||||
org.gradle.jvmargs=-Xmx2G
|
||||
|
|
|
|||
|
|
@ -2,9 +2,9 @@
|
|||
sqliteJdbc = "3.50.2.0"
|
||||
nightmonkeys = "1.0.0"
|
||||
twelvemonkeys = "3.12.0"
|
||||
springboot = "3.5.4"
|
||||
springboot = "3.5.14"
|
||||
lucene = "9.9.1" # v10 requires JDK 21
|
||||
jooq = "3.19.24" # should be aligned with the version provided by Spring Boot
|
||||
jooq = "3.19.32" # should be aligned with the version provided by Spring Boot
|
||||
|
||||
[plugins]
|
||||
gradleGitProperties = {id = "com.gorylenko.gradle-git-properties", version = "2.5.2"}
|
||||
gradleGitProperties = {id = "com.gorylenko.gradle-git-properties", version = "2.5.7"}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
dialog_error.close=إغلاق
|
||||
dialog_error.copy_clipboard=النسخ إلى الحافظة
|
||||
dialog_error.title=Komga لم يقدر على البدء
|
||||
error_message.port_in_use=الباب {} على قيد الاستعمال.\nربما Komga جارٍ بالفعل.\nتحقق أيقونة علبة النظام أو القائمة لأيقونة Komga.
|
||||
error_message.unexpected=حصل خطأ غير متوقع.
|
||||
menu.open_komga=فتح Komga
|
||||
menu.quit=إغلاق Komga
|
||||
menu.show_conf_dir=فتح موقع الإعدادات
|
||||
menu.show_log=إظهار ملف السجل
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
dialog_error.close=Pechar
|
||||
dialog_error.copy_clipboard=Copiar ao portapapeis
|
||||
dialog_error.title=Komga fallou ao iniciar
|
||||
error_message.port_in_use=O porto {} está en uso.\nÉ probable que Komga xa esté a executarse.\nBusca a icona de Komga na bandexa de sistema ou a barra de menú.
|
||||
error_message.unexpected=Aconteceu un erro imprevisto.
|
||||
menu.open_komga=Abrir Komga
|
||||
menu.quit=Saír de Komga
|
||||
menu.show_conf_dir=Abrir o cartafol de configuración
|
||||
menu.show_log=Amosar o ficheiro de rexistro
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
dialog_error.close=Закрыть
|
||||
dialog_error.copy_clipboard=Скопировать в буфер обмена
|
||||
dialog_error.title=Komga не смог запуститься
|
||||
error_message.port_in_use=Порт {] уже используется.\nKomga возможно уже работает.\nПроверьте панель задач или меню на наличие иконки Komga.
|
||||
dialog_error.title=Komga не удалось запустить
|
||||
error_message.port_in_use=Порт {} уже используется.\nВероятно, Komga уже запущен.\nПроверьте область уведомлений или панель меню на наличие иконки Komga.
|
||||
error_message.unexpected=Произошла непредвиденная ошибка.
|
||||
menu.open_komga=Открыть Komga
|
||||
menu.quit=Закрыть Komga
|
||||
|
|
|
|||
3137
komga-webui/package-lock.json
generated
3137
komga-webui/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -10,17 +10,17 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@d-i-t-a/reader": "github:gotson/R2D2BC#fork",
|
||||
"@saekitominaga/isbn-verify": "^2.0.1",
|
||||
"axios": "^1.12.0",
|
||||
"@w0s/isbn-verify": "^3.1.2",
|
||||
"axios": "^1.16.0",
|
||||
"chart.js": "^2.9.4",
|
||||
"core-js": "^3.8.3",
|
||||
"date-fns": "^2.30.0",
|
||||
"filesize": "^10.0.12",
|
||||
"js-file-downloader": "^1.1.25",
|
||||
"language-tags": "^1.0.9",
|
||||
"lodash": "^4.17.21",
|
||||
"lodash": "^4.18.1",
|
||||
"marked": "^15.0.4",
|
||||
"qs": "^6.11.2",
|
||||
"qs": "^6.15.2",
|
||||
"screenfull": "^5.2.0",
|
||||
"vue": "^2.6.14",
|
||||
"vue-chartkick": "^0.6.1",
|
||||
|
|
|
|||
|
|
@ -200,7 +200,7 @@
|
|||
<script lang="ts">
|
||||
import Vue from 'vue'
|
||||
import {BookDto} from '@/types/komga-books'
|
||||
import IsbnVerify from '@saekitominaga/isbn-verify'
|
||||
import IsbnVerify from '@w0s/isbn-verify'
|
||||
import {isMatch} from 'date-fns'
|
||||
import {ERROR} from '@/types/events'
|
||||
|
||||
|
|
|
|||
|
|
@ -430,7 +430,7 @@ import {authorRoles} from '@/types/author-roles'
|
|||
import Vue from 'vue'
|
||||
import {helpers, requiredIf} from 'vuelidate/lib/validators'
|
||||
import {BookDto, BookThumbnailDto} from '@/types/komga-books'
|
||||
import IsbnVerify from '@saekitominaga/isbn-verify'
|
||||
import IsbnVerify from '@w0s/isbn-verify'
|
||||
import {isMatch} from 'date-fns'
|
||||
import {debounce} from 'lodash'
|
||||
import {ERROR, ErrorEvent} from '@/types/events'
|
||||
|
|
|
|||
|
|
@ -570,7 +570,7 @@ import DropZone from '@/components/DropZone.vue'
|
|||
import ThumbnailCard from '@/components/ThumbnailCard.vue'
|
||||
import {BookDto, BookThumbnailDto} from '@/types/komga-books'
|
||||
import {isMatch} from 'date-fns'
|
||||
import IsbnVerify from '@saekitominaga/isbn-verify'
|
||||
import IsbnVerify from '@w0s/isbn-verify'
|
||||
import {debounce} from 'lodash'
|
||||
import {authorRoles} from '@/types/author-roles'
|
||||
import {groupAuthorsByRole} from '@/functions/authors'
|
||||
|
|
|
|||
|
|
@ -19,7 +19,15 @@
|
|||
},
|
||||
"account_settings": {
|
||||
"account_settings": "إعدادات الحساب",
|
||||
"change_password": "تغيير كلمة السر"
|
||||
"api_key": {
|
||||
"created_date": "تاريخ الصنع: {date}",
|
||||
"force_kobo_sync": "إجبار مزامنة Kobo",
|
||||
"generate_api_key": "توليد مفتاح API",
|
||||
"no_keys": "لم يخلق مفتاح API بعد"
|
||||
},
|
||||
"change_password": "تغيير كلمة السر",
|
||||
"details": "تفاصيل",
|
||||
"my_account": "حسابي"
|
||||
},
|
||||
"announcements": {
|
||||
"mark_all_read": "اشر عليها بانها قرأت",
|
||||
|
|
@ -27,6 +35,7 @@
|
|||
"tab_title": "إعلانات"
|
||||
},
|
||||
"authentication_activity": {
|
||||
"api_key": "مفتاح API",
|
||||
"datetime": "التاريخ والوقت",
|
||||
"email": "البريد الإلكتروني",
|
||||
"error": "خطأ",
|
||||
|
|
@ -85,7 +94,8 @@
|
|||
"bookreader": {
|
||||
"beginning_of_book": "أنت في بداية الكتاب.",
|
||||
"changing_reading_direction": "تغيير اتجاه القراءة إلى",
|
||||
"cycling_page_layout": "تخطيط دوري للصفحة",
|
||||
"cycling_page_layout": "تغيير تخطيط الصفحة",
|
||||
"cycling_page_margin": "تغيير هامش الصفحة",
|
||||
"cycling_scale": "تغيير حجم التحرير",
|
||||
"cycling_side_padding": "تغيير الحدود الجانبية",
|
||||
"download_current_page": "تنزيل الصفحة الحالية",
|
||||
|
|
@ -128,6 +138,7 @@
|
|||
"general": "إعدادات عامة",
|
||||
"gestures": "الإيماءات",
|
||||
"page_layout": "تخطيط الصفحة",
|
||||
"page_margin": "هامش الصفحة",
|
||||
"paged": "خيارات القارئ المرقم",
|
||||
"reading_mode": "وضع القراءة",
|
||||
"scale_type": "نوع القياس",
|
||||
|
|
@ -137,8 +148,9 @@
|
|||
},
|
||||
"shortcuts": {
|
||||
"close": "إغلاق",
|
||||
"cycle_page_layout": "دورة تخطيط الصفحة",
|
||||
"cycle_scale": "مقياس الدورة",
|
||||
"cycle_page_layout": "تغيير تخطيط الصفحة",
|
||||
"cycle_page_margin": "تغيير هامش الصفحة",
|
||||
"cycle_scale": "تغيير الحجم",
|
||||
"cycle_side_padding": "تغيير الحدود الجانبية",
|
||||
"first_page": "الصفحة الأولى",
|
||||
"fullscreen": "إدخال/إنهاء ملء الشاشة",
|
||||
|
|
@ -161,6 +173,8 @@
|
|||
},
|
||||
"browse_book": {
|
||||
"comment": "تعليق",
|
||||
"date_created": "صُنِع",
|
||||
"date_modified": "آخر تعديل",
|
||||
"download_file": "تحميل الملف",
|
||||
"file": "ملف",
|
||||
"format": "صيغة",
|
||||
|
|
@ -170,6 +184,8 @@
|
|||
"outdated_tooltip": "تم تغيير ملف هذا الكتاب ، يجب إعادة تحليل هذا الكتاب",
|
||||
"read_book": "قراءة كتاب",
|
||||
"read_incognito": "قراءة التصفح المتخفي",
|
||||
"remove_from_collection": "إزالة الكتاب من المجموعة",
|
||||
"remove_from_readlist": "إزالة الكتاب من قائمة القراءة",
|
||||
"size": "حجم"
|
||||
},
|
||||
"browse_collection": {
|
||||
|
|
@ -184,6 +200,7 @@
|
|||
},
|
||||
"browse_series": {
|
||||
"earliest_year_from_release_dates": "هذه هي السنة الأولى من تواريخ الإصدار لجميع الكتب في السلسلة",
|
||||
"remove_from_collection": "إزالة السلسلة من المجموعة",
|
||||
"series_no_summary": "هذه السلسلة لا تحتوي على ملخص ، لذلك اخترنا واحدًا لك!",
|
||||
"summary_from_book": "ملخص من الكتاب {number}:"
|
||||
},
|
||||
|
|
@ -194,6 +211,8 @@
|
|||
"common": {
|
||||
"age": "العمر",
|
||||
"all_libraries": "كل المكتبات",
|
||||
"all_of": "كل من",
|
||||
"any_of": "أي من",
|
||||
"book": "كتاب",
|
||||
"books": "كتب",
|
||||
"books_n": "لا يوجد كتاب | 1 كتاب | {count} كتب",
|
||||
|
|
@ -203,15 +222,19 @@
|
|||
"choose_image": "اختر صورة",
|
||||
"close": "إغلاق",
|
||||
"collections": "المجموعات",
|
||||
"copied": "تم النسخ!",
|
||||
"create": "صنع",
|
||||
"delete": "حذف",
|
||||
"discard": "تجاهل",
|
||||
"dimension": "ع:{width}, ط:{height}",
|
||||
"discard": "تخلص",
|
||||
"disk_space": "مساحة القرص",
|
||||
"dismiss": "رفض",
|
||||
"download": "تحميل",
|
||||
"drag_drop": "أمسك واسحب",
|
||||
"duplicate": "مكرر",
|
||||
"email": "البريد الإلكتروني",
|
||||
"epub": "Epub",
|
||||
"epub": "EPUB",
|
||||
"error": "خطأ",
|
||||
"filename": "اسم الملف",
|
||||
"filter_no_matches": "الفلتر النشط ليس له تطابق",
|
||||
"genre": "نوع",
|
||||
|
|
@ -219,13 +242,17 @@
|
|||
"go_to_library": "اذهب إلى المكتبة",
|
||||
"go_to_readlist": "انتقل إلى قائمة القراءة",
|
||||
"go_to_series": "الانتقال إلى السلسلة",
|
||||
"i_understand": "فهمت",
|
||||
"library": "مكتبة",
|
||||
"locale_name": "العربية",
|
||||
"locale_rtl": "true",
|
||||
"lock_all": "قفل الكل",
|
||||
"media": "الوسائط",
|
||||
"more": "المزيد",
|
||||
"n_selected": "{count} مختار",
|
||||
"nothing_to_show": "لا شيء للعرض",
|
||||
"oneshot": "طلقة واحدة",
|
||||
"ok": "حسنا",
|
||||
"oneshot": "قصة منفردة",
|
||||
"outdated": "متقادمة",
|
||||
"page": "صفحة",
|
||||
"page_number": "رقم الصفحة",
|
||||
|
|
@ -235,19 +262,23 @@
|
|||
"password": "كلمة السر",
|
||||
"pdf": "PDF",
|
||||
"pending_tasks": "لا توجد مهام معلقة | مهمة واحدة معلقة | {count} مهام معلقة",
|
||||
"pinned_libraries": "المكتبات المثبتة",
|
||||
"publisher": "الناشر",
|
||||
"read": "اقرأ",
|
||||
"read_on": "قرأ في {date}",
|
||||
"readlist": "قائمة القراءة",
|
||||
"readlists": "قوائم القراءة",
|
||||
"remember-me": "تذكرني",
|
||||
"reorder": "تغيير الترتيب",
|
||||
"required": "مطلوب",
|
||||
"reset_filters": "إعادة تعيين فلتر",
|
||||
"roles": "أدوار",
|
||||
"save_changes": "حفظ التغييرات",
|
||||
"series": "سلسلة",
|
||||
"settings": "الإعدادات",
|
||||
"sidecars": "Sidecars",
|
||||
"tags": "التصنيف",
|
||||
"ui": "واجهة المستخدم",
|
||||
"unavailable": "غير متوفر",
|
||||
"unlock_all": "فتح الكل",
|
||||
"url": "عنوان URL",
|
||||
|
|
@ -271,10 +302,11 @@
|
|||
"comicrack_preambule_html": "يمكنك استيراد قوائم قراءة ComicRack الحالية بتنسيق <code>cbl</code>.<br>سيحاول Komga مطابقة السلسلة ورقم الكتاب المقدمين مع السلسلة والكتب في مكتباتك.",
|
||||
"dialog_confirmation": {
|
||||
"body": "{unmatched} / {total} الكتب غير متطابقة",
|
||||
"body2": "{duplicates} / {total} كتاب مكرر",
|
||||
"create": "الخلق على أي حال",
|
||||
"title": "بعض الكتب لا تتطابق"
|
||||
},
|
||||
"field_file_label": "ComicRack Reading List (.cbl)",
|
||||
"field_file_label": "قائمة قراءة ComicRack (من نوع cbl.)",
|
||||
"field_files_label": "قوائم القراءة ComicRack (.cbl)",
|
||||
"import_read_lists": "استيراد قوائم القراءة",
|
||||
"imported_as": "مستورد كـ {name}",
|
||||
|
|
@ -286,6 +318,14 @@
|
|||
"tab_title": "استيراد البيانات"
|
||||
},
|
||||
"dialog": {
|
||||
"add_api_key": {
|
||||
"button_confirm": "توليد",
|
||||
"context": "يمكن استعمال مفاتيح الAPI للتوثيق عبر بروتوكول Kobo Sync.",
|
||||
"dialog_title": "توليد مفتاح API جديد",
|
||||
"field_comment": "تعليق",
|
||||
"field_comment_hint": "ما الغرض من مفتاح الAPI هذا؟",
|
||||
"info_copy": "يرجى التأكد من نسخ مفتاح الAPI الآن. لا يستطاع النظر عليه مجددا!"
|
||||
},
|
||||
"add_to_collection": {
|
||||
"button_create": "خلق",
|
||||
"card_collection_subtitle": "لا توجد سلسلة | 1 سلسلة | {count} سلسلة",
|
||||
|
|
@ -319,6 +359,12 @@
|
|||
"filter": "مصنف حسب رقم الكتاب أو العنوان أو تاريخ الإصدار",
|
||||
"title": "حدد كتاب"
|
||||
},
|
||||
"delete_apikey": {
|
||||
"button_confirm": "حذف",
|
||||
"confirm_delete": "فهمت, حذف مفتاح الAPI المسمى {name}",
|
||||
"dialog_title": "حذف مفتاح الAPI",
|
||||
"warning_html": "كل التطبيقات التي تستعمل مفتاح الAPI هذا ستصبح غير قادرة على الوصول إلى الAPI التابع لKomga. لا يمكن التراجع عن هذا الإجراء."
|
||||
},
|
||||
"delete_book": {
|
||||
"button_confirm": "حذف",
|
||||
"confirm_delete": "نعم، حذف كتاب \"{name}\" وملفاته",
|
||||
|
|
@ -389,6 +435,8 @@
|
|||
"field_summary": "ملخص",
|
||||
"field_tags": "التصنيف",
|
||||
"field_title": "العنوان",
|
||||
"number_sort_decrement": "تقليل الجميع ب1",
|
||||
"number_sort_increment": "زيادة الجميع ب1",
|
||||
"tab_authors": "المؤلفون",
|
||||
"tab_general": "إعدادات عامة",
|
||||
"tab_links": "الروابط",
|
||||
|
|
@ -415,6 +463,7 @@
|
|||
"dialot_title_edit": "تحرير المكتبة",
|
||||
"field_analysis_analyze_dimensions": "تحليل أبعاد الصفحات",
|
||||
"field_analysis_hash_files": "حساب تجزئة للملفات",
|
||||
"field_analysis_hash_koreader": "حسابة التلبيد لملفات KOReader",
|
||||
"field_analysis_hash_pages": "حساب تجزئة الصفحات",
|
||||
"field_convert_to_cbz": "تحويل تلقائيا إلى CBZ",
|
||||
"field_import_barcode_isbn": "الباركود ردمك",
|
||||
|
|
@ -422,15 +471,19 @@
|
|||
"field_import_comicinfo_collections": "المجموعات",
|
||||
"field_import_comicinfo_readlists": "قوائم القراءة",
|
||||
"field_import_comicinfo_series": "سلسلة البيانات الوصفية",
|
||||
"field_import_comicinfo_series_append_volume": "إضافة المجلد إلى عنوان المسلسل",
|
||||
"field_import_epub_book": "البيانات الوصفية للكتاب",
|
||||
"field_import_epub_series": "سلسلة البيانات الوصفية",
|
||||
"field_import_local_artwork": "الأعمال الفنية المحلية",
|
||||
"field_import_mylar_series": "سلسلة البيانات الوصفية",
|
||||
"field_name": "الاسم",
|
||||
"field_oneshotsdirectory": "موقع القصص المنفردة",
|
||||
"field_repair_extensions": "إصلاح ملحقات الملفات غير الصحيحة تلقائيًا",
|
||||
"field_root_folder": "المجلد الرئيسي",
|
||||
"field_scan_interval": "تكرار البحث عن الملفات",
|
||||
"field_scanner_empty_trash_after_scan": "تفريغ المهملات تلقائيا بعد كل فحص",
|
||||
"field_scanner_force_directory_modified_time": "فرض وقت تعديل الدليل",
|
||||
"field_scanner_scan_startup": "البحث عن الملفات عند بدء البرنامج",
|
||||
"field_series_cover": "غلاف السلسلة",
|
||||
"file_browser_dialog_button_confirm": "إختيار",
|
||||
"file_browser_dialog_title": "المجلد الجذر للمكتبة",
|
||||
|
|
@ -441,11 +494,14 @@
|
|||
"label_import_epub": "استيراد البيانات الوصفية من ملفات EPUB",
|
||||
"label_import_local": "استيراد أصول الوسائط المحلية",
|
||||
"label_import_mylar": "استيراد البيانات الوصفية التي تم إنشاؤها بواسطة Mylar",
|
||||
"label_scan_directory_exclusions": "استبعاد المواقع",
|
||||
"label_scan_types": "البحث عن أنواع الملفات هذه",
|
||||
"label_scanner": "الماسح الضوئي",
|
||||
"label_series_cover": "غلاف السلسلة",
|
||||
"tab_general": "إعدادات عامة",
|
||||
"tab_metadata": "البيانات الوصفية",
|
||||
"tab_options": "الخيارات",
|
||||
"tooltip_oneshotsdirectory": "يترك فارغا للتعطيل",
|
||||
"tooltip_scanner_force_modified_time": "تمكين إذا كانت المكتبة على Google Drive",
|
||||
"tooltip_use_resources": "يمكن أن تستهلك الكثير من الموارد في مكتبات كبيرة أو أجهزة بطيئة"
|
||||
},
|
||||
|
|
@ -453,11 +509,16 @@
|
|||
"button_cancel": "إلغاء",
|
||||
"button_confirm": "حفظ التغييرات",
|
||||
"dialog_title": "تحرير قائمة القراءة",
|
||||
"field_manual_ordering": "ترتيب يدوي",
|
||||
"field_name": "الاسم",
|
||||
"field_summary": "ملخص",
|
||||
"tab_general": "عام",
|
||||
"tab_poster": "ملصق"
|
||||
},
|
||||
"edit_recommended": {
|
||||
"button_confirm": "حفظ التعديلات",
|
||||
"button_reset": "الإعادة إلى التعديلات الأصلية"
|
||||
},
|
||||
"edit_series": {
|
||||
"button_cancel": "إلغاء",
|
||||
"button_confirm": "حفظ التغييرات",
|
||||
|
|
@ -483,6 +544,7 @@
|
|||
"tab_poster": "ملصق",
|
||||
"tab_sharing": "مشاركة",
|
||||
"tab_tags": "التصنيف",
|
||||
"tab_titles": "العناوين البديلة",
|
||||
"tags_notice_multiple_edit": "أنت تقوم بتحرير العلامات لسلسلة متعددة. سيؤدي هذا إلى تجاوز العلامات الموجودة في كل سلسلة."
|
||||
},
|
||||
"edit_user": {
|
||||
|
|
@ -525,6 +587,9 @@
|
|||
},
|
||||
"title": "اسم الوجهة"
|
||||
},
|
||||
"force_kobo_sync": {
|
||||
"dialog_title": "إجبار مزامنة Kobo"
|
||||
},
|
||||
"password_change": {
|
||||
"button_cancel": "إلغاء",
|
||||
"button_confirm": "تغيير كلمة السر",
|
||||
|
|
@ -541,6 +606,7 @@
|
|||
},
|
||||
"series_picker": {
|
||||
"label_search_series": "سلسلة البحث",
|
||||
"no_results": "لم يتم العثور على أي سلسلة",
|
||||
"title": "اختيار سلسلة"
|
||||
},
|
||||
"server_stop": {
|
||||
|
|
@ -579,21 +645,31 @@
|
|||
}
|
||||
},
|
||||
"duplicate_pages": {
|
||||
"action_auto_delete_remaining": "باق إلغاء {count} أوتوماتيكيا",
|
||||
"action_delete_auto": "حذف تلقائي",
|
||||
"action_delete_manual": "حذف يدوي",
|
||||
"action_delete_matches": "حذف المطابقات",
|
||||
"action_ignore": "تجاهل",
|
||||
"action_ignore_remaining": "تجاهل الباقي ({count})",
|
||||
"action_manual_delete_remaining": "إلغاء الباقي يدويا ({count})",
|
||||
"delete_to_save": "حذف لحفظ {size}",
|
||||
"deleted_count": "تم حذف {count} مرة",
|
||||
"empty_title": "لم يتم العثور على صفحات مكررة",
|
||||
"empty_title_known": "لا توجد نسخ مكررة معروف عنها",
|
||||
"filter": {
|
||||
"count": "عدد",
|
||||
"date_added": "تاريخ الإضافة",
|
||||
"date_modified": "تاريخ التعديل",
|
||||
"delete_count": "عدد الحذف",
|
||||
"delete_size": "المساحة المحفوظة",
|
||||
"match_count": "عدد النتائج المتطابقة",
|
||||
"size": "حجم",
|
||||
"total_size": "الحجم الإجمالي"
|
||||
},
|
||||
"info": "حذف الصفحات المكررة سيغيّر ملفاتك. احتفظ بنسخة احتياطية من ملفاتك واستخدم الحذف اليدوي قبل استخدام الحذف التلقائي.",
|
||||
"known": "المعروفة",
|
||||
"matches_n": "لا يوجد تطابق | 1 تطابق | {count} التطابق",
|
||||
"new": "الجديدة",
|
||||
"saved_size": "حُفظ {size}",
|
||||
"title": "صفحات مكررة",
|
||||
"unknown_size": "حجم مجهول"
|
||||
|
|
@ -609,6 +685,23 @@
|
|||
"HARDLINK": "ملفات الروابط الثابتة/النسخ",
|
||||
"MOVE": "نقل الملفات"
|
||||
},
|
||||
"epubreader": {
|
||||
"appearances": {
|
||||
"day": "النهار",
|
||||
"night": "الليل",
|
||||
"sepia": "سيبيا"
|
||||
},
|
||||
"column_count": {
|
||||
"auto": "أوتوماتيكي",
|
||||
"one": "واحد",
|
||||
"two": "اثنان"
|
||||
},
|
||||
"reading_direction": {
|
||||
"auto": "أوتوماتيكي",
|
||||
"ltr": "من اليسار إلى اليمين",
|
||||
"rtl": "من اليمين إلى اليسار"
|
||||
}
|
||||
},
|
||||
"historical_event_type": {
|
||||
"BookConverted": "تمّ تحويل الكتاب",
|
||||
"BookFileDeleted": "تمّ مسح ملف الكتاب",
|
||||
|
|
@ -616,6 +709,11 @@
|
|||
"DuplicatePageDeleted": "تمّ حذف الصفحة المكررة",
|
||||
"SeriesFolderDeleted": "تمّ حذف مجلد السلسلة"
|
||||
},
|
||||
"media_profile": {
|
||||
"DIVINA": "DIVINA",
|
||||
"EPUB": "EPUB",
|
||||
"PDF": "PDF"
|
||||
},
|
||||
"media_status": {
|
||||
"ERROR": "خطأ",
|
||||
"OUTDATED": "قديمه",
|
||||
|
|
@ -634,6 +732,14 @@
|
|||
"VERTICAL": "عمودي",
|
||||
"WEBTOON": "ويبتون"
|
||||
},
|
||||
"scan_interval": {
|
||||
"DAILY": "يوميا",
|
||||
"DISABLED": "معطل",
|
||||
"EVERY_12H": "كل 12 ساعة",
|
||||
"EVERY_6H": "كل 6 ساعات",
|
||||
"HOURLY": "كل ساعة",
|
||||
"WEEKLY": "كل أسبوع"
|
||||
},
|
||||
"series_cover": {
|
||||
"FIRST": "أول",
|
||||
"LAST": "أخير"
|
||||
|
|
@ -645,6 +751,34 @@
|
|||
"ONGOING": "مستمر"
|
||||
}
|
||||
},
|
||||
"epubreader": {
|
||||
"current_chapter": "الفصل الحالي",
|
||||
"page_of": "الصفحة {page} من {count}",
|
||||
"publisher_font": "الناشر",
|
||||
"settings": {
|
||||
"column_count": "عدد أعمدة",
|
||||
"font_family": "الخط",
|
||||
"layout": "تخطيط",
|
||||
"layout_scroll": "تمرير",
|
||||
"navigation_mode": "وضع التنقل",
|
||||
"navigation_options": {
|
||||
"both": "كلاهما",
|
||||
"buttons": "أزرار",
|
||||
"click": "نقر/ضغط"
|
||||
},
|
||||
"page_margins": "هوامش الصفحة"
|
||||
},
|
||||
"shortcuts": {
|
||||
"cycle_pagination": "تغيير عدد الأعمدة",
|
||||
"font_size_decrease": "تصغير الخط",
|
||||
"font_size_increase": "تكبير الخط",
|
||||
"menus": "القائمات",
|
||||
"next": "أمام",
|
||||
"previous": "خلف",
|
||||
"settings": "الإعدادات",
|
||||
"show_hide_toc": "إظهار/إخفاء الفهرس"
|
||||
}
|
||||
},
|
||||
"error_codes": {
|
||||
"ERR_1000": "تعذر الوصول إلى الملف أثناء التحليل",
|
||||
"ERR_1001": "نوع الوسائط غير مدعوم",
|
||||
|
|
@ -667,11 +801,13 @@
|
|||
"filter": {
|
||||
"age_rating": "التصنيف العمري",
|
||||
"age_rating_none": "لا شيء",
|
||||
"any": "أي",
|
||||
"complete": "اكتمل",
|
||||
"genre": "نوع",
|
||||
"in_progress": "قيد التقدم",
|
||||
"language": "اللغة",
|
||||
"library": "المكتبة",
|
||||
"oneshot": "قصة منفردة",
|
||||
"publisher": "الناشر",
|
||||
"read": "اقرأ",
|
||||
"release_date": "تاريخ الاصدار",
|
||||
|
|
@ -699,6 +835,8 @@
|
|||
},
|
||||
"library_navigation": {
|
||||
"browse": "تصفّح",
|
||||
"browse_books": "كتب",
|
||||
"browse_series": "سلسلات",
|
||||
"collections": "المجموعات",
|
||||
"readlists": "قوائم القراءة",
|
||||
"recommended": "موصى به"
|
||||
|
|
@ -730,6 +868,7 @@
|
|||
"empty_trash": "إفراغ سلة المهملات",
|
||||
"mark_read": "تحديد كمقروء",
|
||||
"mark_unread": "تحديد كغير مقروء",
|
||||
"pin": "تثبيت",
|
||||
"refresh_metadata": "تحديث البيانات الوصفية",
|
||||
"scan_library_files": "فحص ملفات المكتبة",
|
||||
"select_all": "تحديد الكل"
|
||||
|
|
@ -745,6 +884,9 @@
|
|||
"libraries": "المكتبات",
|
||||
"logout": "تسجيل الخروج"
|
||||
},
|
||||
"no_libraries_pinned": {
|
||||
"title": "لا مكتبات مثبتة"
|
||||
},
|
||||
"page_not_found": {
|
||||
"go_back_to_home_page": "العودة إلى الصفحة الرئيسية",
|
||||
"page_does_not_exist": "الصفحة التي تبحث عنها غير موجودة.",
|
||||
|
|
@ -754,6 +896,12 @@
|
|||
"less": "أقرأ أقل",
|
||||
"more": "اقرأ أكثر"
|
||||
},
|
||||
"readlist_import": {
|
||||
"row": {
|
||||
"duplicate_book": "كتاب مكرر",
|
||||
"error_choose_book": "اختيار كتاب"
|
||||
}
|
||||
},
|
||||
"readlists_expansion_panel": {
|
||||
"manage_readlist": "إدارة قائمة القراءة",
|
||||
"title": "{name} قائمة القراءة"
|
||||
|
|
@ -775,12 +923,21 @@
|
|||
"button_empty_trash": "إفراغ سلة المهملات لكل المكتبات",
|
||||
"button_scan_libraries": "مسح جميع المكتبات",
|
||||
"button_shutdown": "إيقاف التشغيل",
|
||||
"download_log": "تحميل ملف السجل",
|
||||
"notification_tasks_cancelled": "لا يوجد مهام لإلغائها | تمّ إلغاء 1 مهمة | تمّ إلغاء {count} مهمة",
|
||||
"section_title": "إدارة الخادم"
|
||||
},
|
||||
"tab_title": "خادم"
|
||||
"tab_title": "خادم",
|
||||
"updates": "تحديثات"
|
||||
},
|
||||
"server_settings": {
|
||||
"dialog_regenerate_thumbnails": {
|
||||
"btn_alternate": "نعم، جميع الكتب",
|
||||
"btn_cancel": "لا",
|
||||
"btn_confirm": "نعم، لكن فقط إن كانت اكبر"
|
||||
},
|
||||
"label_kobo_port": "باب مزامنة Kobo الخارجي",
|
||||
"label_server_port": "باب الخادم",
|
||||
"server_settings": "إعدادات الخادم"
|
||||
},
|
||||
"settings_user": {
|
||||
|
|
@ -795,12 +952,15 @@
|
|||
"sort": {
|
||||
"books_count": "عدد الكتب",
|
||||
"date_added": "تاريخ الإضافة",
|
||||
"date_read": "تاريخ القراءة",
|
||||
"date_updated": "تاريخ التحديث",
|
||||
"file_name": "اسم الملف",
|
||||
"file_size": "حجم الملف",
|
||||
"folder_name": "اسم المجلد",
|
||||
"name": "الاسم",
|
||||
"number": "رقم",
|
||||
"page_count": "عدد الصفحات",
|
||||
"random": "عشوائي",
|
||||
"release_date": "تاريخ الإصدار"
|
||||
},
|
||||
"theme": {
|
||||
|
|
@ -818,16 +978,36 @@
|
|||
"tooltip_too_big": "الملف كبير جدًا!",
|
||||
"tooltip_user_uploaded": "تمّ الرفع بواسطة المستخدم"
|
||||
},
|
||||
"titles_more": {
|
||||
"less": "عناوين أقل",
|
||||
"more": "عناوين أكثر"
|
||||
},
|
||||
"ui_settings": {
|
||||
"general": "عام",
|
||||
"section_oauth2": "OAuth2",
|
||||
"series_groups": {
|
||||
"alpha": "ابجدي",
|
||||
"japanese": "غوجون (ياباني)"
|
||||
}
|
||||
},
|
||||
"updates": {
|
||||
"available": "توجد تحديثات"
|
||||
},
|
||||
"user_roles": {
|
||||
"ADMIN": "مدير",
|
||||
"FILE_DOWNLOAD": "تحميل الملف",
|
||||
"PAGE_STREAMING": "صفحات البث",
|
||||
"KOBO_SYNC": "مزامنة Kobo",
|
||||
"KOREADER_SYNC": "مزامنة KOReader",
|
||||
"PAGE_STREAMING": "بث الصفحات",
|
||||
"USER": "مستخدم"
|
||||
},
|
||||
"users": {
|
||||
"api_keys": "مفاتيح الAPI",
|
||||
"users": "المستخدمين"
|
||||
},
|
||||
"validation": {
|
||||
"one_or_more": "يجب أن يكون 1 أو أكثر",
|
||||
"tcp_port": "يجب أن يكون بين 1 و 65535",
|
||||
"zero_or_more": "يجب أن يكون 0 أو أكثر"
|
||||
},
|
||||
"welcome": {
|
||||
|
|
|
|||
|
|
@ -19,7 +19,15 @@
|
|||
},
|
||||
"account_settings": {
|
||||
"account_settings": "Настройки на акаунта",
|
||||
"change_password": "смени парола"
|
||||
"api_key": {
|
||||
"created_date": "Създадено на: {date}",
|
||||
"force_kobo_sync": "Принудително синхронизиране на Kobo",
|
||||
"generate_api_key": "Генерирай API ключ",
|
||||
"no_keys": "Все още няма създадени API ключове"
|
||||
},
|
||||
"change_password": "смени парола",
|
||||
"details": "Детайли",
|
||||
"my_account": "Моят акаунт"
|
||||
},
|
||||
"announcements": {
|
||||
"mark_all_read": "Отбележи всички като прочетени",
|
||||
|
|
@ -27,6 +35,7 @@
|
|||
"tab_title": "Обявления"
|
||||
},
|
||||
"authentication_activity": {
|
||||
"api_key": "API ключ",
|
||||
"datetime": "Дата Време",
|
||||
"email": "Имейл",
|
||||
"error": "Грешка",
|
||||
|
|
@ -86,6 +95,7 @@
|
|||
"beginning_of_book": "Вие сте в началото на книгата.",
|
||||
"changing_reading_direction": "Смяна на посока на четене към",
|
||||
"cycling_page_layout": "Циклиране на Подредба на Страница",
|
||||
"cycling_page_margin": "Циклични Отстояния на Станици",
|
||||
"cycling_scale": "Циклиране на Мащаб",
|
||||
"cycling_side_padding": "Циклиране на Странична Подложка",
|
||||
"download_current_page": "Свали текущата страница",
|
||||
|
|
@ -128,6 +138,7 @@
|
|||
"general": "Основни",
|
||||
"gestures": "Жестове",
|
||||
"page_layout": "Подреждане на страница",
|
||||
"page_margin": "Отстояния на Страници",
|
||||
"paged": "Опций на Странициран Четец",
|
||||
"reading_mode": "Режим на четене",
|
||||
"scale_type": "Тип мащабиране",
|
||||
|
|
@ -161,6 +172,8 @@
|
|||
},
|
||||
"browse_book": {
|
||||
"comment": "КОМЕНТАР",
|
||||
"date_created": "СЪЗДАДЕНО",
|
||||
"date_modified": "ПОСЛЕДНО ПРОМЕНЯНО",
|
||||
"download_file": "Свали файл",
|
||||
"file": "ФАЙЛ",
|
||||
"format": "ФОРМАТ",
|
||||
|
|
@ -170,6 +183,8 @@
|
|||
"outdated_tooltip": "Файла за тази книга е променен, книгата трябва да бъде анализирана отново",
|
||||
"read_book": "Чети книга",
|
||||
"read_incognito": "Чети инкогнито",
|
||||
"remove_from_collection": "Премахни книга от колекция",
|
||||
"remove_from_readlist": "Премахни книга от списък за четене",
|
||||
"size": "РАЗМЕР"
|
||||
},
|
||||
"browse_collection": {
|
||||
|
|
@ -184,6 +199,7 @@
|
|||
},
|
||||
"browse_series": {
|
||||
"earliest_year_from_release_dates": "Това е най-ранната година на издаване за всички книги в поредицата",
|
||||
"remove_from_collection": "Премахни поредица от колекция",
|
||||
"series_no_summary": "Тази поредица няма резюме, затова избрахме за Вас!",
|
||||
"summary_from_book": "Резюме от книга {number}:"
|
||||
},
|
||||
|
|
@ -194,14 +210,18 @@
|
|||
"common": {
|
||||
"age": "Възраст",
|
||||
"all_libraries": "Всички Библиотеки",
|
||||
"all_of": "Всички",
|
||||
"any_of": "Които и да е",
|
||||
"book": "Книга",
|
||||
"books": "Книги",
|
||||
"books_n": "Няма книги | 1 книга | {count} книги",
|
||||
"books_total": "{count} / {total} книги",
|
||||
"cancel": "Отмени",
|
||||
"cbx": "Комикси Архив",
|
||||
"choose_image": "Изберете изображение",
|
||||
"close": "Затвори",
|
||||
"collections": "Колекции",
|
||||
"copied": "Копирано!",
|
||||
"create": "Създай",
|
||||
"delete": "Изтрий",
|
||||
"dimension": "ш: {width}, в: {height}",
|
||||
|
|
@ -210,8 +230,10 @@
|
|||
"dismiss": "Отхвърли",
|
||||
"download": "Свали",
|
||||
"drag_drop": "теглене и пускане",
|
||||
"duplicate": "Дубликирай",
|
||||
"email": "Имейл",
|
||||
"epub": "Epub",
|
||||
"error": "Грешка",
|
||||
"filename": "Име на файл",
|
||||
"filter_no_matches": "Активният филтър няма съвпадения",
|
||||
"genre": "Жанр",
|
||||
|
|
@ -219,12 +241,16 @@
|
|||
"go_to_library": "Към библиотеката",
|
||||
"go_to_readlist": "Към списъка за четене",
|
||||
"go_to_series": "Към поредицата",
|
||||
"i_understand": "Разбирам",
|
||||
"library": "Библиотека",
|
||||
"locale_name": "Български",
|
||||
"locale_rtl": "false",
|
||||
"lock_all": "Заключи всички",
|
||||
"media": "Медия",
|
||||
"more": "Още",
|
||||
"n_selected": "{count} избрани",
|
||||
"nothing_to_show": "Нищо за показване",
|
||||
"ok": "ОК",
|
||||
"oneshot": "Единично",
|
||||
"outdated": "Остарял",
|
||||
"page": "Страница",
|
||||
|
|
@ -235,19 +261,23 @@
|
|||
"password": "Парола",
|
||||
"pdf": "PDF",
|
||||
"pending_tasks": "Няма чакащи задачи | 1 чакаща задача | {count} чакащи задачи",
|
||||
"pinned_libraries": "Закачени Библиотеки",
|
||||
"publisher": "Издател",
|
||||
"read": "Чети",
|
||||
"read_on": "Четено на {date}",
|
||||
"readlist": "Списък за четене",
|
||||
"readlists": "Списък на прочетени",
|
||||
"remember-me": "Запомни ме",
|
||||
"reorder": "Пренареди",
|
||||
"required": "Задължително",
|
||||
"reset_filters": "Нулиране на филтри",
|
||||
"roles": "Роли",
|
||||
"save_changes": "Запазите промените",
|
||||
"series": "Поредица | Поредици",
|
||||
"settings": "Настройки",
|
||||
"sidecars": "Странични файлове",
|
||||
"tags": "Тагове",
|
||||
"ui": "Потребителски Интерфейс",
|
||||
"unavailable": "Недостъпен",
|
||||
"unlock_all": "Отключи всички",
|
||||
"url": "URL",
|
||||
|
|
@ -271,6 +301,7 @@
|
|||
"comicrack_preambule_html": "Можете да вмъкнете съществуващи списъци за четене на ComicRack във формат <code>.cbl</code>.<br>Komga ще се опита да съпостави предоставената поредица и номер на книга с поредици и книги във вашите библиотеки.",
|
||||
"dialog_confirmation": {
|
||||
"body": "{unmatched} / {total} книги са несравними",
|
||||
"body2": "{duplicates} / {total} книги се дублират",
|
||||
"create": "Създайте все пак",
|
||||
"title": "Някои книги не съответстват"
|
||||
},
|
||||
|
|
@ -286,6 +317,14 @@
|
|||
"tab_title": "Вмъкване на данни"
|
||||
},
|
||||
"dialog": {
|
||||
"add_api_key": {
|
||||
"button_confirm": "Генерирай",
|
||||
"context": "API Ключовете могат да се ползват за да се аутентикират чрез Kobo Sync протокола.",
|
||||
"dialog_title": "Генерирай нов API ключ",
|
||||
"field_comment": "Коментар",
|
||||
"field_comment_hint": "За какво е този API ключ?",
|
||||
"info_copy": "Подсигури, че си копирал твоят API ключ сега. Повече няма да може да го видиш!"
|
||||
},
|
||||
"add_to_collection": {
|
||||
"button_create": "Създай",
|
||||
"card_collection_subtitle": "Няма серия | 1 серия | {count} серии",
|
||||
|
|
@ -319,6 +358,12 @@
|
|||
"filter": "Филтриране по номер на книгата, заглавие или дата на издаване",
|
||||
"title": "Изберете книга"
|
||||
},
|
||||
"delete_apikey": {
|
||||
"button_confirm": "Изтрий",
|
||||
"confirm_delete": "Разбирам, изтрий API ключа \"{name}\"",
|
||||
"dialog_title": "Изтрий API ключ",
|
||||
"warning_html": "Всички приложения или скриптове ползващи този API ключ няма да могат да достигнат Komga API-то. Това действие не може да бъде отменено."
|
||||
},
|
||||
"delete_book": {
|
||||
"button_confirm": "Изтрий",
|
||||
"confirm_delete": "Да, изтрий книгата \"{name}\" и нейните файлове",
|
||||
|
|
@ -417,6 +462,7 @@
|
|||
"dialot_title_edit": "Редактиране на библиотеката",
|
||||
"field_analysis_analyze_dimensions": "Анализирайте размерите на страниците",
|
||||
"field_analysis_hash_files": "Изчисляване на хеш за файлове",
|
||||
"field_analysis_hash_koreader": "Изчисли хеш за файлове за KOReader",
|
||||
"field_analysis_hash_pages": "Изчисляване на хеш за страници",
|
||||
"field_convert_to_cbz": "Автоматично конвертиране в CBZ",
|
||||
"field_import_barcode_isbn": "ISBN баркод",
|
||||
|
|
@ -469,6 +515,11 @@
|
|||
"tab_general": "Основни",
|
||||
"tab_poster": "Плакат"
|
||||
},
|
||||
"edit_recommended": {
|
||||
"button_confirm": "Запази промени",
|
||||
"button_reset": "Възтанови в начални",
|
||||
"dialog_title": "Редактирай предложеният изглед"
|
||||
},
|
||||
"edit_series": {
|
||||
"button_cancel": "Отмени",
|
||||
"button_confirm": "Запазване на промените",
|
||||
|
|
@ -537,6 +588,10 @@
|
|||
},
|
||||
"title": "Име на Целевия Файл"
|
||||
},
|
||||
"force_kobo_sync": {
|
||||
"dialog_title": "Принудително синхронизиране на Kobo",
|
||||
"warning_html": "Това ще изтрие цялата история на синхронизация за този API ключ. Тоят Kobo ще синхронизира всичко на следващата синхронизациая."
|
||||
},
|
||||
"password_change": {
|
||||
"button_cancel": "Отмени",
|
||||
"button_confirm": "Промяна на паролата",
|
||||
|
|
@ -604,8 +659,11 @@
|
|||
"delete_to_save": "Изтрийте, за да запазите {size}",
|
||||
"deleted_count": "Изтрит {count} пъти",
|
||||
"empty_title": "Не са намерани дублирани страници",
|
||||
"empty_title_known": "Няма известни дубликати",
|
||||
"filter": {
|
||||
"count": "Брой",
|
||||
"date_added": "Дата на добавяне",
|
||||
"date_modified": "Дата на промяна",
|
||||
"delete_count": "Брой изтрити",
|
||||
"delete_size": "Спестено място",
|
||||
"match_count": "Брой съвпадения",
|
||||
|
|
@ -617,7 +675,7 @@
|
|||
"matches_n": "Няма съвпадения | 1 съвпадение | {count} съвпадения",
|
||||
"new": "Нови",
|
||||
"saved_size": "Спестено {size}",
|
||||
"title": "Дублирани страници",
|
||||
"title": "Дублирани Страници",
|
||||
"unknown_size": "Неизвестен размер"
|
||||
},
|
||||
"duplicates": {
|
||||
|
|
@ -633,7 +691,19 @@
|
|||
},
|
||||
"epubreader": {
|
||||
"appearances": {
|
||||
"day": "Ден"
|
||||
"day": "Ден",
|
||||
"night": "Нощ",
|
||||
"sepia": "Сепия"
|
||||
},
|
||||
"column_count": {
|
||||
"auto": "Авто",
|
||||
"one": "Едно",
|
||||
"two": "Две"
|
||||
},
|
||||
"reading_direction": {
|
||||
"auto": "Автоматично",
|
||||
"ltr": "От ляво на дясно",
|
||||
"rtl": "От дясно на ляво"
|
||||
}
|
||||
},
|
||||
"historical_event_type": {
|
||||
|
|
@ -643,6 +713,11 @@
|
|||
"DuplicatePageDeleted": "Дублираната страница е изтрита",
|
||||
"SeriesFolderDeleted": "Папката на поредицата е изтрита"
|
||||
},
|
||||
"media_profile": {
|
||||
"DIVINA": "DIVINA",
|
||||
"EPUB": "EPUB",
|
||||
"PDF": "PDF"
|
||||
},
|
||||
"media_status": {
|
||||
"ERROR": "Грешка",
|
||||
"OUTDATED": "Остарял",
|
||||
|
|
@ -661,6 +736,14 @@
|
|||
"VERTICAL": "Вертикално",
|
||||
"WEBTOON": "Уебтун"
|
||||
},
|
||||
"scan_interval": {
|
||||
"DAILY": "Дневно",
|
||||
"DISABLED": "Спряно",
|
||||
"EVERY_12H": "На всеки 12 часа",
|
||||
"EVERY_6H": "На всеки 6 часа",
|
||||
"HOURLY": "На час",
|
||||
"WEEKLY": "Седмично"
|
||||
},
|
||||
"series_cover": {
|
||||
"FIRST": "Първа",
|
||||
"FIRST_UNREAD_OR_FIRST": "Първа непрочетена иначе първа",
|
||||
|
|
@ -672,11 +755,21 @@
|
|||
"ENDED": "Приключила",
|
||||
"HIATUS": "Хиатус",
|
||||
"ONGOING": "Продължава"
|
||||
},
|
||||
"thumbnail_size": {
|
||||
"DEFAULT": "По подразбиране (300px)",
|
||||
"LARGE": "Голямо (900px)",
|
||||
"MEDIUM": "Средно (600px)",
|
||||
"XLARGE": "Много Голямо (1200px)"
|
||||
}
|
||||
},
|
||||
"epubreader": {
|
||||
"current_chapter": "Текуща глава",
|
||||
"page_of": "Станица {page} от {count}",
|
||||
"publisher_font": "Издателство",
|
||||
"settings": {
|
||||
"column_count": "Брой колони",
|
||||
"font_family": "Шрифт",
|
||||
"layout": "Оформление",
|
||||
"layout_paginated": "Страницирано",
|
||||
"layout_scroll": "Позициониране",
|
||||
|
|
@ -698,7 +791,7 @@
|
|||
"next": "Напред",
|
||||
"previous": "Назад",
|
||||
"reader_navigation": "Навигация на четец",
|
||||
"scroll": "Промени оформление към позициониране",
|
||||
"scroll": "Превключи на непрекъснато превъртане",
|
||||
"settings": "Настройки",
|
||||
"show_hide_toc": "Покажи/скрий съдържание"
|
||||
}
|
||||
|
|
@ -731,17 +824,27 @@
|
|||
"ERR_1029": "ComicRack CBL не съдържа никакъв елемент Book",
|
||||
"ERR_1030": "ComicRack CBL няма елемент Name",
|
||||
"ERR_1031": "ComicRack CBL в Book липсва серия или номер",
|
||||
"ERR_1032": "EPUB файл е с грешен тип медия"
|
||||
"ERR_1032": "EPUB файл е с грешен тип медия",
|
||||
"ERR_1033": "Някои записи липсват",
|
||||
"ERR_1034": "API ключ с този коментар вече съществува",
|
||||
"ERR_1035": "Грешка при четене на EPUB Съдържание",
|
||||
"ERR_1036": "Грешка при четене на EPUB ориентирите",
|
||||
"ERR_1037": "Грешка при четене на EPUB списък на страници",
|
||||
"ERR_1038": "Грешка при четене на EPUB divina страници",
|
||||
"ERR_1039": "Грешка при четене на EPUB позиций"
|
||||
},
|
||||
"filter": {
|
||||
"age_rating": "възрастова оценка",
|
||||
"age_rating_none": "Без",
|
||||
"any": "Всички",
|
||||
"complete": "Завършени",
|
||||
"genre": "жанр",
|
||||
"in_progress": "В Обръщение",
|
||||
"language": "език",
|
||||
"library": "библиотека",
|
||||
"oneshot": "Единично",
|
||||
"media_profile": "Профил на медия",
|
||||
"media_status": "Статус на медиа",
|
||||
"oneshot": "Самостоятелно издание",
|
||||
"publisher": "издателство",
|
||||
"read": "Прочетени",
|
||||
"release_date": "дата на издаване",
|
||||
|
|
@ -770,6 +873,8 @@
|
|||
},
|
||||
"library_navigation": {
|
||||
"browse": "Преглед",
|
||||
"browse_books": "Книги",
|
||||
"browse_series": "Поредици",
|
||||
"collections": "Колекции",
|
||||
"readlists": "Списъци за Четене",
|
||||
"recommended": "Препоръчани"
|
||||
|
|
@ -781,7 +886,7 @@
|
|||
},
|
||||
"media_analysis": {
|
||||
"comment": "Коментар",
|
||||
"media_analysis": "Медиен анализ",
|
||||
"media_analysis": "Медиен Анализ",
|
||||
"media_type": "Тип на Медията",
|
||||
"name": "Име",
|
||||
"size": "Размер",
|
||||
|
|
@ -802,10 +907,12 @@
|
|||
"empty_trash": "Изпразване на кошчето",
|
||||
"mark_read": "Отбележи като прочетено",
|
||||
"mark_unread": "Отбележи като непрочетено",
|
||||
"pin": "Закачи",
|
||||
"refresh_metadata": "Опресняване на метаданните",
|
||||
"scan_library_files": "Сканирайте библиотечните файлове",
|
||||
"scan_library_files_deep": "Сканирай библиотека за файлове (дълбоко)",
|
||||
"select_all": "Изберете всички"
|
||||
"select_all": "Изберете всички",
|
||||
"unpin": "Разкачи"
|
||||
},
|
||||
"metrics": {
|
||||
"library_books": "Книги на библиотека",
|
||||
|
|
@ -816,11 +923,18 @@
|
|||
"tasks_total_time": "Общо време на задачите",
|
||||
"title": "Показатели"
|
||||
},
|
||||
"missing_posters": {
|
||||
"title": "Липсващ Постер"
|
||||
},
|
||||
"navigation": {
|
||||
"home": "Начало",
|
||||
"libraries": "Библиотеки",
|
||||
"logout": "Изход"
|
||||
},
|
||||
"no_libraries_pinned": {
|
||||
"subtitle": "Може да закачиш библиотеки от менюто с 3 точки",
|
||||
"title": "Няма закачени библиотеки"
|
||||
},
|
||||
"page_not_found": {
|
||||
"go_back_to_home_page": "Връщане към началната страница",
|
||||
"page_does_not_exist": "Страницата, която търсите, не съществува.",
|
||||
|
|
@ -858,10 +972,12 @@
|
|||
"button_scan_libraries": "Сканиране на всички библиотеки",
|
||||
"button_scan_libraries_deep": "Сканирай всички библиотеки (дълбоко)",
|
||||
"button_shutdown": "Изключване",
|
||||
"download_log": "Изтегли лог файл",
|
||||
"notification_tasks_cancelled": "Няма задачи за отмяна | Една отменена задача | {count} отменени задачи",
|
||||
"section_title": "Управление на сървъра"
|
||||
},
|
||||
"tab_title": "Сървър"
|
||||
"tab_title": "Сървър",
|
||||
"updates": "Обновления"
|
||||
},
|
||||
"server_settings": {
|
||||
"config_precedence": "Има предимство пред конфигурационния файл",
|
||||
|
|
@ -872,8 +988,12 @@
|
|||
"btn_confirm": "Да, но само за по-големите",
|
||||
"title": "Регенерирай тъмбнейловете"
|
||||
},
|
||||
"hint_kobo_port": "Задайте само в случай на проблеми със синхронизирането на кориците и изтеглянията",
|
||||
"label_delete_empty_collections": "Изтрий празни колекций след сканиране",
|
||||
"label_delete_empty_readlists": "Изтрий празни листове след сканиране",
|
||||
"label_kepubify_path": "Път към kepubify",
|
||||
"label_kobo_port": "Kobo Sync външен порт",
|
||||
"label_kobo_proxy": "Прокси Kobo Sync заявки към Kobo Store",
|
||||
"label_rememberme_duration": "Запомни ме за период (в дни)",
|
||||
"label_server_context_path": "Базов URL",
|
||||
"label_server_port": "Прот на сървъра",
|
||||
|
|
@ -894,13 +1014,17 @@
|
|||
"sort": {
|
||||
"books_count": "Брой книги",
|
||||
"date_added": "Дата на добавяне",
|
||||
"date_read": "Дата на четене",
|
||||
"date_updated": "Дата на актуализация",
|
||||
"file_name": "Име на файл",
|
||||
"file_size": "Размер на файла",
|
||||
"folder_name": "Име на папка",
|
||||
"name": "Име",
|
||||
"number": "Номер",
|
||||
"release_date": "Дата на издаване"
|
||||
"page_count": "Брой страници",
|
||||
"random": "Случайно",
|
||||
"release_date": "Дата на издаване",
|
||||
"series": "Поредица"
|
||||
},
|
||||
"theme": {
|
||||
"dark": "Тъмна",
|
||||
|
|
@ -922,13 +1046,34 @@
|
|||
"less": "По-малко заглавия",
|
||||
"more": "Още заглавия"
|
||||
},
|
||||
"ui_settings": {
|
||||
"general": "Основни",
|
||||
"label_oauth2_auto_login": "Автоматичнен OAuth2 login",
|
||||
"label_oauth2_hide_login": "Скрий логин полетата ако OAuth2 е включено",
|
||||
"label_poster_blur_unread": "Замажи постери за непречетени книги и поредици",
|
||||
"label_poster_stretch": "Разтегли постези за да изпълнят картата",
|
||||
"label_series_groups": "Групиране на поредици",
|
||||
"section_oauth2": "OAuth2",
|
||||
"series_groups": {
|
||||
"alpha": "Азбучно",
|
||||
"japanese": "Gojūon (Японски)"
|
||||
},
|
||||
"tooltip_oauth2_auto_login": "Изисква единен OAuth2 източник, и 'скрити логин полета' включени"
|
||||
},
|
||||
"updates": {
|
||||
"available": "Има налични обновления",
|
||||
"latest_installed": "Последната версия на Komga е инсталирана"
|
||||
},
|
||||
"user_roles": {
|
||||
"ADMIN": "Администратор",
|
||||
"FILE_DOWNLOAD": "Изтегляне на файлове",
|
||||
"KOBO_SYNC": "Kobo Sync",
|
||||
"KOREADER_SYNC": "KOReader Sync",
|
||||
"PAGE_STREAMING": "Стриймване на страници",
|
||||
"USER": "Потребител"
|
||||
},
|
||||
"users": {
|
||||
"api_keys": "API ключове",
|
||||
"authentication_activity": "Дейност по удостоверяване",
|
||||
"users": "Потребители"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@
|
|||
},
|
||||
"change_password": "Passwort ändern",
|
||||
"details": "Details",
|
||||
"my_account": "Mein Account"
|
||||
"my_account": "Mein Konto"
|
||||
},
|
||||
"announcements": {
|
||||
"mark_all_read": "Alle als gelesen markieren",
|
||||
|
|
@ -52,7 +52,7 @@
|
|||
"letterer": "Setzer",
|
||||
"penciller": "Zeichner",
|
||||
"translator": "Übersetzer",
|
||||
"writer": "Schriftsteller"
|
||||
"writer": "Autoren"
|
||||
},
|
||||
"book_card": {
|
||||
"error": "Fehler",
|
||||
|
|
@ -104,9 +104,9 @@
|
|||
"move_next": "Klicken oder drücken Sie „Weiter“, um zum nächsten Buch zu gelangen.",
|
||||
"move_next_exit": "Klicken oder drücken Sie „Weiter“ erneut, um den Lesemodus zu beenden.",
|
||||
"move_previous": "Klicken oder drücken Sie erneut auf „Vorherige Seite“, um zum letzten Buch zu wechseln.",
|
||||
"notification_poster_set_book": "Die aktuelle Seite ist nun als Bücherplakat gesetzt.",
|
||||
"notification_poster_set_readlist": "Die aktuelle Seite ist als Leselistenposter gesetzt.",
|
||||
"notification_poster_set_series": "Die aktuelle Seite ist jetzt als Serienplakat gesetzt.",
|
||||
"notification_poster_set_book": "Die aktuelle Seite ist jetzt als Titelbild definiert.",
|
||||
"notification_poster_set_readlist": "Die aktuelle Seite wurde als Titelbild für die Lesteliste festgelegt.",
|
||||
"notification_poster_set_series": "Die aktuelle Seite wurde als Titelbild der Serie festgelegt.",
|
||||
"paged_reader_layout": {
|
||||
"double": "Doppelseite",
|
||||
"double_no_cover": "Doppelseitig ohne Titelbild",
|
||||
|
|
@ -122,9 +122,9 @@
|
|||
"width": "An Breite ausrichten",
|
||||
"width_shrink_only": "An Breite ausrichten (nur verkleinern)"
|
||||
},
|
||||
"set_current_page_as_book_poster": "Seite als Plakat für das Buch gesetzt",
|
||||
"set_current_page_as_readlist_poster": "Setze die aktuelle Seite als Plakat für die Leseliste",
|
||||
"set_current_page_as_series_poster": "Seite zu Serienposter",
|
||||
"set_current_page_as_book_poster": "Diese Seite als Titelbild für das Buch festlegen",
|
||||
"set_current_page_as_readlist_poster": "Diese Seite als Titelbild für die Leseliste festlegen",
|
||||
"set_current_page_as_series_poster": "Diese Seite als Titelbild für die Serie festlegen",
|
||||
"settings": {
|
||||
"always_fullscreen": "Dauerhaftes Vollbild",
|
||||
"animate_page_transitions": "Fließender Seitenübergangseffekt",
|
||||
|
|
@ -202,7 +202,7 @@
|
|||
"earliest_year_from_release_dates": "Dies ist das früheste Erscheinungsjahr von allen Büchern in der Serie",
|
||||
"remove_from_collection": "Entferne Serie aus der Sammlung",
|
||||
"series_no_summary": "Diese Serie hat keine Kurzbeschreibung, es wurde eine aus der Serie per Zufall ausgewählt!",
|
||||
"summary_from_book": "Inhaltsangabe des Buches {number}:"
|
||||
"summary_from_book": "Inhaltsangabe von Buch {number}:"
|
||||
},
|
||||
"collections_expansion_panel": {
|
||||
"manage_collection": "Sammlungverwaltung",
|
||||
|
|
@ -247,7 +247,7 @@
|
|||
"locale_name": "Deutsch",
|
||||
"locale_rtl": "false",
|
||||
"lock_all": "Alle sperren",
|
||||
"media": "Media",
|
||||
"media": "Medien",
|
||||
"more": "Mehr",
|
||||
"n_selected": "{count} markiert",
|
||||
"nothing_to_show": "Nichts anzuzeigen",
|
||||
|
|
@ -351,7 +351,7 @@
|
|||
"field_password": "Passwort"
|
||||
},
|
||||
"analyze_library": {
|
||||
"body": "Analysiert alle Mediendateien in der Bibliothek. Bei der Analyse werden Informationen über die Medien erfasst. Je nach Größe Ihrer Bibliothek kann dies sehr lange dauern.",
|
||||
"body": "Analysiert alle Mediendateien in der Bibliothek. Bei der Analyse werden Informationen über die Mediendatien erfasst. Je nach Größe Ihrer Bibliothek kann dies sehr lange dauern.",
|
||||
"button_confirm": "Analysieren",
|
||||
"title": "Bibliothek analysieren"
|
||||
},
|
||||
|
|
@ -371,8 +371,8 @@
|
|||
"confirm_delete_multiple": "Ja, lösche {count} Bücher und die dazugehörigen Dateien",
|
||||
"dialog_title": "Buch löschen",
|
||||
"dialog_title_multiple": "Bücher löschen",
|
||||
"warning_html": "Das Buch <b>{name}</b> wird vom Server inklusive der gespeicherten Daten auf der Festplatte entfernt. Dies <b>kann nicht</b> rückgängig gemacht werden. Forfahren?",
|
||||
"warning_multiple_html": "{count} Bücher werden vom Server inklusive der gespeicherten Daten auf der Festplatte entfernt. Dies <b>kann nicht</b> rückgängig gemacht werden. Forfahren?"
|
||||
"warning_html": "Das Buch <b>{name}</b> wird vom Server inklusive der gespeicherten Dateien auf der Festplatte entfernt. Dies <b>kann nicht</b> rückgängig gemacht werden. Forfahren?",
|
||||
"warning_multiple_html": "{count} Bücher werden vom Server inklusive der gespeicherten Dateien auf der Festplatte entfernt. Dies <b>kann nicht</b> rückgängig gemacht werden. Forfahren?"
|
||||
},
|
||||
"delete_collection": {
|
||||
"button_confirm": "Löschen",
|
||||
|
|
@ -380,14 +380,14 @@
|
|||
"confirm_delete_multiple": "Ja, {count} Sammlung(en) löschen",
|
||||
"dialog_title": "Sammlung löschen",
|
||||
"dialog_title_multiple": "Sammlungen löschen",
|
||||
"warning_html": "Die Sammlung <b>{name}</b> wird vom Server entfernt. Die physikalischen Dateien bleiben unverändert. Dies kann <b>NICHT</b> rückgängig gemacht werden. Fortfahren?",
|
||||
"warning_html": "Die Sammlung <b>{name}</b> wird vom Server entfernt. Die Mediendateien bleiben unverändert. Dies kann <b>NICHT</b> rückgängig gemacht werden. Fortfahren?",
|
||||
"warning_multiple_html": "{count} Sammlungen werden von diesem Server entfernt. Ihre Mediendateien sind davon nicht betroffen. Dies kann <b>nicht</b> rückgängig gemacht werden. Fortsetzen?"
|
||||
},
|
||||
"delete_library": {
|
||||
"button_confirm": "Löschen",
|
||||
"confirm_delete": "Ja, die Bibliothek „{name}“ löschen",
|
||||
"title": "Bibliothek löschen",
|
||||
"warning_html": "Die Bibliothek <b>{name}</b> wird vom Server gelöscht. Die physikalischen Dateien bleiben unverändert. Dies kann <b>NICHT</b> rückgängig gemacht werden. Fortfahren?"
|
||||
"warning_html": "Die Bibliothek <b>{name}</b> wird vom Server gelöscht. Die Mediendateien bleiben unverändert. Dies kann <b>NICHT</b> rückgängig gemacht werden. Fortfahren?"
|
||||
},
|
||||
"delete_readlist": {
|
||||
"button_confirm": "Löschen",
|
||||
|
|
@ -395,7 +395,7 @@
|
|||
"confirm_delete_multiple": "Ja, {count} Leselisten löschen",
|
||||
"dialog_title": "Leseliste löschen",
|
||||
"dialog_title_multiple": "Leselisten löschen",
|
||||
"warning_html": "Die Leseliste <b>{name}</b> wird vom Server entfernt. Die physikalischen Dateien bleiben unverändert. Dies kann <b>NICHT</b> rückgängig gemacht werden. Fortfahren?",
|
||||
"warning_html": "Die Leseliste <b>{name}</b> wird vom Server entfernt. Die Mediendateien bleiben unverändert. Dies kann <b>NICHT</b> rückgängig gemacht werden. Fortfahren?",
|
||||
"warning_multiple_html": "{count} Leselisten werden von diesem Server entfernt. Ihre Mediendateien sind davon nicht betroffen. Dies <b>kann nicht</b> rückgängig gemacht werden. Fortsetzen?"
|
||||
},
|
||||
"delete_series": {
|
||||
|
|
@ -413,7 +413,7 @@
|
|||
"warning_html": "Der Benutzer <b>{name}</b> wird gelöscht. Dies kann <b>NICHT</b> rückgängig gemacht werden. Fortfahren?"
|
||||
},
|
||||
"edit_books": {
|
||||
"add_author_role_error_duplicate": "Author existiert bereits",
|
||||
"add_author_role_error_duplicate": "Autor existiert bereits",
|
||||
"authors_notice_multiple_edit": "Sie verändern mehrere Bücher. Dies wird die existierenden Einträge der Autoren jedes einzelnen Buches durch den neuen Eintrag ersetzen.",
|
||||
"button_cancel": "Abbrechen",
|
||||
"button_confirm": "Änderungen speichern",
|
||||
|
|
@ -440,7 +440,7 @@
|
|||
"tab_authors": "Autoren",
|
||||
"tab_general": "Allgemein",
|
||||
"tab_links": "Links",
|
||||
"tab_poster": "Poster",
|
||||
"tab_poster": "Titelbild",
|
||||
"tab_tags": "Stichwörter",
|
||||
"tags_notice_multiple_edit": "Sie verändern die Stichwörter von mehreren Büchern. Dies wird die existierenden Einträge der Stichwörter jedes einzelnen Buches durch den neuen Eintrag ersetzen."
|
||||
},
|
||||
|
|
@ -451,7 +451,7 @@
|
|||
"field_manual_ordering": "Manuelle Sortierung",
|
||||
"label_ordering": "Sammlungen werden standardmäßig nach Namen sortiert. Sie können die manuelle Sortierung aktivieren und eine eigene Sortierfolge festlegen.",
|
||||
"tab_general": "Allgemein",
|
||||
"tab_poster": "Poster"
|
||||
"tab_poster": "Titelbild"
|
||||
},
|
||||
"edit_library": {
|
||||
"button_browse": "Durchsuchen",
|
||||
|
|
@ -463,7 +463,7 @@
|
|||
"dialot_title_edit": "Bibliothek bearbeiten",
|
||||
"field_analysis_analyze_dimensions": "Analysiere Seitenformat",
|
||||
"field_analysis_hash_files": "Erzeuge einen Hash für Dateien",
|
||||
"field_analysis_hash_koreader": "Compute Hash für KO Reader Dateien",
|
||||
"field_analysis_hash_koreader": "Erzeuge einen Hash für KO Reader Dateien",
|
||||
"field_analysis_hash_pages": "Erzeuge einen Hash für Seiten",
|
||||
"field_convert_to_cbz": "Automatisch in CBZ konvertieren",
|
||||
"field_import_barcode_isbn": "ISBN Strichcode",
|
||||
|
|
@ -514,7 +514,7 @@
|
|||
"field_summary": "Zusammenfassung",
|
||||
"label_ordering": "Standardmäßig werden die Bücher in einer Leseliste manuell sortiert. Sie können die manuelle Sortierung deaktivieren, um die Bücher nach Erscheinungsdatum zu sortieren.",
|
||||
"tab_general": "Allgemein",
|
||||
"tab_poster": "Poster"
|
||||
"tab_poster": "Titelbild"
|
||||
},
|
||||
"edit_recommended": {
|
||||
"button_confirm": "Änderungen speichern",
|
||||
|
|
@ -543,7 +543,7 @@
|
|||
"field_total_book_count_error": "Anzahl der Bücher einer Serie muß größer eins sein",
|
||||
"mixed": "Vermischtes",
|
||||
"tab_general": "Allgemein",
|
||||
"tab_poster": "Poster",
|
||||
"tab_poster": "Titelbild",
|
||||
"tab_sharing": "Teilen",
|
||||
"tab_tags": "Stichwörter",
|
||||
"tab_titles": "Alternative Titel",
|
||||
|
|
@ -591,7 +591,7 @@
|
|||
},
|
||||
"force_kobo_sync": {
|
||||
"dialog_title": "Erzwinge Kobo Sync",
|
||||
"warning_html": "Dies löscht die komplette Sync Historie für diesen API Schlüssel. Dein Kobo wird einen vollständigen Sync beim nächsten Mal durchführen."
|
||||
"warning_html": "Dies löscht den kompletten Synchronisierungverlauf für diesen API Schlüssel. Dein Kobo beim nächsten Mal eine vollständige Synchronisierung durchführen."
|
||||
},
|
||||
"password_change": {
|
||||
"button_cancel": "Abbrechen",
|
||||
|
|
@ -818,7 +818,7 @@
|
|||
"ERR_1022": "Ein neu importiertes Buch konnte nicht gescannt werden",
|
||||
"ERR_1023": "Buch ist in der Leseliste schon vorhanden",
|
||||
"ERR_1024": "OAuth2 Anmeldefehler: Kein E-Mail Attribut",
|
||||
"ERR_1025": "OAuth2 Anmeldefehler: Keinen lokalen Nutzer mit eingegebener E-Mail gefunden",
|
||||
"ERR_1025": "OAuth2 Anmeldefehler: Keinen lokalen Nutzer mit der angegebenen E-Mail gefunden",
|
||||
"ERR_1026": "OpenID Connect Anmeldefehler: E-Mail nicht verifiziert",
|
||||
"ERR_1027": "OpenID Connect-Anmeldefehler: Fehlendes email_verified Attribut",
|
||||
"ERR_1028": "OpenID Connect-Anmeldefehler: kein E-Mail Attribut",
|
||||
|
|
@ -866,11 +866,11 @@
|
|||
"series": "Serie",
|
||||
"type": "Type"
|
||||
},
|
||||
"title": "Historie"
|
||||
"title": "Verlauf"
|
||||
},
|
||||
"home": {
|
||||
"theme": "Design",
|
||||
"translation": "Übersetzung"
|
||||
"translation": "Sprache"
|
||||
},
|
||||
"library_navigation": {
|
||||
"browse": "Stöbern",
|
||||
|
|
@ -878,7 +878,7 @@
|
|||
"browse_series": "Serien",
|
||||
"collections": "Sammlungen",
|
||||
"readlists": "Leseliste",
|
||||
"recommended": "Empfohlen"
|
||||
"recommended": "Empfehlungen"
|
||||
},
|
||||
"login": {
|
||||
"create_user_account": "Benutzerkonto erstellen",
|
||||
|
|
@ -887,7 +887,7 @@
|
|||
},
|
||||
"media_analysis": {
|
||||
"comment": "Kommentar",
|
||||
"media_analysis": "Medien Analyse",
|
||||
"media_analysis": "Medienanalyse",
|
||||
"media_type": "Medientyp",
|
||||
"name": "Name",
|
||||
"size": "Größe",
|
||||
|
|
@ -896,7 +896,7 @@
|
|||
},
|
||||
"menu": {
|
||||
"add_to_collection": "Zu Sammlung hinzufügen",
|
||||
"add_to_readlist": "Füge zur Leseliste hinzu",
|
||||
"add_to_readlist": "Zur Leseliste hinzufügen",
|
||||
"analyze": "Analysieren",
|
||||
"bulk_edit_metadata": "Massenverarbeitung Metadaten",
|
||||
"delete": "Löschen",
|
||||
|
|
@ -909,7 +909,7 @@
|
|||
"mark_read": "Als gelesen markieren",
|
||||
"mark_unread": "Als ungelesen markieren",
|
||||
"pin": "Anpinnen",
|
||||
"refresh_metadata": "Erneuere Metadaten",
|
||||
"refresh_metadata": "Metadaten aktualisieren",
|
||||
"scan_library_files": "Überprüfe (Scan) Bibliotheksdateien",
|
||||
"scan_library_files_deep": "(Tiefen) Scan der Bibliotheksdateien",
|
||||
"select_all": "Alle auswählen",
|
||||
|
|
@ -922,10 +922,10 @@
|
|||
"library_sidecars": "Extras pro Bibliothek",
|
||||
"tasks_executed": "Aufgaben ausgeführt",
|
||||
"tasks_total_time": "Benötigte Gesamtzeit für die Aufgaben",
|
||||
"title": "Metriken"
|
||||
"title": "Statistik"
|
||||
},
|
||||
"missing_posters": {
|
||||
"title": "Fehlende Poster"
|
||||
"title": "Fehlende Titelbilder"
|
||||
},
|
||||
"navigation": {
|
||||
"home": "Übersicht",
|
||||
|
|
@ -990,7 +990,7 @@
|
|||
"title": "Vorschaubilder neu generieren"
|
||||
},
|
||||
"hint_kobo_port": "Nur zu setzen wenn es Sync Probleme mit Covers und Downloads gibt",
|
||||
"label_delete_empty_collections": "Lösche leere Kollectionen nach der Prüfung (Scan)",
|
||||
"label_delete_empty_collections": "Lösche leere Kollektionen nach der Prüfung (Scan)",
|
||||
"label_delete_empty_readlists": "Lösche leere Leselisten nach der Überprüfung (Scan)",
|
||||
"label_kepubify_path": "Dateipfad zu kepubify",
|
||||
"label_kobo_port": "Kobo Sync externer Port",
|
||||
|
|
@ -1009,7 +1009,7 @@
|
|||
"edit_user": "Benutzerdaten bearbeiten",
|
||||
"latest_activity": "Letzte Aktivität: {date}",
|
||||
"no_recent_activity": "Keine letzten Aktivitäten",
|
||||
"role_administrator": "Systemverwalter",
|
||||
"role_administrator": "Administrator",
|
||||
"role_user": "Benutzer"
|
||||
},
|
||||
"sort": {
|
||||
|
|
@ -1023,7 +1023,7 @@
|
|||
"name": "Nach Name sortiert",
|
||||
"number": "Nummer",
|
||||
"page_count": "Anzahl Seiten",
|
||||
"random": "Zufallsortierung",
|
||||
"random": "Zufällige Sortierung",
|
||||
"release_date": "Veröffentlichungsdatum",
|
||||
"series": "Serie"
|
||||
},
|
||||
|
|
@ -1049,10 +1049,10 @@
|
|||
},
|
||||
"ui_settings": {
|
||||
"general": "Allgemein",
|
||||
"label_oauth2_auto_login": "Automatischer OAuth2 Login",
|
||||
"label_oauth2_hide_login": "Verstecke die Login Felder wenn OAuth2 aktiviert ist",
|
||||
"label_poster_blur_unread": "Vertrübe Poster für ungelesene Bücher und Serien",
|
||||
"label_poster_stretch": "Passe die Poster den Kacheln an",
|
||||
"label_oauth2_auto_login": "Automatische Anmeldung über OAuth2",
|
||||
"label_oauth2_hide_login": "Anmeldefelder ausblenden, wenn OAuth2 aktiviert ist",
|
||||
"label_poster_blur_unread": "Unscharfe Titelbilder bei ungelesene Bücher und Serien",
|
||||
"label_poster_stretch": "Titelbilder an die Kachelgröße anpassen",
|
||||
"label_series_groups": "Seriengruppierung",
|
||||
"section_oauth2": "OAuth2",
|
||||
"series_groups": {
|
||||
|
|
@ -1067,7 +1067,7 @@
|
|||
},
|
||||
"user_roles": {
|
||||
"ADMIN": "Systemverwalter",
|
||||
"FILE_DOWNLOAD": "Datei-Herunterladen",
|
||||
"FILE_DOWNLOAD": "Dateien herunterladen",
|
||||
"KOBO_SYNC": "Kobo Syncronisation",
|
||||
"KOREADER_SYNC": "KOReader Synchronisation",
|
||||
"PAGE_STREAMING": "Online lesen",
|
||||
|
|
|
|||
|
|
@ -19,7 +19,15 @@
|
|||
},
|
||||
"account_settings": {
|
||||
"account_settings": "Configuración da conta",
|
||||
"change_password": "Cambiar o contrasinal"
|
||||
"api_key": {
|
||||
"created_date": "Data de creación: {date}",
|
||||
"force_kobo_sync": "Forzar a sincronización con Kobo",
|
||||
"generate_api_key": "Xerar clave API",
|
||||
"no_keys": "Aínda non se xerou clave API ningunha"
|
||||
},
|
||||
"change_password": "Cambiar o contrasinal",
|
||||
"details": "Detalles",
|
||||
"my_account": "A miña conta"
|
||||
},
|
||||
"announcements": {
|
||||
"mark_all_read": "Marcar todo como lido",
|
||||
|
|
@ -27,6 +35,7 @@
|
|||
"tab_title": "Avisos"
|
||||
},
|
||||
"authentication_activity": {
|
||||
"api_key": "Clave API",
|
||||
"datetime": "Data e Hora",
|
||||
"email": "Correo electrónico",
|
||||
"error": "Erro",
|
||||
|
|
@ -58,9 +67,196 @@
|
|||
"button_scan": "Escanear",
|
||||
"button_select_series": "Escolle a serie",
|
||||
"field_import_path": "Importar dende un cartafol",
|
||||
"info_part1": "Esta pantalla permitiralle importar arquivos que están fóra das súas bibliotecas existentes. Só pódese importar arquivos a series que xa existan, nese caso Komga moverá ou copiará os arquivos cara o directorio da serie escollida."
|
||||
"info_part1": "Esta pantalla permitiralle importar arquivos que están fóra das súas bibliotecas existentes. Só pódese importar arquivos a series que xa existan, nese caso Komga moverá ou copiará os arquivos cara o directorio da serie escollida.",
|
||||
"info_part2": "Se escolles un número para un libro e existe xa algún outro libro con ese número, poderás comparalos. Se decides importar o libro, Komga actualizará o existente co novo, substituindo o ficheiro existente co novo.",
|
||||
"no_files_found": "Non se atoparon ficheiros",
|
||||
"notification": {
|
||||
"go_to_book": "Ir ao libro",
|
||||
"import_failure": "Fallou a importación do libro: {file}",
|
||||
"import_successful": "Libro importado con éxito: {book}",
|
||||
"source_file": "Ficheiro orixe: {file}"
|
||||
},
|
||||
"row": {
|
||||
"error_analyze_first": "É necesario analizar antes o libro",
|
||||
"error_choose_series": "Escoller serie",
|
||||
"error_only_import_no_errors": "Só se poden importar libros sen erros",
|
||||
"warning_upgrade": "Actualizarase o libro existente"
|
||||
},
|
||||
"table": {
|
||||
"destination_name": "Nome de destino",
|
||||
"file_name": "Nome do ficheiro",
|
||||
"number": "Número",
|
||||
"series": "Serie"
|
||||
},
|
||||
"title": "Importar",
|
||||
"try_another_directory": "Tenta atopar outro directorio"
|
||||
},
|
||||
"bookreader": {
|
||||
"beginning_of_book": "Atópaste ao principio do libro.",
|
||||
"changing_reading_direction": "Trocar o sentido de lectura a",
|
||||
"download_current_page": "Baixar a páxina actual",
|
||||
"end_of_book": "Chegaches ao final do libro.",
|
||||
"from_series_metadata": "dende os metadatos da serie",
|
||||
"move_next": "Volve pulsar \"Seguinte\" para pasar ao seguinte libro.",
|
||||
"move_next_exit": "Volve pulser \"Seguinte\" para saír do lector.",
|
||||
"move_previous": "Volve pulsar \"Anterior\" para pasar ao libro anterior.",
|
||||
"notification_poster_set_book": "A portada do libro estableceuse á páxina actual.",
|
||||
"notification_poster_set_readlist": "A portada da lista de lectura estableceuse á páxina actual.",
|
||||
"notification_poster_set_series": "A portada de serie estableceuse á páxina actual.",
|
||||
"paged_reader_layout": {
|
||||
"double": "Dobre páxina",
|
||||
"double_no_cover": "Dobre páxina (sen portada)",
|
||||
"single": "Páxina simple"
|
||||
},
|
||||
"reader_settings": "Configuración do lector",
|
||||
"scale_type": {
|
||||
"continuous_original": "Orixinal",
|
||||
"continuous_width": "Axuste á anchura",
|
||||
"height": "Axuste á altura",
|
||||
"original": "Orixinal",
|
||||
"screen": "Pantalla",
|
||||
"width": "Axusta ó ancho",
|
||||
"width_shrink_only": "Axusta ó ancho (só encoller)"
|
||||
},
|
||||
"set_current_page_as_book_poster": "Escolle a páxina como cuberta do libro",
|
||||
"set_current_page_as_readlist_poster": "Escolle a páxina como cuberta da lista de lectura",
|
||||
"set_current_page_as_series_poster": "Escolle a páxina como cuberta da serie",
|
||||
"settings": {
|
||||
"always_fullscreen": "Sempre a pantalla completa",
|
||||
"animate_page_transitions": "Transicións de páxina animadas",
|
||||
"background_color": "Cor de fondo",
|
||||
"background_colors": {
|
||||
"black": "Negro",
|
||||
"gray": "Gris",
|
||||
"white": "Branco"
|
||||
},
|
||||
"display": "Pantalla",
|
||||
"general": "Xeral",
|
||||
"gestures": "Xestos",
|
||||
"page_layout": "Disposición de páxina",
|
||||
"page_margin": "Marxe de páxina",
|
||||
"paged": "Opcións de paxinado do lector",
|
||||
"reading_mode": "Modo de lectura",
|
||||
"scale_type": "Tipo de escala",
|
||||
"side_padding": "Espazo lateral",
|
||||
"side_padding_none": "Ningún",
|
||||
"webtoon": "Opcións do lector de Webtoon"
|
||||
},
|
||||
"shortcuts": {
|
||||
"close": "Pechar",
|
||||
"cycle_page_layout": "Cambiar a disposición da páxina",
|
||||
"cycle_page_margin": "Cambia a marxe da páxina",
|
||||
"cycle_scale": "Cambia a escala",
|
||||
"cycle_side_padding": "Cambia o espaciado lateral",
|
||||
"first_page": "Primeira páxina",
|
||||
"fullscreen": "Entrar/Saír da pantalla completa",
|
||||
"last_page": "Derradeira páxina",
|
||||
"left_to_right": "De esquerda a dereita",
|
||||
"menus": "Menús",
|
||||
"next_page": "Seguinte páxina",
|
||||
"previous_page": "Páxina anterior",
|
||||
"reader_navigation": "Navegación do lector",
|
||||
"right_to_left": "De dereita a esquerda",
|
||||
"settings": "Axustes",
|
||||
"show_hide_help": "Mostra/agocha a axuda",
|
||||
"show_hide_settings": "Mostra/agocha o menú de axuda",
|
||||
"show_hide_thumbnails": "Mostra/agocha o explorador de miniaturas",
|
||||
"show_hide_toolbars": "Mostra/agocha as barras de ferramentas",
|
||||
"vertical": "Vertical",
|
||||
"webtoon": "Webtoon"
|
||||
},
|
||||
"tooltip_incognito": "Non se gardará o progreso de lectura"
|
||||
},
|
||||
"browse_book": {
|
||||
"comment": "COMENTARIO",
|
||||
"date_created": "CREACIÓN",
|
||||
"date_modified": "ÚLTIMA MODIFICACIÓN",
|
||||
"download_file": "Baixar ficheiro",
|
||||
"file": "FICHEIRO",
|
||||
"format": "FORMATO",
|
||||
"isbn": "ISBN",
|
||||
"links": "LIGAZÓNS",
|
||||
"navigation_within_readlist": "Navegación na lista de lectura:{name}",
|
||||
"outdated_tooltip": "Cambiouse o ficheiro deste libro; é necesario volver analizalo",
|
||||
"read_book": "Ler libro",
|
||||
"read_incognito": "Ler de incógnito",
|
||||
"remove_from_collection": "Quitar libro da colección",
|
||||
"remove_from_readlist": "Quitar libro da lista de lectura",
|
||||
"size": "TAMAÑO"
|
||||
},
|
||||
"browse_collection": {
|
||||
"edit_collection": "Editar colección",
|
||||
"edit_elements": "Editar elementos",
|
||||
"manual_ordering": "Ordenación manual"
|
||||
},
|
||||
"browse_readlist": {
|
||||
"edit_elements": "Editar elementos",
|
||||
"edit_readlist": "Editar lista de lectura",
|
||||
"manual_ordering": "Ordenación manual"
|
||||
},
|
||||
"browse_series": {
|
||||
"earliest_year_from_release_dates": "Este é o ano máis temperán entre as datas de lanzamento de tódolos libros da serie",
|
||||
"remove_from_collection": "Quitar serie da colección",
|
||||
"series_no_summary": "Esta serie non ten sumario, así que escollemos un por ti!",
|
||||
"summary_from_book": "Sumario do libro {number}:"
|
||||
},
|
||||
"collections_expansion_panel": {
|
||||
"manage_collection": "Xestionar colección",
|
||||
"title": "{name} colección"
|
||||
},
|
||||
"common": {
|
||||
"locale_name": "Galego"
|
||||
"age": "Idade",
|
||||
"all_libraries": "Tódalas bibliotecas",
|
||||
"all_of": "Todo",
|
||||
"any_of": "Calquera",
|
||||
"book": "Libro",
|
||||
"books": "Libros",
|
||||
"books_n": "Ningún libro | 1 libro | {count} libros",
|
||||
"books_total": "{count} / {total} libros",
|
||||
"cancel": "Cancelar",
|
||||
"cbx": "Arquivos de Cómics",
|
||||
"choose_image": "Escoller unha imaxe",
|
||||
"close": "Pechar",
|
||||
"collections": "Coleccións",
|
||||
"copied": "Copiado!",
|
||||
"create": "Crear",
|
||||
"delete": "Borrar",
|
||||
"dimension": "anch.: {width}, alt.: {height}",
|
||||
"discard": "Descartar",
|
||||
"disk_space": "Espazo en disco",
|
||||
"dismiss": "Desbota",
|
||||
"download": "Baixar",
|
||||
"drag_drop": "Arrastra e solta",
|
||||
"duplicate": "Duplicar",
|
||||
"email": "Correo electrónico",
|
||||
"epub": "EPUB",
|
||||
"error": "Erro",
|
||||
"filename": "Nome de ficheiro",
|
||||
"filter_no_matches": "O filtro activo non atopa semellanzas",
|
||||
"genre": "Xénero",
|
||||
"go_to_collection": "Ir á colección",
|
||||
"go_to_library": "Ir á biblioteca",
|
||||
"go_to_readlist": "Ir á lista de lectura",
|
||||
"go_to_series": "Ir á serie",
|
||||
"i_understand": "Entendido",
|
||||
"library": "Biblioteca",
|
||||
"locale_name": "Galego",
|
||||
"locale_rtl": "false",
|
||||
"lock_all": "Bloquea todo",
|
||||
"media": "Medios",
|
||||
"more": "Máis",
|
||||
"n_selected": "{count} seleccionado(s)",
|
||||
"nothing_to_show": "Nada que amosar",
|
||||
"ok": "Ok",
|
||||
"oneshot": "Volume único",
|
||||
"outdated": "Desactualizado",
|
||||
"page": "Páxina",
|
||||
"page_number": "Número de páxina",
|
||||
"pages": "páxinas",
|
||||
"pages_left": "Non quedan páxinas | Queda 1 páxina | Quedan {count} páxinas",
|
||||
"pages_n": "Ningunha páxina | 1 páxina | {count} páxinas",
|
||||
"password": "Contrasinal",
|
||||
"pdf": "PDF",
|
||||
"pending_tasks": "Sen tarefas pendentes | 1 tarefa pendente | {count} tarefas pendentes"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@
|
|||
},
|
||||
"author_roles": {
|
||||
"colorist": "koloristi",
|
||||
"cover": "omot",
|
||||
"cover": "naslovnica",
|
||||
"editor": "urednici",
|
||||
"inker": "bojitelj",
|
||||
"letterer": "tipografi",
|
||||
|
|
@ -109,7 +109,7 @@
|
|||
"notification_poster_set_series": "Trenutačna stranica je sada postavljena kao poster serije.",
|
||||
"paged_reader_layout": {
|
||||
"double": "Dvije stranice",
|
||||
"double_no_cover": "Dvije stranice (bez omota)",
|
||||
"double_no_cover": "Dvije stranice (bez naslovnice)",
|
||||
"single": "Jedna stranica"
|
||||
},
|
||||
"reader_settings": "Postavke čitača",
|
||||
|
|
@ -253,7 +253,7 @@
|
|||
"nothing_to_show": "Nema ničega za pokazati",
|
||||
"ok": "U redu",
|
||||
"oneshot": "Izdanje bez nastavka",
|
||||
"outdated": "Neaktualno",
|
||||
"outdated": "Zastarjelo",
|
||||
"page": "Stranica",
|
||||
"page_number": "Broj stranice",
|
||||
"pages": "stranice",
|
||||
|
|
@ -484,7 +484,7 @@
|
|||
"field_scanner_empty_trash_after_scan": "Automatski isprazni smeće nakon svakog pretraživanja",
|
||||
"field_scanner_force_directory_modified_time": "Pretraži mape na osnovi vremena promjene",
|
||||
"field_scanner_scan_startup": "Pretraži tijekom pokretanja",
|
||||
"field_series_cover": "Omot serije",
|
||||
"field_series_cover": "Naslovnica serije",
|
||||
"file_browser_dialog_button_confirm": "Odaberi",
|
||||
"file_browser_dialog_title": "Osnovna mapa biblioteke",
|
||||
"label_analysis": "Analiza",
|
||||
|
|
@ -495,9 +495,9 @@
|
|||
"label_import_local": "Uvezi lokalne medije",
|
||||
"label_import_mylar": "Uvezi metapodatke generirane pomoću Mylar-a",
|
||||
"label_scan_directory_exclusions": "Isključivanja mapa",
|
||||
"label_scan_types": "Traži ove vrste datoteka",
|
||||
"label_scanner": "Tražilica",
|
||||
"label_series_cover": "Omot serije",
|
||||
"label_scan_types": "Pretraži ove vrste datoteka",
|
||||
"label_scanner": "Pretraživanje",
|
||||
"label_series_cover": "Naslovnica serije",
|
||||
"tab_general": "Općenito",
|
||||
"tab_metadata": "Metapodaci",
|
||||
"tab_options": "Opcije",
|
||||
|
|
@ -526,8 +526,8 @@
|
|||
"button_confirm": "Spremi promjene",
|
||||
"dialog_title_multiple": "Uredi {count} seriju | Uredi {count} serije",
|
||||
"dialog_title_single": "Uredi {series}",
|
||||
"field_age_rating": "Dobna kategorija",
|
||||
"field_age_rating_error": "Dobna kategorija mora biti 0 ili više",
|
||||
"field_age_rating": "Dobna klasifikacija",
|
||||
"field_age_rating_error": "Dobna klasifikacija mora biti 0 ili više",
|
||||
"field_genres": "Žanrovi",
|
||||
"field_labels": "Etikete",
|
||||
"field_language": "Jezik",
|
||||
|
|
@ -721,7 +721,7 @@
|
|||
},
|
||||
"media_status": {
|
||||
"ERROR": "Greška",
|
||||
"OUTDATED": "Neaktualno",
|
||||
"OUTDATED": "Zastarjelo",
|
||||
"READY": "Spremno",
|
||||
"UNKNOWN": "Nepoznato",
|
||||
"UNSUPPORTED": "Nepodržano"
|
||||
|
|
@ -835,7 +835,7 @@
|
|||
"ERR_1039": "Greška prilikom dohvaćanja pozicija EPUB-a"
|
||||
},
|
||||
"filter": {
|
||||
"age_rating": "dobna kategorija",
|
||||
"age_rating": "dobna klasifikacija",
|
||||
"age_rating_none": "Bez",
|
||||
"any": "Bilo koji",
|
||||
"complete": "Dovršeno",
|
||||
|
|
@ -973,9 +973,9 @@
|
|||
"button_scan_libraries": "Pretraži sve biblioteke",
|
||||
"button_scan_libraries_deep": "Pretraži sve biblioteke (duboko)",
|
||||
"button_shutdown": "Isključi",
|
||||
"download_log": "Preuzmi datoteku zapisa",
|
||||
"download_log": "Preuzmi log-datoteku",
|
||||
"notification_tasks_cancelled": "Nema zadataka za prekidanje | Jedan zadatak prekinut | {count} zadatka prekinuta",
|
||||
"section_title": "Upravljanje serverom"
|
||||
"section_title": "Upravljanje serverima"
|
||||
},
|
||||
"tab_title": "Server",
|
||||
"updates": "Aktualiziranja"
|
||||
|
|
@ -989,7 +989,7 @@
|
|||
"btn_confirm": "Da, ali samo ako su veće",
|
||||
"title": "Nanovo generiraj minijature"
|
||||
},
|
||||
"hint_kobo_port": "Postavi samo u slučaju problema sa sinkronizacijom omota i preuzimanja",
|
||||
"hint_kobo_port": "Postavi samo u slučaju problema sa sinkronizacijom naslovnica i preuzimanja",
|
||||
"label_delete_empty_collections": "Izbriši prazne zbirke nakon pretraživanja",
|
||||
"label_delete_empty_readlists": "Izbriši prazne liste čitanja nakon pretraživanja",
|
||||
"label_kepubify_path": "Staza do kepubify",
|
||||
|
|
|
|||
|
|
@ -396,15 +396,15 @@
|
|||
"dialog_title": "읽기 목록 삭제",
|
||||
"dialog_title_multiple": "읽기 목록 삭제",
|
||||
"warning_html": "읽기 목록 <b>{name}</b> 이(가) 이 서버에서 제거됩니다. 미디어 파일은 영향을 받지 않습니다. <b>이 일은 되돌릴 수 없습니다.</b> 계속하시겠습니까?",
|
||||
"warning_multiple_html": "{count}개의 읽기 목록이 서버에서 제거됩니다. 미디어 파일은 영향을 받지 않습니다. <b>이 일은 되돌릴 수 없습니다.</b> 계속하시겠습니까?"
|
||||
"warning_multiple_html": "{count}개의 읽기 목록이 서버에서 제거됩니다. 미디어 파일은 영향을 받지 않습니다. <b>이 작업은 되돌릴 수 없습니다.</b> 계속하시겠습니까?"
|
||||
},
|
||||
"delete_series": {
|
||||
"button_confirm": "삭제",
|
||||
"confirm_delete": "네, 시리즈 \"{name}\"와(과) 파일을 삭제합니다",
|
||||
"confirm_delete_multiple": "네, {count}개의 시리즈와 파일을 삭제합니다",
|
||||
"dialog_title": "시리즈 삭제",
|
||||
"warning_html": "시리즈 <b>{name}</b> 이(가) 저장된 미디어 파일과 함께 이 서버에서 제거됩니다. <b>이 일은 되돌릴 수 없습니다.</b> 계속하시겠습니까?",
|
||||
"warning_multiple_html": "{count}개의 시리즈가 저장된 미디어 파일과 함께 이 서버에서 제거됩니다. <b>이 일은 되돌릴 수 없습니다.</b> 계속하시겠습니까?"
|
||||
"warning_html": "시리즈 <b>{name}</b> 이(가) 저장된 미디어 파일과 함께 이 서버에서 제거됩니다. <b>이 작업은 되돌릴 수 없습니다.</b> 계속하시겠습니까?",
|
||||
"warning_multiple_html": "{count}개의 시리즈가 저장된 미디어 파일과 함께 이 서버에서 제거됩니다. <b>이 작업은 되돌릴 수 없습니다.</b> 계속하시겠습니까?"
|
||||
},
|
||||
"delete_user": {
|
||||
"button_confirm": "삭제",
|
||||
|
|
|
|||
|
|
@ -212,7 +212,7 @@
|
|||
"age": "Idade",
|
||||
"all_libraries": "Todas as bibliotecas",
|
||||
"all_of": "Todos",
|
||||
"any_of": "Qualquer",
|
||||
"any_of": "Qualquer um",
|
||||
"book": "Livro",
|
||||
"books": "Livros",
|
||||
"books_n": "Nenhum livro | 1 livro | {count} livros",
|
||||
|
|
@ -228,7 +228,7 @@
|
|||
"dimension": "l: {width}, a:{height}",
|
||||
"discard": "Descartar",
|
||||
"disk_space": "Espaço em disco",
|
||||
"dismiss": "Ignorar",
|
||||
"dismiss": "Dispensar",
|
||||
"download": "Baixar",
|
||||
"drag_drop": "Arrastar e soltar",
|
||||
"duplicate": "Duplicado",
|
||||
|
|
@ -319,7 +319,12 @@
|
|||
},
|
||||
"dialog": {
|
||||
"add_api_key": {
|
||||
"button_confirm": "Gerar"
|
||||
"button_confirm": "Gerar",
|
||||
"context": "Chaves API podem ser usadas para autenticar no protocolo Kobo Sync.",
|
||||
"dialog_title": "Gerar chave de API",
|
||||
"field_comment": "Comentar",
|
||||
"field_comment_hint": "Como a chave API será usada?",
|
||||
"info_copy": "Tenha a certeza de que a chave API foi salva. Você não poderá vê-la novamente!"
|
||||
},
|
||||
"add_to_collection": {
|
||||
"button_create": "Criar",
|
||||
|
|
@ -354,6 +359,12 @@
|
|||
"filter": "Filtrar por número, título ou data de lançamento",
|
||||
"title": "Selecionar livro"
|
||||
},
|
||||
"delete_apikey": {
|
||||
"button_confirm": "Excluir",
|
||||
"confirm_delete": "Eu entendo, exclua a chave API \"{name}\"",
|
||||
"dialog_title": "Deletar chave API",
|
||||
"warning_html": "Quaisquer aplicativos ou scripts que utilizem esta chave API não poderão mais acessar a API Komga. Você não poderá desfazer esta ação."
|
||||
},
|
||||
"delete_book": {
|
||||
"button_confirm": "Excluir",
|
||||
"confirm_delete": "Sim, exclua o livro \"{name}\" e seus arquivos",
|
||||
|
|
@ -452,6 +463,7 @@
|
|||
"dialot_title_edit": "Editar Biblioteca",
|
||||
"field_analysis_analyze_dimensions": "Analisar as dimensões das paginas",
|
||||
"field_analysis_hash_files": "Computar hash para arquivos",
|
||||
"field_analysis_hash_koreader": "Computar hash para arquivos para o KOReader",
|
||||
"field_analysis_hash_pages": "Computar hash para páginas",
|
||||
"field_convert_to_cbz": "Converter automaticamente para CBZ",
|
||||
"field_import_barcode_isbn": "Código de barra ISBN",
|
||||
|
|
@ -465,6 +477,7 @@
|
|||
"field_import_local_artwork": "Mídia local",
|
||||
"field_import_mylar_series": "Metadados de séries",
|
||||
"field_name": "Nome",
|
||||
"field_oneshotsdirectory": "Diretório de One-Shots",
|
||||
"field_repair_extensions": "Reparar extensões de arquivo incorretas automaticamente",
|
||||
"field_root_folder": "Pasta raíz",
|
||||
"field_scan_interval": "Intervalo de scan",
|
||||
|
|
@ -503,6 +516,11 @@
|
|||
"tab_general": "Geral",
|
||||
"tab_poster": "Pôster"
|
||||
},
|
||||
"edit_recommended": {
|
||||
"button_confirm": "Salvar mudanças",
|
||||
"button_reset": "Redefinir para o padrão",
|
||||
"dialog_title": "Editar visualização recomendada"
|
||||
},
|
||||
"edit_series": {
|
||||
"button_cancel": "Cancelar",
|
||||
"button_confirm": "Salvar mudanças",
|
||||
|
|
@ -571,6 +589,10 @@
|
|||
},
|
||||
"title": "Nome do Arquivo de Destino"
|
||||
},
|
||||
"force_kobo_sync": {
|
||||
"dialog_title": "Forçar sincronização com Kobo",
|
||||
"warning_html": "Isso excluirá todo o histórico de sincronização para esta chave de API. Seu Kobo sincronizará tudo na próxima sincronização."
|
||||
},
|
||||
"password_change": {
|
||||
"button_cancel": "Cancelar",
|
||||
"button_confirm": "Mudar senha",
|
||||
|
|
@ -587,6 +609,7 @@
|
|||
},
|
||||
"series_picker": {
|
||||
"label_search_series": "Buscar Séries",
|
||||
"no_results": "Nenhuma serie encontrada",
|
||||
"title": "Selecionar Série"
|
||||
},
|
||||
"server_stop": {
|
||||
|
|
@ -625,12 +648,41 @@
|
|||
}
|
||||
},
|
||||
"duplicate_pages": {
|
||||
"action_auto_delete_remaining": "Exclusão automática restantes {count}",
|
||||
"action_delete_auto": "Exclusão automática",
|
||||
"action_delete_manual": "Exclusão manual",
|
||||
"action_delete_matches": "Excluir correspondências",
|
||||
"action_ignore": "Ignorar",
|
||||
"action_ignore_remaining": "{count} ignorados restantes",
|
||||
"action_manual_delete_remaining": "Exclusão manual restantes {count}",
|
||||
"confirm_auto_delete_remaining": "Todos os hashes de página restantes nesta página {count} serão marcados para exclusão automática.",
|
||||
"confirm_manual_delete_remaining": "Todos os hashes de página restantes nesta página {count} serão marcados para exclusão manual.",
|
||||
"delete_to_save": "Exclua para economizar {size}",
|
||||
"deleted_count": "Deletada {count} vezes",
|
||||
"empty_title": "Nenhuma página duplicada encontrada",
|
||||
"empty_title_known": "Nenhuma duplicata encontrada",
|
||||
"filter": {
|
||||
"size": "Tamanho"
|
||||
}
|
||||
"count": "Contagem",
|
||||
"date_added": "Data de adição",
|
||||
"date_modified": "Data de modificação",
|
||||
"delete_count": "Contagem de exclusão",
|
||||
"delete_size": "Espaço economizado",
|
||||
"match_count": "Contagem de correspondência",
|
||||
"size": "Tamanho",
|
||||
"total_size": "Tamanho total"
|
||||
},
|
||||
"info": "Excluir páginas duplicadas modificará seus arquivos. Faça backup de seus arquivos e use a exclusão manual antes de usar a exclusão automática.",
|
||||
"known": "Conhecidas",
|
||||
"matches_n": "Nenhuma correspondência | 1 correspondência | {count} correspondências",
|
||||
"new": "Novo",
|
||||
"saved_size": "Salvou {size}",
|
||||
"title": "Duplicar páginas",
|
||||
"unknown_size": "Tamanho desconhecido"
|
||||
},
|
||||
"duplicates": {
|
||||
"file_hash": "Hash do arquivo",
|
||||
"size": "Tamanho",
|
||||
"title": "Duplicar arquivos",
|
||||
"url": "URL"
|
||||
},
|
||||
"enums": {
|
||||
|
|
@ -638,6 +690,35 @@
|
|||
"HARDLINK": "Hardlink/Copiar arquivos",
|
||||
"MOVE": "Mover Arquivos"
|
||||
},
|
||||
"epubreader": {
|
||||
"appearances": {
|
||||
"day": "Dia",
|
||||
"night": "Noite",
|
||||
"sepia": "Sépia"
|
||||
},
|
||||
"column_count": {
|
||||
"auto": "Auto",
|
||||
"one": "Uma",
|
||||
"two": "Duas"
|
||||
},
|
||||
"reading_direction": {
|
||||
"auto": "Automático",
|
||||
"ltr": "Da esquerda para a direita",
|
||||
"rtl": "Da direita para a esquerda"
|
||||
}
|
||||
},
|
||||
"historical_event_type": {
|
||||
"BookConverted": "Livro convertido",
|
||||
"BookFileDeleted": "Arquivo de livro excluído",
|
||||
"BookImported": "Livro importado",
|
||||
"DuplicatePageDeleted": "Página duplicada excluída",
|
||||
"SeriesFolderDeleted": "Pasta da série excluída"
|
||||
},
|
||||
"media_profile": {
|
||||
"DIVINA": "DIVINA",
|
||||
"EPUB": "EPUB",
|
||||
"PDF": "PDF"
|
||||
},
|
||||
"media_status": {
|
||||
"ERROR": "Erro",
|
||||
"OUTDATED": "Desatualizado",
|
||||
|
|
@ -645,12 +726,25 @@
|
|||
"UNKNOWN": "Desconhecido",
|
||||
"UNSUPPORTED": "Não Suportado"
|
||||
},
|
||||
"page_hash_action": {
|
||||
"DELETE_AUTO": "Exclusão automática",
|
||||
"DELETE_MANUAL": "Exclusão manual",
|
||||
"IGNORE": "Ignorar"
|
||||
},
|
||||
"reading_direction": {
|
||||
"LEFT_TO_RIGHT": "Esquerda para direita",
|
||||
"RIGHT_TO_LEFT": "Direita para esquerda",
|
||||
"VERTICAL": "Vertical",
|
||||
"WEBTOON": "Webtoon"
|
||||
},
|
||||
"scan_interval": {
|
||||
"DAILY": "Diariamente",
|
||||
"DISABLED": "Desativado",
|
||||
"EVERY_12H": "A cada 12 horas",
|
||||
"EVERY_6H": "A cada 6 horas",
|
||||
"HOURLY": "A cada 1 hora",
|
||||
"WEEKLY": "Semanalmente"
|
||||
},
|
||||
"series_cover": {
|
||||
"FIRST": "Primeiro",
|
||||
"FIRST_UNREAD_OR_FIRST": "Primeiro não lido ou primeiro",
|
||||
|
|
@ -662,6 +756,45 @@
|
|||
"ENDED": "Finalizado",
|
||||
"HIATUS": "Interrompido",
|
||||
"ONGOING": "Em andamento"
|
||||
},
|
||||
"thumbnail_size": {
|
||||
"DEFAULT": "Padrão (300px)",
|
||||
"LARGE": "Grande (900px)",
|
||||
"MEDIUM": "Médio (600px)",
|
||||
"XLARGE": "Extra Grande (1200px)"
|
||||
}
|
||||
},
|
||||
"epubreader": {
|
||||
"current_chapter": "Capítulo atual",
|
||||
"page_of": "Página {page} de {count}",
|
||||
"publisher_font": "Editora",
|
||||
"settings": {
|
||||
"column_count": "Colunas",
|
||||
"font_family": "Fonte",
|
||||
"layout": "Layout",
|
||||
"layout_paginated": "Paginado",
|
||||
"layout_scroll": "Rolagem",
|
||||
"navigation_mode": "Modo de navegação",
|
||||
"navigation_options": {
|
||||
"both": "Ambos",
|
||||
"buttons": "Botões",
|
||||
"click": "Clique / Toque"
|
||||
},
|
||||
"page_margins": "Margem de Páginas",
|
||||
"viewing_theme": "Tema de visualização"
|
||||
},
|
||||
"shortcuts": {
|
||||
"cycle_pagination": "Contagem de colunas do ciclo",
|
||||
"cycle_viewing_theme": "Tema de visualização do ciclo",
|
||||
"font_size_decrease": "Diminuir tamanho da fonte",
|
||||
"font_size_increase": "Aumentar tamanho da fonte",
|
||||
"menus": "Menus",
|
||||
"next": "Avançar",
|
||||
"previous": "Voltar",
|
||||
"reader_navigation": "Navegação do leitor",
|
||||
"scroll": "Altere o layout para rolagem",
|
||||
"settings": "Configurações",
|
||||
"show_hide_toc": "Mostrar/ocultar índice"
|
||||
}
|
||||
},
|
||||
"error_codes": {
|
||||
|
|
@ -686,18 +819,37 @@
|
|||
"ERR_1023": "Livro já presente na Lista de Leitura",
|
||||
"ERR_1024": "Erro de login OAuth2: nenhum atributo de e-mail",
|
||||
"ERR_1025": "Erro de login OAuth2: não existe nenhum usuário local com esse e-mail",
|
||||
"ERR_1026": "Erro de login do OpenID Connect: e-mail não verificado"
|
||||
"ERR_1026": "Erro de login do OpenID Connect: e-mail não verificado",
|
||||
"ERR_1027": "Erro de login OpenID Connect: o atributo email_verified está ausente",
|
||||
"ERR_1028": "Erro de login OpenID Connect: o atributo email está ausente",
|
||||
"ERR_1029": "O ComicRack CBL não contém nenhum elemento Book",
|
||||
"ERR_1030": "O ComicRack CBL não contém nenhum elemento Name",
|
||||
"ERR_1031": "ComicRack CBL Book está sem série ou número",
|
||||
"ERR_1032": "O arquivo EPUB tem o tipo de mídia errado",
|
||||
"ERR_1033": "Algumas entradas estão faltando",
|
||||
"ERR_1034": "Uma chave de API com esse comentário já existe",
|
||||
"ERR_1035": "Erro ao obter o EPUB TOC",
|
||||
"ERR_1036": "Erro ao obter EPUB Landmarks",
|
||||
"ERR_1037": "Erro ao obter a lista de páginas do EPUB",
|
||||
"ERR_1038": "Erro ao obter páginas EPUB DIVINA",
|
||||
"ERR_1039": "Erro ao obter posições do EPUB"
|
||||
},
|
||||
"filter": {
|
||||
"age_rating": "classificação etária",
|
||||
"age_rating_none": "Nenhuma",
|
||||
"any": "Qualquer",
|
||||
"complete": "Completo",
|
||||
"genre": "gênero",
|
||||
"in_progress": "Em progresso",
|
||||
"language": "idioma",
|
||||
"library": "biblioteca",
|
||||
"media_profile": "Perfil de mídia",
|
||||
"media_status": "Estado da mídia",
|
||||
"oneshot": "One-shot",
|
||||
"publisher": "editora",
|
||||
"read": "Lidos",
|
||||
"release_date": "data de lançamento",
|
||||
"sharing_label": "Etiqueta de compartilhamento",
|
||||
"status": "estado",
|
||||
"tag": "tag",
|
||||
"unread": "Não Lidos"
|
||||
|
|
@ -708,8 +860,13 @@
|
|||
},
|
||||
"history": {
|
||||
"header": {
|
||||
"book": "Livro"
|
||||
}
|
||||
"book": "Livro",
|
||||
"date": "Data",
|
||||
"details": "Detalhes",
|
||||
"series": "Séries",
|
||||
"type": "Tiopo"
|
||||
},
|
||||
"title": "Histórico"
|
||||
},
|
||||
"home": {
|
||||
"theme": "Tema",
|
||||
|
|
@ -717,6 +874,8 @@
|
|||
},
|
||||
"library_navigation": {
|
||||
"browse": "Navegar",
|
||||
"browse_books": "Livros",
|
||||
"browse_series": "Séries",
|
||||
"collections": "Coleções",
|
||||
"readlists": "Listas de Leitura",
|
||||
"recommended": "Recomendado"
|
||||
|
|
@ -749,15 +908,34 @@
|
|||
"empty_trash": "Esvaziar a lixeira",
|
||||
"mark_read": "Marcar como lido",
|
||||
"mark_unread": "Marcar como não lido",
|
||||
"pin": "Fixar",
|
||||
"refresh_metadata": "Atualizar metadados",
|
||||
"scan_library_files": "Varrer arquivos na biblioteca",
|
||||
"select_all": "Selecionar todas"
|
||||
"scan_library_files": "Escanear arquivos da biblioteca",
|
||||
"scan_library_files_deep": "Escanear arquivos da biblioteca (profundo)",
|
||||
"select_all": "Selecionar todas",
|
||||
"unpin": "Liberar"
|
||||
},
|
||||
"metrics": {
|
||||
"library_books": "Livros por biblioteca",
|
||||
"library_disk_space": "Espaço ocupado pela biblioteca",
|
||||
"library_series": "Série por biblioteca",
|
||||
"library_sidecars": "Arquivos auxiliares por biblioteca",
|
||||
"tasks_executed": "Tarefas executadas",
|
||||
"tasks_total_time": "Tempo total das tarefas",
|
||||
"title": "Métricas"
|
||||
},
|
||||
"missing_posters": {
|
||||
"title": "Posters Ausentes"
|
||||
},
|
||||
"navigation": {
|
||||
"home": "Início",
|
||||
"libraries": "Bibliotecas",
|
||||
"logout": "Sair"
|
||||
},
|
||||
"no_libraries_pinned": {
|
||||
"subtitle": "Você pode fixar uma biblioteca no menu de 3 pontos",
|
||||
"title": "Nenhuma biblioteca fixada"
|
||||
},
|
||||
"page_not_found": {
|
||||
"go_back_to_home_page": "Retornar à página inicial",
|
||||
"page_does_not_exist": "A página que você procura não existe.",
|
||||
|
|
@ -767,6 +945,12 @@
|
|||
"less": "Ver menos",
|
||||
"more": "Ver mais"
|
||||
},
|
||||
"readlist_import": {
|
||||
"row": {
|
||||
"duplicate_book": "Duplicar livro",
|
||||
"error_choose_book": "Escolha um livro"
|
||||
}
|
||||
},
|
||||
"readlists_expansion_panel": {
|
||||
"manage_readlist": "Gerenciar lista de leitura",
|
||||
"title": "Lista de leitura: {name}"
|
||||
|
|
@ -787,17 +971,41 @@
|
|||
"button_cancel_all_tasks": "Cancelar todas as tarefas",
|
||||
"button_empty_trash": "Limpar a lixeira de todas as bibliotecas",
|
||||
"button_scan_libraries": "Escanear todas as bibliotecas",
|
||||
"button_scan_libraries_deep": "Escanear todas bibliotecas (profundo)",
|
||||
"button_shutdown": "Desligar",
|
||||
"download_log": "Baixar arquivo de log",
|
||||
"notification_tasks_cancelled": "Nenhuma tarefa para cancelar | Uma tarefa cancelada | {count} tarefas canceladas",
|
||||
"section_title": "Gerenciamento do Servidor"
|
||||
},
|
||||
"tab_title": "Servidor"
|
||||
"tab_title": "Servidor",
|
||||
"updates": "Atualizações"
|
||||
},
|
||||
"server_settings": {
|
||||
"config_precedence": "Prevalece sobre o arquivo de configuração",
|
||||
"dialog_regenerate_thumbnails": {
|
||||
"body": "O tamanho das miniaturas mudou. Deseja gerar novamente as miniaturas dos livros?",
|
||||
"btn_alternate": "Sim, de todos os livros",
|
||||
"btn_cancel": "Não",
|
||||
"btn_confirm": "Sim, mas apenas se tiverem aumentado",
|
||||
"title": "Gerar miniaturas novamente"
|
||||
},
|
||||
"hint_kobo_port": "Definir apenas em caso de problemas de sincronização com capas e downloads",
|
||||
"label_delete_empty_collections": "Exclua coleções vazias depois do escaneamento",
|
||||
"label_delete_empty_readlists": "Exclua listas de leitura vazias depois do escaneamento",
|
||||
"label_kepubify_path": "Localização do kepubify",
|
||||
"label_kobo_port": "Porta externa do Kobo Sync",
|
||||
"label_kobo_proxy": "Proxy Kobo Sync para sincronização com a Kobo Store",
|
||||
"label_rememberme_duration": "Duração do Lembrar de mim (em dias)",
|
||||
"label_server_context_path": "URL Base",
|
||||
"label_server_port": "Porta do servidor",
|
||||
"label_task_pool_size": "Threads de tarefas",
|
||||
"label_thumbnail_size": "Tamanho das miniaturas",
|
||||
"requires_restart": "Requer reinicialização para entrar em vigor",
|
||||
"server_settings": "Configurações do Servidor"
|
||||
},
|
||||
"settings_user": {
|
||||
"change_password": "Alterar senha",
|
||||
"edit_restrictions": "Editar restrições",
|
||||
"edit_user": "Editar Usuário",
|
||||
"latest_activity": "Última atividade: {date}",
|
||||
"no_recent_activity": "Nenhuma atividade recente",
|
||||
|
|
@ -807,13 +1015,17 @@
|
|||
"sort": {
|
||||
"books_count": "Total de livros",
|
||||
"date_added": "Data de adição",
|
||||
"date_read": "Data de leitura",
|
||||
"date_updated": "Data de atualização",
|
||||
"file_name": "Nome do arquivo",
|
||||
"file_size": "Tamanho do arquivo",
|
||||
"folder_name": "Nome da pasta",
|
||||
"name": "Nome",
|
||||
"number": "Número",
|
||||
"release_date": "Data de lançamento"
|
||||
"page_count": "Quantidade de páginas",
|
||||
"random": "Aleatório",
|
||||
"release_date": "Data de lançamento",
|
||||
"series": "Séries"
|
||||
},
|
||||
"theme": {
|
||||
"dark": "Escuro",
|
||||
|
|
@ -822,6 +1034,7 @@
|
|||
},
|
||||
"thumbnail_card": {
|
||||
"tooltip_delete": "Excluir",
|
||||
"tooltip_generated": "Arte gerada",
|
||||
"tooltip_mark_as_selected": "Marcar como selecionado",
|
||||
"tooltip_selected": "Selecionado",
|
||||
"tooltip_sidecar": "Mídia local",
|
||||
|
|
@ -830,16 +1043,47 @@
|
|||
"tooltip_too_big": "Arquivo muito grande!",
|
||||
"tooltip_user_uploaded": "Enviado pelo usuário"
|
||||
},
|
||||
"titles_more": {
|
||||
"less": "Menos títulos",
|
||||
"more": "Mais títulos"
|
||||
},
|
||||
"ui_settings": {
|
||||
"general": "Geral",
|
||||
"label_oauth2_auto_login": "Login OAuth2 automático",
|
||||
"label_oauth2_hide_login": "Ocultar campos de login se OAuth2 estiver ativado",
|
||||
"label_poster_blur_unread": "Desfocar poster de livros e séries não lidos",
|
||||
"label_poster_stretch": "Esticar pôster para ajustar ao card",
|
||||
"label_series_groups": "Agrupamento de séries",
|
||||
"section_oauth2": "OAuth2",
|
||||
"series_groups": {
|
||||
"alpha": "Alfabética",
|
||||
"japanese": "Gojūon (japonês)"
|
||||
},
|
||||
"tooltip_oauth2_auto_login": "É necessário um único provedor OAuth2 e a ativação de 'ocultar campos de login'"
|
||||
},
|
||||
"updates": {
|
||||
"available": "Atualizações disponiveis",
|
||||
"latest_installed": "A versão mais recente do Komga já está instalada"
|
||||
},
|
||||
"user_roles": {
|
||||
"ADMIN": "Administrador",
|
||||
"FILE_DOWNLOAD": "Baixar arquivos",
|
||||
"KOBO_SYNC": "Kobo Sync",
|
||||
"KOREADER_SYNC": "KOReader Sync",
|
||||
"PAGE_STREAMING": "Streaming de páginas",
|
||||
"USER": "Usuário"
|
||||
},
|
||||
"users": {
|
||||
"api_keys": "Chaves API",
|
||||
"authentication_activity": "Atividade de Autenticação",
|
||||
"users": "Usuários"
|
||||
},
|
||||
"validation": {
|
||||
"context_path": "Deve começar com '/', não terminar com '/-_' e conter apenas '/-_a-z0-9'",
|
||||
"one_or_more": "Deve ser 1 ou mais",
|
||||
"tcp_port": "Deve estar entre 1 e 65535",
|
||||
"zero_or_more": "Deve ser 0 ou mais"
|
||||
},
|
||||
"welcome": {
|
||||
"add_library": "Adicionar biblioteca",
|
||||
"no_libraries_yet": "Ainda não foram adicionadas bibliotecas!",
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@
|
|||
"pageText": "{0}-{1} из {2}"
|
||||
},
|
||||
"dataIterator": {
|
||||
"loadingText": "Загрузка объектов...",
|
||||
"noResultsText": "Подходящих записей не найдено"
|
||||
"loadingText": "Загрузка элементов...",
|
||||
"noResultsText": "Совпадений не найдено"
|
||||
},
|
||||
"dataTable": {
|
||||
"itemsPerPageText": "Строк на странице:",
|
||||
|
|
@ -15,30 +15,33 @@
|
|||
"counter": "Файлов: {0}",
|
||||
"counterSize": "Файлов: {0} (всего {1})"
|
||||
},
|
||||
"noDataText": "Отсутствуют данные"
|
||||
"noDataText": "Данные отсутствуют"
|
||||
},
|
||||
"account_settings": {
|
||||
"account_settings": "Настройки Аккаунта",
|
||||
"account_settings": "Настройки аккаунта",
|
||||
"api_key": {
|
||||
"created_date": "Дата создания: {date}",
|
||||
"generate_api_key": "Сгенерировать API ключ",
|
||||
"force_kobo_sync": "Принудительная синхронизация с Kobo",
|
||||
"generate_api_key": "Сгенерировать ключ API",
|
||||
"no_keys": "Ни одного ключа API еще не создано"
|
||||
},
|
||||
"change_password": "изменить пароль"
|
||||
"change_password": "изменить пароль",
|
||||
"details": "Подробности",
|
||||
"my_account": "Мой аккаунт"
|
||||
},
|
||||
"announcements": {
|
||||
"mark_all_read": "Пометить всё как прочитанное",
|
||||
"mark_read": "Пометить как прочитанное",
|
||||
"mark_all_read": "Отметить всё как прочитанное",
|
||||
"mark_read": "Отметить как прочитанное",
|
||||
"tab_title": "Объявления"
|
||||
},
|
||||
"authentication_activity": {
|
||||
"api_key": "API Ключ",
|
||||
"datetime": "Дата / Время",
|
||||
"api_key": "API-ключ",
|
||||
"datetime": "Дата/Время",
|
||||
"email": "Эл. почта",
|
||||
"error": "Ошибка",
|
||||
"ip": "IP-адрес",
|
||||
"source": "Источник",
|
||||
"success": "Статус",
|
||||
"success": "Успех",
|
||||
"user_agent": "User Agent"
|
||||
},
|
||||
"author_roles": {
|
||||
|
|
@ -54,18 +57,18 @@
|
|||
"book_card": {
|
||||
"error": "Ошибка",
|
||||
"no_release_date": "Дата релиза отсутствует",
|
||||
"unknown": "Необходимо проанализировать",
|
||||
"unknown": "Подлежит анализу",
|
||||
"unread": "Не прочитано",
|
||||
"unsupported": "Неподдерживаемый"
|
||||
"unsupported": "Не поддерживается"
|
||||
},
|
||||
"book_import": {
|
||||
"button_browse": "Обзор",
|
||||
"button_import": "Импортировать",
|
||||
"button_import": "Импорт",
|
||||
"button_scan": "Сканировать",
|
||||
"button_select_series": "Выберите Серию",
|
||||
"button_select_series": "Выберите серию",
|
||||
"field_import_path": "Импортировать из каталога",
|
||||
"info_part1": "Этот раздел позволяет вам импортировать файлы, которые находятся за пределами ваших существующих библиотек. Вы можете импортировать файлы только в существующие Серии, в этом случае Komga переместит или скопирует файлы в каталог выбранной Серии.",
|
||||
"info_part2": "Если вы выберете номер для книги и книга с таким номером уже существует, то вы сможете сравнить 2 книги. Если вы решите импортировать книгу, Komga обновит существующую книгу, эффективно заменив старый файл новым.",
|
||||
"info_part1": "Этот раздел позволяет вам импортировать файлы, которые находятся за пределами ваших существующих библиотек. Вы можете импортировать файлы только в существующие серии; в этом случае Komga переместит или скопирует файлы в каталог выбранной серии.",
|
||||
"info_part2": "Если вы укажете номер для книги, и книга с таким номером уже существует, вы сможете сравнить оба варианта. Если вы решите импортировать книгу, Komga обновит существующий вариант, заменив старый файл новым.",
|
||||
"no_files_found": "Файлы не найдены",
|
||||
"notification": {
|
||||
"go_to_book": "Перейти к книге",
|
||||
|
|
@ -74,9 +77,9 @@
|
|||
"source_file": "Исходный файл: {file}"
|
||||
},
|
||||
"row": {
|
||||
"error_analyze_first": "Книгу нужно сначала проанализировать",
|
||||
"error_analyze_first": "Книга нуждается в предварительном анализе",
|
||||
"error_choose_series": "Выберите серию",
|
||||
"error_only_import_no_errors": "Можно импортировать только книги без ошибок",
|
||||
"error_only_import_no_errors": "Можно импортировать только книги без наличия ошибок",
|
||||
"warning_upgrade": "Существующая книга будет обновлена"
|
||||
},
|
||||
"table": {
|
||||
|
|
@ -90,10 +93,11 @@
|
|||
},
|
||||
"bookreader": {
|
||||
"beginning_of_book": "Вы находитесь в начале книги.",
|
||||
"changing_reading_direction": "Изменение Направления Чтения на",
|
||||
"cycling_page_layout": "Переключить Формат Страниц",
|
||||
"cycling_scale": "Переключить Масштабирование",
|
||||
"cycling_side_padding": "Переключить Боковой Отступ",
|
||||
"changing_reading_direction": "Изменение направления чтения на",
|
||||
"cycling_page_layout": "Переключение макета страницы",
|
||||
"cycling_page_margin": "Переключение полей страницы",
|
||||
"cycling_scale": "Масштабирование",
|
||||
"cycling_side_padding": "Переключение боковых отступов",
|
||||
"download_current_page": "Скачать текущую страницу",
|
||||
"end_of_book": "Вы достигли конца книги.",
|
||||
"from_series_metadata": "из метаданных серии",
|
||||
|
|
@ -104,8 +108,8 @@
|
|||
"notification_poster_set_readlist": "Текущая страница теперь используется в качестве постера списка чтения.",
|
||||
"notification_poster_set_series": "Текущая страница теперь используется в качестве постера серии.",
|
||||
"paged_reader_layout": {
|
||||
"double": "Двойные страницы",
|
||||
"double_no_cover": "Двойные страницы (без обложки)",
|
||||
"double": "Две страницы",
|
||||
"double_no_cover": "Две страницы (без обложки)",
|
||||
"single": "Одна страница"
|
||||
},
|
||||
"reader_settings": "Настройки Ридера",
|
||||
|
|
@ -114,16 +118,16 @@
|
|||
"continuous_width": "По ширине",
|
||||
"height": "По высоте",
|
||||
"original": "Исходное",
|
||||
"screen": "По экрану",
|
||||
"screen": "По размеру экрана",
|
||||
"width": "По ширине",
|
||||
"width_shrink_only": "По ширине (с отступами)"
|
||||
},
|
||||
"set_current_page_as_book_poster": "Установить страницу в качестве постера для книги",
|
||||
"set_current_page_as_readlist_poster": "Установить страницу в качестве постера для списка чтения",
|
||||
"set_current_page_as_series_poster": "Установить страницу в качестве постера для серии",
|
||||
"set_current_page_as_book_poster": "Установить страницу в качестве обложки для книги",
|
||||
"set_current_page_as_readlist_poster": "Установить страницу в качестве обложки для списка чтения",
|
||||
"set_current_page_as_series_poster": "Установить страницу в качестве обложки для серии",
|
||||
"settings": {
|
||||
"always_fullscreen": "Всегда в полный экран",
|
||||
"animate_page_transitions": "Анимировать переходы страниц",
|
||||
"always_fullscreen": "Всегда полноэкранный режим",
|
||||
"animate_page_transitions": "Анимировать переходы между страницами",
|
||||
"background_color": "Цвет фона",
|
||||
"background_colors": {
|
||||
"black": "Чёрный",
|
||||
|
|
@ -134,54 +138,60 @@
|
|||
"general": "Общее",
|
||||
"gestures": "Жесты",
|
||||
"page_layout": "Формат страницы",
|
||||
"paged": "Настройки Отображения Страниц",
|
||||
"page_margin": "Поля страницы",
|
||||
"paged": "Настройки отображения страниц",
|
||||
"reading_mode": "Режим чтения",
|
||||
"scale_type": "Масштабирование",
|
||||
"side_padding": "Боковой отступ",
|
||||
"side_padding": "Боковые отступы",
|
||||
"side_padding_none": "Нет",
|
||||
"webtoon": "Параметры Режима Webtoon"
|
||||
"webtoon": "Настройки режима цифрового комикса"
|
||||
},
|
||||
"shortcuts": {
|
||||
"close": "Закрыть",
|
||||
"cycle_page_layout": "Переключить формат страниц",
|
||||
"cycle_page_layout": "Переключить макет страницы",
|
||||
"cycle_page_margin": "Переключить поля страницы",
|
||||
"cycle_scale": "Переключить масштаб",
|
||||
"cycle_side_padding": "Переключить боковой отступ",
|
||||
"cycle_side_padding": "Переключить боковые отступы",
|
||||
"first_page": "Первая страница",
|
||||
"fullscreen": "Войти/выйти из полноэкранного режима",
|
||||
"last_page": "Последняя страница",
|
||||
"left_to_right": "Слева Направо",
|
||||
"left_to_right": "Слева направо",
|
||||
"menus": "Меню",
|
||||
"next_page": "Следующая страница",
|
||||
"previous_page": "Предыдущая страница",
|
||||
"reader_navigation": "Навигация",
|
||||
"right_to_left": "Справа Налево",
|
||||
"right_to_left": "Справа налево",
|
||||
"settings": "Настройки",
|
||||
"show_hide_help": "Показать/скрыть помощь",
|
||||
"show_hide_settings": "Показать/скрыть меню настроек",
|
||||
"show_hide_thumbnails": "Показать/скрыть просмотр эскизов",
|
||||
"show_hide_thumbnails": "Показать/скрыть обозреватель миниатюр",
|
||||
"show_hide_toolbars": "Показать/скрыть панели инструментов",
|
||||
"vertical": "Вертикально",
|
||||
"webtoon": "Webtoon"
|
||||
"webtoon": "Цифровой комикс"
|
||||
},
|
||||
"tooltip_incognito": "Прогресс чтения не будет сохранен"
|
||||
},
|
||||
"browse_book": {
|
||||
"comment": "КОММЕНТАРИЙ",
|
||||
"date_created": "СОЗДАНО",
|
||||
"date_modified": "ПОСЛЕДНЕЕ ИЗМЕНЕНИЕ",
|
||||
"download_file": "Скачать файл",
|
||||
"file": "ФАЙЛ",
|
||||
"format": "ФОРМАТ",
|
||||
"isbn": "ISBN",
|
||||
"links": "ССЫЛКИ",
|
||||
"navigation_within_readlist": "Навигация в пределах списка чтения: {name}",
|
||||
"outdated_tooltip": "Файл этой книги изменен, книгу необходимо повторно проанализировать",
|
||||
"navigation_within_readlist": "Навигация внутри списка чтения: {name}",
|
||||
"outdated_tooltip": "Файл этой книги изменился, книгу необходимо повторно проанализировать",
|
||||
"read_book": "Читать книгу",
|
||||
"read_incognito": "Читать инкогнито",
|
||||
"remove_from_collection": "Удалить книгу из коллекции",
|
||||
"remove_from_readlist": "Удалить книгу из списка чтения",
|
||||
"size": "РАЗМЕР"
|
||||
},
|
||||
"browse_collection": {
|
||||
"edit_collection": "Редактировать коллекцию",
|
||||
"edit_elements": "Редактировать элементы",
|
||||
"manual_ordering": "ручной порядок"
|
||||
"manual_ordering": "ручная сортировка"
|
||||
},
|
||||
"browse_readlist": {
|
||||
"edit_elements": "Редактировать элементы",
|
||||
|
|
@ -189,17 +199,19 @@
|
|||
"manual_ordering": "ручная сортировка"
|
||||
},
|
||||
"browse_series": {
|
||||
"earliest_year_from_release_dates": "Это самая ранняя дата выпуска из всех книг в этой серии",
|
||||
"series_no_summary": "У серии нет описания, поэтому мы подобрали его для вас!",
|
||||
"earliest_year_from_release_dates": "Это самый ранний год из дат выхода всех книг серии",
|
||||
"remove_from_collection": "Удалить серию из коллекции",
|
||||
"series_no_summary": "У этой серии нет описания, поэтому мы подобрали его для вас!",
|
||||
"summary_from_book": "Краткое описание из книги {number}:"
|
||||
},
|
||||
"collections_expansion_panel": {
|
||||
"manage_collection": "Управлять коллекцией",
|
||||
"manage_collection": "Управление коллекцией",
|
||||
"title": "Коллекция {name}"
|
||||
},
|
||||
"common": {
|
||||
"age": "Возраст",
|
||||
"all_libraries": "Все Библиотеки",
|
||||
"all_libraries": "Все библиотеки",
|
||||
"any_of": "Любой из",
|
||||
"book": "Книга",
|
||||
"books": "Книги",
|
||||
"books_n": "Книг нет | 1 книга | {count} книг",
|
||||
|
|
@ -212,14 +224,16 @@
|
|||
"copied": "Скопировано!",
|
||||
"create": "Создать",
|
||||
"delete": "Удалить",
|
||||
"dimension": "шир.: {width} выс.: {height}",
|
||||
"dimension": "шир.: {width}, выс.: {height}",
|
||||
"discard": "Отмена",
|
||||
"disk_space": "Дисковое пространство",
|
||||
"dismiss": "Отклонить",
|
||||
"download": "Скачать",
|
||||
"drag_drop": "перетащить",
|
||||
"duplicate": "Дублировать",
|
||||
"email": "Эл. почта",
|
||||
"epub": "Epub",
|
||||
"error": "Ошибка",
|
||||
"filename": "Имя файла",
|
||||
"filter_no_matches": "Нет совпадений по заданному фильтру",
|
||||
"genre": "Жанр",
|
||||
|
|
@ -227,12 +241,16 @@
|
|||
"go_to_library": "Вернуться к библиотеке",
|
||||
"go_to_readlist": "Перейти к списку чтения",
|
||||
"go_to_series": "Перейти к серии",
|
||||
"i_understand": "Я понимаю",
|
||||
"library": "Библиотека",
|
||||
"locale_name": "Русский",
|
||||
"locale_rtl": "false",
|
||||
"lock_all": "Заблокировать все",
|
||||
"media": "Медиа",
|
||||
"more": "Ещё",
|
||||
"n_selected": "{count} выбрано",
|
||||
"nothing_to_show": "Нет данных для отображения",
|
||||
"ok": "OK",
|
||||
"outdated": "Устарело",
|
||||
"page": "Страница",
|
||||
"page_number": "Номер страницы",
|
||||
|
|
@ -242,17 +260,20 @@
|
|||
"password": "Пароль",
|
||||
"pdf": "PDF",
|
||||
"pending_tasks": "Нет незавершенных задач | 1 незавершенная задача | {count} незавершенных задач",
|
||||
"pinned_libraries": "Закреплённые библиотеки",
|
||||
"publisher": "Издатель",
|
||||
"read": "Читать",
|
||||
"read_on": "Читать {date}",
|
||||
"read_on": "Прочитано {date}",
|
||||
"readlist": "Список чтения",
|
||||
"readlists": "Списки чтения",
|
||||
"remember-me": "Запомнить",
|
||||
"required": "Необходимо",
|
||||
"remember-me": "Запомнить меня",
|
||||
"reorder": "Изменить порядок",
|
||||
"required": "Обязательно",
|
||||
"reset_filters": "Сбросить фильтры",
|
||||
"roles": "Роли",
|
||||
"save_changes": "Сохранить изменения",
|
||||
"series": "Серии",
|
||||
"settings": "Настройки",
|
||||
"tags": "Теги",
|
||||
"unavailable": "Недоступно",
|
||||
"unlock_all": "Разблокировать все",
|
||||
|
|
@ -326,7 +347,7 @@
|
|||
"confirm_delete": "Да, удалить коллекцию \"{name}\"",
|
||||
"confirm_delete_multiple": "Да, удалить выбранные ({count}) коллекции",
|
||||
"dialog_title": "Удалить коллекцию",
|
||||
"dialog_title_multiple": "Удалить Коллекции",
|
||||
"dialog_title_multiple": "Удалить коллекции",
|
||||
"warning_html": "Коллекция <b>{name}</b> будет удалена с этого сервера. Ваши медиа файлы не будут затронуты. Это действие <b>не может</b> быть отменено. Продолжить?",
|
||||
"warning_multiple_html": "Выбранные ({count}) коллекции будут удалены с этого сервера. Ваши медиафайлы не будут затронуты. Это действие <b>не может</b> быть отменено. Продолжить?"
|
||||
},
|
||||
|
|
@ -340,8 +361,8 @@
|
|||
"button_confirm": "Удалить",
|
||||
"confirm_delete": "Да, удалить список чтения \"{name}\"",
|
||||
"confirm_delete_multiple": "Да, удалить выбранные ({count}) списки чтения",
|
||||
"dialog_title": "Удалить Список Чтения",
|
||||
"dialog_title_multiple": "Удалить Списки чтения",
|
||||
"dialog_title": "Удалить список чтения",
|
||||
"dialog_title_multiple": "Удалить списки чтения",
|
||||
"warning_html": "Список чтения <b>{name}</b> будет удален с этого сервера. Ваши медиа файлы не будут затронуты. Это действие <b>не может</b> быть отменено. Продолжить?",
|
||||
"warning_multiple_html": "Выбранные ({count}) списки чтения будут удалены с этого сервера. Ваши медиафайлы не будут затронуты. Это действие <b>не может</b> быть отменено. Продолжить?"
|
||||
},
|
||||
|
|
@ -355,32 +376,34 @@
|
|||
"delete_user": {
|
||||
"button_confirm": "Удалить",
|
||||
"confirm_delete": "Да, удалить пользователя \"{name}\"",
|
||||
"dialog_title": "Удалить Пользователя",
|
||||
"warning_html": "Пользователь <b>{name}</b> буден удален с этого сервера. Это действие <b>не может</b> быть отменено. Продолжить?"
|
||||
"dialog_title": "Удалить пользователя",
|
||||
"warning_html": "Пользователь <b>{name}</b> буден удален с этого сервера. Это действие <b>нельзя</b> отменить. Продолжить?"
|
||||
},
|
||||
"edit_books": {
|
||||
"add_author_role_error_duplicate": "Уже существует",
|
||||
"authors_notice_multiple_edit": "Вы редактируете авторов для нескольких книг. Это действие перезапишет существующих авторов для каждой книги.",
|
||||
"authors_notice_multiple_edit": "Вы редактируете авторов для нескольких книг. Это приведёт к перезаписи существующих авторов в каждой книге.",
|
||||
"button_cancel": "Отмена",
|
||||
"button_confirm": "Сохранить изменения",
|
||||
"copy_from": "Копировать из {field}",
|
||||
"dialog_title_multiple": "Редактировать {count} книгу | Редактировать {count} книг(и)",
|
||||
"dialog_title_single": "Редактировать {book}",
|
||||
"field_alternate_title": "Альтернативное название",
|
||||
"field_isbn": "ISBN",
|
||||
"field_isbn_error": "Должен быть действительный ISBN-13",
|
||||
"field_link_label": "Метка",
|
||||
"field_link_url": "URL",
|
||||
"field_number": "Номер",
|
||||
"field_number_sort": "Номер сортировки",
|
||||
"field_number_sort": "Порядковый номер",
|
||||
"field_number_sort_hint": "Вы можете использовать десятичные числа",
|
||||
"field_release_date": "Дата выхода",
|
||||
"field_release_date_error": "Дата должна быть в действительном YYYY-MM-DD формате",
|
||||
"field_summary": "Краткое Описание",
|
||||
"field_summary": "Аннотация",
|
||||
"field_tags": "Теги",
|
||||
"field_title": "Заголовок",
|
||||
"tab_authors": "Авторы",
|
||||
"tab_general": "Общее",
|
||||
"tab_links": "Ссылки",
|
||||
"tab_poster": "Постер",
|
||||
"tab_poster": "Обложка",
|
||||
"tab_tags": "Теги",
|
||||
"tags_notice_multiple_edit": "Вы редактируете теги для нескольких книг. Это действие перзапишет существующие теги для каждой книги."
|
||||
},
|
||||
|
|
@ -388,8 +411,8 @@
|
|||
"button_cancel": "Отмена",
|
||||
"button_confirm": "Сохранить изменения",
|
||||
"dialog_title": "Редактировать коллекцию",
|
||||
"field_manual_ordering": "Ручной порядок",
|
||||
"label_ordering": "По умолчанию серии в коллекции будут отсортированы по имени. Вы можете включить ручной порядок, чтобы указать собственный порядок.",
|
||||
"field_manual_ordering": "Ручное упорядочивание",
|
||||
"label_ordering": "По умолчанию серии в коллекции упорядочиваются по названию. Вы можете включить ручную сортировку, чтобы задать собственный порядок.",
|
||||
"tab_general": "Общее",
|
||||
"tab_poster": "Постер"
|
||||
},
|
||||
|
|
@ -399,76 +422,90 @@
|
|||
"button_confirm_add": "Добавить",
|
||||
"button_confirm_edit": "Редактировать",
|
||||
"button_next": "Далее",
|
||||
"dialog_title_add": "Добавить Библиотеку",
|
||||
"dialot_title_edit": "Редактировать Библиотеку",
|
||||
"dialog_title_add": "Добавить библиотеку",
|
||||
"dialot_title_edit": "Редактировать библиотеку",
|
||||
"field_analysis_analyze_dimensions": "Анализировать размеры страниц",
|
||||
"field_analysis_hash_files": "Вычислять хеш-суммы файлов",
|
||||
"field_analysis_hash_koreader": "Вычислять хеш-суммы файлов для KOReader",
|
||||
"field_analysis_hash_pages": "Вычислять хеш-суммы страниц",
|
||||
"field_convert_to_cbz": "Автоматическая конвертация в CBZ",
|
||||
"field_import_barcode_isbn": "ISBN штрихкод",
|
||||
"field_import_barcode_isbn": "ISBN штрих-код",
|
||||
"field_import_comicinfo_book": "Метаданные книг",
|
||||
"field_import_comicinfo_collections": "Коллекции",
|
||||
"field_import_comicinfo_readlists": "Списки чтения",
|
||||
"field_import_comicinfo_series": "Метаданные серий",
|
||||
"field_import_epub_book": "Метаданные книг",
|
||||
"field_import_epub_series": "Метаданные серий",
|
||||
"field_import_comicinfo_series_append_volume": "Включать том в название серии",
|
||||
"field_import_epub_book": "Метаданные книги",
|
||||
"field_import_epub_series": "Метаданные серии",
|
||||
"field_import_local_artwork": "Локальные обложки",
|
||||
"field_import_mylar_series": "Метаданные серий",
|
||||
"field_import_mylar_series": "Метаданные серии",
|
||||
"field_name": "Имя",
|
||||
"field_oneshotsdirectory": "Каталог для ваншотов",
|
||||
"field_repair_extensions": "Автоматическое исправление неправильных расширений файлов",
|
||||
"field_root_folder": "Корневой каталог",
|
||||
"field_scanner_empty_trash_after_scan": "Автоматически очищать корзину после каждого сканирования",
|
||||
"field_scanner_force_directory_modified_time": "Выполнять поиск даты модификации каталога",
|
||||
"field_scanner_scan_startup": "Сканировать при запуске",
|
||||
"field_series_cover": "Обложка серии",
|
||||
"file_browser_dialog_button_confirm": "Выбрать",
|
||||
"file_browser_dialog_title": "Корневой каталог библиотеки",
|
||||
"label_analysis": "Анализ",
|
||||
"label_file_management": "Управление файлами",
|
||||
"label_import_barcode_isbn": "Импорт ISBN через штрихкод",
|
||||
"label_import_barcode_isbn": "Импорт ISBN через штрих-код",
|
||||
"label_import_comicinfo": "Импорт метаданных для CBR/CBZ, содержащих файл ComicInfo.xml",
|
||||
"label_import_epub": "Импорт метаданных из EPUB файлов",
|
||||
"label_import_epub": "Импорт метаданных из файлов EPUB",
|
||||
"label_import_local": "Импорт локальных медиа данных",
|
||||
"label_import_mylar": "Импортировать метаданные созданные Mylar",
|
||||
"label_scan_directory_exclusions": "Исключения из каталогов",
|
||||
"label_scan_types": "Сканировать следующие типы файлов",
|
||||
"label_scanner": "Сканер",
|
||||
"label_series_cover": "Обложка серии",
|
||||
"tab_general": "Общее",
|
||||
"tab_metadata": "Метаданные",
|
||||
"tab_options": "Опции",
|
||||
"tooltip_scanner_force_modified_time": "Включите если библиотека размещена на Google Drive",
|
||||
"tooltip_use_resources": "Может потреблять много ресурсов на больших библиотеках или медленном оборудовании"
|
||||
"tooltip_oneshotsdirectory": "Оставьте пустым для отключения",
|
||||
"tooltip_scanner_force_modified_time": "Включите, если библиотека размещена на Google Drive",
|
||||
"tooltip_use_resources": "Может потреблять много ресурсов при работе с большими библиотеками или на слабом оборудовании"
|
||||
},
|
||||
"edit_readlist": {
|
||||
"button_cancel": "Отмена",
|
||||
"button_confirm": "Сохранить изменения",
|
||||
"dialog_title": "Редактировать список чтения",
|
||||
"field_manual_ordering": "Ручная сортировка",
|
||||
"field_name": "Имя",
|
||||
"field_summary": "Сводка",
|
||||
"field_summary": "Аннотация",
|
||||
"label_ordering": "По умолчанию книги в списке чтения упорядочиваются вручную. Вы можете отключить ручную сортировку, чтобы упорядочить книги по дате выхода.",
|
||||
"tab_general": "Общее",
|
||||
"tab_poster": "Постер"
|
||||
"tab_poster": "Обложка"
|
||||
},
|
||||
"edit_recommended": {
|
||||
"button_confirm": "Сохранить изменения",
|
||||
"button_reset": "Сбросить по умолчанию",
|
||||
"dialog_title": "Редактировать рекомендуемый вид"
|
||||
},
|
||||
"edit_series": {
|
||||
"button_cancel": "Отмена",
|
||||
"button_confirm": "Сохранить изменения",
|
||||
"dialog_title_multiple": "Редактировать {count} серию | Редактировать {count} серий",
|
||||
"dialog_title_single": "Редактировать {series}",
|
||||
"field_age_rating": "Возрастной Рейтинг",
|
||||
"field_age_rating_error": "Возрастной рейтинг должен быть 0 или больше",
|
||||
"field_age_rating": "Возрастной рейтинг",
|
||||
"field_age_rating_error": "Возрастной рейтинг может быть большим или равным 0",
|
||||
"field_genres": "Жанры",
|
||||
"field_labels": "Метки",
|
||||
"field_language": "Язык",
|
||||
"field_language_hint": "Языковой тег IETF BCP 47",
|
||||
"field_publisher": "Издатель",
|
||||
"field_reading_direction": "Направление Чтения",
|
||||
"field_sort_title": "Сортировать по Названию",
|
||||
"field_reading_direction": "Направление чтения",
|
||||
"field_sort_title": "Сортировать по названию",
|
||||
"field_status": "Статус",
|
||||
"field_summary": "Краткое Описание",
|
||||
"field_summary": "Краткое описание",
|
||||
"field_tags": "Теги",
|
||||
"field_title": "Название",
|
||||
"field_total_book_count": "Общее Количество Книг",
|
||||
"field_total_book_count_error": "Общее количество книг может быть 1 или более",
|
||||
"field_total_book_count": "Общее количество книг",
|
||||
"field_total_book_count_error": "Общее количество книг может быть большим или равным 1",
|
||||
"mixed": "СМЕШАННЫЙ",
|
||||
"tab_general": "Общее",
|
||||
"tab_poster": "Постер",
|
||||
"tab_poster": "Обложка",
|
||||
"tab_tags": "Теги",
|
||||
"tags_notice_multiple_edit": "Вы редактируете теги для нескольких серий. Это действие перезапишет существующие теги для каждой серии."
|
||||
},
|
||||
|
|
@ -483,12 +520,14 @@
|
|||
"none": "Без ограничений"
|
||||
},
|
||||
"edit_restrictions_for": "Редактировать ограничения для {name}",
|
||||
"label_age_restriction": "Ограничение по возрасту",
|
||||
"label_age_restriction": "Возрастное ограничение",
|
||||
"label_allow_only_labels": "Разрешить только метки",
|
||||
"label_exclude_labels": "Исключить метки"
|
||||
"label_exclude_labels": "Исключить метки",
|
||||
"tab_content_restrictions": "Ограничения контента",
|
||||
"tab_shared_libraries": "Общие библиотеки"
|
||||
},
|
||||
"empty_trash": {
|
||||
"body": "По умолчанию медиа-сервер не удаляет информацию для медиа сразу. Это помогает, если диск временно отключен. Когда вы очищаете корзину для библиотеки, вся информация об отсутствующих медиафайлах удаляется.",
|
||||
"body": "По умолчанию медиасервер не удаляет информацию о медиафайлах сразу. Это помогает, если диск был временно отключён. При очистке корзины библиотеки удаляется вся информация об отсутствующих медиафайлах.",
|
||||
"button_confirm": "Очистить",
|
||||
"title": "Очистить корзину для библиотеки"
|
||||
},
|
||||
|
|
@ -496,17 +535,17 @@
|
|||
"button_cancel": "Отмена",
|
||||
"button_confirm_default": "Выбрать",
|
||||
"dialog_title_default": "Обозреватель файлов",
|
||||
"parent_directory": "Родитель"
|
||||
"parent_directory": "Родительский каталог"
|
||||
},
|
||||
"filename_chooser": {
|
||||
"button_choose": "Выбрать",
|
||||
"field_destination_filename": "Имя файла назначения",
|
||||
"label_source_filename": "Исходное имя файла",
|
||||
"table": {
|
||||
"existing_file": "Существующий Файл",
|
||||
"existing_file": "Существующий файл",
|
||||
"order": "Порядок"
|
||||
},
|
||||
"title": "Имя Файла Назначения"
|
||||
"title": "Имя файла назначения"
|
||||
},
|
||||
"password_change": {
|
||||
"button_cancel": "Отмена",
|
||||
|
|
@ -524,6 +563,7 @@
|
|||
},
|
||||
"series_picker": {
|
||||
"label_search_series": "Поиск Серии",
|
||||
"no_results": "No Series found",
|
||||
"title": "Выберите Серию"
|
||||
},
|
||||
"server_stop": {
|
||||
|
|
@ -612,44 +652,97 @@
|
|||
"ONGOING": "Выпускается"
|
||||
}
|
||||
},
|
||||
"epubreader": {
|
||||
"publisher_font": "Издатель",
|
||||
"settings": {
|
||||
"column_count": "Количество столбцов",
|
||||
"font_family": "Шрифт",
|
||||
"layout": "Вид",
|
||||
"layout_paginated": "Постраничный",
|
||||
"layout_scroll": "Непрерывный",
|
||||
"navigation_mode": "Режим навигации",
|
||||
"navigation_options": {
|
||||
"both": "Оба",
|
||||
"buttons": "Кнопки",
|
||||
"click": "Клик/Касание"
|
||||
},
|
||||
"page_margins": "Поля страницы",
|
||||
"viewing_theme": "Цветовая схема"
|
||||
},
|
||||
"shortcuts": {
|
||||
"cycle_pagination": "Циклическое переключение количества столбцов",
|
||||
"cycle_viewing_theme": "Циклическое переключение цветовой схемы",
|
||||
"font_size_decrease": "Уменьшить размер шрифта",
|
||||
"font_size_increase": "Увеличить размер шрифта",
|
||||
"menus": "Меню",
|
||||
"next": "Вперёд",
|
||||
"previous": "Назад",
|
||||
"reader_navigation": "Навигация",
|
||||
"scroll": "Изменить вид на непрерывный",
|
||||
"settings": "Настройки",
|
||||
"show_hide_toc": "Показать/скрыть оглавление"
|
||||
}
|
||||
},
|
||||
"error_codes": {
|
||||
"ERR_1000": "Не удалось получить доступ к файлу во время анализа",
|
||||
"ERR_1001": "Неподдерживаемый медиа формат",
|
||||
"ERR_1002": "Зашифрованные архивы RAR не поддерживаются",
|
||||
"ERR_1003": "Solid RAR архивы не поддерживаются",
|
||||
"ERR_1004": "Multi-Volume RAR архивы не поддерживаются",
|
||||
"ERR_1005": "Неизвестная ошибка при анализе книги",
|
||||
"ERR_1001": "Тип медиафайла не поддерживается",
|
||||
"ERR_1002": "Зашифрованные RAR-архивы не поддерживаются",
|
||||
"ERR_1003": "Непрерывные RAR-архивы не поддерживаются",
|
||||
"ERR_1004": "Многотомные RAR-архивы не поддерживаются",
|
||||
"ERR_1005": "Неизвестная ошибка в процессе анализа книги",
|
||||
"ERR_1006": "Книга не содержит ни одной страницы",
|
||||
"ERR_1007": "Некоторые записи не могут быть проанализированы",
|
||||
"ERR_1008": "Неизвестная ошибка при получении записей книги",
|
||||
"ERR_1007": "Некоторые записи не удалось проанализировать",
|
||||
"ERR_1008": "Неизвестная ошибка в процессе получения записей книги",
|
||||
"ERR_1009": "Список чтения с таким именем уже существует",
|
||||
"ERR_1015": "Ошибка при десериализации Списка чтения ComicRack",
|
||||
"ERR_1015": "Ошибка при десериализации CBL-файла ComicRack",
|
||||
"ERR_1016": "Каталог недоступен или не является каталогом",
|
||||
"ERR_1017": "Невозможно просканировать папку, которая является частью существующей библиотеки",
|
||||
"ERR_1018": "Файл не найден",
|
||||
"ERR_1019": "Невозможно импортировать файл, который является частью существующей библиотеки",
|
||||
"ERR_1020": "Книга для обновления не относится к указанной серии",
|
||||
"ERR_1020": "Книга для обновления не принадлежит указанной серии",
|
||||
"ERR_1021": "Файл назначения уже существует",
|
||||
"ERR_1022": "Недавно импортированная книга не может быть отсканирована"
|
||||
"ERR_1022": "Недавно импортированную книгу не удалось просканировать",
|
||||
"ERR_1023": "Книга уже присутствует в списке чтения",
|
||||
"ERR_1024": "Ошибка входа через OAuth2: отсутствует атрибут 'email'",
|
||||
"ERR_1025": "Ошибка входа через OAuth2: локальный пользователь с таким email не существует",
|
||||
"ERR_1026": "Ошибка входа через OpenID Connect: email не подтверждён",
|
||||
"ERR_1027": "Ошибка входа через OpenID Connect: отсутствует атрибут 'email_verified'",
|
||||
"ERR_1028": "Ошибка входа через OpenID Connect: отсутствует атрибут 'email'",
|
||||
"ERR_1029": "CBL-файл ComicRack не содержит ни одного элемента 'Book'",
|
||||
"ERR_1030": "В CBL-файле ComicRack отсутствует элемент 'Name'",
|
||||
"ERR_1031": "В элементе 'Book' CBL-файла ComicRack отсутствует серия или номер",
|
||||
"ERR_1032": "Файл EPUB имеет неверный медиа-тип",
|
||||
"ERR_1033": "Некоторые записи отсутствуют",
|
||||
"ERR_1034": "Ключ API с таким комментарием уже существует",
|
||||
"ERR_1035": "Ошибка при получении оглавления EPUB",
|
||||
"ERR_1036": "Ошибка при получении навигационных меток EPUB",
|
||||
"ERR_1037": "Ошибка при получении списка страниц EPUB",
|
||||
"ERR_1038": "Ошибка при получении страниц divina в EPUB",
|
||||
"ERR_1039": "Ошибка при получении позиций в EPUB"
|
||||
},
|
||||
"filter": {
|
||||
"age_rating": "Возрастной Рейтинг",
|
||||
"age_rating_none": "Нет",
|
||||
"age_rating": "Возрастной рейтинг",
|
||||
"age_rating_none": "Не задан",
|
||||
"any": "Любой",
|
||||
"complete": "Завершенные",
|
||||
"genre": "жанр",
|
||||
"in_progress": "Читаю",
|
||||
"language": "язык",
|
||||
"library": "библиотека",
|
||||
"publisher": "издатель",
|
||||
"genre": "Жанр",
|
||||
"in_progress": "В процессе",
|
||||
"language": "Язык",
|
||||
"library": "Библиотека",
|
||||
"media_profile": "Медиапрофиль",
|
||||
"media_status": "Статус медиа",
|
||||
"oneshot": "Ван-шот",
|
||||
"publisher": "Издатель",
|
||||
"read": "Прочитано",
|
||||
"release_date": "дата выхода",
|
||||
"status": "статус",
|
||||
"tag": "тег",
|
||||
"unread": "Непрочитанные"
|
||||
"release_date": "Дата выхода",
|
||||
"sharing_label": "Метка общего доступа",
|
||||
"status": "Статус",
|
||||
"tag": "Тег",
|
||||
"unread": "Не прочитано"
|
||||
},
|
||||
"filter_drawer": {
|
||||
"filter": "фильтр",
|
||||
"sort": "сортировка"
|
||||
"filter": "Фильтр",
|
||||
"sort": "Сортировка"
|
||||
},
|
||||
"history": {
|
||||
"header": {
|
||||
|
|
@ -667,19 +760,21 @@
|
|||
},
|
||||
"library_navigation": {
|
||||
"browse": "Обзор",
|
||||
"browse_books": "Книги",
|
||||
"browse_series": "Серии",
|
||||
"collections": "Коллекции",
|
||||
"readlists": "Списки Чтения",
|
||||
"readlists": "Списки чтения",
|
||||
"recommended": "Рекомендуемые"
|
||||
},
|
||||
"login": {
|
||||
"create_user_account": "Создать аккаунт пользователя",
|
||||
"create_user_account": "Создать учётную запись пользователя",
|
||||
"login": "Войти",
|
||||
"unclaimed_html": "Этот Komga сервер еще не активен, чтобы получить к нему доступ вам необходимо создать аккаунт пользователя.<br><br>Выберите <strong>эл. почту</strong> и <strong>пароль</strong> и нажмите на <strong>Создать аккаунт пользователя</strong>."
|
||||
"unclaimed_html": "Этот сервер Komga еще не активtн: для доступа к нему необходимо создать учётную запись пользователя.<br><br>Выберите <strong>email</strong> и <strong>пароль</strong> и нажмите на <strong>Создать учетную запись пользователя</strong>."
|
||||
},
|
||||
"media_analysis": {
|
||||
"comment": "Комментарий",
|
||||
"media_analysis": "Медиа анализ",
|
||||
"media_type": "Медиатип",
|
||||
"media_analysis": "Медиаанализ",
|
||||
"media_type": "Тип медиа",
|
||||
"name": "Имя",
|
||||
"size": "Размер",
|
||||
"status": "Статус",
|
||||
|
|
@ -689,6 +784,7 @@
|
|||
"add_to_collection": "Добавить в коллекцию",
|
||||
"add_to_readlist": "Добавить в список чтения",
|
||||
"analyze": "Анализировать",
|
||||
"bulk_edit_metadata": "Массовое редактирование метаданных",
|
||||
"delete": "Удалить",
|
||||
"deselect_all": "Отменить выбор",
|
||||
"download_readlist": "Скачать список чтения",
|
||||
|
|
@ -698,20 +794,34 @@
|
|||
"empty_trash": "Очистить корзину",
|
||||
"mark_read": "Отметить как прочитанное",
|
||||
"mark_unread": "Пометить как непрочитанное",
|
||||
"pin": "Закрепить",
|
||||
"refresh_metadata": "Обновить метаданные",
|
||||
"scan_library_files": "Сканировать файлы библиотеки",
|
||||
"select_all": "Выбрать всё"
|
||||
"scan_library_files_deep": "Сканировать файлы библиотеки (полное сканирование)",
|
||||
"select_all": "Выбрать всё",
|
||||
"unpin": "Открепить"
|
||||
},
|
||||
"metrics": {
|
||||
"library_books": "Книг в библиотеке",
|
||||
"library_disk_space": "Дисковое пространство библиотеки",
|
||||
"library_series": "Серий в библиотеке",
|
||||
"library_sidecars": "Сопутствующих файлов в библиотеке",
|
||||
"tasks_executed": "Выполнено задач",
|
||||
"tasks_total_time": "Общее время выполнения задач",
|
||||
"title": "Метрики"
|
||||
},
|
||||
"missing_posters": {
|
||||
"title": "Отсутствующие обложки"
|
||||
},
|
||||
"navigation": {
|
||||
"home": "Главная",
|
||||
"libraries": "Библиотеки",
|
||||
"logout": "Выйти"
|
||||
},
|
||||
"no_libraries_pinned": {
|
||||
"subtitle": "Вы можете закрепить библиотеку через меню с тремя точками",
|
||||
"title": "Нет закреплённых библиотек"
|
||||
},
|
||||
"page_not_found": {
|
||||
"go_back_to_home_page": "Вернуться на главную",
|
||||
"page_does_not_exist": "Искомая страница не существует.",
|
||||
|
|
@ -721,12 +831,18 @@
|
|||
"less": "Свернуть",
|
||||
"more": "Подробнее"
|
||||
},
|
||||
"readlist_import": {
|
||||
"row": {
|
||||
"duplicate_book": "Дубликат книги",
|
||||
"error_choose_book": "Выберите книгу"
|
||||
}
|
||||
},
|
||||
"readlists_expansion_panel": {
|
||||
"manage_readlist": "Управлять списком чтения",
|
||||
"title": "Список чтения {name}"
|
||||
},
|
||||
"search": {
|
||||
"no_results": "Поиск не вернул результатов",
|
||||
"no_results": "Поиск не дал результатов",
|
||||
"search": "Поиск",
|
||||
"search_for_something_else": "Попробуйте поискать что-нибудь другое",
|
||||
"search_results_for": "Результаты поиска по запросу \"{name}\""
|
||||
|
|
@ -734,39 +850,68 @@
|
|||
"searchbox": {
|
||||
"in_library": "в {library}",
|
||||
"no_results": "Ничего не найдено",
|
||||
"search_all": "Найти все…"
|
||||
"search_all": "Искать везде…"
|
||||
},
|
||||
"server": {
|
||||
"server_management": {
|
||||
"button_cancel_all_tasks": "Отменить все задачи",
|
||||
"button_empty_trash": "Очистить корзину для всех библиотек",
|
||||
"button_scan_libraries": "Сканировать все библиотеки",
|
||||
"button_scan_libraries_deep": "Сканировать все библиотеки (полное сканирование)",
|
||||
"button_shutdown": "Выключить",
|
||||
"download_log": "Скачать файл журнала",
|
||||
"notification_tasks_cancelled": "Нет задач для отмены | Одна задача отменена | Отменено задач: {count}",
|
||||
"section_title": "Управление сервером"
|
||||
},
|
||||
"tab_title": "Сервер"
|
||||
"tab_title": "Сервер",
|
||||
"updates": "Обновления"
|
||||
},
|
||||
"server_settings": {
|
||||
"server_settings": "Настройки Сервера"
|
||||
"config_precedence": "Имеет приоритет над конфигурационным файлом",
|
||||
"dialog_regenerate_thumbnails": {
|
||||
"body": "Размер миниатюр изменён. Хотите пересоздать миниатюры книг?",
|
||||
"btn_alternate": "Да, все книги",
|
||||
"btn_cancel": "Нет",
|
||||
"btn_confirm": "Да, но только если размер стал больше",
|
||||
"title": "Пересоздать миниатюры"
|
||||
},
|
||||
"hint_kobo_port": "Устанавливайте только в случае проблем с синхронизацией обложек и загрузок",
|
||||
"label_delete_empty_collections": "Удалять пустые коллекции после сканирования",
|
||||
"label_delete_empty_readlists": "Удалять пустые списки чтения после сканирования",
|
||||
"label_kepubify_path": "Путь к kepubify",
|
||||
"label_kobo_port": "Внешний порт синхронизации Kobo",
|
||||
"label_kobo_proxy": "Проксировать запросы синхронизации Kobo в магазин Kobo",
|
||||
"label_rememberme_duration": "Длительность сессии (в днях)",
|
||||
"label_server_context_path": "Базовый URL",
|
||||
"label_server_port": "Порт сервера",
|
||||
"label_task_pool_size": "Потоки задач",
|
||||
"label_thumbnail_size": "Размер миниатюр",
|
||||
"requires_restart": "Требуется перезапуск для применения изменений",
|
||||
"server_settings": "Настройки сервера"
|
||||
},
|
||||
"settings_user": {
|
||||
"change_password": "Изменить пароль",
|
||||
"edit_restrictions": "Редактировать ограничения",
|
||||
"edit_user": "Редактировать пользователя",
|
||||
"latest_activity": "Активность: {date}",
|
||||
"latest_activity": "Последняя активность: {date}",
|
||||
"no_recent_activity": "Не обнаружено недавней активности",
|
||||
"role_administrator": "Администратор",
|
||||
"role_user": "Пользователь"
|
||||
},
|
||||
"sort": {
|
||||
"books_count": "Количество книг",
|
||||
"date_added": "Дата добавления",
|
||||
"date_updated": "Дата обновления",
|
||||
"file_name": "Имя файла",
|
||||
"file_size": "Размер файла",
|
||||
"folder_name": "Имя каталога",
|
||||
"name": "Имя",
|
||||
"number": "Номер",
|
||||
"release_date": "Дата выхода"
|
||||
"books_count": "По количеству книг",
|
||||
"date_added": "По дате добавления",
|
||||
"date_read": "По дате прочтения",
|
||||
"date_updated": "По дате обновления",
|
||||
"file_name": "По имени файла",
|
||||
"file_size": "По размеру файла",
|
||||
"folder_name": "По имени каталога",
|
||||
"name": "По имени",
|
||||
"number": "По номеру",
|
||||
"page_count": "По количеству страниц",
|
||||
"random": "В случайном порядке",
|
||||
"release_date": "По дате выхода",
|
||||
"series": "По сериям"
|
||||
},
|
||||
"theme": {
|
||||
"dark": "Тёмная",
|
||||
|
|
@ -774,18 +919,57 @@
|
|||
"system": "Системная"
|
||||
},
|
||||
"thumbnail_card": {
|
||||
"tooltip_delete": "Удалить"
|
||||
"tooltip_delete": "Удалить",
|
||||
"tooltip_generated": "Сгенерированные обложки",
|
||||
"tooltip_mark_as_selected": "Отметить как выбранные",
|
||||
"tooltip_selected": "Выбранные",
|
||||
"tooltip_sidecar": "Локальные обложки",
|
||||
"tooltip_to_be_deleted": "Ожидает удаления",
|
||||
"tooltip_to_be_uploaded": "Ожидает загрузки",
|
||||
"tooltip_too_big": "Файл слишком большой!",
|
||||
"tooltip_user_uploaded": "Загружено пользователем"
|
||||
},
|
||||
"titles_more": {
|
||||
"less": "Меньше заголовков",
|
||||
"more": "Больше заголовков"
|
||||
},
|
||||
"ui_settings": {
|
||||
"general": "Общее",
|
||||
"label_oauth2_auto_login": "Автоматический вход через OAuth2",
|
||||
"label_oauth2_hide_login": "Скрывать поля авторизации, если включен OAuth2",
|
||||
"label_poster_blur_unread": "Размывать обложки для непрочитанных книг и серий",
|
||||
"label_poster_stretch": "Растягивать обложку по размеру карточки",
|
||||
"label_series_groups": "Группировка серий",
|
||||
"section_oauth2": "OAuth2",
|
||||
"series_groups": {
|
||||
"alpha": "Алфавитная",
|
||||
"japanese": "Годзюон (Японский)"
|
||||
},
|
||||
"tooltip_oauth2_auto_login": "Требуется единственный OAuth2-провайдер и включённая опция «Скрывать поля авторизации»"
|
||||
},
|
||||
"updates": {
|
||||
"available": "Доступны обновления",
|
||||
"latest_installed": "Последняя версия Komga уже установлена"
|
||||
},
|
||||
"user_roles": {
|
||||
"ADMIN": "Администратор",
|
||||
"FILE_DOWNLOAD": "Скачивание файлов",
|
||||
"KOBO_SYNC": "Синхронизация с Kobo",
|
||||
"KOREADER_SYNC": "Синхронизация с KOReader",
|
||||
"PAGE_STREAMING": "Потоковый просмотр страниц",
|
||||
"USER": "Пользователь"
|
||||
},
|
||||
"users": {
|
||||
"authentication_activity": "Проверка подлинности",
|
||||
"api_keys": "Ключи API",
|
||||
"authentication_activity": "Аутентификация активности",
|
||||
"users": "Пользователи"
|
||||
},
|
||||
"validation": {
|
||||
"context_path": "Должно начинаться с '/', не заканчиваться на '/-_', и содержать только '/-_a-z0-9'",
|
||||
"one_or_more": "Должно быть большим или равным 1",
|
||||
"tcp_port": "Должно находиться в диапазоне от 1 до 65535",
|
||||
"zero_or_more": "Должно быть большим или равным 0"
|
||||
},
|
||||
"welcome": {
|
||||
"add_library": "Добавить библиотеку",
|
||||
"no_libraries_yet": "Библиотеки еще не были добавлены!",
|
||||
|
|
|
|||
|
|
@ -19,7 +19,15 @@
|
|||
},
|
||||
"account_settings": {
|
||||
"account_settings": "Kontoinställningar",
|
||||
"change_password": "ändra lösenord"
|
||||
"api_key": {
|
||||
"created_date": "Skapades datum: {date}",
|
||||
"force_kobo_sync": "Tvinga Kobo synk",
|
||||
"generate_api_key": "Skapa API-nyckel",
|
||||
"no_keys": "Inga API-nycklar skapade ännu"
|
||||
},
|
||||
"change_password": "ändra lösenord",
|
||||
"details": "Detaljer",
|
||||
"my_account": "Mitt konto"
|
||||
},
|
||||
"announcements": {
|
||||
"mark_all_read": "Markera alla som lästa",
|
||||
|
|
@ -27,6 +35,7 @@
|
|||
"tab_title": "Annonseringar"
|
||||
},
|
||||
"authentication_activity": {
|
||||
"api_key": "API-nyckel",
|
||||
"datetime": "Datum & Tid",
|
||||
"email": "E-post",
|
||||
"error": "Fel",
|
||||
|
|
@ -86,6 +95,7 @@
|
|||
"beginning_of_book": "Du är i början av boken.",
|
||||
"changing_reading_direction": "Byt läsriktning till",
|
||||
"cycling_page_layout": "Växla Sidlayout",
|
||||
"cycling_page_margin": "Växlar sidmarginal",
|
||||
"cycling_scale": "Växla Skala",
|
||||
"cycling_side_padding": "Växla Spaltfyllnad",
|
||||
"download_current_page": "Ladda ner nuvarande sida",
|
||||
|
|
@ -128,6 +138,7 @@
|
|||
"general": "Generella",
|
||||
"gestures": "Gester",
|
||||
"page_layout": "Sidlayout",
|
||||
"page_margin": "Sidmarginal",
|
||||
"paged": "Inställningar för sidvisning",
|
||||
"reading_mode": "Läsläge",
|
||||
"scale_type": "Skal typ",
|
||||
|
|
@ -138,6 +149,7 @@
|
|||
"shortcuts": {
|
||||
"close": "Stäng",
|
||||
"cycle_page_layout": "Växla sidlayout",
|
||||
"cycle_page_margin": "Växla sidmarginal",
|
||||
"cycle_scale": "Växla skala",
|
||||
"cycle_side_padding": "Växla sidofyllning",
|
||||
"first_page": "Första sidan",
|
||||
|
|
@ -161,6 +173,8 @@
|
|||
},
|
||||
"browse_book": {
|
||||
"comment": "KOMMENTAR",
|
||||
"date_created": "SKAPADES",
|
||||
"date_modified": "SENAST ÄNDRAD",
|
||||
"download_file": "Ladda ner fil",
|
||||
"file": "FIL",
|
||||
"format": "FORMAT",
|
||||
|
|
@ -170,6 +184,8 @@
|
|||
"outdated_tooltip": "Filen för den här boken har ändrats, boken måste analyseras om",
|
||||
"read_book": "Läs bok",
|
||||
"read_incognito": "Läs incognito",
|
||||
"remove_from_collection": "Ta bort bok från samling",
|
||||
"remove_from_readlist": "Ta bort bok från läslista",
|
||||
"size": "STORLEK"
|
||||
},
|
||||
"browse_collection": {
|
||||
|
|
@ -184,6 +200,7 @@
|
|||
},
|
||||
"browse_series": {
|
||||
"earliest_year_from_release_dates": "Detta är det tidigaste året från utgivningsdatum från alla böcker i serien",
|
||||
"remove_from_collection": "Ta bort serie från samling",
|
||||
"series_no_summary": "Denna serie har ingen sammanfattning, så vi valde en för dig!",
|
||||
"summary_from_book": "Sammanfattning från bok {number}:"
|
||||
},
|
||||
|
|
@ -194,21 +211,28 @@
|
|||
"common": {
|
||||
"age": "Ålder",
|
||||
"all_libraries": "Alla bibliotek",
|
||||
"all_of": "Samtliga",
|
||||
"any_of": "Någon av",
|
||||
"book": "Bok",
|
||||
"books": "Böcker",
|
||||
"books_n": "Ingen bok | 1 bok | {count} böcker",
|
||||
"books_total": "{count} / {total} böcker",
|
||||
"cancel": "Avbryt",
|
||||
"cbx": "Serietidningsarkiv",
|
||||
"choose_image": "Välj en bild",
|
||||
"close": "Stäng",
|
||||
"collections": "Samlingar",
|
||||
"copied": "Kopierad!",
|
||||
"create": "Skapa",
|
||||
"delete": "Redera",
|
||||
"dimension": "b: {width}, h: {height}",
|
||||
"disk_space": "Diskutrymme",
|
||||
"dismiss": "Avfärda",
|
||||
"download": "Ladda ner",
|
||||
"drag_drop": "dra och släpp",
|
||||
"email": "E-post",
|
||||
"epub": "Epub",
|
||||
"error": "Fel",
|
||||
"filename": "Filnamn",
|
||||
"filter_no_matches": "Det aktiva filtret ger ingen träff",
|
||||
"genre": "Genre",
|
||||
|
|
@ -216,12 +240,16 @@
|
|||
"go_to_library": "Gå till bibliotek",
|
||||
"go_to_readlist": "Gå till läslistan",
|
||||
"go_to_series": "Gå till serien",
|
||||
"i_understand": "Jag förstår",
|
||||
"library": "Bibliotek",
|
||||
"locale_name": "Svenska",
|
||||
"locale_rtl": "false",
|
||||
"lock_all": "Lås alla",
|
||||
"media": "Media",
|
||||
"more": "Mer",
|
||||
"n_selected": "{count} valda",
|
||||
"nothing_to_show": "Inget att visa",
|
||||
"ok": "OK",
|
||||
"oneshot": "One-shot",
|
||||
"outdated": "Föråldrad",
|
||||
"page": "Sida",
|
||||
|
|
@ -230,19 +258,25 @@
|
|||
"pages_left": "Inga sidor kvar | 1 sida kvar | {count} sidor kvar",
|
||||
"pages_n": "Inga sidor | 1 sida | {count} sidor",
|
||||
"password": "Lösenord",
|
||||
"pdf": "PDF",
|
||||
"pending_tasks": "Inga väntande uppgifter | 1 väntande uppgift | {count} väntande uppgifter",
|
||||
"pinned_libraries": "Fästa Bibliotek",
|
||||
"publisher": "Utgivare",
|
||||
"read": "Läs",
|
||||
"read_on": "Läst den {date}",
|
||||
"readlist": "Läslista",
|
||||
"readlists": "Läslistor",
|
||||
"remember-me": "Kom ihåg mig",
|
||||
"reorder": "Ordna om",
|
||||
"required": "Krävs",
|
||||
"reset_filters": "Återställ filter",
|
||||
"roles": "Roller",
|
||||
"save_changes": "Spara ändringar",
|
||||
"series": "Serier | Serier",
|
||||
"settings": "Inställningar",
|
||||
"sidecars": "Sidovagnar",
|
||||
"tags": "Taggar",
|
||||
"ui": "Gränssnitt",
|
||||
"unavailable": "Otillgänglig",
|
||||
"unlock_all": "Lås upp alla",
|
||||
"url": "URL",
|
||||
|
|
@ -281,6 +315,11 @@
|
|||
"tab_title": "Data import"
|
||||
},
|
||||
"dialog": {
|
||||
"add_api_key": {
|
||||
"context": "API-nycklar kan användas för autentisering via Kobo Synkprotokoll.",
|
||||
"dialog_title": "Skapa ny API-nyckel",
|
||||
"field_comment": "Kommentar"
|
||||
},
|
||||
"add_to_collection": {
|
||||
"button_create": "Skapa",
|
||||
"card_collection_subtitle": "Ingen serie | 1 serie | {count} serier",
|
||||
|
|
@ -314,6 +353,12 @@
|
|||
"filter": "Filtrera efter boknummer, titel, eller utgivningsdatum",
|
||||
"title": "Välj bok"
|
||||
},
|
||||
"delete_apikey": {
|
||||
"button_confirm": "Radera",
|
||||
"confirm_delete": "Jag förstår, radera API-nyckel \"{name}\"",
|
||||
"dialog_title": "Radera API-nyckel",
|
||||
"warning_html": "Applikationer eller skript som använder denna API-nyckel kommer inte längre kunna nyttja Komga API:et. Det går ej att ångra denna åtgärd."
|
||||
},
|
||||
"delete_book": {
|
||||
"button_confirm": "Ta bort",
|
||||
"confirm_delete": "Ja, radera boken \"{name}\" och dess filer",
|
||||
|
|
@ -456,10 +501,13 @@
|
|||
"field_manual_ordering": "Manuell sortering",
|
||||
"field_name": "Namn",
|
||||
"field_summary": "Sammanfattning",
|
||||
"label_ordering": "Som standard, böcker i en läslista sorteras manuellt. Du kan inaktivera manuell sortering för att sortera böcker efter släppdatum.",
|
||||
"label_ordering": "Som standard sorteras böcker i en läslista manuellt. Du kan inaktivera manuell sortering för att sortera böcker efter släppdatum.",
|
||||
"tab_general": "Allmänt",
|
||||
"tab_poster": "Affisch"
|
||||
},
|
||||
"edit_recommended": {
|
||||
"button_confirm": "Spara ändringar"
|
||||
},
|
||||
"edit_series": {
|
||||
"button_cancel": "Avbryt",
|
||||
"button_confirm": "Spara ändringar",
|
||||
|
|
@ -528,6 +576,10 @@
|
|||
},
|
||||
"title": "Namn på målfil"
|
||||
},
|
||||
"force_kobo_sync": {
|
||||
"dialog_title": "Tvinga Kobo synk",
|
||||
"warning_html": "Detta raderar all synkhistorik för denna API-nyckel. Din Kobo kommer synka allt vid nästa synktillfälle."
|
||||
},
|
||||
"password_change": {
|
||||
"button_cancel": "Avbryt",
|
||||
"button_confirm": "Ändra lösenord",
|
||||
|
|
@ -597,6 +649,8 @@
|
|||
"empty_title": "Inga dubbletter av sidor hittades",
|
||||
"filter": {
|
||||
"count": "Antal",
|
||||
"date_added": "Datum tillagd",
|
||||
"date_modified": "Datum ändrad",
|
||||
"delete_count": "Antal gånger raderat",
|
||||
"delete_size": "Sparat utrymme",
|
||||
"match_count": "Matcha antal",
|
||||
|
|
@ -622,6 +676,23 @@
|
|||
"HARDLINK": "Hårdlänk/kopiera filer",
|
||||
"MOVE": "Flytta filer"
|
||||
},
|
||||
"epubreader": {
|
||||
"appearances": {
|
||||
"day": "Dag",
|
||||
"night": "Natt",
|
||||
"sepia": "Sepia"
|
||||
},
|
||||
"column_count": {
|
||||
"auto": "Auto",
|
||||
"one": "En",
|
||||
"two": "Två"
|
||||
},
|
||||
"reading_direction": {
|
||||
"auto": "Automatisk",
|
||||
"ltr": "Vänster till höger",
|
||||
"rtl": "Höger till vänster"
|
||||
}
|
||||
},
|
||||
"historical_event_type": {
|
||||
"BookConverted": "Boken konverterad",
|
||||
"BookFileDeleted": "Bokfilen raderad",
|
||||
|
|
@ -629,6 +700,11 @@
|
|||
"DuplicatePageDeleted": "Duplicerad sida borttagen",
|
||||
"SeriesFolderDeleted": "Seriemappen borttagen"
|
||||
},
|
||||
"media_profile": {
|
||||
"DIVINA": "DIVINA",
|
||||
"EPUB": "EPUB",
|
||||
"PDF": "PDF"
|
||||
},
|
||||
"media_status": {
|
||||
"ERROR": "Fel",
|
||||
"OUTDATED": "Föråldrad",
|
||||
|
|
@ -647,6 +723,14 @@
|
|||
"VERTICAL": "Lodrät",
|
||||
"WEBTOON": "Webtoon"
|
||||
},
|
||||
"scan_interval": {
|
||||
"DAILY": "Varje dag",
|
||||
"DISABLED": "Inaktiverad",
|
||||
"EVERY_12H": "Varje 12 timmar",
|
||||
"EVERY_6H": "Varje 6 timmar",
|
||||
"HOURLY": "Varje timme",
|
||||
"WEEKLY": "Varje vecka"
|
||||
},
|
||||
"series_cover": {
|
||||
"FIRST": "Första",
|
||||
"FIRST_UNREAD_OR_FIRST": "Första olästa annars första",
|
||||
|
|
@ -658,6 +742,34 @@
|
|||
"ENDED": "Avslutad",
|
||||
"HIATUS": "Hiatus",
|
||||
"ONGOING": "Pågående"
|
||||
},
|
||||
"thumbnail_size": {
|
||||
"LARGE": "Stor (900px)",
|
||||
"MEDIUM": "Mellan (600px)"
|
||||
}
|
||||
},
|
||||
"epubreader": {
|
||||
"current_chapter": "Nuvarande kapitel",
|
||||
"page_of": "Sida {page} av {count}",
|
||||
"publisher_font": "Utgivare",
|
||||
"settings": {
|
||||
"font_family": "Teckensnitt",
|
||||
"layout": "Layout",
|
||||
"layout_paginated": "Paginerad",
|
||||
"navigation_mode": "Navigeringsläge",
|
||||
"navigation_options": {
|
||||
"buttons": "Knappar"
|
||||
},
|
||||
"page_margins": "Sidmarginal",
|
||||
"viewing_theme": "Visningstema"
|
||||
},
|
||||
"shortcuts": {
|
||||
"cycle_viewing_theme": "Växla visningstema",
|
||||
"font_size_decrease": "Minska storlek på teckensnitt",
|
||||
"font_size_increase": "Öka storlek på teckensnitt",
|
||||
"menus": "Menyer",
|
||||
"settings": "Inställningar",
|
||||
"show_hide_toc": "Visa/dölj innehållsförteckning"
|
||||
}
|
||||
},
|
||||
"error_codes": {
|
||||
|
|
|
|||
|
|
@ -425,7 +425,7 @@
|
|||
"field_isbn_error": "செல்லுபடியாகும் ISBN 13 ஆக இருக்க வேண்டும்",
|
||||
"field_link_label": "சிட்டை",
|
||||
"field_link_url": "முகவரி",
|
||||
"field_link_url_error_protocol": "HTTP அல்லது HTTPS ஆக இருக்க வேண்டும்",
|
||||
"field_link_url_error_protocol": "http அல்லது https ஆக இருக்க வேண்டும்",
|
||||
"field_link_url_error_url": "செல்லுபடியாகும் முகவரி ஆக இருக்க வேண்டும்",
|
||||
"field_number": "எண்",
|
||||
"field_number_sort": "வரிசை எண்",
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -26,7 +26,7 @@
|
|||
"no_keys": "尚未创建 API 密钥"
|
||||
},
|
||||
"change_password": "更改密码",
|
||||
"details": "详情",
|
||||
"details": "详细信息",
|
||||
"my_account": "我的账户"
|
||||
},
|
||||
"announcements": {
|
||||
|
|
@ -636,7 +636,7 @@
|
|||
"size": "文件大小",
|
||||
"width": "宽"
|
||||
},
|
||||
"title": "书籍详情",
|
||||
"title": "书籍详细信息",
|
||||
"title_comparison": "书籍比较"
|
||||
},
|
||||
"transient_book_viewer": {
|
||||
|
|
@ -862,7 +862,7 @@
|
|||
"header": {
|
||||
"book": "书籍",
|
||||
"date": "日期",
|
||||
"details": "详情",
|
||||
"details": "详细信息",
|
||||
"series": "系列",
|
||||
"type": "类型"
|
||||
},
|
||||
|
|
@ -916,9 +916,9 @@
|
|||
"unpin": "取消固定"
|
||||
},
|
||||
"metrics": {
|
||||
"library_books": "每个库的书籍数",
|
||||
"library_disk_space": "库磁盘空间",
|
||||
"library_series": "每个库的系列数",
|
||||
"library_books": "每个库的书籍数量",
|
||||
"library_disk_space": "每个库磁盘空间占用",
|
||||
"library_series": "每个库的系列数量",
|
||||
"library_sidecars": "每个库的边车",
|
||||
"tasks_executed": "已执行的任务",
|
||||
"tasks_total_time": "任务总时间",
|
||||
|
|
@ -1051,7 +1051,7 @@
|
|||
"general": "常规",
|
||||
"label_oauth2_auto_login": "自动 OAuth2 登录",
|
||||
"label_oauth2_hide_login": "如果启用了 OAuth2,则隐藏登录字段",
|
||||
"label_poster_blur_unread": "未读书籍和系列的模糊海报",
|
||||
"label_poster_blur_unread": "为未读书籍和系列模糊海报",
|
||||
"label_poster_stretch": "拉伸海报以适合卡片",
|
||||
"label_series_groups": "系列分组",
|
||||
"section_oauth2": "OAuth2",
|
||||
|
|
|
|||
|
|
@ -751,7 +751,7 @@ export default Vue.extend({
|
|||
|
||||
const fontFamiliesInjectables = this.fontFamiliesAdditional.map(x => ({
|
||||
type: 'style',
|
||||
url: new URL(`${urls.origin}api/v1/fonts/resource/${x}/css`, import.meta.url).toString(),
|
||||
url: new URL(`${urls.origin}api/v1/fonts/resource/${x}/css`).toString(),
|
||||
fontFamily: x,
|
||||
}))
|
||||
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ dependencies {
|
|||
|
||||
implementation("org.apache.tika:tika-core:2.9.1")
|
||||
implementation("org.apache.commons:commons-compress:1.27.1")
|
||||
implementation("com.github.junrar:junrar:7.5.5")
|
||||
implementation("com.github.junrar:junrar:7.6.0")
|
||||
implementation("com.github.gotson.nightcompress:nightcompress:1.1.1")
|
||||
implementation("org.apache.pdfbox:pdfbox:3.0.5")
|
||||
implementation("net.grey-panther:natural-comparator:1.1")
|
||||
|
|
@ -394,6 +394,7 @@ openApi {
|
|||
args.add("--spring.profiles.active=claim,generate-openapi")
|
||||
args.add("--server.port=8080")
|
||||
}
|
||||
waitTimeInSeconds.set(60)
|
||||
}
|
||||
|
||||
tasks.jacocoTestReport {
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
FROM eclipse-temurin:17-jre as builder
|
||||
FROM eclipse-temurin:17-jre AS builder
|
||||
ARG JAR={{distributionArtifactFile}}
|
||||
WORKDIR /builder
|
||||
COPY assembly/${JAR} application.jar
|
||||
RUN java -Djarmode=tools -jar application.jar extract --layers --destination extracted
|
||||
|
||||
# amd64 builder
|
||||
FROM ubuntu:24.10 as build-amd64
|
||||
FROM ubuntu:26.04 AS build-amd64
|
||||
ENV JAVA_HOME=/opt/java/openjdk
|
||||
COPY --from=eclipse-temurin:23-jre $JAVA_HOME $JAVA_HOME
|
||||
ENV PATH="${JAVA_HOME}/bin:${PATH}"
|
||||
|
|
@ -19,7 +19,7 @@ RUN apt -y update && \
|
|||
ENV LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:/usr/lib/x86_64-linux-gnu"
|
||||
|
||||
# arm64 builder
|
||||
FROM ubuntu:24.10 as build-arm64
|
||||
FROM ubuntu:26.04 AS build-arm64
|
||||
ENV JAVA_HOME=/opt/java/openjdk
|
||||
COPY --from=eclipse-temurin:23-jre $JAVA_HOME $JAVA_HOME
|
||||
ENV PATH="${JAVA_HOME}/bin:${PATH}"
|
||||
|
|
@ -33,7 +33,7 @@ RUN apt -y update && \
|
|||
ENV LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:/usr/lib/aarch64-linux-gnu"
|
||||
|
||||
# arm builder: uses temurin-17, as arm32 support was dropped in JDK 21
|
||||
FROM eclipse-temurin:17-jre as build-arm
|
||||
FROM eclipse-temurin:17-jre AS build-arm
|
||||
RUN apt -y update && \
|
||||
apt -y install wget curl && \
|
||||
wget "https://github.com/pgaskin/kepubify/releases/latest/download/kepubify-linux-arm" -O /usr/bin/kepubify && \
|
||||
|
|
@ -41,9 +41,8 @@ RUN apt -y update && \
|
|||
apt -y autoremove && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
FROM build-${TARGETARCH} AS runner
|
||||
VOLUME /tmp
|
||||
VOLUME /config
|
||||
WORKDIR app
|
||||
WORKDIR /app
|
||||
COPY --from=builder /builder/extracted/dependencies/ ./
|
||||
COPY --from=builder /builder/extracted/spring-boot-loader/ ./
|
||||
COPY --from=builder /builder/extracted/snapshot-dependencies/ ./
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -3,14 +3,24 @@ package org.gotson.komga.domain.model
|
|||
import com.fasterxml.jackson.annotation.JsonInclude
|
||||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
import com.fasterxml.jackson.annotation.JsonTypeInfo
|
||||
import io.swagger.v3.oas.annotations.media.Schema
|
||||
|
||||
class SearchCondition {
|
||||
@Schema(
|
||||
name = "SearchConditionBook",
|
||||
oneOf = [AnyOfBook::class, AllOfBook::class, LibraryId::class, ReadListId::class, SeriesId::class, Deleted::class, OneShot::class, Title::class, ReleaseDate::class, Tag::class, NumberSort::class, ReadStatus::class, MediaStatus::class, MediaProfile::class, Author::class, Poster::class],
|
||||
)
|
||||
@JsonTypeInfo(use = JsonTypeInfo.Id.DEDUCTION)
|
||||
sealed interface Book
|
||||
|
||||
@Schema(
|
||||
name = "SearchConditionSeries",
|
||||
oneOf = [AnyOfSeries::class, AllOfSeries::class, LibraryId::class, CollectionId::class, Deleted::class, Complete::class, OneShot::class, Title::class, TitleSort::class, ReleaseDate::class, Tag::class, SharingLabel::class, Publisher::class, Language::class, Genre::class, AgeRating::class, ReadStatus::class, SeriesStatus::class, Author::class],
|
||||
)
|
||||
@JsonTypeInfo(use = JsonTypeInfo.Id.DEDUCTION)
|
||||
sealed interface Series
|
||||
|
||||
@Schema(name = "SearchConditionAnyOfBook")
|
||||
data class AnyOfBook(
|
||||
@JsonProperty("anyOf")
|
||||
val conditions: List<Book>,
|
||||
|
|
@ -18,6 +28,7 @@ class SearchCondition {
|
|||
constructor(vararg args: Book) : this(args.toList())
|
||||
}
|
||||
|
||||
@Schema(name = "SearchConditionAllOfBook")
|
||||
data class AllOfBook(
|
||||
@JsonProperty("allOf")
|
||||
val conditions: List<Book>,
|
||||
|
|
@ -25,6 +36,7 @@ class SearchCondition {
|
|||
constructor(vararg args: Book) : this(args.toList())
|
||||
}
|
||||
|
||||
@Schema(name = "SearchConditionAnyOfSeries")
|
||||
data class AnyOfSeries(
|
||||
@JsonProperty("anyOf")
|
||||
val conditions: List<Series>,
|
||||
|
|
@ -32,6 +44,7 @@ class SearchCondition {
|
|||
constructor(vararg args: Series) : this(args.toList())
|
||||
}
|
||||
|
||||
@Schema(name = "SearchConditionAllOfSeries")
|
||||
data class AllOfSeries(
|
||||
@JsonProperty("allOf")
|
||||
val conditions: List<Series>,
|
||||
|
|
@ -39,118 +52,140 @@ class SearchCondition {
|
|||
constructor(vararg args: Series) : this(args.toList())
|
||||
}
|
||||
|
||||
@Schema(name = "SearchConditionLibraryId")
|
||||
data class LibraryId(
|
||||
@JsonProperty("libraryId")
|
||||
val operator: SearchOperator.Equality<String>,
|
||||
) : Book,
|
||||
Series
|
||||
|
||||
@Schema(name = "SearchConditionCollectionId")
|
||||
data class CollectionId(
|
||||
@JsonProperty("collectionId")
|
||||
val operator: SearchOperator.Equality<String>,
|
||||
) : Series
|
||||
|
||||
@Schema(name = "SearchConditionReadListId")
|
||||
data class ReadListId(
|
||||
@JsonProperty("readListId")
|
||||
val operator: SearchOperator.Equality<String>,
|
||||
) : Book
|
||||
|
||||
@Schema(name = "SearchConditionSeriesId")
|
||||
data class SeriesId(
|
||||
@JsonProperty("seriesId")
|
||||
val operator: SearchOperator.Equality<String>,
|
||||
) : Book
|
||||
|
||||
@Schema(name = "SearchConditionDeleted")
|
||||
data class Deleted(
|
||||
@JsonProperty("deleted")
|
||||
val operator: SearchOperator.Boolean,
|
||||
) : Book,
|
||||
Series
|
||||
|
||||
@Schema(name = "SearchConditionComplete")
|
||||
data class Complete(
|
||||
@JsonProperty("complete")
|
||||
val operator: SearchOperator.Boolean,
|
||||
) : Series
|
||||
|
||||
@Schema(name = "SearchConditionOneShot")
|
||||
data class OneShot(
|
||||
@JsonProperty("oneShot")
|
||||
val operator: SearchOperator.Boolean,
|
||||
) : Book,
|
||||
Series
|
||||
|
||||
@Schema(name = "SearchConditionTitle")
|
||||
data class Title(
|
||||
@JsonProperty("title")
|
||||
val operator: SearchOperator.StringOp,
|
||||
) : Book,
|
||||
Series
|
||||
|
||||
@Schema(name = "SearchConditionTitleSort")
|
||||
data class TitleSort(
|
||||
@JsonProperty("titleSort")
|
||||
val operator: SearchOperator.StringOp,
|
||||
) : Series
|
||||
|
||||
@Schema(name = "SearchConditionReleaseDate")
|
||||
data class ReleaseDate(
|
||||
@JsonProperty("releaseDate")
|
||||
val operator: SearchOperator.Date,
|
||||
) : Book,
|
||||
Series
|
||||
|
||||
@Schema(name = "SearchConditionNumberSort")
|
||||
data class NumberSort(
|
||||
@JsonProperty("numberSort")
|
||||
val operator: SearchOperator.Numeric<Float>,
|
||||
) : Book
|
||||
|
||||
@Schema(name = "SearchConditionTag")
|
||||
data class Tag(
|
||||
@JsonProperty("tag")
|
||||
val operator: SearchOperator.EqualityNullable<String>,
|
||||
) : Book,
|
||||
Series
|
||||
|
||||
@Schema(name = "SearchConditionSharingLabel")
|
||||
data class SharingLabel(
|
||||
@JsonProperty("sharingLabel")
|
||||
val operator: SearchOperator.EqualityNullable<String>,
|
||||
) : Series
|
||||
|
||||
@Schema(name = "SearchConditionPublisher")
|
||||
data class Publisher(
|
||||
@JsonProperty("publisher")
|
||||
val operator: SearchOperator.Equality<String>,
|
||||
) : Series
|
||||
|
||||
@Schema(name = "SearchConditionLanguage")
|
||||
data class Language(
|
||||
@JsonProperty("language")
|
||||
val operator: SearchOperator.Equality<String>,
|
||||
) : Series
|
||||
|
||||
@Schema(name = "SearchConditionGenre")
|
||||
data class Genre(
|
||||
@JsonProperty("genre")
|
||||
val operator: SearchOperator.EqualityNullable<String>,
|
||||
) : Series
|
||||
|
||||
@Schema(name = "SearchConditionAgeRating")
|
||||
data class AgeRating(
|
||||
@JsonProperty("ageRating")
|
||||
val operator: SearchOperator.NumericNullable<Int>,
|
||||
) : Series
|
||||
|
||||
@Schema(name = "SearchConditionReadStatus")
|
||||
data class ReadStatus(
|
||||
@JsonProperty("readStatus")
|
||||
val operator: SearchOperator.Equality<org.gotson.komga.domain.model.ReadStatus>,
|
||||
) : Book,
|
||||
Series
|
||||
|
||||
@Schema(name = "SearchConditionMediaStatus")
|
||||
data class MediaStatus(
|
||||
@JsonProperty("mediaStatus")
|
||||
val operator: SearchOperator.Equality<Media.Status>,
|
||||
) : Book
|
||||
|
||||
@Schema(name = "SearchConditionSeriesStatus")
|
||||
data class SeriesStatus(
|
||||
@JsonProperty("seriesStatus")
|
||||
val operator: SearchOperator.Equality<SeriesMetadata.Status>,
|
||||
) : Series
|
||||
|
||||
@Schema(name = "SearchConditionMediaProfile")
|
||||
data class MediaProfile(
|
||||
@JsonProperty("mediaProfile")
|
||||
val operator: SearchOperator.Equality<org.gotson.komga.domain.model.MediaProfile>,
|
||||
) : Book
|
||||
|
||||
@Schema(name = "SearchConditionAuthor")
|
||||
data class Author(
|
||||
@JsonProperty("author")
|
||||
val operator: SearchOperator.Equality<AuthorMatch>,
|
||||
|
|
@ -163,6 +198,7 @@ class SearchCondition {
|
|||
val role: String? = null,
|
||||
)
|
||||
|
||||
@Schema(name = "SearchConditionPoster")
|
||||
data class Poster(
|
||||
@JsonProperty("poster")
|
||||
val operator: SearchOperator.Equality<PosterMatch>,
|
||||
|
|
|
|||
|
|
@ -2,10 +2,21 @@ package org.gotson.komga.domain.model
|
|||
|
||||
import com.fasterxml.jackson.annotation.JsonTypeInfo
|
||||
import com.fasterxml.jackson.annotation.JsonTypeName
|
||||
import io.swagger.v3.oas.annotations.media.DiscriminatorMapping
|
||||
import io.swagger.v3.oas.annotations.media.Schema
|
||||
import java.time.Duration
|
||||
import java.time.ZonedDateTime
|
||||
|
||||
class SearchOperator {
|
||||
@Schema(
|
||||
name = "SearchOperatorEquality",
|
||||
discriminatorProperty = "operator",
|
||||
oneOf = [ Is::class, IsNot::class],
|
||||
discriminatorMapping = [
|
||||
DiscriminatorMapping("is", Is::class),
|
||||
DiscriminatorMapping("isNot", IsNot::class),
|
||||
],
|
||||
)
|
||||
@JsonTypeInfo(
|
||||
use = JsonTypeInfo.Id.NAME,
|
||||
include = JsonTypeInfo.As.PROPERTY,
|
||||
|
|
@ -13,6 +24,17 @@ class SearchOperator {
|
|||
)
|
||||
sealed interface Equality<T>
|
||||
|
||||
@Schema(
|
||||
name = "SearchOperatorEqualityNullable",
|
||||
discriminatorProperty = "operator",
|
||||
oneOf = [ Is::class, IsNot::class, IsNullT::class, IsNotNullT::class],
|
||||
discriminatorMapping = [
|
||||
DiscriminatorMapping("is", Is::class),
|
||||
DiscriminatorMapping("isNot", IsNot::class),
|
||||
DiscriminatorMapping("isNull", IsNullT::class),
|
||||
DiscriminatorMapping("isNotNull", IsNotNullT::class),
|
||||
],
|
||||
)
|
||||
@JsonTypeInfo(
|
||||
use = JsonTypeInfo.Id.NAME,
|
||||
include = JsonTypeInfo.As.PROPERTY,
|
||||
|
|
@ -20,6 +42,21 @@ class SearchOperator {
|
|||
)
|
||||
sealed interface EqualityNullable<T>
|
||||
|
||||
@Schema(
|
||||
name = "SearchOperatorString",
|
||||
discriminatorProperty = "operator",
|
||||
oneOf = [BeginsWith::class, DoesNotBeginWith::class, Contains::class, DoesNotContain::class, EndsWith::class, DoesNotEndWith::class, Is::class, IsNot::class],
|
||||
discriminatorMapping = [
|
||||
DiscriminatorMapping("beginsWith", BeginsWith::class),
|
||||
DiscriminatorMapping("doesNotBeginWith", DoesNotBeginWith::class),
|
||||
DiscriminatorMapping("contains", Contains::class),
|
||||
DiscriminatorMapping("doesNotContain", DoesNotContain::class),
|
||||
DiscriminatorMapping("endsWith", EndsWith::class),
|
||||
DiscriminatorMapping("doesNotEndWith", DoesNotEndWith::class),
|
||||
DiscriminatorMapping("is", Is::class),
|
||||
DiscriminatorMapping("isNot", IsNot::class),
|
||||
],
|
||||
)
|
||||
@JsonTypeInfo(
|
||||
use = JsonTypeInfo.Id.NAME,
|
||||
include = JsonTypeInfo.As.PROPERTY,
|
||||
|
|
@ -27,6 +64,17 @@ class SearchOperator {
|
|||
)
|
||||
sealed interface StringOp
|
||||
|
||||
@Schema(
|
||||
name = "SearchOperatorNumericT",
|
||||
discriminatorProperty = "operator",
|
||||
oneOf = [GreaterThan::class, LessThan::class, Is::class, IsNot::class],
|
||||
discriminatorMapping = [
|
||||
DiscriminatorMapping("greaterThan", GreaterThan::class),
|
||||
DiscriminatorMapping("lessThan", LessThan::class),
|
||||
DiscriminatorMapping("is", Is::class),
|
||||
DiscriminatorMapping("isNot", IsNot::class),
|
||||
],
|
||||
)
|
||||
@JsonTypeInfo(
|
||||
use = JsonTypeInfo.Id.NAME,
|
||||
include = JsonTypeInfo.As.PROPERTY,
|
||||
|
|
@ -34,6 +82,19 @@ class SearchOperator {
|
|||
)
|
||||
sealed interface Numeric<T>
|
||||
|
||||
@Schema(
|
||||
name = "SearchOperatorNumericNullable",
|
||||
discriminatorProperty = "operator",
|
||||
oneOf = [GreaterThan::class, LessThan::class, IsNullT::class, IsNotNullT::class, Is::class, IsNot::class],
|
||||
discriminatorMapping = [
|
||||
DiscriminatorMapping("greaterThan", GreaterThan::class),
|
||||
DiscriminatorMapping("lessThan", LessThan::class),
|
||||
DiscriminatorMapping("isNull", IsNullT::class),
|
||||
DiscriminatorMapping("isNotNull", IsNotNullT::class),
|
||||
DiscriminatorMapping("is", Is::class),
|
||||
DiscriminatorMapping("isNot", IsNot::class),
|
||||
],
|
||||
)
|
||||
@JsonTypeInfo(
|
||||
use = JsonTypeInfo.Id.NAME,
|
||||
include = JsonTypeInfo.As.PROPERTY,
|
||||
|
|
@ -41,6 +102,19 @@ class SearchOperator {
|
|||
)
|
||||
sealed interface NumericNullable<T>
|
||||
|
||||
@Schema(
|
||||
name = "SearchOperatorDate",
|
||||
discriminatorProperty = "operator",
|
||||
oneOf = [Before::class, After::class, IsInTheLast::class, IsNotInTheLast::class, IsNull::class, IsNotNull::class],
|
||||
discriminatorMapping = [
|
||||
DiscriminatorMapping("before", Before::class),
|
||||
DiscriminatorMapping("after", After::class),
|
||||
DiscriminatorMapping("isInTheLast", IsInTheLast::class),
|
||||
DiscriminatorMapping("isNotInTheLast", IsNotInTheLast::class),
|
||||
DiscriminatorMapping("isNull", IsNull::class),
|
||||
DiscriminatorMapping("isNotNull", IsNotNull::class),
|
||||
],
|
||||
)
|
||||
@JsonTypeInfo(
|
||||
use = JsonTypeInfo.Id.NAME,
|
||||
include = JsonTypeInfo.As.PROPERTY,
|
||||
|
|
@ -48,6 +122,15 @@ class SearchOperator {
|
|||
)
|
||||
sealed interface Date
|
||||
|
||||
@Schema(
|
||||
name = "SearchOperatorBoolean",
|
||||
discriminatorProperty = "operator",
|
||||
oneOf = [IsTrue::class, IsFalse::class],
|
||||
discriminatorMapping = [
|
||||
DiscriminatorMapping("isTrue", IsTrue::class),
|
||||
DiscriminatorMapping("isFalse", IsFalse::class),
|
||||
],
|
||||
)
|
||||
@JsonTypeInfo(
|
||||
use = JsonTypeInfo.Id.NAME,
|
||||
include = JsonTypeInfo.As.PROPERTY,
|
||||
|
|
@ -55,6 +138,7 @@ class SearchOperator {
|
|||
)
|
||||
sealed interface Boolean
|
||||
|
||||
@Schema(name = "SearchOperatorIs")
|
||||
@JsonTypeName("is")
|
||||
data class Is<T>(
|
||||
val value: T,
|
||||
|
|
@ -64,6 +148,7 @@ class SearchOperator {
|
|||
Numeric<T>,
|
||||
NumericNullable<T>
|
||||
|
||||
@Schema(name = "SearchOperatorIsNot")
|
||||
@JsonTypeName("isNot")
|
||||
data class IsNot<T>(
|
||||
val value: T,
|
||||
|
|
@ -73,80 +158,97 @@ class SearchOperator {
|
|||
Numeric<T>,
|
||||
NumericNullable<T>
|
||||
|
||||
@Schema(name = "SearchOperatorContains")
|
||||
@JsonTypeName("contains")
|
||||
data class Contains(
|
||||
val value: String,
|
||||
) : StringOp
|
||||
|
||||
@Schema(name = "SearchOperatorDoesNotContain")
|
||||
@JsonTypeName("doesNotContain")
|
||||
data class DoesNotContain(
|
||||
val value: String,
|
||||
) : StringOp
|
||||
|
||||
@Schema(name = "SearchOperatorBeginsWith")
|
||||
@JsonTypeName("beginsWith")
|
||||
data class BeginsWith(
|
||||
val value: String,
|
||||
) : StringOp
|
||||
|
||||
@Schema(name = "SearchOperatorDoesNotBeginWith")
|
||||
@JsonTypeName("doesNotBeginWith")
|
||||
data class DoesNotBeginWith(
|
||||
val value: String,
|
||||
) : StringOp
|
||||
|
||||
@Schema(name = "SearchOperatorEndsWith")
|
||||
@JsonTypeName("endsWith")
|
||||
data class EndsWith(
|
||||
val value: String,
|
||||
) : StringOp
|
||||
|
||||
@Schema(name = "SearchOperatorDoesNotEndWith")
|
||||
@JsonTypeName("doesNotEndWith")
|
||||
data class DoesNotEndWith(
|
||||
val value: String,
|
||||
) : StringOp
|
||||
|
||||
@Schema(name = "SearchOperatorGreaterThan")
|
||||
@JsonTypeName("greaterThan")
|
||||
data class GreaterThan<T>(
|
||||
val value: T,
|
||||
) : Numeric<T>,
|
||||
NumericNullable<T>
|
||||
|
||||
@Schema(name = "SearchOperatorLessThan")
|
||||
@JsonTypeName("lessThan")
|
||||
data class LessThan<T>(
|
||||
val value: T,
|
||||
) : Numeric<T>,
|
||||
NumericNullable<T>
|
||||
|
||||
@Schema(name = "SearchOperatorBefore")
|
||||
@JsonTypeName("before")
|
||||
data class Before(
|
||||
val dateTime: ZonedDateTime,
|
||||
) : Date
|
||||
|
||||
@Schema(name = "SearchOperatorAfter")
|
||||
@JsonTypeName("after")
|
||||
data class After(
|
||||
val dateTime: ZonedDateTime,
|
||||
) : Date
|
||||
|
||||
@Schema(name = "SearchOperatorIsInTheLast")
|
||||
@JsonTypeName("isInTheLast")
|
||||
data class IsInTheLast(
|
||||
val duration: Duration,
|
||||
) : Date
|
||||
|
||||
@Schema(name = "SearchOperatorIsNotInTheLast")
|
||||
@JsonTypeName("isNotInTheLast")
|
||||
data class IsNotInTheLast(
|
||||
val duration: Duration,
|
||||
) : Date
|
||||
|
||||
@Schema(name = "SearchOperatorIsTrue")
|
||||
@JsonTypeName("isTrue")
|
||||
data object IsTrue : Boolean
|
||||
|
||||
@Schema(name = "SearchOperatorIsFalse")
|
||||
@JsonTypeName("isFalse")
|
||||
data object IsFalse : Boolean
|
||||
|
||||
@Schema(name = "SearchOperatorIsNull")
|
||||
@JsonTypeName("isNull")
|
||||
data object IsNull : Date
|
||||
|
||||
@Schema(name = "SearchOperatorIsNotNull")
|
||||
@JsonTypeName("isNotNull")
|
||||
data object IsNotNull : Date
|
||||
|
||||
@Schema(name = "SearchOperatorIsNullT")
|
||||
@JsonTypeName("isNull")
|
||||
class IsNullT<T> :
|
||||
NumericNullable<T>,
|
||||
|
|
@ -160,6 +262,7 @@ class SearchOperator {
|
|||
override fun hashCode(): Int = javaClass.hashCode()
|
||||
}
|
||||
|
||||
@Schema(name = "SearchOperatorIsNotNullT")
|
||||
@JsonTypeName("isNotNull")
|
||||
class IsNotNullT<T> :
|
||||
NumericNullable<T>,
|
||||
|
|
|
|||
|
|
@ -24,6 +24,14 @@ interface MediaRepository {
|
|||
|
||||
fun update(media: Media)
|
||||
|
||||
/**
|
||||
* Performs a full copy of a Media, including MediaExtension, pages, and files.
|
||||
*/
|
||||
fun copy(
|
||||
fromBookId: String,
|
||||
toBookId: String,
|
||||
)
|
||||
|
||||
fun delete(bookId: String)
|
||||
|
||||
fun delete(bookIds: Collection<String>)
|
||||
|
|
|
|||
|
|
@ -21,6 +21,10 @@ interface ThumbnailBookRepository {
|
|||
|
||||
fun existsById(thumbnailId: String): Boolean
|
||||
|
||||
fun getLibraryIdOrNull(thumbnailId: String): String?
|
||||
|
||||
fun getSeriesIdOrNull(thumbnailId: String): String?
|
||||
|
||||
fun insert(thumbnail: ThumbnailBook)
|
||||
|
||||
fun update(thumbnail: ThumbnailBook)
|
||||
|
|
|
|||
|
|
@ -146,7 +146,6 @@ class BookAnalyzer(
|
|||
): Media {
|
||||
book.path.epub { epub ->
|
||||
val (resources, missingResources) = epubExtractor.getResources(epub).partition { it.fileSize != null }
|
||||
val isFixedLayout = epubExtractor.isFixedLayout(epub)
|
||||
val isKepub = epubExtractor.isKepub(epub, resources)
|
||||
|
||||
val errors = mutableListOf<String>()
|
||||
|
|
@ -180,13 +179,15 @@ class BookAnalyzer(
|
|||
|
||||
val divinaPages =
|
||||
try {
|
||||
epubExtractor.getDivinaPages(epub, isFixedLayout, analyzeDimensions)
|
||||
epubExtractor.getDivinaPages(epub, analyzeDimensions)
|
||||
} catch (e: Exception) {
|
||||
logger.error(e) { "Error while getting EPUB Divina pages" }
|
||||
errors.add("ERR_1038")
|
||||
emptyList()
|
||||
}
|
||||
|
||||
val isFixedLayout = divinaPages.isNotEmpty() || epubExtractor.isFixedLayout(epub)
|
||||
|
||||
val positions =
|
||||
try {
|
||||
epubExtractor.computePositions(epub, book.path, resources, isFixedLayout, isKepub)
|
||||
|
|
@ -212,7 +213,7 @@ class BookAnalyzer(
|
|||
status = Media.Status.READY,
|
||||
pages = divinaPages,
|
||||
files = resources,
|
||||
pageCount = epubExtractor.computePageCount(epub),
|
||||
pageCount = if (divinaPages.isNotEmpty()) divinaPages.size else epubExtractor.computePageCount(epub),
|
||||
epubDivinaCompatible = divinaPages.isNotEmpty(),
|
||||
epubIsKepub = isKepub,
|
||||
extension =
|
||||
|
|
@ -265,27 +266,28 @@ class BookAnalyzer(
|
|||
|
||||
fun getPoster(book: BookWithMedia): TypedBytes? =
|
||||
when (book.media.profile) {
|
||||
MediaProfile.DIVINA ->
|
||||
divinaExtractors[book.media.mediaType]
|
||||
?.getEntryStream(
|
||||
book.book.path,
|
||||
book.media.pages
|
||||
.first()
|
||||
.fileName,
|
||||
)?.let {
|
||||
TypedBytes(
|
||||
it,
|
||||
book.media.pages
|
||||
.first()
|
||||
.mediaType,
|
||||
)
|
||||
}
|
||||
|
||||
MediaProfile.DIVINA -> divinaExtractors[book.media.mediaType]?.getPoster(book)
|
||||
MediaProfile.PDF -> pdfExtractor.getPageContentAsImage(book.book.path, 1)
|
||||
MediaProfile.EPUB -> epubExtractor.getCover(book.book.path)
|
||||
MediaProfile.EPUB -> epubExtractor.getCover(book.book.path) ?: if (book.media.epubDivinaCompatible) divinaExtractors[MediaType.ZIP.type]?.getPoster(book) else null
|
||||
null -> null
|
||||
}
|
||||
|
||||
private fun DivinaExtractor.getPoster(book: BookWithMedia): TypedBytes =
|
||||
this
|
||||
.getEntryStream(
|
||||
book.book.path,
|
||||
book.media.pages
|
||||
.first()
|
||||
.fileName,
|
||||
).let {
|
||||
TypedBytes(
|
||||
it,
|
||||
book.media.pages
|
||||
.first()
|
||||
.mediaType,
|
||||
)
|
||||
}
|
||||
|
||||
@Throws(
|
||||
MediaNotReadyException::class,
|
||||
IndexOutOfBoundsException::class,
|
||||
|
|
|
|||
|
|
@ -381,9 +381,7 @@ class LibraryContentLifecycle(
|
|||
logger.info { "Match found, restore $match into $bookToAdd" }
|
||||
transactionTemplate.executeWithoutResult {
|
||||
// copy media
|
||||
mediaRepository.findById(match.id).let { deleted ->
|
||||
mediaRepository.update(deleted.copy(bookId = bookToAdd.id))
|
||||
}
|
||||
mediaRepository.copy(match.id, bookToAdd.id)
|
||||
|
||||
// copy generated and user uploaded thumbnails
|
||||
thumbnailBookRepository.findAllByBookIdAndType(match.id, setOf(ThumbnailBook.Type.GENERATED, ThumbnailBook.Type.USER_UPLOADED)).forEach { deleted ->
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package org.gotson.komga.infrastructure.jooq.main
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import io.github.oshai.kotlinlogging.KotlinLogging
|
||||
import org.gotson.komga.domain.model.BookPage
|
||||
import org.gotson.komga.domain.model.Dimension
|
||||
import org.gotson.komga.domain.model.Media
|
||||
|
|
@ -26,6 +27,8 @@ import org.springframework.transaction.annotation.Transactional
|
|||
import java.time.LocalDateTime
|
||||
import java.time.ZoneId
|
||||
|
||||
private val logger = KotlinLogging.logger {}
|
||||
|
||||
@Component
|
||||
class MediaDao(
|
||||
dslRW: DSLContext,
|
||||
|
|
@ -158,7 +161,14 @@ class MediaDao(
|
|||
media.pageCount,
|
||||
media.epubDivinaCompatible,
|
||||
media.epubIsKepub,
|
||||
media.extension?.let { if (it is ProxyExtension) null else it::class.qualifiedName },
|
||||
media.extension?.let {
|
||||
if (it is ProxyExtension) {
|
||||
logger.error { "Found ProxyExtension while trying to insert Media: this is not expected and should be reported." }
|
||||
null
|
||||
} else {
|
||||
it::class.qualifiedName
|
||||
}
|
||||
},
|
||||
media.extension?.let { if (it is ProxyExtension) null else mapper.serializeJsonGz(it) },
|
||||
)
|
||||
}
|
||||
|
|
@ -249,9 +259,13 @@ class MediaDao(
|
|||
.set(m.EPUB_DIVINA_COMPATIBLE, media.epubDivinaCompatible)
|
||||
.set(m.EPUB_IS_KEPUB, media.epubIsKepub)
|
||||
.apply {
|
||||
if (media.extension != null && media.extension !is ProxyExtension) {
|
||||
set(m.EXTENSION_CLASS, media.extension::class.qualifiedName)
|
||||
set(m.EXTENSION_VALUE_BLOB, mapper.serializeJsonGz(media.extension))
|
||||
if (media.extension != null) {
|
||||
if (media.extension !is ProxyExtension) {
|
||||
set(m.EXTENSION_CLASS, media.extension::class.qualifiedName)
|
||||
set(m.EXTENSION_VALUE_BLOB, mapper.serializeJsonGz(media.extension))
|
||||
} else {
|
||||
logger.error { "Found ProxyExtension while trying to update Media: this is not expected and should be reported." }
|
||||
}
|
||||
}
|
||||
}.set(m.LAST_MODIFIED_DATE, LocalDateTime.now(ZoneId.of("Z")))
|
||||
.where(m.BOOK_ID.eq(media.bookId))
|
||||
|
|
@ -271,6 +285,18 @@ class MediaDao(
|
|||
dslRW.insertFiles(listOf(media))
|
||||
}
|
||||
|
||||
@Transactional
|
||||
override fun copy(
|
||||
fromBookId: String,
|
||||
toBookId: String,
|
||||
) {
|
||||
val source = findById(fromBookId)
|
||||
val sourceExtension = findExtensionByIdOrNull(fromBookId)
|
||||
|
||||
val copy = source.copy(bookId = toBookId, extension = sourceExtension)
|
||||
update(copy)
|
||||
}
|
||||
|
||||
@Transactional
|
||||
override fun delete(bookId: String) {
|
||||
dslRW.deleteFrom(p).where(p.BOOK_ID.eq(bookId)).execute()
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ class ThumbnailBookDao(
|
|||
) : SplitDslDaoBase(dslRW, dslRO),
|
||||
ThumbnailBookRepository {
|
||||
private val tb = Tables.THUMBNAIL_BOOK
|
||||
private val b = Tables.BOOK
|
||||
|
||||
override fun findAllByBookId(bookId: String): Collection<ThumbnailBook> =
|
||||
dslRO
|
||||
|
|
@ -72,6 +73,24 @@ class ThumbnailBookDao(
|
|||
|
||||
override fun existsById(thumbnailId: String): Boolean = dslRO.fetchExists(tb, tb.ID.eq(thumbnailId))
|
||||
|
||||
override fun getLibraryIdOrNull(thumbnailId: String): String? =
|
||||
dslRO
|
||||
.select(b.LIBRARY_ID)
|
||||
.from(tb)
|
||||
.leftJoin(b)
|
||||
.on(tb.BOOK_ID.eq(b.ID))
|
||||
.where(tb.ID.eq(thumbnailId))
|
||||
.fetchOne(b.LIBRARY_ID)
|
||||
|
||||
override fun getSeriesIdOrNull(thumbnailId: String): String? =
|
||||
dslRO
|
||||
.select(b.SERIES_ID)
|
||||
.from(tb)
|
||||
.leftJoin(b)
|
||||
.on(tb.BOOK_ID.eq(b.ID))
|
||||
.where(tb.ID.eq(thumbnailId))
|
||||
.fetchOne(b.SERIES_ID)
|
||||
|
||||
override fun insert(thumbnail: ThumbnailBook) {
|
||||
dslRW
|
||||
.insertInto(tb)
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ import org.springframework.util.LinkedMultiValueMap
|
|||
import org.springframework.web.client.RestClient
|
||||
import org.springframework.web.client.toEntity
|
||||
import org.springframework.web.server.ResponseStatusException
|
||||
import org.springframework.web.util.DefaultUriBuilderFactory
|
||||
import kotlin.time.Duration.Companion.minutes
|
||||
import kotlin.time.toJavaDuration
|
||||
|
||||
|
|
@ -29,11 +30,15 @@ class KoboProxy(
|
|||
private val komgaSyncTokenGenerator: KomgaSyncTokenGenerator,
|
||||
private val komgaSettingsProvider: KomgaSettingsProvider,
|
||||
) {
|
||||
private val koboApiClient =
|
||||
private val koboApiClient: RestClient =
|
||||
RestClient
|
||||
.builder()
|
||||
.baseUrl("https://storeapi.kobo.com")
|
||||
.requestFactory(
|
||||
.uriBuilderFactory(
|
||||
DefaultUriBuilderFactory("https://storeapi.kobo.com")
|
||||
.apply {
|
||||
this.encodingMode = DefaultUriBuilderFactory.EncodingMode.NONE
|
||||
},
|
||||
).requestFactory(
|
||||
ClientHttpRequestFactoryBuilder.reactor().build(
|
||||
ClientHttpRequestFactorySettings
|
||||
.defaults()
|
||||
|
|
@ -42,7 +47,7 @@ class KoboProxy(
|
|||
),
|
||||
).build()
|
||||
|
||||
private val pathRegex = """\/kobo\/[-\w]*(.*)""".toRegex()
|
||||
private val pathRegex = """/kobo/[-\w]*(.*)""".toRegex()
|
||||
|
||||
private val headersOutInclude =
|
||||
setOf(
|
||||
|
|
@ -50,6 +55,7 @@ class KoboProxy(
|
|||
HttpHeaders.USER_AGENT,
|
||||
HttpHeaders.ACCEPT,
|
||||
HttpHeaders.ACCEPT_LANGUAGE,
|
||||
HttpHeaders.CONTENT_TYPE,
|
||||
)
|
||||
|
||||
private val headersOutExclude =
|
||||
|
|
@ -68,7 +74,7 @@ class KoboProxy(
|
|||
* raw Kobo sync token returned, and added to the response headers.
|
||||
*/
|
||||
fun proxyCurrentRequest(
|
||||
body: Any? = null,
|
||||
body: ByteArray? = null,
|
||||
includeSyncToken: Boolean = false,
|
||||
): ResponseEntity<JsonNode> {
|
||||
if (!komgaSettingsProvider.koboProxy) throw IllegalStateException("kobo proxying is disabled")
|
||||
|
|
@ -110,6 +116,7 @@ class KoboProxy(
|
|||
}.apply { if (body != null) body(body) }
|
||||
.retrieve()
|
||||
.onStatus(HttpStatusCode::isError) { _, response ->
|
||||
logger.debug { "Kobo response: ${response.statusCode}: ${response.body.bufferedReader().use { it.readText() }}" }
|
||||
throw ResponseStatusException(response.statusCode, response.statusText)
|
||||
}.toEntity<JsonNode>()
|
||||
|
||||
|
|
|
|||
|
|
@ -28,7 +28,6 @@ class RarExtractor(
|
|||
): List<MediaContainerEntry> =
|
||||
Archive(path.toFile()).use { rar ->
|
||||
if (rar.isPasswordProtected) throw MediaUnsupportedException("Encrypted RAR archives are not supported", "ERR_1002")
|
||||
if (rar.mainHeader.isSolid) throw MediaUnsupportedException("Solid RAR archives are not supported", "ERR_1003")
|
||||
if (rar.mainHeader.isMultiVolume) throw MediaUnsupportedException("Multi-Volume RAR archives are not supported", "ERR_1004")
|
||||
rar.fileHeaders
|
||||
.filter { !it.isDirectory }
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ class EpubExtractor(
|
|||
fun isEpub(path: Path): Boolean =
|
||||
try {
|
||||
getEntryStream(path, "mimetype").decodeToString().trim() == "application/epub+zip"
|
||||
} catch (e: Exception) {
|
||||
} catch (_: Exception) {
|
||||
false
|
||||
}
|
||||
|
||||
|
|
@ -67,7 +67,7 @@ class EpubExtractor(
|
|||
?: // try id="cover-image"
|
||||
manifest.values.firstOrNull { it.id == "cover-image" }
|
||||
if (coverManifestItem != null) {
|
||||
val href = coverManifestItem.href
|
||||
val href = URLDecoder.decode(coverManifestItem.href, Charsets.UTF_8)
|
||||
val mediaType = coverManifestItem.mediaType
|
||||
val coverPath = normalizeHref(opfDir, href)
|
||||
zip.getEntryBytes(coverPath)?.let { coverBytes ->
|
||||
|
|
@ -114,14 +114,8 @@ class EpubExtractor(
|
|||
|
||||
fun getDivinaPages(
|
||||
epub: EpubPackage,
|
||||
isFixedLayout: Boolean,
|
||||
analyzeDimensions: Boolean,
|
||||
): List<BookPage> {
|
||||
if (!isFixedLayout) {
|
||||
logger.info { "Epub Divina detection failed: book is not fixed layout" }
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
val pageCount =
|
||||
run {
|
||||
val spine =
|
||||
|
|
@ -139,24 +133,31 @@ class EpubExtractor(
|
|||
epub.opfDoc
|
||||
.select("*|spine > *|itemref")
|
||||
.map { it.attr("idref") }
|
||||
.mapNotNull { idref -> epub.manifest[idref]?.href?.let { normalizeHref(epub.opfDir, it) } }
|
||||
.map { pagePath ->
|
||||
val doc = epub.zip.getEntryInputStream(pagePath)?.use { Jsoup.parse(it, null, "") } ?: return@map emptyList()
|
||||
.mapNotNull { idref ->
|
||||
val manifestItem = epub.manifest[idref] ?: return@mapNotNull null
|
||||
normalizeHref(epub.opfDir, manifestItem.href) to manifestItem.mediaType
|
||||
}.map { (pagePath, mediaType) ->
|
||||
if (mediaType.startsWith("image", true)) {
|
||||
// image in spine
|
||||
listOf(Path(pagePath).normalize().invariantSeparatorsPathString)
|
||||
} else {
|
||||
val doc = epub.zip.getEntryInputStream(pagePath)?.use { Jsoup.parse(it, null, "") } ?: return@map emptyList()
|
||||
|
||||
// if a page has text over the threshold then the book is not divina compatible
|
||||
if (doc.body().text().length > letterCountThreshold) return emptyList()
|
||||
// if a page has text over the threshold then the book is not divina compatible
|
||||
if (doc.body().text().length > letterCountThreshold) return emptyList()
|
||||
|
||||
val img =
|
||||
doc
|
||||
.getElementsByTag("img")
|
||||
.map { it.attr("src") } // get the src, which can be a relative path
|
||||
val img =
|
||||
doc
|
||||
.getElementsByTag("img")
|
||||
.map { it.attr("src") } // get the src, which can be a relative path
|
||||
|
||||
val svg =
|
||||
doc
|
||||
.select("svg > image[xlink:href]")
|
||||
.map { it.attr("xlink:href") } // get the source, which can be a relative path
|
||||
val svg =
|
||||
doc
|
||||
.select("svg > image[xlink:href]")
|
||||
.map { it.attr("xlink:href") } // get the source, which can be a relative path
|
||||
|
||||
(img + svg).map { (Path(pagePath).parent ?: Path("")).resolve(it).normalize().invariantSeparatorsPathString } // resolve it against the page folder
|
||||
(img + svg).map { (Path(pagePath).parent ?: Path("")).resolve(it).normalize().invariantSeparatorsPathString } // resolve it against the page folder
|
||||
}
|
||||
}
|
||||
|
||||
if (pagesWithImages.size != pageCount) {
|
||||
|
|
@ -164,7 +165,7 @@ class EpubExtractor(
|
|||
return emptyList()
|
||||
}
|
||||
// Only keep unique image path for each page. KCC sometimes generates HTML pages with 5 times the same image.
|
||||
val imagesPath = pagesWithImages.map { it.distinct() }.flatten()
|
||||
val imagesPath = pagesWithImages.flatMap { it.distinct() }
|
||||
if (imagesPath.size != pageCount) {
|
||||
logger.info { "Epub Divina detection failed: book has ${imagesPath.size} detected images, but $pageCount total pages" }
|
||||
return emptyList()
|
||||
|
|
@ -259,7 +260,7 @@ class EpubExtractor(
|
|||
val positions = computePositionsFromKoboSpan(readingOrder) { filename -> getZipEntryBytes(kepub, filename).decodeToString() }
|
||||
kepub.deleteIfExists()
|
||||
positions
|
||||
} catch (e: Exception) {
|
||||
} catch (_: Exception) {
|
||||
logger.warn { "Could not convert to Kepub to compute positions: $path" }
|
||||
emptyMap()
|
||||
}
|
||||
|
|
@ -336,7 +337,8 @@ class EpubExtractor(
|
|||
|
||||
fun getToc(epub: EpubPackage): List<EpubTocEntry> {
|
||||
// Epub 3
|
||||
epub.getNavResource()?.let { return processNav(it, Epub3Nav.TOC) }
|
||||
epub.getNavResource()?.let { processNav(it, Epub3Nav.TOC) }?.let { if (it.isNotEmpty()) return it }
|
||||
|
||||
// Epub 2
|
||||
epub.getNcxResource()?.let { return processNcx(it, Epub2Nav.TOC) }
|
||||
return emptyList()
|
||||
|
|
@ -344,7 +346,8 @@ class EpubExtractor(
|
|||
|
||||
fun getPageList(epub: EpubPackage): List<EpubTocEntry> {
|
||||
// Epub 3
|
||||
epub.getNavResource()?.let { return processNav(it, Epub3Nav.PAGELIST) }
|
||||
epub.getNavResource()?.let { processNav(it, Epub3Nav.PAGELIST) }?.let { if (it.isNotEmpty()) return it }
|
||||
|
||||
// Epub 2
|
||||
epub.getNcxResource()?.let { return processNcx(it, Epub2Nav.PAGELIST) }
|
||||
return emptyList()
|
||||
|
|
@ -352,7 +355,7 @@ class EpubExtractor(
|
|||
|
||||
fun getLandmarks(epub: EpubPackage): List<EpubTocEntry> {
|
||||
// Epub 3
|
||||
epub.getNavResource()?.let { return processNav(it, Epub3Nav.LANDMARKS) }
|
||||
epub.getNavResource()?.let { processNav(it, Epub3Nav.LANDMARKS) }?.let { if (it.isNotEmpty()) return it }
|
||||
|
||||
// Epub 2
|
||||
return processOpfGuide(epub.opfDoc, epub.opfDir)
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import org.gotson.komga.domain.model.EpubTocEntry
|
|||
import org.gotson.komga.infrastructure.util.getEntryBytes
|
||||
import org.jsoup.Jsoup
|
||||
import org.jsoup.nodes.Element
|
||||
import org.jsoup.parser.Parser
|
||||
import java.net.URLDecoder
|
||||
import java.nio.file.Path
|
||||
import kotlin.io.path.Path
|
||||
|
|
@ -20,7 +21,7 @@ fun processNav(
|
|||
document: ResourceContent,
|
||||
navElement: Epub3Nav,
|
||||
): List<EpubTocEntry> {
|
||||
val doc = Jsoup.parse(document.content)
|
||||
val doc = Jsoup.parse(document.content, "", Parser.xmlParser())
|
||||
val nav =
|
||||
doc
|
||||
.select("nav")
|
||||
|
|
|
|||
|
|
@ -0,0 +1,44 @@
|
|||
package org.gotson.komga.infrastructure.openapi
|
||||
|
||||
import org.springdoc.core.customizers.OpenApiCustomizer
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.core.Ordered
|
||||
import org.springframework.core.annotation.Order
|
||||
|
||||
/**
|
||||
* The generated schema for sealed classes is somehow wrong.
|
||||
* This customizer will correct the issues.
|
||||
*/
|
||||
@Configuration
|
||||
@Order(Ordered.LOWEST_PRECEDENCE)
|
||||
class InheritanceFlattenerConfiguration {
|
||||
private val schemaPrefix = listOf("SearchOperator", "SearchCondition")
|
||||
|
||||
@Bean
|
||||
fun flattenInheritedSchemasCustomizer(): OpenApiCustomizer =
|
||||
OpenApiCustomizer { openApi ->
|
||||
openApi.components
|
||||
?.schemas
|
||||
?.values
|
||||
?.filter { schema -> schemaPrefix.any { prefix -> schema.name.startsWith(prefix, false) } }
|
||||
?.forEach { schema ->
|
||||
// Swagger models inheritance as an allOf list with exactly two items:
|
||||
// 1. The $ref to the parent interface
|
||||
// 2. An inline schema containing the child's actual properties
|
||||
if (schema.allOf != null) {
|
||||
val refSchema = schema.allOf.filter { it.`$ref` != null }
|
||||
val inlineSchema = schema.allOf.find { it.properties != null }
|
||||
|
||||
// If both are found, we know this is an inherited schema wrapper
|
||||
if (refSchema.isNotEmpty() && inlineSchema != null) {
|
||||
// Move the properties up to the root schema
|
||||
schema.properties = inlineSchema.properties
|
||||
|
||||
// Delete the allOf array entirely
|
||||
schema.allOf = null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -4,6 +4,7 @@ import org.gotson.komga.domain.model.Book
|
|||
import org.gotson.komga.domain.model.KomgaUser
|
||||
import org.gotson.komga.domain.persistence.BookRepository
|
||||
import org.gotson.komga.domain.persistence.SeriesMetadataRepository
|
||||
import org.gotson.komga.domain.persistence.ThumbnailBookRepository
|
||||
import org.gotson.komga.interfaces.api.rest.dto.BookDto
|
||||
import org.gotson.komga.interfaces.api.rest.dto.SeriesDto
|
||||
import org.springframework.http.HttpStatus
|
||||
|
|
@ -14,6 +15,7 @@ import org.springframework.web.server.ResponseStatusException
|
|||
class ContentRestrictionChecker(
|
||||
private val seriesMetadataRepository: SeriesMetadataRepository,
|
||||
private val bookRepository: BookRepository,
|
||||
private val thumbnailBookRepository: ThumbnailBookRepository,
|
||||
) {
|
||||
/**
|
||||
* Convenience function to check for content restriction.
|
||||
|
|
@ -84,4 +86,26 @@ class ContentRestrictionChecker(
|
|||
if (!komgaUser.canAccessLibrary(series.libraryId)) throw ResponseStatusException(HttpStatus.FORBIDDEN)
|
||||
if (!komgaUser.isContentAllowed(series.metadata.ageRating, series.metadata.sharingLabels)) throw ResponseStatusException(HttpStatus.FORBIDDEN)
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience function to check for content restriction.
|
||||
*
|
||||
* @throws[ResponseStatusException] if the user cannot access the content
|
||||
*/
|
||||
fun checkContentRestrictionBookThumbnail(
|
||||
komgaUser: KomgaUser,
|
||||
thumbnailId: String,
|
||||
) {
|
||||
if (!komgaUser.canAccessAllLibraries()) {
|
||||
thumbnailBookRepository.getLibraryIdOrNull(thumbnailId)?.let {
|
||||
if (!komgaUser.canAccessLibrary(it)) throw ResponseStatusException(HttpStatus.FORBIDDEN)
|
||||
} ?: throw ResponseStatusException(HttpStatus.NOT_FOUND)
|
||||
}
|
||||
if (komgaUser.restrictions.isRestricted)
|
||||
thumbnailBookRepository.getSeriesIdOrNull(thumbnailId)?.let { seriesId ->
|
||||
seriesMetadataRepository.findById(seriesId).let {
|
||||
if (!komgaUser.isContentAllowed(it.ageRating, it.sharingLabels)) throw ResponseStatusException(HttpStatus.FORBIDDEN)
|
||||
}
|
||||
} ?: throw ResponseStatusException(HttpStatus.NOT_FOUND)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@ class OpdsGenerator(
|
|||
links =
|
||||
listOf(
|
||||
WPLinkDto(rel = "help", href = "https://komga.org"),
|
||||
WPLinkDto(rel = "logo", href = ServletUriComponentsBuilder.fromCurrentContextPath().path("android-chrome-512x512.png").toUriString()),
|
||||
WPLinkDto(rel = "logo", href = ServletUriComponentsBuilder.fromCurrentContextPath().pathSegment("android-chrome-512x512.png").toUriString()),
|
||||
),
|
||||
authentication =
|
||||
listOf(
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package org.gotson.komga.interfaces.api.kobo
|
|||
import com.fasterxml.jackson.databind.JsonNode
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode
|
||||
import com.fasterxml.jackson.module.kotlin.readValue
|
||||
import com.fasterxml.jackson.module.kotlin.treeToValue
|
||||
import com.github.benmanes.caffeine.cache.Caffeine
|
||||
import io.github.oshai.kotlinlogging.KotlinLogging
|
||||
|
|
@ -174,6 +175,7 @@ class KoboController(
|
|||
private val imageConverter: ImageConverter,
|
||||
private val mediaRepository: MediaRepository,
|
||||
private val contentRestrictionChecker: ContentRestrictionChecker,
|
||||
private val objectMapper: ObjectMapper,
|
||||
) {
|
||||
private val cachedKepub =
|
||||
Caffeine
|
||||
|
|
@ -194,6 +196,7 @@ class KoboController(
|
|||
try {
|
||||
koboProxy.proxyCurrentRequest().body?.get("Resources")
|
||||
} catch (e: Exception) {
|
||||
if (e is ResponseStatusException && e.statusCode == HttpStatus.UNAUTHORIZED) throw e
|
||||
logger.warn { "Failed to get response from Kobo /v1/initialization, fallback to noproxy" }
|
||||
null
|
||||
} ?: koboProxy.nativeKoboResources
|
||||
|
|
@ -229,14 +232,16 @@ class KoboController(
|
|||
*/
|
||||
@PostMapping("v1/auth/device")
|
||||
fun authDevice(
|
||||
@RequestBody body: JsonNode,
|
||||
@RequestBody rawBody: ByteArray,
|
||||
): Any {
|
||||
try {
|
||||
return koboProxy.proxyCurrentRequest(body)
|
||||
} catch (e: Exception) {
|
||||
return koboProxy.proxyCurrentRequest(rawBody)
|
||||
} catch (_: Exception) {
|
||||
logger.warn { "Failed to get response from Kobo /v1/auth/device, fallback to noproxy" }
|
||||
}
|
||||
|
||||
val body = objectMapper.readTree(rawBody)
|
||||
|
||||
/**
|
||||
* Komga does not use the /v1/auth/device API call for authentication/authorization.
|
||||
* Return dummy data to keep the device happy.
|
||||
|
|
@ -395,7 +400,7 @@ class KoboController(
|
|||
addAll(
|
||||
// changed books are also passed as changed reading state because Kobo does not process ChangedEntitlement even if it contains a ReadingState
|
||||
(booksChanged.content + changedReadingState.content).mapNotNull { book ->
|
||||
readProgress[book.bookId]?.let { it ->
|
||||
readProgress[book.bookId]?.let {
|
||||
ChangedReadingStateDto(
|
||||
WrappedReadingStateDto(
|
||||
it.toDto(),
|
||||
|
|
@ -511,13 +516,17 @@ class KoboController(
|
|||
*/
|
||||
@GetMapping("/v1/library/{bookId}/metadata")
|
||||
fun getBookMetadata(
|
||||
@AuthenticationPrincipal principal: KomgaPrincipal,
|
||||
@PathVariable authToken: String,
|
||||
@PathVariable bookId: String,
|
||||
): ResponseEntity<*> =
|
||||
if (!bookRepository.existsById(bookId) && koboProxy.isEnabled())
|
||||
if (!bookRepository.existsById(bookId) && koboProxy.isEnabled()) {
|
||||
koboProxy.proxyCurrentRequest()
|
||||
else
|
||||
} else {
|
||||
contentRestrictionChecker.checkContentRestriction(principal.user, bookId)
|
||||
|
||||
ResponseEntity.ok(koboDtoRepository.findBookMetadataByIds(listOf(bookId)).map { it.withDownloadUrls(getDownloadUrlBuilder(authToken)) })
|
||||
}
|
||||
|
||||
/**
|
||||
* @return an array of [ReadingStateDto]
|
||||
|
|
@ -534,6 +543,8 @@ class KoboController(
|
|||
else
|
||||
throw ResponseStatusException(HttpStatus.NOT_FOUND)
|
||||
|
||||
contentRestrictionChecker.checkContentRestriction(principal.user, book)
|
||||
|
||||
val response = readProgressRepository.findByBookIdAndUserIdOrNull(bookId, principal.user.id)?.toDto() ?: getEmptyReadProgressForBook(book)
|
||||
return ResponseEntity.ok(listOf(response))
|
||||
}
|
||||
|
|
@ -545,16 +556,20 @@ class KoboController(
|
|||
fun updateState(
|
||||
@AuthenticationPrincipal principal: KomgaPrincipal,
|
||||
@PathVariable bookId: String,
|
||||
@RequestBody body: ReadingStateStateUpdateDto,
|
||||
@RequestBody rawBody: ByteArray,
|
||||
@RequestHeader(name = X_KOBO_DEVICEID, required = false) koboDeviceId: String = "unknown",
|
||||
): ResponseEntity<*> {
|
||||
val body = objectMapper.readValue<ReadingStateStateUpdateDto>(rawBody)
|
||||
|
||||
val book =
|
||||
bookRepository.findByIdOrNull(bookId)
|
||||
?: if (koboProxy.isEnabled())
|
||||
return koboProxy.proxyCurrentRequest(body)
|
||||
return koboProxy.proxyCurrentRequest(rawBody)
|
||||
else
|
||||
throw ResponseStatusException(HttpStatus.NOT_FOUND)
|
||||
|
||||
contentRestrictionChecker.checkContentRestriction(principal.user, book)
|
||||
|
||||
val koboUpdate = body.readingStates.firstOrNull() ?: throw ResponseStatusException(HttpStatus.BAD_REQUEST)
|
||||
if (koboUpdate.currentBookmark.location == null || koboUpdate.currentBookmark.contentSourceProgressPercent == null) throw ResponseStatusException(HttpStatus.BAD_REQUEST)
|
||||
|
||||
|
|
@ -718,6 +733,8 @@ class KoboController(
|
|||
.location(UriComponentsBuilder.fromUriString(koboProxy.imageHostUrl).buildAndExpand(thumbnailId, width, height).toUri())
|
||||
.build()
|
||||
} else {
|
||||
contentRestrictionChecker.checkContentRestrictionBookThumbnail(principal.user, thumbnailId)
|
||||
|
||||
val poster = bookLifecycle.getThumbnailBytesByThumbnailId(thumbnailId) ?: throw ResponseStatusException(HttpStatus.NOT_FOUND)
|
||||
val posterBytes =
|
||||
if (poster.mediaType != ImageType.JPEG.mediaType)
|
||||
|
|
@ -732,7 +749,7 @@ class KoboController(
|
|||
method = [RequestMethod.GET, RequestMethod.PUT, RequestMethod.POST, RequestMethod.DELETE, RequestMethod.PATCH],
|
||||
)
|
||||
fun catchAll(
|
||||
@RequestBody body: Any?,
|
||||
@RequestBody body: ByteArray?,
|
||||
): ResponseEntity<JsonNode> =
|
||||
if (koboProxy.isEnabled())
|
||||
koboProxy.proxyCurrentRequest(body)
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import org.gotson.komga.infrastructure.security.KomgaPrincipal
|
|||
import org.gotson.komga.interfaces.api.kosync.dto.DocumentProgressDto
|
||||
import org.gotson.komga.interfaces.api.kosync.dto.UserAuthenticationDto
|
||||
import org.springframework.http.HttpStatus
|
||||
import org.springframework.http.MediaType
|
||||
import org.springframework.http.ResponseEntity
|
||||
import org.springframework.security.core.annotation.AuthenticationPrincipal
|
||||
import org.springframework.web.bind.annotation.GetMapping
|
||||
|
|
@ -29,7 +30,7 @@ import java.time.ZonedDateTime
|
|||
private val logger = KotlinLogging.logger {}
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/koreader", produces = ["application/vnd.koreader.v1+json"])
|
||||
@RequestMapping("/koreader", produces = [MediaType.APPLICATION_JSON_VALUE, "application/vnd.koreader.v1+json"])
|
||||
class KoreaderSyncController(
|
||||
private val bookRepository: BookRepository,
|
||||
private val mediaRepository: MediaRepository,
|
||||
|
|
|
|||
|
|
@ -435,7 +435,7 @@ class Opds2Controller(
|
|||
PageRequest.of(page.pageNumber, page.pageSize, Sort.by(Sort.Order.desc("lastModified"))),
|
||||
).map { it.toWPLinkDto() }
|
||||
|
||||
val uriBuilder = uriBuilder("libraries${if (library != null) "/${library.id}" else ""}/books/latest")
|
||||
val uriBuilder = uriBuilder("libraries${if (library != null) "/${library.id}" else ""}/series/latest")
|
||||
|
||||
return FeedDto(
|
||||
metadata =
|
||||
|
|
|
|||
|
|
@ -268,7 +268,7 @@ class ReadListController(
|
|||
}
|
||||
|
||||
@Operation(summary = "Match ComicRack list", tags = [OpenApiConfiguration.TagNames.COMICRACK])
|
||||
@PostMapping("match/comicrack")
|
||||
@PostMapping("match/comicrack", consumes = [MediaType.MULTIPART_FORM_DATA_VALUE])
|
||||
@PreAuthorize("hasRole('ADMIN')")
|
||||
fun matchComicRackList(
|
||||
@RequestParam("file") file: MultipartFile,
|
||||
|
|
|
|||
|
|
@ -112,10 +112,12 @@ class UserController(
|
|||
restrictions =
|
||||
ContentRestrictions(
|
||||
ageRestriction =
|
||||
if (ageRestriction == null || ageRestriction.restriction == AllowExcludeDto.NONE)
|
||||
null
|
||||
else
|
||||
AgeRestriction(ageRestriction.age, ageRestriction.restriction.toDomain()),
|
||||
ageRestriction.let {
|
||||
if (it == null || it.restriction == AllowExcludeDto.NONE)
|
||||
null
|
||||
else
|
||||
AgeRestriction(it.age, it.restriction.toDomain())
|
||||
},
|
||||
labelsAllow = labelsAllow ?: emptySet(),
|
||||
labelsExclude = labelsExclude ?: emptySet(),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
package org.gotson.komga.interfaces.api.rest.dto
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude
|
||||
import org.gotson.komga.domain.model.AgeRestriction
|
||||
import org.gotson.komga.domain.model.AllowExclude
|
||||
import org.gotson.komga.domain.model.KomgaUser
|
||||
import org.gotson.komga.infrastructure.security.KomgaPrincipal
|
||||
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
data class UserDto(
|
||||
val id: String,
|
||||
val email: String,
|
||||
|
|
|
|||
|
|
@ -55,6 +55,19 @@ class SseController(
|
|||
return emitter
|
||||
}
|
||||
|
||||
@Scheduled(fixedRate = 15_000)
|
||||
fun heartbeat() {
|
||||
if (emitters.isNotEmpty())
|
||||
synchronized(emitters) {
|
||||
emitters.forEach { (emitter, _) ->
|
||||
try {
|
||||
emitter.send(SseEmitter.event().comment("heartbeat"))
|
||||
} catch (_: IOException) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Scheduled(fixedRate = 10_000)
|
||||
fun taskCount() {
|
||||
if (emitters.isNotEmpty()) {
|
||||
|
|
|
|||
|
|
@ -59,14 +59,21 @@ class BookAnalyzerTest(
|
|||
assertThat(media.pages).hasSize(3)
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(
|
||||
strings = [
|
||||
"rar4-solid.rar", "rar4-encrypted.rar",
|
||||
],
|
||||
)
|
||||
fun `given rar4 solid or encrypted archive when analyzing then media status is UNSUPPORTED`(fileName: String) {
|
||||
val file = ClassPathResource("archives/$fileName")
|
||||
@Test
|
||||
fun `given rar4 solid archive when analyzing then media status is READY`() {
|
||||
val file = ClassPathResource("archives/rar4-solid.rar")
|
||||
val book = Book("book", file.url, LocalDateTime.now())
|
||||
|
||||
val media = bookAnalyzer.analyze(book, false)
|
||||
|
||||
assertThat(media.mediaType).isEqualTo("application/x-rar-compressed; version=4")
|
||||
assertThat(media.status).isEqualTo(Media.Status.READY)
|
||||
assertThat(media.pages).hasSize(3)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `given rar4 encrypted archive when analyzing then media status is UNSUPPORTED`() {
|
||||
val file = ClassPathResource("archives/rar4-encrypted.rar")
|
||||
val book = Book("book", file.url, LocalDateTime.now())
|
||||
|
||||
val media = bookAnalyzer.analyze(book, false)
|
||||
|
|
@ -144,7 +151,6 @@ class BookAnalyzerTest(
|
|||
|
||||
assertThat(media.mediaType).isEqualTo("application/epub+zip")
|
||||
assertThat(media.status).isEqualTo(Media.Status.READY)
|
||||
assertThat(media.pages).hasSize(0)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -230,7 +236,7 @@ class BookAnalyzerTest(
|
|||
val file = ClassPathResource("epub/The Incomplete Theft - Ralph Burke.epub")
|
||||
val book = Book("book", file.url, LocalDateTime.now())
|
||||
|
||||
every { epubExtractor.getDivinaPages(any(), any(), any()) } throws Exception("mock exception")
|
||||
every { epubExtractor.getDivinaPages(any(), any()) } throws Exception("mock exception")
|
||||
|
||||
val media = bookAnalyzer.analyze(book, false)
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package org.gotson.komga.infrastructure.mediacontainer.epub
|
|||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.gotson.komga.domain.model.EpubTocEntry
|
||||
import org.jsoup.Jsoup
|
||||
import org.jsoup.parser.Parser
|
||||
import org.junit.jupiter.params.ParameterizedTest
|
||||
import org.junit.jupiter.params.provider.ValueSource
|
||||
import org.springframework.core.io.ClassPathResource
|
||||
|
|
@ -15,7 +16,7 @@ class OpfTest {
|
|||
// given
|
||||
val opfResource = ClassPathResource("epub/clash.opf")
|
||||
val opfString = opfResource.inputStream.readAllBytes().decodeToString()
|
||||
val opfDoc = Jsoup.parse(opfString)
|
||||
val opfDoc = Jsoup.parse(opfString, "", Parser.xmlParser())
|
||||
|
||||
// when
|
||||
val opfLandmarks = processOpfGuide(opfDoc, if (prefix.isBlank()) null else Path.of(prefix))
|
||||
|
|
|
|||
|
|
@ -7,9 +7,13 @@ import org.gotson.komga.domain.service.KomgaUserLifecycle
|
|||
import org.junit.jupiter.api.AfterAll
|
||||
import org.junit.jupiter.api.BeforeAll
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.params.ParameterizedTest
|
||||
import org.junit.jupiter.params.provider.ValueSource
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc
|
||||
import org.springframework.boot.test.context.SpringBootTest
|
||||
import org.springframework.http.HttpHeaders
|
||||
import org.springframework.http.MediaType
|
||||
import org.springframework.test.web.servlet.MockMvc
|
||||
import org.springframework.test.web.servlet.get
|
||||
import org.springframework.test.web.servlet.post
|
||||
|
|
@ -68,4 +72,17 @@ class KoreaderSyncControllerTest(
|
|||
jsonPath("authorized") { value("OK") }
|
||||
}
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = [MediaType.APPLICATION_JSON_VALUE, "application/vnd.koreader.v1+json"])
|
||||
fun `given accept header when calling API user then returns OK`(acceptHeader: String) {
|
||||
mockMvc
|
||||
.get("/koreader/users/auth") {
|
||||
header("x-auth-user", apiKey)
|
||||
header(HttpHeaders.ACCEPT, acceptHeader)
|
||||
}.andExpect {
|
||||
status { isOk() }
|
||||
jsonPath("authorized") { value("OK") }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@ class UserControllerTest(
|
|||
jsonPath("$.sharedLibrariesId") { doesNotExist() }
|
||||
jsonPath("$.labelsAllow") { isEmpty() }
|
||||
jsonPath("$.labelsExclude") { isEmpty() }
|
||||
jsonPath("$.ageRestriction") { isEmpty() }
|
||||
jsonPath("$.ageRestriction") { doesNotExist() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue