Compare commits

..
159 changed files with 33685 additions and 46034 deletions

No files matched your search

-86
View File
@@ -1,91 +1,5 @@
# Changelog # Changelog
## paperless-ngx 3.4.0
### Features / Enhancements
- Enhancement: support custom fields in workflow title templates [@shamoon](https://github.com/shamoon) ([#14564](https://github.com/paperless-ngx/paperless-ngx/pull/14564))
- Enhancement: relative date custom field queries [@shamoon](https://github.com/shamoon) ([#14549](https://github.com/paperless-ngx/paperless-ngx/pull/14549))
- Performance: reduce tasks badge load times [@JanKleine](https://github.com/JanKleine) ([#14552](https://github.com/paperless-ngx/paperless-ngx/pull/14552))
- Enhancement: skip local 2FA for trusted OIDC AMR [@shamoon](https://github.com/shamoon) ([#14403](https://github.com/paperless-ngx/paperless-ngx/pull/14403))
- Feature: Generate PDF thumbnails via poppler utils [@stumpylog](https://github.com/stumpylog) ([#14420](https://github.com/paperless-ngx/paperless-ngx/pull/14420))
- Enhancement: add upload count to button, link to tray, reduce notifications [@shamoon](https://github.com/shamoon) ([#14501](https://github.com/paperless-ngx/paperless-ngx/pull/14501))
- Enhancement: notifications improvements [@shamoon](https://github.com/shamoon) ([#14500](https://github.com/paperless-ngx/paperless-ngx/pull/14500))
- Enhancement: doc details ux improvements [@shamoon](https://github.com/shamoon) ([#14485](https://github.com/paperless-ngx/paperless-ngx/pull/14485))
- Enhancement (QoL): allow independently toggling child + parent tags in WF tag fields [@shamoon](https://github.com/shamoon) ([#14400](https://github.com/paperless-ngx/paperless-ngx/pull/14400))
- Tweak: drop the user dropdown caret [@shamoon](https://github.com/shamoon) ([#14444](https://github.com/paperless-ngx/paperless-ngx/pull/14444))
- Enhancement: navbar upload button [@shamoon](https://github.com/shamoon) ([#14442](https://github.com/paperless-ngx/paperless-ngx/pull/14442))
- Enhancement: AI chat UX tweaks [@shamoon](https://github.com/shamoon) ([#14415](https://github.com/paperless-ngx/paperless-ngx/pull/14415))
- Enhancement: support markdown in AI chat [@shamoon](https://github.com/shamoon) ([#14409](https://github.com/paperless-ngx/paperless-ngx/pull/14409))
### Bug Fixes
- Fix: truncate long version labels in dropdown [@shamoon](https://github.com/shamoon) ([#14578](https://github.com/paperless-ngx/paperless-ngx/pull/14578))
- Fixhancement: show better result for revoked / expired tasks [@shamoon](https://github.com/shamoon) ([#14566](https://github.com/paperless-ngx/paperless-ngx/pull/14566))
- Fix: move re-index after workflow runs on doc edit [@shamoon](https://github.com/shamoon) ([#14558](https://github.com/paperless-ngx/paperless-ngx/pull/14558))
- Fix: folder export with --delete fails on a stale manifest.json.tmp [@benpetty](https://github.com/benpetty) ([#14526](https://github.com/paperless-ngx/paperless-ngx/pull/14526))
- Fix: fix list type for api schema document object filters [@shamoon](https://github.com/shamoon) ([#14524](https://github.com/paperless-ngx/paperless-ngx/pull/14524))
- Fix: standardize some dropdown sizing [@shamoon](https://github.com/shamoon) ([#14510](https://github.com/paperless-ngx/paperless-ngx/pull/14510))
- Fix: prevent doc permissions queries on schema view [@shamoon](https://github.com/shamoon) ([#14503](https://github.com/paperless-ngx/paperless-ngx/pull/14503))
- Fix: dont defer tag assignment when barcode will not result in a split [@shamoon](https://github.com/shamoon) ([#14497](https://github.com/paperless-ngx/paperless-ngx/pull/14497))
### Dependencies
<details>
<summary>6 changes</summary>
- Chore: bump some frontend deps for security fixes [@shamoon](https://github.com/shamoon) ([#14581](https://github.com/paperless-ngx/paperless-ngx/pull/14581))
- Chore: bump brotli, djangorestframework, filelock, msgpack, setuptools for security fixes [@stumpylog](https://github.com/stumpylog) ([#14575](https://github.com/paperless-ngx/paperless-ngx/pull/14575))
- Chore: bump django-allauth to 65.20 and oauthlib to 4.0 [@stumpylog](https://github.com/stumpylog) ([#14570](https://github.com/paperless-ngx/paperless-ngx/pull/14570))
- Chore(deps): Bump the uv group across 1 directory with 2 updates @[dependabot[bot]](https://github.com/apps/dependabot) ([#14517](https://github.com/paperless-ngx/paperless-ngx/pull/14517))
- Chore(deps): Bump the uv group across 1 directory with 2 updates @[dependabot[bot]](https://github.com/apps/dependabot) ([#14493](https://github.com/paperless-ngx/paperless-ngx/pull/14493))
- Chore: Drop ImageMagik as a dependency [@stumpylog](https://github.com/stumpylog) ([#14440](https://github.com/paperless-ngx/paperless-ngx/pull/14440))
</details>
### All App Changes
<details>
<summary>35 changes</summary>
- Chore: Consolidate test sample files [@stumpylog](https://github.com/stumpylog) ([#14430](https://github.com/paperless-ngx/paperless-ngx/pull/14430))
- Chore: bump some frontend deps for security fixes [@shamoon](https://github.com/shamoon) ([#14581](https://github.com/paperless-ngx/paperless-ngx/pull/14581))
- Enhancement: support custom fields in workflow title templates [@shamoon](https://github.com/shamoon) ([#14564](https://github.com/paperless-ngx/paperless-ngx/pull/14564))
- Enhancement: relative date custom field queries [@shamoon](https://github.com/shamoon) ([#14549](https://github.com/paperless-ngx/paperless-ngx/pull/14549))
- Fix: truncate long version labels in dropdown [@shamoon](https://github.com/shamoon) ([#14578](https://github.com/paperless-ngx/paperless-ngx/pull/14578))
- Chore: bump brotli, djangorestframework, filelock, msgpack, setuptools for security fixes [@stumpylog](https://github.com/stumpylog) ([#14575](https://github.com/paperless-ngx/paperless-ngx/pull/14575))
- Chore: bump django-allauth to 65.20 and oauthlib to 4.0 [@stumpylog](https://github.com/stumpylog) ([#14570](https://github.com/paperless-ngx/paperless-ngx/pull/14570))
- Fixhancement: show better result for revoked / expired tasks [@shamoon](https://github.com/shamoon) ([#14566](https://github.com/paperless-ngx/paperless-ngx/pull/14566))
- Fix: move re-index after workflow runs on doc edit [@shamoon](https://github.com/shamoon) ([#14558](https://github.com/paperless-ngx/paperless-ngx/pull/14558))
- Performance: reduce tasks badge load times [@JanKleine](https://github.com/JanKleine) ([#14552](https://github.com/paperless-ngx/paperless-ngx/pull/14552))
- Enhancement: skip local 2FA for trusted OIDC AMR [@shamoon](https://github.com/shamoon) ([#14403](https://github.com/paperless-ngx/paperless-ngx/pull/14403))
- Chore: consolidate direct permission grant lookups into one helper [@stumpylog](https://github.com/stumpylog) ([#14456](https://github.com/paperless-ngx/paperless-ngx/pull/14456))
- Chore: drop get\_groups\_with\_only\_permission [@stumpylog](https://github.com/stumpylog) ([#14454](https://github.com/paperless-ngx/paperless-ngx/pull/14454))
- Chore: Consolidate to a single way to set permission on an object [@stumpylog](https://github.com/stumpylog) ([#14453](https://github.com/paperless-ngx/paperless-ngx/pull/14453))
- Chore: Refactor bulk edit to remove PDF knowledge [@stumpylog](https://github.com/stumpylog) ([#14445](https://github.com/paperless-ngx/paperless-ngx/pull/14445))
- Fix: folder export with --delete fails on a stale manifest.json.tmp [@benpetty](https://github.com/benpetty) ([#14526](https://github.com/paperless-ngx/paperless-ngx/pull/14526))
- Chore(deps): Bump the uv group across 1 directory with 2 updates @[dependabot[bot]](https://github.com/apps/dependabot) ([#14517](https://github.com/paperless-ngx/paperless-ngx/pull/14517))
- Fix: fix list type for api schema document object filters [@shamoon](https://github.com/shamoon) ([#14524](https://github.com/paperless-ngx/paperless-ngx/pull/14524))
- Chore(deps): Bump the uv group across 1 directory with 2 updates @[dependabot[bot]](https://github.com/apps/dependabot) ([#14493](https://github.com/paperless-ngx/paperless-ngx/pull/14493))
- Chore: drop get\_objects\_for\_user\_owner\_aware [@stumpylog](https://github.com/stumpylog) ([#14457](https://github.com/paperless-ngx/paperless-ngx/pull/14457))
- Chore: update Angular components to 22.2.2 [@shamoon](https://github.com/shamoon) ([#14515](https://github.com/paperless-ngx/paperless-ngx/pull/14515))
- Chore: share one base class for the method-mapped permission classes [@stumpylog](https://github.com/stumpylog) ([#14458](https://github.com/paperless-ngx/paperless-ngx/pull/14458))
- Fix: standardize some dropdown sizing [@shamoon](https://github.com/shamoon) ([#14510](https://github.com/paperless-ngx/paperless-ngx/pull/14510))
- Chore: Drop ImageMagik as a dependency [@stumpylog](https://github.com/stumpylog) ([#14440](https://github.com/paperless-ngx/paperless-ngx/pull/14440))
- Feature: Generate PDF thumbnails via poppler utils [@stumpylog](https://github.com/stumpylog) ([#14420](https://github.com/paperless-ngx/paperless-ngx/pull/14420))
- Fix: prevent doc permissions queries on schema view [@shamoon](https://github.com/shamoon) ([#14503](https://github.com/paperless-ngx/paperless-ngx/pull/14503))
- Enhancement: add upload count to button, link to tray, reduce notifications [@shamoon](https://github.com/shamoon) ([#14501](https://github.com/paperless-ngx/paperless-ngx/pull/14501))
- Enhancement: notifications improvements [@shamoon](https://github.com/shamoon) ([#14500](https://github.com/paperless-ngx/paperless-ngx/pull/14500))
- Enhancement: doc details ux improvements [@shamoon](https://github.com/shamoon) ([#14485](https://github.com/paperless-ngx/paperless-ngx/pull/14485))
- Enhancement (QoL): allow independently toggling child + parent tags in WF tag fields [@shamoon](https://github.com/shamoon) ([#14400](https://github.com/paperless-ngx/paperless-ngx/pull/14400))
- Tweak: drop the user dropdown caret [@shamoon](https://github.com/shamoon) ([#14444](https://github.com/paperless-ngx/paperless-ngx/pull/14444))
- Enhancement: navbar upload button [@shamoon](https://github.com/shamoon) ([#14442](https://github.com/paperless-ngx/paperless-ngx/pull/14442))
- Enhancement: AI chat UX tweaks [@shamoon](https://github.com/shamoon) ([#14415](https://github.com/paperless-ngx/paperless-ngx/pull/14415))
- Enhancement: support markdown in AI chat [@shamoon](https://github.com/shamoon) ([#14409](https://github.com/paperless-ngx/paperless-ngx/pull/14409))
- Fix: dont defer tag assignment when barcode will not result in a split [@shamoon](https://github.com/shamoon) ([#14497](https://github.com/paperless-ngx/paperless-ngx/pull/14497))
</details>
## paperless-ngx 3.3.4 ## paperless-ngx 3.3.4
### All App Changes ### All App Changes
+3 -3
View File
@@ -1,6 +1,6 @@
[project] [project]
name = "paperless-ngx" name = "paperless-ngx"
version = "3.4.0" version = "3.3.4"
description = """\ description = """\
A community-supported supercharged document management system: scan, index and archive all your physical documents\ A community-supported supercharged document management system: scan, index and archive all your physical documents\
""" """
@@ -256,8 +256,8 @@ isort.force-single-line = true
[tool.codespell] [tool.codespell]
ignore-words-list = "criterias,afterall,valeu,ureue,equest,ure,assertIn,Oktober,commitish,NIN,nin,reprot" ignore-words-list = "criterias,afterall,valeu,ureue,equest,ure,assertIn,Oktober,commitish,NIN,nin,reprot"
skip = """\ skip = """\
src-ui/src/locale/*,src-ui/pnpm-lock.yaml,src-ui/e2e/*,src/paperless/tests/samples/mail/*,src/documents/tests/samples\ src-ui/src/locale/*,src-ui/pnpm-lock.yaml,src-ui/e2e/*,src/paperless_mail/tests/samples/*,src/paperless/tests/samples\
/*,src/paperless_testing/sample_files/*,*.po,*.json\ /mail/*,src/documents/tests/samples/*,*.po,*.json\
""" """
write-changes = true write-changes = true
+1 -3
View File
@@ -134,9 +134,7 @@ def seed_database() -> None:
originals.mkdir(parents=True) originals.mkdir(parents=True)
thumbnails = Path(os.environ["PAPERLESS_MEDIA_ROOT"]) / "documents" / "thumbnails" thumbnails = Path(os.environ["PAPERLESS_MEDIA_ROOT"]) / "documents" / "thumbnails"
thumbnails.mkdir(parents=True) thumbnails.mkdir(parents=True)
sample_pdf = ( sample_pdf = SOURCE_ROOT / "documents" / "tests" / "samples" / "simple.pdf"
SOURCE_ROOT / "paperless_testing" / "sample_files" / "simple-digital.pdf"
)
for document in documents: for document in documents:
shutil.copyfile(sample_pdf, originals / document.filename) shutil.copyfile(sample_pdf, originals / document.filename)
shutil.copyfile( shutil.copyfile(
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "paperless-ngx-ui", "name": "paperless-ngx-ui",
"version": "3.4.0", "version": "3.3.4",
"scripts": { "scripts": {
"preinstall": "npx only-allow pnpm", "preinstall": "npx only-allow pnpm",
"ng": "ng", "ng": "ng",
+35 -228
View File
@@ -4,10 +4,6 @@ settings:
autoInstallPeers: false autoInstallPeers: false
excludeLinksFromLockfile: false excludeLinksFromLockfile: false
overrides:
vite@>=8.3.0 <8.3.3: ^8.3.3
zod@<4.6.6: ^4.6.6
importers: importers:
.: .:
@@ -1654,9 +1650,6 @@ packages:
'@oxc-project/types@0.150.0': '@oxc-project/types@0.150.0':
resolution: {integrity: sha512-rDS5/31E9HfPl/CIzGrn0DOlvBbXFseQ5URJ9sYMfstbKLD/c6Gm9vmRzRGDdAXyOIL4zmO37lc9RIwYqVruZw==} resolution: {integrity: sha512-rDS5/31E9HfPl/CIzGrn0DOlvBbXFseQ5URJ9sYMfstbKLD/c6Gm9vmRzRGDdAXyOIL4zmO37lc9RIwYqVruZw==}
'@oxc-project/types@0.155.0':
resolution: {integrity: sha512-SeE8JPwW1xs1tHeNycjUtUBdhorRa8o4jlvjwk49R7/Z291i+4DQa7JJIgOm/TaYQZx+QrPQbVJ/9c8dMIZN8Q==}
'@parcel/watcher-android-arm64@2.6.0': '@parcel/watcher-android-arm64@2.6.0':
resolution: {integrity: sha512-trgpLSCKRC/huFjXX/Smh+0sWe4+YtKfktIToiMl59ghz7z+qkH6kMvNnUbLyRs9N11t8l4svSCs1+5B3rOAhA==} resolution: {integrity: sha512-trgpLSCKRC/huFjXX/Smh+0sWe4+YtKfktIToiMl59ghz7z+qkH6kMvNnUbLyRs9N11t8l4svSCs1+5B3rOAhA==}
engines: {node: '>= 10.0.0'} engines: {node: '>= 10.0.0'}
@@ -1755,85 +1748,42 @@ packages:
'@popperjs/core@2.11.8': '@popperjs/core@2.11.8':
resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==} resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==}
'@rolldown/binding-android-arm-eabi@1.2.15':
resolution: {integrity: sha512-aLcgK9gIJ3YRvrrtfSBbRa27F5WrpiTaPulnFpsHPxpUHgFlSgnU4854MHwoRGEBhfRJDWCS2WQ7lIjskE9Olw==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm]
os: [android]
'@rolldown/binding-android-arm-eabi@1.2.8': '@rolldown/binding-android-arm-eabi@1.2.8':
resolution: {integrity: sha512-tN5aztYkKCte4i5SIrrz5yK/HMjEuCqCSCJa418jOV8tZ1cBY3YF2otxB1ktPxzsLA1BeTqwapK0bfjxNvHJVw==} resolution: {integrity: sha512-tN5aztYkKCte4i5SIrrz5yK/HMjEuCqCSCJa418jOV8tZ1cBY3YF2otxB1ktPxzsLA1BeTqwapK0bfjxNvHJVw==}
engines: {node: ^20.19.0 || >=22.12.0} engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm] cpu: [arm]
os: [android] os: [android]
'@rolldown/binding-android-arm64@1.2.15':
resolution: {integrity: sha512-xD7DdZCrbThKuxNg7ooQmvp07ys4J/pnSEMTG3/OdOWl6daC67m/Q4fL78sRHMxTH/N4fGUbYhcPM0MF5WFHkg==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [android]
'@rolldown/binding-android-arm64@1.2.8': '@rolldown/binding-android-arm64@1.2.8':
resolution: {integrity: sha512-dIYTWl9XprMUiQFoc55KUyk/oS8SKYH3zFl0LTR7RT0Xj4hgSVyuJcroH8JUu8RcpF8fTB6E0aOwCkZoYPcDSQ==} resolution: {integrity: sha512-dIYTWl9XprMUiQFoc55KUyk/oS8SKYH3zFl0LTR7RT0Xj4hgSVyuJcroH8JUu8RcpF8fTB6E0aOwCkZoYPcDSQ==}
engines: {node: ^20.19.0 || >=22.12.0} engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64] cpu: [arm64]
os: [android] os: [android]
'@rolldown/binding-darwin-arm64@1.2.15':
resolution: {integrity: sha512-m2WuQ6r0B4OTYxyPpNLtXaMRbRDUbG8YQV2Q3KTdSSK8Th6KHCnC8jVCJt8bvYeSB5WivkkNbc85mKadaSdOxA==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [darwin]
'@rolldown/binding-darwin-arm64@1.2.8': '@rolldown/binding-darwin-arm64@1.2.8':
resolution: {integrity: sha512-PCSDQGXD2IyTEFrcgPyBM8jJuGmrbCMuoIOXdbEGVemruKACXoLQJrb+A45Z0L5t1RQkdfJprAYPkikbh7dzdA==} resolution: {integrity: sha512-PCSDQGXD2IyTEFrcgPyBM8jJuGmrbCMuoIOXdbEGVemruKACXoLQJrb+A45Z0L5t1RQkdfJprAYPkikbh7dzdA==}
engines: {node: ^20.19.0 || >=22.12.0} engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64] cpu: [arm64]
os: [darwin] os: [darwin]
'@rolldown/binding-darwin-x64@1.2.15':
resolution: {integrity: sha512-5RtnsHM36nodM9WbMy+zip0LGS/G+y5wro5RHrpOlr4ac24+1zSi9kiV2MP1myZeZ/ifEHfulQcWjnAXzc2C2A==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64]
os: [darwin]
'@rolldown/binding-darwin-x64@1.2.8': '@rolldown/binding-darwin-x64@1.2.8':
resolution: {integrity: sha512-Uk7lRsGhPFHVX/sAUC6D5H9Ol30dFHd6iquokll2th3LpdJ3F5CzQB+7DHn0Ri2mG+U7k2zXiPHDrwZenXhwSA==} resolution: {integrity: sha512-Uk7lRsGhPFHVX/sAUC6D5H9Ol30dFHd6iquokll2th3LpdJ3F5CzQB+7DHn0Ri2mG+U7k2zXiPHDrwZenXhwSA==}
engines: {node: ^20.19.0 || >=22.12.0} engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64] cpu: [x64]
os: [darwin] os: [darwin]
'@rolldown/binding-freebsd-x64@1.2.15':
resolution: {integrity: sha512-g3l09pyFqhu+135JKkbkwiKGQmwU5hUMUPJ4VdBADvuqR8d33L6H578rh8m7rtxbdp+VmX/+nzI7nvhSZlzpUQ==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64]
os: [freebsd]
'@rolldown/binding-freebsd-x64@1.2.8': '@rolldown/binding-freebsd-x64@1.2.8':
resolution: {integrity: sha512-DjszaTEVogPqA5bYzsEeqDCQxbcp2fexQwKcRspYji2yzR68fCf+e4fx6kBSRDwX5/brZaHw/hWS9+A/+/w9sQ==} resolution: {integrity: sha512-DjszaTEVogPqA5bYzsEeqDCQxbcp2fexQwKcRspYji2yzR68fCf+e4fx6kBSRDwX5/brZaHw/hWS9+A/+/w9sQ==}
engines: {node: ^20.19.0 || >=22.12.0} engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64] cpu: [x64]
os: [freebsd] os: [freebsd]
'@rolldown/binding-linux-arm-gnueabihf@1.2.15':
resolution: {integrity: sha512-nIe3VugI97nGQtspPxDqA4sXMUpeiocKIP/CqpY/u/vgbT+alX+cVxu1C/oVBPKg4feNTmYovE91v4DgXvXNwQ==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm]
os: [linux]
'@rolldown/binding-linux-arm-gnueabihf@1.2.8': '@rolldown/binding-linux-arm-gnueabihf@1.2.8':
resolution: {integrity: sha512-zmwa7FTmdzB6aaEEuuls18H6Ap5JmJPSoPTuXixeJZV6tG40SyLkApQtz1g8ptZtiEKqj9OM0oNLPh1AgvE31Q==} resolution: {integrity: sha512-zmwa7FTmdzB6aaEEuuls18H6Ap5JmJPSoPTuXixeJZV6tG40SyLkApQtz1g8ptZtiEKqj9OM0oNLPh1AgvE31Q==}
engines: {node: ^20.19.0 || >=22.12.0} engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm] cpu: [arm]
os: [linux] os: [linux]
'@rolldown/binding-linux-arm64-gnu@1.2.15':
resolution: {integrity: sha512-iTBjXx+B5QSvgI89lJfmqh4wTh8NabR1YZIIN3hNx4zSG0EVfVqkOvLulNpG4251pbd6/IAmZ/LefVk1Y4rPhw==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [linux]
libc: [glibc]
'@rolldown/binding-linux-arm64-gnu@1.2.8': '@rolldown/binding-linux-arm64-gnu@1.2.8':
resolution: {integrity: sha512-KdYQDPHwJVnbFwdTGMgxsI9SqblBlz6STGM+w1We/d5B8OWWidYH0MwkU/uA1wM5fIpO2MkOVxXrNzzuZhw9ew==} resolution: {integrity: sha512-KdYQDPHwJVnbFwdTGMgxsI9SqblBlz6STGM+w1We/d5B8OWWidYH0MwkU/uA1wM5fIpO2MkOVxXrNzzuZhw9ew==}
engines: {node: ^20.19.0 || >=22.12.0} engines: {node: ^20.19.0 || >=22.12.0}
@@ -1841,13 +1791,6 @@ packages:
os: [linux] os: [linux]
libc: [glibc] libc: [glibc]
'@rolldown/binding-linux-arm64-musl@1.2.15':
resolution: {integrity: sha512-uN26XOnVR7rqQupG3V9oAG2EGGatWjcJHOeDOHUFCh4TBWmP2tHTFoVN13aYbwfm0aHqJAEmcwhAu6sooIjfqQ==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [linux]
libc: [musl]
'@rolldown/binding-linux-arm64-musl@1.2.8': '@rolldown/binding-linux-arm64-musl@1.2.8':
resolution: {integrity: sha512-jFJTifHnNPY+yzOoNZQfSIysrVyXzEQPhPnOUjmD1bcQGHH6s7c8cViKWar8YplQImE5N9JRqMCLrM2CdxOrZA==} resolution: {integrity: sha512-jFJTifHnNPY+yzOoNZQfSIysrVyXzEQPhPnOUjmD1bcQGHH6s7c8cViKWar8YplQImE5N9JRqMCLrM2CdxOrZA==}
engines: {node: ^20.19.0 || >=22.12.0} engines: {node: ^20.19.0 || >=22.12.0}
@@ -1855,13 +1798,6 @@ packages:
os: [linux] os: [linux]
libc: [musl] libc: [musl]
'@rolldown/binding-linux-ppc64-gnu@1.2.15':
resolution: {integrity: sha512-9nWkcdd+H+XhaA3fQIwpHnKIrfx/PQ6rO0pivr78Og07tXlUlctBBJoEYLPfhTmCR/QxEVdn6uPjHV5SymPhdw==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [ppc64]
os: [linux]
libc: [glibc]
'@rolldown/binding-linux-ppc64-gnu@1.2.8': '@rolldown/binding-linux-ppc64-gnu@1.2.8':
resolution: {integrity: sha512-FhiOziBDWPBjbcmRzfLyIJnaP7AVMFXT7YCXPjXxj7wKU3vx24RjrCNN/zjvVa+N2vVoHJwCoUBvsrN/DG3zIA==} resolution: {integrity: sha512-FhiOziBDWPBjbcmRzfLyIJnaP7AVMFXT7YCXPjXxj7wKU3vx24RjrCNN/zjvVa+N2vVoHJwCoUBvsrN/DG3zIA==}
engines: {node: ^20.19.0 || >=22.12.0} engines: {node: ^20.19.0 || >=22.12.0}
@@ -1869,13 +1805,6 @@ packages:
os: [linux] os: [linux]
libc: [glibc] libc: [glibc]
'@rolldown/binding-linux-s390x-gnu@1.2.15':
resolution: {integrity: sha512-Ggh0ciFjLwIusLSLz7LZYEaGdxOAUJXI+Qu5JCbhPJJHEt8vP+IjRATTJheiJsdzzTYgUiHUiw3X1Ea3ZpMBdA==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [s390x]
os: [linux]
libc: [glibc]
'@rolldown/binding-linux-s390x-gnu@1.2.8': '@rolldown/binding-linux-s390x-gnu@1.2.8':
resolution: {integrity: sha512-WnHfADMzOV2Y55wlx1hzzQnar/wDt/VdvWSD99r18Mz9ylNieIGOkRx3UV21h7m/eJvjySYJkO26VvGNFkwsIQ==} resolution: {integrity: sha512-WnHfADMzOV2Y55wlx1hzzQnar/wDt/VdvWSD99r18Mz9ylNieIGOkRx3UV21h7m/eJvjySYJkO26VvGNFkwsIQ==}
engines: {node: ^20.19.0 || >=22.12.0} engines: {node: ^20.19.0 || >=22.12.0}
@@ -1883,13 +1812,6 @@ packages:
os: [linux] os: [linux]
libc: [glibc] libc: [glibc]
'@rolldown/binding-linux-x64-gnu@1.2.15':
resolution: {integrity: sha512-FHg60rS6DBePAYZ9X9F67x+JObFdmgn6tupA1C/a3B+CufFmTD4mX+e8M75tCiAO3foR/6xwVBI0KQiI7sn/rw==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64]
os: [linux]
libc: [glibc]
'@rolldown/binding-linux-x64-gnu@1.2.8': '@rolldown/binding-linux-x64-gnu@1.2.8':
resolution: {integrity: sha512-H9tRr5ibfXFVLxbPOseVewewFpl28zcEdjRDt2FTUZU7odxP0gEv1ki4/kGmcGOh78oRwZuuQllGLZ9zTJp84g==} resolution: {integrity: sha512-H9tRr5ibfXFVLxbPOseVewewFpl28zcEdjRDt2FTUZU7odxP0gEv1ki4/kGmcGOh78oRwZuuQllGLZ9zTJp84g==}
engines: {node: ^20.19.0 || >=22.12.0} engines: {node: ^20.19.0 || >=22.12.0}
@@ -1897,13 +1819,6 @@ packages:
os: [linux] os: [linux]
libc: [glibc] libc: [glibc]
'@rolldown/binding-linux-x64-musl@1.2.15':
resolution: {integrity: sha512-/cvV/7v5VGz/moiz0XKRj2dE8DzsKyhIu1KpOvJGPjRywg3yscON889UGvAe8zfiJLHup7VLjBduoGWi3HusWQ==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64]
os: [linux]
libc: [musl]
'@rolldown/binding-linux-x64-musl@1.2.8': '@rolldown/binding-linux-x64-musl@1.2.8':
resolution: {integrity: sha512-UefiqfM3D6IVNlZ8tSGs9+Ejjud2T+oxO0IHADU45Y+lyEjD2dVFyZHbkfX0LUb5Zugo/oIv1eCO/KVYhgYJYA==} resolution: {integrity: sha512-UefiqfM3D6IVNlZ8tSGs9+Ejjud2T+oxO0IHADU45Y+lyEjD2dVFyZHbkfX0LUb5Zugo/oIv1eCO/KVYhgYJYA==}
engines: {node: ^20.19.0 || >=22.12.0} engines: {node: ^20.19.0 || >=22.12.0}
@@ -1911,36 +1826,18 @@ packages:
os: [linux] os: [linux]
libc: [musl] libc: [musl]
'@rolldown/binding-openharmony-arm64@1.2.15':
resolution: {integrity: sha512-MyzC5Hrv/sm+Z7TSGKP/j8001RO2xQm1zOpCNVL4j0cY/VhBZviludA2YFQ7i4lH6ZAXxQm0lcMdBzM+99mE7w==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [openharmony]
'@rolldown/binding-openharmony-arm64@1.2.8': '@rolldown/binding-openharmony-arm64@1.2.8':
resolution: {integrity: sha512-637Ke4kWSy6rp9cxQ9gMOXlxPgIw/c1beASV4M//3+9I4uwBVOOl74G+e3zyU3u19U7RkRl/HuewixZ/Z6+Rjg==} resolution: {integrity: sha512-637Ke4kWSy6rp9cxQ9gMOXlxPgIw/c1beASV4M//3+9I4uwBVOOl74G+e3zyU3u19U7RkRl/HuewixZ/Z6+Rjg==}
engines: {node: ^20.19.0 || >=22.12.0} engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64] cpu: [arm64]
os: [openharmony] os: [openharmony]
'@rolldown/binding-win32-arm64-msvc@1.2.15':
resolution: {integrity: sha512-+PgYiS+AH5omy6L45ZLxybasauJaj3M8buoT83D+nzPmCayXlxUV9hydhciCKVyIg0B/v0BtXPDE1uGqNwCPpg==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [win32]
'@rolldown/binding-win32-arm64-msvc@1.2.8': '@rolldown/binding-win32-arm64-msvc@1.2.8':
resolution: {integrity: sha512-xWBkPOF1Q9k/Gv1nQXnVdLxKu74jXppuOM4Z3mnypVUJJJwLsMl7hNJGRAUJoG8A5MgOI1ACKM+wBFxSJzKy4A==} resolution: {integrity: sha512-xWBkPOF1Q9k/Gv1nQXnVdLxKu74jXppuOM4Z3mnypVUJJJwLsMl7hNJGRAUJoG8A5MgOI1ACKM+wBFxSJzKy4A==}
engines: {node: ^20.19.0 || >=22.12.0} engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64] cpu: [arm64]
os: [win32] os: [win32]
'@rolldown/binding-win32-x64-msvc@1.2.15':
resolution: {integrity: sha512-HFZd2QNQYn1JbIi+Hpd7H+r/lkWxcfIu28nirZ6eCn2LafuvmExMlb/P96Sfx5tf7pPArw39IdhmCF8vmV+NhQ==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64]
os: [win32]
'@rolldown/binding-win32-x64-msvc@1.2.8': '@rolldown/binding-win32-x64-msvc@1.2.8':
resolution: {integrity: sha512-uz2ZvfgXbxqNwijjjbxrnvALwpyODDcgc1T1N8N3rf/DXKQmaFwmB4LX4yyjggpwN2obdQLb2rgirX5ffCWYng==} resolution: {integrity: sha512-uz2ZvfgXbxqNwijjjbxrnvALwpyODDcgc1T1N8N3rf/DXKQmaFwmB4LX4yyjggpwN2obdQLb2rgirX5ffCWYng==}
engines: {node: ^20.19.0 || >=22.12.0} engines: {node: ^20.19.0 || >=22.12.0}
@@ -2235,7 +2132,7 @@ packages:
resolution: {integrity: sha512-bdyo8rB3NnQbikdMpHaML9Z1OZPBu6fFOBo+OtxsBlvMJtysWskmBcnbIDhUqgC8tcxNv/a+BcV5U+2nQMm1OQ==} resolution: {integrity: sha512-bdyo8rB3NnQbikdMpHaML9Z1OZPBu6fFOBo+OtxsBlvMJtysWskmBcnbIDhUqgC8tcxNv/a+BcV5U+2nQMm1OQ==}
engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
peerDependencies: peerDependencies:
vite: ^8.3.3 vite: ^6.0.0 || ^7.0.0 || ^8.0.0
acorn-jsx@5.3.2: acorn-jsx@5.3.2:
resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
@@ -2364,8 +2261,8 @@ packages:
peerDependencies: peerDependencies:
'@popperjs/core': ^2.11.8 '@popperjs/core': ^2.11.8
brace-expansion@2.1.7: brace-expansion@2.1.4:
resolution: {integrity: sha512-uZbew1NqdmPDTMJ8ah1y+b+9QEJrfkXFk3RcTQw3X0jW/xRUvFKsg1CfQdSYGdTbXZWExtU3J3ccxtnfw1Fi0g==} resolution: {integrity: sha512-hGfVzPxthbf3+2yjg/RBs60cB0FhqBS/zvdV/4wn4/BmN0bNMMHPc4V/BbFieqf1TKAGGAHnY4eSjajCl0f2Xg==}
brace-expansion@5.0.12: brace-expansion@5.0.12:
resolution: {integrity: sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==} resolution: {integrity: sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==}
@@ -2700,8 +2597,8 @@ packages:
fast-string-width@3.0.2: fast-string-width@3.0.2:
resolution: {integrity: sha512-gX8LrtNEI5hq8DVUfRQMbr5lpaS4nMIWV+7XEbXk2b8kiQIizgnlr12B4dA3ZEx3308ze0O4Q1R+cHts8kyUJg==} resolution: {integrity: sha512-gX8LrtNEI5hq8DVUfRQMbr5lpaS4nMIWV+7XEbXk2b8kiQIizgnlr12B4dA3ZEx3308ze0O4Q1R+cHts8kyUJg==}
fast-uri@3.1.9: fast-uri@3.1.8:
resolution: {integrity: sha512-hS/0Wt3Ya043oKXs0sIxrMpKQITXhMLIrVAKKXi4gozGC9v7YRWVnXIZzjNPTO02M9BdxLCWqK1yRXgNziVyJQ==} resolution: {integrity: sha512-GZMtZUTNRpOVIECoXwLNZS5xUGE+mVNbTB8h/7Rwh2TFWcBQiPzTgyZi05BF9UMZKkLJv8XBRJTlU7zg8+ZfMg==}
fast-wrap-ansi@0.2.2: fast-wrap-ansi@0.2.2:
resolution: {integrity: sha512-7F2Fl+TjRSenLqlU3UjSH0iyqopqoZIu7eZVpEirP2g1GtWa2G/ecEmBdgz31+Mxr+ELclgg6sokpSFIQiZ02Q==} resolution: {integrity: sha512-7F2Fl+TjRSenLqlU3UjSH0iyqopqoZIu7eZVpEirP2g1GtWa2G/ecEmBdgz31+Mxr+ELclgg6sokpSFIQiZ02Q==}
@@ -3132,8 +3029,8 @@ packages:
js-tokens@4.0.0: js-tokens@4.0.0:
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
js-yaml@3.15.2: js-yaml@3.15.1:
resolution: {integrity: sha512-6EuL879VkRA+1Cz578mKMiKvjPNEuk6+r1JaFzoSWejZmtf7xWbIyw1e3KkxlkzTIt9Taw6JBhEppG7utc1P+w==} resolution: {integrity: sha512-S99WuO3HlhO3XN41EtYUNl9zzXjoJx7QvmipxsJVxtCBT0YHEFy+iOJhjSvrmV12nYhWpZaM8lPHkJm0yUMbag==}
hasBin: true hasBin: true
jsdom@26.1.0: jsdom@26.1.0:
@@ -3383,11 +3280,6 @@ packages:
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
hasBin: true hasBin: true
nanoid@3.3.20:
resolution: {integrity: sha512-uKdg2G3GNCKQn9byYOpxbGqrT2fGO5KRt5J/8b3pok8rT6qxGWF6hxMyJiEYtAf+FVyYuD9hRaDqX5uPFYJ4ZQ==}
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
hasBin: true
napi-postinstall@0.3.4: napi-postinstall@0.3.4:
resolution: {integrity: sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==} resolution: {integrity: sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==}
engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0}
@@ -3618,10 +3510,6 @@ packages:
resolution: {integrity: sha512-RRuzqDtt5Y9h3quz5hWhK+TPnsmVs6WwSU6LkJMeY4HstUEDuYTG8UJSdawMRzmzAtV+KEoG8N3Qg2qLy5vM/A==} resolution: {integrity: sha512-RRuzqDtt5Y9h3quz5hWhK+TPnsmVs6WwSU6LkJMeY4HstUEDuYTG8UJSdawMRzmzAtV+KEoG8N3Qg2qLy5vM/A==}
engines: {node: ^10 || ^12 || >=14} engines: {node: ^10 || ^12 || >=14}
postcss@8.5.31:
resolution: {integrity: sha512-YUbWYCgErwnMAVkjUnYa+KlMBzGpHwiIt/DE7f0G33AuX2LH9UcTk6KgWxd3zRU+pN3u/C+Xl3EnMLM4Hea7Sg==}
engines: {node: ^10 || ^12 || >=14}
prelude-ls@1.2.1: prelude-ls@1.2.1:
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
engines: {node: '>= 0.8.0'} engines: {node: '>= 0.8.0'}
@@ -3713,11 +3601,6 @@ packages:
resolution: {integrity: sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==} resolution: {integrity: sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==}
engines: {node: '>=18'} engines: {node: '>=18'}
rolldown@1.2.15:
resolution: {integrity: sha512-6odND+fel5zVw3I4Yc2e69gvguDnX0CAAGiNDZSq4ik5WUcaLrkD2GLuog0XcODbor31hZ5ayEMgVDno+KPV5g==}
engines: {node: ^20.19.0 || >=22.12.0}
hasBin: true
rolldown@1.2.8: rolldown@1.2.8:
resolution: {integrity: sha512-Z67nTmhZe7anqnM/EjI392w5i/ANUinjip7QYsOyN37oayduxt3ksdX0hf5OOamkAd53BiIHfbfSzfUmzKFQqQ==} resolution: {integrity: sha512-Z67nTmhZe7anqnM/EjI392w5i/ANUinjip7QYsOyN37oayduxt3ksdX0hf5OOamkAd53BiIHfbfSzfUmzKFQqQ==}
engines: {node: ^20.19.0 || >=22.12.0} engines: {node: ^20.19.0 || >=22.12.0}
@@ -3890,8 +3773,8 @@ packages:
resolution: {integrity: sha512-aBY19bn/XA+hKOKX0qL7Z0UfdBsbQvc9hn993U8ALUjzxCvDcuZqLoRXjGJrUARWAlwMnsRVD9sw2AFNOYvalA==} resolution: {integrity: sha512-aBY19bn/XA+hKOKX0qL7Z0UfdBsbQvc9hn993U8ALUjzxCvDcuZqLoRXjGJrUARWAlwMnsRVD9sw2AFNOYvalA==}
engines: {node: '>=22'} engines: {node: '>=22'}
source-map-js@1.2.2: source-map-js@1.2.1:
resolution: {integrity: sha512-KGj/8Y43x35aZVDtt+J4mK1hoLGHULMYfSkODJNQjNDC3oW1PqPoxMwo0pLUsWM/UEGzON/NxeHywEfNXNP3Vw==} resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
source-map-support@0.5.21: source-map-support@0.5.21:
@@ -4122,13 +4005,13 @@ packages:
resolution: {integrity: sha512-zj/ob3UsvJGN0whEAKFp53REA5X66hvffVqoCtVQAakJKnKlH+/PcOfMoFwIG/o4rElqLv/ycAFlx8ZlXUorCg==} resolution: {integrity: sha512-zj/ob3UsvJGN0whEAKFp53REA5X66hvffVqoCtVQAakJKnKlH+/PcOfMoFwIG/o4rElqLv/ycAFlx8ZlXUorCg==}
engines: {node: '>=18.12.0'} engines: {node: '>=18.12.0'}
vite@8.3.5: vite@8.3.0:
resolution: {integrity: sha512-z1YpjieJ9g0ebTmQpLBv/oq9E3F9EIlOe+7LahW8SrE3LTiG3udBRUXQOlYXP9b+IC2q2phHeVxj9xGlw34OEQ==} resolution: {integrity: sha512-lhZBVvEHefgE+HQZC9O7EBJgCU/nVzFNl7vkS4RE0APtWLP02/8QVIkQtzBxPquh7lq5/78NHipTj7ODQ6XuyQ==}
engines: {node: ^20.19.0 || >=22.12.0} engines: {node: ^20.19.0 || >=22.12.0}
hasBin: true hasBin: true
peerDependencies: peerDependencies:
'@types/node': ^20.19.0 || >=22.12.0 '@types/node': ^20.19.0 || >=22.12.0
'@vitejs/devtools': ^0.7.1 || ^0.8.0 '@vitejs/devtools': ^0.7.1
esbuild: ^0.27.0 || ^0.28.0 esbuild: ^0.27.0 || ^0.28.0
jiti: '>=1.21.0' jiti: '>=1.21.0'
less: ^4.0.0 less: ^4.0.0
@@ -4285,8 +4168,8 @@ packages:
resolution: {integrity: sha512-xYqdZFUK/VYazNl/oCDYN+3WloWQwMfZxBoiNt6qNyk+xfOdi598muWE42rNZFp1kNOiqW936q5RhUdnpqElSg==} resolution: {integrity: sha512-xYqdZFUK/VYazNl/oCDYN+3WloWQwMfZxBoiNt6qNyk+xfOdi598muWE42rNZFp1kNOiqW936q5RhUdnpqElSg==}
engines: {node: '>=18'} engines: {node: '>=18'}
zod@4.6.7: zod@4.6.5:
resolution: {integrity: sha512-g8W2D2kU6a8untc053fX1uVBKzM7yqAxW/3zwk83+6RyF2+SKOuV+c0wBDhUwzV1PaGapmZH+rmcUzPf+3CGwg==} resolution: {integrity: sha512-v5l/aFXZQeai4awLbOpSoHecE9UiMrnfx75tEXLjNonXVARxQ5mOeipTjROUchszUNCqnE+hqAMujRsRHsut2Q==}
snapshots: snapshots:
@@ -4486,7 +4369,7 @@ snapshots:
'@babel/core': 8.0.5 '@babel/core': 8.0.5
'@inquirer/confirm': 6.3.2(@types/node@26.6.2) '@inquirer/confirm': 6.3.2(@types/node@26.6.2)
'@parcel/watcher': 2.6.0 '@parcel/watcher': 2.6.0
'@vitejs/plugin-basic-ssl': 2.3.0(vite@8.3.5(@types/node@26.6.2)(esbuild@0.28.2)(jiti@2.7.0)(sass-embedded@1.104.1)(sass@1.104.1)) '@vitejs/plugin-basic-ssl': 2.3.0(vite@8.3.0(@types/node@26.6.2)(esbuild@0.28.2)(jiti@2.7.0)(sass-embedded@1.104.1)(sass@1.104.1))
beasties: 0.5.4 beasties: 0.5.4
browserslist: 4.29.1 browserslist: 4.29.1
chokidar: 5.0.0 chokidar: 5.0.0
@@ -4508,7 +4391,7 @@ snapshots:
tinyglobby: 0.2.17 tinyglobby: 0.2.17
tslib: 2.8.1 tslib: 2.8.1
typescript: 6.0.3 typescript: 6.0.3
vite: 8.3.5(@types/node@26.6.2)(esbuild@0.28.2)(jiti@2.7.0)(sass-embedded@1.104.1)(sass@1.104.1) vite: 8.3.0(@types/node@26.6.2)(esbuild@0.28.2)(jiti@2.7.0)(sass-embedded@1.104.1)(sass@1.104.1)
xxhash-wasm: 1.1.0 xxhash-wasm: 1.1.0
optionalDependencies: optionalDependencies:
'@angular/core': 22.2.2(@angular/compiler@22.2.2)(rxjs@7.8.2) '@angular/core': 22.2.2(@angular/compiler@22.2.2)(rxjs@7.8.2)
@@ -4554,7 +4437,7 @@ snapshots:
parse5-html-rewriting-stream: 8.0.1 parse5-html-rewriting-stream: 8.0.1
semver: 7.8.5 semver: 7.8.5
yargs: 18.1.0 yargs: 18.1.0
zod: 4.6.7 zod: 4.6.5
transitivePeerDependencies: transitivePeerDependencies:
- '@types/node' - '@types/node'
- chokidar - chokidar
@@ -4598,7 +4481,7 @@ snapshots:
'@standard-schema/spec': 1.1.0 '@standard-schema/spec': 1.1.0
rxjs: 7.8.2 rxjs: 7.8.2
tslib: 2.8.1 tslib: 2.8.1
zod: 4.6.7 zod: 4.6.5
'@angular/localize@22.2.2(@angular/compiler-cli@22.2.2(@angular/compiler@22.2.2)(typescript@6.0.3))(@angular/compiler@22.2.2)': '@angular/localize@22.2.2(@angular/compiler-cli@22.2.2(@angular/compiler@22.2.2)(typescript@6.0.3))(@angular/compiler@22.2.2)':
dependencies: dependencies:
@@ -5235,7 +5118,7 @@ snapshots:
camelcase: 5.3.1 camelcase: 5.3.1
find-up: 4.1.0 find-up: 4.1.0
get-package-type: 0.1.0 get-package-type: 0.1.0
js-yaml: 3.15.2 js-yaml: 3.15.1
resolve-from: 5.0.0 resolve-from: 5.0.0
'@istanbuljs/schema@0.1.6': {} '@istanbuljs/schema@0.1.6': {}
@@ -5529,12 +5412,12 @@ snapshots:
'@modelcontextprotocol/core@2.3.1': '@modelcontextprotocol/core@2.3.1':
dependencies: dependencies:
zod: 4.6.7 zod: 4.6.5
'@modelcontextprotocol/server@2.3.1': '@modelcontextprotocol/server@2.3.1':
dependencies: dependencies:
'@modelcontextprotocol/core': 2.3.1 '@modelcontextprotocol/core': 2.3.1
zod: 4.6.7 zod: 4.6.5
'@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.4': '@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.4':
optional: true optional: true
@@ -5769,8 +5652,6 @@ snapshots:
'@oxc-project/types@0.150.0': {} '@oxc-project/types@0.150.0': {}
'@oxc-project/types@0.155.0': {}
'@parcel/watcher-android-arm64@2.6.0': '@parcel/watcher-android-arm64@2.6.0':
optional: true optional: true
@@ -5838,93 +5719,48 @@ snapshots:
'@popperjs/core@2.11.8': {} '@popperjs/core@2.11.8': {}
'@rolldown/binding-android-arm-eabi@1.2.15':
optional: true
'@rolldown/binding-android-arm-eabi@1.2.8': '@rolldown/binding-android-arm-eabi@1.2.8':
optional: true optional: true
'@rolldown/binding-android-arm64@1.2.15':
optional: true
'@rolldown/binding-android-arm64@1.2.8': '@rolldown/binding-android-arm64@1.2.8':
optional: true optional: true
'@rolldown/binding-darwin-arm64@1.2.15':
optional: true
'@rolldown/binding-darwin-arm64@1.2.8': '@rolldown/binding-darwin-arm64@1.2.8':
optional: true optional: true
'@rolldown/binding-darwin-x64@1.2.15':
optional: true
'@rolldown/binding-darwin-x64@1.2.8': '@rolldown/binding-darwin-x64@1.2.8':
optional: true optional: true
'@rolldown/binding-freebsd-x64@1.2.15':
optional: true
'@rolldown/binding-freebsd-x64@1.2.8': '@rolldown/binding-freebsd-x64@1.2.8':
optional: true optional: true
'@rolldown/binding-linux-arm-gnueabihf@1.2.15':
optional: true
'@rolldown/binding-linux-arm-gnueabihf@1.2.8': '@rolldown/binding-linux-arm-gnueabihf@1.2.8':
optional: true optional: true
'@rolldown/binding-linux-arm64-gnu@1.2.15':
optional: true
'@rolldown/binding-linux-arm64-gnu@1.2.8': '@rolldown/binding-linux-arm64-gnu@1.2.8':
optional: true optional: true
'@rolldown/binding-linux-arm64-musl@1.2.15':
optional: true
'@rolldown/binding-linux-arm64-musl@1.2.8': '@rolldown/binding-linux-arm64-musl@1.2.8':
optional: true optional: true
'@rolldown/binding-linux-ppc64-gnu@1.2.15':
optional: true
'@rolldown/binding-linux-ppc64-gnu@1.2.8': '@rolldown/binding-linux-ppc64-gnu@1.2.8':
optional: true optional: true
'@rolldown/binding-linux-s390x-gnu@1.2.15':
optional: true
'@rolldown/binding-linux-s390x-gnu@1.2.8': '@rolldown/binding-linux-s390x-gnu@1.2.8':
optional: true optional: true
'@rolldown/binding-linux-x64-gnu@1.2.15':
optional: true
'@rolldown/binding-linux-x64-gnu@1.2.8': '@rolldown/binding-linux-x64-gnu@1.2.8':
optional: true optional: true
'@rolldown/binding-linux-x64-musl@1.2.15':
optional: true
'@rolldown/binding-linux-x64-musl@1.2.8': '@rolldown/binding-linux-x64-musl@1.2.8':
optional: true optional: true
'@rolldown/binding-openharmony-arm64@1.2.15':
optional: true
'@rolldown/binding-openharmony-arm64@1.2.8': '@rolldown/binding-openharmony-arm64@1.2.8':
optional: true optional: true
'@rolldown/binding-win32-arm64-msvc@1.2.15':
optional: true
'@rolldown/binding-win32-arm64-msvc@1.2.8': '@rolldown/binding-win32-arm64-msvc@1.2.8':
optional: true optional: true
'@rolldown/binding-win32-x64-msvc@1.2.15':
optional: true
'@rolldown/binding-win32-x64-msvc@1.2.8': '@rolldown/binding-win32-x64-msvc@1.2.8':
optional: true optional: true
@@ -6215,9 +6051,9 @@ snapshots:
'@unrs/resolver-binding-win32-x64-msvc@1.12.2': '@unrs/resolver-binding-win32-x64-msvc@1.12.2':
optional: true optional: true
'@vitejs/plugin-basic-ssl@2.3.0(vite@8.3.5(@types/node@26.6.2)(esbuild@0.28.2)(jiti@2.7.0)(sass-embedded@1.104.1)(sass@1.104.1))': '@vitejs/plugin-basic-ssl@2.3.0(vite@8.3.0(@types/node@26.6.2)(esbuild@0.28.2)(jiti@2.7.0)(sass-embedded@1.104.1)(sass@1.104.1))':
dependencies: dependencies:
vite: 8.3.5(@types/node@26.6.2)(esbuild@0.28.2)(jiti@2.7.0)(sass-embedded@1.104.1)(sass@1.104.1) vite: 8.3.0(@types/node@26.6.2)(esbuild@0.28.2)(jiti@2.7.0)(sass-embedded@1.104.1)(sass@1.104.1)
acorn-jsx@5.3.2(acorn@8.18.0): acorn-jsx@5.3.2(acorn@8.18.0):
dependencies: dependencies:
@@ -6247,7 +6083,7 @@ snapshots:
ajv@8.20.0: ajv@8.20.0:
dependencies: dependencies:
fast-deep-equal: 3.1.3 fast-deep-equal: 3.1.3
fast-uri: 3.1.9 fast-uri: 3.1.8
json-schema-traverse: 1.0.0 json-schema-traverse: 1.0.0
require-from-string: 2.0.2 require-from-string: 2.0.2
@@ -6362,7 +6198,7 @@ snapshots:
dependencies: dependencies:
'@popperjs/core': 2.11.8 '@popperjs/core': 2.11.8
brace-expansion@2.1.7: brace-expansion@2.1.4:
dependencies: dependencies:
balanced-match: 1.0.2 balanced-match: 1.0.2
@@ -6707,7 +6543,7 @@ snapshots:
dependencies: dependencies:
fast-string-truncated-width: 3.0.3 fast-string-truncated-width: 3.0.3
fast-uri@3.1.9: {} fast-uri@3.1.8: {}
fast-wrap-ansi@0.2.2: fast-wrap-ansi@0.2.2:
dependencies: dependencies:
@@ -7357,7 +7193,7 @@ snapshots:
js-tokens@4.0.0: {} js-tokens@4.0.0: {}
js-yaml@3.15.2: js-yaml@3.15.1:
dependencies: dependencies:
argparse: 1.0.10 argparse: 1.0.10
esprima: 4.0.1 esprima: 4.0.1
@@ -7557,7 +7393,7 @@ snapshots:
minimatch@9.0.9: minimatch@9.0.9:
dependencies: dependencies:
brace-expansion: 2.1.7 brace-expansion: 2.1.4
minimist@1.2.8: {} minimist@1.2.8: {}
@@ -7592,8 +7428,6 @@ snapshots:
nanoid@3.3.18: {} nanoid@3.3.18: {}
nanoid@3.3.20: {}
napi-postinstall@0.3.4: {} napi-postinstall@0.3.4: {}
natural-compare@1.4.0: {} natural-compare@1.4.0: {}
@@ -7840,13 +7674,7 @@ snapshots:
dependencies: dependencies:
nanoid: 3.3.18 nanoid: 3.3.18
picocolors: 1.1.1 picocolors: 1.1.1
source-map-js: 1.2.2 source-map-js: 1.2.1
postcss@8.5.31:
dependencies:
nanoid: 3.3.20
picocolors: 1.1.1
source-map-js: 1.2.2
prelude-ls@1.2.1: {} prelude-ls@1.2.1: {}
@@ -7914,27 +7742,6 @@ snapshots:
onetime: 7.0.0 onetime: 7.0.0
signal-exit: 4.1.0 signal-exit: 4.1.0
rolldown@1.2.15:
dependencies:
'@oxc-project/types': 0.155.0
'@rolldown/pluginutils': 1.0.1
optionalDependencies:
'@rolldown/binding-android-arm-eabi': 1.2.15
'@rolldown/binding-android-arm64': 1.2.15
'@rolldown/binding-darwin-arm64': 1.2.15
'@rolldown/binding-darwin-x64': 1.2.15
'@rolldown/binding-freebsd-x64': 1.2.15
'@rolldown/binding-linux-arm-gnueabihf': 1.2.15
'@rolldown/binding-linux-arm64-gnu': 1.2.15
'@rolldown/binding-linux-arm64-musl': 1.2.15
'@rolldown/binding-linux-ppc64-gnu': 1.2.15
'@rolldown/binding-linux-s390x-gnu': 1.2.15
'@rolldown/binding-linux-x64-gnu': 1.2.15
'@rolldown/binding-linux-x64-musl': 1.2.15
'@rolldown/binding-openharmony-arm64': 1.2.15
'@rolldown/binding-win32-arm64-msvc': 1.2.15
'@rolldown/binding-win32-x64-msvc': 1.2.15
rolldown@1.2.8: rolldown@1.2.8:
dependencies: dependencies:
'@oxc-project/types': 0.149.0 '@oxc-project/types': 0.149.0
@@ -8055,7 +7862,7 @@ snapshots:
dependencies: dependencies:
chokidar: 5.0.0 chokidar: 5.0.0
immutable: 5.1.9 immutable: 5.1.9
source-map-js: 1.2.2 source-map-js: 1.2.1
optionalDependencies: optionalDependencies:
'@parcel/watcher': 2.6.0 '@parcel/watcher': 2.6.0
@@ -8084,7 +7891,7 @@ snapshots:
ansi-styles: 6.2.3 ansi-styles: 6.2.3
is-fullwidth-code-point: 5.1.0 is-fullwidth-code-point: 5.1.0
source-map-js@1.2.2: {} source-map-js@1.2.1: {}
source-map-support@0.5.21: source-map-support@0.5.21:
dependencies: dependencies:
@@ -8311,12 +8118,12 @@ snapshots:
verkit@0.3.2: {} verkit@0.3.2: {}
vite@8.3.5(@types/node@26.6.2)(esbuild@0.28.2)(jiti@2.7.0)(sass-embedded@1.104.1)(sass@1.104.1): vite@8.3.0(@types/node@26.6.2)(esbuild@0.28.2)(jiti@2.7.0)(sass-embedded@1.104.1)(sass@1.104.1):
dependencies: dependencies:
lightningcss: 1.33.0 lightningcss: 1.33.0
picomatch: 4.0.7 picomatch: 4.0.7
postcss: 8.5.31 postcss: 8.5.28
rolldown: 1.2.15 rolldown: 1.2.8
tinyglobby: 0.2.17 tinyglobby: 0.2.17
optionalDependencies: optionalDependencies:
'@types/node': 26.6.2 '@types/node': 26.6.2
@@ -8434,4 +8241,4 @@ snapshots:
yoctocolors@2.2.0: {} yoctocolors@2.2.0: {}
zod@4.6.7: {} zod@4.6.5: {}
-3
View File
@@ -24,6 +24,3 @@ onlyBuiltDependencies:
ignoredBuiltDependencies: ignoredBuiltDependencies:
- normalize-diacritics - normalize-diacritics
- unrs-resolver - unrs-resolver
overrides:
"vite@>=8.3.0 <8.3.3": "^8.3.3"
"zod@<4.6.6": "^4.6.6"
+1 -1
View File
@@ -8,7 +8,7 @@ export const environment = {
apiVersion: '10', // match src/paperless/settings.py apiVersion: '10', // match src/paperless/settings.py
appTitle: DEFAULT_APP_TITLE, appTitle: DEFAULT_APP_TITLE,
tag: 'prod', tag: 'prod',
version: '3.4.0', version: '3.3.4',
webSocketHost: window.location.host, webSocketHost: window.location.host,
webSocketProtocol: window.location.protocol == 'https:' ? 'wss:' : 'ws:', webSocketProtocol: window.location.protocol == 'https:' ? 'wss:' : 'ws:',
webSocketBaseUrl: base_url.pathname + 'ws/', webSocketBaseUrl: base_url.pathname + 'ws/',
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
-38
View File
@@ -11,8 +11,6 @@ from typing import TYPE_CHECKING
import pytest import pytest
from paperless_testing import samples
if TYPE_CHECKING: if TYPE_CHECKING:
from collections.abc import Generator from collections.abc import Generator
from pathlib import Path from pathlib import Path
@@ -151,39 +149,3 @@ def fake_progress_manager(
monkeypatch.setattr("documents.tasks.ProgressManager", FakeProgressManager) monkeypatch.setattr("documents.tasks.ProgressManager", FakeProgressManager)
return FakeProgressManager return FakeProgressManager
@pytest.fixture(scope="session")
def shared_samples_dir() -> Path:
"""Directory of sample files used by more than one app's tests."""
return samples.SHARED_SAMPLES_DIR
@pytest.fixture(scope="session")
def simple_digital_pdf_file() -> Path:
"""One-page PDF with a text layer."""
return samples.SIMPLE_DIGITAL_PDF
@pytest.fixture(scope="session")
def multi_page_digital_pdf_file() -> Path:
"""Three-page PDF with a text layer."""
return samples.MULTI_PAGE_DIGITAL_PDF
@pytest.fixture(scope="session")
def with_form_pdf_file() -> Path:
"""PDF containing a fillable form."""
return samples.WITH_FORM_PDF
@pytest.fixture(scope="session")
def multi_page_images_pdf_file() -> Path:
"""Multi-page PDF of scanned images, no text layer."""
return samples.MULTI_PAGE_IMAGES_PDF
@pytest.fixture(scope="session")
def thumbnail_webp_file() -> Path:
"""Small WebP thumbnail."""
return samples.THUMBNAIL_WEBP
+6 -3
View File
@@ -576,9 +576,12 @@ def annotate_document_count_by_ids(
or CustomFieldInstance) or CustomFieldInstance)
related_object_field: field on the relation pointing back to queryset pk related_object_field: field on the relation pointing back to queryset pk
document_ids: the document ids to count against -- a concrete list/set, document_ids: the document ids to count against -- a concrete list/set,
or a simple (already resolved) queryset of ids. Keep or a simple (already resolved) queryset of ids. Callers
the list small: it is embedded in the statement as that need this filtered by a complex condition (e.g. a
literal parameters. permission check) should resolve it to a concrete list
first if the same ids will be reused across multiple
calls, rather than passing the complex queryset itself
into each -- see ``_get_selection_data_for_queryset``.
target_field: field on the relation pointing to Document id target_field: field on the relation pointing to Document id
""" """
+6 -6
View File
@@ -476,13 +476,13 @@ def update_filename_and_move_files(
return return
with FileLock(settings.MEDIA_LOCK): with FileLock(settings.MEDIA_LOCK):
try: # If this was waiting for the lock, the filename or archive_filename
# If this was waiting for the lock, the filename or archive_filename # of this document may have been updated. This happens if multiple updates
# of this document may have been updated. This happens if multiple updates # get queued from the UI for the same document
# get queued from the UI for the same document # So freshen up the data before doing anything
# So freshen up the data before doing anything instance.refresh_from_db()
instance.refresh_from_db()
try:
old_filename = instance.filename old_filename = instance.filename
old_source_path = instance.source_path old_source_path = instance.source_path
move_original = False move_original = False
+4 -1
View File
@@ -44,7 +44,10 @@ def localize_date(value: date | datetime | str, format: str, locale: str) -> str
def format_datetime(value: str | datetime, format: str) -> str: def format_datetime(value: str | datetime, format: str) -> str:
if isinstance(value, str): if isinstance(value, str):
value = parse_date(value) parsed = parse_datetime(value) or parse_date(value)
if parsed is None:
raise ValueError(f"Invalid date or datetime string: {value!r}")
return parsed.strftime(format=format)
return value.strftime(format=format) return value.strftime(format=format)
+10 -6
View File
@@ -12,25 +12,29 @@ if TYPE_CHECKING:
from paperless_testing.dirs import PaperlessDirs from paperless_testing.dirs import PaperlessDirs
@pytest.fixture(scope="session")
def document_samples_dir() -> Path:
"""Path to the shared test sample documents."""
return Path(__file__).parent / "samples" / "documents"
@pytest.fixture() @pytest.fixture()
def sample_doc( def sample_doc(
paperless_dirs: "PaperlessDirs", paperless_dirs: "PaperlessDirs",
simple_digital_pdf_file: Path, document_samples_dir: Path,
multi_page_images_pdf_file: Path,
thumbnail_webp_file: Path,
) -> "Document": ) -> "Document":
"""Create a document with valid files and matching checksums.""" """Create a document with valid files and matching checksums."""
with filelock.FileLock(paperless_dirs.media_lock): with filelock.FileLock(paperless_dirs.media_lock):
shutil.copy( shutil.copy(
simple_digital_pdf_file, document_samples_dir / "originals" / "0000001.pdf",
paperless_dirs.originals_dir / "0000001.pdf", paperless_dirs.originals_dir / "0000001.pdf",
) )
shutil.copy( shutil.copy(
multi_page_images_pdf_file, document_samples_dir / "archive" / "0000001.pdf",
paperless_dirs.archive_dir / "0000001.pdf", paperless_dirs.archive_dir / "0000001.pdf",
) )
shutil.copy( shutil.copy(
thumbnail_webp_file, document_samples_dir / "thumbnails" / "0000001.webp",
paperless_dirs.thumbnail_dir / "0000001.webp", paperless_dirs.thumbnail_dir / "0000001.webp",
) )
Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.
+1
View File
@@ -0,0 +1 @@
This is a test file.
@@ -53,7 +53,7 @@ class TestBulkDownload(DirectoriesMixin, SampleDirMixin, APITestCase):
archive_checksum="D", archive_checksum="D",
) )
shutil.copy(self.SIMPLE_PDF, self.doc2.source_path) shutil.copy(self.SAMPLE_DIR / "simple.pdf", self.doc2.source_path)
shutil.copy(self.SAMPLE_DIR / "simple.png", self.doc2b.source_path) shutil.copy(self.SAMPLE_DIR / "simple.png", self.doc2b.source_path)
shutil.copy(self.SAMPLE_DIR / "simple.jpg", self.doc3.source_path) shutil.copy(self.SAMPLE_DIR / "simple.jpg", self.doc3.source_path)
shutil.copy(self.SAMPLE_DIR / "test_with_bom.pdf", self.doc3.archive_path) shutil.copy(self.SAMPLE_DIR / "test_with_bom.pdf", self.doc3.archive_path)
+2 -2
View File
@@ -1141,8 +1141,8 @@ class TestBulkEditAPI(DirectoriesMixin, APITestCase):
self.assertCountEqual( self.assertCountEqual(
response.data["selected_document_types"], response.data["selected_document_types"],
[ [
{"id": self.dt1.id, "document_count": 1}, {"id": self.c1.id, "document_count": 1},
{"id": self.dt2.id, "document_count": 0}, {"id": self.c2.id, "document_count": 0},
], ],
) )
+33 -150
View File
@@ -49,7 +49,6 @@ from documents.models import WorkflowTrigger
from documents.search import get_backend from documents.search import get_backend
from documents.signals.handlers import run_workflows from documents.signals.handlers import run_workflows
from documents.tests.utils import ConsumeTaskMixin from documents.tests.utils import ConsumeTaskMixin
from documents.views import DocumentViewSet
from paperless_testing.dirs import DirectoriesMixin from paperless_testing.dirs import DirectoriesMixin
from paperless_testing.factories import DocumentFactory from paperless_testing.factories import DocumentFactory
from paperless_testing.factories import TagFactory from paperless_testing.factories import TagFactory
@@ -58,8 +57,6 @@ from paperless_testing.http import read_streaming_response
from paperless_testing.permissions import grant_all_global from paperless_testing.permissions import grant_all_global
from paperless_testing.permissions import grant_global from paperless_testing.permissions import grant_global
from paperless_testing.permissions import grant_object from paperless_testing.permissions import grant_object
from paperless_testing.samples import SIMPLE_DIGITAL_PDF
from paperless_testing.samples import THUMBNAIL_WEBP
class TestDocumentApi(DirectoriesMixin, ConsumeTaskMixin, APITestCase): class TestDocumentApi(DirectoriesMixin, ConsumeTaskMixin, APITestCase):
@@ -1756,106 +1753,6 @@ class TestDocumentApi(DirectoriesMixin, ConsumeTaskMixin, APITestCase):
} }
self.assertEqual(counts_by_field[custom_field.id], 1) self.assertEqual(counts_by_field[custom_field.id], 1)
def test_selection_data_counts_with_shared_by_filter(self) -> None:
"""
GIVEN:
- Several documents owned by one user with the same correspondent
and document type, only one of which is shared
WHEN:
- Requesting the document list filtered by shared_by__id with
include_selection_data=true
THEN:
- Counts reflect only the shared document, not every document the
owner has with that correspondent or document type, however the
link-table lookups are batched
"""
owner = User.objects.create_user(username="owner")
other = User.objects.create_user(username="other")
correspondent = Correspondent.objects.create(name="c1")
doc_type = DocumentType.objects.create(name="dt1")
tag = Tag.objects.create(name="tag")
docs = [
Document.objects.create(
checksum=str(i),
owner=owner,
correspondent=correspondent,
document_type=doc_type,
)
for i in range(3)
]
for doc in docs:
doc.tags.add(tag)
grant_object(other, docs[0], "view_document")
for batch_size in (10_000, 1):
with (
self.subTest(link_batch_size=batch_size),
mock.patch.object(
DocumentViewSet,
"selection_data_link_batch_size",
batch_size,
),
):
response = self.client.get(
f"/api/documents/?shared_by__id={owner.id}"
"&include_selection_data=true",
)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data["count"], 1)
selection_data = response.data["selection_data"]
for key, obj in (
("selected_correspondents", correspondent),
("selected_document_types", doc_type),
("selected_tags", tag),
):
counts = {
item["id"]: item["document_count"]
for item in selection_data[key]
}
self.assertEqual(counts[obj.id], 1, key)
def test_selection_data_counts_documents_once_when_filter_joins(self) -> None:
"""
GIVEN:
- A document matching a multi-valued filter through two tags
WHEN:
- Requesting the document list with include_selection_data=true
THEN:
- The document is counted once per correspondent, not once per
matching tag, however the link-table lookups are batched
"""
correspondent = Correspondent.objects.create(name="c1")
tag_a = Tag.objects.create(name="a")
tag_b = Tag.objects.create(name="b")
both = Document.objects.create(checksum="1", correspondent=correspondent)
both.tags.add(tag_a, tag_b)
only_a = Document.objects.create(checksum="2", correspondent=correspondent)
only_a.tags.add(tag_a)
for batch_size in (10_000, 1):
with (
self.subTest(link_batch_size=batch_size),
mock.patch.object(
DocumentViewSet,
"selection_data_link_batch_size",
batch_size,
),
):
response = self.client.get(
f"/api/documents/?tags__id__in={tag_a.id},{tag_b.id}"
"&include_selection_data=true",
)
self.assertEqual(response.status_code, status.HTTP_200_OK)
counts = {
item["id"]: item["document_count"]
for item in response.data["selection_data"][
"selected_correspondents"
]
}
self.assertEqual(counts[correspondent.id], 2)
def test_statistics(self) -> None: def test_statistics(self) -> None:
doc1 = Document.objects.create( doc1 = Document.objects.create(
title="none1", title="none1",
@@ -2020,11 +1917,7 @@ class TestDocumentApi(DirectoriesMixin, ConsumeTaskMixin, APITestCase):
id=str(uuid.uuid4()), id=str(uuid.uuid4()),
) )
with SimpleUploadedFile( with (Path(__file__).parent / "samples" / "simple.pdf").open("rb") as f:
"simple.pdf",
SIMPLE_DIGITAL_PDF.read_bytes(),
content_type="application/pdf",
) as f:
response = self.client.post( response = self.client.post(
"/api/documents/post_document/", "/api/documents/post_document/",
{"document": f}, {"document": f},
@@ -2052,7 +1945,7 @@ class TestDocumentApi(DirectoriesMixin, ConsumeTaskMixin, APITestCase):
payload = SimpleUploadedFile( payload = SimpleUploadedFile(
"../../outside.pdf", "../../outside.pdf",
SIMPLE_DIGITAL_PDF.read_bytes(), (Path(__file__).parent / "samples" / "simple.pdf").read_bytes(),
content_type="application/pdf", content_type="application/pdf",
) )
@@ -2081,7 +1974,7 @@ class TestDocumentApi(DirectoriesMixin, ConsumeTaskMixin, APITestCase):
id=str(uuid.uuid4()), id=str(uuid.uuid4()),
) )
pdf_bytes = SIMPLE_DIGITAL_PDF.read_bytes() pdf_bytes = (Path(__file__).parent / "samples" / "simple.pdf").read_bytes()
boundary = "paperless-boundary" boundary = "paperless-boundary"
payload = ( payload = (
( (
@@ -2157,7 +2050,7 @@ class TestDocumentApi(DirectoriesMixin, ConsumeTaskMixin, APITestCase):
def test_upload_insufficient_permissions(self) -> None: def test_upload_insufficient_permissions(self) -> None:
self.client.force_authenticate(user=UserFactory(username="testuser2")) self.client.force_authenticate(user=UserFactory(username="testuser2"))
with SIMPLE_DIGITAL_PDF.open("rb") as f: with (Path(__file__).parent / "samples" / "simple.pdf").open("rb") as f:
response = self.client.post( response = self.client.post(
"/api/documents/post_document/", "/api/documents/post_document/",
{"document": f}, {"document": f},
@@ -2170,11 +2063,7 @@ class TestDocumentApi(DirectoriesMixin, ConsumeTaskMixin, APITestCase):
id=str(uuid.uuid4()), id=str(uuid.uuid4()),
) )
with SimpleUploadedFile( with (Path(__file__).parent / "samples" / "simple.pdf").open("rb") as f:
"simple.pdf",
SIMPLE_DIGITAL_PDF.read_bytes(),
content_type="application/pdf",
) as f:
response = self.client.post( response = self.client.post(
"/api/documents/post_document/", "/api/documents/post_document/",
{ {
@@ -2207,7 +2096,7 @@ class TestDocumentApi(DirectoriesMixin, ConsumeTaskMixin, APITestCase):
id=str(uuid.uuid4()), id=str(uuid.uuid4()),
) )
with SIMPLE_DIGITAL_PDF.open("rb") as f: with (Path(__file__).parent / "samples" / "simple.pdf").open("rb") as f:
response = self.client.post( response = self.client.post(
"/api/documents/post_document/", "/api/documents/post_document/",
{"documenst": f}, {"documenst": f},
@@ -2233,7 +2122,7 @@ class TestDocumentApi(DirectoriesMixin, ConsumeTaskMixin, APITestCase):
id=str(uuid.uuid4()), id=str(uuid.uuid4()),
) )
with SIMPLE_DIGITAL_PDF.open("rb") as f: with (Path(__file__).parent / "samples" / "simple.pdf").open("rb") as f:
response = self.client.post( response = self.client.post(
"/api/documents/post_document/", "/api/documents/post_document/",
{"document": f, "title": "my custom title"}, {"document": f, "title": "my custom title"},
@@ -2253,7 +2142,7 @@ class TestDocumentApi(DirectoriesMixin, ConsumeTaskMixin, APITestCase):
) )
c = Correspondent.objects.create(name="test-corres") c = Correspondent.objects.create(name="test-corres")
with SIMPLE_DIGITAL_PDF.open("rb") as f: with (Path(__file__).parent / "samples" / "simple.pdf").open("rb") as f:
response = self.client.post( response = self.client.post(
"/api/documents/post_document/", "/api/documents/post_document/",
{"document": f, "correspondent": c.id}, {"document": f, "correspondent": c.id},
@@ -2272,7 +2161,7 @@ class TestDocumentApi(DirectoriesMixin, ConsumeTaskMixin, APITestCase):
id=str(uuid.uuid4()), id=str(uuid.uuid4()),
) )
with SIMPLE_DIGITAL_PDF.open("rb") as f: with (Path(__file__).parent / "samples" / "simple.pdf").open("rb") as f:
response = self.client.post( response = self.client.post(
"/api/documents/post_document/", "/api/documents/post_document/",
{"document": f, "correspondent": 3456}, {"document": f, "correspondent": 3456},
@@ -2287,7 +2176,7 @@ class TestDocumentApi(DirectoriesMixin, ConsumeTaskMixin, APITestCase):
) )
dt = DocumentType.objects.create(name="invoice") dt = DocumentType.objects.create(name="invoice")
with SIMPLE_DIGITAL_PDF.open("rb") as f: with (Path(__file__).parent / "samples" / "simple.pdf").open("rb") as f:
response = self.client.post( response = self.client.post(
"/api/documents/post_document/", "/api/documents/post_document/",
{"document": f, "document_type": dt.id}, {"document": f, "document_type": dt.id},
@@ -2306,7 +2195,7 @@ class TestDocumentApi(DirectoriesMixin, ConsumeTaskMixin, APITestCase):
id=str(uuid.uuid4()), id=str(uuid.uuid4()),
) )
with SIMPLE_DIGITAL_PDF.open("rb") as f: with (Path(__file__).parent / "samples" / "simple.pdf").open("rb") as f:
response = self.client.post( response = self.client.post(
"/api/documents/post_document/", "/api/documents/post_document/",
{"document": f, "document_type": 34578}, {"document": f, "document_type": 34578},
@@ -2321,7 +2210,7 @@ class TestDocumentApi(DirectoriesMixin, ConsumeTaskMixin, APITestCase):
) )
sp = StoragePath.objects.create(name="invoices") sp = StoragePath.objects.create(name="invoices")
with SIMPLE_DIGITAL_PDF.open("rb") as f: with (Path(__file__).parent / "samples" / "simple.pdf").open("rb") as f:
response = self.client.post( response = self.client.post(
"/api/documents/post_document/", "/api/documents/post_document/",
{"document": f, "storage_path": sp.id}, {"document": f, "storage_path": sp.id},
@@ -2340,7 +2229,7 @@ class TestDocumentApi(DirectoriesMixin, ConsumeTaskMixin, APITestCase):
id=str(uuid.uuid4()), id=str(uuid.uuid4()),
) )
with SIMPLE_DIGITAL_PDF.open("rb") as f: with (Path(__file__).parent / "samples" / "simple.pdf").open("rb") as f:
response = self.client.post( response = self.client.post(
"/api/documents/post_document/", "/api/documents/post_document/",
{"document": f, "storage_path": 34578}, {"document": f, "storage_path": 34578},
@@ -2356,7 +2245,7 @@ class TestDocumentApi(DirectoriesMixin, ConsumeTaskMixin, APITestCase):
t1 = Tag.objects.create(name="tag1") t1 = Tag.objects.create(name="tag1")
t2 = Tag.objects.create(name="tag2") t2 = Tag.objects.create(name="tag2")
with SIMPLE_DIGITAL_PDF.open("rb") as f: with (Path(__file__).parent / "samples" / "simple.pdf").open("rb") as f:
response = self.client.post( response = self.client.post(
"/api/documents/post_document/", "/api/documents/post_document/",
{"document": f, "tags": [t2.id, t1.id]}, {"document": f, "tags": [t2.id, t1.id]},
@@ -2377,7 +2266,7 @@ class TestDocumentApi(DirectoriesMixin, ConsumeTaskMixin, APITestCase):
t1 = Tag.objects.create(name="tag1") t1 = Tag.objects.create(name="tag1")
t2 = Tag.objects.create(name="tag2") t2 = Tag.objects.create(name="tag2")
with SIMPLE_DIGITAL_PDF.open("rb") as f: with (Path(__file__).parent / "samples" / "simple.pdf").open("rb") as f:
response = self.client.post( response = self.client.post(
"/api/documents/post_document/", "/api/documents/post_document/",
{"document": f, "tags": [t2.id, t1.id, 734563]}, {"document": f, "tags": [t2.id, t1.id, 734563]},
@@ -2401,7 +2290,7 @@ class TestDocumentApi(DirectoriesMixin, ConsumeTaskMixin, APITestCase):
0, 0,
tzinfo=zoneinfo.ZoneInfo("America/Los_Angeles"), tzinfo=zoneinfo.ZoneInfo("America/Los_Angeles"),
) )
with SIMPLE_DIGITAL_PDF.open("rb") as f: with (Path(__file__).parent / "samples" / "simple.pdf").open("rb") as f:
response = self.client.post( response = self.client.post(
"/api/documents/post_document/", "/api/documents/post_document/",
{"document": f, "created": created}, {"document": f, "created": created},
@@ -2417,11 +2306,7 @@ class TestDocumentApi(DirectoriesMixin, ConsumeTaskMixin, APITestCase):
id=str(uuid.uuid4()), id=str(uuid.uuid4()),
) )
with SimpleUploadedFile( with (Path(__file__).parent / "samples" / "simple.pdf").open("rb") as f:
"simple.pdf",
SIMPLE_DIGITAL_PDF.read_bytes(),
content_type="application/pdf",
) as f:
response = self.client.post( response = self.client.post(
"/api/documents/post_document/", "/api/documents/post_document/",
{"document": f, "archive_serial_number": 500}, {"document": f, "archive_serial_number": 500},
@@ -2448,11 +2333,7 @@ class TestDocumentApi(DirectoriesMixin, ConsumeTaskMixin, APITestCase):
data_type=CustomField.FieldDataType.STRING, data_type=CustomField.FieldDataType.STRING,
) )
with SimpleUploadedFile( with (Path(__file__).parent / "samples" / "simple.pdf").open("rb") as f:
"simple.pdf",
SIMPLE_DIGITAL_PDF.read_bytes(),
content_type="application/pdf",
) as f:
response = self.client.post( response = self.client.post(
"/api/documents/post_document/", "/api/documents/post_document/",
{ {
@@ -2507,7 +2388,7 @@ class TestDocumentApi(DirectoriesMixin, ConsumeTaskMixin, APITestCase):
w1.actions.add(action1) w1.actions.add(action1)
w1.save() w1.save()
with SIMPLE_DIGITAL_PDF.open("rb") as f: with (Path(__file__).parent / "samples" / "simple.pdf").open("rb") as f:
response = self.client.post( response = self.client.post(
"/api/documents/post_document/", "/api/documents/post_document/",
{ {
@@ -2548,11 +2429,7 @@ class TestDocumentApi(DirectoriesMixin, ConsumeTaskMixin, APITestCase):
data_type=CustomField.FieldDataType.INT, data_type=CustomField.FieldDataType.INT,
) )
with SimpleUploadedFile( with (Path(__file__).parent / "samples" / "simple.pdf").open("rb") as f:
"simple.pdf",
SIMPLE_DIGITAL_PDF.read_bytes(),
content_type="application/pdf",
) as f:
response = self.client.post( response = self.client.post(
"/api/documents/post_document/", "/api/documents/post_document/",
{ {
@@ -2601,7 +2478,7 @@ class TestDocumentApi(DirectoriesMixin, ConsumeTaskMixin, APITestCase):
] ]
for payload in error_payloads: for payload in error_payloads:
with SIMPLE_DIGITAL_PDF.open("rb") as f: with (Path(__file__).parent / "samples" / "simple.pdf").open("rb") as f:
data = {"document": f, **payload} data = {"document": f, **payload}
response = self.client.post( response = self.client.post(
"/api/documents/post_document/", "/api/documents/post_document/",
@@ -2659,7 +2536,7 @@ class TestDocumentApi(DirectoriesMixin, ConsumeTaskMixin, APITestCase):
id=str(uuid.uuid4()), id=str(uuid.uuid4()),
) )
with SIMPLE_DIGITAL_PDF.open("rb") as f: with (Path(__file__).parent / "samples" / "simple.pdf").open("rb") as f:
response = self.client.post( response = self.client.post(
"/api/documents/post_document/", "/api/documents/post_document/",
{"document": f, "from_webui": True}, {"document": f, "from_webui": True},
@@ -2698,8 +2575,14 @@ class TestDocumentApi(DirectoriesMixin, ConsumeTaskMixin, APITestCase):
archive_filename="archive.pdf", archive_filename="archive.pdf",
) )
source_file: Path = THUMBNAIL_WEBP source_file: Path = (
archive_file: Path = SIMPLE_DIGITAL_PDF Path(__file__).parent
/ "samples"
/ "documents"
/ "thumbnails"
/ "0000001.webp"
)
archive_file: Path = Path(__file__).parent / "samples" / "simple.pdf"
shutil.copy(source_file, doc.source_path) shutil.copy(source_file, doc.source_path)
shutil.copy(archive_file, doc.archive_path) shutil.copy(archive_file, doc.archive_path)
@@ -2732,7 +2615,7 @@ class TestDocumentApi(DirectoriesMixin, ConsumeTaskMixin, APITestCase):
mime_type="application/pdf", mime_type="application/pdf",
) )
shutil.copy(SIMPLE_DIGITAL_PDF, doc.source_path) shutil.copy(Path(__file__).parent / "samples" / "simple.pdf", doc.source_path)
response = self.client.get(f"/api/documents/{doc.pk}/metadata/") response = self.client.get(f"/api/documents/{doc.pk}/metadata/")
self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.status_code, status.HTTP_200_OK)
@@ -4498,8 +4381,8 @@ class TestDocumentApi(DirectoriesMixin, ConsumeTaskMixin, APITestCase):
filename="test2.pdf", filename="test2.pdf",
) )
archive_file = SIMPLE_DIGITAL_PDF archive_file = Path(__file__).parent / "samples" / "simple.pdf"
source_file = SIMPLE_DIGITAL_PDF source_file = Path(__file__).parent / "samples" / "simple.pdf"
shutil.copy(archive_file, doc.archive_path) shutil.copy(archive_file, doc.archive_path)
shutil.copy(source_file, doc2.source_path) shutil.copy(source_file, doc2.source_path)
+5 -8
View File
@@ -12,9 +12,6 @@ from documents.tests.utils import SampleDirMixin
from paperless_testing.dirs import DirectoriesMixin from paperless_testing.dirs import DirectoriesMixin
from paperless_testing.factories import UserFactory from paperless_testing.factories import UserFactory
from paperless_testing.permissions import grant_global from paperless_testing.permissions import grant_global
from paperless_testing.samples import MULTI_PAGE_DIGITAL_PDF
from paperless_testing.samples import SIMPLE_DIGITAL_PDF
from paperless_testing.samples import WITH_FORM_PDF
class TestEmail(DirectoriesMixin, SampleDirMixin, APITestCase): class TestEmail(DirectoriesMixin, SampleDirMixin, APITestCase):
@@ -45,15 +42,15 @@ class TestEmail(DirectoriesMixin, SampleDirMixin, APITestCase):
# Copy sample files to document paths (using different files to distinguish versions) # Copy sample files to document paths (using different files to distinguish versions)
shutil.copy( shutil.copy(
SIMPLE_DIGITAL_PDF, self.SAMPLE_DIR / "documents" / "originals" / "0000001.pdf",
self.doc1.archive_path, self.doc1.archive_path,
) )
shutil.copy( shutil.copy(
MULTI_PAGE_DIGITAL_PDF, self.SAMPLE_DIR / "documents" / "originals" / "0000002.pdf",
self.doc1.source_path, self.doc1.source_path,
) )
shutil.copy( shutil.copy(
WITH_FORM_PDF, self.SAMPLE_DIR / "documents" / "originals" / "0000003.pdf",
self.doc2.source_path, self.doc2.source_path,
) )
@@ -380,7 +377,7 @@ class TestEmail(DirectoriesMixin, SampleDirMixin, APITestCase):
checksum="3", checksum="3",
filename="test3.pdf", filename="test3.pdf",
) )
shutil.copy(self.SIMPLE_PDF, doc3.source_path) shutil.copy(self.SAMPLE_DIR / "simple.pdf", doc3.source_path)
doc4 = Document.objects.create( doc4 = Document.objects.create(
title="test1", title="test1",
@@ -389,7 +386,7 @@ class TestEmail(DirectoriesMixin, SampleDirMixin, APITestCase):
checksum="4", checksum="4",
filename="test4.pdf", filename="test4.pdf",
) )
shutil.copy(self.SIMPLE_PDF, doc4.source_path) shutil.copy(self.SAMPLE_DIR / "simple.pdf", doc4.source_path)
response = self.client.post( response = self.client.post(
self.ENDPOINT, self.ENDPOINT,
+47
View File
@@ -539,3 +539,50 @@ class TestSystemStatus(APITestCase):
self.assertEqual(response.data["tasks"]["summary"]["success_count"], 1) self.assertEqual(response.data["tasks"]["summary"]["success_count"], 1)
self.assertEqual(response.data["tasks"]["summary"]["failure_count"], 1) self.assertEqual(response.data["tasks"]["summary"]["failure_count"], 1)
self.assertEqual(response.data["tasks"]["summary"]["pending_count"], 1) self.assertEqual(response.data["tasks"]["summary"]["pending_count"], 1)
def test_system_status_reports_database_error(self) -> None:
"""
GIVEN:
- Reading the migration state fails
WHEN:
- The system status is requested
THEN:
- The response reports the database error rather than a server error
"""
self.client.force_login(self.user)
with mock.patch(
"documents.views.MigrationLoader",
side_effect=Exception("database is down"),
):
response = self.client.get(self.ENDPOINT)
self.assertEqual(response.status_code, status.HTTP_200_OK)
database = response.data["database"]
self.assertEqual(database["status"], "ERROR")
self.assertIsNotNone(database["error"])
self.assertEqual(
database["migration_status"],
{"latest_migration": None, "unapplied_migrations": []},
)
def test_system_status_migration_query_error(self) -> None:
"""
GIVEN:
- The migration graph loads but reading the applied migrations fails
WHEN:
- The system status is requested
THEN:
- No migrations are reported as unapplied, since the state is unknown
"""
self.client.force_login(self.user)
with mock.patch("documents.views.MigrationRecorder") as recorder:
recorder.Migration.objects.all.side_effect = Exception("query failed")
response = self.client.get(self.ENDPOINT)
self.assertEqual(response.status_code, status.HTTP_200_OK)
database = response.data["database"]
self.assertEqual(database["status"], "ERROR")
self.assertEqual(
database["migration_status"],
{"latest_migration": None, "unapplied_migrations": []},
)
+2 -2
View File
@@ -169,7 +169,7 @@ class TestBarcode(
- No barcodes detected - No barcodes detected
- No pages to split on - No pages to split on
""" """
test_file = self.SIMPLE_PDF test_file = self.SAMPLE_DIR / "simple.pdf"
with self.get_reader(test_file) as reader: with self.get_reader(test_file) as reader:
reader.detect() reader.detect()
separator_page_numbers = reader.get_separation_pages() separator_page_numbers = reader.get_separation_pages()
@@ -461,7 +461,7 @@ class TestBarcode(
THEN: THEN:
- Nothing happens - Nothing happens
""" """
test_file = self.SIMPLE_PDF test_file = self.SAMPLE_DIR / "simple.pdf"
with self.get_reader(test_file) as reader: with self.get_reader(test_file) as reader:
try: try:
+30 -9
View File
@@ -29,9 +29,6 @@ from documents.permissions import set_permissions_for_objects
from paperless_testing.dirs import DirectoriesMixin from paperless_testing.dirs import DirectoriesMixin
from paperless_testing.factories import DocumentFactory from paperless_testing.factories import DocumentFactory
from paperless_testing.permissions import grant_object from paperless_testing.permissions import grant_object
from paperless_testing.samples import MULTI_PAGE_DIGITAL_PDF
from paperless_testing.samples import SIMPLE_DIGITAL_PDF
from paperless_testing.samples import WITH_FORM_PDF
class TestBulkEdit(DirectoriesMixin, TestCase): class TestBulkEdit(DirectoriesMixin, TestCase):
@@ -709,27 +706,47 @@ class TestPDFActions(DirectoriesMixin, TestCase):
super().setUp() super().setUp()
sample1 = self.dirs.scratch_dir / "sample.pdf" sample1 = self.dirs.scratch_dir / "sample.pdf"
shutil.copy( shutil.copy(
SIMPLE_DIGITAL_PDF, Path(__file__).parent
/ "samples"
/ "documents"
/ "originals"
/ "0000001.pdf",
sample1, sample1,
) )
sample1_archive = self.dirs.archive_dir / "sample_archive.pdf" sample1_archive = self.dirs.archive_dir / "sample_archive.pdf"
shutil.copy( shutil.copy(
SIMPLE_DIGITAL_PDF, Path(__file__).parent
/ "samples"
/ "documents"
/ "originals"
/ "0000001.pdf",
sample1_archive, sample1_archive,
) )
sample2 = self.dirs.scratch_dir / "sample2.pdf" sample2 = self.dirs.scratch_dir / "sample2.pdf"
shutil.copy( shutil.copy(
MULTI_PAGE_DIGITAL_PDF, Path(__file__).parent
/ "samples"
/ "documents"
/ "originals"
/ "0000002.pdf",
sample2, sample2,
) )
sample2_archive = self.dirs.archive_dir / "sample2_archive.pdf" sample2_archive = self.dirs.archive_dir / "sample2_archive.pdf"
shutil.copy( shutil.copy(
MULTI_PAGE_DIGITAL_PDF, Path(__file__).parent
/ "samples"
/ "documents"
/ "originals"
/ "0000002.pdf",
sample2_archive, sample2_archive,
) )
sample3 = self.dirs.scratch_dir / "sample3.pdf" sample3 = self.dirs.scratch_dir / "sample3.pdf"
shutil.copy( shutil.copy(
WITH_FORM_PDF, Path(__file__).parent
/ "samples"
/ "documents"
/ "originals"
/ "0000003.pdf",
sample3, sample3,
) )
self.doc1 = Document.objects.create( self.doc1 = Document.objects.create(
@@ -763,7 +780,11 @@ class TestPDFActions(DirectoriesMixin, TestCase):
) )
img_doc_archive = self.dirs.archive_dir / "sample_image.pdf" img_doc_archive = self.dirs.archive_dir / "sample_image.pdf"
shutil.copy( shutil.copy(
SIMPLE_DIGITAL_PDF, Path(__file__).parent
/ "samples"
/ "documents"
/ "originals"
/ "0000001.pdf",
img_doc_archive, img_doc_archive,
) )
self.img_doc = Document.objects.create( self.img_doc = Document.objects.create(
+28 -9
View File
@@ -39,9 +39,6 @@ from paperless_testing.factories import TagFactory
from paperless_testing.factories import UserFactory from paperless_testing.factories import UserFactory
from paperless_testing.fakes.progress import FakeProgressManager from paperless_testing.fakes.progress import FakeProgressManager
from paperless_testing.permissions import grant_object from paperless_testing.permissions import grant_object
from paperless_testing.samples import MULTI_PAGE_DIGITAL_PDF
from paperless_testing.samples import MULTI_PAGE_IMAGES_PDF
from paperless_testing.samples import SIMPLE_DIGITAL_PDF
class _BaseNewStyleParser: class _BaseNewStyleParser:
@@ -118,7 +115,9 @@ class _BaseNewStyleParser:
class DummyParser(_BaseNewStyleParser): class DummyParser(_BaseNewStyleParser):
_ARCHIVE_SRC = MULTI_PAGE_IMAGES_PDF _ARCHIVE_SRC = (
Path(__file__).parent / "samples" / "documents" / "archive" / "0000001.pdf"
)
def parse(self, document_path, mime_type, *, produce_archive: bool = True) -> None: def parse(self, document_path, mime_type, *, produce_archive: bool = True) -> None:
self._text = "The Text" self._text = "The Text"
@@ -204,19 +203,33 @@ class TestConsumer(
self.addCleanup(patcher.stop) self.addCleanup(patcher.stop)
def get_test_file(self): def get_test_file(self):
src = SIMPLE_DIGITAL_PDF src = (
Path(__file__).parent
/ "samples"
/ "documents"
/ "originals"
/ "0000001.pdf"
)
dst = self.dirs.scratch_dir / "sample.pdf" dst = self.dirs.scratch_dir / "sample.pdf"
shutil.copy(src, dst) shutil.copy(src, dst)
return dst return dst
def get_test_file2(self): def get_test_file2(self):
src = MULTI_PAGE_DIGITAL_PDF src = (
Path(__file__).parent
/ "samples"
/ "documents"
/ "originals"
/ "0000002.pdf"
)
dst = self.dirs.scratch_dir / "sample2.pdf" dst = self.dirs.scratch_dir / "sample2.pdf"
shutil.copy(src, dst) shutil.copy(src, dst)
return dst return dst
def get_test_archive_file(self): def get_test_archive_file(self):
src = MULTI_PAGE_IMAGES_PDF src = (
Path(__file__).parent / "samples" / "documents" / "archive" / "0000001.pdf"
)
dst = self.dirs.scratch_dir / "sample_archive.pdf" dst = self.dirs.scratch_dir / "sample_archive.pdf"
shutil.copy(src, dst) shutil.copy(src, dst)
return dst return dst
@@ -1111,7 +1124,7 @@ class TestConsumer(
@mock.patch("documents.consumer.get_parser_registry") @mock.patch("documents.consumer.get_parser_registry")
def test_similar_filenames(self, m) -> None: def test_similar_filenames(self, m) -> None:
shutil.copy( shutil.copy(
SIMPLE_DIGITAL_PDF, Path(__file__).parent / "samples" / "simple.pdf",
settings.CONSUMPTION_DIR / "simple.pdf", settings.CONSUMPTION_DIR / "simple.pdf",
) )
shutil.copy( shutil.copy(
@@ -1652,7 +1665,13 @@ class TestConsumerRemoteOCR(
self.addCleanup(patcher.stop) self.addCleanup(patcher.stop)
def _consume(self, *, overrides: DocumentMetadataOverrides | None = None) -> bool: def _consume(self, *, overrides: DocumentMetadataOverrides | None = None) -> bool:
src = SIMPLE_DIGITAL_PDF src = (
Path(__file__).parent
/ "samples"
/ "documents"
/ "originals"
/ "0000001.pdf"
)
dst = self.dirs.scratch_dir / "sample.pdf" dst = self.dirs.scratch_dir / "sample.pdf"
shutil.copy(src, dst) shutil.copy(src, dst)
+2 -5
View File
@@ -37,15 +37,12 @@ class TestDoubleSided(
self.double_sided_dir.mkdir() self.double_sided_dir.mkdir()
self.staging_file = self.dirs.scratch_dir / STAGING_FILE_NAME self.staging_file = self.dirs.scratch_dir / STAGING_FILE_NAME
def _sample(self, name: str) -> Path:
return self.SIMPLE_PDF if name == "simple.pdf" else self.SAMPLE_DIR / name
def consume_file(self, srcname, dstname: str | Path = "foo.pdf"): def consume_file(self, srcname, dstname: str | Path = "foo.pdf"):
""" """
Starts the consume process and also ensures the Starts the consume process and also ensures the
destination file does not exist afterwards destination file does not exist afterwards
""" """
src = self._sample(srcname) src = self.SAMPLE_DIR / srcname
dst = self.double_sided_dir / dstname dst = self.double_sided_dir / dstname
dst.parent.mkdir(parents=True, exist_ok=True) dst.parent.mkdir(parents=True, exist_ok=True)
shutil.copy(src, dst) shutil.copy(src, dst)
@@ -60,7 +57,7 @@ class TestDoubleSided(
return msg return msg
def create_staging_file(self, src="double-sided-odd.pdf", datetime=None) -> None: def create_staging_file(self, src="double-sided-odd.pdf", datetime=None) -> None:
shutil.copy(self._sample(src), self.staging_file) shutil.copy(self.SAMPLE_DIR / src, self.staging_file)
if datetime is None: if datetime is None:
datetime = dt.datetime.now() datetime = dt.datetime.now()
os.utime(str(self.staging_file), (datetime.timestamp(),) * 2) os.utime(str(self.staging_file), (datetime.timestamp(),) * 2)
+26
View File
@@ -31,6 +31,7 @@ from documents.serialisers import DocumentSerializer
from documents.tasks import empty_trash from documents.tasks import empty_trash
from paperless_testing.assertions import FileSystemAssertsMixin from paperless_testing.assertions import FileSystemAssertsMixin
from paperless_testing.dirs import DirectoriesMixin from paperless_testing.dirs import DirectoriesMixin
from paperless_testing.dirs import PaperlessDirs
from paperless_testing.factories import DocumentFactory from paperless_testing.factories import DocumentFactory
from paperless_testing.factories import UserFactory from paperless_testing.factories import UserFactory
@@ -2134,3 +2135,28 @@ class TestPathDateLocalization:
with override_settings(FILENAME_FORMAT=filename_format): with override_settings(FILENAME_FORMAT=filename_format):
filename = generate_filename(document) filename = generate_filename(document)
assert filename == Path(expected_filename) assert filename == Path(expected_filename)
@pytest.mark.django_db
def test_refresh_failure_surfaces_database_error(
paperless_dirs: PaperlessDirs,
) -> None:
"""
GIVEN:
- A document with a stored filename
WHEN:
- Saving it triggers a filename update and refreshing it from the database fails
THEN:
- The database error is raised, not an unbound variable error from the rollback
"""
document = DocumentFactory(filename="some.pdf")
with (
mock.patch.object(
Document,
"refresh_from_db",
side_effect=DatabaseError("database is locked"),
),
pytest.raises(DatabaseError, match="database is locked"),
):
document.save()
+21
View File
@@ -4,6 +4,7 @@ from typing import Literal
import pytest import pytest
from documents.templating.filters import format_datetime
from documents.templating.filters import localize_date from documents.templating.filters import localize_date
@@ -294,3 +295,23 @@ class TestDateLocalization:
Tests `localize_date` with `date` string across different locales and formats. Tests `localize_date` with `date` string across different locales and formats.
""" """
assert localize_date(value, format_style, locale_str) == expected_output assert localize_date(value, format_style, locale_str) == expected_output
class TestFormatDatetime:
@pytest.mark.parametrize(
("value", "expected"),
[
pytest.param("2026-09-21", "2026-09-21 00:00", id="date"),
pytest.param(
"2026-09-21T13:45:00+00:00",
"2026-09-21 13:45",
id="datetime",
),
],
)
def test_parses_iso_strings(self, value: str, expected: str) -> None:
assert format_datetime(value, "%Y-%m-%d %H:%M") == expected
def test_rejects_unparseable_string(self) -> None:
with pytest.raises(ValueError, match="not a date"):
format_datetime("not a date", "%Y")
+1 -2
View File
@@ -23,9 +23,8 @@ from documents.tasks import update_document_content_maybe_archive_file
from paperless_testing.assertions import FileSystemAssertsMixin from paperless_testing.assertions import FileSystemAssertsMixin
from paperless_testing.dirs import DirectoriesMixin from paperless_testing.dirs import DirectoriesMixin
from paperless_testing.factories import DocumentFactory from paperless_testing.factories import DocumentFactory
from paperless_testing.samples import SIMPLE_DIGITAL_PDF
sample_file: Path = SIMPLE_DIGITAL_PDF sample_file: Path = Path(__file__).parent / "samples" / "simple.pdf"
@pytest.mark.management @pytest.mark.management
+80 -21
View File
@@ -59,7 +59,6 @@ from paperless_testing.dirs import paperless_environment
from paperless_testing.factories import DocumentBarcodeFactory from paperless_testing.factories import DocumentBarcodeFactory
from paperless_testing.factories import DocumentFactory from paperless_testing.factories import DocumentFactory
from paperless_testing.permissions import grant_object from paperless_testing.permissions import grant_object
from paperless_testing.samples import install_document_samples
@pytest.mark.management @pytest.mark.management
@@ -205,7 +204,10 @@ class TestExportImport(
def test_exporter(self, *, use_filename_format=False) -> None: def test_exporter(self, *, use_filename_format=False) -> None:
shutil.rmtree(Path(self.dirs.media_dir) / "documents") shutil.rmtree(Path(self.dirs.media_dir) / "documents")
install_document_samples(Path(self.dirs.media_dir) / "documents") shutil.copytree(
Path(__file__).parent / "samples" / "documents",
Path(self.dirs.media_dir) / "documents",
)
num_permission_objects = Permission.objects.count() num_permission_objects = Permission.objects.count()
@@ -309,7 +311,10 @@ class TestExportImport(
def test_exporter_with_filename_format(self) -> None: def test_exporter_with_filename_format(self) -> None:
shutil.rmtree(Path(self.dirs.media_dir) / "documents") shutil.rmtree(Path(self.dirs.media_dir) / "documents")
install_document_samples(Path(self.dirs.media_dir) / "documents") shutil.copytree(
Path(__file__).parent / "samples" / "documents",
Path(self.dirs.media_dir) / "documents",
)
with override_settings( with override_settings(
FILENAME_FORMAT="{created_year}/{correspondent}/{title}", FILENAME_FORMAT="{created_year}/{correspondent}/{title}",
@@ -318,7 +323,10 @@ class TestExportImport(
def test_exporter_includes_share_links_and_bundles(self) -> None: def test_exporter_includes_share_links_and_bundles(self) -> None:
shutil.rmtree(Path(self.dirs.media_dir) / "documents") shutil.rmtree(Path(self.dirs.media_dir) / "documents")
install_document_samples(Path(self.dirs.media_dir) / "documents") shutil.copytree(
Path(__file__).parent / "samples" / "documents",
Path(self.dirs.media_dir) / "documents",
)
share_link = ShareLink.objects.create( share_link = ShareLink.objects.create(
slug="share-link-slug", slug="share-link-slug",
@@ -417,7 +425,10 @@ class TestExportImport(
def test_update_export_changed_time(self) -> None: def test_update_export_changed_time(self) -> None:
shutil.rmtree(Path(self.dirs.media_dir) / "documents") shutil.rmtree(Path(self.dirs.media_dir) / "documents")
install_document_samples(Path(self.dirs.media_dir) / "documents") shutil.copytree(
Path(__file__).parent / "samples" / "documents",
Path(self.dirs.media_dir) / "documents",
)
self._do_export() self._do_export()
self.assertIsFile(self.target / "manifest.json") self.assertIsFile(self.target / "manifest.json")
@@ -453,7 +464,10 @@ class TestExportImport(
def test_update_export_changed_checksum(self) -> None: def test_update_export_changed_checksum(self) -> None:
shutil.rmtree(Path(self.dirs.media_dir) / "documents") shutil.rmtree(Path(self.dirs.media_dir) / "documents")
install_document_samples(Path(self.dirs.media_dir) / "documents") shutil.copytree(
Path(__file__).parent / "samples" / "documents",
Path(self.dirs.media_dir) / "documents",
)
self._do_export() self._do_export()
@@ -480,7 +494,10 @@ class TestExportImport(
def test_update_export_deleted_document(self) -> None: def test_update_export_deleted_document(self) -> None:
shutil.rmtree(Path(self.dirs.media_dir) / "documents") shutil.rmtree(Path(self.dirs.media_dir) / "documents")
install_document_samples(Path(self.dirs.media_dir) / "documents") shutil.copytree(
Path(__file__).parent / "samples" / "documents",
Path(self.dirs.media_dir) / "documents",
)
manifest = self._do_export() manifest = self._do_export()
@@ -512,7 +529,10 @@ class TestExportImport(
@override_settings(FILENAME_FORMAT="{title}/{correspondent}") @override_settings(FILENAME_FORMAT="{title}/{correspondent}")
def test_update_export_changed_location(self) -> None: def test_update_export_changed_location(self) -> None:
shutil.rmtree(Path(self.dirs.media_dir) / "documents") shutil.rmtree(Path(self.dirs.media_dir) / "documents")
install_document_samples(Path(self.dirs.media_dir) / "documents") shutil.copytree(
Path(__file__).parent / "samples" / "documents",
Path(self.dirs.media_dir) / "documents",
)
self._do_export(use_filename_format=True) self._do_export(use_filename_format=True)
self.assertIsFile(self.target / "wow1" / "c.pdf") self.assertIsFile(self.target / "wow1" / "c.pdf")
@@ -554,7 +574,10 @@ class TestExportImport(
- Zipfile contains exported files - Zipfile contains exported files
""" """
shutil.rmtree(Path(self.dirs.media_dir) / "documents") shutil.rmtree(Path(self.dirs.media_dir) / "documents")
install_document_samples(Path(self.dirs.media_dir) / "documents") shutil.copytree(
Path(__file__).parent / "samples" / "documents",
Path(self.dirs.media_dir) / "documents",
)
args = ["document_exporter", self.target, "--zip"] args = ["document_exporter", self.target, "--zip"]
@@ -583,7 +606,10 @@ class TestExportImport(
- Zipfile contains exported files - Zipfile contains exported files
""" """
shutil.rmtree(Path(self.dirs.media_dir) / "documents") shutil.rmtree(Path(self.dirs.media_dir) / "documents")
install_document_samples(Path(self.dirs.media_dir) / "documents") shutil.copytree(
Path(__file__).parent / "samples" / "documents",
Path(self.dirs.media_dir) / "documents",
)
args = ["document_exporter", self.target, "--zip", "--use-filename-format"] args = ["document_exporter", self.target, "--zip", "--use-filename-format"]
@@ -619,7 +645,10 @@ class TestExportImport(
- The existing file and directory in target are removed - The existing file and directory in target are removed
""" """
shutil.rmtree(Path(self.dirs.media_dir) / "documents") shutil.rmtree(Path(self.dirs.media_dir) / "documents")
install_document_samples(Path(self.dirs.media_dir) / "documents") shutil.copytree(
Path(__file__).parent / "samples" / "documents",
Path(self.dirs.media_dir) / "documents",
)
# Create stuff in target directory # Create stuff in target directory
existing_file = self.target / "test.txt" existing_file = self.target / "test.txt"
@@ -715,7 +744,10 @@ class TestExportImport(
- Documents can be imported again - Documents can be imported again
""" """
shutil.rmtree(Path(self.dirs.media_dir) / "documents") shutil.rmtree(Path(self.dirs.media_dir) / "documents")
install_document_samples(Path(self.dirs.media_dir) / "documents") shutil.copytree(
Path(__file__).parent / "samples" / "documents",
Path(self.dirs.media_dir) / "documents",
)
manifest = self._do_export() manifest = self._do_export()
has_archive = False has_archive = False
@@ -758,7 +790,10 @@ class TestExportImport(
- Documents can be imported again - Documents can be imported again
""" """
shutil.rmtree(Path(self.dirs.media_dir) / "documents") shutil.rmtree(Path(self.dirs.media_dir) / "documents")
install_document_samples(Path(self.dirs.media_dir) / "documents") shutil.copytree(
Path(__file__).parent / "samples" / "documents",
Path(self.dirs.media_dir) / "documents",
)
manifest = self._do_export() manifest = self._do_export()
has_thumbnail = False has_thumbnail = False
@@ -803,7 +838,10 @@ class TestExportImport(
- Documents can be imported again - Documents can be imported again
""" """
shutil.rmtree(Path(self.dirs.media_dir) / "documents") shutil.rmtree(Path(self.dirs.media_dir) / "documents")
install_document_samples(Path(self.dirs.media_dir) / "documents") shutil.copytree(
Path(__file__).parent / "samples" / "documents",
Path(self.dirs.media_dir) / "documents",
)
manifest = self._do_export(split_manifest=True) manifest = self._do_export(split_manifest=True)
has_document = False has_document = False
@@ -828,7 +866,10 @@ class TestExportImport(
def _export_import_barcodes(self, *, split_manifest: bool) -> None: def _export_import_barcodes(self, *, split_manifest: bool) -> None:
shutil.rmtree(Path(self.dirs.media_dir) / "documents") shutil.rmtree(Path(self.dirs.media_dir) / "documents")
install_document_samples(Path(self.dirs.media_dir) / "documents") shutil.copytree(
Path(__file__).parent / "samples" / "documents",
Path(self.dirs.media_dir) / "documents",
)
DocumentBarcodeFactory(document=self.d1, value="https://example.com") DocumentBarcodeFactory(document=self.d1, value="https://example.com")
DocumentBarcodeFactory(document=self.d2, page=2, value="DE8937") DocumentBarcodeFactory(document=self.d2, page=2, value="DE8937")
@@ -864,7 +905,10 @@ class TestExportImport(
- Documents can be imported again - Documents can be imported again
""" """
shutil.rmtree(Path(self.dirs.media_dir) / "documents") shutil.rmtree(Path(self.dirs.media_dir) / "documents")
install_document_samples(Path(self.dirs.media_dir) / "documents") shutil.copytree(
Path(__file__).parent / "samples" / "documents",
Path(self.dirs.media_dir) / "documents",
)
self._do_export(use_folder_prefix=True) self._do_export(use_folder_prefix=True)
@@ -891,7 +935,10 @@ class TestExportImport(
- Documents can be imported again - Documents can be imported again
""" """
shutil.rmtree(Path(self.dirs.media_dir) / "documents") shutil.rmtree(Path(self.dirs.media_dir) / "documents")
install_document_samples(Path(self.dirs.media_dir) / "documents") shutil.copytree(
Path(__file__).parent / "samples" / "documents",
Path(self.dirs.media_dir) / "documents",
)
self._do_export(use_folder_prefix=True, split_manifest=True) self._do_export(use_folder_prefix=True, split_manifest=True)
@@ -918,7 +965,10 @@ class TestExportImport(
""" """
shutil.rmtree(Path(self.dirs.media_dir) / "documents") shutil.rmtree(Path(self.dirs.media_dir) / "documents")
install_document_samples(Path(self.dirs.media_dir) / "documents") shutil.copytree(
Path(__file__).parent / "samples" / "documents",
Path(self.dirs.media_dir) / "documents",
)
num_content_type_objects = ContentType.objects.count() num_content_type_objects = ContentType.objects.count()
num_permission_objects = Permission.objects.count() num_permission_objects = Permission.objects.count()
@@ -955,7 +1005,10 @@ class TestExportImport(
def test_exporter_with_auditlog_disabled(self) -> None: def test_exporter_with_auditlog_disabled(self) -> None:
shutil.rmtree(Path(self.dirs.media_dir) / "documents") shutil.rmtree(Path(self.dirs.media_dir) / "documents")
install_document_samples(Path(self.dirs.media_dir) / "documents") shutil.copytree(
Path(__file__).parent / "samples" / "documents",
Path(self.dirs.media_dir) / "documents",
)
with override_settings( with override_settings(
AUDIT_LOG_ENABLED=False, AUDIT_LOG_ENABLED=False,
@@ -975,7 +1028,10 @@ class TestExportImport(
survive the round-trip with deleted_at preserved survive the round-trip with deleted_at preserved
""" """
shutil.rmtree(Path(self.dirs.media_dir) / "documents") shutil.rmtree(Path(self.dirs.media_dir) / "documents")
install_document_samples(Path(self.dirs.media_dir) / "documents") shutil.copytree(
Path(__file__).parent / "samples" / "documents",
Path(self.dirs.media_dir) / "documents",
)
# d1 has self.note and self.cfi1 attached via setUp # d1 has self.note and self.cfi1 attached via setUp
self.d1.delete() self.d1.delete()
@@ -1019,7 +1075,10 @@ class TestExportImport(
""" """
shutil.rmtree(self.dirs.media_dir / "documents") shutil.rmtree(self.dirs.media_dir / "documents")
install_document_samples(self.dirs.media_dir / "documents") shutil.copytree(
self.SAMPLE_DIR / "documents",
self.dirs.media_dir / "documents",
)
_ = self._do_export(data_only=True) _ = self._do_export(data_only=True)
@@ -11,7 +11,6 @@ from documents.models import Document
from documents.parsers import get_default_thumbnail from documents.parsers import get_default_thumbnail
from paperless_testing.assertions import FileSystemAssertsMixin from paperless_testing.assertions import FileSystemAssertsMixin
from paperless_testing.dirs import DirectoriesMixin from paperless_testing.dirs import DirectoriesMixin
from paperless_testing.samples import SIMPLE_DIGITAL_PDF
@pytest.mark.management @pytest.mark.management
@@ -25,7 +24,7 @@ class TestMakeThumbnails(DirectoriesMixin, FileSystemAssertsMixin, TestCase):
filename="test.pdf", filename="test.pdf",
) )
shutil.copy( shutil.copy(
SIMPLE_DIGITAL_PDF, Path(__file__).parent / "samples" / "simple.pdf",
self.d1.source_path, self.d1.source_path,
) )
@@ -37,7 +36,7 @@ class TestMakeThumbnails(DirectoriesMixin, FileSystemAssertsMixin, TestCase):
filename="test2.pdf", filename="test2.pdf",
) )
shutil.copy( shutil.copy(
SIMPLE_DIGITAL_PDF, Path(__file__).parent / "samples" / "simple.pdf",
self.d2.source_path, self.d2.source_path,
) )
+1 -2
View File
@@ -15,11 +15,10 @@ import pytest
from documents import pdf_ops from documents import pdf_ops
from documents.pdf_ops import PageSpec from documents.pdf_ops import PageSpec
from paperless_testing.samples import MULTI_PAGE_DIGITAL_PDF
SRC_ROOT = Path(__file__).parents[2] SRC_ROOT = Path(__file__).parents[2]
SAMPLES = Path(__file__).parent / "samples" SAMPLES = Path(__file__).parent / "samples"
THREE_PAGES = MULTI_PAGE_DIGITAL_PDF THREE_PAGES = SAMPLES / "documents" / "originals" / "0000002.pdf"
TWELVE_PAGES = SAMPLES / "barcodes" / "split-by-asn-2.pdf" TWELVE_PAGES = SAMPLES / "barcodes" / "split-by-asn-2.pdf"
ENCRYPTED = SAMPLES / "password-is-test.pdf" ENCRYPTED = SAMPLES / "password-is-test.pdf"
SIGNED = SRC_ROOT / "paperless" / "tests" / "samples" / "tesseract" / "signed.pdf" SIGNED = SRC_ROOT / "paperless" / "tests" / "samples" / "tesseract" / "signed.pdf"
+23 -5
View File
@@ -21,7 +21,6 @@ from documents.tests.helpers import dummy_preprocess
from paperless_testing.assertions import FileSystemAssertsMixin from paperless_testing.assertions import FileSystemAssertsMixin
from paperless_testing.dirs import DirectoriesMixin from paperless_testing.dirs import DirectoriesMixin
from paperless_testing.factories import DocumentFactory from paperless_testing.factories import DocumentFactory
from paperless_testing.samples import SIMPLE_DIGITAL_PDF
@pytest.mark.django_db @pytest.mark.django_db
@@ -230,12 +229,20 @@ class TestUpdateContent(DirectoriesMixin, TestCase):
""" """
sample1 = self.dirs.scratch_dir / "sample.pdf" sample1 = self.dirs.scratch_dir / "sample.pdf"
shutil.copy( shutil.copy(
SIMPLE_DIGITAL_PDF, Path(__file__).parent
/ "samples"
/ "documents"
/ "originals"
/ "0000001.pdf",
sample1, sample1,
) )
sample1_archive = self.dirs.archive_dir / "sample_archive.pdf" sample1_archive = self.dirs.archive_dir / "sample_archive.pdf"
shutil.copy( shutil.copy(
SIMPLE_DIGITAL_PDF, Path(__file__).parent
/ "samples"
/ "documents"
/ "originals"
/ "0000001.pdf",
sample1_archive, sample1_archive,
) )
doc = Document.objects.create( doc = Document.objects.create(
@@ -263,7 +270,11 @@ class TestUpdateContent(DirectoriesMixin, TestCase):
""" """
sample1 = self.dirs.scratch_dir / "sample.pdf" sample1 = self.dirs.scratch_dir / "sample.pdf"
shutil.copy( shutil.copy(
SIMPLE_DIGITAL_PDF, Path(__file__).parent
/ "samples"
/ "documents"
/ "originals"
/ "0000001.pdf",
sample1, sample1,
) )
doc = Document.objects.create( doc = Document.objects.create(
@@ -279,7 +290,14 @@ class TestUpdateContent(DirectoriesMixin, TestCase):
def _create_root_with_version(self) -> tuple[Document, Document]: def _create_root_with_version(self) -> tuple[Document, Document]:
sample1 = self.dirs.scratch_dir / "sample.pdf" sample1 = self.dirs.scratch_dir / "sample.pdf"
shutil.copy(SIMPLE_DIGITAL_PDF, sample1) shutil.copy(
Path(__file__).parent
/ "samples"
/ "documents"
/ "originals"
/ "0000001.pdf",
sample1,
)
root = DocumentFactory(content="root content", mime_type="application/pdf") root = DocumentFactory(content="root content", mime_type="application/pdf")
version = DocumentFactory( version = DocumentFactory(
content="my document", content="my document",
+27 -27
View File
@@ -178,7 +178,7 @@ class TestWorkflows(
self.assertEqual(action.__str__(), "WorkflowAction 1") self.assertEqual(action.__str__(), "WorkflowAction 1")
test_file = shutil.copy( test_file = shutil.copy(
self.SIMPLE_PDF, self.SAMPLE_DIR / "simple.pdf",
self.dirs.scratch_dir / "simple.pdf", self.dirs.scratch_dir / "simple.pdf",
) )
@@ -290,7 +290,7 @@ class TestWorkflows(
w.save() w.save()
test_file = shutil.copy( test_file = shutil.copy(
self.SIMPLE_PDF, self.SAMPLE_DIR / "simple.pdf",
self.dirs.scratch_dir / "simple.pdf", self.dirs.scratch_dir / "simple.pdf",
) )
@@ -409,7 +409,7 @@ class TestWorkflows(
w2.save() w2.save()
test_file = shutil.copy( test_file = shutil.copy(
self.SIMPLE_PDF, self.SAMPLE_DIR / "simple.pdf",
self.dirs.scratch_dir / "simple.pdf", self.dirs.scratch_dir / "simple.pdf",
) )
@@ -478,7 +478,7 @@ class TestWorkflows(
w.save() w.save()
test_file = shutil.copy( test_file = shutil.copy(
self.SIMPLE_PDF, self.SAMPLE_DIR / "simple.pdf",
self.dirs.scratch_dir / "simple.pdf", self.dirs.scratch_dir / "simple.pdf",
) )
@@ -531,7 +531,7 @@ class TestWorkflows(
w.save() w.save()
test_file = shutil.copy( test_file = shutil.copy(
self.SIMPLE_PDF, self.SAMPLE_DIR / "simple.pdf",
self.dirs.scratch_dir / "simple.pdf", self.dirs.scratch_dir / "simple.pdf",
) )
@@ -608,7 +608,7 @@ class TestWorkflows(
w.save() w.save()
test_file = shutil.copy( test_file = shutil.copy(
self.SIMPLE_PDF, self.SAMPLE_DIR / "simple.pdf",
self.dirs.scratch_dir / "simple.pdf", self.dirs.scratch_dir / "simple.pdf",
) )
@@ -687,7 +687,7 @@ class TestWorkflows(
w.save() w.save()
test_file = shutil.copy( test_file = shutil.copy(
self.SIMPLE_PDF, self.SAMPLE_DIR / "simple.pdf",
self.dirs.scratch_dir / "simple.pdf", self.dirs.scratch_dir / "simple.pdf",
) )
@@ -765,7 +765,7 @@ class TestWorkflows(
w.save() w.save()
test_file = shutil.copy( test_file = shutil.copy(
self.SIMPLE_PDF, self.SAMPLE_DIR / "simple.pdf",
self.dirs.scratch_dir / "simple.pdf", self.dirs.scratch_dir / "simple.pdf",
) )
@@ -876,7 +876,7 @@ class TestWorkflows(
w.save() w.save()
test_file = shutil.copy( test_file = shutil.copy(
self.SIMPLE_PDF, self.SAMPLE_DIR / "simple.pdf",
self.dirs.scratch_dir / "simple.pdf", self.dirs.scratch_dir / "simple.pdf",
) )
@@ -928,7 +928,7 @@ class TestWorkflows(
generated = generate_unique_filename(doc) generated = generate_unique_filename(doc)
destination = (settings.ORIGINALS_DIR / generated).resolve() destination = (settings.ORIGINALS_DIR / generated).resolve()
create_source_path_directory(destination) create_source_path_directory(destination)
shutil.copy(self.SIMPLE_PDF, destination) shutil.copy(self.SAMPLE_DIR / "simple.pdf", destination)
Document.objects.filter(pk=doc.pk).update(filename=generated.as_posix()) Document.objects.filter(pk=doc.pk).update(filename=generated.as_posix())
doc.refresh_from_db() doc.refresh_from_db()
@@ -2067,7 +2067,7 @@ class TestWorkflows(
superuser = UserFactory(username="superuser", superuser=True) superuser = UserFactory(username="superuser", superuser=True)
self.client.force_authenticate(user=superuser) self.client.force_authenticate(user=superuser)
test_file = shutil.copy( test_file = shutil.copy(
self.SIMPLE_PDF, self.SAMPLE_DIR / "simple.pdf",
self.dirs.scratch_dir / "simple.pdf", self.dirs.scratch_dir / "simple.pdf",
) )
tasks.consume_file( tasks.consume_file(
@@ -3053,7 +3053,7 @@ class TestWorkflows(
generated = generate_unique_filename(doc) generated = generate_unique_filename(doc)
destination = (settings.ORIGINALS_DIR / generated).resolve() destination = (settings.ORIGINALS_DIR / generated).resolve()
create_source_path_directory(destination) create_source_path_directory(destination)
shutil.copy(self.SIMPLE_PDF, destination) shutil.copy(self.SAMPLE_DIR / "simple.pdf", destination)
Document.objects.filter(pk=doc.pk).update(filename=generated.as_posix()) Document.objects.filter(pk=doc.pk).update(filename=generated.as_posix())
doc.refresh_from_db() doc.refresh_from_db()
doc.tags.set([self.t1, self.t2]) doc.tags.set([self.t1, self.t2])
@@ -3117,7 +3117,7 @@ class TestWorkflows(
generated = generate_unique_filename(doc) generated = generate_unique_filename(doc)
destination = (settings.ORIGINALS_DIR / generated).resolve() destination = (settings.ORIGINALS_DIR / generated).resolve()
create_source_path_directory(destination) create_source_path_directory(destination)
shutil.copy(self.SIMPLE_PDF, destination) shutil.copy(self.SAMPLE_DIR / "simple.pdf", destination)
Document.objects.filter(pk=doc.pk).update(filename=generated.as_posix()) Document.objects.filter(pk=doc.pk).update(filename=generated.as_posix())
doc.refresh_from_db() doc.refresh_from_db()
doc.tags.set([self.t1]) doc.tags.set([self.t1])
@@ -3266,7 +3266,7 @@ class TestWorkflows(
w.save() w.save()
test_file = shutil.copy( test_file = shutil.copy(
self.SIMPLE_PDF, self.SAMPLE_DIR / "simple.pdf",
self.dirs.scratch_dir / "simple.pdf", self.dirs.scratch_dir / "simple.pdf",
) )
@@ -3390,7 +3390,7 @@ class TestWorkflows(
w.save() w.save()
test_file = shutil.copy( test_file = shutil.copy(
self.SIMPLE_PDF, self.SAMPLE_DIR / "simple.pdf",
self.dirs.scratch_dir / "simple.pdf", self.dirs.scratch_dir / "simple.pdf",
) )
@@ -3540,7 +3540,7 @@ class TestWorkflows(
workflow.actions.set([assignment_action, email_action]) workflow.actions.set([assignment_action, email_action])
temp_working_copy = shutil.copy( temp_working_copy = shutil.copy(
self.SIMPLE_PDF, self.SAMPLE_DIR / "simple.pdf",
self.dirs.scratch_dir / "working-copy.pdf", self.dirs.scratch_dir / "working-copy.pdf",
) )
@@ -3640,7 +3640,7 @@ class TestWorkflows(
# move the file # move the file
test_file = shutil.copy( test_file = shutil.copy(
self.SIMPLE_PDF, self.SAMPLE_DIR / "simple.pdf",
self.dirs.scratch_dir / "simple.pdf", self.dirs.scratch_dir / "simple.pdf",
) )
@@ -3748,7 +3748,7 @@ class TestWorkflows(
generated = generate_unique_filename(doc) generated = generate_unique_filename(doc)
destination = (settings.ORIGINALS_DIR / generated).resolve() destination = (settings.ORIGINALS_DIR / generated).resolve()
create_source_path_directory(destination) create_source_path_directory(destination)
shutil.copy(self.SIMPLE_PDF, destination) shutil.copy(self.SAMPLE_DIR / "simple.pdf", destination)
Document.objects.filter(pk=doc.pk).update(filename=generated.as_posix()) Document.objects.filter(pk=doc.pk).update(filename=generated.as_posix())
run_workflows(WorkflowTrigger.WorkflowTriggerType.DOCUMENT_UPDATED, doc) run_workflows(WorkflowTrigger.WorkflowTriggerType.DOCUMENT_UPDATED, doc)
@@ -3959,7 +3959,7 @@ class TestWorkflows(
w.save() w.save()
test_file = shutil.copy( test_file = shutil.copy(
self.SIMPLE_PDF, self.SAMPLE_DIR / "simple.pdf",
self.dirs.scratch_dir / "simple.pdf", self.dirs.scratch_dir / "simple.pdf",
) )
@@ -4080,7 +4080,7 @@ class TestWorkflows(
w.save() w.save()
test_file = shutil.copy( test_file = shutil.copy(
self.SIMPLE_PDF, self.SAMPLE_DIR / "simple.pdf",
self.dirs.scratch_dir / "simple.pdf", self.dirs.scratch_dir / "simple.pdf",
) )
@@ -4431,7 +4431,7 @@ class TestWorkflows(
w.save() w.save()
test_file = shutil.copy( test_file = shutil.copy(
self.SIMPLE_PDF, self.SAMPLE_DIR / "simple.pdf",
self.dirs.scratch_dir / "simple.pdf", self.dirs.scratch_dir / "simple.pdf",
) )
@@ -4879,7 +4879,7 @@ class TestWorkflows(
w.save() w.save()
test_file = shutil.copy( test_file = shutil.copy(
self.SIMPLE_PDF, self.SAMPLE_DIR / "simple.pdf",
self.dirs.scratch_dir / "simple.pdf", self.dirs.scratch_dir / "simple.pdf",
) )
@@ -5071,7 +5071,7 @@ class TestWorkflows(
# Create a test file to be consumed # Create a test file to be consumed
test_file = shutil.copy( test_file = shutil.copy(
self.SIMPLE_PDF, self.SAMPLE_DIR / "simple.pdf",
self.dirs.scratch_dir / "simple.pdf", self.dirs.scratch_dir / "simple.pdf",
) )
test_file_path = Path(test_file) test_file_path = Path(test_file)
@@ -5135,7 +5135,7 @@ class TestWorkflows(
# Create a test file to be consumed # Create a test file to be consumed
test_file = shutil.copy( test_file = shutil.copy(
self.SIMPLE_PDF, self.SAMPLE_DIR / "simple.pdf",
self.dirs.scratch_dir / "simple2.pdf", self.dirs.scratch_dir / "simple2.pdf",
) )
test_file_path = Path(test_file) test_file_path = Path(test_file)
@@ -5639,7 +5639,7 @@ class TestDateWorkflowLocalization(
) )
test_file = shutil.copy( test_file = shutil.copy(
self.SIMPLE_PDF, self.SAMPLE_DIR / "simple.pdf",
tmp_path / "simple.pdf", tmp_path / "simple.pdf",
) )
@@ -5706,7 +5706,7 @@ class TestRemoteOCRWorkflowAction(DirectoriesMixin, SampleDirMixin, APITestCase)
self._make_workflow(WorkflowTrigger.WorkflowTriggerType.CONSUMPTION) self._make_workflow(WorkflowTrigger.WorkflowTriggerType.CONSUMPTION)
test_file = shutil.copy( test_file = shutil.copy(
self.SIMPLE_PDF, self.SAMPLE_DIR / "simple.pdf",
self.dirs.scratch_dir / "simple.pdf", self.dirs.scratch_dir / "simple.pdf",
) )
overrides = DocumentMetadataOverrides() overrides = DocumentMetadataOverrides()
@@ -5924,7 +5924,7 @@ class TestApplyAISuggestionsWorkflowAction(
) )
test_file = shutil.copy( test_file = shutil.copy(
self.SIMPLE_PDF, self.SAMPLE_DIR / "simple.pdf",
self.dirs.scratch_dir / "simple.pdf", self.dirs.scratch_dir / "simple.pdf",
) )
-3
View File
@@ -11,7 +11,6 @@ from documents.data_models import ConsumableDocument
from documents.data_models import DocumentMetadataOverrides from documents.data_models import DocumentMetadataOverrides
from documents.data_models import DocumentSource from documents.data_models import DocumentSource
from paperless_testing.fakes.progress import FakeProgressManager from paperless_testing.fakes.progress import FakeProgressManager
from paperless_testing.samples import SIMPLE_DIGITAL_PDF
class ConsumeTaskMixin: class ConsumeTaskMixin:
@@ -54,8 +53,6 @@ class SampleDirMixin:
BARCODE_SAMPLE_DIR = SAMPLE_DIR / "barcodes" BARCODE_SAMPLE_DIR = SAMPLE_DIR / "barcodes"
SIMPLE_PDF = SIMPLE_DIGITAL_PDF
class GetConsumerMixin: class GetConsumerMixin:
@contextmanager @contextmanager
+73 -78
View File
@@ -5,7 +5,6 @@ import platform
import re import re
import tempfile import tempfile
import zipfile import zipfile
from collections import Counter
from collections import deque from collections import deque
from collections.abc import Callable from collections.abc import Callable
from datetime import datetime from datetime import datetime
@@ -169,6 +168,7 @@ from documents.permissions import PaperlessNotePermissions
from documents.permissions import PaperlessObjectPermissions from documents.permissions import PaperlessObjectPermissions
from documents.permissions import TrashPermissions from documents.permissions import TrashPermissions
from documents.permissions import ViewDocumentsPermissions from documents.permissions import ViewDocumentsPermissions
from documents.permissions import annotate_document_count_by_ids
from documents.permissions import annotate_document_count_for_related_queryset from documents.permissions import annotate_document_count_for_related_queryset
from documents.permissions import get_document_count_filter_for_user from documents.permissions import get_document_count_filter_for_user
from documents.permissions import get_permission_grantees from documents.permissions import get_permission_grantees
@@ -1022,83 +1022,71 @@ class DocumentViewSet(
"custom_field_", "custom_field_",
) )
# Matching document ids are looked up in the link tables in batches of this
# size: one literal IN (...) over every match is a multi-MB statement per
# relation and, on SQLite, exceeds the bound-parameter limit.
selection_data_link_batch_size = 10_000
def _get_selection_data_for_queryset(self, queryset): def _get_selection_data_for_queryset(self, queryset):
# The filtered queryset is evaluated once, as the page's own filter is, # Resolve once instead of once per model below. `queryset` can carry an
# and never wrapped in a subquery: re-deriving a join or a HAVING # arbitrarily expensive WHERE clause (user filters plus the permission
# (shared_by__id) per statement is very slow on some databases, and # filter); re-embedding it as a subquery inside 5 separate Count(...)
# regrouping the queryset by another column would miscount. # calls forces the database to re-evaluate that whole thing 5 times, and
# order_by() drops the default/user ordering, which only costs a sort. # -- for FK relations especially -- can defeat semi-join planning
correspondents: Counter = Counter() # entirely at scale. A concrete id list is cheap to reuse.
document_types: Counter = Counter() # order_by() drops the default/user ordering -- irrelevant for a plain
storage_paths: Counter = Counter() # id list, but left in place it forces a sort over the full filtered
document_ids: list[int] = [] # set before the ids can even be collected.
seen: set[int] = set() document_ids = list(queryset.order_by().values_list("pk", flat=True))
rows = queryset.order_by().values_list(
"pk", correspondents = Correspondent.objects.annotate(
"correspondent_id", document_count=Count(
"document_type_id", "documents",
"storage_path_id", filter=Q(documents__id__in=document_ids),
distinct=True,
),
)
document_types = DocumentType.objects.annotate(
document_count=Count(
"documents",
filter=Q(documents__id__in=document_ids),
distinct=True,
),
)
storage_paths = StoragePath.objects.annotate(
document_count=Count(
"documents",
filter=Q(documents__id__in=document_ids),
distinct=True,
),
)
# Tag and CustomField reach Document through an M2M/through-model table;
# a plain Count(filter=...) there is a much more expensive plan than the
# FK relations above once the bridge table is large -- see
# annotate_document_count_by_ids() for why.
tags = annotate_document_count_by_ids(
Tag.objects.all(),
through_model=Document.tags.through,
related_object_field="tag_id",
document_ids=document_ids,
)
custom_fields = annotate_document_count_by_ids(
CustomField.objects.all(),
through_model=CustomFieldInstance,
related_object_field="field_id",
document_ids=document_ids,
) )
for pk, correspondent, document_type, storage_path in rows:
# A filter can join, repeating a document row.
if pk in seen:
continue
seen.add(pk)
document_ids.append(pk)
# Documents without a value count under None, which selection()
# never looks up.
correspondents[correspondent] += 1
document_types[document_type] += 1
storage_paths[storage_path] += 1
def link_table_counts(link_model, field_name: str) -> Counter:
result: Counter = Counter()
batch_size = self.selection_data_link_batch_size
for start in range(0, len(document_ids), batch_size):
result.update(
dict(
link_model.objects.filter(
document_id__in=document_ids[start : start + batch_size],
)
.values_list(field_name)
.annotate(document_count=Count("document_id")),
),
)
return result
def selection(model, counts: Counter) -> list[dict[str, int]]:
# Every object is listed, with 0 for those with no matching document.
return [
{"id": pk, "document_count": counts.get(pk, 0)}
for pk in model.objects.values_list("pk", flat=True)
]
return { return {
"selected_correspondents": selection( "selected_correspondents": [
Correspondent, {"id": t.id, "document_count": t.document_count} for t in correspondents
correspondents, ],
), "selected_tags": [
"selected_tags": selection( {"id": t.id, "document_count": t.document_count} for t in tags
Tag, ],
link_table_counts(Document.tags.through, "tag_id"), "selected_document_types": [
), {"id": t.id, "document_count": t.document_count} for t in document_types
"selected_document_types": selection( ],
DocumentType, "selected_storage_paths": [
document_types, {"id": t.id, "document_count": t.document_count} for t in storage_paths
), ],
"selected_storage_paths": selection( "selected_custom_fields": [
StoragePath, {"id": t.id, "document_count": t.document_count} for t in custom_fields
storage_paths, ],
),
"selected_custom_fields": selection(
CustomField,
link_table_counts(CustomFieldInstance, "field_id"),
),
} }
@classmethod @classmethod
@@ -5279,7 +5267,9 @@ class CustomFieldViewSet(PermissionsAwareDocumentCountMixin, ModelViewSet[Custom
"migration_status": inline_serializer( "migration_status": inline_serializer(
name="MigrationStatus", name="MigrationStatus",
fields={ fields={
"latest_migration": serializers.CharField(), "latest_migration": serializers.CharField(
allow_null=True,
),
"unapplied_migrations": serializers.ListSerializer( "unapplied_migrations": serializers.ListSerializer(
child=serializers.CharField(), child=serializers.CharField(),
), ),
@@ -5354,6 +5344,8 @@ class SystemStatusView(PassUserMixin):
db_conn = connections["default"] db_conn = connections["default"]
db_url = str(db_conn.settings_dict["NAME"]) db_url = str(db_conn.settings_dict["NAME"])
db_error = None db_error = None
all_migrations: list[str] = []
applied_migrations: list[str] = []
try: try:
db_conn.ensure_connection() db_conn.ensure_connection()
@@ -5364,7 +5356,8 @@ class SystemStatusView(PassUserMixin):
f"{m.app}.{m.name}" f"{m.app}.{m.name}"
for m in MigrationRecorder.Migration.objects.all().order_by("id") for m in MigrationRecorder.Migration.objects.all().order_by("id")
] ]
except Exception as e: # pragma: no cover except Exception as e:
all_migrations = []
applied_migrations = [] applied_migrations = []
db_status = "ERROR" db_status = "ERROR"
logger.exception( logger.exception(
@@ -5560,7 +5553,9 @@ class SystemStatusView(PassUserMixin):
"status": db_status, "status": db_status,
"error": db_error, "error": db_error,
"migration_status": { "migration_status": {
"latest_migration": applied_migrations[-1], "latest_migration": (
applied_migrations[-1] if applied_migrations else None
),
"unapplied_migrations": [ "unapplied_migrations": [
m for m in all_migrations if m not in applied_migrations m for m in all_migrations if m not in applied_migrations
], ],
+68 -72
View File
@@ -2,8 +2,8 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: paperless-ngx\n" "Project-Id-Version: paperless-ngx\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-10-29 17:25+0000\n" "POT-Creation-Date: 2026-10-19 15:40+0000\n"
"PO-Revision-Date: 2026-10-29 17:27\n" "PO-Revision-Date: 2026-10-19 15:42\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Afrikaans\n" "Language-Team: Afrikaans\n"
"Language: af_ZA\n" "Language: af_ZA\n"
@@ -21,43 +21,39 @@ msgstr ""
msgid "Documents" msgid "Documents"
msgstr "Dokumente" msgstr "Dokumente"
#: documents/filters.py:337 #: documents/filters.py:464
msgid "Expected a date or a relative date such as \"today\" or \"in 30 days\"."
msgstr ""
#: documents/filters.py:513
msgid "Value must be valid JSON." msgid "Value must be valid JSON."
msgstr "Waarde moet geldige JSON wees." msgstr "Waarde moet geldige JSON wees."
#: documents/filters.py:534 #: documents/filters.py:483
msgid "Invalid custom field query expression" msgid "Invalid custom field query expression"
msgstr "Ongeldige gepasmaakte veldnavraaguitdrukking" msgstr "Ongeldige gepasmaakte veldnavraaguitdrukking"
#: documents/filters.py:544 #: documents/filters.py:493
msgid "Invalid expression list. Must be nonempty." msgid "Invalid expression list. Must be nonempty."
msgstr "Ongeldige uitdrukking lys. Moet nie leeg wees nie." msgstr "Ongeldige uitdrukking lys. Moet nie leeg wees nie."
#: documents/filters.py:565 #: documents/filters.py:514
msgid "Invalid logical operator {op!r}" msgid "Invalid logical operator {op!r}"
msgstr "Ongeldige logiese uitdrukking {op!r}" msgstr "Ongeldige logiese uitdrukking {op!r}"
#: documents/filters.py:579 #: documents/filters.py:528
msgid "Maximum number of query conditions exceeded." msgid "Maximum number of query conditions exceeded."
msgstr "" msgstr ""
#: documents/filters.py:643 #: documents/filters.py:592
msgid "{name!r} is not a valid custom field." msgid "{name!r} is not a valid custom field."
msgstr "" msgstr ""
#: documents/filters.py:680 #: documents/filters.py:629
msgid "{data_type} does not support query expr {expr!r}." msgid "{data_type} does not support query expr {expr!r}."
msgstr "" msgstr ""
#: documents/filters.py:801 documents/models.py:137 #: documents/filters.py:748 documents/models.py:137
msgid "Maximum nesting depth exceeded." msgid "Maximum nesting depth exceeded."
msgstr "" msgstr ""
#: documents/filters.py:1178 #: documents/filters.py:1125
msgid "Custom field not found" msgid "Custom field not found"
msgstr "" msgstr ""
@@ -1639,48 +1635,48 @@ msgstr ""
msgid "workflow runs" msgid "workflow runs"
msgstr "" msgstr ""
#: documents/serialisers.py:483 documents/serialisers.py:840 #: documents/serialisers.py:515 documents/serialisers.py:872
#: documents/serialisers.py:2872 documents/views.py:360 documents/views.py:2730 #: documents/serialisers.py:2902 documents/views.py:363 documents/views.py:2768
#: paperless_mail/serialisers.py:156 #: paperless_mail/serialisers.py:156
msgid "Insufficient permissions." msgid "Insufficient permissions."
msgstr "" msgstr ""
#: documents/serialisers.py:676 #: documents/serialisers.py:708
msgid "Invalid color." msgid "Invalid color."
msgstr "Ongeldige kleur." msgstr "Ongeldige kleur."
#: documents/serialisers.py:2339 #: documents/serialisers.py:2369
#, python-format #, python-format
msgid "File type %(type)s not supported" msgid "File type %(type)s not supported"
msgstr "Lêertipe %(type)s word nie ondersteun nie" msgstr "Lêertipe %(type)s word nie ondersteun nie"
#: documents/serialisers.py:2383 #: documents/serialisers.py:2413
#, python-format #, python-format
msgid "Custom field id must be an integer: %(id)s" msgid "Custom field id must be an integer: %(id)s"
msgstr "" msgstr ""
#: documents/serialisers.py:2390 #: documents/serialisers.py:2420
#, python-format #, python-format
msgid "Custom field with id %(id)s does not exist" msgid "Custom field with id %(id)s does not exist"
msgstr "" msgstr ""
#: documents/serialisers.py:2407 documents/serialisers.py:2417 #: documents/serialisers.py:2437 documents/serialisers.py:2447
msgid "Custom fields must be a list of integers or an object mapping ids to values." msgid "Custom fields must be a list of integers or an object mapping ids to values."
msgstr "" msgstr ""
#: documents/serialisers.py:2412 #: documents/serialisers.py:2442
msgid "Some custom fields don't exist or were specified twice." msgid "Some custom fields don't exist or were specified twice."
msgstr "" msgstr ""
#: documents/serialisers.py:2559 #: documents/serialisers.py:2589
msgid "Invalid variable detected." msgid "Invalid variable detected."
msgstr "Ongeldige veranderlike bespeur." msgstr "Ongeldige veranderlike bespeur."
#: documents/serialisers.py:2928 #: documents/serialisers.py:2958
msgid "Duplicate document identifiers are not allowed." msgid "Duplicate document identifiers are not allowed."
msgstr "" msgstr ""
#: documents/serialisers.py:2958 documents/views.py:4780 #: documents/serialisers.py:2988 documents/views.py:4816
#, python-format #, python-format
msgid "Documents not found: %(ids)s" msgid "Documents not found: %(ids)s"
msgstr "" msgstr ""
@@ -1920,40 +1916,40 @@ msgstr ""
msgid ", " msgid ", "
msgstr "" msgstr ""
#: documents/views.py:315 #: documents/views.py:318
msgid "Specify only one of text, title_search, query, or more_like_id." msgid "Specify only one of text, title_search, query, or more_like_id."
msgstr "" msgstr ""
#: documents/views.py:353 documents/views.py:2727 #: documents/views.py:356 documents/views.py:2765
msgid "Invalid more_like_id" msgid "Invalid more_like_id"
msgstr "" msgstr ""
#: documents/views.py:1665 #: documents/views.py:1703
msgid "Invalid AI configuration." msgid "Invalid AI configuration."
msgstr "" msgstr ""
#: documents/views.py:1676 #: documents/views.py:1714
msgid "AI backend request timed out." msgid "AI backend request timed out."
msgstr "" msgstr ""
#: documents/views.py:1688 #: documents/views.py:1726
msgid "AI backend rejected the request. Check logs for details." msgid "AI backend rejected the request. Check logs for details."
msgstr "" msgstr ""
#: documents/views.py:4796 #: documents/views.py:4832
#, python-format #, python-format
msgid "Insufficient permissions to share document %(id)s." msgid "Insufficient permissions to share document %(id)s."
msgstr "" msgstr ""
#: documents/views.py:4843 #: documents/views.py:4879
msgid "Bundle is already being processed." msgid "Bundle is already being processed."
msgstr "" msgstr ""
#: documents/views.py:4909 #: documents/views.py:4945
msgid "The share link bundle is still being prepared. Please try again later." msgid "The share link bundle is still being prepared. Please try again later."
msgstr "" msgstr ""
#: documents/views.py:4923 #: documents/views.py:4959
msgid "The share link bundle is unavailable." msgid "The share link bundle is unavailable."
msgstr "" msgstr ""
@@ -2245,151 +2241,151 @@ msgstr ""
msgid "paperless application settings" msgid "paperless application settings"
msgstr "" msgstr ""
#: paperless/settings/__init__.py:566 #: paperless/settings/__init__.py:562
msgid "English (US)" msgid "English (US)"
msgstr "Engels (VS)" msgstr "Engels (VS)"
#: paperless/settings/__init__.py:567 #: paperless/settings/__init__.py:563
msgid "Arabic" msgid "Arabic"
msgstr "Arabies" msgstr "Arabies"
#: paperless/settings/__init__.py:568 #: paperless/settings/__init__.py:564
msgid "Afrikaans" msgid "Afrikaans"
msgstr "" msgstr ""
#: paperless/settings/__init__.py:569 #: paperless/settings/__init__.py:565
msgid "Belarusian" msgid "Belarusian"
msgstr "Belorussies" msgstr "Belorussies"
#: paperless/settings/__init__.py:570 #: paperless/settings/__init__.py:566
msgid "Bulgarian" msgid "Bulgarian"
msgstr "" msgstr ""
#: paperless/settings/__init__.py:571 #: paperless/settings/__init__.py:567
msgid "Catalan" msgid "Catalan"
msgstr "Katalaans" msgstr "Katalaans"
#: paperless/settings/__init__.py:572 #: paperless/settings/__init__.py:568
msgid "Czech" msgid "Czech"
msgstr "Tsjeggies" msgstr "Tsjeggies"
#: paperless/settings/__init__.py:573 #: paperless/settings/__init__.py:569
msgid "Danish" msgid "Danish"
msgstr "Deens" msgstr "Deens"
#: paperless/settings/__init__.py:574 #: paperless/settings/__init__.py:570
msgid "German" msgid "German"
msgstr "Duits" msgstr "Duits"
#: paperless/settings/__init__.py:575 #: paperless/settings/__init__.py:571
msgid "Greek" msgid "Greek"
msgstr "" msgstr ""
#: paperless/settings/__init__.py:576 #: paperless/settings/__init__.py:572
msgid "English (GB)" msgid "English (GB)"
msgstr "Engels (GB)" msgstr "Engels (GB)"
#: paperless/settings/__init__.py:577 #: paperless/settings/__init__.py:573
msgid "Spanish" msgid "Spanish"
msgstr "Spaans" msgstr "Spaans"
#: paperless/settings/__init__.py:578 #: paperless/settings/__init__.py:574
msgid "Persian" msgid "Persian"
msgstr "" msgstr ""
#: paperless/settings/__init__.py:579 #: paperless/settings/__init__.py:575
msgid "Finnish" msgid "Finnish"
msgstr "Fins" msgstr "Fins"
#: paperless/settings/__init__.py:580 #: paperless/settings/__init__.py:576
msgid "French" msgid "French"
msgstr "Frans" msgstr "Frans"
#: paperless/settings/__init__.py:581 #: paperless/settings/__init__.py:577
msgid "Hungarian" msgid "Hungarian"
msgstr "" msgstr ""
#: paperless/settings/__init__.py:582 #: paperless/settings/__init__.py:578
msgid "Indonesian" msgid "Indonesian"
msgstr "" msgstr ""
#: paperless/settings/__init__.py:583 #: paperless/settings/__init__.py:579
msgid "Italian" msgid "Italian"
msgstr "Italiaans" msgstr "Italiaans"
#: paperless/settings/__init__.py:584 #: paperless/settings/__init__.py:580
msgid "Japanese" msgid "Japanese"
msgstr "" msgstr ""
#: paperless/settings/__init__.py:585 #: paperless/settings/__init__.py:581
msgid "Korean" msgid "Korean"
msgstr "" msgstr ""
#: paperless/settings/__init__.py:586 #: paperless/settings/__init__.py:582
msgid "Luxembourgish" msgid "Luxembourgish"
msgstr "Luxemburgs" msgstr "Luxemburgs"
#: paperless/settings/__init__.py:587 #: paperless/settings/__init__.py:583
msgid "Norwegian" msgid "Norwegian"
msgstr "" msgstr ""
#: paperless/settings/__init__.py:588 #: paperless/settings/__init__.py:584
msgid "Dutch" msgid "Dutch"
msgstr "Nederlands" msgstr "Nederlands"
#: paperless/settings/__init__.py:589 #: paperless/settings/__init__.py:585
msgid "Polish" msgid "Polish"
msgstr "Pools" msgstr "Pools"
#: paperless/settings/__init__.py:590 #: paperless/settings/__init__.py:586
msgid "Portuguese (Brazil)" msgid "Portuguese (Brazil)"
msgstr "Portugees (Brasilië)" msgstr "Portugees (Brasilië)"
#: paperless/settings/__init__.py:591 #: paperless/settings/__init__.py:587
msgid "Portuguese" msgid "Portuguese"
msgstr "Portugees" msgstr "Portugees"
#: paperless/settings/__init__.py:592 #: paperless/settings/__init__.py:588
msgid "Romanian" msgid "Romanian"
msgstr "Roemeens" msgstr "Roemeens"
#: paperless/settings/__init__.py:593 #: paperless/settings/__init__.py:589
msgid "Russian" msgid "Russian"
msgstr "Russies" msgstr "Russies"
#: paperless/settings/__init__.py:594 #: paperless/settings/__init__.py:590
msgid "Slovak" msgid "Slovak"
msgstr "" msgstr ""
#: paperless/settings/__init__.py:595 #: paperless/settings/__init__.py:591
msgid "Slovenian" msgid "Slovenian"
msgstr "Sloweens" msgstr "Sloweens"
#: paperless/settings/__init__.py:596 #: paperless/settings/__init__.py:592
msgid "Serbian" msgid "Serbian"
msgstr "Serwies" msgstr "Serwies"
#: paperless/settings/__init__.py:597 #: paperless/settings/__init__.py:593
msgid "Swedish" msgid "Swedish"
msgstr "Sweeds" msgstr "Sweeds"
#: paperless/settings/__init__.py:598 #: paperless/settings/__init__.py:594
msgid "Turkish" msgid "Turkish"
msgstr "Turks" msgstr "Turks"
#: paperless/settings/__init__.py:599 #: paperless/settings/__init__.py:595
msgid "Ukrainian" msgid "Ukrainian"
msgstr "" msgstr ""
#: paperless/settings/__init__.py:600 #: paperless/settings/__init__.py:596
msgid "Vietnamese" msgid "Vietnamese"
msgstr "" msgstr ""
#: paperless/settings/__init__.py:601 #: paperless/settings/__init__.py:597
msgid "Chinese Simplified" msgid "Chinese Simplified"
msgstr "Vereenvoudigde Sjinees" msgstr "Vereenvoudigde Sjinees"
#: paperless/settings/__init__.py:602 #: paperless/settings/__init__.py:598
msgid "Chinese Traditional" msgid "Chinese Traditional"
msgstr "" msgstr ""
+68 -72
View File
@@ -2,8 +2,8 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: paperless-ngx\n" "Project-Id-Version: paperless-ngx\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-10-29 17:25+0000\n" "POT-Creation-Date: 2026-10-19 15:40+0000\n"
"PO-Revision-Date: 2026-10-29 17:27\n" "PO-Revision-Date: 2026-10-19 15:42\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Amharic\n" "Language-Team: Amharic\n"
"Language: am_ET\n" "Language: am_ET\n"
@@ -21,43 +21,39 @@ msgstr ""
msgid "Documents" msgid "Documents"
msgstr "መዝገባት" msgstr "መዝገባት"
#: documents/filters.py:337 #: documents/filters.py:464
msgid "Expected a date or a relative date such as \"today\" or \"in 30 days\"."
msgstr ""
#: documents/filters.py:513
msgid "Value must be valid JSON." msgid "Value must be valid JSON."
msgstr "የሚሰራው እሴት \"JSON\" መሆን አለበት" msgstr "የሚሰራው እሴት \"JSON\" መሆን አለበት"
#: documents/filters.py:534 #: documents/filters.py:483
msgid "Invalid custom field query expression" msgid "Invalid custom field query expression"
msgstr "ልክ ያልሆነ የተወሰነ የቦታ መጠይቅ አገላለጽ" msgstr "ልክ ያልሆነ የተወሰነ የቦታ መጠይቅ አገላለጽ"
#: documents/filters.py:544 #: documents/filters.py:493
msgid "Invalid expression list. Must be nonempty." msgid "Invalid expression list. Must be nonempty."
msgstr "ልክ ያልሆነ የመግለጫ ዝርዝር። ባዶ መሆን የለበትም።" msgstr "ልክ ያልሆነ የመግለጫ ዝርዝር። ባዶ መሆን የለበትም።"
#: documents/filters.py:565 #: documents/filters.py:514
msgid "Invalid logical operator {op!r}" msgid "Invalid logical operator {op!r}"
msgstr "ልክ ያልሆነ የሎጂክ ኦፕሬተር {op!r}" msgstr "ልክ ያልሆነ የሎጂክ ኦፕሬተር {op!r}"
#: documents/filters.py:579 #: documents/filters.py:528
msgid "Maximum number of query conditions exceeded." msgid "Maximum number of query conditions exceeded."
msgstr "ከፍተኛው የጥያቄ ሁኔታዎች/መጠን ብዛት አልፏል።" msgstr "ከፍተኛው የጥያቄ ሁኔታዎች/መጠን ብዛት አልፏል።"
#: documents/filters.py:643 #: documents/filters.py:592
msgid "{name!r} is not a valid custom field." msgid "{name!r} is not a valid custom field."
msgstr "{name!r} ይሄ ታዐማኒነት ያለው ልማድ አይደለም።" msgstr "{name!r} ይሄ ታዐማኒነት ያለው ልማድ አይደለም።"
#: documents/filters.py:680 #: documents/filters.py:629
msgid "{data_type} does not support query expr {expr!r}." msgid "{data_type} does not support query expr {expr!r}."
msgstr "ጥያቄን አይደግፍም expr {expr!r}." msgstr "ጥያቄን አይደግፍም expr {expr!r}."
#: documents/filters.py:801 documents/models.py:137 #: documents/filters.py:748 documents/models.py:137
msgid "Maximum nesting depth exceeded." msgid "Maximum nesting depth exceeded."
msgstr "ከፍተኛው የጥገኝነት ጥልቀት አልፏል።" msgstr "ከፍተኛው የጥገኝነት ጥልቀት አልፏል።"
#: documents/filters.py:1178 #: documents/filters.py:1125
msgid "Custom field not found" msgid "Custom field not found"
msgstr "ይህ ልማድ አልተገኘም" msgstr "ይህ ልማድ አልተገኘም"
@@ -1639,48 +1635,48 @@ msgstr ""
msgid "workflow runs" msgid "workflow runs"
msgstr "" msgstr ""
#: documents/serialisers.py:483 documents/serialisers.py:840 #: documents/serialisers.py:515 documents/serialisers.py:872
#: documents/serialisers.py:2872 documents/views.py:360 documents/views.py:2730 #: documents/serialisers.py:2902 documents/views.py:363 documents/views.py:2768
#: paperless_mail/serialisers.py:156 #: paperless_mail/serialisers.py:156
msgid "Insufficient permissions." msgid "Insufficient permissions."
msgstr "" msgstr ""
#: documents/serialisers.py:676 #: documents/serialisers.py:708
msgid "Invalid color." msgid "Invalid color."
msgstr "" msgstr ""
#: documents/serialisers.py:2339 #: documents/serialisers.py:2369
#, python-format #, python-format
msgid "File type %(type)s not supported" msgid "File type %(type)s not supported"
msgstr "" msgstr ""
#: documents/serialisers.py:2383 #: documents/serialisers.py:2413
#, python-format #, python-format
msgid "Custom field id must be an integer: %(id)s" msgid "Custom field id must be an integer: %(id)s"
msgstr "" msgstr ""
#: documents/serialisers.py:2390 #: documents/serialisers.py:2420
#, python-format #, python-format
msgid "Custom field with id %(id)s does not exist" msgid "Custom field with id %(id)s does not exist"
msgstr "" msgstr ""
#: documents/serialisers.py:2407 documents/serialisers.py:2417 #: documents/serialisers.py:2437 documents/serialisers.py:2447
msgid "Custom fields must be a list of integers or an object mapping ids to values." msgid "Custom fields must be a list of integers or an object mapping ids to values."
msgstr "" msgstr ""
#: documents/serialisers.py:2412 #: documents/serialisers.py:2442
msgid "Some custom fields don't exist or were specified twice." msgid "Some custom fields don't exist or were specified twice."
msgstr "" msgstr ""
#: documents/serialisers.py:2559 #: documents/serialisers.py:2589
msgid "Invalid variable detected." msgid "Invalid variable detected."
msgstr "" msgstr ""
#: documents/serialisers.py:2928 #: documents/serialisers.py:2958
msgid "Duplicate document identifiers are not allowed." msgid "Duplicate document identifiers are not allowed."
msgstr "" msgstr ""
#: documents/serialisers.py:2958 documents/views.py:4780 #: documents/serialisers.py:2988 documents/views.py:4816
#, python-format #, python-format
msgid "Documents not found: %(ids)s" msgid "Documents not found: %(ids)s"
msgstr "" msgstr ""
@@ -1920,40 +1916,40 @@ msgstr ""
msgid ", " msgid ", "
msgstr "" msgstr ""
#: documents/views.py:315 #: documents/views.py:318
msgid "Specify only one of text, title_search, query, or more_like_id." msgid "Specify only one of text, title_search, query, or more_like_id."
msgstr "" msgstr ""
#: documents/views.py:353 documents/views.py:2727 #: documents/views.py:356 documents/views.py:2765
msgid "Invalid more_like_id" msgid "Invalid more_like_id"
msgstr "" msgstr ""
#: documents/views.py:1665 #: documents/views.py:1703
msgid "Invalid AI configuration." msgid "Invalid AI configuration."
msgstr "" msgstr ""
#: documents/views.py:1676 #: documents/views.py:1714
msgid "AI backend request timed out." msgid "AI backend request timed out."
msgstr "" msgstr ""
#: documents/views.py:1688 #: documents/views.py:1726
msgid "AI backend rejected the request. Check logs for details." msgid "AI backend rejected the request. Check logs for details."
msgstr "" msgstr ""
#: documents/views.py:4796 #: documents/views.py:4832
#, python-format #, python-format
msgid "Insufficient permissions to share document %(id)s." msgid "Insufficient permissions to share document %(id)s."
msgstr "" msgstr ""
#: documents/views.py:4843 #: documents/views.py:4879
msgid "Bundle is already being processed." msgid "Bundle is already being processed."
msgstr "" msgstr ""
#: documents/views.py:4909 #: documents/views.py:4945
msgid "The share link bundle is still being prepared. Please try again later." msgid "The share link bundle is still being prepared. Please try again later."
msgstr "" msgstr ""
#: documents/views.py:4923 #: documents/views.py:4959
msgid "The share link bundle is unavailable." msgid "The share link bundle is unavailable."
msgstr "" msgstr ""
@@ -2245,151 +2241,151 @@ msgstr ""
msgid "paperless application settings" msgid "paperless application settings"
msgstr "" msgstr ""
#: paperless/settings/__init__.py:566 #: paperless/settings/__init__.py:562
msgid "English (US)" msgid "English (US)"
msgstr "" msgstr ""
#: paperless/settings/__init__.py:567 #: paperless/settings/__init__.py:563
msgid "Arabic" msgid "Arabic"
msgstr "" msgstr ""
#: paperless/settings/__init__.py:568 #: paperless/settings/__init__.py:564
msgid "Afrikaans" msgid "Afrikaans"
msgstr "" msgstr ""
#: paperless/settings/__init__.py:569 #: paperless/settings/__init__.py:565
msgid "Belarusian" msgid "Belarusian"
msgstr "" msgstr ""
#: paperless/settings/__init__.py:570 #: paperless/settings/__init__.py:566
msgid "Bulgarian" msgid "Bulgarian"
msgstr "" msgstr ""
#: paperless/settings/__init__.py:571 #: paperless/settings/__init__.py:567
msgid "Catalan" msgid "Catalan"
msgstr "" msgstr ""
#: paperless/settings/__init__.py:572 #: paperless/settings/__init__.py:568
msgid "Czech" msgid "Czech"
msgstr "" msgstr ""
#: paperless/settings/__init__.py:573 #: paperless/settings/__init__.py:569
msgid "Danish" msgid "Danish"
msgstr "" msgstr ""
#: paperless/settings/__init__.py:574 #: paperless/settings/__init__.py:570
msgid "German" msgid "German"
msgstr "" msgstr ""
#: paperless/settings/__init__.py:575 #: paperless/settings/__init__.py:571
msgid "Greek" msgid "Greek"
msgstr "" msgstr ""
#: paperless/settings/__init__.py:576 #: paperless/settings/__init__.py:572
msgid "English (GB)" msgid "English (GB)"
msgstr "" msgstr ""
#: paperless/settings/__init__.py:577 #: paperless/settings/__init__.py:573
msgid "Spanish" msgid "Spanish"
msgstr "" msgstr ""
#: paperless/settings/__init__.py:578 #: paperless/settings/__init__.py:574
msgid "Persian" msgid "Persian"
msgstr "" msgstr ""
#: paperless/settings/__init__.py:579 #: paperless/settings/__init__.py:575
msgid "Finnish" msgid "Finnish"
msgstr "" msgstr ""
#: paperless/settings/__init__.py:580 #: paperless/settings/__init__.py:576
msgid "French" msgid "French"
msgstr "" msgstr ""
#: paperless/settings/__init__.py:581 #: paperless/settings/__init__.py:577
msgid "Hungarian" msgid "Hungarian"
msgstr "" msgstr ""
#: paperless/settings/__init__.py:582 #: paperless/settings/__init__.py:578
msgid "Indonesian" msgid "Indonesian"
msgstr "" msgstr ""
#: paperless/settings/__init__.py:583 #: paperless/settings/__init__.py:579
msgid "Italian" msgid "Italian"
msgstr "" msgstr ""
#: paperless/settings/__init__.py:584 #: paperless/settings/__init__.py:580
msgid "Japanese" msgid "Japanese"
msgstr "" msgstr ""
#: paperless/settings/__init__.py:585 #: paperless/settings/__init__.py:581
msgid "Korean" msgid "Korean"
msgstr "" msgstr ""
#: paperless/settings/__init__.py:586 #: paperless/settings/__init__.py:582
msgid "Luxembourgish" msgid "Luxembourgish"
msgstr "" msgstr ""
#: paperless/settings/__init__.py:587 #: paperless/settings/__init__.py:583
msgid "Norwegian" msgid "Norwegian"
msgstr "" msgstr ""
#: paperless/settings/__init__.py:588 #: paperless/settings/__init__.py:584
msgid "Dutch" msgid "Dutch"
msgstr "" msgstr ""
#: paperless/settings/__init__.py:589 #: paperless/settings/__init__.py:585
msgid "Polish" msgid "Polish"
msgstr "" msgstr ""
#: paperless/settings/__init__.py:590 #: paperless/settings/__init__.py:586
msgid "Portuguese (Brazil)" msgid "Portuguese (Brazil)"
msgstr "" msgstr ""
#: paperless/settings/__init__.py:591 #: paperless/settings/__init__.py:587
msgid "Portuguese" msgid "Portuguese"
msgstr "" msgstr ""
#: paperless/settings/__init__.py:592 #: paperless/settings/__init__.py:588
msgid "Romanian" msgid "Romanian"
msgstr "" msgstr ""
#: paperless/settings/__init__.py:593 #: paperless/settings/__init__.py:589
msgid "Russian" msgid "Russian"
msgstr "" msgstr ""
#: paperless/settings/__init__.py:594 #: paperless/settings/__init__.py:590
msgid "Slovak" msgid "Slovak"
msgstr "" msgstr ""
#: paperless/settings/__init__.py:595 #: paperless/settings/__init__.py:591
msgid "Slovenian" msgid "Slovenian"
msgstr "" msgstr ""
#: paperless/settings/__init__.py:596 #: paperless/settings/__init__.py:592
msgid "Serbian" msgid "Serbian"
msgstr "" msgstr ""
#: paperless/settings/__init__.py:597 #: paperless/settings/__init__.py:593
msgid "Swedish" msgid "Swedish"
msgstr "" msgstr ""
#: paperless/settings/__init__.py:598 #: paperless/settings/__init__.py:594
msgid "Turkish" msgid "Turkish"
msgstr "" msgstr ""
#: paperless/settings/__init__.py:599 #: paperless/settings/__init__.py:595
msgid "Ukrainian" msgid "Ukrainian"
msgstr "" msgstr ""
#: paperless/settings/__init__.py:600 #: paperless/settings/__init__.py:596
msgid "Vietnamese" msgid "Vietnamese"
msgstr "" msgstr ""
#: paperless/settings/__init__.py:601 #: paperless/settings/__init__.py:597
msgid "Chinese Simplified" msgid "Chinese Simplified"
msgstr "" msgstr ""
#: paperless/settings/__init__.py:602 #: paperless/settings/__init__.py:598
msgid "Chinese Traditional" msgid "Chinese Traditional"
msgstr "" msgstr ""
+68 -72
View File
@@ -2,8 +2,8 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: paperless-ngx\n" "Project-Id-Version: paperless-ngx\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-10-29 17:25+0000\n" "POT-Creation-Date: 2026-10-19 15:40+0000\n"
"PO-Revision-Date: 2026-10-29 17:27\n" "PO-Revision-Date: 2026-10-19 15:42\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Arabic\n" "Language-Team: Arabic\n"
"Language: ar_SA\n" "Language: ar_SA\n"
@@ -21,43 +21,39 @@ msgstr ""
msgid "Documents" msgid "Documents"
msgstr "المستندات" msgstr "المستندات"
#: documents/filters.py:337 #: documents/filters.py:464
msgid "Expected a date or a relative date such as \"today\" or \"in 30 days\"."
msgstr ""
#: documents/filters.py:513
msgid "Value must be valid JSON." msgid "Value must be valid JSON."
msgstr "يجب أن تكون القيمة JSON." msgstr "يجب أن تكون القيمة JSON."
#: documents/filters.py:534 #: documents/filters.py:483
msgid "Invalid custom field query expression" msgid "Invalid custom field query expression"
msgstr "تعبير استعلام غير صالح للحقول المخصصة" msgstr "تعبير استعلام غير صالح للحقول المخصصة"
#: documents/filters.py:544 #: documents/filters.py:493
msgid "Invalid expression list. Must be nonempty." msgid "Invalid expression list. Must be nonempty."
msgstr "قائمة عبارة خاطئة." msgstr "قائمة عبارة خاطئة."
#: documents/filters.py:565 #: documents/filters.py:514
msgid "Invalid logical operator {op!r}" msgid "Invalid logical operator {op!r}"
msgstr "" msgstr ""
#: documents/filters.py:579 #: documents/filters.py:528
msgid "Maximum number of query conditions exceeded." msgid "Maximum number of query conditions exceeded."
msgstr "تجاوز الحد الأقصى لعدد شروط الاستعلام." msgstr "تجاوز الحد الأقصى لعدد شروط الاستعلام."
#: documents/filters.py:643 #: documents/filters.py:592
msgid "{name!r} is not a valid custom field." msgid "{name!r} is not a valid custom field."
msgstr "{name!r} حقل مخصص غير صالح." msgstr "{name!r} حقل مخصص غير صالح."
#: documents/filters.py:680 #: documents/filters.py:629
msgid "{data_type} does not support query expr {expr!r}." msgid "{data_type} does not support query expr {expr!r}."
msgstr "{data_type} لا يدعم تعبير الاستعلام {expr!r}." msgstr "{data_type} لا يدعم تعبير الاستعلام {expr!r}."
#: documents/filters.py:801 documents/models.py:137 #: documents/filters.py:748 documents/models.py:137
msgid "Maximum nesting depth exceeded." msgid "Maximum nesting depth exceeded."
msgstr "" msgstr ""
#: documents/filters.py:1178 #: documents/filters.py:1125
msgid "Custom field not found" msgid "Custom field not found"
msgstr "لم يتم العثور على حقل مخصص" msgstr "لم يتم العثور على حقل مخصص"
@@ -1639,48 +1635,48 @@ msgstr ""
msgid "workflow runs" msgid "workflow runs"
msgstr "" msgstr ""
#: documents/serialisers.py:483 documents/serialisers.py:840 #: documents/serialisers.py:515 documents/serialisers.py:872
#: documents/serialisers.py:2872 documents/views.py:360 documents/views.py:2730 #: documents/serialisers.py:2902 documents/views.py:363 documents/views.py:2768
#: paperless_mail/serialisers.py:156 #: paperless_mail/serialisers.py:156
msgid "Insufficient permissions." msgid "Insufficient permissions."
msgstr "" msgstr ""
#: documents/serialisers.py:676 #: documents/serialisers.py:708
msgid "Invalid color." msgid "Invalid color."
msgstr "لون خاطئ." msgstr "لون خاطئ."
#: documents/serialisers.py:2339 #: documents/serialisers.py:2369
#, python-format #, python-format
msgid "File type %(type)s not supported" msgid "File type %(type)s not supported"
msgstr "نوع الملف %(type)s غير مدعوم" msgstr "نوع الملف %(type)s غير مدعوم"
#: documents/serialisers.py:2383 #: documents/serialisers.py:2413
#, python-format #, python-format
msgid "Custom field id must be an integer: %(id)s" msgid "Custom field id must be an integer: %(id)s"
msgstr "" msgstr ""
#: documents/serialisers.py:2390 #: documents/serialisers.py:2420
#, python-format #, python-format
msgid "Custom field with id %(id)s does not exist" msgid "Custom field with id %(id)s does not exist"
msgstr "" msgstr ""
#: documents/serialisers.py:2407 documents/serialisers.py:2417 #: documents/serialisers.py:2437 documents/serialisers.py:2447
msgid "Custom fields must be a list of integers or an object mapping ids to values." msgid "Custom fields must be a list of integers or an object mapping ids to values."
msgstr "" msgstr ""
#: documents/serialisers.py:2412 #: documents/serialisers.py:2442
msgid "Some custom fields don't exist or were specified twice." msgid "Some custom fields don't exist or were specified twice."
msgstr "" msgstr ""
#: documents/serialisers.py:2559 #: documents/serialisers.py:2589
msgid "Invalid variable detected." msgid "Invalid variable detected."
msgstr "اكتشاف متغير خاطئ." msgstr "اكتشاف متغير خاطئ."
#: documents/serialisers.py:2928 #: documents/serialisers.py:2958
msgid "Duplicate document identifiers are not allowed." msgid "Duplicate document identifiers are not allowed."
msgstr "" msgstr ""
#: documents/serialisers.py:2958 documents/views.py:4780 #: documents/serialisers.py:2988 documents/views.py:4816
#, python-format #, python-format
msgid "Documents not found: %(ids)s" msgid "Documents not found: %(ids)s"
msgstr "" msgstr ""
@@ -1921,40 +1917,40 @@ msgstr "كخطوة أخيرة، يرجى ملء النموذج التالي:"
msgid ", " msgid ", "
msgstr "" msgstr ""
#: documents/views.py:315 #: documents/views.py:318
msgid "Specify only one of text, title_search, query, or more_like_id." msgid "Specify only one of text, title_search, query, or more_like_id."
msgstr "" msgstr ""
#: documents/views.py:353 documents/views.py:2727 #: documents/views.py:356 documents/views.py:2765
msgid "Invalid more_like_id" msgid "Invalid more_like_id"
msgstr "" msgstr ""
#: documents/views.py:1665 #: documents/views.py:1703
msgid "Invalid AI configuration." msgid "Invalid AI configuration."
msgstr "" msgstr ""
#: documents/views.py:1676 #: documents/views.py:1714
msgid "AI backend request timed out." msgid "AI backend request timed out."
msgstr "" msgstr ""
#: documents/views.py:1688 #: documents/views.py:1726
msgid "AI backend rejected the request. Check logs for details." msgid "AI backend rejected the request. Check logs for details."
msgstr "" msgstr ""
#: documents/views.py:4796 #: documents/views.py:4832
#, python-format #, python-format
msgid "Insufficient permissions to share document %(id)s." msgid "Insufficient permissions to share document %(id)s."
msgstr "" msgstr ""
#: documents/views.py:4843 #: documents/views.py:4879
msgid "Bundle is already being processed." msgid "Bundle is already being processed."
msgstr "" msgstr ""
#: documents/views.py:4909 #: documents/views.py:4945
msgid "The share link bundle is still being prepared. Please try again later." msgid "The share link bundle is still being prepared. Please try again later."
msgstr "" msgstr ""
#: documents/views.py:4923 #: documents/views.py:4959
msgid "The share link bundle is unavailable." msgid "The share link bundle is unavailable."
msgstr "" msgstr ""
@@ -2246,151 +2242,151 @@ msgstr ""
msgid "paperless application settings" msgid "paperless application settings"
msgstr "إعدادات التطبيق paperless" msgstr "إعدادات التطبيق paperless"
#: paperless/settings/__init__.py:566 #: paperless/settings/__init__.py:562
msgid "English (US)" msgid "English (US)"
msgstr "الإنجليزية (الولايات المتحدة)" msgstr "الإنجليزية (الولايات المتحدة)"
#: paperless/settings/__init__.py:567 #: paperless/settings/__init__.py:563
msgid "Arabic" msgid "Arabic"
msgstr "العربية" msgstr "العربية"
#: paperless/settings/__init__.py:568 #: paperless/settings/__init__.py:564
msgid "Afrikaans" msgid "Afrikaans"
msgstr "اللغة الأفريقانية" msgstr "اللغة الأفريقانية"
#: paperless/settings/__init__.py:569 #: paperless/settings/__init__.py:565
msgid "Belarusian" msgid "Belarusian"
msgstr "البيلاروسية" msgstr "البيلاروسية"
#: paperless/settings/__init__.py:570 #: paperless/settings/__init__.py:566
msgid "Bulgarian" msgid "Bulgarian"
msgstr "البلغارية" msgstr "البلغارية"
#: paperless/settings/__init__.py:571 #: paperless/settings/__init__.py:567
msgid "Catalan" msgid "Catalan"
msgstr "اللغة الكتالونية" msgstr "اللغة الكتالونية"
#: paperless/settings/__init__.py:572 #: paperless/settings/__init__.py:568
msgid "Czech" msgid "Czech"
msgstr "التشيكية" msgstr "التشيكية"
#: paperless/settings/__init__.py:573 #: paperless/settings/__init__.py:569
msgid "Danish" msgid "Danish"
msgstr "الدانماركية" msgstr "الدانماركية"
#: paperless/settings/__init__.py:574 #: paperless/settings/__init__.py:570
msgid "German" msgid "German"
msgstr "الألمانية" msgstr "الألمانية"
#: paperless/settings/__init__.py:575 #: paperless/settings/__init__.py:571
msgid "Greek" msgid "Greek"
msgstr "اليونانية" msgstr "اليونانية"
#: paperless/settings/__init__.py:576 #: paperless/settings/__init__.py:572
msgid "English (GB)" msgid "English (GB)"
msgstr "الإنجليزية (المملكة المتحدة)" msgstr "الإنجليزية (المملكة المتحدة)"
#: paperless/settings/__init__.py:577 #: paperless/settings/__init__.py:573
msgid "Spanish" msgid "Spanish"
msgstr "الإسبانية" msgstr "الإسبانية"
#: paperless/settings/__init__.py:578 #: paperless/settings/__init__.py:574
msgid "Persian" msgid "Persian"
msgstr "" msgstr ""
#: paperless/settings/__init__.py:579 #: paperless/settings/__init__.py:575
msgid "Finnish" msgid "Finnish"
msgstr "الفنلندية" msgstr "الفنلندية"
#: paperless/settings/__init__.py:580 #: paperless/settings/__init__.py:576
msgid "French" msgid "French"
msgstr "الفرنسية" msgstr "الفرنسية"
#: paperless/settings/__init__.py:581 #: paperless/settings/__init__.py:577
msgid "Hungarian" msgid "Hungarian"
msgstr "المجرية" msgstr "المجرية"
#: paperless/settings/__init__.py:582 #: paperless/settings/__init__.py:578
msgid "Indonesian" msgid "Indonesian"
msgstr "" msgstr ""
#: paperless/settings/__init__.py:583 #: paperless/settings/__init__.py:579
msgid "Italian" msgid "Italian"
msgstr "الإيطالية" msgstr "الإيطالية"
#: paperless/settings/__init__.py:584 #: paperless/settings/__init__.py:580
msgid "Japanese" msgid "Japanese"
msgstr "اليابانية" msgstr "اليابانية"
#: paperless/settings/__init__.py:585 #: paperless/settings/__init__.py:581
msgid "Korean" msgid "Korean"
msgstr "" msgstr ""
#: paperless/settings/__init__.py:586 #: paperless/settings/__init__.py:582
msgid "Luxembourgish" msgid "Luxembourgish"
msgstr "اللوكسمبرجية" msgstr "اللوكسمبرجية"
#: paperless/settings/__init__.py:587 #: paperless/settings/__init__.py:583
msgid "Norwegian" msgid "Norwegian"
msgstr "النرويجية" msgstr "النرويجية"
#: paperless/settings/__init__.py:588 #: paperless/settings/__init__.py:584
msgid "Dutch" msgid "Dutch"
msgstr "الهولندية" msgstr "الهولندية"
#: paperless/settings/__init__.py:589 #: paperless/settings/__init__.py:585
msgid "Polish" msgid "Polish"
msgstr "البولندية" msgstr "البولندية"
#: paperless/settings/__init__.py:590 #: paperless/settings/__init__.py:586
msgid "Portuguese (Brazil)" msgid "Portuguese (Brazil)"
msgstr "البرتغالية (البرازيل)" msgstr "البرتغالية (البرازيل)"
#: paperless/settings/__init__.py:591 #: paperless/settings/__init__.py:587
msgid "Portuguese" msgid "Portuguese"
msgstr "البرتغالية" msgstr "البرتغالية"
#: paperless/settings/__init__.py:592 #: paperless/settings/__init__.py:588
msgid "Romanian" msgid "Romanian"
msgstr "الرومانية" msgstr "الرومانية"
#: paperless/settings/__init__.py:593 #: paperless/settings/__init__.py:589
msgid "Russian" msgid "Russian"
msgstr "الروسية" msgstr "الروسية"
#: paperless/settings/__init__.py:594 #: paperless/settings/__init__.py:590
msgid "Slovak" msgid "Slovak"
msgstr "السلوفاكية" msgstr "السلوفاكية"
#: paperless/settings/__init__.py:595 #: paperless/settings/__init__.py:591
msgid "Slovenian" msgid "Slovenian"
msgstr "السلوفانية" msgstr "السلوفانية"
#: paperless/settings/__init__.py:596 #: paperless/settings/__init__.py:592
msgid "Serbian" msgid "Serbian"
msgstr "الصربية" msgstr "الصربية"
#: paperless/settings/__init__.py:597 #: paperless/settings/__init__.py:593
msgid "Swedish" msgid "Swedish"
msgstr "السويدية" msgstr "السويدية"
#: paperless/settings/__init__.py:598 #: paperless/settings/__init__.py:594
msgid "Turkish" msgid "Turkish"
msgstr "التركية" msgstr "التركية"
#: paperless/settings/__init__.py:599 #: paperless/settings/__init__.py:595
msgid "Ukrainian" msgid "Ukrainian"
msgstr "الأوكرانية" msgstr "الأوكرانية"
#: paperless/settings/__init__.py:600 #: paperless/settings/__init__.py:596
msgid "Vietnamese" msgid "Vietnamese"
msgstr "" msgstr ""
#: paperless/settings/__init__.py:601 #: paperless/settings/__init__.py:597
msgid "Chinese Simplified" msgid "Chinese Simplified"
msgstr "الصينية المبسطة" msgstr "الصينية المبسطة"
#: paperless/settings/__init__.py:602 #: paperless/settings/__init__.py:598
msgid "Chinese Traditional" msgid "Chinese Traditional"
msgstr "" msgstr ""
+68 -72
View File
@@ -2,8 +2,8 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: paperless-ngx\n" "Project-Id-Version: paperless-ngx\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-10-29 17:25+0000\n" "POT-Creation-Date: 2026-10-19 15:40+0000\n"
"PO-Revision-Date: 2026-10-29 17:27\n" "PO-Revision-Date: 2026-10-19 15:42\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Belarusian\n" "Language-Team: Belarusian\n"
"Language: be_BY\n" "Language: be_BY\n"
@@ -21,43 +21,39 @@ msgstr ""
msgid "Documents" msgid "Documents"
msgstr "Дакументы" msgstr "Дакументы"
#: documents/filters.py:337 #: documents/filters.py:464
msgid "Expected a date or a relative date such as \"today\" or \"in 30 days\"."
msgstr ""
#: documents/filters.py:513
msgid "Value must be valid JSON." msgid "Value must be valid JSON."
msgstr "" msgstr ""
#: documents/filters.py:534 #: documents/filters.py:483
msgid "Invalid custom field query expression" msgid "Invalid custom field query expression"
msgstr "" msgstr ""
#: documents/filters.py:544 #: documents/filters.py:493
msgid "Invalid expression list. Must be nonempty." msgid "Invalid expression list. Must be nonempty."
msgstr "" msgstr ""
#: documents/filters.py:565 #: documents/filters.py:514
msgid "Invalid logical operator {op!r}" msgid "Invalid logical operator {op!r}"
msgstr "" msgstr ""
#: documents/filters.py:579 #: documents/filters.py:528
msgid "Maximum number of query conditions exceeded." msgid "Maximum number of query conditions exceeded."
msgstr "" msgstr ""
#: documents/filters.py:643 #: documents/filters.py:592
msgid "{name!r} is not a valid custom field." msgid "{name!r} is not a valid custom field."
msgstr "" msgstr ""
#: documents/filters.py:680 #: documents/filters.py:629
msgid "{data_type} does not support query expr {expr!r}." msgid "{data_type} does not support query expr {expr!r}."
msgstr "" msgstr ""
#: documents/filters.py:801 documents/models.py:137 #: documents/filters.py:748 documents/models.py:137
msgid "Maximum nesting depth exceeded." msgid "Maximum nesting depth exceeded."
msgstr "" msgstr ""
#: documents/filters.py:1178 #: documents/filters.py:1125
msgid "Custom field not found" msgid "Custom field not found"
msgstr "" msgstr ""
@@ -1639,48 +1635,48 @@ msgstr ""
msgid "workflow runs" msgid "workflow runs"
msgstr "" msgstr ""
#: documents/serialisers.py:483 documents/serialisers.py:840 #: documents/serialisers.py:515 documents/serialisers.py:872
#: documents/serialisers.py:2872 documents/views.py:360 documents/views.py:2730 #: documents/serialisers.py:2902 documents/views.py:363 documents/views.py:2768
#: paperless_mail/serialisers.py:156 #: paperless_mail/serialisers.py:156
msgid "Insufficient permissions." msgid "Insufficient permissions."
msgstr "" msgstr ""
#: documents/serialisers.py:676 #: documents/serialisers.py:708
msgid "Invalid color." msgid "Invalid color."
msgstr "Няправільны колер." msgstr "Няправільны колер."
#: documents/serialisers.py:2339 #: documents/serialisers.py:2369
#, python-format #, python-format
msgid "File type %(type)s not supported" msgid "File type %(type)s not supported"
msgstr "Тып файла %(type)s не падтрымліваецца" msgstr "Тып файла %(type)s не падтрымліваецца"
#: documents/serialisers.py:2383 #: documents/serialisers.py:2413
#, python-format #, python-format
msgid "Custom field id must be an integer: %(id)s" msgid "Custom field id must be an integer: %(id)s"
msgstr "" msgstr ""
#: documents/serialisers.py:2390 #: documents/serialisers.py:2420
#, python-format #, python-format
msgid "Custom field with id %(id)s does not exist" msgid "Custom field with id %(id)s does not exist"
msgstr "" msgstr ""
#: documents/serialisers.py:2407 documents/serialisers.py:2417 #: documents/serialisers.py:2437 documents/serialisers.py:2447
msgid "Custom fields must be a list of integers or an object mapping ids to values." msgid "Custom fields must be a list of integers or an object mapping ids to values."
msgstr "" msgstr ""
#: documents/serialisers.py:2412 #: documents/serialisers.py:2442
msgid "Some custom fields don't exist or were specified twice." msgid "Some custom fields don't exist or were specified twice."
msgstr "" msgstr ""
#: documents/serialisers.py:2559 #: documents/serialisers.py:2589
msgid "Invalid variable detected." msgid "Invalid variable detected."
msgstr "Выяўлена няправільная зменная." msgstr "Выяўлена няправільная зменная."
#: documents/serialisers.py:2928 #: documents/serialisers.py:2958
msgid "Duplicate document identifiers are not allowed." msgid "Duplicate document identifiers are not allowed."
msgstr "" msgstr ""
#: documents/serialisers.py:2958 documents/views.py:4780 #: documents/serialisers.py:2988 documents/views.py:4816
#, python-format #, python-format
msgid "Documents not found: %(ids)s" msgid "Documents not found: %(ids)s"
msgstr "" msgstr ""
@@ -1920,40 +1916,40 @@ msgstr ""
msgid ", " msgid ", "
msgstr "" msgstr ""
#: documents/views.py:315 #: documents/views.py:318
msgid "Specify only one of text, title_search, query, or more_like_id." msgid "Specify only one of text, title_search, query, or more_like_id."
msgstr "" msgstr ""
#: documents/views.py:353 documents/views.py:2727 #: documents/views.py:356 documents/views.py:2765
msgid "Invalid more_like_id" msgid "Invalid more_like_id"
msgstr "" msgstr ""
#: documents/views.py:1665 #: documents/views.py:1703
msgid "Invalid AI configuration." msgid "Invalid AI configuration."
msgstr "" msgstr ""
#: documents/views.py:1676 #: documents/views.py:1714
msgid "AI backend request timed out." msgid "AI backend request timed out."
msgstr "" msgstr ""
#: documents/views.py:1688 #: documents/views.py:1726
msgid "AI backend rejected the request. Check logs for details." msgid "AI backend rejected the request. Check logs for details."
msgstr "" msgstr ""
#: documents/views.py:4796 #: documents/views.py:4832
#, python-format #, python-format
msgid "Insufficient permissions to share document %(id)s." msgid "Insufficient permissions to share document %(id)s."
msgstr "" msgstr ""
#: documents/views.py:4843 #: documents/views.py:4879
msgid "Bundle is already being processed." msgid "Bundle is already being processed."
msgstr "" msgstr ""
#: documents/views.py:4909 #: documents/views.py:4945
msgid "The share link bundle is still being prepared. Please try again later." msgid "The share link bundle is still being prepared. Please try again later."
msgstr "" msgstr ""
#: documents/views.py:4923 #: documents/views.py:4959
msgid "The share link bundle is unavailable." msgid "The share link bundle is unavailable."
msgstr "" msgstr ""
@@ -2245,151 +2241,151 @@ msgstr ""
msgid "paperless application settings" msgid "paperless application settings"
msgstr "" msgstr ""
#: paperless/settings/__init__.py:566 #: paperless/settings/__init__.py:562
msgid "English (US)" msgid "English (US)"
msgstr "Англійская (ЗША)" msgstr "Англійская (ЗША)"
#: paperless/settings/__init__.py:567 #: paperless/settings/__init__.py:563
msgid "Arabic" msgid "Arabic"
msgstr "" msgstr ""
#: paperless/settings/__init__.py:568 #: paperless/settings/__init__.py:564
msgid "Afrikaans" msgid "Afrikaans"
msgstr "" msgstr ""
#: paperless/settings/__init__.py:569 #: paperless/settings/__init__.py:565
msgid "Belarusian" msgid "Belarusian"
msgstr "Беларуская" msgstr "Беларуская"
#: paperless/settings/__init__.py:570 #: paperless/settings/__init__.py:566
msgid "Bulgarian" msgid "Bulgarian"
msgstr "" msgstr ""
#: paperless/settings/__init__.py:571 #: paperless/settings/__init__.py:567
msgid "Catalan" msgid "Catalan"
msgstr "" msgstr ""
#: paperless/settings/__init__.py:572 #: paperless/settings/__init__.py:568
msgid "Czech" msgid "Czech"
msgstr "Чэшская" msgstr "Чэшская"
#: paperless/settings/__init__.py:573 #: paperless/settings/__init__.py:569
msgid "Danish" msgid "Danish"
msgstr "Дацкая" msgstr "Дацкая"
#: paperless/settings/__init__.py:574 #: paperless/settings/__init__.py:570
msgid "German" msgid "German"
msgstr "Нямецкая" msgstr "Нямецкая"
#: paperless/settings/__init__.py:575 #: paperless/settings/__init__.py:571
msgid "Greek" msgid "Greek"
msgstr "" msgstr ""
#: paperless/settings/__init__.py:576 #: paperless/settings/__init__.py:572
msgid "English (GB)" msgid "English (GB)"
msgstr "Англійская (Вялікабрытанія)" msgstr "Англійская (Вялікабрытанія)"
#: paperless/settings/__init__.py:577 #: paperless/settings/__init__.py:573
msgid "Spanish" msgid "Spanish"
msgstr "Іспанская" msgstr "Іспанская"
#: paperless/settings/__init__.py:578 #: paperless/settings/__init__.py:574
msgid "Persian" msgid "Persian"
msgstr "" msgstr ""
#: paperless/settings/__init__.py:579 #: paperless/settings/__init__.py:575
msgid "Finnish" msgid "Finnish"
msgstr "" msgstr ""
#: paperless/settings/__init__.py:580 #: paperless/settings/__init__.py:576
msgid "French" msgid "French"
msgstr "Французская" msgstr "Французская"
#: paperless/settings/__init__.py:581 #: paperless/settings/__init__.py:577
msgid "Hungarian" msgid "Hungarian"
msgstr "" msgstr ""
#: paperless/settings/__init__.py:582 #: paperless/settings/__init__.py:578
msgid "Indonesian" msgid "Indonesian"
msgstr "" msgstr ""
#: paperless/settings/__init__.py:583 #: paperless/settings/__init__.py:579
msgid "Italian" msgid "Italian"
msgstr "Італьянская" msgstr "Італьянская"
#: paperless/settings/__init__.py:584 #: paperless/settings/__init__.py:580
msgid "Japanese" msgid "Japanese"
msgstr "" msgstr ""
#: paperless/settings/__init__.py:585 #: paperless/settings/__init__.py:581
msgid "Korean" msgid "Korean"
msgstr "" msgstr ""
#: paperless/settings/__init__.py:586 #: paperless/settings/__init__.py:582
msgid "Luxembourgish" msgid "Luxembourgish"
msgstr "Люксембургская" msgstr "Люксембургская"
#: paperless/settings/__init__.py:587 #: paperless/settings/__init__.py:583
msgid "Norwegian" msgid "Norwegian"
msgstr "" msgstr ""
#: paperless/settings/__init__.py:588 #: paperless/settings/__init__.py:584
msgid "Dutch" msgid "Dutch"
msgstr "Нідэрландская" msgstr "Нідэрландская"
#: paperless/settings/__init__.py:589 #: paperless/settings/__init__.py:585
msgid "Polish" msgid "Polish"
msgstr "Польская" msgstr "Польская"
#: paperless/settings/__init__.py:590 #: paperless/settings/__init__.py:586
msgid "Portuguese (Brazil)" msgid "Portuguese (Brazil)"
msgstr "Партугальская (Бразілія)" msgstr "Партугальская (Бразілія)"
#: paperless/settings/__init__.py:591 #: paperless/settings/__init__.py:587
msgid "Portuguese" msgid "Portuguese"
msgstr "Партугальская" msgstr "Партугальская"
#: paperless/settings/__init__.py:592 #: paperless/settings/__init__.py:588
msgid "Romanian" msgid "Romanian"
msgstr "Румынская" msgstr "Румынская"
#: paperless/settings/__init__.py:593 #: paperless/settings/__init__.py:589
msgid "Russian" msgid "Russian"
msgstr "Руская" msgstr "Руская"
#: paperless/settings/__init__.py:594 #: paperless/settings/__init__.py:590
msgid "Slovak" msgid "Slovak"
msgstr "" msgstr ""
#: paperless/settings/__init__.py:595 #: paperless/settings/__init__.py:591
msgid "Slovenian" msgid "Slovenian"
msgstr "Славенская" msgstr "Славенская"
#: paperless/settings/__init__.py:596 #: paperless/settings/__init__.py:592
msgid "Serbian" msgid "Serbian"
msgstr "Сербская" msgstr "Сербская"
#: paperless/settings/__init__.py:597 #: paperless/settings/__init__.py:593
msgid "Swedish" msgid "Swedish"
msgstr "Шведская" msgstr "Шведская"
#: paperless/settings/__init__.py:598 #: paperless/settings/__init__.py:594
msgid "Turkish" msgid "Turkish"
msgstr "Турэцкая" msgstr "Турэцкая"
#: paperless/settings/__init__.py:599 #: paperless/settings/__init__.py:595
msgid "Ukrainian" msgid "Ukrainian"
msgstr "" msgstr ""
#: paperless/settings/__init__.py:600 #: paperless/settings/__init__.py:596
msgid "Vietnamese" msgid "Vietnamese"
msgstr "" msgstr ""
#: paperless/settings/__init__.py:601 #: paperless/settings/__init__.py:597
msgid "Chinese Simplified" msgid "Chinese Simplified"
msgstr "Кітайская спрошчаная" msgstr "Кітайская спрошчаная"
#: paperless/settings/__init__.py:602 #: paperless/settings/__init__.py:598
msgid "Chinese Traditional" msgid "Chinese Traditional"
msgstr "" msgstr ""
+68 -72
View File
@@ -2,8 +2,8 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: paperless-ngx\n" "Project-Id-Version: paperless-ngx\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-10-29 17:25+0000\n" "POT-Creation-Date: 2026-10-19 15:40+0000\n"
"PO-Revision-Date: 2026-10-29 17:27\n" "PO-Revision-Date: 2026-10-19 15:42\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Bulgarian\n" "Language-Team: Bulgarian\n"
"Language: bg_BG\n" "Language: bg_BG\n"
@@ -21,43 +21,39 @@ msgstr ""
msgid "Documents" msgid "Documents"
msgstr "Документи" msgstr "Документи"
#: documents/filters.py:337 #: documents/filters.py:464
msgid "Expected a date or a relative date such as \"today\" or \"in 30 days\"."
msgstr ""
#: documents/filters.py:513
msgid "Value must be valid JSON." msgid "Value must be valid JSON."
msgstr "Стойността трябва да е валидна JSON." msgstr "Стойността трябва да е валидна JSON."
#: documents/filters.py:534 #: documents/filters.py:483
msgid "Invalid custom field query expression" msgid "Invalid custom field query expression"
msgstr "Невалидна заявка на персонализираното полето" msgstr "Невалидна заявка на персонализираното полето"
#: documents/filters.py:544 #: documents/filters.py:493
msgid "Invalid expression list. Must be nonempty." msgid "Invalid expression list. Must be nonempty."
msgstr "Списък с невалиден израз. Не може да е празно." msgstr "Списък с невалиден израз. Не може да е празно."
#: documents/filters.py:565 #: documents/filters.py:514
msgid "Invalid logical operator {op!r}" msgid "Invalid logical operator {op!r}"
msgstr "Невалиден логически оператор {op!r}" msgstr "Невалиден логически оператор {op!r}"
#: documents/filters.py:579 #: documents/filters.py:528
msgid "Maximum number of query conditions exceeded." msgid "Maximum number of query conditions exceeded."
msgstr "Надвишен е максимален брой за заявки." msgstr "Надвишен е максимален брой за заявки."
#: documents/filters.py:643 #: documents/filters.py:592
msgid "{name!r} is not a valid custom field." msgid "{name!r} is not a valid custom field."
msgstr "{name!r} не е валидно персонализирано поле." msgstr "{name!r} не е валидно персонализирано поле."
#: documents/filters.py:680 #: documents/filters.py:629
msgid "{data_type} does not support query expr {expr!r}." msgid "{data_type} does not support query expr {expr!r}."
msgstr "{data_type} не поддържа заявка expr {expr!r}." msgstr "{data_type} не поддържа заявка expr {expr!r}."
#: documents/filters.py:801 documents/models.py:137 #: documents/filters.py:748 documents/models.py:137
msgid "Maximum nesting depth exceeded." msgid "Maximum nesting depth exceeded."
msgstr "Надвишена е максималната дълбочина на вмъкване." msgstr "Надвишена е максималната дълбочина на вмъкване."
#: documents/filters.py:1178 #: documents/filters.py:1125
msgid "Custom field not found" msgid "Custom field not found"
msgstr "Персонализирано поле не е намерено" msgstr "Персонализирано поле не е намерено"
@@ -1639,48 +1635,48 @@ msgstr "стартиране на работния процес"
msgid "workflow runs" msgid "workflow runs"
msgstr "стартиране на работните процеси" msgstr "стартиране на работните процеси"
#: documents/serialisers.py:483 documents/serialisers.py:840 #: documents/serialisers.py:515 documents/serialisers.py:872
#: documents/serialisers.py:2872 documents/views.py:360 documents/views.py:2730 #: documents/serialisers.py:2902 documents/views.py:363 documents/views.py:2768
#: paperless_mail/serialisers.py:156 #: paperless_mail/serialisers.py:156
msgid "Insufficient permissions." msgid "Insufficient permissions."
msgstr "" msgstr ""
#: documents/serialisers.py:676 #: documents/serialisers.py:708
msgid "Invalid color." msgid "Invalid color."
msgstr "Невалиден цвят." msgstr "Невалиден цвят."
#: documents/serialisers.py:2339 #: documents/serialisers.py:2369
#, python-format #, python-format
msgid "File type %(type)s not supported" msgid "File type %(type)s not supported"
msgstr "Файловия тип %(type)s не се поддържа" msgstr "Файловия тип %(type)s не се поддържа"
#: documents/serialisers.py:2383 #: documents/serialisers.py:2413
#, python-format #, python-format
msgid "Custom field id must be an integer: %(id)s" msgid "Custom field id must be an integer: %(id)s"
msgstr "" msgstr ""
#: documents/serialisers.py:2390 #: documents/serialisers.py:2420
#, python-format #, python-format
msgid "Custom field with id %(id)s does not exist" msgid "Custom field with id %(id)s does not exist"
msgstr "" msgstr ""
#: documents/serialisers.py:2407 documents/serialisers.py:2417 #: documents/serialisers.py:2437 documents/serialisers.py:2447
msgid "Custom fields must be a list of integers or an object mapping ids to values." msgid "Custom fields must be a list of integers or an object mapping ids to values."
msgstr "" msgstr ""
#: documents/serialisers.py:2412 #: documents/serialisers.py:2442
msgid "Some custom fields don't exist or were specified twice." msgid "Some custom fields don't exist or were specified twice."
msgstr "" msgstr ""
#: documents/serialisers.py:2559 #: documents/serialisers.py:2589
msgid "Invalid variable detected." msgid "Invalid variable detected."
msgstr "Засечена е невалидна променлива." msgstr "Засечена е невалидна променлива."
#: documents/serialisers.py:2928 #: documents/serialisers.py:2958
msgid "Duplicate document identifiers are not allowed." msgid "Duplicate document identifiers are not allowed."
msgstr "" msgstr ""
#: documents/serialisers.py:2958 documents/views.py:4780 #: documents/serialisers.py:2988 documents/views.py:4816
#, python-format #, python-format
msgid "Documents not found: %(ids)s" msgid "Documents not found: %(ids)s"
msgstr "" msgstr ""
@@ -1921,40 +1917,40 @@ msgstr "Като последна стъпка, моля, попълнете с
msgid ", " msgid ", "
msgstr "" msgstr ""
#: documents/views.py:315 #: documents/views.py:318
msgid "Specify only one of text, title_search, query, or more_like_id." msgid "Specify only one of text, title_search, query, or more_like_id."
msgstr "" msgstr ""
#: documents/views.py:353 documents/views.py:2727 #: documents/views.py:356 documents/views.py:2765
msgid "Invalid more_like_id" msgid "Invalid more_like_id"
msgstr "" msgstr ""
#: documents/views.py:1665 #: documents/views.py:1703
msgid "Invalid AI configuration." msgid "Invalid AI configuration."
msgstr "" msgstr ""
#: documents/views.py:1676 #: documents/views.py:1714
msgid "AI backend request timed out." msgid "AI backend request timed out."
msgstr "" msgstr ""
#: documents/views.py:1688 #: documents/views.py:1726
msgid "AI backend rejected the request. Check logs for details." msgid "AI backend rejected the request. Check logs for details."
msgstr "" msgstr ""
#: documents/views.py:4796 #: documents/views.py:4832
#, python-format #, python-format
msgid "Insufficient permissions to share document %(id)s." msgid "Insufficient permissions to share document %(id)s."
msgstr "" msgstr ""
#: documents/views.py:4843 #: documents/views.py:4879
msgid "Bundle is already being processed." msgid "Bundle is already being processed."
msgstr "" msgstr ""
#: documents/views.py:4909 #: documents/views.py:4945
msgid "The share link bundle is still being prepared. Please try again later." msgid "The share link bundle is still being prepared. Please try again later."
msgstr "" msgstr ""
#: documents/views.py:4923 #: documents/views.py:4959
msgid "The share link bundle is unavailable." msgid "The share link bundle is unavailable."
msgstr "" msgstr ""
@@ -2246,151 +2242,151 @@ msgstr ""
msgid "paperless application settings" msgid "paperless application settings"
msgstr "настройки на софтуера" msgstr "настройки на софтуера"
#: paperless/settings/__init__.py:566 #: paperless/settings/__init__.py:562
msgid "English (US)" msgid "English (US)"
msgstr "Английски (САЩ)" msgstr "Английски (САЩ)"
#: paperless/settings/__init__.py:567 #: paperless/settings/__init__.py:563
msgid "Arabic" msgid "Arabic"
msgstr "Арабски" msgstr "Арабски"
#: paperless/settings/__init__.py:568 #: paperless/settings/__init__.py:564
msgid "Afrikaans" msgid "Afrikaans"
msgstr "Африканс" msgstr "Африканс"
#: paperless/settings/__init__.py:569 #: paperless/settings/__init__.py:565
msgid "Belarusian" msgid "Belarusian"
msgstr "Беларуски" msgstr "Беларуски"
#: paperless/settings/__init__.py:570 #: paperless/settings/__init__.py:566
msgid "Bulgarian" msgid "Bulgarian"
msgstr "Български" msgstr "Български"
#: paperless/settings/__init__.py:571 #: paperless/settings/__init__.py:567
msgid "Catalan" msgid "Catalan"
msgstr "Каталунски" msgstr "Каталунски"
#: paperless/settings/__init__.py:572 #: paperless/settings/__init__.py:568
msgid "Czech" msgid "Czech"
msgstr "Чешки" msgstr "Чешки"
#: paperless/settings/__init__.py:573 #: paperless/settings/__init__.py:569
msgid "Danish" msgid "Danish"
msgstr "Датски" msgstr "Датски"
#: paperless/settings/__init__.py:574 #: paperless/settings/__init__.py:570
msgid "German" msgid "German"
msgstr "Немски" msgstr "Немски"
#: paperless/settings/__init__.py:575 #: paperless/settings/__init__.py:571
msgid "Greek" msgid "Greek"
msgstr "Гръцки" msgstr "Гръцки"
#: paperless/settings/__init__.py:576 #: paperless/settings/__init__.py:572
msgid "English (GB)" msgid "English (GB)"
msgstr "Английски (Великобритания)" msgstr "Английски (Великобритания)"
#: paperless/settings/__init__.py:577 #: paperless/settings/__init__.py:573
msgid "Spanish" msgid "Spanish"
msgstr "Испански" msgstr "Испански"
#: paperless/settings/__init__.py:578 #: paperless/settings/__init__.py:574
msgid "Persian" msgid "Persian"
msgstr "" msgstr ""
#: paperless/settings/__init__.py:579 #: paperless/settings/__init__.py:575
msgid "Finnish" msgid "Finnish"
msgstr "Финландски" msgstr "Финландски"
#: paperless/settings/__init__.py:580 #: paperless/settings/__init__.py:576
msgid "French" msgid "French"
msgstr "Френски" msgstr "Френски"
#: paperless/settings/__init__.py:581 #: paperless/settings/__init__.py:577
msgid "Hungarian" msgid "Hungarian"
msgstr "Унгарски" msgstr "Унгарски"
#: paperless/settings/__init__.py:582 #: paperless/settings/__init__.py:578
msgid "Indonesian" msgid "Indonesian"
msgstr "" msgstr ""
#: paperless/settings/__init__.py:583 #: paperless/settings/__init__.py:579
msgid "Italian" msgid "Italian"
msgstr "Италиански" msgstr "Италиански"
#: paperless/settings/__init__.py:584 #: paperless/settings/__init__.py:580
msgid "Japanese" msgid "Japanese"
msgstr "Японски" msgstr "Японски"
#: paperless/settings/__init__.py:585 #: paperless/settings/__init__.py:581
msgid "Korean" msgid "Korean"
msgstr "Корейски" msgstr "Корейски"
#: paperless/settings/__init__.py:586 #: paperless/settings/__init__.py:582
msgid "Luxembourgish" msgid "Luxembourgish"
msgstr "Люксембургски" msgstr "Люксембургски"
#: paperless/settings/__init__.py:587 #: paperless/settings/__init__.py:583
msgid "Norwegian" msgid "Norwegian"
msgstr "Норвежки" msgstr "Норвежки"
#: paperless/settings/__init__.py:588 #: paperless/settings/__init__.py:584
msgid "Dutch" msgid "Dutch"
msgstr "Холандски" msgstr "Холандски"
#: paperless/settings/__init__.py:589 #: paperless/settings/__init__.py:585
msgid "Polish" msgid "Polish"
msgstr "Полски" msgstr "Полски"
#: paperless/settings/__init__.py:590 #: paperless/settings/__init__.py:586
msgid "Portuguese (Brazil)" msgid "Portuguese (Brazil)"
msgstr "Португалски (Бразилия)" msgstr "Португалски (Бразилия)"
#: paperless/settings/__init__.py:591 #: paperless/settings/__init__.py:587
msgid "Portuguese" msgid "Portuguese"
msgstr "Португалски" msgstr "Португалски"
#: paperless/settings/__init__.py:592 #: paperless/settings/__init__.py:588
msgid "Romanian" msgid "Romanian"
msgstr "Румънски" msgstr "Румънски"
#: paperless/settings/__init__.py:593 #: paperless/settings/__init__.py:589
msgid "Russian" msgid "Russian"
msgstr "Руски" msgstr "Руски"
#: paperless/settings/__init__.py:594 #: paperless/settings/__init__.py:590
msgid "Slovak" msgid "Slovak"
msgstr "Словашки" msgstr "Словашки"
#: paperless/settings/__init__.py:595 #: paperless/settings/__init__.py:591
msgid "Slovenian" msgid "Slovenian"
msgstr "Словенски" msgstr "Словенски"
#: paperless/settings/__init__.py:596 #: paperless/settings/__init__.py:592
msgid "Serbian" msgid "Serbian"
msgstr "Сръбски" msgstr "Сръбски"
#: paperless/settings/__init__.py:597 #: paperless/settings/__init__.py:593
msgid "Swedish" msgid "Swedish"
msgstr "Шведски" msgstr "Шведски"
#: paperless/settings/__init__.py:598 #: paperless/settings/__init__.py:594
msgid "Turkish" msgid "Turkish"
msgstr "Турски" msgstr "Турски"
#: paperless/settings/__init__.py:599 #: paperless/settings/__init__.py:595
msgid "Ukrainian" msgid "Ukrainian"
msgstr "Украински" msgstr "Украински"
#: paperless/settings/__init__.py:600 #: paperless/settings/__init__.py:596
msgid "Vietnamese" msgid "Vietnamese"
msgstr "" msgstr ""
#: paperless/settings/__init__.py:601 #: paperless/settings/__init__.py:597
msgid "Chinese Simplified" msgid "Chinese Simplified"
msgstr "Китайски опростен" msgstr "Китайски опростен"
#: paperless/settings/__init__.py:602 #: paperless/settings/__init__.py:598
msgid "Chinese Traditional" msgid "Chinese Traditional"
msgstr "Китайски традиционен" msgstr "Китайски традиционен"
+68 -72
View File
@@ -2,8 +2,8 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: paperless-ngx\n" "Project-Id-Version: paperless-ngx\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-10-29 17:25+0000\n" "POT-Creation-Date: 2026-10-19 15:40+0000\n"
"PO-Revision-Date: 2026-10-29 17:27\n" "PO-Revision-Date: 2026-10-19 15:42\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Catalan\n" "Language-Team: Catalan\n"
"Language: ca_ES\n" "Language: ca_ES\n"
@@ -21,43 +21,39 @@ msgstr ""
msgid "Documents" msgid "Documents"
msgstr "Documents " msgstr "Documents "
#: documents/filters.py:337 #: documents/filters.py:464
msgid "Expected a date or a relative date such as \"today\" or \"in 30 days\"."
msgstr ""
#: documents/filters.py:513
msgid "Value must be valid JSON." msgid "Value must be valid JSON."
msgstr "Valor ha de ser un JSON valid." msgstr "Valor ha de ser un JSON valid."
#: documents/filters.py:534 #: documents/filters.py:483
msgid "Invalid custom field query expression" msgid "Invalid custom field query expression"
msgstr "Expressió de camp de consulta invàlid" msgstr "Expressió de camp de consulta invàlid"
#: documents/filters.py:544 #: documents/filters.py:493
msgid "Invalid expression list. Must be nonempty." msgid "Invalid expression list. Must be nonempty."
msgstr "Expressió de llista invàlida. No ha d'estar buida." msgstr "Expressió de llista invàlida. No ha d'estar buida."
#: documents/filters.py:565 #: documents/filters.py:514
msgid "Invalid logical operator {op!r}" msgid "Invalid logical operator {op!r}"
msgstr "Invàlid operand lògic {op!r}" msgstr "Invàlid operand lògic {op!r}"
#: documents/filters.py:579 #: documents/filters.py:528
msgid "Maximum number of query conditions exceeded." msgid "Maximum number of query conditions exceeded."
msgstr "Condicions de consulta excedits." msgstr "Condicions de consulta excedits."
#: documents/filters.py:643 #: documents/filters.py:592
msgid "{name!r} is not a valid custom field." msgid "{name!r} is not a valid custom field."
msgstr "{name!r} no és un camp personalitzat vàlid." msgstr "{name!r} no és un camp personalitzat vàlid."
#: documents/filters.py:680 #: documents/filters.py:629
msgid "{data_type} does not support query expr {expr!r}." msgid "{data_type} does not support query expr {expr!r}."
msgstr "{data_type} no suporta expressió de consulta {expr!r}." msgstr "{data_type} no suporta expressió de consulta {expr!r}."
#: documents/filters.py:801 documents/models.py:137 #: documents/filters.py:748 documents/models.py:137
msgid "Maximum nesting depth exceeded." msgid "Maximum nesting depth exceeded."
msgstr "Màxima profunditat anidada excedida." msgstr "Màxima profunditat anidada excedida."
#: documents/filters.py:1178 #: documents/filters.py:1125
msgid "Custom field not found" msgid "Custom field not found"
msgstr "Camp personalitzat no trobat" msgstr "Camp personalitzat no trobat"
@@ -1639,48 +1635,48 @@ msgstr "data del flux"
msgid "workflow runs" msgid "workflow runs"
msgstr "flux corrents" msgstr "flux corrents"
#: documents/serialisers.py:483 documents/serialisers.py:840 #: documents/serialisers.py:515 documents/serialisers.py:872
#: documents/serialisers.py:2872 documents/views.py:360 documents/views.py:2730 #: documents/serialisers.py:2902 documents/views.py:363 documents/views.py:2768
#: paperless_mail/serialisers.py:156 #: paperless_mail/serialisers.py:156
msgid "Insufficient permissions." msgid "Insufficient permissions."
msgstr "Permisos insuficients." msgstr "Permisos insuficients."
#: documents/serialisers.py:676 #: documents/serialisers.py:708
msgid "Invalid color." msgid "Invalid color."
msgstr "Color Invàlid." msgstr "Color Invàlid."
#: documents/serialisers.py:2339 #: documents/serialisers.py:2369
#, python-format #, python-format
msgid "File type %(type)s not supported" msgid "File type %(type)s not supported"
msgstr "Tipus arxiu %(type)s no suportat" msgstr "Tipus arxiu %(type)s no suportat"
#: documents/serialisers.py:2383 #: documents/serialisers.py:2413
#, python-format #, python-format
msgid "Custom field id must be an integer: %(id)s" msgid "Custom field id must be an integer: %(id)s"
msgstr "ID de camp personalizat ha de ser enter: %(id)s" msgstr "ID de camp personalizat ha de ser enter: %(id)s"
#: documents/serialisers.py:2390 #: documents/serialisers.py:2420
#, python-format #, python-format
msgid "Custom field with id %(id)s does not exist" msgid "Custom field with id %(id)s does not exist"
msgstr "Camp personalitzat amb ID %(id)s no existeix" msgstr "Camp personalitzat amb ID %(id)s no existeix"
#: documents/serialisers.py:2407 documents/serialisers.py:2417 #: documents/serialisers.py:2437 documents/serialisers.py:2447
msgid "Custom fields must be a list of integers or an object mapping ids to values." msgid "Custom fields must be a list of integers or an object mapping ids to values."
msgstr "Camps personalitzats han de ser una llista d'enters o un objecte que mapegi els identificadors amb els valors." msgstr "Camps personalitzats han de ser una llista d'enters o un objecte que mapegi els identificadors amb els valors."
#: documents/serialisers.py:2412 #: documents/serialisers.py:2442
msgid "Some custom fields don't exist or were specified twice." msgid "Some custom fields don't exist or were specified twice."
msgstr "Alguns camps personalitzats no existeixen o s'han especificat dues vegades." msgstr "Alguns camps personalitzats no existeixen o s'han especificat dues vegades."
#: documents/serialisers.py:2559 #: documents/serialisers.py:2589
msgid "Invalid variable detected." msgid "Invalid variable detected."
msgstr "Variable detectada invàlida." msgstr "Variable detectada invàlida."
#: documents/serialisers.py:2928 #: documents/serialisers.py:2958
msgid "Duplicate document identifiers are not allowed." msgid "Duplicate document identifiers are not allowed."
msgstr "Duplicat d'identificadors de documents no permès." msgstr "Duplicat d'identificadors de documents no permès."
#: documents/serialisers.py:2958 documents/views.py:4780 #: documents/serialisers.py:2988 documents/views.py:4816
#, python-format #, python-format
msgid "Documents not found: %(ids)s" msgid "Documents not found: %(ids)s"
msgstr "Documents no trobats: %(ids)s" msgstr "Documents no trobats: %(ids)s"
@@ -1921,40 +1917,40 @@ msgstr "Com a pas final, completa el següent formulari:"
msgid ", " msgid ", "
msgstr "" msgstr ""
#: documents/views.py:315 #: documents/views.py:318
msgid "Specify only one of text, title_search, query, or more_like_id." msgid "Specify only one of text, title_search, query, or more_like_id."
msgstr "Especifica només un dels següents valors: text, title_search, query o more_like_id." msgstr "Especifica només un dels següents valors: text, title_search, query o more_like_id."
#: documents/views.py:353 documents/views.py:2727 #: documents/views.py:356 documents/views.py:2765
msgid "Invalid more_like_id" msgid "Invalid more_like_id"
msgstr "Invalid more_like_id" msgstr "Invalid more_like_id"
#: documents/views.py:1665 #: documents/views.py:1703
msgid "Invalid AI configuration." msgid "Invalid AI configuration."
msgstr "Configuració AI invàlida." msgstr "Configuració AI invàlida."
#: documents/views.py:1676 #: documents/views.py:1714
msgid "AI backend request timed out." msgid "AI backend request timed out."
msgstr "" msgstr ""
#: documents/views.py:1688 #: documents/views.py:1726
msgid "AI backend rejected the request. Check logs for details." msgid "AI backend rejected the request. Check logs for details."
msgstr "" msgstr ""
#: documents/views.py:4796 #: documents/views.py:4832
#, python-format #, python-format
msgid "Insufficient permissions to share document %(id)s." msgid "Insufficient permissions to share document %(id)s."
msgstr "Permisos insuficients per compartir document %(id)s." msgstr "Permisos insuficients per compartir document %(id)s."
#: documents/views.py:4843 #: documents/views.py:4879
msgid "Bundle is already being processed." msgid "Bundle is already being processed."
msgstr "Paquet ja s'està processant." msgstr "Paquet ja s'està processant."
#: documents/views.py:4909 #: documents/views.py:4945
msgid "The share link bundle is still being prepared. Please try again later." msgid "The share link bundle is still being prepared. Please try again later."
msgstr "El paquet de link encarà s'està preparant. Prova de nou més tard." msgstr "El paquet de link encarà s'està preparant. Prova de nou més tard."
#: documents/views.py:4923 #: documents/views.py:4959
msgid "The share link bundle is unavailable." msgid "The share link bundle is unavailable."
msgstr "El paquet d'enllaç no està disponible." msgstr "El paquet d'enllaç no està disponible."
@@ -2246,151 +2242,151 @@ msgstr "Estableix temps d'espera en segons"
msgid "paperless application settings" msgid "paperless application settings"
msgstr "configuració de l'aplicació paperless" msgstr "configuració de l'aplicació paperless"
#: paperless/settings/__init__.py:566 #: paperless/settings/__init__.py:562
msgid "English (US)" msgid "English (US)"
msgstr "Anglès (US)" msgstr "Anglès (US)"
#: paperless/settings/__init__.py:567 #: paperless/settings/__init__.py:563
msgid "Arabic" msgid "Arabic"
msgstr "Àrab" msgstr "Àrab"
#: paperless/settings/__init__.py:568 #: paperless/settings/__init__.py:564
msgid "Afrikaans" msgid "Afrikaans"
msgstr "Africà" msgstr "Africà"
#: paperless/settings/__init__.py:569 #: paperless/settings/__init__.py:565
msgid "Belarusian" msgid "Belarusian"
msgstr "Bielorús" msgstr "Bielorús"
#: paperless/settings/__init__.py:570 #: paperless/settings/__init__.py:566
msgid "Bulgarian" msgid "Bulgarian"
msgstr "Búlgar" msgstr "Búlgar"
#: paperless/settings/__init__.py:571 #: paperless/settings/__init__.py:567
msgid "Catalan" msgid "Catalan"
msgstr "Català" msgstr "Català"
#: paperless/settings/__init__.py:572 #: paperless/settings/__init__.py:568
msgid "Czech" msgid "Czech"
msgstr "Txec" msgstr "Txec"
#: paperless/settings/__init__.py:573 #: paperless/settings/__init__.py:569
msgid "Danish" msgid "Danish"
msgstr "Danès" msgstr "Danès"
#: paperless/settings/__init__.py:574 #: paperless/settings/__init__.py:570
msgid "German" msgid "German"
msgstr "Alemany" msgstr "Alemany"
#: paperless/settings/__init__.py:575 #: paperless/settings/__init__.py:571
msgid "Greek" msgid "Greek"
msgstr "Grec" msgstr "Grec"
#: paperless/settings/__init__.py:576 #: paperless/settings/__init__.py:572
msgid "English (GB)" msgid "English (GB)"
msgstr "Anglès (GB)" msgstr "Anglès (GB)"
#: paperless/settings/__init__.py:577 #: paperless/settings/__init__.py:573
msgid "Spanish" msgid "Spanish"
msgstr "Espanyol" msgstr "Espanyol"
#: paperless/settings/__init__.py:578 #: paperless/settings/__init__.py:574
msgid "Persian" msgid "Persian"
msgstr "Persa" msgstr "Persa"
#: paperless/settings/__init__.py:579 #: paperless/settings/__init__.py:575
msgid "Finnish" msgid "Finnish"
msgstr "Finès" msgstr "Finès"
#: paperless/settings/__init__.py:580 #: paperless/settings/__init__.py:576
msgid "French" msgid "French"
msgstr "Francès" msgstr "Francès"
#: paperless/settings/__init__.py:581 #: paperless/settings/__init__.py:577
msgid "Hungarian" msgid "Hungarian"
msgstr "Hongarès" msgstr "Hongarès"
#: paperless/settings/__init__.py:582 #: paperless/settings/__init__.py:578
msgid "Indonesian" msgid "Indonesian"
msgstr "Indonesi" msgstr "Indonesi"
#: paperless/settings/__init__.py:583 #: paperless/settings/__init__.py:579
msgid "Italian" msgid "Italian"
msgstr "Italià" msgstr "Italià"
#: paperless/settings/__init__.py:584 #: paperless/settings/__init__.py:580
msgid "Japanese" msgid "Japanese"
msgstr "Japonès" msgstr "Japonès"
#: paperless/settings/__init__.py:585 #: paperless/settings/__init__.py:581
msgid "Korean" msgid "Korean"
msgstr "Coreà" msgstr "Coreà"
#: paperless/settings/__init__.py:586 #: paperless/settings/__init__.py:582
msgid "Luxembourgish" msgid "Luxembourgish"
msgstr "Luxemburguès" msgstr "Luxemburguès"
#: paperless/settings/__init__.py:587 #: paperless/settings/__init__.py:583
msgid "Norwegian" msgid "Norwegian"
msgstr "Noruec" msgstr "Noruec"
#: paperless/settings/__init__.py:588 #: paperless/settings/__init__.py:584
msgid "Dutch" msgid "Dutch"
msgstr "Holandès" msgstr "Holandès"
#: paperless/settings/__init__.py:589 #: paperless/settings/__init__.py:585
msgid "Polish" msgid "Polish"
msgstr "Polonès" msgstr "Polonès"
#: paperless/settings/__init__.py:590 #: paperless/settings/__init__.py:586
msgid "Portuguese (Brazil)" msgid "Portuguese (Brazil)"
msgstr "Portuguès (Brasil)" msgstr "Portuguès (Brasil)"
#: paperless/settings/__init__.py:591 #: paperless/settings/__init__.py:587
msgid "Portuguese" msgid "Portuguese"
msgstr "Portuguès" msgstr "Portuguès"
#: paperless/settings/__init__.py:592 #: paperless/settings/__init__.py:588
msgid "Romanian" msgid "Romanian"
msgstr "Romanès" msgstr "Romanès"
#: paperless/settings/__init__.py:593 #: paperless/settings/__init__.py:589
msgid "Russian" msgid "Russian"
msgstr "Rus" msgstr "Rus"
#: paperless/settings/__init__.py:594 #: paperless/settings/__init__.py:590
msgid "Slovak" msgid "Slovak"
msgstr "Eslovac" msgstr "Eslovac"
#: paperless/settings/__init__.py:595 #: paperless/settings/__init__.py:591
msgid "Slovenian" msgid "Slovenian"
msgstr "Eslovè" msgstr "Eslovè"
#: paperless/settings/__init__.py:596 #: paperless/settings/__init__.py:592
msgid "Serbian" msgid "Serbian"
msgstr "Serbi" msgstr "Serbi"
#: paperless/settings/__init__.py:597 #: paperless/settings/__init__.py:593
msgid "Swedish" msgid "Swedish"
msgstr "Suec" msgstr "Suec"
#: paperless/settings/__init__.py:598 #: paperless/settings/__init__.py:594
msgid "Turkish" msgid "Turkish"
msgstr "Turc" msgstr "Turc"
#: paperless/settings/__init__.py:599 #: paperless/settings/__init__.py:595
msgid "Ukrainian" msgid "Ukrainian"
msgstr "Ucranià" msgstr "Ucranià"
#: paperless/settings/__init__.py:600 #: paperless/settings/__init__.py:596
msgid "Vietnamese" msgid "Vietnamese"
msgstr "Vietnamita" msgstr "Vietnamita"
#: paperless/settings/__init__.py:601 #: paperless/settings/__init__.py:597
msgid "Chinese Simplified" msgid "Chinese Simplified"
msgstr "Xinès Simplificat" msgstr "Xinès Simplificat"
#: paperless/settings/__init__.py:602 #: paperless/settings/__init__.py:598
msgid "Chinese Traditional" msgid "Chinese Traditional"
msgstr "Xinès tradicional" msgstr "Xinès tradicional"
+68 -72
View File
@@ -2,8 +2,8 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: paperless-ngx\n" "Project-Id-Version: paperless-ngx\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-10-29 17:25+0000\n" "POT-Creation-Date: 2026-10-19 15:40+0000\n"
"PO-Revision-Date: 2026-10-29 17:27\n" "PO-Revision-Date: 2026-10-19 15:42\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Czech\n" "Language-Team: Czech\n"
"Language: cs_CZ\n" "Language: cs_CZ\n"
@@ -21,43 +21,39 @@ msgstr ""
msgid "Documents" msgid "Documents"
msgstr "Dokumenty" msgstr "Dokumenty"
#: documents/filters.py:337 #: documents/filters.py:464
msgid "Expected a date or a relative date such as \"today\" or \"in 30 days\"."
msgstr ""
#: documents/filters.py:513
msgid "Value must be valid JSON." msgid "Value must be valid JSON."
msgstr "Hodnota musí být platný JSON." msgstr "Hodnota musí být platný JSON."
#: documents/filters.py:534 #: documents/filters.py:483
msgid "Invalid custom field query expression" msgid "Invalid custom field query expression"
msgstr "Neplatný výraz dotazu na vlastní pole" msgstr "Neplatný výraz dotazu na vlastní pole"
#: documents/filters.py:544 #: documents/filters.py:493
msgid "Invalid expression list. Must be nonempty." msgid "Invalid expression list. Must be nonempty."
msgstr "Neplatný seznam výrazů. Nesmí být prázdný." msgstr "Neplatný seznam výrazů. Nesmí být prázdný."
#: documents/filters.py:565 #: documents/filters.py:514
msgid "Invalid logical operator {op!r}" msgid "Invalid logical operator {op!r}"
msgstr "Neplatný logický operátor {op!r}" msgstr "Neplatný logický operátor {op!r}"
#: documents/filters.py:579 #: documents/filters.py:528
msgid "Maximum number of query conditions exceeded." msgid "Maximum number of query conditions exceeded."
msgstr "Překročen maximální počet podmínek dotazu." msgstr "Překročen maximální počet podmínek dotazu."
#: documents/filters.py:643 #: documents/filters.py:592
msgid "{name!r} is not a valid custom field." msgid "{name!r} is not a valid custom field."
msgstr "{name!r} není platné vlastní pole." msgstr "{name!r} není platné vlastní pole."
#: documents/filters.py:680 #: documents/filters.py:629
msgid "{data_type} does not support query expr {expr!r}." msgid "{data_type} does not support query expr {expr!r}."
msgstr "{data_type} nepodporuje výraz dotazu {expr!r}." msgstr "{data_type} nepodporuje výraz dotazu {expr!r}."
#: documents/filters.py:801 documents/models.py:137 #: documents/filters.py:748 documents/models.py:137
msgid "Maximum nesting depth exceeded." msgid "Maximum nesting depth exceeded."
msgstr "Překročena maximální hloubka větvení." msgstr "Překročena maximální hloubka větvení."
#: documents/filters.py:1178 #: documents/filters.py:1125
msgid "Custom field not found" msgid "Custom field not found"
msgstr "Vlastní pole nebylo nalezeno" msgstr "Vlastní pole nebylo nalezeno"
@@ -1639,48 +1635,48 @@ msgstr "spuštění pracovního postupu"
msgid "workflow runs" msgid "workflow runs"
msgstr "spuštění pracovních postupů" msgstr "spuštění pracovních postupů"
#: documents/serialisers.py:483 documents/serialisers.py:840 #: documents/serialisers.py:515 documents/serialisers.py:872
#: documents/serialisers.py:2872 documents/views.py:360 documents/views.py:2730 #: documents/serialisers.py:2902 documents/views.py:363 documents/views.py:2768
#: paperless_mail/serialisers.py:156 #: paperless_mail/serialisers.py:156
msgid "Insufficient permissions." msgid "Insufficient permissions."
msgstr "Nedostatečná oprávnění." msgstr "Nedostatečná oprávnění."
#: documents/serialisers.py:676 #: documents/serialisers.py:708
msgid "Invalid color." msgid "Invalid color."
msgstr "Neplatná barva." msgstr "Neplatná barva."
#: documents/serialisers.py:2339 #: documents/serialisers.py:2369
#, python-format #, python-format
msgid "File type %(type)s not supported" msgid "File type %(type)s not supported"
msgstr "Typ souboru %(type)s není podporován" msgstr "Typ souboru %(type)s není podporován"
#: documents/serialisers.py:2383 #: documents/serialisers.py:2413
#, python-format #, python-format
msgid "Custom field id must be an integer: %(id)s" msgid "Custom field id must be an integer: %(id)s"
msgstr "Vlastní ID pole musí být celé číslo: %(id)s" msgstr "Vlastní ID pole musí být celé číslo: %(id)s"
#: documents/serialisers.py:2390 #: documents/serialisers.py:2420
#, python-format #, python-format
msgid "Custom field with id %(id)s does not exist" msgid "Custom field with id %(id)s does not exist"
msgstr "Vlastní pole s ID %(id)s neexistuje" msgstr "Vlastní pole s ID %(id)s neexistuje"
#: documents/serialisers.py:2407 documents/serialisers.py:2417 #: documents/serialisers.py:2437 documents/serialisers.py:2447
msgid "Custom fields must be a list of integers or an object mapping ids to values." msgid "Custom fields must be a list of integers or an object mapping ids to values."
msgstr "Vlastní pole musí být seznam celých čísel nebo ID pro mapování objektů na hodnoty." msgstr "Vlastní pole musí být seznam celých čísel nebo ID pro mapování objektů na hodnoty."
#: documents/serialisers.py:2412 #: documents/serialisers.py:2442
msgid "Some custom fields don't exist or were specified twice." msgid "Some custom fields don't exist or were specified twice."
msgstr "Některá vlastní pole neexistují nebo byla zadána dvakrát." msgstr "Některá vlastní pole neexistují nebo byla zadána dvakrát."
#: documents/serialisers.py:2559 #: documents/serialisers.py:2589
msgid "Invalid variable detected." msgid "Invalid variable detected."
msgstr "Zjištěna neplatná proměnná." msgstr "Zjištěna neplatná proměnná."
#: documents/serialisers.py:2928 #: documents/serialisers.py:2958
msgid "Duplicate document identifiers are not allowed." msgid "Duplicate document identifiers are not allowed."
msgstr "" msgstr ""
#: documents/serialisers.py:2958 documents/views.py:4780 #: documents/serialisers.py:2988 documents/views.py:4816
#, python-format #, python-format
msgid "Documents not found: %(ids)s" msgid "Documents not found: %(ids)s"
msgstr "" msgstr ""
@@ -1921,40 +1917,40 @@ msgstr "Jako poslední krok vyplňte následující formulář:"
msgid ", " msgid ", "
msgstr "" msgstr ""
#: documents/views.py:315 #: documents/views.py:318
msgid "Specify only one of text, title_search, query, or more_like_id." msgid "Specify only one of text, title_search, query, or more_like_id."
msgstr "" msgstr ""
#: documents/views.py:353 documents/views.py:2727 #: documents/views.py:356 documents/views.py:2765
msgid "Invalid more_like_id" msgid "Invalid more_like_id"
msgstr "" msgstr ""
#: documents/views.py:1665 #: documents/views.py:1703
msgid "Invalid AI configuration." msgid "Invalid AI configuration."
msgstr "" msgstr ""
#: documents/views.py:1676 #: documents/views.py:1714
msgid "AI backend request timed out." msgid "AI backend request timed out."
msgstr "" msgstr ""
#: documents/views.py:1688 #: documents/views.py:1726
msgid "AI backend rejected the request. Check logs for details." msgid "AI backend rejected the request. Check logs for details."
msgstr "" msgstr ""
#: documents/views.py:4796 #: documents/views.py:4832
#, python-format #, python-format
msgid "Insufficient permissions to share document %(id)s." msgid "Insufficient permissions to share document %(id)s."
msgstr "Nedostatečná oprávnění ke sdílení dokumentu %(id)s." msgstr "Nedostatečná oprávnění ke sdílení dokumentu %(id)s."
#: documents/views.py:4843 #: documents/views.py:4879
msgid "Bundle is already being processed." msgid "Bundle is already being processed."
msgstr "" msgstr ""
#: documents/views.py:4909 #: documents/views.py:4945
msgid "The share link bundle is still being prepared. Please try again later." msgid "The share link bundle is still being prepared. Please try again later."
msgstr "" msgstr ""
#: documents/views.py:4923 #: documents/views.py:4959
msgid "The share link bundle is unavailable." msgid "The share link bundle is unavailable."
msgstr "" msgstr ""
@@ -2246,151 +2242,151 @@ msgstr "Nastaví časový limit LLM v sekundách"
msgid "paperless application settings" msgid "paperless application settings"
msgstr "nastavení aplikace paperless" msgstr "nastavení aplikace paperless"
#: paperless/settings/__init__.py:566 #: paperless/settings/__init__.py:562
msgid "English (US)" msgid "English (US)"
msgstr "Angličtina (US)" msgstr "Angličtina (US)"
#: paperless/settings/__init__.py:567 #: paperless/settings/__init__.py:563
msgid "Arabic" msgid "Arabic"
msgstr "Arabština" msgstr "Arabština"
#: paperless/settings/__init__.py:568 #: paperless/settings/__init__.py:564
msgid "Afrikaans" msgid "Afrikaans"
msgstr "Afrikánština" msgstr "Afrikánština"
#: paperless/settings/__init__.py:569 #: paperless/settings/__init__.py:565
msgid "Belarusian" msgid "Belarusian"
msgstr "Běloruština" msgstr "Běloruština"
#: paperless/settings/__init__.py:570 #: paperless/settings/__init__.py:566
msgid "Bulgarian" msgid "Bulgarian"
msgstr "Bulharština" msgstr "Bulharština"
#: paperless/settings/__init__.py:571 #: paperless/settings/__init__.py:567
msgid "Catalan" msgid "Catalan"
msgstr "Katalánština" msgstr "Katalánština"
#: paperless/settings/__init__.py:572 #: paperless/settings/__init__.py:568
msgid "Czech" msgid "Czech"
msgstr "Čeština" msgstr "Čeština"
#: paperless/settings/__init__.py:573 #: paperless/settings/__init__.py:569
msgid "Danish" msgid "Danish"
msgstr "Dánština" msgstr "Dánština"
#: paperless/settings/__init__.py:574 #: paperless/settings/__init__.py:570
msgid "German" msgid "German"
msgstr "Němčina" msgstr "Němčina"
#: paperless/settings/__init__.py:575 #: paperless/settings/__init__.py:571
msgid "Greek" msgid "Greek"
msgstr "Řečtina" msgstr "Řečtina"
#: paperless/settings/__init__.py:576 #: paperless/settings/__init__.py:572
msgid "English (GB)" msgid "English (GB)"
msgstr "Angličtina (GB)" msgstr "Angličtina (GB)"
#: paperless/settings/__init__.py:577 #: paperless/settings/__init__.py:573
msgid "Spanish" msgid "Spanish"
msgstr "Španělština" msgstr "Španělština"
#: paperless/settings/__init__.py:578 #: paperless/settings/__init__.py:574
msgid "Persian" msgid "Persian"
msgstr "Perština" msgstr "Perština"
#: paperless/settings/__init__.py:579 #: paperless/settings/__init__.py:575
msgid "Finnish" msgid "Finnish"
msgstr "Finština" msgstr "Finština"
#: paperless/settings/__init__.py:580 #: paperless/settings/__init__.py:576
msgid "French" msgid "French"
msgstr "Francouzština" msgstr "Francouzština"
#: paperless/settings/__init__.py:581 #: paperless/settings/__init__.py:577
msgid "Hungarian" msgid "Hungarian"
msgstr "Maďarština" msgstr "Maďarština"
#: paperless/settings/__init__.py:582 #: paperless/settings/__init__.py:578
msgid "Indonesian" msgid "Indonesian"
msgstr "Indonéština" msgstr "Indonéština"
#: paperless/settings/__init__.py:583 #: paperless/settings/__init__.py:579
msgid "Italian" msgid "Italian"
msgstr "Italština" msgstr "Italština"
#: paperless/settings/__init__.py:584 #: paperless/settings/__init__.py:580
msgid "Japanese" msgid "Japanese"
msgstr "Japonština" msgstr "Japonština"
#: paperless/settings/__init__.py:585 #: paperless/settings/__init__.py:581
msgid "Korean" msgid "Korean"
msgstr "Korejština" msgstr "Korejština"
#: paperless/settings/__init__.py:586 #: paperless/settings/__init__.py:582
msgid "Luxembourgish" msgid "Luxembourgish"
msgstr "Lucemburština" msgstr "Lucemburština"
#: paperless/settings/__init__.py:587 #: paperless/settings/__init__.py:583
msgid "Norwegian" msgid "Norwegian"
msgstr "Norština" msgstr "Norština"
#: paperless/settings/__init__.py:588 #: paperless/settings/__init__.py:584
msgid "Dutch" msgid "Dutch"
msgstr "Holandština" msgstr "Holandština"
#: paperless/settings/__init__.py:589 #: paperless/settings/__init__.py:585
msgid "Polish" msgid "Polish"
msgstr "Polština" msgstr "Polština"
#: paperless/settings/__init__.py:590 #: paperless/settings/__init__.py:586
msgid "Portuguese (Brazil)" msgid "Portuguese (Brazil)"
msgstr "Portugalština (Brazílie)" msgstr "Portugalština (Brazílie)"
#: paperless/settings/__init__.py:591 #: paperless/settings/__init__.py:587
msgid "Portuguese" msgid "Portuguese"
msgstr "Portugalština" msgstr "Portugalština"
#: paperless/settings/__init__.py:592 #: paperless/settings/__init__.py:588
msgid "Romanian" msgid "Romanian"
msgstr "Rumunština" msgstr "Rumunština"
#: paperless/settings/__init__.py:593 #: paperless/settings/__init__.py:589
msgid "Russian" msgid "Russian"
msgstr "Ruština" msgstr "Ruština"
#: paperless/settings/__init__.py:594 #: paperless/settings/__init__.py:590
msgid "Slovak" msgid "Slovak"
msgstr "Slovenština" msgstr "Slovenština"
#: paperless/settings/__init__.py:595 #: paperless/settings/__init__.py:591
msgid "Slovenian" msgid "Slovenian"
msgstr "Slovinština" msgstr "Slovinština"
#: paperless/settings/__init__.py:596 #: paperless/settings/__init__.py:592
msgid "Serbian" msgid "Serbian"
msgstr "Srbština" msgstr "Srbština"
#: paperless/settings/__init__.py:597 #: paperless/settings/__init__.py:593
msgid "Swedish" msgid "Swedish"
msgstr "Švédština" msgstr "Švédština"
#: paperless/settings/__init__.py:598 #: paperless/settings/__init__.py:594
msgid "Turkish" msgid "Turkish"
msgstr "Turečtina" msgstr "Turečtina"
#: paperless/settings/__init__.py:599 #: paperless/settings/__init__.py:595
msgid "Ukrainian" msgid "Ukrainian"
msgstr "Ukrajinština" msgstr "Ukrajinština"
#: paperless/settings/__init__.py:600 #: paperless/settings/__init__.py:596
msgid "Vietnamese" msgid "Vietnamese"
msgstr "Vietnamština" msgstr "Vietnamština"
#: paperless/settings/__init__.py:601 #: paperless/settings/__init__.py:597
msgid "Chinese Simplified" msgid "Chinese Simplified"
msgstr "Čínština (zjednodušená)" msgstr "Čínština (zjednodušená)"
#: paperless/settings/__init__.py:602 #: paperless/settings/__init__.py:598
msgid "Chinese Traditional" msgid "Chinese Traditional"
msgstr "Čínština (tradiční)" msgstr "Čínština (tradiční)"
+68 -72
View File
@@ -2,8 +2,8 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: paperless-ngx\n" "Project-Id-Version: paperless-ngx\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-10-29 17:25+0000\n" "POT-Creation-Date: 2026-10-19 15:40+0000\n"
"PO-Revision-Date: 2026-10-29 17:27\n" "PO-Revision-Date: 2026-10-19 15:42\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Danish\n" "Language-Team: Danish\n"
"Language: da_DK\n" "Language: da_DK\n"
@@ -21,43 +21,39 @@ msgstr ""
msgid "Documents" msgid "Documents"
msgstr "Dokumenter" msgstr "Dokumenter"
#: documents/filters.py:337 #: documents/filters.py:464
msgid "Expected a date or a relative date such as \"today\" or \"in 30 days\"."
msgstr ""
#: documents/filters.py:513
msgid "Value must be valid JSON." msgid "Value must be valid JSON."
msgstr "Værdien skal være gyldig JSON." msgstr "Værdien skal være gyldig JSON."
#: documents/filters.py:534 #: documents/filters.py:483
msgid "Invalid custom field query expression" msgid "Invalid custom field query expression"
msgstr "Ugyldigt tilpasset feltforespørgselsudtryk" msgstr "Ugyldigt tilpasset feltforespørgselsudtryk"
#: documents/filters.py:544 #: documents/filters.py:493
msgid "Invalid expression list. Must be nonempty." msgid "Invalid expression list. Must be nonempty."
msgstr "Ugyldig udtryksliste. Må ikke være tom." msgstr "Ugyldig udtryksliste. Må ikke være tom."
#: documents/filters.py:565 #: documents/filters.py:514
msgid "Invalid logical operator {op!r}" msgid "Invalid logical operator {op!r}"
msgstr "Ugyldig logisk operatør {op!r}" msgstr "Ugyldig logisk operatør {op!r}"
#: documents/filters.py:579 #: documents/filters.py:528
msgid "Maximum number of query conditions exceeded." msgid "Maximum number of query conditions exceeded."
msgstr "Maksimalt antal forespørgselsbetingelser overskredet." msgstr "Maksimalt antal forespørgselsbetingelser overskredet."
#: documents/filters.py:643 #: documents/filters.py:592
msgid "{name!r} is not a valid custom field." msgid "{name!r} is not a valid custom field."
msgstr "{name!r} er ikke et gyldigt tilpasset felt." msgstr "{name!r} er ikke et gyldigt tilpasset felt."
#: documents/filters.py:680 #: documents/filters.py:629
msgid "{data_type} does not support query expr {expr!r}." msgid "{data_type} does not support query expr {expr!r}."
msgstr "{data_type} understøtter ikke forespørgsel expr {expr!r}." msgstr "{data_type} understøtter ikke forespørgsel expr {expr!r}."
#: documents/filters.py:801 documents/models.py:137 #: documents/filters.py:748 documents/models.py:137
msgid "Maximum nesting depth exceeded." msgid "Maximum nesting depth exceeded."
msgstr "Maksimal indlejringsdybde overskredet." msgstr "Maksimal indlejringsdybde overskredet."
#: documents/filters.py:1178 #: documents/filters.py:1125
msgid "Custom field not found" msgid "Custom field not found"
msgstr "Tilpasset felt ikke fundet" msgstr "Tilpasset felt ikke fundet"
@@ -1639,48 +1635,48 @@ msgstr "workflow-kørsel"
msgid "workflow runs" msgid "workflow runs"
msgstr "workflow-kørsler" msgstr "workflow-kørsler"
#: documents/serialisers.py:483 documents/serialisers.py:840 #: documents/serialisers.py:515 documents/serialisers.py:872
#: documents/serialisers.py:2872 documents/views.py:360 documents/views.py:2730 #: documents/serialisers.py:2902 documents/views.py:363 documents/views.py:2768
#: paperless_mail/serialisers.py:156 #: paperless_mail/serialisers.py:156
msgid "Insufficient permissions." msgid "Insufficient permissions."
msgstr "" msgstr ""
#: documents/serialisers.py:676 #: documents/serialisers.py:708
msgid "Invalid color." msgid "Invalid color."
msgstr "Ugyldig farve." msgstr "Ugyldig farve."
#: documents/serialisers.py:2339 #: documents/serialisers.py:2369
#, python-format #, python-format
msgid "File type %(type)s not supported" msgid "File type %(type)s not supported"
msgstr "Filtype %(type)s understøttes ikke" msgstr "Filtype %(type)s understøttes ikke"
#: documents/serialisers.py:2383 #: documents/serialisers.py:2413
#, python-format #, python-format
msgid "Custom field id must be an integer: %(id)s" msgid "Custom field id must be an integer: %(id)s"
msgstr "" msgstr ""
#: documents/serialisers.py:2390 #: documents/serialisers.py:2420
#, python-format #, python-format
msgid "Custom field with id %(id)s does not exist" msgid "Custom field with id %(id)s does not exist"
msgstr "" msgstr ""
#: documents/serialisers.py:2407 documents/serialisers.py:2417 #: documents/serialisers.py:2437 documents/serialisers.py:2447
msgid "Custom fields must be a list of integers or an object mapping ids to values." msgid "Custom fields must be a list of integers or an object mapping ids to values."
msgstr "" msgstr ""
#: documents/serialisers.py:2412 #: documents/serialisers.py:2442
msgid "Some custom fields don't exist or were specified twice." msgid "Some custom fields don't exist or were specified twice."
msgstr "" msgstr ""
#: documents/serialisers.py:2559 #: documents/serialisers.py:2589
msgid "Invalid variable detected." msgid "Invalid variable detected."
msgstr "Ugyldig variabel fundet." msgstr "Ugyldig variabel fundet."
#: documents/serialisers.py:2928 #: documents/serialisers.py:2958
msgid "Duplicate document identifiers are not allowed." msgid "Duplicate document identifiers are not allowed."
msgstr "" msgstr ""
#: documents/serialisers.py:2958 documents/views.py:4780 #: documents/serialisers.py:2988 documents/views.py:4816
#, python-format #, python-format
msgid "Documents not found: %(ids)s" msgid "Documents not found: %(ids)s"
msgstr "" msgstr ""
@@ -1921,40 +1917,40 @@ msgstr "Som sidste trin, udfyld venligst flg. formular:"
msgid ", " msgid ", "
msgstr "" msgstr ""
#: documents/views.py:315 #: documents/views.py:318
msgid "Specify only one of text, title_search, query, or more_like_id." msgid "Specify only one of text, title_search, query, or more_like_id."
msgstr "" msgstr ""
#: documents/views.py:353 documents/views.py:2727 #: documents/views.py:356 documents/views.py:2765
msgid "Invalid more_like_id" msgid "Invalid more_like_id"
msgstr "" msgstr ""
#: documents/views.py:1665 #: documents/views.py:1703
msgid "Invalid AI configuration." msgid "Invalid AI configuration."
msgstr "" msgstr ""
#: documents/views.py:1676 #: documents/views.py:1714
msgid "AI backend request timed out." msgid "AI backend request timed out."
msgstr "" msgstr ""
#: documents/views.py:1688 #: documents/views.py:1726
msgid "AI backend rejected the request. Check logs for details." msgid "AI backend rejected the request. Check logs for details."
msgstr "" msgstr ""
#: documents/views.py:4796 #: documents/views.py:4832
#, python-format #, python-format
msgid "Insufficient permissions to share document %(id)s." msgid "Insufficient permissions to share document %(id)s."
msgstr "" msgstr ""
#: documents/views.py:4843 #: documents/views.py:4879
msgid "Bundle is already being processed." msgid "Bundle is already being processed."
msgstr "" msgstr ""
#: documents/views.py:4909 #: documents/views.py:4945
msgid "The share link bundle is still being prepared. Please try again later." msgid "The share link bundle is still being prepared. Please try again later."
msgstr "" msgstr ""
#: documents/views.py:4923 #: documents/views.py:4959
msgid "The share link bundle is unavailable." msgid "The share link bundle is unavailable."
msgstr "" msgstr ""
@@ -2246,151 +2242,151 @@ msgstr ""
msgid "paperless application settings" msgid "paperless application settings"
msgstr "paperless-applikationsindstillinger" msgstr "paperless-applikationsindstillinger"
#: paperless/settings/__init__.py:566 #: paperless/settings/__init__.py:562
msgid "English (US)" msgid "English (US)"
msgstr "Engelsk (USA)" msgstr "Engelsk (USA)"
#: paperless/settings/__init__.py:567 #: paperless/settings/__init__.py:563
msgid "Arabic" msgid "Arabic"
msgstr "" msgstr ""
#: paperless/settings/__init__.py:568 #: paperless/settings/__init__.py:564
msgid "Afrikaans" msgid "Afrikaans"
msgstr "Afrikaans" msgstr "Afrikaans"
#: paperless/settings/__init__.py:569 #: paperless/settings/__init__.py:565
msgid "Belarusian" msgid "Belarusian"
msgstr "Hviderussisk" msgstr "Hviderussisk"
#: paperless/settings/__init__.py:570 #: paperless/settings/__init__.py:566
msgid "Bulgarian" msgid "Bulgarian"
msgstr "Bulgarsk" msgstr "Bulgarsk"
#: paperless/settings/__init__.py:571 #: paperless/settings/__init__.py:567
msgid "Catalan" msgid "Catalan"
msgstr "Katalansk" msgstr "Katalansk"
#: paperless/settings/__init__.py:572 #: paperless/settings/__init__.py:568
msgid "Czech" msgid "Czech"
msgstr "Tjekkisk" msgstr "Tjekkisk"
#: paperless/settings/__init__.py:573 #: paperless/settings/__init__.py:569
msgid "Danish" msgid "Danish"
msgstr "Dansk" msgstr "Dansk"
#: paperless/settings/__init__.py:574 #: paperless/settings/__init__.py:570
msgid "German" msgid "German"
msgstr "Tysk" msgstr "Tysk"
#: paperless/settings/__init__.py:575 #: paperless/settings/__init__.py:571
msgid "Greek" msgid "Greek"
msgstr "Græsk" msgstr "Græsk"
#: paperless/settings/__init__.py:576 #: paperless/settings/__init__.py:572
msgid "English (GB)" msgid "English (GB)"
msgstr "Engelsk (GB)" msgstr "Engelsk (GB)"
#: paperless/settings/__init__.py:577 #: paperless/settings/__init__.py:573
msgid "Spanish" msgid "Spanish"
msgstr "Spansk" msgstr "Spansk"
#: paperless/settings/__init__.py:578 #: paperless/settings/__init__.py:574
msgid "Persian" msgid "Persian"
msgstr "" msgstr ""
#: paperless/settings/__init__.py:579 #: paperless/settings/__init__.py:575
msgid "Finnish" msgid "Finnish"
msgstr "Finsk" msgstr "Finsk"
#: paperless/settings/__init__.py:580 #: paperless/settings/__init__.py:576
msgid "French" msgid "French"
msgstr "Fransk" msgstr "Fransk"
#: paperless/settings/__init__.py:581 #: paperless/settings/__init__.py:577
msgid "Hungarian" msgid "Hungarian"
msgstr "Ungarsk" msgstr "Ungarsk"
#: paperless/settings/__init__.py:582 #: paperless/settings/__init__.py:578
msgid "Indonesian" msgid "Indonesian"
msgstr "" msgstr ""
#: paperless/settings/__init__.py:583 #: paperless/settings/__init__.py:579
msgid "Italian" msgid "Italian"
msgstr "Italiensk" msgstr "Italiensk"
#: paperless/settings/__init__.py:584 #: paperless/settings/__init__.py:580
msgid "Japanese" msgid "Japanese"
msgstr "Japansk" msgstr "Japansk"
#: paperless/settings/__init__.py:585 #: paperless/settings/__init__.py:581
msgid "Korean" msgid "Korean"
msgstr "Koreansk" msgstr "Koreansk"
#: paperless/settings/__init__.py:586 #: paperless/settings/__init__.py:582
msgid "Luxembourgish" msgid "Luxembourgish"
msgstr "Luxemburgsk" msgstr "Luxemburgsk"
#: paperless/settings/__init__.py:587 #: paperless/settings/__init__.py:583
msgid "Norwegian" msgid "Norwegian"
msgstr "Norsk" msgstr "Norsk"
#: paperless/settings/__init__.py:588 #: paperless/settings/__init__.py:584
msgid "Dutch" msgid "Dutch"
msgstr "Hollandsk" msgstr "Hollandsk"
#: paperless/settings/__init__.py:589 #: paperless/settings/__init__.py:585
msgid "Polish" msgid "Polish"
msgstr "Polsk" msgstr "Polsk"
#: paperless/settings/__init__.py:590 #: paperless/settings/__init__.py:586
msgid "Portuguese (Brazil)" msgid "Portuguese (Brazil)"
msgstr "Portugisisk (Brasilien)" msgstr "Portugisisk (Brasilien)"
#: paperless/settings/__init__.py:591 #: paperless/settings/__init__.py:587
msgid "Portuguese" msgid "Portuguese"
msgstr "Portugisisk" msgstr "Portugisisk"
#: paperless/settings/__init__.py:592 #: paperless/settings/__init__.py:588
msgid "Romanian" msgid "Romanian"
msgstr "Romansk" msgstr "Romansk"
#: paperless/settings/__init__.py:593 #: paperless/settings/__init__.py:589
msgid "Russian" msgid "Russian"
msgstr "Russisk" msgstr "Russisk"
#: paperless/settings/__init__.py:594 #: paperless/settings/__init__.py:590
msgid "Slovak" msgid "Slovak"
msgstr "Slovakisk" msgstr "Slovakisk"
#: paperless/settings/__init__.py:595 #: paperless/settings/__init__.py:591
msgid "Slovenian" msgid "Slovenian"
msgstr "Slovensk" msgstr "Slovensk"
#: paperless/settings/__init__.py:596 #: paperless/settings/__init__.py:592
msgid "Serbian" msgid "Serbian"
msgstr "Serbisk" msgstr "Serbisk"
#: paperless/settings/__init__.py:597 #: paperless/settings/__init__.py:593
msgid "Swedish" msgid "Swedish"
msgstr "Svensk" msgstr "Svensk"
#: paperless/settings/__init__.py:598 #: paperless/settings/__init__.py:594
msgid "Turkish" msgid "Turkish"
msgstr "Tyrkisk" msgstr "Tyrkisk"
#: paperless/settings/__init__.py:599 #: paperless/settings/__init__.py:595
msgid "Ukrainian" msgid "Ukrainian"
msgstr "Ukrainsk" msgstr "Ukrainsk"
#: paperless/settings/__init__.py:600 #: paperless/settings/__init__.py:596
msgid "Vietnamese" msgid "Vietnamese"
msgstr "" msgstr ""
#: paperless/settings/__init__.py:601 #: paperless/settings/__init__.py:597
msgid "Chinese Simplified" msgid "Chinese Simplified"
msgstr "Kinesisk, forenklet" msgstr "Kinesisk, forenklet"
#: paperless/settings/__init__.py:602 #: paperless/settings/__init__.py:598
msgid "Chinese Traditional" msgid "Chinese Traditional"
msgstr "Kinesisk, traditionelt" msgstr "Kinesisk, traditionelt"
+68 -72
View File
@@ -2,8 +2,8 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: paperless-ngx\n" "Project-Id-Version: paperless-ngx\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-10-29 17:25+0000\n" "POT-Creation-Date: 2026-10-19 15:40+0000\n"
"PO-Revision-Date: 2026-10-29 17:27\n" "PO-Revision-Date: 2026-10-19 15:42\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: German, Switzerland\n" "Language-Team: German, Switzerland\n"
"Language: de_CH\n" "Language: de_CH\n"
@@ -21,43 +21,39 @@ msgstr ""
msgid "Documents" msgid "Documents"
msgstr "Dokumente" msgstr "Dokumente"
#: documents/filters.py:337 #: documents/filters.py:464
msgid "Expected a date or a relative date such as \"today\" or \"in 30 days\"."
msgstr ""
#: documents/filters.py:513
msgid "Value must be valid JSON." msgid "Value must be valid JSON."
msgstr "Wert muss gültiges JSON sein." msgstr "Wert muss gültiges JSON sein."
#: documents/filters.py:534 #: documents/filters.py:483
msgid "Invalid custom field query expression" msgid "Invalid custom field query expression"
msgstr "Ungültiger benutzerdefinierter Feldabfrageausdruck" msgstr "Ungültiger benutzerdefinierter Feldabfrageausdruck"
#: documents/filters.py:544 #: documents/filters.py:493
msgid "Invalid expression list. Must be nonempty." msgid "Invalid expression list. Must be nonempty."
msgstr "Ungültige Ausdrucksliste. Darf nicht leer sein." msgstr "Ungültige Ausdrucksliste. Darf nicht leer sein."
#: documents/filters.py:565 #: documents/filters.py:514
msgid "Invalid logical operator {op!r}" msgid "Invalid logical operator {op!r}"
msgstr "Ungültiger logischer Operator {op!r}" msgstr "Ungültiger logischer Operator {op!r}"
#: documents/filters.py:579 #: documents/filters.py:528
msgid "Maximum number of query conditions exceeded." msgid "Maximum number of query conditions exceeded."
msgstr "Maximale Anzahl an Abfragebedingungen überschritten." msgstr "Maximale Anzahl an Abfragebedingungen überschritten."
#: documents/filters.py:643 #: documents/filters.py:592
msgid "{name!r} is not a valid custom field." msgid "{name!r} is not a valid custom field."
msgstr "{name!r} ist kein gültiges Zusatzfeld." msgstr "{name!r} ist kein gültiges Zusatzfeld."
#: documents/filters.py:680 #: documents/filters.py:629
msgid "{data_type} does not support query expr {expr!r}." msgid "{data_type} does not support query expr {expr!r}."
msgstr "{data_type} unterstützt den Abfrageausdruck {expr!r} nicht." msgstr "{data_type} unterstützt den Abfrageausdruck {expr!r} nicht."
#: documents/filters.py:801 documents/models.py:137 #: documents/filters.py:748 documents/models.py:137
msgid "Maximum nesting depth exceeded." msgid "Maximum nesting depth exceeded."
msgstr "Maximale Verschachtelungstiefe überschritten." msgstr "Maximale Verschachtelungstiefe überschritten."
#: documents/filters.py:1178 #: documents/filters.py:1125
msgid "Custom field not found" msgid "Custom field not found"
msgstr "Benutzerdefiniertes Feld nicht gefunden" msgstr "Benutzerdefiniertes Feld nicht gefunden"
@@ -1639,48 +1635,48 @@ msgstr "Arbeitsablauf-Ausführung"
msgid "workflow runs" msgid "workflow runs"
msgstr "Arbeitsablauf wird ausgeführt" msgstr "Arbeitsablauf wird ausgeführt"
#: documents/serialisers.py:483 documents/serialisers.py:840 #: documents/serialisers.py:515 documents/serialisers.py:872
#: documents/serialisers.py:2872 documents/views.py:360 documents/views.py:2730 #: documents/serialisers.py:2902 documents/views.py:363 documents/views.py:2768
#: paperless_mail/serialisers.py:156 #: paperless_mail/serialisers.py:156
msgid "Insufficient permissions." msgid "Insufficient permissions."
msgstr "Unzureichende Berechtigungen." msgstr "Unzureichende Berechtigungen."
#: documents/serialisers.py:676 #: documents/serialisers.py:708
msgid "Invalid color." msgid "Invalid color."
msgstr "Ungültige Farbe." msgstr "Ungültige Farbe."
#: documents/serialisers.py:2339 #: documents/serialisers.py:2369
#, python-format #, python-format
msgid "File type %(type)s not supported" msgid "File type %(type)s not supported"
msgstr "Dateityp %(type)s nicht unterstützt" msgstr "Dateityp %(type)s nicht unterstützt"
#: documents/serialisers.py:2383 #: documents/serialisers.py:2413
#, python-format #, python-format
msgid "Custom field id must be an integer: %(id)s" msgid "Custom field id must be an integer: %(id)s"
msgstr "Feld-ID eines benutzerdefinierten Felds muss eine Ganzzahl sein: %(id)s" msgstr "Feld-ID eines benutzerdefinierten Felds muss eine Ganzzahl sein: %(id)s"
#: documents/serialisers.py:2390 #: documents/serialisers.py:2420
#, python-format #, python-format
msgid "Custom field with id %(id)s does not exist" msgid "Custom field with id %(id)s does not exist"
msgstr "Benutzerdefiniertes Feld mit ID %(id)s existiert nicht" msgstr "Benutzerdefiniertes Feld mit ID %(id)s existiert nicht"
#: documents/serialisers.py:2407 documents/serialisers.py:2417 #: documents/serialisers.py:2437 documents/serialisers.py:2447
msgid "Custom fields must be a list of integers or an object mapping ids to values." msgid "Custom fields must be a list of integers or an object mapping ids to values."
msgstr "Benutzerdefinierte Felder müssen eine Liste von Ganzzahlen oder ein Objekt mit Zuordnung von IDs zu Werten sein." msgstr "Benutzerdefinierte Felder müssen eine Liste von Ganzzahlen oder ein Objekt mit Zuordnung von IDs zu Werten sein."
#: documents/serialisers.py:2412 #: documents/serialisers.py:2442
msgid "Some custom fields don't exist or were specified twice." msgid "Some custom fields don't exist or were specified twice."
msgstr "Einige benutzerdefinierte Felder existieren nicht oder wurden zweimal angegeben." msgstr "Einige benutzerdefinierte Felder existieren nicht oder wurden zweimal angegeben."
#: documents/serialisers.py:2559 #: documents/serialisers.py:2589
msgid "Invalid variable detected." msgid "Invalid variable detected."
msgstr "Ungültige Variable erkannt." msgstr "Ungültige Variable erkannt."
#: documents/serialisers.py:2928 #: documents/serialisers.py:2958
msgid "Duplicate document identifiers are not allowed." msgid "Duplicate document identifiers are not allowed."
msgstr "Doppelte Dokumentbezeichner sind nicht erlaubt." msgstr "Doppelte Dokumentbezeichner sind nicht erlaubt."
#: documents/serialisers.py:2958 documents/views.py:4780 #: documents/serialisers.py:2988 documents/views.py:4816
#, python-format #, python-format
msgid "Documents not found: %(ids)s" msgid "Documents not found: %(ids)s"
msgstr "Dokumente nicht gefunden: %(ids)s" msgstr "Dokumente nicht gefunden: %(ids)s"
@@ -1921,40 +1917,40 @@ msgstr "Bitte füllen Sie zum Abschluss folgendes Formular aus:"
msgid ", " msgid ", "
msgstr "" msgstr ""
#: documents/views.py:315 #: documents/views.py:318
msgid "Specify only one of text, title_search, query, or more_like_id." msgid "Specify only one of text, title_search, query, or more_like_id."
msgstr "Geben Sie nur einen von text, title_search, query, oder more_like_id an." msgstr "Geben Sie nur einen von text, title_search, query, oder more_like_id an."
#: documents/views.py:353 documents/views.py:2727 #: documents/views.py:356 documents/views.py:2765
msgid "Invalid more_like_id" msgid "Invalid more_like_id"
msgstr "Ungültige more_like_id" msgstr "Ungültige more_like_id"
#: documents/views.py:1665 #: documents/views.py:1703
msgid "Invalid AI configuration." msgid "Invalid AI configuration."
msgstr "Ungültige KI-Konfiguration." msgstr "Ungültige KI-Konfiguration."
#: documents/views.py:1676 #: documents/views.py:1714
msgid "AI backend request timed out." msgid "AI backend request timed out."
msgstr "" msgstr ""
#: documents/views.py:1688 #: documents/views.py:1726
msgid "AI backend rejected the request. Check logs for details." msgid "AI backend rejected the request. Check logs for details."
msgstr "" msgstr ""
#: documents/views.py:4796 #: documents/views.py:4832
#, python-format #, python-format
msgid "Insufficient permissions to share document %(id)s." msgid "Insufficient permissions to share document %(id)s."
msgstr "Unzureichende Berechtigungen, um Dokument %(id)s zu teilen." msgstr "Unzureichende Berechtigungen, um Dokument %(id)s zu teilen."
#: documents/views.py:4843 #: documents/views.py:4879
msgid "Bundle is already being processed." msgid "Bundle is already being processed."
msgstr "Paket wird bereits verarbeitet." msgstr "Paket wird bereits verarbeitet."
#: documents/views.py:4909 #: documents/views.py:4945
msgid "The share link bundle is still being prepared. Please try again later." msgid "The share link bundle is still being prepared. Please try again later."
msgstr "Das Freigabelink-Paket wird noch vorbereitet. Bitte versuchen Sie es später erneut." msgstr "Das Freigabelink-Paket wird noch vorbereitet. Bitte versuchen Sie es später erneut."
#: documents/views.py:4923 #: documents/views.py:4959
msgid "The share link bundle is unavailable." msgid "The share link bundle is unavailable."
msgstr "Das Freigabelink-Paket ist nicht verfügbar." msgstr "Das Freigabelink-Paket ist nicht verfügbar."
@@ -2246,151 +2242,151 @@ msgstr ""
msgid "paperless application settings" msgid "paperless application settings"
msgstr "Paperless-ngx-Anwendungseinstellungen" msgstr "Paperless-ngx-Anwendungseinstellungen"
#: paperless/settings/__init__.py:566 #: paperless/settings/__init__.py:562
msgid "English (US)" msgid "English (US)"
msgstr "Englisch (US)" msgstr "Englisch (US)"
#: paperless/settings/__init__.py:567 #: paperless/settings/__init__.py:563
msgid "Arabic" msgid "Arabic"
msgstr "Arabisch" msgstr "Arabisch"
#: paperless/settings/__init__.py:568 #: paperless/settings/__init__.py:564
msgid "Afrikaans" msgid "Afrikaans"
msgstr "Afrikanisch" msgstr "Afrikanisch"
#: paperless/settings/__init__.py:569 #: paperless/settings/__init__.py:565
msgid "Belarusian" msgid "Belarusian"
msgstr "Belarussisch" msgstr "Belarussisch"
#: paperless/settings/__init__.py:570 #: paperless/settings/__init__.py:566
msgid "Bulgarian" msgid "Bulgarian"
msgstr "Bulgarisch" msgstr "Bulgarisch"
#: paperless/settings/__init__.py:571 #: paperless/settings/__init__.py:567
msgid "Catalan" msgid "Catalan"
msgstr "Katalanisch" msgstr "Katalanisch"
#: paperless/settings/__init__.py:572 #: paperless/settings/__init__.py:568
msgid "Czech" msgid "Czech"
msgstr "Tschechisch" msgstr "Tschechisch"
#: paperless/settings/__init__.py:573 #: paperless/settings/__init__.py:569
msgid "Danish" msgid "Danish"
msgstr "Dänisch" msgstr "Dänisch"
#: paperless/settings/__init__.py:574 #: paperless/settings/__init__.py:570
msgid "German" msgid "German"
msgstr "Deutsch" msgstr "Deutsch"
#: paperless/settings/__init__.py:575 #: paperless/settings/__init__.py:571
msgid "Greek" msgid "Greek"
msgstr "Griechisch" msgstr "Griechisch"
#: paperless/settings/__init__.py:576 #: paperless/settings/__init__.py:572
msgid "English (GB)" msgid "English (GB)"
msgstr "Englisch (UK)" msgstr "Englisch (UK)"
#: paperless/settings/__init__.py:577 #: paperless/settings/__init__.py:573
msgid "Spanish" msgid "Spanish"
msgstr "Spanisch" msgstr "Spanisch"
#: paperless/settings/__init__.py:578 #: paperless/settings/__init__.py:574
msgid "Persian" msgid "Persian"
msgstr "Persisch" msgstr "Persisch"
#: paperless/settings/__init__.py:579 #: paperless/settings/__init__.py:575
msgid "Finnish" msgid "Finnish"
msgstr "Finnisch" msgstr "Finnisch"
#: paperless/settings/__init__.py:580 #: paperless/settings/__init__.py:576
msgid "French" msgid "French"
msgstr "Französisch" msgstr "Französisch"
#: paperless/settings/__init__.py:581 #: paperless/settings/__init__.py:577
msgid "Hungarian" msgid "Hungarian"
msgstr "Ungarisch" msgstr "Ungarisch"
#: paperless/settings/__init__.py:582 #: paperless/settings/__init__.py:578
msgid "Indonesian" msgid "Indonesian"
msgstr "Indonesisch" msgstr "Indonesisch"
#: paperless/settings/__init__.py:583 #: paperless/settings/__init__.py:579
msgid "Italian" msgid "Italian"
msgstr "Italienisch" msgstr "Italienisch"
#: paperless/settings/__init__.py:584 #: paperless/settings/__init__.py:580
msgid "Japanese" msgid "Japanese"
msgstr "Japanisch" msgstr "Japanisch"
#: paperless/settings/__init__.py:585 #: paperless/settings/__init__.py:581
msgid "Korean" msgid "Korean"
msgstr "Koreanisch" msgstr "Koreanisch"
#: paperless/settings/__init__.py:586 #: paperless/settings/__init__.py:582
msgid "Luxembourgish" msgid "Luxembourgish"
msgstr "Luxemburgisch" msgstr "Luxemburgisch"
#: paperless/settings/__init__.py:587 #: paperless/settings/__init__.py:583
msgid "Norwegian" msgid "Norwegian"
msgstr "Norwegisch" msgstr "Norwegisch"
#: paperless/settings/__init__.py:588 #: paperless/settings/__init__.py:584
msgid "Dutch" msgid "Dutch"
msgstr "Niederländisch" msgstr "Niederländisch"
#: paperless/settings/__init__.py:589 #: paperless/settings/__init__.py:585
msgid "Polish" msgid "Polish"
msgstr "Polnisch" msgstr "Polnisch"
#: paperless/settings/__init__.py:590 #: paperless/settings/__init__.py:586
msgid "Portuguese (Brazil)" msgid "Portuguese (Brazil)"
msgstr "Portugiesisch (Brasilien)" msgstr "Portugiesisch (Brasilien)"
#: paperless/settings/__init__.py:591 #: paperless/settings/__init__.py:587
msgid "Portuguese" msgid "Portuguese"
msgstr "Portugiesisch" msgstr "Portugiesisch"
#: paperless/settings/__init__.py:592 #: paperless/settings/__init__.py:588
msgid "Romanian" msgid "Romanian"
msgstr "Rumänisch" msgstr "Rumänisch"
#: paperless/settings/__init__.py:593 #: paperless/settings/__init__.py:589
msgid "Russian" msgid "Russian"
msgstr "Russisch" msgstr "Russisch"
#: paperless/settings/__init__.py:594 #: paperless/settings/__init__.py:590
msgid "Slovak" msgid "Slovak"
msgstr "Slowakisch" msgstr "Slowakisch"
#: paperless/settings/__init__.py:595 #: paperless/settings/__init__.py:591
msgid "Slovenian" msgid "Slovenian"
msgstr "Slowenisch" msgstr "Slowenisch"
#: paperless/settings/__init__.py:596 #: paperless/settings/__init__.py:592
msgid "Serbian" msgid "Serbian"
msgstr "Serbisch" msgstr "Serbisch"
#: paperless/settings/__init__.py:597 #: paperless/settings/__init__.py:593
msgid "Swedish" msgid "Swedish"
msgstr "Schwedisch" msgstr "Schwedisch"
#: paperless/settings/__init__.py:598 #: paperless/settings/__init__.py:594
msgid "Turkish" msgid "Turkish"
msgstr "Türkisch" msgstr "Türkisch"
#: paperless/settings/__init__.py:599 #: paperless/settings/__init__.py:595
msgid "Ukrainian" msgid "Ukrainian"
msgstr "Ukrainisch" msgstr "Ukrainisch"
#: paperless/settings/__init__.py:600 #: paperless/settings/__init__.py:596
msgid "Vietnamese" msgid "Vietnamese"
msgstr "Vietnamesisch" msgstr "Vietnamesisch"
#: paperless/settings/__init__.py:601 #: paperless/settings/__init__.py:597
msgid "Chinese Simplified" msgid "Chinese Simplified"
msgstr "Chinesisch (vereinfacht)" msgstr "Chinesisch (vereinfacht)"
#: paperless/settings/__init__.py:602 #: paperless/settings/__init__.py:598
msgid "Chinese Traditional" msgid "Chinese Traditional"
msgstr "Chinesisch (traditionell)" msgstr "Chinesisch (traditionell)"
+68 -72
View File
@@ -2,8 +2,8 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: paperless-ngx\n" "Project-Id-Version: paperless-ngx\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-10-29 17:25+0000\n" "POT-Creation-Date: 2026-10-19 15:40+0000\n"
"PO-Revision-Date: 2026-10-29 17:27\n" "PO-Revision-Date: 2026-10-19 15:42\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: German\n" "Language-Team: German\n"
"Language: de_DE\n" "Language: de_DE\n"
@@ -21,43 +21,39 @@ msgstr ""
msgid "Documents" msgid "Documents"
msgstr "Dokumente" msgstr "Dokumente"
#: documents/filters.py:337 #: documents/filters.py:464
msgid "Expected a date or a relative date such as \"today\" or \"in 30 days\"."
msgstr ""
#: documents/filters.py:513
msgid "Value must be valid JSON." msgid "Value must be valid JSON."
msgstr "Wert muss gültiges JSON sein." msgstr "Wert muss gültiges JSON sein."
#: documents/filters.py:534 #: documents/filters.py:483
msgid "Invalid custom field query expression" msgid "Invalid custom field query expression"
msgstr "Ungültiger Zusatzfeld-Abfrageausdruck" msgstr "Ungültiger Zusatzfeld-Abfrageausdruck"
#: documents/filters.py:544 #: documents/filters.py:493
msgid "Invalid expression list. Must be nonempty." msgid "Invalid expression list. Must be nonempty."
msgstr "Ungültige Ausdrucksliste. Darf nicht leer sein." msgstr "Ungültige Ausdrucksliste. Darf nicht leer sein."
#: documents/filters.py:565 #: documents/filters.py:514
msgid "Invalid logical operator {op!r}" msgid "Invalid logical operator {op!r}"
msgstr "Ungültiger logischer Operator {op!r}" msgstr "Ungültiger logischer Operator {op!r}"
#: documents/filters.py:579 #: documents/filters.py:528
msgid "Maximum number of query conditions exceeded." msgid "Maximum number of query conditions exceeded."
msgstr "Maximale Anzahl an Abfragebedingungen überschritten." msgstr "Maximale Anzahl an Abfragebedingungen überschritten."
#: documents/filters.py:643 #: documents/filters.py:592
msgid "{name!r} is not a valid custom field." msgid "{name!r} is not a valid custom field."
msgstr "{name!r} ist kein gültiges Zusatzfeld." msgstr "{name!r} ist kein gültiges Zusatzfeld."
#: documents/filters.py:680 #: documents/filters.py:629
msgid "{data_type} does not support query expr {expr!r}." msgid "{data_type} does not support query expr {expr!r}."
msgstr "{data_type} unterstützt den Abfrageausdruck {expr!r} nicht." msgstr "{data_type} unterstützt den Abfrageausdruck {expr!r} nicht."
#: documents/filters.py:801 documents/models.py:137 #: documents/filters.py:748 documents/models.py:137
msgid "Maximum nesting depth exceeded." msgid "Maximum nesting depth exceeded."
msgstr "Maximale Verschachtelungstiefe überschritten." msgstr "Maximale Verschachtelungstiefe überschritten."
#: documents/filters.py:1178 #: documents/filters.py:1125
msgid "Custom field not found" msgid "Custom field not found"
msgstr "Zusatzfeld nicht gefunden" msgstr "Zusatzfeld nicht gefunden"
@@ -1639,48 +1635,48 @@ msgstr "Arbeitsablauf-Ausführung"
msgid "workflow runs" msgid "workflow runs"
msgstr "Arbeitsablauf wird ausgeführt" msgstr "Arbeitsablauf wird ausgeführt"
#: documents/serialisers.py:483 documents/serialisers.py:840 #: documents/serialisers.py:515 documents/serialisers.py:872
#: documents/serialisers.py:2872 documents/views.py:360 documents/views.py:2730 #: documents/serialisers.py:2902 documents/views.py:363 documents/views.py:2768
#: paperless_mail/serialisers.py:156 #: paperless_mail/serialisers.py:156
msgid "Insufficient permissions." msgid "Insufficient permissions."
msgstr "Unzureichende Berechtigungen." msgstr "Unzureichende Berechtigungen."
#: documents/serialisers.py:676 #: documents/serialisers.py:708
msgid "Invalid color." msgid "Invalid color."
msgstr "Ungültige Farbe." msgstr "Ungültige Farbe."
#: documents/serialisers.py:2339 #: documents/serialisers.py:2369
#, python-format #, python-format
msgid "File type %(type)s not supported" msgid "File type %(type)s not supported"
msgstr "Dateityp %(type)s nicht unterstützt" msgstr "Dateityp %(type)s nicht unterstützt"
#: documents/serialisers.py:2383 #: documents/serialisers.py:2413
#, python-format #, python-format
msgid "Custom field id must be an integer: %(id)s" msgid "Custom field id must be an integer: %(id)s"
msgstr "Zusatzfeld-ID muss eine Ganzzahl sein: %(id)s" msgstr "Zusatzfeld-ID muss eine Ganzzahl sein: %(id)s"
#: documents/serialisers.py:2390 #: documents/serialisers.py:2420
#, python-format #, python-format
msgid "Custom field with id %(id)s does not exist" msgid "Custom field with id %(id)s does not exist"
msgstr "Zusatzfeld mit ID %(id)s existiert nicht" msgstr "Zusatzfeld mit ID %(id)s existiert nicht"
#: documents/serialisers.py:2407 documents/serialisers.py:2417 #: documents/serialisers.py:2437 documents/serialisers.py:2447
msgid "Custom fields must be a list of integers or an object mapping ids to values." msgid "Custom fields must be a list of integers or an object mapping ids to values."
msgstr "Zusatzfelder müssen eine Liste von Ganzzahlen oder ein Objekt mit Zuordnung von IDs zu Werten sein." msgstr "Zusatzfelder müssen eine Liste von Ganzzahlen oder ein Objekt mit Zuordnung von IDs zu Werten sein."
#: documents/serialisers.py:2412 #: documents/serialisers.py:2442
msgid "Some custom fields don't exist or were specified twice." msgid "Some custom fields don't exist or were specified twice."
msgstr "Einige Zusatzfelder existieren nicht oder wurden zweimal angegeben." msgstr "Einige Zusatzfelder existieren nicht oder wurden zweimal angegeben."
#: documents/serialisers.py:2559 #: documents/serialisers.py:2589
msgid "Invalid variable detected." msgid "Invalid variable detected."
msgstr "Ungültige Variable erkannt." msgstr "Ungültige Variable erkannt."
#: documents/serialisers.py:2928 #: documents/serialisers.py:2958
msgid "Duplicate document identifiers are not allowed." msgid "Duplicate document identifiers are not allowed."
msgstr "Doppelte Dokumentbezeichner sind nicht erlaubt." msgstr "Doppelte Dokumentbezeichner sind nicht erlaubt."
#: documents/serialisers.py:2958 documents/views.py:4780 #: documents/serialisers.py:2988 documents/views.py:4816
#, python-format #, python-format
msgid "Documents not found: %(ids)s" msgid "Documents not found: %(ids)s"
msgstr "Dokumente nicht gefunden: %(ids)s" msgstr "Dokumente nicht gefunden: %(ids)s"
@@ -1921,40 +1917,40 @@ msgstr "Bitte füllen Sie zum Abschluss folgendes Formular aus:"
msgid ", " msgid ", "
msgstr ", " msgstr ", "
#: documents/views.py:315 #: documents/views.py:318
msgid "Specify only one of text, title_search, query, or more_like_id." msgid "Specify only one of text, title_search, query, or more_like_id."
msgstr "Geben Sie nur einen von text, title_search, query, oder more_like_id an." msgstr "Geben Sie nur einen von text, title_search, query, oder more_like_id an."
#: documents/views.py:353 documents/views.py:2727 #: documents/views.py:356 documents/views.py:2765
msgid "Invalid more_like_id" msgid "Invalid more_like_id"
msgstr "Ungültige more_like_id" msgstr "Ungültige more_like_id"
#: documents/views.py:1665 #: documents/views.py:1703
msgid "Invalid AI configuration." msgid "Invalid AI configuration."
msgstr "Ungültige KI-Konfiguration." msgstr "Ungültige KI-Konfiguration."
#: documents/views.py:1676 #: documents/views.py:1714
msgid "AI backend request timed out." msgid "AI backend request timed out."
msgstr "Zeitüberschreitung bei der KI-Backendanfrage." msgstr "Zeitüberschreitung bei der KI-Backendanfrage."
#: documents/views.py:1688 #: documents/views.py:1726
msgid "AI backend rejected the request. Check logs for details." msgid "AI backend rejected the request. Check logs for details."
msgstr "Das KI-Backend hat die Anfrage abgelehnt. Details in den Protokollen." msgstr "Das KI-Backend hat die Anfrage abgelehnt. Details in den Protokollen."
#: documents/views.py:4796 #: documents/views.py:4832
#, python-format #, python-format
msgid "Insufficient permissions to share document %(id)s." msgid "Insufficient permissions to share document %(id)s."
msgstr "Unzureichende Berechtigungen, um Dokument %(id)s zu teilen." msgstr "Unzureichende Berechtigungen, um Dokument %(id)s zu teilen."
#: documents/views.py:4843 #: documents/views.py:4879
msgid "Bundle is already being processed." msgid "Bundle is already being processed."
msgstr "Paket wird bereits verarbeitet." msgstr "Paket wird bereits verarbeitet."
#: documents/views.py:4909 #: documents/views.py:4945
msgid "The share link bundle is still being prepared. Please try again later." msgid "The share link bundle is still being prepared. Please try again later."
msgstr "Das Freigabelink-Paket wird noch vorbereitet. Bitte versuchen Sie es später erneut." msgstr "Das Freigabelink-Paket wird noch vorbereitet. Bitte versuchen Sie es später erneut."
#: documents/views.py:4923 #: documents/views.py:4959
msgid "The share link bundle is unavailable." msgid "The share link bundle is unavailable."
msgstr "Das Freigabelink-Paket ist nicht verfügbar." msgstr "Das Freigabelink-Paket ist nicht verfügbar."
@@ -2246,151 +2242,151 @@ msgstr "Legt das LLM-Zeitlimit in Sekunden fest"
msgid "paperless application settings" msgid "paperless application settings"
msgstr "Paperless-ngx-Anwendungseinstellungen" msgstr "Paperless-ngx-Anwendungseinstellungen"
#: paperless/settings/__init__.py:566 #: paperless/settings/__init__.py:562
msgid "English (US)" msgid "English (US)"
msgstr "Englisch (US)" msgstr "Englisch (US)"
#: paperless/settings/__init__.py:567 #: paperless/settings/__init__.py:563
msgid "Arabic" msgid "Arabic"
msgstr "Arabisch" msgstr "Arabisch"
#: paperless/settings/__init__.py:568 #: paperless/settings/__init__.py:564
msgid "Afrikaans" msgid "Afrikaans"
msgstr "Afrikanisch" msgstr "Afrikanisch"
#: paperless/settings/__init__.py:569 #: paperless/settings/__init__.py:565
msgid "Belarusian" msgid "Belarusian"
msgstr "Belarussisch" msgstr "Belarussisch"
#: paperless/settings/__init__.py:570 #: paperless/settings/__init__.py:566
msgid "Bulgarian" msgid "Bulgarian"
msgstr "Bulgarisch" msgstr "Bulgarisch"
#: paperless/settings/__init__.py:571 #: paperless/settings/__init__.py:567
msgid "Catalan" msgid "Catalan"
msgstr "Katalanisch" msgstr "Katalanisch"
#: paperless/settings/__init__.py:572 #: paperless/settings/__init__.py:568
msgid "Czech" msgid "Czech"
msgstr "Tschechisch" msgstr "Tschechisch"
#: paperless/settings/__init__.py:573 #: paperless/settings/__init__.py:569
msgid "Danish" msgid "Danish"
msgstr "Dänisch" msgstr "Dänisch"
#: paperless/settings/__init__.py:574 #: paperless/settings/__init__.py:570
msgid "German" msgid "German"
msgstr "Deutsch" msgstr "Deutsch"
#: paperless/settings/__init__.py:575 #: paperless/settings/__init__.py:571
msgid "Greek" msgid "Greek"
msgstr "Griechisch" msgstr "Griechisch"
#: paperless/settings/__init__.py:576 #: paperless/settings/__init__.py:572
msgid "English (GB)" msgid "English (GB)"
msgstr "Englisch (UK)" msgstr "Englisch (UK)"
#: paperless/settings/__init__.py:577 #: paperless/settings/__init__.py:573
msgid "Spanish" msgid "Spanish"
msgstr "Spanisch" msgstr "Spanisch"
#: paperless/settings/__init__.py:578 #: paperless/settings/__init__.py:574
msgid "Persian" msgid "Persian"
msgstr "Persisch" msgstr "Persisch"
#: paperless/settings/__init__.py:579 #: paperless/settings/__init__.py:575
msgid "Finnish" msgid "Finnish"
msgstr "Finnisch" msgstr "Finnisch"
#: paperless/settings/__init__.py:580 #: paperless/settings/__init__.py:576
msgid "French" msgid "French"
msgstr "Französisch" msgstr "Französisch"
#: paperless/settings/__init__.py:581 #: paperless/settings/__init__.py:577
msgid "Hungarian" msgid "Hungarian"
msgstr "Ungarisch" msgstr "Ungarisch"
#: paperless/settings/__init__.py:582 #: paperless/settings/__init__.py:578
msgid "Indonesian" msgid "Indonesian"
msgstr "Indonesisch" msgstr "Indonesisch"
#: paperless/settings/__init__.py:583 #: paperless/settings/__init__.py:579
msgid "Italian" msgid "Italian"
msgstr "Italienisch" msgstr "Italienisch"
#: paperless/settings/__init__.py:584 #: paperless/settings/__init__.py:580
msgid "Japanese" msgid "Japanese"
msgstr "Japanisch" msgstr "Japanisch"
#: paperless/settings/__init__.py:585 #: paperless/settings/__init__.py:581
msgid "Korean" msgid "Korean"
msgstr "Koreanisch" msgstr "Koreanisch"
#: paperless/settings/__init__.py:586 #: paperless/settings/__init__.py:582
msgid "Luxembourgish" msgid "Luxembourgish"
msgstr "Luxemburgisch" msgstr "Luxemburgisch"
#: paperless/settings/__init__.py:587 #: paperless/settings/__init__.py:583
msgid "Norwegian" msgid "Norwegian"
msgstr "Norwegisch" msgstr "Norwegisch"
#: paperless/settings/__init__.py:588 #: paperless/settings/__init__.py:584
msgid "Dutch" msgid "Dutch"
msgstr "Niederländisch" msgstr "Niederländisch"
#: paperless/settings/__init__.py:589 #: paperless/settings/__init__.py:585
msgid "Polish" msgid "Polish"
msgstr "Polnisch" msgstr "Polnisch"
#: paperless/settings/__init__.py:590 #: paperless/settings/__init__.py:586
msgid "Portuguese (Brazil)" msgid "Portuguese (Brazil)"
msgstr "Portugiesisch (Brasilien)" msgstr "Portugiesisch (Brasilien)"
#: paperless/settings/__init__.py:591 #: paperless/settings/__init__.py:587
msgid "Portuguese" msgid "Portuguese"
msgstr "Portugiesisch" msgstr "Portugiesisch"
#: paperless/settings/__init__.py:592 #: paperless/settings/__init__.py:588
msgid "Romanian" msgid "Romanian"
msgstr "Rumänisch" msgstr "Rumänisch"
#: paperless/settings/__init__.py:593 #: paperless/settings/__init__.py:589
msgid "Russian" msgid "Russian"
msgstr "Russisch" msgstr "Russisch"
#: paperless/settings/__init__.py:594 #: paperless/settings/__init__.py:590
msgid "Slovak" msgid "Slovak"
msgstr "Slowakisch" msgstr "Slowakisch"
#: paperless/settings/__init__.py:595 #: paperless/settings/__init__.py:591
msgid "Slovenian" msgid "Slovenian"
msgstr "Slowenisch" msgstr "Slowenisch"
#: paperless/settings/__init__.py:596 #: paperless/settings/__init__.py:592
msgid "Serbian" msgid "Serbian"
msgstr "Serbisch" msgstr "Serbisch"
#: paperless/settings/__init__.py:597 #: paperless/settings/__init__.py:593
msgid "Swedish" msgid "Swedish"
msgstr "Schwedisch" msgstr "Schwedisch"
#: paperless/settings/__init__.py:598 #: paperless/settings/__init__.py:594
msgid "Turkish" msgid "Turkish"
msgstr "Türkisch" msgstr "Türkisch"
#: paperless/settings/__init__.py:599 #: paperless/settings/__init__.py:595
msgid "Ukrainian" msgid "Ukrainian"
msgstr "Ukrainisch" msgstr "Ukrainisch"
#: paperless/settings/__init__.py:600 #: paperless/settings/__init__.py:596
msgid "Vietnamese" msgid "Vietnamese"
msgstr "Vietnamesisch" msgstr "Vietnamesisch"
#: paperless/settings/__init__.py:601 #: paperless/settings/__init__.py:597
msgid "Chinese Simplified" msgid "Chinese Simplified"
msgstr "Chinesisch (vereinfacht)" msgstr "Chinesisch (vereinfacht)"
#: paperless/settings/__init__.py:602 #: paperless/settings/__init__.py:598
msgid "Chinese Traditional" msgid "Chinese Traditional"
msgstr "Chinesisch (traditionell)" msgstr "Chinesisch (traditionell)"
Loaded 100 of 159 files, more files were not shown because too many files have changed in this diff. Show more