Compare commits

..
Author SHA1 Message Date
Crowdin Bot 8ac3ca0d6f New Crowdin translations by GitHub Action 2026-10-07 12:33:24 +00:00
59 changed files with 457 additions and 1829 deletions

No files matched your search

+1 -1
View File
@@ -111,7 +111,7 @@ jobs:
timeout-minutes: 12 timeout-minutes: 12
uses: $/.github/actions/apt-install uses: $/.github/actions/apt-install
with: with:
packages: unpaper tesseract-ocr imagemagick ghostscript poppler-utils qpdf packages: unpaper tesseract-ocr imagemagick ghostscript poppler-utils
- name: Configure ImageMagick - name: Configure ImageMagick
run: | run: |
sudo cp docker/rootfs/etc/ImageMagick-6/paperless-policy.xml /etc/ImageMagick-7/policy.xml sudo cp docker/rootfs/etc/ImageMagick-6/paperless-policy.xml /etc/ImageMagick-7/policy.xml
+18 -6
View File
@@ -1315,17 +1315,29 @@ valid crontab(5) expression describing when to run.
#### [`PAPERLESS_CONVERT_MEMORY_LIMIT=<num>`](#PAPERLESS_CONVERT_MEMORY_LIMIT) {#PAPERLESS_CONVERT_MEMORY_LIMIT} #### [`PAPERLESS_CONVERT_MEMORY_LIMIT=<num>`](#PAPERLESS_CONVERT_MEMORY_LIMIT) {#PAPERLESS_CONVERT_MEMORY_LIMIT}
!!! warning : On smaller systems, or even in the case of Very Large Documents, the
consumer may explode, complaining about how it's "unable to extend
pixel cache". In such cases, try setting this to a reasonably low
value, like 32. The default is to use whatever is necessary to do
everything without writing to disk, and units are in megabytes.
Deprecated and has no effect, since PDF thumbnails no longer use For more information on how to use this value, you should search the
ImageMagick. It will be removed in a future release. web for "MAGICK_MEMORY_LIMIT".
Defaults to 0, which disables the limit.
#### [`PAPERLESS_CONVERT_TMPDIR=<path>`](#PAPERLESS_CONVERT_TMPDIR) {#PAPERLESS_CONVERT_TMPDIR} #### [`PAPERLESS_CONVERT_TMPDIR=<path>`](#PAPERLESS_CONVERT_TMPDIR) {#PAPERLESS_CONVERT_TMPDIR}
!!! warning : Similar to the memory limit, if you've got a small system and your
OS mounts /tmp as tmpfs, you should set this to a path that's on a
physical disk, like /home/your_user/tmp or something. ImageMagick
will use this as scratch space when crunching through very large
documents.
Deprecated and has no effect, since PDF thumbnails no longer use For more information on how to use this value, you should search the
ImageMagick. It will be removed in a future release. web for "MAGICK_TMPDIR".
Default is none, which disables the temporary directory.
#### [`PAPERLESS_APPS=<string>`](#PAPERLESS_APPS) {#PAPERLESS_APPS} #### [`PAPERLESS_APPS=<string>`](#PAPERLESS_APPS) {#PAPERLESS_APPS}
+7 -4
View File
@@ -177,12 +177,12 @@ to a positive number to enable polling and disable native filesystem notificatio
- `pkg-config` for mysqlclient (python dependency) - `pkg-config` for mysqlclient (python dependency)
- `fonts-liberation` for generating thumbnails for plain text - `fonts-liberation` for generating thumbnails for plain text
files files
- `imagemagick` >= 6 for image alpha handling - `imagemagick` >= 6 for PDF conversion
- `gnupg` for decrypting GPG-encrypted email - `gnupg` for decrypting GPG-encrypted email
- `libpq-dev` for PostgreSQL - `libpq-dev` for PostgreSQL
- `libmagic-dev` for mime type detection - `libmagic-dev` for mime type detection
- `mariadb-client` for MariaDB compile time - `mariadb-client` for MariaDB compile time
- `poppler-utils` for thumbnail generation and barcode detection - `poppler-utils` for barcode detection
Use this list for your preferred package management: Use this list for your preferred package management:
@@ -416,8 +416,11 @@ to a positive number to enable polling and disable native filesystem notificatio
You may need to change the path in the files. Example: You may need to change the path in the files. Example:
`ExecStart=/opt/paperless/.local/bin/celery --app paperless worker --loglevel INFO` `ExecStart=/opt/paperless/.local/bin/celery --app paperless worker --loglevel INFO`
12. Harden ImageMagick by disabling formats that Paperless-ngx does not use. 12. Configure ImageMagick to allow processing of PDF documents and disable
PDF processing is not needed and should stay disabled. formats that Paperless-ngx does not use. Most distributions disable PDF
processing by default, since PDF documents can contain malware. If you
don't enable it, Paperless-ngx will fall back to Ghostscript for certain
steps such as thumbnail generation.
Configure the active ImageMagick policy file (commonly Configure the active ImageMagick policy file (commonly
`/etc/ImageMagick-6/policy.xml` or `/etc/ImageMagick-7/policy.xml`) and `/etc/ImageMagick-6/policy.xml` or `/etc/ImageMagick-7/policy.xml`) and
+2
View File
@@ -50,6 +50,8 @@ PAPERLESS_SECRET_KEY=change-me
#PAPERLESS_OCR_ROTATE_PAGES=true #PAPERLESS_OCR_ROTATE_PAGES=true
#PAPERLESS_OCR_ROTATE_PAGES_THRESHOLD=12.0 #PAPERLESS_OCR_ROTATE_PAGES_THRESHOLD=12.0
#PAPERLESS_OCR_USER_ARGS={} #PAPERLESS_OCR_USER_ARGS={}
#PAPERLESS_CONVERT_MEMORY_LIMIT=0
#PAPERLESS_CONVERT_TMPDIR=/var/tmp/paperless
# Software tweaks # Software tweaks
+1 -1
View File
@@ -8525,7 +8525,7 @@
<context context-type="sourcefile">src/app/components/common/suggestions-dropdown/suggestions-dropdown.component.html</context> <context context-type="sourcefile">src/app/components/common/suggestions-dropdown/suggestions-dropdown.component.html</context>
<context context-type="linenumber">54</context> <context context-type="linenumber">54</context>
</context-group> </context-group>
<target state="needs-translation">{VAR_PLURAL, plural, =1 {1 suggestion available below} other {<x id="INTERPOLATION"/> suggestions available below}}</target> <target state="translated">{VAR_PLURAL, plural, =1 {1 Vorschlag unten verfügbar} other {<x id="INTERPOLATION"/> Vorschläge unten verfügbar}}</target>
</trans-unit> </trans-unit>
<trans-unit id="4169875112244042673" datatype="html" approved="yes"> <trans-unit id="4169875112244042673" datatype="html" approved="yes">
<source>Suggestion options</source> <source>Suggestion options</source>
File diff suppressed because it is too large. Load diff
+96 -159
View File
@@ -1,8 +1,8 @@
from __future__ import annotations from __future__ import annotations
import logging import logging
import math
import mimetypes import mimetypes
import os
import shutil import shutil
import subprocess import subprocess
import tempfile import tempfile
@@ -68,6 +68,58 @@ def get_supported_file_extensions() -> set[str]:
return extensions return extensions
def run_convert(
input_file,
output_file,
*,
density=None,
scale=None,
alpha=None,
strip=False,
trim=False,
type=None,
depth=None,
auto_orient=False,
use_cropbox=False,
extra=None,
logging_group=None,
) -> None:
environment = os.environ.copy()
if settings.CONVERT_MEMORY_LIMIT:
# MAGICK_MEMORY_LIMIT sets the maximum amount of RAM the pixel cache can use.
# MAGICK_MAP_LIMIT sets the maximum amount of memory-mapped I/O allowed.
#
# For large-format documents ImageMagick will hit the RAM limit and
# immediately try to "map" the remaining data. If MAGICK_MAP_LIMIT isn't
# also set, the process may trigger an OOM kill because the default
# system/policy map limit is often too restrictive for these massive bitmaps.
environment["MAGICK_MEMORY_LIMIT"] = settings.CONVERT_MEMORY_LIMIT
environment["MAGICK_MAP_LIMIT"] = settings.CONVERT_MEMORY_LIMIT
if settings.CONVERT_TMPDIR:
environment["MAGICK_TMPDIR"] = settings.CONVERT_TMPDIR
args = [settings.CONVERT_BINARY]
args += ["-density", str(density)] if density else []
args += ["-scale", str(scale)] if scale else []
args += ["-alpha", str(alpha)] if alpha else []
args += ["-strip"] if strip else []
args += ["-trim"] if trim else []
args += ["-type", str(type)] if type else []
args += ["-depth", str(depth)] if depth else []
args += ["-auto-orient"] if auto_orient else []
args += ["-define", "pdf:use-cropbox=true"] if use_cropbox else []
args += [str(input_file), str(output_file)]
logger.debug("Execute: " + " ".join(args), extra={"group": logging_group})
try:
run_subprocess(args, environment, logger)
except subprocess.CalledProcessError as e:
raise ParseError(f"Convert failed at {args}") from e
except Exception as e: # pragma: no cover
raise ParseError("Unknown error running convert") from e
def get_default_thumbnail() -> Path: def get_default_thumbnail() -> Path:
""" """
Returns the path to a generic thumbnail Returns the path to a generic thumbnail
@@ -75,168 +127,46 @@ def get_default_thumbnail() -> Path:
return (Path(__file__).parent / "resources" / "document.webp").resolve() return (Path(__file__).parent / "resources" / "document.webp").resolve()
_THUMBNAIL_MAX_WIDTH = 500 def make_thumbnail_from_pdf_gs_fallback(in_path, temp_dir, logging_group=None) -> Path:
_THUMBNAIL_MAX_HEIGHT = 5000 out_path: Path = Path(temp_dir) / "convert_gs.webp"
# Used only when the page geometry cannot be read
_THUMBNAIL_FALLBACK_DPI = 150
# Applied before supersampling, so tiny pages are not enlarged
_THUMBNAIL_MAX_DPI = 300
# Rendering at a multiple and downsampling keeps text crisper
_THUMBNAIL_SUPERSAMPLE = 2
def rasterize_pdf_page_to_png(
in_path: Path,
out_path: Path,
*,
dpi: int,
logging_group=None,
) -> None:
"""
Rasterizes the first page of a PDF to a PNG with pdftoppm.
"""
# -singlefile drops the page number and -png appends ".png", so pass the
# path without its suffix
args = [
"pdftoppm",
"-f",
"1",
"-l",
"1",
"-r",
str(dpi),
"-png",
"-singlefile",
"-cropbox",
str(in_path),
str(out_path.with_suffix("")),
]
logger.debug("Execute: " + " ".join(args), extra={"group": logging_group})
try:
run_subprocess(args, logger=logger)
except subprocess.CalledProcessError as e:
raise ParseError(f"pdftoppm failed at {args}") from e
except Exception as e: # pragma: no cover
raise ParseError("Unknown error running pdftoppm") from e
def encode_thumbnail_webp(
png_path: Path,
out_path: Path,
*,
supersample: int = 1,
) -> None:
"""
Flattens alpha onto white, undoes supersampling, shrinks to fit and saves as WebP.
"""
from PIL import Image
try:
with Image.open(png_path) as im:
if im.mode in ("RGBA", "LA"):
flattened = Image.new("RGB", im.size, (255, 255, 255))
flattened.paste(im, mask=im.split()[-1])
else:
flattened = im.convert("RGB")
if supersample > 1:
flattened = flattened.resize(
(
max(1, round(flattened.width / supersample)),
max(1, round(flattened.height / supersample)),
),
Image.Resampling.LANCZOS,
)
flattened.thumbnail((_THUMBNAIL_MAX_WIDTH, _THUMBNAIL_MAX_HEIGHT))
flattened.save(out_path, format="WEBP")
except (OSError, Image.DecompressionBombError) as e:
raise ParseError(f"Unable to encode thumbnail from {png_path}") from e
def _compute_thumbnail_dpi(in_path: Path, logging_group=None) -> tuple[int, int]:
"""
Returns (dpi, supersample). Unknown geometry is not supersampled, since
the render size cannot be bounded.
"""
from paperless.parsers.utils import get_pdf_first_page_size_points
size = get_pdf_first_page_size_points(in_path)
if size is None:
logger.debug(
"Could not read PDF page size, using fallback DPI",
extra={"group": logging_group},
)
return _THUMBNAIL_FALLBACK_DPI, 1
width_pts, height_pts = size
dpi_for_width = _THUMBNAIL_MAX_WIDTH * 72 / width_pts
dpi_for_height = _THUMBNAIL_MAX_HEIGHT * 72 / height_pts
# Round up so the downsampled render is never a few pixels short of the
# target; the shrink-only clamp in encode_thumbnail_webp trims the excess.
dpi = max(
1,
math.ceil(min(_THUMBNAIL_MAX_DPI, dpi_for_width, dpi_for_height)),
)
# At the 1 DPI floor the page is already oversized, so do not supersample
return dpi, 1 if dpi == 1 else _THUMBNAIL_SUPERSAMPLE
def _render_pdf_thumbnail(
in_path: Path,
png_path: Path,
out_path: Path,
logging_group=None,
) -> None:
dpi, supersample = _compute_thumbnail_dpi(in_path, logging_group=logging_group)
rasterize_pdf_page_to_png(
in_path,
png_path,
dpi=dpi * supersample,
logging_group=logging_group,
)
encode_thumbnail_webp(png_path, out_path, supersample=supersample)
def _repair_pdf_with_qpdf(in_path: Path, out_path: Path) -> None:
# qpdf exits 3 after a repair; --warning-exit-0 keeps that from failing
try:
shutil.copy(in_path, out_path)
run_subprocess(
["qpdf", "--warning-exit-0", "--replace-input", str(out_path)],
logger=logger,
)
except (subprocess.CalledProcessError, OSError) as e:
raise ParseError(f"qpdf repair failed for {in_path}") from e
def make_thumbnail_from_pdf_qpdf_fallback(
in_path: Path,
temp_dir: Path,
logging_group=None,
) -> Path:
png_path = temp_dir / "page1_repaired.png"
out_path = temp_dir / "convert_qpdf.webp"
repaired_path = temp_dir / "repaired.pdf"
# if convert fails, fall back to extracting
# the first PDF page as a PNG using Ghostscript
logger.warning( logger.warning(
"Thumbnail generation with pdftoppm failed, attempting qpdf repair and retry.", "Thumbnail generation with ImageMagick failed, falling back "
"to ghostscript. Check your /etc/ImageMagick-x/policy.xml!",
extra={"group": logging_group}, extra={"group": logging_group},
) )
# Ghostscript doesn't handle WebP outputs
gs_out_path: Path = Path(temp_dir) / "gs_out.png"
cmd = [settings.GS_BINARY, "-q", "-sDEVICE=pngalpha", "-o", gs_out_path, in_path]
try: try:
_repair_pdf_with_qpdf(in_path, repaired_path) try:
_render_pdf_thumbnail(repaired_path, png_path, out_path, logging_group) run_subprocess(cmd, logger=logger)
except subprocess.CalledProcessError as e:
raise ParseError(f"Thumbnail (gs) failed at {cmd}") from e
# then run convert on the output from gs to make WebP
run_convert(
density=300,
scale="500x5000>",
alpha="remove",
strip=True,
trim=False,
auto_orient=True,
input_file=gs_out_path,
output_file=out_path,
logging_group=logging_group,
)
return out_path return out_path
except ParseError as e: except ParseError as e:
logger.error(f"Unable to make thumbnail after qpdf repair: {e}") logger.error(f"Unable to make thumbnail with Ghostscript: {e}")
# The caller might expect a generated thumbnail that can be moved, # The caller might expect a generated thumbnail that can be moved,
# so we need to copy it before it gets moved. # so we need to copy it before it gets moved.
# https://github.com/paperless-ngx/paperless-ngx/issues/3631 # https://github.com/paperless-ngx/paperless-ngx/issues/3631
default_thumbnail_path = temp_dir / "document.webp" default_thumbnail_path: Path = Path(temp_dir) / "document.webp"
copy_file_with_basic_stats(get_default_thumbnail(), default_thumbnail_path) copy_file_with_basic_stats(get_default_thumbnail(), default_thumbnail_path)
return default_thumbnail_path return default_thumbnail_path
@@ -245,18 +175,25 @@ def make_thumbnail_from_pdf(in_path: Path, temp_dir: Path, logging_group=None) -
""" """
The thumbnail of a PDF is just a 500px wide image of the first page. The thumbnail of a PDF is just a 500px wide image of the first page.
""" """
png_path: Path = temp_dir / "page1.png"
out_path: Path = temp_dir / "convert.webp" out_path: Path = temp_dir / "convert.webp"
# Run convert to get a decent thumbnail
try: try:
_render_pdf_thumbnail(in_path, png_path, out_path, logging_group) run_convert(
except ParseError as e: density=300,
logger.error(f"Unable to make thumbnail with pdftoppm: {e}") scale="500x5000>",
out_path = make_thumbnail_from_pdf_qpdf_fallback( alpha="remove",
in_path, strip=True,
temp_dir, trim=False,
logging_group, auto_orient=True,
use_cropbox=True,
input_file=f"{in_path}[0]",
output_file=str(out_path),
logging_group=logging_group,
) )
except ParseError as e:
logger.error(f"Unable to make thumbnail with convert: {e}")
out_path = make_thumbnail_from_pdf_gs_fallback(in_path, temp_dir, logging_group)
return out_path return out_path
-382
View File
@@ -1,22 +1,11 @@
import subprocess
from collections.abc import Generator from collections.abc import Generator
from pathlib import Path
import pikepdf
import pytest import pytest
from PIL import Image
from pytest_django.fixtures import Settings from pytest_django.fixtures import Settings
from pytest_mock import MockerFixture
from documents.parsers import ParseError
from documents.parsers import _compute_thumbnail_dpi
from documents.parsers import encode_thumbnail_webp
from documents.parsers import get_default_file_extension from documents.parsers import get_default_file_extension
from documents.parsers import get_default_thumbnail
from documents.parsers import get_supported_file_extensions from documents.parsers import get_supported_file_extensions
from documents.parsers import is_file_ext_supported from documents.parsers import is_file_ext_supported
from documents.parsers import make_thumbnail_from_pdf
from documents.parsers import rasterize_pdf_page_to_png
from paperless.parsers.registry import get_parser_registry from paperless.parsers.registry import get_parser_registry
from paperless.parsers.registry import reset_parser_registry from paperless.parsers.registry import reset_parser_registry
from paperless.parsers.tesseract import RasterisedDocumentParser from paperless.parsers.tesseract import RasterisedDocumentParser
@@ -136,374 +125,3 @@ class TestParserAvailability:
assert is_file_ext_supported(".pdf") assert is_file_ext_supported(".pdf")
assert not is_file_ext_supported(".hsdfh") assert not is_file_ext_supported(".hsdfh")
assert not is_file_ext_supported("") assert not is_file_ext_supported("")
class TestComputeThumbnailDpi:
@pytest.mark.parametrize(
("size", "expected"),
[
pytest.param((612.0, 792.0), (59, 2), id="letter-width-bound"),
pytest.param((792.0, 612.0), (46, 2), id="landscape-rounded-up"),
pytest.param((612.0, 100000.0), (4, 2), id="tall-strip-height-bound"),
pytest.param((200.0, 300.0), (180, 2), id="small-page-width-bound"),
pytest.param((72.0, 72.0), (300, 2), id="tiny-page-capped-at-300"),
pytest.param(
(1000000.0, 1000000.0),
(1, 1),
id="huge-page-minimum-one-unsupersampled",
),
pytest.param(None, (150, 1), id="unreadable-geometry-fallback"),
],
)
def test_dpi_from_page_size(
self,
mocker: MockerFixture,
tmp_path: Path,
size: tuple[float, float] | None,
expected: tuple[int, int],
) -> None:
"""
GIVEN:
- A first page of the given size, or unreadable geometry
WHEN:
- The thumbnail DPI is computed
THEN:
- The expected DPI and supersample factor are returned
"""
mocker.patch(
"paperless.parsers.utils.get_pdf_first_page_size_points",
return_value=size,
)
assert _compute_thumbnail_dpi(tmp_path / "doc.pdf") == expected
class TestMakeThumbnailFromPdf:
@pytest.fixture
def work_dir(self, tmp_path: Path) -> Path:
path = tmp_path / "work"
path.mkdir()
return path
@staticmethod
def _write_blank_pdf(path: Path, page_size: tuple[int, int] = (612, 792)) -> Path:
pdf = pikepdf.new()
pdf.add_blank_page(page_size=page_size)
pdf.save(path, object_stream_mode=pikepdf.ObjectStreamMode.disable)
return path
@pytest.mark.parametrize(
("size", "expected_dpi", "expected_supersample"),
[
pytest.param((612.0, 792.0), 118, 2, id="known-geometry-2x"),
pytest.param(None, 150, 1, id="unreadable-geometry-plain-fallback"),
],
)
def test_render_dpi_requested(
self,
mocker: MockerFixture,
tmp_path: Path,
work_dir: Path,
size: tuple[float, float] | None,
expected_dpi: int,
expected_supersample: int,
) -> None:
"""
GIVEN:
- Readable or unreadable page geometry
WHEN:
- A thumbnail is made
THEN:
- Rasterize and encode get the matching DPI and supersample factor
"""
mocker.patch(
"paperless.parsers.utils.get_pdf_first_page_size_points",
return_value=size,
)
rasterize = mocker.patch("documents.parsers.rasterize_pdf_page_to_png")
encode = mocker.patch("documents.parsers.encode_thumbnail_webp")
make_thumbnail_from_pdf(tmp_path / "in.pdf", work_dir)
assert rasterize.call_args.kwargs["dpi"] == expected_dpi
assert encode.call_args.kwargs["supersample"] == expected_supersample
@pytest.mark.parametrize(
("page_size", "expected_width"),
[
pytest.param((612, 792), 500, id="letter"),
pytest.param((792, 612), 500, id="landscape-letter"),
pytest.param((595, 842), 500, id="a4"),
pytest.param((200, 300), 500, id="small-page"),
pytest.param((72, 72), 300, id="tiny-page-capped"),
],
)
def test_thumbnail_width(
self,
tmp_path: Path,
work_dir: Path,
page_size: tuple[int, int],
expected_width: int,
) -> None:
"""
GIVEN:
- A PDF whose first page has the given size in points
WHEN:
- A thumbnail is made from it
THEN:
- The thumbnail has the expected width
"""
pdf_path = self._write_blank_pdf(tmp_path / "in.pdf", page_size)
thumb = make_thumbnail_from_pdf(pdf_path, work_dir)
assert thumb == work_dir / "convert.webp"
with Image.open(thumb) as im:
assert im.format == "WEBP"
assert im.width == expected_width
@classmethod
def _write_pdf_without_xref(cls, path: Path) -> Path:
"""
Cuts off the xref and trailer, which pdftoppm cannot recover from but qpdf can.
"""
cls._write_blank_pdf(path)
data = path.read_bytes()
path.write_bytes(data[: data.rindex(b"\nxref")])
return path
def test_qpdf_repair_produces_real_thumbnail(
self,
tmp_path: Path,
work_dir: Path,
) -> None:
"""
GIVEN:
- A PDF with its xref table and trailer cut off
WHEN:
- A thumbnail is made from it
THEN:
- The thumbnail is rendered from a qpdf repaired copy
- The original file is unchanged
"""
pdf_path = self._write_pdf_without_xref(tmp_path / "broken.pdf")
original_bytes = pdf_path.read_bytes()
with pytest.raises(ParseError):
rasterize_pdf_page_to_png(pdf_path, work_dir / "probe.png", dpi=50)
thumb = make_thumbnail_from_pdf(pdf_path, work_dir)
assert thumb == work_dir / "convert_qpdf.webp"
with Image.open(thumb) as im:
assert im.format == "WEBP"
assert im.width == 500
assert pdf_path.read_bytes() == original_bytes
@pytest.mark.parametrize(
"qpdf_error",
[
pytest.param(subprocess.CalledProcessError(2, "qpdf"), id="qpdf-fails"),
pytest.param(None, id="repaired-still-unrenderable"),
],
)
def test_double_failure_uses_default_thumbnail(
self,
mocker: MockerFixture,
tmp_path: Path,
work_dir: Path,
qpdf_error: subprocess.CalledProcessError | None,
) -> None:
"""
GIVEN:
- A PDF that cannot be rendered, even after qpdf repair
WHEN:
- A thumbnail is made from it
THEN:
- A copy of the default thumbnail is returned
"""
mocker.patch(
"documents.parsers.rasterize_pdf_page_to_png",
side_effect=ParseError("Does not compute."),
)
if qpdf_error is not None:
mocker.patch("documents.parsers.run_subprocess", side_effect=qpdf_error)
pdf_path = self._write_blank_pdf(tmp_path / "in.pdf")
thumb = make_thumbnail_from_pdf(pdf_path, work_dir)
assert thumb == work_dir / "document.webp"
assert thumb.read_bytes() == get_default_thumbnail().read_bytes()
class TestRasterizePdfPageToPng:
@staticmethod
def _write_pdf(
path: Path,
*,
crop_box: tuple[float, float, float, float] | None = None,
rotate: int | None = None,
) -> Path:
pdf = pikepdf.new()
pdf.add_blank_page(page_size=(144, 72))
pdf.add_blank_page(page_size=(300, 300))
page = pdf.pages[0]
if crop_box is not None:
page.obj.CropBox = pikepdf.Array(crop_box)
if rotate is not None:
page.obj.Rotate = rotate
pdf.save(path)
return path
@pytest.mark.parametrize(
("crop_box", "rotate", "expected_size"),
[
pytest.param(None, None, (144, 72), id="plain"),
pytest.param(None, 90, (72, 144), id="rotated-90"),
pytest.param((0, 0, 72, 36), None, (72, 36), id="crop-box"),
],
)
def test_renders_first_page_to_exact_path(
self,
tmp_path: Path,
crop_box: tuple[float, float, float, float] | None,
rotate: int | None,
expected_size: tuple[int, int],
) -> None:
"""
GIVEN:
- A two page PDF, first page optionally cropped or rotated
WHEN:
- The first page is rasterized at 72 DPI
THEN:
- Only out_path is written, sized to the first page's crop and rotation
"""
pdf_path = self._write_pdf(
tmp_path / "in.pdf",
crop_box=crop_box,
rotate=rotate,
)
out_dir = tmp_path / "out"
out_dir.mkdir()
out_path = out_dir / "page1.png"
rasterize_pdf_page_to_png(pdf_path, out_path, dpi=72)
assert list(out_dir.iterdir()) == [out_path]
with Image.open(out_path) as im:
assert im.format == "PNG"
assert im.size == expected_size
def test_failure_raises_parse_error(self, tmp_path: Path) -> None:
"""
GIVEN:
- A file that is not a PDF
WHEN:
- Rasterization is attempted
THEN:
- A ParseError is raised
"""
bad = tmp_path / "bad.pdf"
bad.write_bytes(b"not a pdf")
with pytest.raises(ParseError):
rasterize_pdf_page_to_png(bad, tmp_path / "page1.png", dpi=72)
class TestEncodeThumbnailWebp:
@pytest.mark.parametrize(
("mode", "color"),
[
pytest.param("RGBA", (0, 0, 0, 0), id="rgba"),
pytest.param("LA", (0, 0), id="la"),
],
)
def test_alpha_flattened_onto_white(
self,
tmp_path: Path,
mode: str,
color: tuple[int, ...],
) -> None:
"""
GIVEN:
- A fully transparent PNG with an alpha channel
WHEN:
- It is encoded as a thumbnail
THEN:
- The WebP output is RGB with the transparency flattened to white
"""
png_path = tmp_path / "in.png"
Image.new(mode, (20, 10), color).save(png_path)
out_path = tmp_path / "out.webp"
encode_thumbnail_webp(png_path, out_path)
with Image.open(out_path) as im:
assert im.format == "WEBP"
assert im.mode == "RGB"
assert im.size == (20, 10)
red, green, blue = im.getpixel((10, 5))
assert min(red, green, blue) >= 250
@pytest.mark.parametrize(
("in_size", "supersample", "expected_size"),
[
pytest.param((1000, 2000), 1, (500, 1000), id="too-wide-shrunk"),
pytest.param((100, 10000), 1, (50, 5000), id="too-tall-shrunk"),
pytest.param((100, 200), 1, (100, 200), id="small-not-enlarged"),
pytest.param((1000, 1400), 2, (500, 700), id="2x-halved"),
pytest.param((1001, 1401), 2, (500, 700), id="2x-odd-rounded"),
pytest.param((600, 800), 2, (300, 400), id="2x-small-not-enlarged"),
pytest.param((900, 1200), 2, (450, 600), id="2x-below-clamp"),
],
)
def test_size_clamped_and_downsampled(
self,
tmp_path: Path,
in_size: tuple[int, int],
supersample: int,
expected_size: tuple[int, int],
) -> None:
"""
GIVEN:
- A rendered image and its supersample factor
WHEN:
- It is encoded as a thumbnail with that factor
THEN:
- It is downsampled, fit within 500x5000 and never enlarged
"""
png_path = tmp_path / "in.png"
Image.new("RGB", in_size, (255, 255, 255)).save(png_path)
out_path = tmp_path / "out.webp"
encode_thumbnail_webp(png_path, out_path, supersample=supersample)
with Image.open(out_path) as im:
assert im.size == expected_size
@pytest.mark.parametrize(
"error",
[
pytest.param(OSError("broken image"), id="os-error"),
pytest.param(Image.DecompressionBombError("too large"), id="bomb"),
],
)
def test_decode_failure_raises_parse_error(
self,
tmp_path: Path,
mocker: MockerFixture,
error: Exception,
) -> None:
"""
GIVEN:
- Opening the rendered image fails
WHEN:
- It is encoded as a thumbnail
THEN:
- A ParseError is raised
"""
png_path = tmp_path / "in.png"
Image.new("RGB", (10, 10)).save(png_path)
mocker.patch("PIL.Image.open", side_effect=error)
with pytest.raises(ParseError):
encode_thumbnail_webp(png_path, tmp_path / "out.webp")
+3 -18
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-05 16:26+0000\n" "POT-Creation-Date: 2026-10-06 15:12+0000\n"
"PO-Revision-Date: 2026-10-05 16:27\n" "PO-Revision-Date: 2026-10-06 15:13\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Afrikaans\n" "Language-Team: Afrikaans\n"
"Language: af_ZA\n" "Language: af_ZA\n"
@@ -1912,23 +1912,8 @@ msgstr ""
msgid "As a final step, please complete the following form:" msgid "As a final step, please complete the following form:"
msgstr "" msgstr ""
#: documents/validators.py:24
#, python-brace-format
msgid "Unable to parse URI {value}, missing scheme"
msgstr ""
#: documents/validators.py:29
#, python-brace-format
msgid "Unable to parse URI {value}, missing net location or path"
msgstr ""
#: documents/validators.py:36 #: documents/validators.py:36
msgid "URI scheme '{parts.scheme}' is not allowed. Allowed schemes: {', '.join(allowed_schemes)}" msgid ", "
msgstr ""
#: documents/validators.py:45
#, python-brace-format
msgid "Unable to parse URI {value}"
msgstr "" msgstr ""
#: documents/views.py:336 documents/views.py:2729 #: documents/views.py:336 documents/views.py:2729
+3 -18
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-05 16:26+0000\n" "POT-Creation-Date: 2026-10-06 15:12+0000\n"
"PO-Revision-Date: 2026-10-05 16:27\n" "PO-Revision-Date: 2026-10-06 15:13\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Amharic\n" "Language-Team: Amharic\n"
"Language: am_ET\n" "Language: am_ET\n"
@@ -1912,23 +1912,8 @@ msgstr ""
msgid "As a final step, please complete the following form:" msgid "As a final step, please complete the following form:"
msgstr "" msgstr ""
#: documents/validators.py:24
#, python-brace-format
msgid "Unable to parse URI {value}, missing scheme"
msgstr ""
#: documents/validators.py:29
#, python-brace-format
msgid "Unable to parse URI {value}, missing net location or path"
msgstr ""
#: documents/validators.py:36 #: documents/validators.py:36
msgid "URI scheme '{parts.scheme}' is not allowed. Allowed schemes: {', '.join(allowed_schemes)}" msgid ", "
msgstr ""
#: documents/validators.py:45
#, python-brace-format
msgid "Unable to parse URI {value}"
msgstr "" msgstr ""
#: documents/views.py:336 documents/views.py:2729 #: documents/views.py:336 documents/views.py:2729
+3 -18
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-05 16:26+0000\n" "POT-Creation-Date: 2026-10-06 15:12+0000\n"
"PO-Revision-Date: 2026-10-05 16:27\n" "PO-Revision-Date: 2026-10-06 15:13\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Arabic\n" "Language-Team: Arabic\n"
"Language: ar_SA\n" "Language: ar_SA\n"
@@ -1913,23 +1913,8 @@ msgstr "أنت على وشك استعمال حسابك في %(provider_name)s ل
msgid "As a final step, please complete the following form:" msgid "As a final step, please complete the following form:"
msgstr "كخطوة أخيرة، يرجى ملء النموذج التالي:" msgstr "كخطوة أخيرة، يرجى ملء النموذج التالي:"
#: documents/validators.py:24
#, python-brace-format
msgid "Unable to parse URI {value}, missing scheme"
msgstr ""
#: documents/validators.py:29
#, python-brace-format
msgid "Unable to parse URI {value}, missing net location or path"
msgstr ""
#: documents/validators.py:36 #: documents/validators.py:36
msgid "URI scheme '{parts.scheme}' is not allowed. Allowed schemes: {', '.join(allowed_schemes)}" msgid ", "
msgstr ""
#: documents/validators.py:45
#, python-brace-format
msgid "Unable to parse URI {value}"
msgstr "" msgstr ""
#: documents/views.py:336 documents/views.py:2729 #: documents/views.py:336 documents/views.py:2729
+3 -18
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-05 16:26+0000\n" "POT-Creation-Date: 2026-10-06 15:12+0000\n"
"PO-Revision-Date: 2026-10-05 16:27\n" "PO-Revision-Date: 2026-10-06 15:13\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Belarusian\n" "Language-Team: Belarusian\n"
"Language: be_BY\n" "Language: be_BY\n"
@@ -1912,23 +1912,8 @@ msgstr ""
msgid "As a final step, please complete the following form:" msgid "As a final step, please complete the following form:"
msgstr "" msgstr ""
#: documents/validators.py:24
#, python-brace-format
msgid "Unable to parse URI {value}, missing scheme"
msgstr ""
#: documents/validators.py:29
#, python-brace-format
msgid "Unable to parse URI {value}, missing net location or path"
msgstr ""
#: documents/validators.py:36 #: documents/validators.py:36
msgid "URI scheme '{parts.scheme}' is not allowed. Allowed schemes: {', '.join(allowed_schemes)}" msgid ", "
msgstr ""
#: documents/validators.py:45
#, python-brace-format
msgid "Unable to parse URI {value}"
msgstr "" msgstr ""
#: documents/views.py:336 documents/views.py:2729 #: documents/views.py:336 documents/views.py:2729
+3 -18
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-05 16:26+0000\n" "POT-Creation-Date: 2026-10-06 15:12+0000\n"
"PO-Revision-Date: 2026-10-05 16:27\n" "PO-Revision-Date: 2026-10-06 15:13\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Bulgarian\n" "Language-Team: Bulgarian\n"
"Language: bg_BG\n" "Language: bg_BG\n"
@@ -1913,23 +1913,8 @@ msgstr "На път сте да използвате профила си в %(pr
msgid "As a final step, please complete the following form:" msgid "As a final step, please complete the following form:"
msgstr "Като последна стъпка, моля, попълнете следната форма:" msgstr "Като последна стъпка, моля, попълнете следната форма:"
#: documents/validators.py:24
#, python-brace-format
msgid "Unable to parse URI {value}, missing scheme"
msgstr ""
#: documents/validators.py:29
#, python-brace-format
msgid "Unable to parse URI {value}, missing net location or path"
msgstr ""
#: documents/validators.py:36 #: documents/validators.py:36
msgid "URI scheme '{parts.scheme}' is not allowed. Allowed schemes: {', '.join(allowed_schemes)}" msgid ", "
msgstr ""
#: documents/validators.py:45
#, python-brace-format
msgid "Unable to parse URI {value}"
msgstr "" msgstr ""
#: documents/views.py:336 documents/views.py:2729 #: documents/views.py:336 documents/views.py:2729
+4 -19
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-05 16:26+0000\n" "POT-Creation-Date: 2026-10-06 15:12+0000\n"
"PO-Revision-Date: 2026-10-05 16:27\n" "PO-Revision-Date: 2026-10-06 15:13\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Catalan\n" "Language-Team: Catalan\n"
"Language: ca_ES\n" "Language: ca_ES\n"
@@ -1913,24 +1913,9 @@ msgstr "Estàs a punt d'emprar el teu %(provider_name)s compte per a fer login."
msgid "As a final step, please complete the following form:" msgid "As a final step, please complete the following form:"
msgstr "Com a pas final, completa el següent formulari:" msgstr "Com a pas final, completa el següent formulari:"
#: documents/validators.py:24
#, python-brace-format
msgid "Unable to parse URI {value}, missing scheme"
msgstr "No es pot analitzar l'URI {value}, falta l'esquema"
#: documents/validators.py:29
#, python-brace-format
msgid "Unable to parse URI {value}, missing net location or path"
msgstr "No es pot analitzar l'URI {value}, falta la ubicació de xarxa o la ruta"
#: documents/validators.py:36 #: documents/validators.py:36
msgid "URI scheme '{parts.scheme}' is not allowed. Allowed schemes: {', '.join(allowed_schemes)}" msgid ", "
msgstr "L'esquema d'URI '{parts.scheme}' no està permès. Esquemes permesos: {', '.join(allowed_schemes)}" msgstr ""
#: documents/validators.py:45
#, python-brace-format
msgid "Unable to parse URI {value}"
msgstr "No s'ha pogut analitzar l'URI {value}"
#: documents/views.py:336 documents/views.py:2729 #: documents/views.py:336 documents/views.py:2729
msgid "Invalid more_like_id" msgid "Invalid more_like_id"
+4 -20
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-05 16:26+0000\n" "POT-Creation-Date: 2026-10-06 15:12+0000\n"
"PO-Revision-Date: 2026-10-05 16:27\n" "PO-Revision-Date: 2026-10-06 15:13\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Czech\n" "Language-Team: Czech\n"
"Language: cs_CZ\n" "Language: cs_CZ\n"
@@ -1913,25 +1913,9 @@ msgstr "Chystáte se použít svůj účet %(provider_name)s k přihlášení."
msgid "As a final step, please complete the following form:" msgid "As a final step, please complete the following form:"
msgstr "Jako poslední krok vyplňte následující formulář:" msgstr "Jako poslední krok vyplňte následující formulář:"
#: documents/validators.py:24
#, python-brace-format
msgid "Unable to parse URI {value}, missing scheme"
msgstr "Nelze analyzovat URI {value}, chybí schéma"
#: documents/validators.py:29
#, python-brace-format
msgid "Unable to parse URI {value}, missing net location or path"
msgstr "Nelze analyzovat URI {value}, chybí síťové umístění nebo cesta"
#: documents/validators.py:36 #: documents/validators.py:36
msgid "URI scheme '{parts.scheme}' is not allowed. Allowed schemes: {', '.join(allowed_schemes)}" msgid ", "
msgstr "URI schéma '{parts.scheme}' není povoleno. Povolená schémata: {',\n" msgstr ""
"'.join(allowed_schemes)}"
#: documents/validators.py:45
#, python-brace-format
msgid "Unable to parse URI {value}"
msgstr "Nelze zpracovat URI {value}"
#: documents/views.py:336 documents/views.py:2729 #: documents/views.py:336 documents/views.py:2729
msgid "Invalid more_like_id" msgid "Invalid more_like_id"
+3 -18
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-05 16:26+0000\n" "POT-Creation-Date: 2026-10-06 15:12+0000\n"
"PO-Revision-Date: 2026-10-05 16:27\n" "PO-Revision-Date: 2026-10-06 15:13\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Danish\n" "Language-Team: Danish\n"
"Language: da_DK\n" "Language: da_DK\n"
@@ -1913,23 +1913,8 @@ msgstr "En %(provider_name)s-konto er ved at blive brugt til indlogning."
msgid "As a final step, please complete the following form:" msgid "As a final step, please complete the following form:"
msgstr "Som sidste trin, udfyld venligst flg. formular:" msgstr "Som sidste trin, udfyld venligst flg. formular:"
#: documents/validators.py:24
#, python-brace-format
msgid "Unable to parse URI {value}, missing scheme"
msgstr ""
#: documents/validators.py:29
#, python-brace-format
msgid "Unable to parse URI {value}, missing net location or path"
msgstr ""
#: documents/validators.py:36 #: documents/validators.py:36
msgid "URI scheme '{parts.scheme}' is not allowed. Allowed schemes: {', '.join(allowed_schemes)}" msgid ", "
msgstr ""
#: documents/validators.py:45
#, python-brace-format
msgid "Unable to parse URI {value}"
msgstr "" msgstr ""
#: documents/views.py:336 documents/views.py:2729 #: documents/views.py:336 documents/views.py:2729
+4 -19
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-05 16:26+0000\n" "POT-Creation-Date: 2026-10-06 15:12+0000\n"
"PO-Revision-Date: 2026-10-05 16:27\n" "PO-Revision-Date: 2026-10-06 15:13\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"
@@ -1913,24 +1913,9 @@ msgstr "Sie sind dabei, Ihr %(provider_name)s-Konto zur Anmeldung zu verwenden."
msgid "As a final step, please complete the following form:" msgid "As a final step, please complete the following form:"
msgstr "Bitte füllen Sie zum Abschluss folgendes Formular aus:" msgstr "Bitte füllen Sie zum Abschluss folgendes Formular aus:"
#: documents/validators.py:24
#, python-brace-format
msgid "Unable to parse URI {value}, missing scheme"
msgstr "URI {value} kann nicht gelesen werden, fehlendes Schema"
#: documents/validators.py:29
#, python-brace-format
msgid "Unable to parse URI {value}, missing net location or path"
msgstr "URI {value} kann nicht gelesen werden, Netzadresse oder Pfad fehlt"
#: documents/validators.py:36 #: documents/validators.py:36
msgid "URI scheme '{parts.scheme}' is not allowed. Allowed schemes: {', '.join(allowed_schemes)}" msgid ", "
msgstr "URI-Schema „{parts.scheme}“ ist nicht erlaubt. Erlaubte Schemata: {', '.join(allowed_schemes)}" msgstr ""
#: documents/validators.py:45
#, python-brace-format
msgid "Unable to parse URI {value}"
msgstr "URI {value} kann nicht gelesen werden"
#: documents/views.py:336 documents/views.py:2729 #: documents/views.py:336 documents/views.py:2729
msgid "Invalid more_like_id" msgid "Invalid more_like_id"
+4 -19
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-05 16:26+0000\n" "POT-Creation-Date: 2026-10-06 15:12+0000\n"
"PO-Revision-Date: 2026-10-06 00:56\n" "PO-Revision-Date: 2026-10-07 00:59\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: German\n" "Language-Team: German\n"
"Language: de_DE\n" "Language: de_DE\n"
@@ -1913,24 +1913,9 @@ msgstr "Sie sind dabei, Ihr %(provider_name)s-Konto zur Anmeldung zu verwenden."
msgid "As a final step, please complete the following form:" msgid "As a final step, please complete the following form:"
msgstr "Bitte füllen Sie zum Abschluss folgendes Formular aus:" msgstr "Bitte füllen Sie zum Abschluss folgendes Formular aus:"
#: documents/validators.py:24
#, python-brace-format
msgid "Unable to parse URI {value}, missing scheme"
msgstr "URI {value} kann nicht gelesen werden, fehlendes Schema"
#: documents/validators.py:29
#, python-brace-format
msgid "Unable to parse URI {value}, missing net location or path"
msgstr "URI {value} kann nicht gelesen werden, Netzadresse oder Pfad fehlt"
#: documents/validators.py:36 #: documents/validators.py:36
msgid "URI scheme '{parts.scheme}' is not allowed. Allowed schemes: {', '.join(allowed_schemes)}" msgid ", "
msgstr "URI-Schema „{parts.scheme}“ ist nicht erlaubt. Erlaubte Schemata: {', '.join(allowed_schemes)}" msgstr ""
#: documents/validators.py:45
#, python-brace-format
msgid "Unable to parse URI {value}"
msgstr "URI {value} kann nicht gelesen werden"
#: documents/views.py:336 documents/views.py:2729 #: documents/views.py:336 documents/views.py:2729
msgid "Invalid more_like_id" msgid "Invalid more_like_id"
+3 -18
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-05 16:26+0000\n" "POT-Creation-Date: 2026-10-06 15:12+0000\n"
"PO-Revision-Date: 2026-10-05 16:27\n" "PO-Revision-Date: 2026-10-06 15:13\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Greek\n" "Language-Team: Greek\n"
"Language: el_GR\n" "Language: el_GR\n"
@@ -1913,23 +1913,8 @@ msgstr "Πρόκειται να χρησιμοποιήσετε το λογαρι
msgid "As a final step, please complete the following form:" msgid "As a final step, please complete the following form:"
msgstr "Ως τελικό βήμα, παρακαλούμε να συμπληρώσετε την ακόλουθη φόρμα:" msgstr "Ως τελικό βήμα, παρακαλούμε να συμπληρώσετε την ακόλουθη φόρμα:"
#: documents/validators.py:24
#, python-brace-format
msgid "Unable to parse URI {value}, missing scheme"
msgstr ""
#: documents/validators.py:29
#, python-brace-format
msgid "Unable to parse URI {value}, missing net location or path"
msgstr ""
#: documents/validators.py:36 #: documents/validators.py:36
msgid "URI scheme '{parts.scheme}' is not allowed. Allowed schemes: {', '.join(allowed_schemes)}" msgid ", "
msgstr ""
#: documents/validators.py:45
#, python-brace-format
msgid "Unable to parse URI {value}"
msgstr "" msgstr ""
#: documents/views.py:336 documents/views.py:2729 #: documents/views.py:336 documents/views.py:2729
+4 -19
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-05 16:26+0000\n" "POT-Creation-Date: 2026-10-06 15:12+0000\n"
"PO-Revision-Date: 2026-10-05 16:27\n" "PO-Revision-Date: 2026-10-06 15:13\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Spanish\n" "Language-Team: Spanish\n"
"Language: es_ES\n" "Language: es_ES\n"
@@ -1913,24 +1913,9 @@ msgstr "Estás a punto de usar tu cuenta de %(provider_name)s para iniciar sesi
msgid "As a final step, please complete the following form:" msgid "As a final step, please complete the following form:"
msgstr "Como último paso, por favor complete el siguiente formulario:" msgstr "Como último paso, por favor complete el siguiente formulario:"
#: documents/validators.py:24
#, python-brace-format
msgid "Unable to parse URI {value}, missing scheme"
msgstr "No se puede analizar la URI {value}, falta el esquema"
#: documents/validators.py:29
#, python-brace-format
msgid "Unable to parse URI {value}, missing net location or path"
msgstr "No se puede analizar la URI {value}, falta la ubicación de la red o la ruta"
#: documents/validators.py:36 #: documents/validators.py:36
msgid "URI scheme '{parts.scheme}' is not allowed. Allowed schemes: {', '.join(allowed_schemes)}" msgid ", "
msgstr "El esquema URI '{parts.scheme}' no está permitido. Esquemas permitidos: {', '.join(allowed_schemes)}" msgstr ""
#: documents/validators.py:45
#, python-brace-format
msgid "Unable to parse URI {value}"
msgstr "No se puede analizar la URI {value}"
#: documents/views.py:336 documents/views.py:2729 #: documents/views.py:336 documents/views.py:2729
msgid "Invalid more_like_id" msgid "Invalid more_like_id"
+3 -18
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-05 16:26+0000\n" "POT-Creation-Date: 2026-10-06 15:12+0000\n"
"PO-Revision-Date: 2026-10-05 16:27\n" "PO-Revision-Date: 2026-10-06 15:13\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Estonian\n" "Language-Team: Estonian\n"
"Language: et_EE\n" "Language: et_EE\n"
@@ -1912,23 +1912,8 @@ msgstr ""
msgid "As a final step, please complete the following form:" msgid "As a final step, please complete the following form:"
msgstr "" msgstr ""
#: documents/validators.py:24
#, python-brace-format
msgid "Unable to parse URI {value}, missing scheme"
msgstr ""
#: documents/validators.py:29
#, python-brace-format
msgid "Unable to parse URI {value}, missing net location or path"
msgstr ""
#: documents/validators.py:36 #: documents/validators.py:36
msgid "URI scheme '{parts.scheme}' is not allowed. Allowed schemes: {', '.join(allowed_schemes)}" msgid ", "
msgstr ""
#: documents/validators.py:45
#, python-brace-format
msgid "Unable to parse URI {value}"
msgstr "" msgstr ""
#: documents/views.py:336 documents/views.py:2729 #: documents/views.py:336 documents/views.py:2729
+3 -18
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-05 16:26+0000\n" "POT-Creation-Date: 2026-10-06 15:12+0000\n"
"PO-Revision-Date: 2026-10-05 16:27\n" "PO-Revision-Date: 2026-10-06 15:13\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Persian\n" "Language-Team: Persian\n"
"Language: fa_IR\n" "Language: fa_IR\n"
@@ -1912,23 +1912,8 @@ msgstr ""
msgid "As a final step, please complete the following form:" msgid "As a final step, please complete the following form:"
msgstr "به عنوان مرحله آخر ، لطفاً فرم زیر را تکمیل کنید:" msgstr "به عنوان مرحله آخر ، لطفاً فرم زیر را تکمیل کنید:"
#: documents/validators.py:24
#, python-brace-format
msgid "Unable to parse URI {value}, missing scheme"
msgstr ""
#: documents/validators.py:29
#, python-brace-format
msgid "Unable to parse URI {value}, missing net location or path"
msgstr ""
#: documents/validators.py:36 #: documents/validators.py:36
msgid "URI scheme '{parts.scheme}' is not allowed. Allowed schemes: {', '.join(allowed_schemes)}" msgid ", "
msgstr ""
#: documents/validators.py:45
#, python-brace-format
msgid "Unable to parse URI {value}"
msgstr "" msgstr ""
#: documents/views.py:336 documents/views.py:2729 #: documents/views.py:336 documents/views.py:2729
+3 -18
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-05 16:26+0000\n" "POT-Creation-Date: 2026-10-06 15:12+0000\n"
"PO-Revision-Date: 2026-10-05 16:27\n" "PO-Revision-Date: 2026-10-06 15:13\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Finnish\n" "Language-Team: Finnish\n"
"Language: fi_FI\n" "Language: fi_FI\n"
@@ -1913,23 +1913,8 @@ msgstr ""
msgid "As a final step, please complete the following form:" msgid "As a final step, please complete the following form:"
msgstr "" msgstr ""
#: documents/validators.py:24
#, python-brace-format
msgid "Unable to parse URI {value}, missing scheme"
msgstr ""
#: documents/validators.py:29
#, python-brace-format
msgid "Unable to parse URI {value}, missing net location or path"
msgstr ""
#: documents/validators.py:36 #: documents/validators.py:36
msgid "URI scheme '{parts.scheme}' is not allowed. Allowed schemes: {', '.join(allowed_schemes)}" msgid ", "
msgstr ""
#: documents/validators.py:45
#, python-brace-format
msgid "Unable to parse URI {value}"
msgstr "" msgstr ""
#: documents/views.py:336 documents/views.py:2729 #: documents/views.py:336 documents/views.py:2729
+4 -19
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-05 16:26+0000\n" "POT-Creation-Date: 2026-10-06 15:12+0000\n"
"PO-Revision-Date: 2026-10-05 16:27\n" "PO-Revision-Date: 2026-10-06 15:13\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: French\n" "Language-Team: French\n"
"Language: fr_FR\n" "Language: fr_FR\n"
@@ -1912,24 +1912,9 @@ msgstr "Vous vous apprêtez à utiliser votre compte %(provider_name)s pour vous
msgid "As a final step, please complete the following form:" msgid "As a final step, please complete the following form:"
msgstr "Pour finir, veuillez remplir le formulaire suivant :" msgstr "Pour finir, veuillez remplir le formulaire suivant :"
#: documents/validators.py:24
#, python-brace-format
msgid "Unable to parse URI {value}, missing scheme"
msgstr "Impossible d'analyser l'URI {value}, schéma manquant"
#: documents/validators.py:29
#, python-brace-format
msgid "Unable to parse URI {value}, missing net location or path"
msgstr "Impossible d'analyser l'URI {value}, emplacement réseau ou chemin manquant"
#: documents/validators.py:36 #: documents/validators.py:36
msgid "URI scheme '{parts.scheme}' is not allowed. Allowed schemes: {', '.join(allowed_schemes)}" msgid ", "
msgstr "Le schéma d'URI « {parts.scheme} » n'est pas autorisé. Schémas autorisés : {', '.join(allowed_schemes)}" msgstr ""
#: documents/validators.py:45
#, python-brace-format
msgid "Unable to parse URI {value}"
msgstr "Impossible d'analyser l'URI {value}"
#: documents/views.py:336 documents/views.py:2729 #: documents/views.py:336 documents/views.py:2729
msgid "Invalid more_like_id" msgid "Invalid more_like_id"
+4 -19
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-05 16:26+0000\n" "POT-Creation-Date: 2026-10-06 15:12+0000\n"
"PO-Revision-Date: 2026-10-05 16:27\n" "PO-Revision-Date: 2026-10-06 15:13\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Hebrew\n" "Language-Team: Hebrew\n"
"Language: he_IL\n" "Language: he_IL\n"
@@ -1914,24 +1914,9 @@ msgstr "שלך כדי להתחבר %(provider_name)s אתה עומד להשתמ
msgid "As a final step, please complete the following form:" msgid "As a final step, please complete the following form:"
msgstr ": כצעד אחרון, אנא מלא את הטופס הבא:" msgstr ": כצעד אחרון, אנא מלא את הטופס הבא:"
#: documents/validators.py:24
#, python-brace-format
msgid "Unable to parse URI {value}, missing scheme"
msgstr "לא ניתן לפענח את ה-URI ‏{value}, חסר פרוטוקול (scheme)"
#: documents/validators.py:29
#, python-brace-format
msgid "Unable to parse URI {value}, missing net location or path"
msgstr "לא ניתן לפענח את ה-URI ‏{value}, חסר מיקום רשת (net location) או נתיב"
#: documents/validators.py:36 #: documents/validators.py:36
msgid "URI scheme '{parts.scheme}' is not allowed. Allowed schemes: {', '.join(allowed_schemes)}" msgid ", "
msgstr "פרוטוקול ה-URI ‏'{parts.scheme}' אינו מורשה. הפרוטוקולים המורשים הם: {', '.join(allowed_schemes)}" msgstr ""
#: documents/validators.py:45
#, python-brace-format
msgid "Unable to parse URI {value}"
msgstr "לא ניתן לפענח את ה URI ‏{value}"
#: documents/views.py:336 documents/views.py:2729 #: documents/views.py:336 documents/views.py:2729
msgid "Invalid more_like_id" msgid "Invalid more_like_id"
+3 -18
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-05 16:26+0000\n" "POT-Creation-Date: 2026-10-06 15:12+0000\n"
"PO-Revision-Date: 2026-10-05 16:27\n" "PO-Revision-Date: 2026-10-06 15:13\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Hindi\n" "Language-Team: Hindi\n"
"Language: hi_IN\n" "Language: hi_IN\n"
@@ -1912,23 +1912,8 @@ msgstr ""
msgid "As a final step, please complete the following form:" msgid "As a final step, please complete the following form:"
msgstr "" msgstr ""
#: documents/validators.py:24
#, python-brace-format
msgid "Unable to parse URI {value}, missing scheme"
msgstr ""
#: documents/validators.py:29
#, python-brace-format
msgid "Unable to parse URI {value}, missing net location or path"
msgstr ""
#: documents/validators.py:36 #: documents/validators.py:36
msgid "URI scheme '{parts.scheme}' is not allowed. Allowed schemes: {', '.join(allowed_schemes)}" msgid ", "
msgstr ""
#: documents/validators.py:45
#, python-brace-format
msgid "Unable to parse URI {value}"
msgstr "" msgstr ""
#: documents/views.py:336 documents/views.py:2729 #: documents/views.py:336 documents/views.py:2729
+4 -19
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-05 16:26+0000\n" "POT-Creation-Date: 2026-10-06 15:12+0000\n"
"PO-Revision-Date: 2026-10-05 16:27\n" "PO-Revision-Date: 2026-10-06 15:13\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Croatian\n" "Language-Team: Croatian\n"
"Language: hr_HR\n" "Language: hr_HR\n"
@@ -1913,24 +1913,9 @@ msgstr "Upravo ćete koristiti svoj račun %(provider_name)s za prijavu."
msgid "As a final step, please complete the following form:" msgid "As a final step, please complete the following form:"
msgstr "Kao posljednji korak ispunite sljedeći obrazac:" msgstr "Kao posljednji korak ispunite sljedeći obrazac:"
#: documents/validators.py:24
#, python-brace-format
msgid "Unable to parse URI {value}, missing scheme"
msgstr "Nije moguće analizirati URI {value}, nedostaje shema"
#: documents/validators.py:29
#, python-brace-format
msgid "Unable to parse URI {value}, missing net location or path"
msgstr "Nije moguće analizirati URI {value}, nedostaje mrežna lokacija ili put"
#: documents/validators.py:36 #: documents/validators.py:36
msgid "URI scheme '{parts.scheme}' is not allowed. Allowed schemes: {', '.join(allowed_schemes)}" msgid ", "
msgstr "URI shema '{parts.scheme}' nije dopuštena. Dopuštene sheme: {', '.join(allowed_schemes)}" msgstr ""
#: documents/validators.py:45
#, python-brace-format
msgid "Unable to parse URI {value}"
msgstr "Nije moguće raščlaniti URI {value}"
#: documents/views.py:336 documents/views.py:2729 #: documents/views.py:336 documents/views.py:2729
msgid "Invalid more_like_id" msgid "Invalid more_like_id"
+4 -19
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-05 16:26+0000\n" "POT-Creation-Date: 2026-10-06 15:12+0000\n"
"PO-Revision-Date: 2026-10-05 16:27\n" "PO-Revision-Date: 2026-10-06 15:13\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Hungarian\n" "Language-Team: Hungarian\n"
"Language: hu_HU\n" "Language: hu_HU\n"
@@ -1913,24 +1913,9 @@ msgstr "A %(provider_name)s felhasználói fiókkal fogsz belépni."
msgid "As a final step, please complete the following form:" msgid "As a final step, please complete the following form:"
msgstr "Utolsó lépésként kérjük válaszoljon az alábbi kérdésekre:" msgstr "Utolsó lépésként kérjük válaszoljon az alábbi kérdésekre:"
#: documents/validators.py:24
#, python-brace-format
msgid "Unable to parse URI {value}, missing scheme"
msgstr "A {value} URI értelmezése sikertelen, hiányzó séma"
#: documents/validators.py:29
#, python-brace-format
msgid "Unable to parse URI {value}, missing net location or path"
msgstr "A {value} URI értelmezése sikertelen, hiányzó hálózati vagy elérési útvonal"
#: documents/validators.py:36 #: documents/validators.py:36
msgid "URI scheme '{parts.scheme}' is not allowed. Allowed schemes: {', '.join(allowed_schemes)}" msgid ", "
msgstr "A '{parts.scheme}' séma nem engedélyezett. Engedélyezett sémák: {', '.join(allowed_schemes)}" msgstr ""
#: documents/validators.py:45
#, python-brace-format
msgid "Unable to parse URI {value}"
msgstr "A {value} URI értelmezése sikertelen"
#: documents/views.py:336 documents/views.py:2729 #: documents/views.py:336 documents/views.py:2729
msgid "Invalid more_like_id" msgid "Invalid more_like_id"
+4 -19
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-05 16:26+0000\n" "POT-Creation-Date: 2026-10-06 15:12+0000\n"
"PO-Revision-Date: 2026-10-05 16:27\n" "PO-Revision-Date: 2026-10-06 15:13\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Indonesian\n" "Language-Team: Indonesian\n"
"Language: id_ID\n" "Language: id_ID\n"
@@ -1913,24 +1913,9 @@ msgstr "Anda akan menggunakan akun %(provider_name)s Anda untuk masuk."
msgid "As a final step, please complete the following form:" msgid "As a final step, please complete the following form:"
msgstr "Sebagai langkah terakhir, mohon formulir berikut:" msgstr "Sebagai langkah terakhir, mohon formulir berikut:"
#: documents/validators.py:24
#, python-brace-format
msgid "Unable to parse URI {value}, missing scheme"
msgstr "Gagal membaca URI {value}, skema tidak ditemukan"
#: documents/validators.py:29
#, python-brace-format
msgid "Unable to parse URI {value}, missing net location or path"
msgstr "Gagal membaca URI {value}, lokasi jaringan atau path tidak ditemukan"
#: documents/validators.py:36 #: documents/validators.py:36
msgid "URI scheme '{parts.scheme}' is not allowed. Allowed schemes: {', '.join(allowed_schemes)}" msgid ", "
msgstr "Skema URI '{parts.scheme}' tidak diizinkan. Skema yang diizinkan: {', '.join(allowed_schemes)}" msgstr ""
#: documents/validators.py:45
#, python-brace-format
msgid "Unable to parse URI {value}"
msgstr "Gagal membaca URI {value}"
#: documents/views.py:336 documents/views.py:2729 #: documents/views.py:336 documents/views.py:2729
msgid "Invalid more_like_id" msgid "Invalid more_like_id"
+12 -27
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-05 16:26+0000\n" "POT-Creation-Date: 2026-10-06 15:12+0000\n"
"PO-Revision-Date: 2026-10-05 16:27\n" "PO-Revision-Date: 2026-10-06 15:13\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Italian\n" "Language-Team: Italian\n"
"Language: it_IT\n" "Language: it_IT\n"
@@ -253,7 +253,7 @@ msgstr "documento radice per questa versione"
#: documents/models.py:325 #: documents/models.py:325
msgid "version index" msgid "version index"
msgstr "indice della versione" msgstr "indice versione"
#: documents/models.py:329 #: documents/models.py:329
msgid "Index of this version within the root document." msgid "Index of this version within the root document."
@@ -261,11 +261,11 @@ msgstr "Indice di questa versione all'interno del documento radice."
#: documents/models.py:333 #: documents/models.py:333
msgid "version label" msgid "version label"
msgstr "etichetta della versione" msgstr "etichetta versione"
#: documents/models.py:337 #: documents/models.py:337
msgid "Optional short label for a document version." msgid "Optional short label for a document version."
msgstr "Etichetta breve facoltativa per una versione del documento." msgstr "Etichetta abbreviata facoltativa per una versione del documento."
#: documents/models.py:342 documents/models.py:961 documents/models.py:992 #: documents/models.py:342 documents/models.py:961 documents/models.py:992
#: documents/models.py:1096 documents/models.py:2126 #: documents/models.py:1096 documents/models.py:2126
@@ -1006,11 +1006,11 @@ msgstr "note"
#: documents/models.py:996 #: documents/models.py:996
msgid "page" msgid "page"
msgstr "" msgstr "pagina"
#: documents/models.py:997 #: documents/models.py:997
msgid "Page of the original file, starting at 1" msgid "Page of the original file, starting at 1"
msgstr "" msgstr "Pagina del file originale, partendo da 1"
#: documents/models.py:1052 #: documents/models.py:1052
msgid "format" msgid "format"
@@ -1018,11 +1018,11 @@ msgstr ""
#: documents/models.py:1056 #: documents/models.py:1056
msgid "document barcode" msgid "document barcode"
msgstr "" msgstr "codice a barre del documento"
#: documents/models.py:1057 #: documents/models.py:1057
msgid "document barcodes" msgid "document barcodes"
msgstr "" msgstr "codici a barre del documento"
#: documents/models.py:1066 #: documents/models.py:1066
msgid "Original" msgid "Original"
@@ -1913,24 +1913,9 @@ msgstr "Stai per utilizzare il tuo account %(provider_name)s per effettuare il l
msgid "As a final step, please complete the following form:" msgid "As a final step, please complete the following form:"
msgstr "Come ultimo passo, compila il seguente modulo:" msgstr "Come ultimo passo, compila il seguente modulo:"
#: documents/validators.py:24
#, python-brace-format
msgid "Unable to parse URI {value}, missing scheme"
msgstr "Impossibile analizzare l'URI {value}, schema mancante"
#: documents/validators.py:29
#, python-brace-format
msgid "Unable to parse URI {value}, missing net location or path"
msgstr "Impossibile analizzare l'URI {value}, posizione o percorso di rete mancante"
#: documents/validators.py:36 #: documents/validators.py:36
msgid "URI scheme '{parts.scheme}' is not allowed. Allowed schemes: {', '.join(allowed_schemes)}" msgid ", "
msgstr "Lo schema URI '{parts.scheme}' non è consentito. Schemi consentiti: {', '.join(allowed_schemes)}" msgstr ""
#: documents/validators.py:45
#, python-brace-format
msgid "Unable to parse URI {value}"
msgstr "Impossibile analizzare l'URI {value}"
#: documents/views.py:336 documents/views.py:2729 #: documents/views.py:336 documents/views.py:2729
msgid "Invalid more_like_id" msgid "Invalid more_like_id"
@@ -2183,7 +2168,7 @@ msgstr "Abilita la suddivisione sui codici a barre dei tag"
#: paperless/models.py:308 #: paperless/models.py:308
msgid "Stores the values of detected barcodes" msgid "Stores the values of detected barcodes"
msgstr "" msgstr "Memorizza i valori dei codici a barre individuati"
#: paperless/models.py:318 #: paperless/models.py:318
msgid "Sets the remote OCR engine" msgid "Sets the remote OCR engine"
+3 -18
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-05 16:26+0000\n" "POT-Creation-Date: 2026-10-06 15:12+0000\n"
"PO-Revision-Date: 2026-10-05 16:27\n" "PO-Revision-Date: 2026-10-06 15:13\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Japanese\n" "Language-Team: Japanese\n"
"Language: ja_JP\n" "Language: ja_JP\n"
@@ -1913,23 +1913,8 @@ msgstr "%(provider_name)s アカウントでログインしようとしていま
msgid "As a final step, please complete the following form:" msgid "As a final step, please complete the following form:"
msgstr "最後のステップとして、以下のフォームに記入してください" msgstr "最後のステップとして、以下のフォームに記入してください"
#: documents/validators.py:24
#, python-brace-format
msgid "Unable to parse URI {value}, missing scheme"
msgstr ""
#: documents/validators.py:29
#, python-brace-format
msgid "Unable to parse URI {value}, missing net location or path"
msgstr ""
#: documents/validators.py:36 #: documents/validators.py:36
msgid "URI scheme '{parts.scheme}' is not allowed. Allowed schemes: {', '.join(allowed_schemes)}" msgid ", "
msgstr ""
#: documents/validators.py:45
#, python-brace-format
msgid "Unable to parse URI {value}"
msgstr "" msgstr ""
#: documents/views.py:336 documents/views.py:2729 #: documents/views.py:336 documents/views.py:2729
+4 -19
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-05 16:26+0000\n" "POT-Creation-Date: 2026-10-06 15:12+0000\n"
"PO-Revision-Date: 2026-10-05 16:27\n" "PO-Revision-Date: 2026-10-06 15:13\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Korean\n" "Language-Team: Korean\n"
"Language: ko_KR\n" "Language: ko_KR\n"
@@ -1913,24 +1913,9 @@ msgstr "%(provider_name)s 의 계정을 사용하여 로그인하려고 합니
msgid "As a final step, please complete the following form:" msgid "As a final step, please complete the following form:"
msgstr "마지막 단계로 다음 양식을 작성해 주세요:" msgstr "마지막 단계로 다음 양식을 작성해 주세요:"
#: documents/validators.py:24
#, python-brace-format
msgid "Unable to parse URI {value}, missing scheme"
msgstr "{value} URI를 파싱할 수 없습니다: 스킴이 누락되었습니다."
#: documents/validators.py:29
#, python-brace-format
msgid "Unable to parse URI {value}, missing net location or path"
msgstr "{value} URI를 파싱할 수 없습니다: 네트워크 위치 또는 경로가 누락되었습니다."
#: documents/validators.py:36 #: documents/validators.py:36
msgid "URI scheme '{parts.scheme}' is not allowed. Allowed schemes: {', '.join(allowed_schemes)}" msgid ", "
msgstr "URI 스킴 '{parts.scheme}'는 허용되지 않습니다. 허용된 스킴: {', '.join(allowed_schemes)}" msgstr ""
#: documents/validators.py:45
#, python-brace-format
msgid "Unable to parse URI {value}"
msgstr "{value} URI를 파싱할 수 없음"
#: documents/views.py:336 documents/views.py:2729 #: documents/views.py:336 documents/views.py:2729
msgid "Invalid more_like_id" msgid "Invalid more_like_id"
+3 -18
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-05 16:26+0000\n" "POT-Creation-Date: 2026-10-06 15:12+0000\n"
"PO-Revision-Date: 2026-10-05 16:27\n" "PO-Revision-Date: 2026-10-06 15:13\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Luxembourgish\n" "Language-Team: Luxembourgish\n"
"Language: lb_LU\n" "Language: lb_LU\n"
@@ -1912,23 +1912,8 @@ msgstr ""
msgid "As a final step, please complete the following form:" msgid "As a final step, please complete the following form:"
msgstr "" msgstr ""
#: documents/validators.py:24
#, python-brace-format
msgid "Unable to parse URI {value}, missing scheme"
msgstr ""
#: documents/validators.py:29
#, python-brace-format
msgid "Unable to parse URI {value}, missing net location or path"
msgstr ""
#: documents/validators.py:36 #: documents/validators.py:36
msgid "URI scheme '{parts.scheme}' is not allowed. Allowed schemes: {', '.join(allowed_schemes)}" msgid ", "
msgstr ""
#: documents/validators.py:45
#, python-brace-format
msgid "Unable to parse URI {value}"
msgstr "" msgstr ""
#: documents/views.py:336 documents/views.py:2729 #: documents/views.py:336 documents/views.py:2729
+4 -19
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-05 16:26+0000\n" "POT-Creation-Date: 2026-10-06 15:12+0000\n"
"PO-Revision-Date: 2026-10-05 16:27\n" "PO-Revision-Date: 2026-10-06 15:13\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Lithuanian\n" "Language-Team: Lithuanian\n"
"Language: lt_LT\n" "Language: lt_LT\n"
@@ -1912,24 +1912,9 @@ msgstr "Ketinate prisijungimui naudoti savo %(provider_name)s paskyrą."
msgid "As a final step, please complete the following form:" msgid "As a final step, please complete the following form:"
msgstr "Galiausiai užpildykite šią formą:" msgstr "Galiausiai užpildykite šią formą:"
#: documents/validators.py:24
#, python-brace-format
msgid "Unable to parse URI {value}, missing scheme"
msgstr "Nepavyko apdoroti URI {value}, trūksta schemos"
#: documents/validators.py:29
#, python-brace-format
msgid "Unable to parse URI {value}, missing net location or path"
msgstr "Nepavyko apdoroti URI {value}, trūksta tinklo vietos arba kelio"
#: documents/validators.py:36 #: documents/validators.py:36
msgid "URI scheme '{parts.scheme}' is not allowed. Allowed schemes: {', '.join(allowed_schemes)}" msgid ", "
msgstr "URI schema '{parts.scheme}' nėra leistina. Galimos schemos: {', '.join(allowed_schemes)}" msgstr ""
#: documents/validators.py:45
#, python-brace-format
msgid "Unable to parse URI {value}"
msgstr "Nepavyko apdoroti URI {value}"
#: documents/views.py:336 documents/views.py:2729 #: documents/views.py:336 documents/views.py:2729
msgid "Invalid more_like_id" msgid "Invalid more_like_id"
+3 -18
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-05 16:26+0000\n" "POT-Creation-Date: 2026-10-06 15:12+0000\n"
"PO-Revision-Date: 2026-10-05 16:27\n" "PO-Revision-Date: 2026-10-06 15:13\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Latvian\n" "Language-Team: Latvian\n"
"Language: lv_LV\n" "Language: lv_LV\n"
@@ -1912,23 +1912,8 @@ msgstr ""
msgid "As a final step, please complete the following form:" msgid "As a final step, please complete the following form:"
msgstr "" msgstr ""
#: documents/validators.py:24
#, python-brace-format
msgid "Unable to parse URI {value}, missing scheme"
msgstr ""
#: documents/validators.py:29
#, python-brace-format
msgid "Unable to parse URI {value}, missing net location or path"
msgstr ""
#: documents/validators.py:36 #: documents/validators.py:36
msgid "URI scheme '{parts.scheme}' is not allowed. Allowed schemes: {', '.join(allowed_schemes)}" msgid ", "
msgstr ""
#: documents/validators.py:45
#, python-brace-format
msgid "Unable to parse URI {value}"
msgstr "" msgstr ""
#: documents/views.py:336 documents/views.py:2729 #: documents/views.py:336 documents/views.py:2729
+3 -18
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-05 16:26+0000\n" "POT-Creation-Date: 2026-10-06 15:12+0000\n"
"PO-Revision-Date: 2026-10-05 16:27\n" "PO-Revision-Date: 2026-10-06 15:13\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Macedonian\n" "Language-Team: Macedonian\n"
"Language: mk_MK\n" "Language: mk_MK\n"
@@ -1912,23 +1912,8 @@ msgstr ""
msgid "As a final step, please complete the following form:" msgid "As a final step, please complete the following form:"
msgstr "" msgstr ""
#: documents/validators.py:24
#, python-brace-format
msgid "Unable to parse URI {value}, missing scheme"
msgstr ""
#: documents/validators.py:29
#, python-brace-format
msgid "Unable to parse URI {value}, missing net location or path"
msgstr ""
#: documents/validators.py:36 #: documents/validators.py:36
msgid "URI scheme '{parts.scheme}' is not allowed. Allowed schemes: {', '.join(allowed_schemes)}" msgid ", "
msgstr ""
#: documents/validators.py:45
#, python-brace-format
msgid "Unable to parse URI {value}"
msgstr "" msgstr ""
#: documents/views.py:336 documents/views.py:2729 #: documents/views.py:336 documents/views.py:2729
+3 -18
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-05 16:26+0000\n" "POT-Creation-Date: 2026-10-06 15:12+0000\n"
"PO-Revision-Date: 2026-10-05 16:27\n" "PO-Revision-Date: 2026-10-06 15:13\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Malay\n" "Language-Team: Malay\n"
"Language: ms_MY\n" "Language: ms_MY\n"
@@ -1912,23 +1912,8 @@ msgstr ""
msgid "As a final step, please complete the following form:" msgid "As a final step, please complete the following form:"
msgstr "" msgstr ""
#: documents/validators.py:24
#, python-brace-format
msgid "Unable to parse URI {value}, missing scheme"
msgstr ""
#: documents/validators.py:29
#, python-brace-format
msgid "Unable to parse URI {value}, missing net location or path"
msgstr ""
#: documents/validators.py:36 #: documents/validators.py:36
msgid "URI scheme '{parts.scheme}' is not allowed. Allowed schemes: {', '.join(allowed_schemes)}" msgid ", "
msgstr ""
#: documents/validators.py:45
#, python-brace-format
msgid "Unable to parse URI {value}"
msgstr "" msgstr ""
#: documents/views.py:336 documents/views.py:2729 #: documents/views.py:336 documents/views.py:2729
+3 -18
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-05 16:26+0000\n" "POT-Creation-Date: 2026-10-06 15:12+0000\n"
"PO-Revision-Date: 2026-10-05 16:27\n" "PO-Revision-Date: 2026-10-06 15:13\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Dutch\n" "Language-Team: Dutch\n"
"Language: nl_NL\n" "Language: nl_NL\n"
@@ -1913,23 +1913,8 @@ msgstr "Je staat op het punt om met je %(provider_name)s account in te loggen."
msgid "As a final step, please complete the following form:" msgid "As a final step, please complete the following form:"
msgstr "Vul als laatste stap het volgende formulier in:" msgstr "Vul als laatste stap het volgende formulier in:"
#: documents/validators.py:24
#, python-brace-format
msgid "Unable to parse URI {value}, missing scheme"
msgstr ""
#: documents/validators.py:29
#, python-brace-format
msgid "Unable to parse URI {value}, missing net location or path"
msgstr ""
#: documents/validators.py:36 #: documents/validators.py:36
msgid "URI scheme '{parts.scheme}' is not allowed. Allowed schemes: {', '.join(allowed_schemes)}" msgid ", "
msgstr ""
#: documents/validators.py:45
#, python-brace-format
msgid "Unable to parse URI {value}"
msgstr "" msgstr ""
#: documents/views.py:336 documents/views.py:2729 #: documents/views.py:336 documents/views.py:2729
+4 -19
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-05 16:26+0000\n" "POT-Creation-Date: 2026-10-06 15:12+0000\n"
"PO-Revision-Date: 2026-10-05 16:27\n" "PO-Revision-Date: 2026-10-06 15:13\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Norwegian\n" "Language-Team: Norwegian\n"
"Language: no_NO\n" "Language: no_NO\n"
@@ -1913,24 +1913,9 @@ msgstr "You are about to use your %(provider_name)s account to login. (NO)"
msgid "As a final step, please complete the following form:" msgid "As a final step, please complete the following form:"
msgstr "As a final step, please complete the following form: (NO)" msgstr "As a final step, please complete the following form: (NO)"
#: documents/validators.py:24
#, python-brace-format
msgid "Unable to parse URI {value}, missing scheme"
msgstr "Unable to parse URI {value}, missing scheme (NO)"
#: documents/validators.py:29
#, python-brace-format
msgid "Unable to parse URI {value}, missing net location or path"
msgstr "Unable to parse URI {value}, missing net location or path (NO)"
#: documents/validators.py:36 #: documents/validators.py:36
msgid "URI scheme '{parts.scheme}' is not allowed. Allowed schemes: {', '.join(allowed_schemes)}" msgid ", "
msgstr "URI scheme '{parts.scheme}' is not allowed. Allowed schemes: {', '.join(allowed_schemes)} (NO)" msgstr ""
#: documents/validators.py:45
#, python-brace-format
msgid "Unable to parse URI {value}"
msgstr "Unable to parse URI {value} (NO)"
#: documents/views.py:336 documents/views.py:2729 #: documents/views.py:336 documents/views.py:2729
msgid "Invalid more_like_id" msgid "Invalid more_like_id"
+4 -19
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-05 16:26+0000\n" "POT-Creation-Date: 2026-10-06 15:12+0000\n"
"PO-Revision-Date: 2026-10-05 16:27\n" "PO-Revision-Date: 2026-10-06 15:13\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Polish\n" "Language-Team: Polish\n"
"Language: pl_PL\n" "Language: pl_PL\n"
@@ -1913,24 +1913,9 @@ msgstr "Zamierzasz użyć konta %(provider_name)s aby się zalogować."
msgid "As a final step, please complete the following form:" msgid "As a final step, please complete the following form:"
msgstr "Na koniec należy wypełnić poniższy formularz:" msgstr "Na koniec należy wypełnić poniższy formularz:"
#: documents/validators.py:24
#, python-brace-format
msgid "Unable to parse URI {value}, missing scheme"
msgstr "Nie można przeanalizować URI {value}, brak schematu"
#: documents/validators.py:29
#, python-brace-format
msgid "Unable to parse URI {value}, missing net location or path"
msgstr "Nie można przeanalizować URI {value}, brak lokalizacji sieciowej lub ścieżki"
#: documents/validators.py:36 #: documents/validators.py:36
msgid "URI scheme '{parts.scheme}' is not allowed. Allowed schemes: {', '.join(allowed_schemes)}" msgid ", "
msgstr "Schemat URI '{parts.scheme}' jest niedozwolony. Dozwolone schematy: {', '.join(allowed_schemes)}" msgstr ""
#: documents/validators.py:45
#, python-brace-format
msgid "Unable to parse URI {value}"
msgstr "Nie można przetworzyć URI {value}"
#: documents/views.py:336 documents/views.py:2729 #: documents/views.py:336 documents/views.py:2729
msgid "Invalid more_like_id" msgid "Invalid more_like_id"
+4 -20
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-05 16:26+0000\n" "POT-Creation-Date: 2026-10-06 15:12+0000\n"
"PO-Revision-Date: 2026-10-05 16:27\n" "PO-Revision-Date: 2026-10-06 15:13\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Portuguese, Brazilian\n" "Language-Team: Portuguese, Brazilian\n"
"Language: pt_BR\n" "Language: pt_BR\n"
@@ -1914,25 +1914,9 @@ msgstr "Você está prestes a usar sua conta %(provider_name)s para entrar."
msgid "As a final step, please complete the following form:" msgid "As a final step, please complete the following form:"
msgstr "Como etapa final, por favor preencha o seguinte formulário:" msgstr "Como etapa final, por favor preencha o seguinte formulário:"
#: documents/validators.py:24
#, python-brace-format
msgid "Unable to parse URI {value}, missing scheme"
msgstr "Não é possível analisar o URI {value}, esquema ausente"
#: documents/validators.py:29
#, python-brace-format
msgid "Unable to parse URI {value}, missing net location or path"
msgstr ""
#: documents/validators.py:36 #: documents/validators.py:36
msgid "URI scheme '{parts.scheme}' is not allowed. Allowed schemes: {', '.join(allowed_schemes)}" msgid ", "
msgstr "Esquema URI '{parts.scheme}' não é permitido. Esquemas permitidos:\n" msgstr ""
"{', '.join(allowed_schemes)}"
#: documents/validators.py:45
#, python-brace-format
msgid "Unable to parse URI {value}"
msgstr "Não é possível analisar o URI {value}"
#: documents/views.py:336 documents/views.py:2729 #: documents/views.py:336 documents/views.py:2729
msgid "Invalid more_like_id" msgid "Invalid more_like_id"
+3 -18
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-05 16:26+0000\n" "POT-Creation-Date: 2026-10-06 15:12+0000\n"
"PO-Revision-Date: 2026-10-05 16:27\n" "PO-Revision-Date: 2026-10-06 15:13\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Portuguese\n" "Language-Team: Portuguese\n"
"Language: pt_PT\n" "Language: pt_PT\n"
@@ -1913,25 +1913,10 @@ msgstr ""
msgid "As a final step, please complete the following form:" msgid "As a final step, please complete the following form:"
msgstr "" msgstr ""
#: documents/validators.py:24
#, python-brace-format
msgid "Unable to parse URI {value}, missing scheme"
msgstr "Não foi possível analisar o URI {value}, o esquema está em falta"
#: documents/validators.py:29
#, python-brace-format
msgid "Unable to parse URI {value}, missing net location or path"
msgstr ""
#: documents/validators.py:36 #: documents/validators.py:36
msgid "URI scheme '{parts.scheme}' is not allowed. Allowed schemes: {', '.join(allowed_schemes)}" msgid ", "
msgstr "" msgstr ""
#: documents/validators.py:45
#, python-brace-format
msgid "Unable to parse URI {value}"
msgstr "Não foi possível analisar o URI {value}"
#: documents/views.py:336 documents/views.py:2729 #: documents/views.py:336 documents/views.py:2729
msgid "Invalid more_like_id" msgid "Invalid more_like_id"
msgstr "" msgstr ""
+4 -19
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-05 16:26+0000\n" "POT-Creation-Date: 2026-10-06 15:12+0000\n"
"PO-Revision-Date: 2026-10-05 16:27\n" "PO-Revision-Date: 2026-10-06 15:13\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Romanian\n" "Language-Team: Romanian\n"
"Language: ro_RO\n" "Language: ro_RO\n"
@@ -1913,24 +1913,9 @@ msgstr "Sunteți pe cale să vă utilizați contul %(provider_name)s pentru a v
msgid "As a final step, please complete the following form:" msgid "As a final step, please complete the following form:"
msgstr "În etapa finală, vă rugăm să completați următorul formular:" msgstr "În etapa finală, vă rugăm să completați următorul formular:"
#: documents/validators.py:24
#, python-brace-format
msgid "Unable to parse URI {value}, missing scheme"
msgstr "Imposibil de analizat URI {value}, schemă lipsă"
#: documents/validators.py:29
#, python-brace-format
msgid "Unable to parse URI {value}, missing net location or path"
msgstr "Imposibil de analizat URI {value}, lipsă locație sau cale"
#: documents/validators.py:36 #: documents/validators.py:36
msgid "URI scheme '{parts.scheme}' is not allowed. Allowed schemes: {', '.join(allowed_schemes)}" msgid ", "
msgstr "Schema URI '{parts.scheme}' nu este permisă. Schemele permise: {', '.join(allowed_schemes)}" msgstr ""
#: documents/validators.py:45
#, python-brace-format
msgid "Unable to parse URI {value}"
msgstr "Nu se poate analiza URI {value}"
#: documents/views.py:336 documents/views.py:2729 #: documents/views.py:336 documents/views.py:2729
msgid "Invalid more_like_id" msgid "Invalid more_like_id"
+4 -19
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-05 16:26+0000\n" "POT-Creation-Date: 2026-10-06 15:12+0000\n"
"PO-Revision-Date: 2026-10-05 16:27\n" "PO-Revision-Date: 2026-10-06 15:13\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Russian\n" "Language-Team: Russian\n"
"Language: ru_RU\n" "Language: ru_RU\n"
@@ -1913,24 +1913,9 @@ msgstr "Вы собираетесь войти через сторонний с
msgid "As a final step, please complete the following form:" msgid "As a final step, please complete the following form:"
msgstr "На завершение, пожалуйста заполните следующую форму:" msgstr "На завершение, пожалуйста заполните следующую форму:"
#: documents/validators.py:24
#, python-brace-format
msgid "Unable to parse URI {value}, missing scheme"
msgstr "Не удается распознать URI {value}, отсутствует схема"
#: documents/validators.py:29
#, python-brace-format
msgid "Unable to parse URI {value}, missing net location or path"
msgstr "Не удалось распознать URI {value}, отсутствует сетевое расположение или путь"
#: documents/validators.py:36 #: documents/validators.py:36
msgid "URI scheme '{parts.scheme}' is not allowed. Allowed schemes: {', '.join(allowed_schemes)}" msgid ", "
msgstr "Недопустимая схема URI '{parts.scheme}'. Разрешенные схемы: {', '.join(allowed_schemes)}" msgstr ""
#: documents/validators.py:45
#, python-brace-format
msgid "Unable to parse URI {value}"
msgstr "Невозможно распознать URI {value}"
#: documents/views.py:336 documents/views.py:2729 #: documents/views.py:336 documents/views.py:2729
msgid "Invalid more_like_id" msgid "Invalid more_like_id"
+4 -19
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-05 16:26+0000\n" "POT-Creation-Date: 2026-10-06 15:12+0000\n"
"PO-Revision-Date: 2026-10-06 02:00\n" "PO-Revision-Date: 2026-10-07 12:33\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Slovak\n" "Language-Team: Slovak\n"
"Language: sk_SK\n" "Language: sk_SK\n"
@@ -1913,24 +1913,9 @@ msgstr "Chystáte sa na prihlásenie použiť svoj účet %(provider_name)s."
msgid "As a final step, please complete the following form:" msgid "As a final step, please complete the following form:"
msgstr "Ako posledný krok vyplňte nasledujúci formulár:" msgstr "Ako posledný krok vyplňte nasledujúci formulár:"
#: documents/validators.py:24
#, python-brace-format
msgid "Unable to parse URI {value}, missing scheme"
msgstr "Nepodarilo sa analyzovať URI {value}, chýba schéma"
#: documents/validators.py:29
#, python-brace-format
msgid "Unable to parse URI {value}, missing net location or path"
msgstr "Nepodarilo sa analyzovať URI {value}; chýba sieťové umiestnenie alebo cesta."
#: documents/validators.py:36 #: documents/validators.py:36
msgid "URI scheme '{parts.scheme}' is not allowed. Allowed schemes: {', '.join(allowed_schemes)}" msgid ", "
msgstr "Schéma URI „{parts.scheme}“ nie je povolená. Povolené schémy: {', '.join(allowed_schemes)}" msgstr ""
#: documents/validators.py:45
#, python-brace-format
msgid "Unable to parse URI {value}"
msgstr "Nepodarilo sa analyzovať URI {value}"
#: documents/views.py:336 documents/views.py:2729 #: documents/views.py:336 documents/views.py:2729
msgid "Invalid more_like_id" msgid "Invalid more_like_id"
+4 -19
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-05 16:26+0000\n" "POT-Creation-Date: 2026-10-06 15:12+0000\n"
"PO-Revision-Date: 2026-10-05 16:27\n" "PO-Revision-Date: 2026-10-06 15:13\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Slovenian\n" "Language-Team: Slovenian\n"
"Language: sl_SI\n" "Language: sl_SI\n"
@@ -1913,24 +1913,9 @@ msgstr "Za prijavo boste uporabili račun ponudnika %(provider_name)s."
msgid "As a final step, please complete the following form:" msgid "As a final step, please complete the following form:"
msgstr "Kot zadnji korak vas prosimo, da izpolnite naslednji obrazec:" msgstr "Kot zadnji korak vas prosimo, da izpolnite naslednji obrazec:"
#: documents/validators.py:24
#, python-brace-format
msgid "Unable to parse URI {value}, missing scheme"
msgstr "Ni mogoče razčleniti URI-ja {value}, manjka shema"
#: documents/validators.py:29
#, python-brace-format
msgid "Unable to parse URI {value}, missing net location or path"
msgstr "Ni mogoče razčleniti URI-ja {value}, manjka omrežna lokacija ali pot"
#: documents/validators.py:36 #: documents/validators.py:36
msgid "URI scheme '{parts.scheme}' is not allowed. Allowed schemes: {', '.join(allowed_schemes)}" msgid ", "
msgstr "Shema URI '{parts.scheme}' ni dovoljena. Dovoljene sheme: {', '.join(allowed_schemes)}" msgstr ""
#: documents/validators.py:45
#, python-brace-format
msgid "Unable to parse URI {value}"
msgstr "Ni mogoče razčleniti URI-ja {value}"
#: documents/views.py:336 documents/views.py:2729 #: documents/views.py:336 documents/views.py:2729
msgid "Invalid more_like_id" msgid "Invalid more_like_id"
+3 -18
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-05 16:26+0000\n" "POT-Creation-Date: 2026-10-06 15:12+0000\n"
"PO-Revision-Date: 2026-10-05 16:27\n" "PO-Revision-Date: 2026-10-06 15:13\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Albanian\n" "Language-Team: Albanian\n"
"Language: sq_AL\n" "Language: sq_AL\n"
@@ -1913,23 +1913,8 @@ msgstr "You are about to use your %(provider_name)s llogari to login."
msgid "As a final step, please complete the following form:" msgid "As a final step, please complete the following form:"
msgstr "Si hap i fundit, ju lutemi plotësoni formularin e mëposhtëm:" msgstr "Si hap i fundit, ju lutemi plotësoni formularin e mëposhtëm:"
#: documents/validators.py:24
#, python-brace-format
msgid "Unable to parse URI {value}, missing scheme"
msgstr ""
#: documents/validators.py:29
#, python-brace-format
msgid "Unable to parse URI {value}, missing net location or path"
msgstr ""
#: documents/validators.py:36 #: documents/validators.py:36
msgid "URI scheme '{parts.scheme}' is not allowed. Allowed schemes: {', '.join(allowed_schemes)}" msgid ", "
msgstr ""
#: documents/validators.py:45
#, python-brace-format
msgid "Unable to parse URI {value}"
msgstr "" msgstr ""
#: documents/views.py:336 documents/views.py:2729 #: documents/views.py:336 documents/views.py:2729
+4 -19
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-05 16:26+0000\n" "POT-Creation-Date: 2026-10-06 15:12+0000\n"
"PO-Revision-Date: 2026-10-05 16:27\n" "PO-Revision-Date: 2026-10-06 15:13\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Serbian (Latin)\n" "Language-Team: Serbian (Latin)\n"
"Language: sr_CS\n" "Language: sr_CS\n"
@@ -1913,24 +1913,9 @@ msgstr "Uskoro ćete koristiti svoj nalog na %(provider_name)s za prijavu."
msgid "As a final step, please complete the following form:" msgid "As a final step, please complete the following form:"
msgstr "Kao poslednji korak, molimo Vas da popunite sledeći obrazac:" msgstr "Kao poslednji korak, molimo Vas da popunite sledeći obrazac:"
#: documents/validators.py:24
#, python-brace-format
msgid "Unable to parse URI {value}, missing scheme"
msgstr "Nije moguće analizirati URI {value}, nedostaje šema"
#: documents/validators.py:29
#, python-brace-format
msgid "Unable to parse URI {value}, missing net location or path"
msgstr "Nije moguće analizirati URI {value}, nedostaje mrežan lokacija ili putanja"
#: documents/validators.py:36 #: documents/validators.py:36
msgid "URI scheme '{parts.scheme}' is not allowed. Allowed schemes: {', '.join(allowed_schemes)}" msgid ", "
msgstr "Šema URI-ja '{parts.scheme}' nije dozvoljena. Dozvoljene šeme {', '.join(allowed_schemes)}" msgstr ""
#: documents/validators.py:45
#, python-brace-format
msgid "Unable to parse URI {value}"
msgstr "Nije moguće analizirati URI {value}"
#: documents/views.py:336 documents/views.py:2729 #: documents/views.py:336 documents/views.py:2729
msgid "Invalid more_like_id" msgid "Invalid more_like_id"
+4 -19
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-05 16:26+0000\n" "POT-Creation-Date: 2026-10-06 15:12+0000\n"
"PO-Revision-Date: 2026-10-05 16:27\n" "PO-Revision-Date: 2026-10-06 15:13\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Swedish\n" "Language-Team: Swedish\n"
"Language: sv_SE\n" "Language: sv_SE\n"
@@ -1913,24 +1913,9 @@ msgstr "Du håller på att använda ditt %(provider_name)s-konto för att logga
msgid "As a final step, please complete the following form:" msgid "As a final step, please complete the following form:"
msgstr "Slutför följande formulär som ett sista steg:" msgstr "Slutför följande formulär som ett sista steg:"
#: documents/validators.py:24
#, python-brace-format
msgid "Unable to parse URI {value}, missing scheme"
msgstr "Kunde inte tolka URI {value}, schema saknas"
#: documents/validators.py:29
#, python-brace-format
msgid "Unable to parse URI {value}, missing net location or path"
msgstr "Kunde inte tolka URI {value}, nätverksplats eller sökväg saknas"
#: documents/validators.py:36 #: documents/validators.py:36
msgid "URI scheme '{parts.scheme}' is not allowed. Allowed schemes: {', '.join(allowed_schemes)}" msgid ", "
msgstr "URI-schemat '{parts.scheme}' är inte tillåtet. Tillåtna scheman: {', '.join(allowed_schemes)}" msgstr ""
#: documents/validators.py:45
#, python-brace-format
msgid "Unable to parse URI {value}"
msgstr "Kunde inte tolka URI {value}"
#: documents/views.py:336 documents/views.py:2729 #: documents/views.py:336 documents/views.py:2729
msgid "Invalid more_like_id" msgid "Invalid more_like_id"
+3 -18
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-05 16:26+0000\n" "POT-Creation-Date: 2026-10-06 15:12+0000\n"
"PO-Revision-Date: 2026-10-05 16:27\n" "PO-Revision-Date: 2026-10-06 15:13\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Thai\n" "Language-Team: Thai\n"
"Language: th_TH\n" "Language: th_TH\n"
@@ -1912,23 +1912,8 @@ msgstr ""
msgid "As a final step, please complete the following form:" msgid "As a final step, please complete the following form:"
msgstr "" msgstr ""
#: documents/validators.py:24
#, python-brace-format
msgid "Unable to parse URI {value}, missing scheme"
msgstr ""
#: documents/validators.py:29
#, python-brace-format
msgid "Unable to parse URI {value}, missing net location or path"
msgstr ""
#: documents/validators.py:36 #: documents/validators.py:36
msgid "URI scheme '{parts.scheme}' is not allowed. Allowed schemes: {', '.join(allowed_schemes)}" msgid ", "
msgstr ""
#: documents/validators.py:45
#, python-brace-format
msgid "Unable to parse URI {value}"
msgstr "" msgstr ""
#: documents/views.py:336 documents/views.py:2729 #: documents/views.py:336 documents/views.py:2729
+4 -19
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-05 16:26+0000\n" "POT-Creation-Date: 2026-10-06 15:12+0000\n"
"PO-Revision-Date: 2026-10-05 16:27\n" "PO-Revision-Date: 2026-10-06 15:13\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Turkish\n" "Language-Team: Turkish\n"
"Language: tr_TR\n" "Language: tr_TR\n"
@@ -1913,24 +1913,9 @@ msgstr "Giriş yapmak için %(provider_name)s hesabınızı kullanmak üzeresini
msgid "As a final step, please complete the following form:" msgid "As a final step, please complete the following form:"
msgstr "Son adım olarak, lütfen aşağıdaki formu doldurun:" msgstr "Son adım olarak, lütfen aşağıdaki formu doldurun:"
#: documents/validators.py:24
#, python-brace-format
msgid "Unable to parse URI {value}, missing scheme"
msgstr "URI {value} ayrıştırılamıyor, şema eksik"
#: documents/validators.py:29
#, python-brace-format
msgid "Unable to parse URI {value}, missing net location or path"
msgstr "URI {value} ayrıştırılamıyor, ağ konumu veya yol eksik"
#: documents/validators.py:36 #: documents/validators.py:36
msgid "URI scheme '{parts.scheme}' is not allowed. Allowed schemes: {', '.join(allowed_schemes)}" msgid ", "
msgstr "URI şeması ‘{parts.scheme}’ izin verilmez. İzin verilen şemalar: {‘, ’.join(allowed_schemes)}" msgstr ""
#: documents/validators.py:45
#, python-brace-format
msgid "Unable to parse URI {value}"
msgstr "URI {value} işlenemiyor"
#: documents/views.py:336 documents/views.py:2729 #: documents/views.py:336 documents/views.py:2729
msgid "Invalid more_like_id" msgid "Invalid more_like_id"
+3 -18
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-05 16:26+0000\n" "POT-Creation-Date: 2026-10-06 15:12+0000\n"
"PO-Revision-Date: 2026-10-05 16:27\n" "PO-Revision-Date: 2026-10-06 15:13\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Ukrainian\n" "Language-Team: Ukrainian\n"
"Language: uk_UA\n" "Language: uk_UA\n"
@@ -1913,23 +1913,8 @@ msgstr "Ви збираєтеся використовувати ваш облі
msgid "As a final step, please complete the following form:" msgid "As a final step, please complete the following form:"
msgstr "Як останній крок, будь ласка, заповніть наступну форму:" msgstr "Як останній крок, будь ласка, заповніть наступну форму:"
#: documents/validators.py:24
#, python-brace-format
msgid "Unable to parse URI {value}, missing scheme"
msgstr ""
#: documents/validators.py:29
#, python-brace-format
msgid "Unable to parse URI {value}, missing net location or path"
msgstr ""
#: documents/validators.py:36 #: documents/validators.py:36
msgid "URI scheme '{parts.scheme}' is not allowed. Allowed schemes: {', '.join(allowed_schemes)}" msgid ", "
msgstr ""
#: documents/validators.py:45
#, python-brace-format
msgid "Unable to parse URI {value}"
msgstr "" msgstr ""
#: documents/views.py:336 documents/views.py:2729 #: documents/views.py:336 documents/views.py:2729
+4 -19
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-05 16:26+0000\n" "POT-Creation-Date: 2026-10-06 15:12+0000\n"
"PO-Revision-Date: 2026-10-05 16:27\n" "PO-Revision-Date: 2026-10-06 15:13\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Vietnamese\n" "Language-Team: Vietnamese\n"
"Language: vi_VN\n" "Language: vi_VN\n"
@@ -1913,24 +1913,9 @@ msgstr "Bạn sắp sử dụng tài khoản %(provider_name)s của bạn để
msgid "As a final step, please complete the following form:" msgid "As a final step, please complete the following form:"
msgstr "Là bước cuối cùng, vui lòng hoàn thành mẫu đơn sau:" msgstr "Là bước cuối cùng, vui lòng hoàn thành mẫu đơn sau:"
#: documents/validators.py:24
#, python-brace-format
msgid "Unable to parse URI {value}, missing scheme"
msgstr "Không thể phân tích URI {value}, thiếu giao thức"
#: documents/validators.py:29
#, python-brace-format
msgid "Unable to parse URI {value}, missing net location or path"
msgstr "Không thể phân tích URI {value}, thiếu tên miền hoặc đường dẫn"
#: documents/validators.py:36 #: documents/validators.py:36
msgid "URI scheme '{parts.scheme}' is not allowed. Allowed schemes: {', '.join(allowed_schemes)}" msgid ", "
msgstr "Giao thức URI '{parts.scheme}' không được phép. Các giao thức được phép: {', '.join(allowed_schemes)}" msgstr ""
#: documents/validators.py:45
#, python-brace-format
msgid "Unable to parse URI {value}"
msgstr "Không thể phân tích URI {value}"
#: documents/views.py:336 documents/views.py:2729 #: documents/views.py:336 documents/views.py:2729
msgid "Invalid more_like_id" msgid "Invalid more_like_id"
+4 -19
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-05 16:26+0000\n" "POT-Creation-Date: 2026-10-06 15:12+0000\n"
"PO-Revision-Date: 2026-10-05 16:27\n" "PO-Revision-Date: 2026-10-06 15:13\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Chinese Simplified\n" "Language-Team: Chinese Simplified\n"
"Language: zh_CN\n" "Language: zh_CN\n"
@@ -1913,24 +1913,9 @@ msgstr "您将使用您的 %(provider_name)s 账户登录."
msgid "As a final step, please complete the following form:" msgid "As a final step, please complete the following form:"
msgstr "作为最后一步,请填写以下表格:" msgstr "作为最后一步,请填写以下表格:"
#: documents/validators.py:24
#, python-brace-format
msgid "Unable to parse URI {value}, missing scheme"
msgstr "无法解析 URI {value},缺少scheme"
#: documents/validators.py:29
#, python-brace-format
msgid "Unable to parse URI {value}, missing net location or path"
msgstr "无法解析 URI {value},缺少网络位置或路径"
#: documents/validators.py:36 #: documents/validators.py:36
msgid "URI scheme '{parts.scheme}' is not allowed. Allowed schemes: {', '.join(allowed_schemes)}" msgid ", "
msgstr "URI 格式 '{parts.scheme}' 不支持。支持的格式有:{', '.join(allowed_schemes)}" msgstr ""
#: documents/validators.py:45
#, python-brace-format
msgid "Unable to parse URI {value}"
msgstr "无法解析 URI {value}"
#: documents/views.py:336 documents/views.py:2729 #: documents/views.py:336 documents/views.py:2729
msgid "Invalid more_like_id" msgid "Invalid more_like_id"
+4 -19
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-05 16:26+0000\n" "POT-Creation-Date: 2026-10-06 15:12+0000\n"
"PO-Revision-Date: 2026-10-05 16:27\n" "PO-Revision-Date: 2026-10-06 15:13\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Chinese Traditional\n" "Language-Team: Chinese Traditional\n"
"Language: zh_TW\n" "Language: zh_TW\n"
@@ -1913,24 +1913,9 @@ msgstr "即將使用 %(provider_name)s 帳號登入。"
msgid "As a final step, please complete the following form:" msgid "As a final step, please complete the following form:"
msgstr "最後一步,請填寫以下表單:" msgstr "最後一步,請填寫以下表單:"
#: documents/validators.py:24
#, python-brace-format
msgid "Unable to parse URI {value}, missing scheme"
msgstr "無法解析 URI {value},缺少協定"
#: documents/validators.py:29
#, python-brace-format
msgid "Unable to parse URI {value}, missing net location or path"
msgstr "無法解析 URI {value},缺少網路位置或路徑"
#: documents/validators.py:36 #: documents/validators.py:36
msgid "URI scheme '{parts.scheme}' is not allowed. Allowed schemes: {', '.join(allowed_schemes)}" msgid ", "
msgstr "URI 協定「{parts.scheme}」不被允許。允許的協定有:{', '.join(allowed_schemes)}" msgstr ""
#: documents/validators.py:45
#, python-brace-format
msgid "Unable to parse URI {value}"
msgstr "無法解析 URI {value}"
#: documents/views.py:336 documents/views.py:2729 #: documents/views.py:336 documents/views.py:2729
msgid "Invalid more_like_id" msgid "Invalid more_like_id"
-46
View File
@@ -265,52 +265,6 @@ def get_page_count_for_pdf(
return None return None
def get_pdf_first_page_size_points(
path: Path,
log: logging.Logger | None = None,
) -> tuple[float, float] | None:
"""Return the first page's (width, height) in PDF points, post-rotation.
Uses the CropBox (MediaBox if absent), which must match pdftoppm's
``-cropbox`` or the computed DPI targets the wrong box.
Swaps width and height for 90/270 rotation. ``page.rotation`` resolves
inherited and negative ``/Rotate`` values, a raw lookup does not.
Parameters
----------
path:
Absolute path to the PDF file.
log:
Logger for warnings. Falls back to the module-level logger when omitted.
Returns
-------
tuple[float, float] | None
``(width_points, height_points)``, or ``None`` if the file cannot be
opened, has no pages, or the page box is degenerate.
"""
import pikepdf
_log = log or logger
try:
with pikepdf.Pdf.open(path) as pdf:
if len(pdf.pages) == 0:
return None
page = pdf.pages[0]
llx, lly, urx, ury = (float(v) for v in page.cropbox)
width = abs(urx - llx)
height = abs(ury - lly)
if width <= 0 or height <= 0:
return None
if page.rotation in (90, 270):
width, height = height, width
return width, height
except Exception as e:
_log.warning("Could not determine PDF page size for %s: %s", path, e)
return None
def extract_pdf_metadata( def extract_pdf_metadata(
document_path: Path, document_path: Path,
log: logging.Logger | None = None, log: logging.Logger | None = None,
+2
View File
@@ -986,6 +986,8 @@ GNUPG_HOME = os.getenv("HOME", "/tmp")
# Convert is part of the ImageMagick package # Convert is part of the ImageMagick package
CONVERT_BINARY = os.getenv("PAPERLESS_CONVERT_BINARY", "convert") CONVERT_BINARY = os.getenv("PAPERLESS_CONVERT_BINARY", "convert")
CONVERT_TMPDIR = os.getenv("PAPERLESS_CONVERT_TMPDIR")
CONVERT_MEMORY_LIMIT = os.getenv("PAPERLESS_CONVERT_MEMORY_LIMIT")
GS_BINARY = os.getenv("PAPERLESS_GS_BINARY", "gs") GS_BINARY = os.getenv("PAPERLESS_GS_BINARY", "gs")
@@ -15,10 +15,9 @@ from typing import TYPE_CHECKING
import pytest import pytest
from ocrmypdf import SubprocessOutputError from ocrmypdf import SubprocessOutputError
from PIL import Image
from documents.parsers import ParseError from documents.parsers import ParseError
from documents.parsers import rasterize_pdf_page_to_png from documents.parsers import run_convert
from paperless.models import ModeChoices from paperless.models import ModeChoices
from paperless.parsers import ParserProtocol from paperless.parsers import ParserProtocol
from paperless.parsers.tesseract import RasterisedDocumentParser from paperless.parsers.tesseract import RasterisedDocumentParser
@@ -281,71 +280,24 @@ class TestGetThumbnail:
) )
assert thumb.is_file() assert thumb.is_file()
@pytest.mark.parametrize( def test_thumbnail_fallback_on_convert_error(
("filename", "expected_height"),
[
pytest.param("simple-digital.pdf", 647, id="portrait-letter"),
pytest.param("rotated.pdf", 386, id="landscape"),
],
)
def test_thumbnail_is_correct_format_and_size(
self,
tesseract_parser: RasterisedDocumentParser,
tesseract_samples_dir: Path,
filename: str,
expected_height: int,
) -> None:
"""
GIVEN:
- A portrait or landscape PDF
WHEN:
- A thumbnail is generated
THEN:
- A 500px wide WebP keeping the page's aspect ratio
"""
thumb = tesseract_parser.get_thumbnail(
tesseract_samples_dir / filename,
"application/pdf",
)
with Image.open(thumb) as im:
assert im.format == "WEBP"
assert im.width == 500
assert im.height == pytest.approx(expected_height, abs=2)
def test_thumbnail_fallback_on_pdftoppm_error(
self, self,
mocker: MockerFixture, mocker: MockerFixture,
tesseract_parser: RasterisedDocumentParser, tesseract_parser: RasterisedDocumentParser,
tesseract_samples_dir: Path, tesseract_samples_dir: Path,
) -> None: ) -> None:
""" def _raise_on_pdf(input_file, output_file, **kwargs) -> None:
GIVEN: if ".pdf" in str(input_file):
- Rasterizing the original PDF fails
WHEN:
- A thumbnail is generated
THEN:
- The PDF is repaired with qpdf and a real thumbnail is rendered
"""
original = tesseract_samples_dir / "simple-digital.pdf"
def _fail_on_original(in_path: Path, out_path: Path, **kwargs) -> None:
if in_path == original:
raise ParseError("Does not compute.") raise ParseError("Does not compute.")
rasterize_pdf_page_to_png(in_path, out_path, **kwargs) run_convert(input_file=input_file, output_file=output_file, **kwargs)
rasterize = mocker.patch( mocker.patch("documents.parsers.run_convert", side_effect=_raise_on_pdf)
"documents.parsers.rasterize_pdf_page_to_png",
side_effect=_fail_on_original, thumb = tesseract_parser.get_thumbnail(
tesseract_samples_dir / "simple-digital.pdf",
"application/pdf",
) )
thumb = tesseract_parser.get_thumbnail(original, "application/pdf")
assert rasterize.call_count == 2
assert thumb.is_file() assert thumb.is_file()
assert thumb.name == "convert_qpdf.webp"
with Image.open(thumb) as im:
assert im.format == "WEBP"
assert im.width == 500
def test_thumbnail_encrypted_pdf( def test_thumbnail_encrypted_pdf(
self, self,
-145
View File
@@ -6,10 +6,8 @@ import codecs
from pathlib import Path from pathlib import Path
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
import pikepdf
import pytest import pytest
from paperless.parsers.utils import get_pdf_first_page_size_points
from paperless.parsers.utils import is_tagged_pdf from paperless.parsers.utils import is_tagged_pdf
from paperless.parsers.utils import pdf_born_digital_text from paperless.parsers.utils import pdf_born_digital_text
from paperless.parsers.utils import post_process_text from paperless.parsers.utils import post_process_text
@@ -72,149 +70,6 @@ class TestIsTaggedPdf:
assert is_tagged_pdf(bad) is False assert is_tagged_pdf(bad) is False
class TestGetPdfFirstPageSizePoints:
@staticmethod
def _write_pdf(
path: Path,
*,
media_box: tuple[float, float, float, float] = (0, 0, 600, 800),
crop_box: tuple[float, float, float, float] | None = None,
page_rotate: int | None = None,
inherited_rotate: int | None = None,
) -> Path:
pdf = pikepdf.new()
pdf.add_blank_page(page_size=(media_box[2], media_box[3]))
page = pdf.pages[0]
page.obj.MediaBox = pikepdf.Array(media_box)
if crop_box is not None:
page.obj.CropBox = pikepdf.Array(crop_box)
if page_rotate is not None:
page.obj.Rotate = page_rotate
if inherited_rotate is not None:
pdf.Root.Pages.Rotate = inherited_rotate
pdf.save(path)
return path
def test_letter_sample(self) -> None:
"""
GIVEN:
- A US Letter sample PDF with no CropBox and no rotation
WHEN:
- The first page size is requested
THEN:
- The MediaBox size in points is returned
"""
assert get_pdf_first_page_size_points(SAMPLES / "simple-digital.pdf") == (
612.0,
792.0,
)
@pytest.mark.parametrize(
("rotate", "expected"),
[
pytest.param(0, (600.0, 800.0), id="rotate-0"),
pytest.param(90, (800.0, 600.0), id="rotate-90"),
pytest.param(180, (600.0, 800.0), id="rotate-180"),
pytest.param(270, (800.0, 600.0), id="rotate-270"),
pytest.param(-90, (800.0, 600.0), id="rotate-negative-90"),
],
)
def test_page_rotation_swaps_dimensions(
self,
tmp_path: Path,
rotate: int,
expected: tuple[float, float],
) -> None:
"""
GIVEN:
- A portrait PDF page with /Rotate set directly on the page
WHEN:
- The first page size is requested
THEN:
- Width and height are swapped for quarter-turn rotations only
"""
pdf_path = self._write_pdf(tmp_path / "rotated.pdf", page_rotate=rotate)
assert get_pdf_first_page_size_points(pdf_path) == expected
def test_inherited_rotation_swaps_dimensions(self, tmp_path: Path) -> None:
"""
GIVEN:
- A page inheriting /Rotate 90 from the /Pages node
WHEN:
- The first page size is requested
THEN:
- Width and height are swapped
"""
pdf_path = self._write_pdf(tmp_path / "inherited.pdf", inherited_rotate=90)
assert get_pdf_first_page_size_points(pdf_path) == (800.0, 600.0)
def test_crop_box_preferred_over_media_box(self, tmp_path: Path) -> None:
"""
GIVEN:
- A PDF page with a CropBox smaller than its MediaBox
WHEN:
- The first page size is requested
THEN:
- The CropBox size is returned
"""
pdf_path = self._write_pdf(
tmp_path / "cropped.pdf",
crop_box=(50, 100, 350, 500),
)
assert get_pdf_first_page_size_points(pdf_path) == (300.0, 400.0)
def test_degenerate_box_returns_none(self, tmp_path: Path) -> None:
"""
GIVEN:
- A PDF page whose box has zero width
WHEN:
- The first page size is requested
THEN:
- None is returned
"""
pdf_path = self._write_pdf(
tmp_path / "degenerate.pdf",
media_box=(0, 0, 600, 800),
crop_box=(100, 0, 100, 800),
)
assert get_pdf_first_page_size_points(pdf_path) is None
def test_nonexistent_path_returns_none(self) -> None:
"""
GIVEN:
- A path that does not exist
WHEN:
- The first page size is requested
THEN:
- None is returned and nothing is raised
"""
assert get_pdf_first_page_size_points(Path("/nonexistent/file.pdf")) is None
def test_corrupt_pdf_returns_none(self, tmp_path: Path) -> None:
"""
GIVEN:
- A file that is not a PDF
WHEN:
- The first page size is requested
THEN:
- None is returned and nothing is raised
"""
bad = tmp_path / "bad.pdf"
bad.write_bytes(b"not a pdf")
assert get_pdf_first_page_size_points(bad) is None
def test_encrypted_pdf_returns_none(self) -> None:
"""
GIVEN:
- A password protected PDF
WHEN:
- The first page size is requested
THEN:
- None is returned and nothing is raised
"""
assert get_pdf_first_page_size_points(SAMPLES / "encrypted.pdf") is None
class TestPostProcessText: class TestPostProcessText:
@pytest.mark.parametrize( @pytest.mark.parametrize(
("source", "expected"), ("source", "expected"),