Compare commits

..
Author SHA1 Message Date
shamoon b67cfdf3fd Bump version to 3.4.1 2026-10-30 22:20:31 -07:00
github-actions[bot]andCrowdin Bot 98d2ddd1c6 New Crowdin translations by GitHub Action (#14584)
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
2026-10-31 05:12:07 +00:00
GitHub Actions 91b35eada6 Auto translate strings 2026-10-31 04:48:33 +00:00
shamoon 11248f776d Fix: fix the id__none schema in the right place (#14604) 2026-10-30 21:47:12 -07:00
shamoon 331fa13088 Fix: drop redundant change perms checks on cards open button (#14601) 2026-10-30 16:16:48 -07:00
shamoon ebddd5687c Chore: fix a couple e2e warnings / flakiness (#14596) 2026-10-30 15:45:46 -07:00
Trenton H 2925b8de81 Chore: Skip repeating Django system checks in the Docker consumer, scheduler and worker (#14598)
The init-system-checks step already runs them once and all three services
depend on init-complete. Measured idle anon PSS saved on
Python 3.14: consumer 14 MiB, beat 26 MiB, worker 27 MiB.
2026-10-30 22:37:37 +00:00
GitHub Actions 5e397e1222 Auto translate strings 2026-10-30 22:26:54 +00:00
Trenton H 6f99ad9469 Chore: Improve idle memory via more lazy imports (#14599)
* Chore: Import dateparser lazily so processes that never parse dates skip it

* Chore: Import turbohtml lazily in the mail parser

* Chore: Import lxml lazily in the SVG validator

* Chore: Import paperless_ai.indexing lazily in document tasks

* Chore: Import paperless_ai helpers lazily in views

* Chore: Read the OCRmyPDF sRGB profile on first use instead of at import

* Chore: Import pikepdf and img2pdf lazily so startup does not load them

* Chore: Reuse the initialized Django ASGI application for HTTP routing
2026-10-30 22:25:42 +00:00
shamoon a5d3247ca7 Tweakhancement: make new pdf controls mostly hidden (#14595) 2026-10-30 10:22:50 -07:00
GitHub Actions 8a67481a9d Auto translate strings 2026-10-30 16:59:59 +00:00
shamoon 652f964f5d Tweak: move preview button in doc list (#14594) 2026-10-30 09:58:29 -07:00
shamoon 80a1827fa0 Fix: checksum light mode display and cf dropdown mobile position (#14590) 2026-10-30 07:03:08 -07:00
153 changed files with 4063 additions and 4198 deletions

No files matched your search

@@ -39,6 +39,7 @@ declare -a scope=(
"${site_packages}/allauth" "${site_packages}/allauth"
"${site_packages}/drf_spectacular" "${site_packages}/drf_spectacular"
"${site_packages}/drf_spectacular_sidecar" "${site_packages}/drf_spectacular_sidecar"
"${site_packages}/treenode"
"${site_packages}/compression_middleware" "${site_packages}/compression_middleware"
) )
@@ -10,9 +10,11 @@ if [[ -n "${PAPERLESS_CONSUMER_DISABLE}" ]]; then
else else
cd ${PAPERLESS_SRC_DIR} cd ${PAPERLESS_SRC_DIR}
# Django system checks already ran once in init-system-checks, skip repeating them
if [[ -n "${USER_IS_NON_ROOT}" ]]; then if [[ -n "${USER_IS_NON_ROOT}" ]]; then
exec python3 manage.py document_consumer exec python3 manage.py document_consumer --skip-checks
else else
exec s6-setuidgid paperless python3 manage.py document_consumer exec s6-setuidgid paperless python3 manage.py document_consumer --skip-checks
fi fi
fi fi
@@ -3,8 +3,9 @@
cd ${PAPERLESS_SRC_DIR} cd ${PAPERLESS_SRC_DIR}
# Django system checks already ran once in init-system-checks, skip repeating them
if [[ -n "${USER_IS_NON_ROOT}" ]]; then if [[ -n "${USER_IS_NON_ROOT}" ]]; then
exec /usr/local/bin/celery --app paperless beat --loglevel INFO exec /usr/local/bin/celery --skip-checks --app paperless beat --loglevel INFO
else else
exec s6-setuidgid paperless /usr/local/bin/celery --app paperless beat --loglevel INFO exec s6-setuidgid paperless /usr/local/bin/celery --skip-checks --app paperless beat --loglevel INFO
fi fi
@@ -3,8 +3,9 @@
cd ${PAPERLESS_SRC_DIR} cd ${PAPERLESS_SRC_DIR}
# Django system checks already ran once in init-system-checks, skip repeating them
if [[ -n "${USER_IS_NON_ROOT}" ]]; then if [[ -n "${USER_IS_NON_ROOT}" ]]; then
exec /usr/local/bin/celery --app paperless worker --loglevel INFO --without-mingle --without-gossip exec /usr/local/bin/celery --skip-checks --app paperless worker --loglevel INFO --without-mingle --without-gossip
else else
exec s6-setuidgid paperless /usr/local/bin/celery --app paperless worker --loglevel INFO --without-mingle --without-gossip exec s6-setuidgid paperless /usr/local/bin/celery --skip-checks --app paperless worker --loglevel INFO --without-mingle --without-gossip
fi fi
+2 -1
View File
@@ -1,6 +1,6 @@
[project] [project]
name = "paperless-ngx" name = "paperless-ngx"
version = "3.4.0" version = "3.4.1"
description = """\ description = """\
A community-supported supercharged document management system: scan, index and archive all your physical documents\ A community-supported supercharged document management system: scan, index and archive all your physical documents\
""" """
@@ -38,6 +38,7 @@ dependencies = [
"django-multiselectfield~=1.0.1", "django-multiselectfield~=1.0.1",
"django-rich~=2.2.0", "django-rich~=2.2.0",
"django-soft-delete~=1.0.18", "django-soft-delete~=1.0.18",
"django-treenode>=0.24",
"djangorestframework~=3.16", "djangorestframework~=3.16",
"drf-spectacular~=0.30", "drf-spectacular~=0.30",
"drf-spectacular-sidecar>=2026.7.1,<2026.10", "drf-spectacular-sidecar>=2026.7.1,<2026.10",
+9 -1
View File
@@ -43,6 +43,7 @@ def configure_environment(instance_root: Path) -> None:
def seed_database() -> None: def seed_database() -> None:
from django.contrib.auth.models import Permission
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.core.management import call_command from django.core.management import call_command
from django.utils import timezone from django.utils import timezone
@@ -63,11 +64,18 @@ def seed_database() -> None:
username="playwright", username="playwright",
password="playwright", # NOSONAR password="playwright", # NOSONAR
) )
User.objects.create_user( viewer = User.objects.create_user(
username="viewer", username="viewer",
password="viewer", # NOSONAR password="viewer", # NOSONAR
) )
viewer.user_permissions.add(
Permission.objects.get(
content_type__app_label="documents",
codename="view_uisettings",
),
)
inbox = Tag.objects.create(name="Inbox", is_inbox_tag=True, owner=admin) inbox = Tag.objects.create(name="Inbox", is_inbox_tag=True, owner=admin)
quick_filter = Tag.objects.create(name="Another Sample Tag", owner=admin) quick_filter = Tag.objects.create(name="Another Sample Tag", owner=admin)
Tag.objects.create(name="TagWithPartial", owner=admin) Tag.objects.create(name="TagWithPartial", owner=admin)
@@ -80,12 +80,21 @@ test('should show a list of notes', async ({ page }) => {
test('should support quick filters', async ({ page }) => { test('should support quick filters', async ({ page }) => {
await page.goto('/documents/1/details') await page.goto('/documents/1/details')
// filter button is available before tags have loaded
const selectedTags = page.locator('pngx-input-tags .ng-value pngx-tag')
await expect(selectedTags).toHaveCount(2)
await expect(
selectedTags.getByText('Another Sample Tag', { exact: true })
).toBeVisible()
await expect(selectedTags.getByText('Inbox', { exact: true })).toBeVisible()
await page await page
.getByRole('button', { name: 'Filter documents with these Tags' }) .getByRole('button', { name: 'Filter documents with these Tags' })
.click() .click()
await expect(page).toHaveURL( await expect(page).toHaveURL((url) => {
/tags__id__all=2,1&sort=created&reverse=1&page=1/ const tags = url.searchParams.get('tags__id__all')?.split(',').sort()
) return url.pathname === '/documents' && tags?.join(',') === '1,2'
})
await expect(page.locator('pngx-document-list')).toHaveText(/one document/i)
}) })
test('should finish reloading the preview after a remote document update', async ({ test('should finish reloading the preview after a remote document update', async ({
@@ -6,8 +6,15 @@ test.use({
}, },
}) })
test('should not allow user to edit settings', async ({ page }) => { test.beforeEach(async ({ page }) => {
const settingsLoaded = page.waitForResponse((response) =>
response.url().endsWith('/api/ui_settings/')
)
await page.goto('/dashboard') await page.goto('/dashboard')
expect((await settingsLoaded).status()).toBe(200)
})
test('should not allow user to edit settings', async ({ page }) => {
await expect(page.getByRole('link', { name: 'Settings' })).not.toBeAttached() await expect(page.getByRole('link', { name: 'Settings' })).not.toBeAttached()
await page.goto('/settings') await page.goto('/settings')
await expect(page.locator('body')).toHaveText( await expect(page.locator('body')).toHaveText(
@@ -16,7 +23,6 @@ test('should not allow user to edit settings', async ({ page }) => {
}) })
test('should not allow user to view documents', async ({ page }) => { test('should not allow user to view documents', async ({ page }) => {
await page.goto('/dashboard')
await expect( await expect(
page.locator('nav').getByRole('link', { name: 'Documents' }) page.locator('nav').getByRole('link', { name: 'Documents' })
).not.toBeAttached() ).not.toBeAttached()
@@ -31,7 +37,6 @@ test('should not allow user to view documents', async ({ page }) => {
}) })
test('should not allow user to view correspondents', async ({ page }) => { test('should not allow user to view correspondents', async ({ page }) => {
await page.goto('/dashboard')
await expect( await expect(
page.getByRole('link', { name: 'Attributes' }) page.getByRole('link', { name: 'Attributes' })
).not.toBeAttached() ).not.toBeAttached()
@@ -42,7 +47,6 @@ test('should not allow user to view correspondents', async ({ page }) => {
}) })
test('should not allow user to view tags', async ({ page }) => { test('should not allow user to view tags', async ({ page }) => {
await page.goto('/dashboard')
await expect( await expect(
page.getByRole('link', { name: 'Attributes' }) page.getByRole('link', { name: 'Attributes' })
).not.toBeAttached() ).not.toBeAttached()
@@ -53,7 +57,6 @@ test('should not allow user to view tags', async ({ page }) => {
}) })
test('should not allow user to view document types', async ({ page }) => { test('should not allow user to view document types', async ({ page }) => {
await page.goto('/dashboard')
await expect( await expect(
page.getByRole('link', { name: 'Attributes' }) page.getByRole('link', { name: 'Attributes' })
).not.toBeAttached() ).not.toBeAttached()
@@ -64,7 +67,6 @@ test('should not allow user to view document types', async ({ page }) => {
}) })
test('should not allow user to view storage paths', async ({ page }) => { test('should not allow user to view storage paths', async ({ page }) => {
await page.goto('/dashboard')
await expect( await expect(
page.getByRole('link', { name: 'Attributes' }) page.getByRole('link', { name: 'Attributes' })
).not.toBeAttached() ).not.toBeAttached()
@@ -75,7 +77,6 @@ test('should not allow user to view storage paths', async ({ page }) => {
}) })
test('should not allow user to view logs', async ({ page }) => { test('should not allow user to view logs', async ({ page }) => {
await page.goto('/dashboard')
await expect(page.getByRole('link', { name: 'Logs' })).not.toBeAttached() await expect(page.getByRole('link', { name: 'Logs' })).not.toBeAttached()
await page.goto('/logs') await page.goto('/logs')
await expect(page.locator('body')).toHaveText( await expect(page.locator('body')).toHaveText(
@@ -84,7 +85,6 @@ test('should not allow user to view logs', async ({ page }) => {
}) })
test('should not allow user to view tasks', async ({ page }) => { test('should not allow user to view tasks', async ({ page }) => {
await page.goto('/dashboard')
await expect(page.getByRole('link', { name: 'Tasks' })).not.toBeAttached() await expect(page.getByRole('link', { name: 'Tasks' })).not.toBeAttached()
await page.goto('/tasks') await page.goto('/tasks')
await expect(page.locator('body')).toHaveText( await expect(page.locator('body')).toHaveText(
+5 -5
View File
@@ -10334,18 +10334,18 @@
<context context-type="linenumber">294,295</context> <context context-type="linenumber">294,295</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html"> <trans-unit id="3420321797707163677" datatype="html">
<source>Edit document</source> <source>Preview document</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context> <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">328</context> <context context-type="linenumber">328</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="3420321797707163677" datatype="html"> <trans-unit id="2179847500064178686" datatype="html">
<source>Preview document</source> <source>Edit document</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context> <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">329</context> <context context-type="linenumber">331</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="4512084577073831437" datatype="html"> <trans-unit id="4512084577073831437" datatype="html">
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "paperless-ngx-ui", "name": "paperless-ngx-ui",
"version": "3.4.0", "version": "3.4.1",
"scripts": { "scripts": {
"preinstall": "npx only-allow pnpm", "preinstall": "npx only-allow pnpm",
"ng": "ng", "ng": "ng",
@@ -1,10 +1,3 @@
.custom-fields-dropdown { .custom-fields-dropdown {
min-width: 300px; min-width: 300px;
// correct position on mobile
@media (max-width: 575.98px) {
&.show {
margin-left: -245px !important;
}
}
} }
@@ -308,7 +308,7 @@
</tr> </tr>
<tr class="align-middle"> <tr class="align-middle">
<td i18n>Original SHA256 checksum</td> <td i18n>Original SHA256 checksum</td>
<td><span class="badge bg-light font-monospace text-wrap text-break text-start">{{metadata()?.original_checksum}}</span></td> <td><span class="badge bg-light text-dark font-monospace text-wrap text-break text-start">{{metadata()?.original_checksum}}</span></td>
</tr> </tr>
<tr> <tr>
<td i18n>Original file size</td> <td i18n>Original file size</td>
@@ -465,7 +465,7 @@
@switch (archiveContentRenderType) { @switch (archiveContentRenderType) {
@case (ContentRenderType.PDF) { @case (ContentRenderType.PDF) {
@if (!useNativePdfViewer) { @if (!useNativePdfViewer) {
<div class="preview-sticky pdf-viewer-container"> <div class="preview-sticky pdf-viewer-container" tabindex="-1">
<pngx-pdf-viewer <pngx-pdf-viewer
[src]="pdfSource()" [src]="pdfSource()"
[sourceRevision]="previewRevision()" [sourceRevision]="previewRevision()"
@@ -477,7 +477,7 @@
(loadError)="onError($event)" (loadError)="onError($event)"
(afterLoadComplete)="pdfPreviewLoaded($event)"> (afterLoadComplete)="pdfPreviewLoaded($event)">
</pngx-pdf-viewer> </pngx-pdf-viewer>
<div class="position-absolute bottom-0 start-50 translate-middle-x z-1 mb-3 d-flex gap-2 p-1 bg-body border rounded shadow"> <div class="preview-controls position-absolute bottom-0 start-50 translate-middle-x z-1 mb-3 d-flex gap-2 p-1 bg-body border rounded shadow">
@if (previewNumPages()) { @if (previewNumPages()) {
<div class="input-group input-group-sm w-auto flex-nowrap"> <div class="input-group input-group-sm w-auto flex-nowrap">
<input class="form-control flex-grow-0 w-auto" type="number" min="1" [max]="previewNumPages()" [ngModelOptions]="{standalone: true}" [ngModel]="previewCurrentPage()" (ngModelChange)="previewCurrentPage.set($event)" aria-label="Page" i18n-aria-label /> <input class="form-control flex-grow-0 w-auto" type="number" min="1" [max]="previewNumPages()" [ngModelOptions]="{standalone: true}" [ngModel]="previewCurrentPage()" (ngModelChange)="previewCurrentPage.set($event)" aria-label="Page" i18n-aria-label />
@@ -12,6 +12,22 @@
width: 100%; width: 100%;
height: 100%; height: 100%;
} }
&:focus {
outline: none;
}
.preview-controls {
opacity: 0;
pointer-events: none;
transition: opacity 0.15s ease-in-out;
}
&:hover .preview-controls,
&:focus-within .preview-controls {
opacity: 1;
pointer-events: auto;
}
} }
.btn-group .dropdown-toggle-split { .btn-group .dropdown-toggle-split {
@@ -72,7 +72,7 @@
<a class="btn btn-sm btn-outline-secondary" (click)="clickMoreLike.emit()"> <a class="btn btn-sm btn-outline-secondary" (click)="clickMoreLike.emit()">
<i-bs name="diagram-3" class="me-1"></i-bs><span class="d-none d-md-inline" i18n>More like this</span> <i-bs name="diagram-3" class="me-1"></i-bs><span class="d-none d-md-inline" i18n>More like this</span>
</a> </a>
<a routerLink="/documents/{{document().id}}" class="btn btn-sm btn-outline-secondary" *pngxIfPermissions="{ action: PermissionAction.Change, type: PermissionType.Document }"> <a routerLink="/documents/{{document().id}}" class="btn btn-sm btn-outline-secondary">
<i-bs name="file-earmark-richtext" class="me-1"></i-bs><span class="d-none d-md-inline" i18n>Open</span> <i-bs name="file-earmark-richtext" class="me-1"></i-bs><span class="d-none d-md-inline" i18n>Open</span>
</a> </a>
<pngx-preview-popup [document]="document()" #popupPreview> <pngx-preview-popup [document]="document()" #popupPreview>
@@ -10,7 +10,6 @@ import {
NgbTooltipModule, NgbTooltipModule,
} from '@ng-bootstrap/ng-bootstrap' } from '@ng-bootstrap/ng-bootstrap'
import { NgxBootstrapIconsModule, allIcons } from 'ngx-bootstrap-icons' import { NgxBootstrapIconsModule, allIcons } from 'ngx-bootstrap-icons'
import { IfPermissionsDirective } from 'src/app/directives/if-permissions.directive'
import { CustomDatePipe } from 'src/app/pipes/custom-date.pipe' import { CustomDatePipe } from 'src/app/pipes/custom-date.pipe'
import { DocumentTitlePipe } from 'src/app/pipes/document-title.pipe' import { DocumentTitlePipe } from 'src/app/pipes/document-title.pipe'
import { IsNumberPipe } from 'src/app/pipes/is-number.pipe' import { IsNumberPipe } from 'src/app/pipes/is-number.pipe'
@@ -52,7 +51,6 @@ describe('DocumentCardLargeComponent', () => {
DocumentCardLargeComponent, DocumentCardLargeComponent,
DocumentTitlePipe, DocumentTitlePipe,
CustomDatePipe, CustomDatePipe,
IfPermissionsDirective,
SafeUrlPipe, SafeUrlPipe,
IsNumberPipe, IsNumberPipe,
PreviewPopupComponent, PreviewPopupComponent,
@@ -20,7 +20,6 @@ import {
Document, Document,
} from 'src/app/data/document' } from 'src/app/data/document'
import { SETTINGS_KEYS } from 'src/app/data/ui-settings' import { SETTINGS_KEYS } from 'src/app/data/ui-settings'
import { IfPermissionsDirective } from 'src/app/directives/if-permissions.directive'
import { CorrespondentNamePipe } from 'src/app/pipes/correspondent-name.pipe' import { CorrespondentNamePipe } from 'src/app/pipes/correspondent-name.pipe'
import { CustomDatePipe } from 'src/app/pipes/custom-date.pipe' import { CustomDatePipe } from 'src/app/pipes/custom-date.pipe'
import { DocumentTitlePipe } from 'src/app/pipes/document-title.pipe' import { DocumentTitlePipe } from 'src/app/pipes/document-title.pipe'
@@ -51,7 +50,6 @@ import { LoadingComponentWithPermissions } from '../../loading-component/loading
CorrespondentNamePipe, CorrespondentNamePipe,
DocumentTypeNamePipe, DocumentTypeNamePipe,
StoragePathNamePipe, StoragePathNamePipe,
IfPermissionsDirective,
CustomDatePipe, CustomDatePipe,
RouterModule, RouterModule,
NgbTooltipModule, NgbTooltipModule,
@@ -144,7 +144,7 @@
<div class="d-flex justify-content-between align-items-center"> <div class="d-flex justify-content-between align-items-center">
<div class="btn-group w-100"> <div class="btn-group w-100">
@if (document()) { @if (document()) {
<a routerLink="/documents/{{document().id}}" class="btn btn-sm btn-outline-secondary" title="Open" i18n-title *pngxIfPermissions="{ action: PermissionAction.Change, type: PermissionType.Document }" i18n-title> <a routerLink="/documents/{{document().id}}" class="btn btn-sm btn-outline-secondary" title="Open" i18n-title>
<i-bs name="file-earmark-richtext"></i-bs> <i-bs name="file-earmark-richtext"></i-bs>
</a> </a>
<pngx-preview-popup [document]="document()" #popupPreview> <pngx-preview-popup [document]="document()" #popupPreview>
@@ -20,7 +20,6 @@ import {
Document, Document,
} from 'src/app/data/document' } from 'src/app/data/document'
import { SETTINGS_KEYS } from 'src/app/data/ui-settings' import { SETTINGS_KEYS } from 'src/app/data/ui-settings'
import { IfPermissionsDirective } from 'src/app/directives/if-permissions.directive'
import { CorrespondentNamePipe } from 'src/app/pipes/correspondent-name.pipe' import { CorrespondentNamePipe } from 'src/app/pipes/correspondent-name.pipe'
import { CustomDatePipe } from 'src/app/pipes/custom-date.pipe' import { CustomDatePipe } from 'src/app/pipes/custom-date.pipe'
import { DocumentTitlePipe } from 'src/app/pipes/document-title.pipe' import { DocumentTitlePipe } from 'src/app/pipes/document-title.pipe'
@@ -51,7 +50,6 @@ import { LoadingComponentWithPermissions } from '../../loading-component/loading
CorrespondentNamePipe, CorrespondentNamePipe,
DocumentTypeNamePipe, DocumentTypeNamePipe,
StoragePathNamePipe, StoragePathNamePipe,
IfPermissionsDirective,
CustomDatePipe, CustomDatePipe,
RouterModule, RouterModule,
NgbTooltipModule, NgbTooltipModule,
@@ -208,7 +208,7 @@
i18n>Correspondent</th> i18n>Correspondent</th>
} }
@if (activeDisplayFields.includes(DisplayField.TITLE)) { @if (activeDisplayFields.includes(DisplayField.TITLE)) {
<th class="cursor-pointer" <th class="cursor-pointer ps-5"
pngxSortable="title" pngxSortable="title"
title="Sort by title" i18n-title title="Sort by title" i18n-title
[currentSortField]="list.sortField" [currentSortField]="list.sortField"
@@ -322,13 +322,13 @@
</td> </td>
} }
@if (activeDisplayFields.includes(DisplayField.TITLE) || activeDisplayFields.includes(DisplayField.TAGS)) { @if (activeDisplayFields.includes(DisplayField.TITLE) || activeDisplayFields.includes(DisplayField.TAGS)) {
<td width="30%"> <td width="30%" class="position-relative" [class.ps-5]="activeDisplayFields.includes(DisplayField.TITLE)">
@if (activeDisplayFields.includes(DisplayField.TITLE)) { @if (activeDisplayFields.includes(DisplayField.TITLE)) {
<div class="d-inline-block" (mouseleave)="popupPreview.close()"> <div class="d-inline-block" (mouseleave)="popupPreview.close()">
<a routerLink="/documents/{{d.id}}" title="Edit document" i18n-title style="overflow-wrap: anywhere;">{{d.title | documentTitle}}</a> <pngx-preview-popup class="position-absolute start-0" [document]="d" linkClasses="btn btn-sm btn-link text-secondary" linkTitle="Preview document" (click)="$event.stopPropagation()" i18n-linkTitle #popupPreview>
<pngx-preview-popup [document]="d" linkClasses="btn btn-sm btn-link text-secondary" linkTitle="Preview document" (click)="$event.stopPropagation()" i18n-linkTitle #popupPreview>
<i-bs name="eye"></i-bs> <i-bs name="eye"></i-bs>
</pngx-preview-popup> </pngx-preview-popup>
<a routerLink="/documents/{{d.id}}" title="Edit document" i18n-title style="overflow-wrap: anywhere;">{{d.title | documentTitle}}</a>
</div> </div>
} }
@if (activeDisplayFields.includes(DisplayField.TAGS)) { @if (activeDisplayFields.includes(DisplayField.TAGS)) {
@@ -87,6 +87,10 @@ $paperless-card-breakpoints: (
} }
} }
.table .ps-5 {
padding-left: 2.2rem !important;
}
a { a {
cursor: pointer; cursor: pointer;
} }
+1 -1
View File
@@ -8,7 +8,7 @@ export const environment = {
apiVersion: '10', // match src/paperless/settings.py apiVersion: '10', // match src/paperless/settings.py
appTitle: DEFAULT_APP_TITLE, appTitle: DEFAULT_APP_TITLE,
tag: 'prod', tag: 'prod',
version: '3.4.0', version: '3.4.1',
webSocketHost: window.location.host, webSocketHost: window.location.host,
webSocketProtocol: window.location.protocol == 'https:' ? 'wss:' : 'ws:', webSocketProtocol: window.location.protocol == 'https:' ? 'wss:' : 'ws:',
webSocketBaseUrl: base_url.pathname + 'ws/', webSocketBaseUrl: base_url.pathname + 'ws/',
+9 -9
View File
@@ -11397,22 +11397,22 @@
</context-group> </context-group>
<target state="needs-translation">Sort by <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target> <target state="needs-translation">Sort by <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">328</context>
</context-group>
<target state="translated">Wysig dokument</target>
</trans-unit>
<trans-unit id="3420321797707163677" datatype="html"> <trans-unit id="3420321797707163677" datatype="html">
<source>Preview document</source> <source>Preview document</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context> <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">329</context> <context context-type="linenumber">328</context>
</context-group> </context-group>
<target state="needs-translation">Preview document</target> <target state="needs-translation">Preview document</target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">331</context>
</context-group>
<target state="translated">Wysig dokument</target>
</trans-unit>
<trans-unit id="4512084577073831437" datatype="html"> <trans-unit id="4512084577073831437" datatype="html">
<source>Reset filters / selection</source> <source>Reset filters / selection</source>
<context-group purpose="location"> <context-group purpose="location">
+9 -9
View File
@@ -11397,22 +11397,22 @@
</context-group> </context-group>
<target state="needs-translation">Sort by <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target> <target state="needs-translation">Sort by <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">328</context>
</context-group>
<target state="needs-translation">Edit document</target>
</trans-unit>
<trans-unit id="3420321797707163677" datatype="html"> <trans-unit id="3420321797707163677" datatype="html">
<source>Preview document</source> <source>Preview document</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context> <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">329</context> <context context-type="linenumber">328</context>
</context-group> </context-group>
<target state="needs-translation">Preview document</target> <target state="needs-translation">Preview document</target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">331</context>
</context-group>
<target state="needs-translation">Edit document</target>
</trans-unit>
<trans-unit id="4512084577073831437" datatype="html"> <trans-unit id="4512084577073831437" datatype="html">
<source>Reset filters / selection</source> <source>Reset filters / selection</source>
<context-group purpose="location"> <context-group purpose="location">
+9 -9
View File
@@ -11397,22 +11397,22 @@
</context-group> </context-group>
<target state="needs-translation">Sort by <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target> <target state="needs-translation">Sort by <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">328</context>
</context-group>
<target state="translated">تعديل المستند</target>
</trans-unit>
<trans-unit id="3420321797707163677" datatype="html"> <trans-unit id="3420321797707163677" datatype="html">
<source>Preview document</source> <source>Preview document</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context> <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">329</context> <context context-type="linenumber">328</context>
</context-group> </context-group>
<target state="needs-translation">Preview document</target> <target state="needs-translation">Preview document</target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">331</context>
</context-group>
<target state="translated">تعديل المستند</target>
</trans-unit>
<trans-unit id="4512084577073831437" datatype="html"> <trans-unit id="4512084577073831437" datatype="html">
<source>Reset filters / selection</source> <source>Reset filters / selection</source>
<context-group purpose="location"> <context-group purpose="location">
+9 -9
View File
@@ -11397,22 +11397,22 @@
</context-group> </context-group>
<target state="needs-translation">Sort by <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target> <target state="needs-translation">Sort by <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">328</context>
</context-group>
<target state="translated">Рэдагаваць дакумент</target>
</trans-unit>
<trans-unit id="3420321797707163677" datatype="html"> <trans-unit id="3420321797707163677" datatype="html">
<source>Preview document</source> <source>Preview document</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context> <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">329</context> <context context-type="linenumber">328</context>
</context-group> </context-group>
<target state="needs-translation">Preview document</target> <target state="needs-translation">Preview document</target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">331</context>
</context-group>
<target state="translated">Рэдагаваць дакумент</target>
</trans-unit>
<trans-unit id="4512084577073831437" datatype="html"> <trans-unit id="4512084577073831437" datatype="html">
<source>Reset filters / selection</source> <source>Reset filters / selection</source>
<context-group purpose="location"> <context-group purpose="location">
+9 -9
View File
@@ -11397,22 +11397,22 @@
</context-group> </context-group>
<target state="translated">Сортирай по: <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target> <target state="translated">Сортирай по: <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">328</context>
</context-group>
<target state="translated">Редактиране на документа</target>
</trans-unit>
<trans-unit id="3420321797707163677" datatype="html"> <trans-unit id="3420321797707163677" datatype="html">
<source>Preview document</source> <source>Preview document</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context> <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">329</context> <context context-type="linenumber">328</context>
</context-group> </context-group>
<target state="translated">Визуализация на документа</target> <target state="translated">Визуализация на документа</target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">331</context>
</context-group>
<target state="translated">Редактиране на документа</target>
</trans-unit>
<trans-unit id="4512084577073831437" datatype="html"> <trans-unit id="4512084577073831437" datatype="html">
<source>Reset filters / selection</source> <source>Reset filters / selection</source>
<context-group purpose="location"> <context-group purpose="location">
+9 -9
View File
@@ -11397,22 +11397,22 @@
</context-group> </context-group>
<target state="translated">Ordena per <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target> <target state="translated">Ordena per <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">328</context>
</context-group>
<target state="translated">Edita document</target>
</trans-unit>
<trans-unit id="3420321797707163677" datatype="html"> <trans-unit id="3420321797707163677" datatype="html">
<source>Preview document</source> <source>Preview document</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context> <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">329</context> <context context-type="linenumber">328</context>
</context-group> </context-group>
<target state="translated">Previsualitza document</target> <target state="translated">Previsualitza document</target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">331</context>
</context-group>
<target state="translated">Edita document</target>
</trans-unit>
<trans-unit id="4512084577073831437" datatype="html"> <trans-unit id="4512084577073831437" datatype="html">
<source>Reset filters / selection</source> <source>Reset filters / selection</source>
<context-group purpose="location"> <context-group purpose="location">
+9 -9
View File
@@ -11396,22 +11396,22 @@
</context-group> </context-group>
<target state="translated">Seřadit podle <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target> <target state="translated">Seřadit podle <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">328</context>
</context-group>
<target state="translated">Upravit dokument</target>
</trans-unit>
<trans-unit id="3420321797707163677" datatype="html"> <trans-unit id="3420321797707163677" datatype="html">
<source>Preview document</source> <source>Preview document</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context> <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">329</context> <context context-type="linenumber">328</context>
</context-group> </context-group>
<target state="translated">Náhled dokumentu</target> <target state="translated">Náhled dokumentu</target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">331</context>
</context-group>
<target state="translated">Upravit dokument</target>
</trans-unit>
<trans-unit id="4512084577073831437" datatype="html"> <trans-unit id="4512084577073831437" datatype="html">
<source>Reset filters / selection</source> <source>Reset filters / selection</source>
<context-group purpose="location"> <context-group purpose="location">
+9 -9
View File
@@ -11397,22 +11397,22 @@
</context-group> </context-group>
<target state="needs-translation">Sort by <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target> <target state="needs-translation">Sort by <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">328</context>
</context-group>
<target state="needs-translation">Edit document</target>
</trans-unit>
<trans-unit id="3420321797707163677" datatype="html"> <trans-unit id="3420321797707163677" datatype="html">
<source>Preview document</source> <source>Preview document</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context> <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">329</context> <context context-type="linenumber">328</context>
</context-group> </context-group>
<target state="needs-translation">Preview document</target> <target state="needs-translation">Preview document</target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">331</context>
</context-group>
<target state="needs-translation">Edit document</target>
</trans-unit>
<trans-unit id="4512084577073831437" datatype="html"> <trans-unit id="4512084577073831437" datatype="html">
<source>Reset filters / selection</source> <source>Reset filters / selection</source>
<context-group purpose="location"> <context-group purpose="location">
+9 -9
View File
@@ -11396,22 +11396,22 @@
</context-group> </context-group>
<target state="translated">Nach <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/> sortieren</target> <target state="translated">Nach <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/> sortieren</target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">328</context>
</context-group>
<target state="translated">Dokument bearbeiten</target>
</trans-unit>
<trans-unit id="3420321797707163677" datatype="html"> <trans-unit id="3420321797707163677" datatype="html">
<source>Preview document</source> <source>Preview document</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context> <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">329</context> <context context-type="linenumber">328</context>
</context-group> </context-group>
<target state="translated">Dokumentenvorschau</target> <target state="translated">Dokumentenvorschau</target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">331</context>
</context-group>
<target state="translated">Dokument bearbeiten</target>
</trans-unit>
<trans-unit id="4512084577073831437" datatype="html"> <trans-unit id="4512084577073831437" datatype="html">
<source>Reset filters / selection</source> <source>Reset filters / selection</source>
<context-group purpose="location"> <context-group purpose="location">
+25 -25
View File
@@ -4795,7 +4795,7 @@
<context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.html</context> <context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.html</context>
<context context-type="linenumber">38</context> <context context-type="linenumber">38</context>
</context-group> </context-group>
<target state="needs-translation">Date mode</target> <target state="translated">Datumsmodus</target>
</trans-unit> </trans-unit>
<trans-unit id="7572800523712857519" datatype="html"> <trans-unit id="7572800523712857519" datatype="html">
<source>Fixed date</source> <source>Fixed date</source>
@@ -4807,7 +4807,7 @@
<context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.html</context> <context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.html</context>
<context context-type="linenumber">40</context> <context context-type="linenumber">40</context>
</context-group> </context-group>
<target state="needs-translation">Fixed date</target> <target state="translated">Festes Datum</target>
</trans-unit> </trans-unit>
<trans-unit id="4108478337308251505" datatype="html"> <trans-unit id="4108478337308251505" datatype="html">
<source>Fixed</source> <source>Fixed</source>
@@ -4815,7 +4815,7 @@
<context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.html</context> <context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.html</context>
<context context-type="linenumber">41,42</context> <context context-type="linenumber">41,42</context>
</context-group> </context-group>
<target state="needs-translation">Fixed</target> <target state="translated">Fixiert</target>
</trans-unit> </trans-unit>
<trans-unit id="8283919074858117329" datatype="html"> <trans-unit id="8283919074858117329" datatype="html">
<source>Relative date</source> <source>Relative date</source>
@@ -4827,7 +4827,7 @@
<context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.html</context> <context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.html</context>
<context context-type="linenumber">44</context> <context context-type="linenumber">44</context>
</context-group> </context-group>
<target state="needs-translation">Relative date</target> <target state="translated">Relatives Datum</target>
</trans-unit> </trans-unit>
<trans-unit id="2731996625798485199" datatype="html"> <trans-unit id="2731996625798485199" datatype="html">
<source>Relative</source> <source>Relative</source>
@@ -4835,7 +4835,7 @@
<context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.html</context> <context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.html</context>
<context context-type="linenumber">45,46</context> <context context-type="linenumber">45,46</context>
</context-group> </context-group>
<target state="needs-translation">Relative</target> <target state="translated">Relativ</target>
</trans-unit> </trans-unit>
<trans-unit id="6533918067030990396" datatype="html"> <trans-unit id="6533918067030990396" datatype="html">
<source>Amount</source> <source>Amount</source>
@@ -4843,7 +4843,7 @@
<context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.html</context> <context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.html</context>
<context context-type="linenumber">51</context> <context context-type="linenumber">51</context>
</context-group> </context-group>
<target state="needs-translation">Amount</target> <target state="translated">Anzahl</target>
</trans-unit> </trans-unit>
<trans-unit id="8932917860978648376" datatype="html"> <trans-unit id="8932917860978648376" datatype="html">
<source>Unit</source> <source>Unit</source>
@@ -4851,7 +4851,7 @@
<context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.html</context> <context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.html</context>
<context context-type="linenumber">56,57</context> <context context-type="linenumber">56,57</context>
</context-group> </context-group>
<target state="needs-translation">Unit</target> <target state="translated">Einheit</target>
</trans-unit> </trans-unit>
<trans-unit id="9138811584797805840" datatype="html"> <trans-unit id="9138811584797805840" datatype="html">
<source>Open date picker</source> <source>Open date picker</source>
@@ -4991,7 +4991,7 @@
<context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.html</context> <context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.html</context>
<context context-type="linenumber">119,120</context> <context context-type="linenumber">119,120</context>
</context-group> </context-group>
<target state="needs-translation">Operator</target> <target state="translated">Operator</target>
</trans-unit> </trans-unit>
<trans-unit id="2328549728463836983" datatype="html"> <trans-unit id="2328549728463836983" datatype="html">
<source>Remove query</source> <source>Remove query</source>
@@ -5051,7 +5051,7 @@
<context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.ts</context> <context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.ts</context>
<context context-type="linenumber">330</context> <context context-type="linenumber">330</context>
</context-group> </context-group>
<target state="needs-translation">days ago</target> <target state="translated">vor Tagen</target>
</trans-unit> </trans-unit>
<trans-unit id="2871318661796659216" datatype="html"> <trans-unit id="2871318661796659216" datatype="html">
<source>weeks ago</source> <source>weeks ago</source>
@@ -5059,7 +5059,7 @@
<context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.ts</context> <context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.ts</context>
<context context-type="linenumber">331</context> <context context-type="linenumber">331</context>
</context-group> </context-group>
<target state="needs-translation">weeks ago</target> <target state="translated">vor Wochen</target>
</trans-unit> </trans-unit>
<trans-unit id="6041340836190906216" datatype="html"> <trans-unit id="6041340836190906216" datatype="html">
<source>months ago</source> <source>months ago</source>
@@ -5067,7 +5067,7 @@
<context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.ts</context> <context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.ts</context>
<context context-type="linenumber">332</context> <context context-type="linenumber">332</context>
</context-group> </context-group>
<target state="needs-translation">months ago</target> <target state="translated">vor Monaten</target>
</trans-unit> </trans-unit>
<trans-unit id="963494111451627204" datatype="html"> <trans-unit id="963494111451627204" datatype="html">
<source>years ago</source> <source>years ago</source>
@@ -5075,7 +5075,7 @@
<context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.ts</context> <context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.ts</context>
<context context-type="linenumber">333</context> <context context-type="linenumber">333</context>
</context-group> </context-group>
<target state="needs-translation">years ago</target> <target state="translated">vor Jahren</target>
</trans-unit> </trans-unit>
<trans-unit id="5555905617885007774" datatype="html"> <trans-unit id="5555905617885007774" datatype="html">
<source>days from now</source> <source>days from now</source>
@@ -5083,7 +5083,7 @@
<context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.ts</context> <context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.ts</context>
<context context-type="linenumber">334</context> <context context-type="linenumber">334</context>
</context-group> </context-group>
<target state="needs-translation">days from now</target> <target state="translated">Tage von heute an</target>
</trans-unit> </trans-unit>
<trans-unit id="4298377021616940216" datatype="html"> <trans-unit id="4298377021616940216" datatype="html">
<source>weeks from now</source> <source>weeks from now</source>
@@ -5091,7 +5091,7 @@
<context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.ts</context> <context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.ts</context>
<context context-type="linenumber">335</context> <context context-type="linenumber">335</context>
</context-group> </context-group>
<target state="needs-translation">weeks from now</target> <target state="translated">Wochen von heute an</target>
</trans-unit> </trans-unit>
<trans-unit id="2772874767134148305" datatype="html"> <trans-unit id="2772874767134148305" datatype="html">
<source>months from now</source> <source>months from now</source>
@@ -5099,7 +5099,7 @@
<context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.ts</context> <context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.ts</context>
<context context-type="linenumber">336</context> <context context-type="linenumber">336</context>
</context-group> </context-group>
<target state="needs-translation">months from now</target> <target state="translated">Monate von heute an</target>
</trans-unit> </trans-unit>
<trans-unit id="6363533917780225967" datatype="html"> <trans-unit id="6363533917780225967" datatype="html">
<source>years from now</source> <source>years from now</source>
@@ -5107,7 +5107,7 @@
<context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.ts</context> <context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.ts</context>
<context context-type="linenumber">337</context> <context context-type="linenumber">337</context>
</context-group> </context-group>
<target state="needs-translation">years from now</target> <target state="translated">Jahr von heute an</target>
</trans-unit> </trans-unit>
<trans-unit id="6630533861307510614" datatype="html"> <trans-unit id="6630533861307510614" datatype="html">
<source>Clear created relative date</source> <source>Clear created relative date</source>
@@ -11396,22 +11396,22 @@
</context-group> </context-group>
<target state="final">Nach <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/> sortieren</target> <target state="final">Nach <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/> sortieren</target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html" approved="yes">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">328</context>
</context-group>
<target state="final">Dokument bearbeiten</target>
</trans-unit>
<trans-unit id="3420321797707163677" datatype="html" approved="yes"> <trans-unit id="3420321797707163677" datatype="html" approved="yes">
<source>Preview document</source> <source>Preview document</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context> <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">329</context> <context context-type="linenumber">328</context>
</context-group> </context-group>
<target state="final">Dokumentenvorschau</target> <target state="final">Dokumentenvorschau</target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html" approved="yes">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">331</context>
</context-group>
<target state="final">Dokument bearbeiten</target>
</trans-unit>
<trans-unit id="4512084577073831437" datatype="html" approved="yes"> <trans-unit id="4512084577073831437" datatype="html" approved="yes">
<source>Reset filters / selection</source> <source>Reset filters / selection</source>
<context-group purpose="location"> <context-group purpose="location">
+9 -9
View File
@@ -11397,22 +11397,22 @@
</context-group> </context-group>
<target state="needs-translation">Sort by <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target> <target state="needs-translation">Sort by <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">328</context>
</context-group>
<target state="translated">Επεξεργασία εγγράφου</target>
</trans-unit>
<trans-unit id="3420321797707163677" datatype="html"> <trans-unit id="3420321797707163677" datatype="html">
<source>Preview document</source> <source>Preview document</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context> <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">329</context> <context context-type="linenumber">328</context>
</context-group> </context-group>
<target state="needs-translation">Preview document</target> <target state="needs-translation">Preview document</target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">331</context>
</context-group>
<target state="translated">Επεξεργασία εγγράφου</target>
</trans-unit>
<trans-unit id="4512084577073831437" datatype="html"> <trans-unit id="4512084577073831437" datatype="html">
<source>Reset filters / selection</source> <source>Reset filters / selection</source>
<context-group purpose="location"> <context-group purpose="location">
+9 -9
View File
@@ -11397,22 +11397,22 @@
</context-group> </context-group>
<target state="translated">Ordenar por <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target> <target state="translated">Ordenar por <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">328</context>
</context-group>
<target state="translated">Editar documento</target>
</trans-unit>
<trans-unit id="3420321797707163677" datatype="html"> <trans-unit id="3420321797707163677" datatype="html">
<source>Preview document</source> <source>Preview document</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context> <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">329</context> <context context-type="linenumber">328</context>
</context-group> </context-group>
<target state="translated">Previsualizar documento</target> <target state="translated">Previsualizar documento</target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">331</context>
</context-group>
<target state="translated">Editar documento</target>
</trans-unit>
<trans-unit id="4512084577073831437" datatype="html"> <trans-unit id="4512084577073831437" datatype="html">
<source>Reset filters / selection</source> <source>Reset filters / selection</source>
<context-group purpose="location"> <context-group purpose="location">
+9 -9
View File
@@ -11397,22 +11397,22 @@
</context-group> </context-group>
<target state="needs-translation">Sort by <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target> <target state="needs-translation">Sort by <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">328</context>
</context-group>
<target state="needs-translation">Edit document</target>
</trans-unit>
<trans-unit id="3420321797707163677" datatype="html"> <trans-unit id="3420321797707163677" datatype="html">
<source>Preview document</source> <source>Preview document</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context> <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">329</context> <context context-type="linenumber">328</context>
</context-group> </context-group>
<target state="needs-translation">Preview document</target> <target state="needs-translation">Preview document</target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">331</context>
</context-group>
<target state="needs-translation">Edit document</target>
</trans-unit>
<trans-unit id="4512084577073831437" datatype="html"> <trans-unit id="4512084577073831437" datatype="html">
<source>Reset filters / selection</source> <source>Reset filters / selection</source>
<context-group purpose="location"> <context-group purpose="location">
+9 -9
View File
@@ -11397,22 +11397,22 @@
</context-group> </context-group>
<target state="needs-translation">Sort by <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target> <target state="needs-translation">Sort by <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">328</context>
</context-group>
<target state="translated">سند ویرایش</target>
</trans-unit>
<trans-unit id="3420321797707163677" datatype="html"> <trans-unit id="3420321797707163677" datatype="html">
<source>Preview document</source> <source>Preview document</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context> <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">329</context> <context context-type="linenumber">328</context>
</context-group> </context-group>
<target state="translated">سند پیش نمایش</target> <target state="translated">سند پیش نمایش</target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">331</context>
</context-group>
<target state="translated">سند ویرایش</target>
</trans-unit>
<trans-unit id="4512084577073831437" datatype="html"> <trans-unit id="4512084577073831437" datatype="html">
<source>Reset filters / selection</source> <source>Reset filters / selection</source>
<context-group purpose="location"> <context-group purpose="location">
+9 -9
View File
@@ -11397,22 +11397,22 @@
</context-group> </context-group>
<target state="needs-translation">Sort by <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target> <target state="needs-translation">Sort by <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">328</context>
</context-group>
<target state="translated">Muokkaa asiakirjaa</target>
</trans-unit>
<trans-unit id="3420321797707163677" datatype="html"> <trans-unit id="3420321797707163677" datatype="html">
<source>Preview document</source> <source>Preview document</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context> <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">329</context> <context context-type="linenumber">328</context>
</context-group> </context-group>
<target state="translated">Esikatsele asiakirja</target> <target state="translated">Esikatsele asiakirja</target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">331</context>
</context-group>
<target state="translated">Muokkaa asiakirjaa</target>
</trans-unit>
<trans-unit id="4512084577073831437" datatype="html"> <trans-unit id="4512084577073831437" datatype="html">
<source>Reset filters / selection</source> <source>Reset filters / selection</source>
<context-group purpose="location"> <context-group purpose="location">
+13 -13
View File
@@ -3719,7 +3719,7 @@
<context context-type="sourcefile">src/app/components/admin/users-groups/users-groups.component.ts</context> <context context-type="sourcefile">src/app/components/admin/users-groups/users-groups.component.ts</context>
<context context-type="linenumber">163</context> <context context-type="linenumber">163</context>
</context-group> </context-group>
<target state="translated">Erreur lors de la supression de l’utilisateur « <x id="PH" equiv-text="user.username"/> ».</target> <target state="translated">Erreur lors de la suppression de l’utilisateur « <x id="PH" equiv-text="user.username"/> ».</target>
</trans-unit> </trans-unit>
<trans-unit id="5766640174051730159" datatype="html" approved="yes"> <trans-unit id="5766640174051730159" datatype="html" approved="yes">
<source>Saved group &quot;<x id="PH" equiv-text="newGroup.name"/>&quot;.</source> <source>Saved group &quot;<x id="PH" equiv-text="newGroup.name"/>&quot;.</source>
@@ -3767,7 +3767,7 @@
<context context-type="sourcefile">src/app/components/admin/users-groups/users-groups.component.ts</context> <context context-type="sourcefile">src/app/components/admin/users-groups/users-groups.component.ts</context>
<context context-type="linenumber">220</context> <context context-type="linenumber">220</context>
</context-group> </context-group>
<target state="translated">Erreur lors de la supression du groupe « <x id="PH" equiv-text="group.name"/> ».</target> <target state="translated">Erreur lors de la suppression du groupe « <x id="PH" equiv-text="group.name"/> ».</target>
</trans-unit> </trans-unit>
<trans-unit id="7931334600001636863" datatype="html" approved="yes"> <trans-unit id="7931334600001636863" datatype="html" approved="yes">
<source>by Paperless-ngx</source> <source>by Paperless-ngx</source>
@@ -6935,7 +6935,7 @@
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context> <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
<context context-type="linenumber">410</context> <context context-type="linenumber">410</context>
</context-group> </context-group>
<target state="translated">Destinatires du courriel</target> <target state="translated">Destinataires du courriel</target>
</trans-unit> </trans-unit>
<trans-unit id="7916910101279824329" datatype="html"> <trans-unit id="7916910101279824329" datatype="html">
<source>Attach document</source> <source>Attach document</source>
@@ -10930,7 +10930,7 @@
<context context-type="sourcefile">src/app/components/document-list/document-card-small/document-card-small.component.html</context> <context context-type="sourcefile">src/app/components/document-list/document-card-small/document-card-small.component.html</context>
<context context-type="linenumber">8,9</context> <context context-type="linenumber">8,9</context>
</context-group> </context-group>
<target state="translated"><x id="INTERPOLATION" equiv-text="{{ document().title | documentTitle }}"/> mignature</target> <target state="translated"><x id="INTERPOLATION" equiv-text="{{ document().title | documentTitle }}"/> miniature</target>
</trans-unit> </trans-unit>
<trans-unit id="2784168796433474565" datatype="html" approved="yes"> <trans-unit id="2784168796433474565" datatype="html" approved="yes">
<source>Filter by tag</source> <source>Filter by tag</source>
@@ -11396,22 +11396,22 @@
</context-group> </context-group>
<target state="translated">Trier par <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target> <target state="translated">Trier par <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html" approved="yes">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">328</context>
</context-group>
<target state="final">Modifier le document</target>
</trans-unit>
<trans-unit id="3420321797707163677" datatype="html"> <trans-unit id="3420321797707163677" datatype="html">
<source>Preview document</source> <source>Preview document</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context> <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">329</context> <context context-type="linenumber">328</context>
</context-group> </context-group>
<target state="translated">Prévisualiser le document</target> <target state="translated">Prévisualiser le document</target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html" approved="yes">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">331</context>
</context-group>
<target state="final">Modifier le document</target>
</trans-unit>
<trans-unit id="4512084577073831437" datatype="html"> <trans-unit id="4512084577073831437" datatype="html">
<source>Reset filters / selection</source> <source>Reset filters / selection</source>
<context-group purpose="location"> <context-group purpose="location">
+9 -9
View File
@@ -11396,22 +11396,22 @@
</context-group> </context-group>
<target state="translated">מיון לפי <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target> <target state="translated">מיון לפי <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">328</context>
</context-group>
<target state="translated">עריכת מסמך</target>
</trans-unit>
<trans-unit id="3420321797707163677" datatype="html"> <trans-unit id="3420321797707163677" datatype="html">
<source>Preview document</source> <source>Preview document</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context> <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">329</context> <context context-type="linenumber">328</context>
</context-group> </context-group>
<target state="translated">תצוגה מקדימה של המסמך</target> <target state="translated">תצוגה מקדימה של המסמך</target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">331</context>
</context-group>
<target state="translated">עריכת מסמך</target>
</trans-unit>
<trans-unit id="4512084577073831437" datatype="html"> <trans-unit id="4512084577073831437" datatype="html">
<source>Reset filters / selection</source> <source>Reset filters / selection</source>
<context-group purpose="location"> <context-group purpose="location">
+9 -9
View File
@@ -11397,22 +11397,22 @@
</context-group> </context-group>
<target state="needs-translation">Sort by <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target> <target state="needs-translation">Sort by <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">328</context>
</context-group>
<target state="needs-translation">Edit document</target>
</trans-unit>
<trans-unit id="3420321797707163677" datatype="html"> <trans-unit id="3420321797707163677" datatype="html">
<source>Preview document</source> <source>Preview document</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context> <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">329</context> <context context-type="linenumber">328</context>
</context-group> </context-group>
<target state="needs-translation">Preview document</target> <target state="needs-translation">Preview document</target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">331</context>
</context-group>
<target state="needs-translation">Edit document</target>
</trans-unit>
<trans-unit id="4512084577073831437" datatype="html"> <trans-unit id="4512084577073831437" datatype="html">
<source>Reset filters / selection</source> <source>Reset filters / selection</source>
<context-group purpose="location"> <context-group purpose="location">
+9 -9
View File
@@ -11397,22 +11397,22 @@
</context-group> </context-group>
<target state="translated">Sortiraj po <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target> <target state="translated">Sortiraj po <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">328</context>
</context-group>
<target state="translated">Uredi dokument</target>
</trans-unit>
<trans-unit id="3420321797707163677" datatype="html"> <trans-unit id="3420321797707163677" datatype="html">
<source>Preview document</source> <source>Preview document</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context> <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">329</context> <context context-type="linenumber">328</context>
</context-group> </context-group>
<target state="translated">Pregledaj dokument</target> <target state="translated">Pregledaj dokument</target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">331</context>
</context-group>
<target state="translated">Uredi dokument</target>
</trans-unit>
<trans-unit id="4512084577073831437" datatype="html"> <trans-unit id="4512084577073831437" datatype="html">
<source>Reset filters / selection</source> <source>Reset filters / selection</source>
<context-group purpose="location"> <context-group purpose="location">
+9 -9
View File
@@ -11397,22 +11397,22 @@
</context-group> </context-group>
<target state="translated">Rendezés <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/> szerint</target> <target state="translated">Rendezés <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/> szerint</target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">328</context>
</context-group>
<target state="translated">Dokumentum szerkesztése</target>
</trans-unit>
<trans-unit id="3420321797707163677" datatype="html"> <trans-unit id="3420321797707163677" datatype="html">
<source>Preview document</source> <source>Preview document</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context> <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">329</context> <context context-type="linenumber">328</context>
</context-group> </context-group>
<target state="translated">Dokumentum előnézete</target> <target state="translated">Dokumentum előnézete</target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">331</context>
</context-group>
<target state="translated">Dokumentum szerkesztése</target>
</trans-unit>
<trans-unit id="4512084577073831437" datatype="html"> <trans-unit id="4512084577073831437" datatype="html">
<source>Reset filters / selection</source> <source>Reset filters / selection</source>
<context-group purpose="location"> <context-group purpose="location">
+9 -9
View File
@@ -11396,22 +11396,22 @@
</context-group> </context-group>
<target state="translated">Urutkan berdasarkan <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target> <target state="translated">Urutkan berdasarkan <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">328</context>
</context-group>
<target state="translated">Edit dokumen</target>
</trans-unit>
<trans-unit id="3420321797707163677" datatype="html"> <trans-unit id="3420321797707163677" datatype="html">
<source>Preview document</source> <source>Preview document</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context> <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">329</context> <context context-type="linenumber">328</context>
</context-group> </context-group>
<target state="translated">Pratinjau dokumen</target> <target state="translated">Pratinjau dokumen</target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">331</context>
</context-group>
<target state="translated">Edit dokumen</target>
</trans-unit>
<trans-unit id="4512084577073831437" datatype="html"> <trans-unit id="4512084577073831437" datatype="html">
<source>Reset filters / selection</source> <source>Reset filters / selection</source>
<context-group purpose="location"> <context-group purpose="location">
+9 -9
View File
@@ -11397,22 +11397,22 @@
</context-group> </context-group>
<target state="translated">Ordina per <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target> <target state="translated">Ordina per <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">328</context>
</context-group>
<target state="translated">Modifica documento</target>
</trans-unit>
<trans-unit id="3420321797707163677" datatype="html"> <trans-unit id="3420321797707163677" datatype="html">
<source>Preview document</source> <source>Preview document</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context> <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">329</context> <context context-type="linenumber">328</context>
</context-group> </context-group>
<target state="translated">Anteprima documento</target> <target state="translated">Anteprima documento</target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">331</context>
</context-group>
<target state="translated">Modifica documento</target>
</trans-unit>
<trans-unit id="4512084577073831437" datatype="html"> <trans-unit id="4512084577073831437" datatype="html">
<source>Reset filters / selection</source> <source>Reset filters / selection</source>
<context-group purpose="location"> <context-group purpose="location">
+9 -9
View File
@@ -11396,22 +11396,22 @@
</context-group> </context-group>
<target state="translated"><x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/> でソート</target> <target state="translated"><x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/> でソート</target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">328</context>
</context-group>
<target state="translated">ドキュメントを編集</target>
</trans-unit>
<trans-unit id="3420321797707163677" datatype="html"> <trans-unit id="3420321797707163677" datatype="html">
<source>Preview document</source> <source>Preview document</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context> <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">329</context> <context context-type="linenumber">328</context>
</context-group> </context-group>
<target state="translated">ドキュメントのプレビュー</target> <target state="translated">ドキュメントのプレビュー</target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">331</context>
</context-group>
<target state="translated">ドキュメントを編集</target>
</trans-unit>
<trans-unit id="4512084577073831437" datatype="html"> <trans-unit id="4512084577073831437" datatype="html">
<source>Reset filters / selection</source> <source>Reset filters / selection</source>
<context-group purpose="location"> <context-group purpose="location">
+9 -9
View File
@@ -11397,22 +11397,22 @@
</context-group> </context-group>
<target state="needs-translation">Sort by <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target> <target state="needs-translation">Sort by <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">328</context>
</context-group>
<target state="translated">문서 수정</target>
</trans-unit>
<trans-unit id="3420321797707163677" datatype="html"> <trans-unit id="3420321797707163677" datatype="html">
<source>Preview document</source> <source>Preview document</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context> <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">329</context> <context context-type="linenumber">328</context>
</context-group> </context-group>
<target state="translated">문서 미리보기</target> <target state="translated">문서 미리보기</target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">331</context>
</context-group>
<target state="translated">문서 수정</target>
</trans-unit>
<trans-unit id="4512084577073831437" datatype="html"> <trans-unit id="4512084577073831437" datatype="html">
<source>Reset filters / selection</source> <source>Reset filters / selection</source>
<context-group purpose="location"> <context-group purpose="location">
+9 -9
View File
@@ -11397,22 +11397,22 @@
</context-group> </context-group>
<target state="needs-translation">Sort by <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target> <target state="needs-translation">Sort by <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">328</context>
</context-group>
<target state="translated">Dokument editéieren</target>
</trans-unit>
<trans-unit id="3420321797707163677" datatype="html"> <trans-unit id="3420321797707163677" datatype="html">
<source>Preview document</source> <source>Preview document</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context> <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">329</context> <context context-type="linenumber">328</context>
</context-group> </context-group>
<target state="needs-translation">Preview document</target> <target state="needs-translation">Preview document</target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">331</context>
</context-group>
<target state="translated">Dokument editéieren</target>
</trans-unit>
<trans-unit id="4512084577073831437" datatype="html"> <trans-unit id="4512084577073831437" datatype="html">
<source>Reset filters / selection</source> <source>Reset filters / selection</source>
<context-group purpose="location"> <context-group purpose="location">
+9 -9
View File
@@ -11397,22 +11397,22 @@
</context-group> </context-group>
<target state="needs-translation">Sort by <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target> <target state="needs-translation">Sort by <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">328</context>
</context-group>
<target state="needs-translation">Edit document</target>
</trans-unit>
<trans-unit id="3420321797707163677" datatype="html"> <trans-unit id="3420321797707163677" datatype="html">
<source>Preview document</source> <source>Preview document</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context> <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">329</context> <context context-type="linenumber">328</context>
</context-group> </context-group>
<target state="needs-translation">Preview document</target> <target state="needs-translation">Preview document</target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">331</context>
</context-group>
<target state="needs-translation">Edit document</target>
</trans-unit>
<trans-unit id="4512084577073831437" datatype="html"> <trans-unit id="4512084577073831437" datatype="html">
<source>Reset filters / selection</source> <source>Reset filters / selection</source>
<context-group purpose="location"> <context-group purpose="location">
+9 -9
View File
@@ -11397,22 +11397,22 @@
</context-group> </context-group>
<target state="needs-translation">Sort by <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target> <target state="needs-translation">Sort by <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">328</context>
</context-group>
<target state="translated">Rediģēt dokumentu</target>
</trans-unit>
<trans-unit id="3420321797707163677" datatype="html"> <trans-unit id="3420321797707163677" datatype="html">
<source>Preview document</source> <source>Preview document</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context> <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">329</context> <context context-type="linenumber">328</context>
</context-group> </context-group>
<target state="needs-translation">Preview document</target> <target state="needs-translation">Preview document</target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">331</context>
</context-group>
<target state="translated">Rediģēt dokumentu</target>
</trans-unit>
<trans-unit id="4512084577073831437" datatype="html"> <trans-unit id="4512084577073831437" datatype="html">
<source>Reset filters / selection</source> <source>Reset filters / selection</source>
<context-group purpose="location"> <context-group purpose="location">
File diff suppressed because it is too large. Load diff
+9 -9
View File
@@ -11397,22 +11397,22 @@
</context-group> </context-group>
<target state="needs-translation">Sort by <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target> <target state="needs-translation">Sort by <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">328</context>
</context-group>
<target state="needs-translation">Edit document</target>
</trans-unit>
<trans-unit id="3420321797707163677" datatype="html"> <trans-unit id="3420321797707163677" datatype="html">
<source>Preview document</source> <source>Preview document</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context> <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">329</context> <context context-type="linenumber">328</context>
</context-group> </context-group>
<target state="needs-translation">Preview document</target> <target state="needs-translation">Preview document</target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">331</context>
</context-group>
<target state="needs-translation">Edit document</target>
</trans-unit>
<trans-unit id="4512084577073831437" datatype="html"> <trans-unit id="4512084577073831437" datatype="html">
<source>Reset filters / selection</source> <source>Reset filters / selection</source>
<context-group purpose="location"> <context-group purpose="location">
+9 -9
View File
@@ -11396,22 +11396,22 @@
</context-group> </context-group>
<target state="translated">Sorteer op <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target> <target state="translated">Sorteer op <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">328</context>
</context-group>
<target state="translated">Document bewerken</target>
</trans-unit>
<trans-unit id="3420321797707163677" datatype="html"> <trans-unit id="3420321797707163677" datatype="html">
<source>Preview document</source> <source>Preview document</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context> <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">329</context> <context context-type="linenumber">328</context>
</context-group> </context-group>
<target state="translated">Voorbeeld van document</target> <target state="translated">Voorbeeld van document</target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">331</context>
</context-group>
<target state="translated">Document bewerken</target>
</trans-unit>
<trans-unit id="4512084577073831437" datatype="html"> <trans-unit id="4512084577073831437" datatype="html">
<source>Reset filters / selection</source> <source>Reset filters / selection</source>
<context-group purpose="location"> <context-group purpose="location">
+9 -9
View File
@@ -11397,22 +11397,22 @@
</context-group> </context-group>
<target state="translated">Sorter etter <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target> <target state="translated">Sorter etter <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">328</context>
</context-group>
<target state="translated">Rediger dokument</target>
</trans-unit>
<trans-unit id="3420321797707163677" datatype="html"> <trans-unit id="3420321797707163677" datatype="html">
<source>Preview document</source> <source>Preview document</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context> <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">329</context> <context context-type="linenumber">328</context>
</context-group> </context-group>
<target state="translated">Forhåndsvis dokument</target> <target state="translated">Forhåndsvis dokument</target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">331</context>
</context-group>
<target state="translated">Rediger dokument</target>
</trans-unit>
<trans-unit id="4512084577073831437" datatype="html"> <trans-unit id="4512084577073831437" datatype="html">
<source>Reset filters / selection</source> <source>Reset filters / selection</source>
<context-group purpose="location"> <context-group purpose="location">
+9 -9
View File
@@ -11396,22 +11396,22 @@
</context-group> </context-group>
<target state="translated">Sortuj według <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target> <target state="translated">Sortuj według <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">328</context>
</context-group>
<target state="translated">Edytuj dokument</target>
</trans-unit>
<trans-unit id="3420321797707163677" datatype="html"> <trans-unit id="3420321797707163677" datatype="html">
<source>Preview document</source> <source>Preview document</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context> <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">329</context> <context context-type="linenumber">328</context>
</context-group> </context-group>
<target state="translated">Podgląd dokumentu</target> <target state="translated">Podgląd dokumentu</target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">331</context>
</context-group>
<target state="translated">Edytuj dokument</target>
</trans-unit>
<trans-unit id="4512084577073831437" datatype="html"> <trans-unit id="4512084577073831437" datatype="html">
<source>Reset filters / selection</source> <source>Reset filters / selection</source>
<context-group purpose="location"> <context-group purpose="location">
+9 -9
View File
@@ -11398,22 +11398,22 @@ Erro ao enviar documentos por e-mail</target>
</context-group> </context-group>
<target state="translated">Ordenar por <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target> <target state="translated">Ordenar por <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">328</context>
</context-group>
<target state="translated">Editar documento</target>
</trans-unit>
<trans-unit id="3420321797707163677" datatype="html"> <trans-unit id="3420321797707163677" datatype="html">
<source>Preview document</source> <source>Preview document</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context> <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">329</context> <context context-type="linenumber">328</context>
</context-group> </context-group>
<target state="translated">Prévisualizar documento</target> <target state="translated">Prévisualizar documento</target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">331</context>
</context-group>
<target state="translated">Editar documento</target>
</trans-unit>
<trans-unit id="4512084577073831437" datatype="html"> <trans-unit id="4512084577073831437" datatype="html">
<source>Reset filters / selection</source> <source>Reset filters / selection</source>
<context-group purpose="location"> <context-group purpose="location">
+9 -9
View File
@@ -11397,22 +11397,22 @@
</context-group> </context-group>
<target state="needs-translation">Sort by <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target> <target state="needs-translation">Sort by <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">328</context>
</context-group>
<target state="translated">Editar documento</target>
</trans-unit>
<trans-unit id="3420321797707163677" datatype="html"> <trans-unit id="3420321797707163677" datatype="html">
<source>Preview document</source> <source>Preview document</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context> <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">329</context> <context context-type="linenumber">328</context>
</context-group> </context-group>
<target state="needs-translation">Preview document</target> <target state="needs-translation">Preview document</target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">331</context>
</context-group>
<target state="translated">Editar documento</target>
</trans-unit>
<trans-unit id="4512084577073831437" datatype="html"> <trans-unit id="4512084577073831437" datatype="html">
<source>Reset filters / selection</source> <source>Reset filters / selection</source>
<context-group purpose="location"> <context-group purpose="location">
+9 -9
View File
@@ -11396,22 +11396,22 @@
</context-group> </context-group>
<target state="translated">Sortează după <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target> <target state="translated">Sortează după <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">328</context>
</context-group>
<target state="translated">Editează document</target>
</trans-unit>
<trans-unit id="3420321797707163677" datatype="html"> <trans-unit id="3420321797707163677" datatype="html">
<source>Preview document</source> <source>Preview document</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context> <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">329</context> <context context-type="linenumber">328</context>
</context-group> </context-group>
<target state="translated">Previzualizare document</target> <target state="translated">Previzualizare document</target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">331</context>
</context-group>
<target state="translated">Editează document</target>
</trans-unit>
<trans-unit id="4512084577073831437" datatype="html"> <trans-unit id="4512084577073831437" datatype="html">
<source>Reset filters / selection</source> <source>Reset filters / selection</source>
<context-group purpose="location"> <context-group purpose="location">
+9 -9
View File
@@ -11396,22 +11396,22 @@
</context-group> </context-group>
<target state="translated">Сортировать по <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target> <target state="translated">Сортировать по <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">328</context>
</context-group>
<target state="translated">Изменить документ</target>
</trans-unit>
<trans-unit id="3420321797707163677" datatype="html"> <trans-unit id="3420321797707163677" datatype="html">
<source>Preview document</source> <source>Preview document</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context> <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">329</context> <context context-type="linenumber">328</context>
</context-group> </context-group>
<target state="translated">Предпросмотр документа</target> <target state="translated">Предпросмотр документа</target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">331</context>
</context-group>
<target state="translated">Изменить документ</target>
</trans-unit>
<trans-unit id="4512084577073831437" datatype="html"> <trans-unit id="4512084577073831437" datatype="html">
<source>Reset filters / selection</source> <source>Reset filters / selection</source>
<context-group purpose="location"> <context-group purpose="location">
+9 -9
View File
@@ -11398,22 +11398,22 @@ zhodujúce sa</target>
</context-group> </context-group>
<target state="needs-translation">Sort by <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target> <target state="needs-translation">Sort by <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">328</context>
</context-group>
<target state="translated">Upraviť dokument</target>
</trans-unit>
<trans-unit id="3420321797707163677" datatype="html"> <trans-unit id="3420321797707163677" datatype="html">
<source>Preview document</source> <source>Preview document</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context> <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">329</context> <context context-type="linenumber">328</context>
</context-group> </context-group>
<target state="needs-translation">Preview document</target> <target state="needs-translation">Preview document</target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">331</context>
</context-group>
<target state="translated">Upraviť dokument</target>
</trans-unit>
<trans-unit id="4512084577073831437" datatype="html"> <trans-unit id="4512084577073831437" datatype="html">
<source>Reset filters / selection</source> <source>Reset filters / selection</source>
<context-group purpose="location"> <context-group purpose="location">
+9 -9
View File
@@ -11397,22 +11397,22 @@
</context-group> </context-group>
<target state="translated">Razvrsti po <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target> <target state="translated">Razvrsti po <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">328</context>
</context-group>
<target state="translated">Uredi dokument</target>
</trans-unit>
<trans-unit id="3420321797707163677" datatype="html"> <trans-unit id="3420321797707163677" datatype="html">
<source>Preview document</source> <source>Preview document</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context> <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">329</context> <context context-type="linenumber">328</context>
</context-group> </context-group>
<target state="translated">Predogled dokumenta</target> <target state="translated">Predogled dokumenta</target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">331</context>
</context-group>
<target state="translated">Uredi dokument</target>
</trans-unit>
<trans-unit id="4512084577073831437" datatype="html"> <trans-unit id="4512084577073831437" datatype="html">
<source>Reset filters / selection</source> <source>Reset filters / selection</source>
<context-group purpose="location"> <context-group purpose="location">
+9 -9
View File
@@ -11397,22 +11397,22 @@
</context-group> </context-group>
<target state="translated">Rendit by <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target> <target state="translated">Rendit by <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">328</context>
</context-group>
<target state="translated">Redakto dokument</target>
</trans-unit>
<trans-unit id="3420321797707163677" datatype="html"> <trans-unit id="3420321797707163677" datatype="html">
<source>Preview document</source> <source>Preview document</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context> <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">329</context> <context context-type="linenumber">328</context>
</context-group> </context-group>
<target state="translated">Preview dokument</target> <target state="translated">Preview dokument</target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">331</context>
</context-group>
<target state="translated">Redakto dokument</target>
</trans-unit>
<trans-unit id="4512084577073831437" datatype="html"> <trans-unit id="4512084577073831437" datatype="html">
<source>Reset filters / selection</source> <source>Reset filters / selection</source>
<context-group purpose="location"> <context-group purpose="location">
+9 -9
View File
@@ -11398,22 +11398,22 @@
</context-group> </context-group>
<target state="translated">Složi prema <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target> <target state="translated">Složi prema <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">328</context>
</context-group>
<target state="translated">Uredi dokument</target>
</trans-unit>
<trans-unit id="3420321797707163677" datatype="html"> <trans-unit id="3420321797707163677" datatype="html">
<source>Preview document</source> <source>Preview document</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context> <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">329</context> <context context-type="linenumber">328</context>
</context-group> </context-group>
<target state="translated">Pregledaj dokument</target> <target state="translated">Pregledaj dokument</target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">331</context>
</context-group>
<target state="translated">Uredi dokument</target>
</trans-unit>
<trans-unit id="4512084577073831437" datatype="html"> <trans-unit id="4512084577073831437" datatype="html">
<source>Reset filters / selection</source> <source>Reset filters / selection</source>
<context-group purpose="location"> <context-group purpose="location">
+9 -9
View File
@@ -11396,22 +11396,22 @@
</context-group> </context-group>
<target state="translated">Sortera efter <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target> <target state="translated">Sortera efter <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">328</context>
</context-group>
<target state="translated">Redigera dokument</target>
</trans-unit>
<trans-unit id="3420321797707163677" datatype="html"> <trans-unit id="3420321797707163677" datatype="html">
<source>Preview document</source> <source>Preview document</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context> <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">329</context> <context context-type="linenumber">328</context>
</context-group> </context-group>
<target state="translated">Förhandsvisa dokument</target> <target state="translated">Förhandsvisa dokument</target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">331</context>
</context-group>
<target state="translated">Redigera dokument</target>
</trans-unit>
<trans-unit id="4512084577073831437" datatype="html"> <trans-unit id="4512084577073831437" datatype="html">
<source>Reset filters / selection</source> <source>Reset filters / selection</source>
<context-group purpose="location"> <context-group purpose="location">
+9 -9
View File
@@ -11397,22 +11397,22 @@
</context-group> </context-group>
<target state="needs-translation">Sort by <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target> <target state="needs-translation">Sort by <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">328</context>
</context-group>
<target state="translated">แก้ไขเอกสาร</target>
</trans-unit>
<trans-unit id="3420321797707163677" datatype="html"> <trans-unit id="3420321797707163677" datatype="html">
<source>Preview document</source> <source>Preview document</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context> <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">329</context> <context context-type="linenumber">328</context>
</context-group> </context-group>
<target state="needs-translation">Preview document</target> <target state="needs-translation">Preview document</target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">331</context>
</context-group>
<target state="translated">แก้ไขเอกสาร</target>
</trans-unit>
<trans-unit id="4512084577073831437" datatype="html"> <trans-unit id="4512084577073831437" datatype="html">
<source>Reset filters / selection</source> <source>Reset filters / selection</source>
<context-group purpose="location"> <context-group purpose="location">
+9 -9
View File
@@ -11398,22 +11398,22 @@ tüm <x id="CLOSE_EMPHASISED_TEXT" ctype="x-em" equiv-text="&lt;/em&gt;"/> krite
</context-group> </context-group>
<target state="translated"><x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/> göre sırala</target> <target state="translated"><x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/> göre sırala</target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">328</context>
</context-group>
<target state="translated">Belgeyi düzenle</target>
</trans-unit>
<trans-unit id="3420321797707163677" datatype="html"> <trans-unit id="3420321797707163677" datatype="html">
<source>Preview document</source> <source>Preview document</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context> <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">329</context> <context context-type="linenumber">328</context>
</context-group> </context-group>
<target state="translated">Belgeyi ön izle</target> <target state="translated">Belgeyi ön izle</target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">331</context>
</context-group>
<target state="translated">Belgeyi düzenle</target>
</trans-unit>
<trans-unit id="4512084577073831437" datatype="html"> <trans-unit id="4512084577073831437" datatype="html">
<source>Reset filters / selection</source> <source>Reset filters / selection</source>
<context-group purpose="location"> <context-group purpose="location">
+9 -9
View File
@@ -11397,22 +11397,22 @@
</context-group> </context-group>
<target state="needs-translation">Sort by <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target> <target state="needs-translation">Sort by <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">328</context>
</context-group>
<target state="translated">Редагувати документ</target>
</trans-unit>
<trans-unit id="3420321797707163677" datatype="html"> <trans-unit id="3420321797707163677" datatype="html">
<source>Preview document</source> <source>Preview document</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context> <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">329</context> <context context-type="linenumber">328</context>
</context-group> </context-group>
<target state="translated">Попередній перегляд документа</target> <target state="translated">Попередній перегляд документа</target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">331</context>
</context-group>
<target state="translated">Редагувати документ</target>
</trans-unit>
<trans-unit id="4512084577073831437" datatype="html"> <trans-unit id="4512084577073831437" datatype="html">
<source>Reset filters / selection</source> <source>Reset filters / selection</source>
<context-group purpose="location"> <context-group purpose="location">
+9 -9
View File
@@ -11459,22 +11459,22 @@
Sắp xếp theo Sắp xếp theo
</target> </target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html" approved="yes">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">328</context>
</context-group>
<target state="final">Chỉnh sửa tài liệu</target>
</trans-unit>
<trans-unit id="3420321797707163677" datatype="html" approved="yes"> <trans-unit id="3420321797707163677" datatype="html" approved="yes">
<source>Preview document</source> <source>Preview document</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context> <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">329</context> <context context-type="linenumber">328</context>
</context-group> </context-group>
<target state="final">Xem trước tài liệu</target> <target state="final">Xem trước tài liệu</target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html" approved="yes">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">331</context>
</context-group>
<target state="final">Chỉnh sửa tài liệu</target>
</trans-unit>
<trans-unit id="4512084577073831437" datatype="html" approved="yes"> <trans-unit id="4512084577073831437" datatype="html" approved="yes">
<source>Reset filters / selection</source> <source>Reset filters / selection</source>
<context-group purpose="location"> <context-group purpose="location">
+9 -9
View File
@@ -11396,22 +11396,22 @@
</context-group> </context-group>
<target state="translated">按 <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/> 排序</target> <target state="translated">按 <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/> 排序</target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">328</context>
</context-group>
<target state="translated">编辑文档</target>
</trans-unit>
<trans-unit id="3420321797707163677" datatype="html"> <trans-unit id="3420321797707163677" datatype="html">
<source>Preview document</source> <source>Preview document</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context> <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">329</context> <context context-type="linenumber">328</context>
</context-group> </context-group>
<target state="translated">预览文档</target> <target state="translated">预览文档</target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">331</context>
</context-group>
<target state="translated">编辑文档</target>
</trans-unit>
<trans-unit id="4512084577073831437" datatype="html"> <trans-unit id="4512084577073831437" datatype="html">
<source>Reset filters / selection</source> <source>Reset filters / selection</source>
<context-group purpose="location"> <context-group purpose="location">
+9 -9
View File
@@ -11397,22 +11397,22 @@
</context-group> </context-group>
<target state="translated">以<x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/>排序</target> <target state="translated">以<x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/>排序</target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">328</context>
</context-group>
<target state="translated">編輯文件</target>
</trans-unit>
<trans-unit id="3420321797707163677" datatype="html"> <trans-unit id="3420321797707163677" datatype="html">
<source>Preview document</source> <source>Preview document</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context> <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">329</context> <context context-type="linenumber">328</context>
</context-group> </context-group>
<target state="translated">預覽文件</target> <target state="translated">預覽文件</target>
</trans-unit> </trans-unit>
<trans-unit id="2179847500064178686" datatype="html">
<source>Edit document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">331</context>
</context-group>
<target state="translated">編輯文件</target>
</trans-unit>
<trans-unit id="4512084577073831437" datatype="html"> <trans-unit id="4512084577073831437" datatype="html">
<source>Reset filters / selection</source> <source>Reset filters / selection</source>
<context-group purpose="location"> <context-group purpose="location">
+2 -1
View File
@@ -1,6 +1,7 @@
from django.conf import settings from django.conf import settings
from django.contrib import admin from django.contrib import admin
from guardian.admin import GuardedModelAdmin from guardian.admin import GuardedModelAdmin
from treenode.admin import TreeNodeModelAdmin
from documents.models import Correspondent from documents.models import Correspondent
from documents.models import CustomField from documents.models import CustomField
@@ -28,7 +29,7 @@ class CorrespondentAdmin(GuardedModelAdmin):
list_editable = ("match", "matching_algorithm") list_editable = ("match", "matching_algorithm")
class TagAdmin(GuardedModelAdmin): class TagAdmin(GuardedModelAdmin, TreeNodeModelAdmin):
list_display = ("name", "color", "match", "matching_algorithm") list_display = ("name", "color", "match", "matching_algorithm")
list_filter = ("matching_algorithm",) list_filter = ("matching_algorithm",)
list_editable = ("color", "match", "matching_algorithm") list_editable = ("color", "match", "matching_algorithm")
+7 -3
View File
@@ -10,9 +10,6 @@ from typing import TYPE_CHECKING
import regex as regex_mod import regex as regex_mod
from django.conf import settings from django.conf import settings
from pdf2image import convert_from_path from pdf2image import convert_from_path
from pikepdf import Page
from pikepdf import PasswordError
from pikepdf import Pdf
from documents.converters import convert_from_tiff_to_pdf from documents.converters import convert_from_tiff_to_pdf
from documents.data_models import ConsumableDocument from documents.data_models import ConsumableDocument
@@ -34,6 +31,7 @@ from documents.utils import maybe_override_pixel_limit
from paperless.config import BarcodeConfig from paperless.config import BarcodeConfig
if TYPE_CHECKING: if TYPE_CHECKING:
from pikepdf import Page
from PIL import Image from PIL import Image
logger = logging.getLogger("paperless.barcodes") logger = logging.getLogger("paperless.barcodes")
@@ -282,6 +280,8 @@ class BarcodePlugin(ConsumeTaskPlugin):
# No op if not a TIFF # No op if not a TIFF
self.convert_from_tiff_to_pdf() self.convert_from_tiff_to_pdf()
from pikepdf import PasswordError
try: try:
self.barcodes = scan_pdf( self.barcodes = scan_pdf(
self.pdf_file, self.pdf_file,
@@ -433,6 +433,8 @@ class BarcodePlugin(ConsumeTaskPlugin):
document_paths = [] document_paths = []
fname: str = self.input_doc.original_file.stem fname: str = self.input_doc.original_file.stem
from pikepdf import Pdf
with Pdf.open(self.pdf_file) as input_pdf: with Pdf.open(self.pdf_file) as input_pdf:
# Start with an empty document # Start with an empty document
current_document: list[Page] = [] current_document: list[Page] = []
@@ -516,6 +518,8 @@ def scan_pdf(pdf_path: Path, settings: BarcodeConfig, work_dir: Path) -> list[Ba
""" """
barcodes: list[Barcode] = [] barcodes: list[Barcode] = []
from pikepdf import Pdf
with Pdf.open(pdf_path) as pdf: with Pdf.open(pdf_path) as pdf:
num_of_pages = len(pdf.pages) num_of_pages = len(pdf.pages)
logger.debug(f"PDF has {num_of_pages} pages") logger.debug(f"PDF has {num_of_pages} pages")
+13 -7
View File
@@ -255,13 +255,19 @@ def modify_tags(
affected_docs = list(qs.values_list("pk", flat=True)) affected_docs = list(qs.values_list("pk", flat=True))
DocumentTagRelationship = Document.tags.through DocumentTagRelationship = Document.tags.through
hierarchy = Tag.get_hierarchy() # add with all ancestors
expanded_add_tags = hierarchy.with_ancestors( expanded_add_tags: set[int] = set()
Tag.objects.filter(pk__in=add_tags).values_list("pk", flat=True), add_tag_objects = Tag.objects.filter(pk__in=add_tags)
) for t in add_tag_objects:
expanded_remove_tags = hierarchy.with_descendants( expanded_add_tags.add(int(t.id))
Tag.objects.filter(pk__in=remove_tags).values_list("pk", flat=True), expanded_add_tags.update(int(pk) for pk in t.get_ancestors_pks())
)
# remove with all descendants
expanded_remove_tags: set[int] = set()
remove_tag_objects = Tag.objects.filter(pk__in=remove_tags)
for t in remove_tag_objects:
expanded_remove_tags.add(int(t.id))
expanded_remove_tags.update(int(pk) for pk in t.get_descendants_pks())
with transaction.atomic(): with transaction.atomic():
if expanded_remove_tags: if expanded_remove_tags:
+2 -1
View File
@@ -1,6 +1,5 @@
from pathlib import Path from pathlib import Path
import img2pdf
from PIL import Image from PIL import Image
from documents.utils import copy_basic_file_stats from documents.utils import copy_basic_file_stats
@@ -17,6 +16,8 @@ def convert_from_tiff_to_pdf(tiff_path: Path, target_directory: Path) -> Path:
Returns the path of the PDF created. Returns the path of the PDF created.
""" """
import img2pdf
# override pixel setting if needed # override pixel setting if needed
maybe_override_pixel_limit() maybe_override_pixel_limit()
+2 -1
View File
@@ -6,7 +6,6 @@ from pathlib import Path
from typing import Final from typing import Final
from django.conf import settings from django.conf import settings
from pikepdf import Pdf
from documents.consumer import ConsumerError from documents.consumer import ConsumerError
from documents.converters import convert_from_tiff_to_pdf from documents.converters import convert_from_tiff_to_pdf
@@ -85,6 +84,8 @@ class CollatePlugin(NoCleanupPluginMixin, NoSetupPluginMixin, ConsumeTaskPlugin)
valid_staging_exists = True valid_staging_exists = True
if valid_staging_exists: if valid_staging_exists:
from pikepdf import Pdf
try: try:
# Collate pages from second PDF in reverse order # Collate pages from second PDF in reverse order
with Pdf.open(staging) as pdf1, Pdf.open(pdf_file) as pdf2: with Pdf.open(staging) as pdf1, Pdf.open(pdf_file) as pdf2:
+2 -1
View File
@@ -11,7 +11,6 @@ from decimal import InvalidOperation
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from typing import Any from typing import Any
import dateparser
from django.conf import settings from django.conf import settings
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.db.models import Case from django.db.models import Case
@@ -350,6 +349,8 @@ class DateQueryField(serializers.DateField):
if not isinstance(value, str): if not isinstance(value, str):
raise raise
import dateparser
try: try:
parsed = dateparser.parse( parsed = dateparser.parse(
value, value,
@@ -108,24 +108,6 @@ def _deserialize_record(
) from e ) from e
for field_name, field_value in record.get("fields", {}).items(): for field_name, field_value in record.get("fields", {}).items():
# Older exports include django-treenode's derived bookkeeping. The
# parent FK is authoritative; accept only these known removed fields.
if Model is Tag and field_name in {
"tn_ancestors_count",
"tn_ancestors_pks",
"tn_children_count",
"tn_children_pks",
"tn_depth",
"tn_descendants_count",
"tn_descendants_pks",
"tn_index",
"tn_level",
"tn_order",
"tn_priority",
"tn_siblings_count",
"tn_siblings_pks",
}:
continue
field = Model._meta.get_field(field_name) field = Model._meta.get_field(field_name)
remote = field.remote_field remote = field.remote_field
@@ -1,64 +0,0 @@
# Generated by Django 5.2.17 on 2026-10-28 22:54
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
("documents", "0027_documentbarcode"),
]
operations = [
migrations.RemoveField(
model_name="tag",
name="tn_ancestors_count",
),
migrations.RemoveField(
model_name="tag",
name="tn_ancestors_pks",
),
migrations.RemoveField(
model_name="tag",
name="tn_children_count",
),
migrations.RemoveField(
model_name="tag",
name="tn_children_pks",
),
migrations.RemoveField(
model_name="tag",
name="tn_depth",
),
migrations.RemoveField(
model_name="tag",
name="tn_descendants_count",
),
migrations.RemoveField(
model_name="tag",
name="tn_descendants_pks",
),
migrations.RemoveField(
model_name="tag",
name="tn_index",
),
migrations.RemoveField(
model_name="tag",
name="tn_level",
),
migrations.RemoveField(
model_name="tag",
name="tn_order",
),
migrations.RemoveField(
model_name="tag",
name="tn_priority",
),
migrations.RemoveField(
model_name="tag",
name="tn_siblings_count",
),
migrations.RemoveField(
model_name="tag",
name="tn_siblings_pks",
),
]
+23 -53
View File
@@ -14,6 +14,7 @@ from django.db import models
from django.utils import timezone from django.utils import timezone
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from multiselectfield import MultiSelectField from multiselectfield import MultiSelectField
from treenode.models import TreeNodeModel
if settings.AUDIT_LOG_ENABLED: if settings.AUDIT_LOG_ENABLED:
from auditlog.registry import auditlog from auditlog.registry import auditlog
@@ -99,17 +100,7 @@ class Correspondent(MatchingModel):
verbose_name_plural = _("correspondents") verbose_name_plural = _("correspondents")
class Tag(MatchingModel): class Tag(MatchingModel, TreeNodeModel):
# Keep the existing column and reverse relation during the transition.
tn_parent = models.ForeignKey(
"self",
blank=True,
null=True,
on_delete=models.CASCADE,
related_name="tn_children",
verbose_name=_("Parent"),
)
color = models.CharField(_("color"), max_length=7, default="#a6cee3") color = models.CharField(_("color"), max_length=7, default="#a6cee3")
# Maximum allowed nesting depth for tags (root = 1, max depth = 5) # Maximum allowed nesting depth for tags (root = 1, max depth = 5)
MAX_NESTING_DEPTH: Final[int] = 5 MAX_NESTING_DEPTH: Final[int] = 5
@@ -123,51 +114,27 @@ class Tag(MatchingModel):
), ),
) )
class Meta(MatchingModel.Meta): class Meta(MatchingModel.Meta, TreeNodeModel.Meta):
verbose_name = _("tag") verbose_name = _("tag")
verbose_name_plural = _("tags") verbose_name_plural = _("tags")
@classmethod
def get_hierarchy(cls):
from documents.tag_hierarchy import TagHierarchy
return TagHierarchy(cls.objects.values_list("pk", "tn_parent_id"))
@property
def parent_pk(self):
return self.tn_parent_id
def get_parent(self):
return self.tn_parent
def get_ancestors_pks(self):
return self.get_hierarchy().ancestors(self.tn_parent_id)
def get_ancestors(self):
ids = self.get_ancestors_pks()
tags = self.__class__.objects.in_bulk(ids)
return [tags[pk] for pk in ids]
def get_descendants_pks(self):
return self.get_hierarchy().descendants([self.pk])
def get_descendants(self):
return self.__class__.objects.filter(pk__in=self.get_descendants_pks())
def get_children_queryset(self):
return self.__class__.objects.filter(tn_parent_id=self.pk)
def clean(self) -> None: def clean(self) -> None:
hierarchy = self.get_hierarchy() # Prevent self-parenting and assigning a descendant as parent
if self.pk is not None and self.tn_parent_id == self.pk: parent = self.get_parent()
raise ValidationError({"tn_parent": _("Cannot set itself as parent.")}) if parent == self:
ancestors = hierarchy.ancestors(self.tn_parent_id) raise ValidationError({"parent": _("Cannot set itself as parent.")})
if self.pk is not None and self.pk in ancestors: if parent and self.pk is not None and self.is_ancestor_of(parent):
raise ValidationError( raise ValidationError({"parent": _("Cannot set parent to a descendant.")})
{"tn_parent": _("Cannot set parent to a descendant.")},
) # Enforce maximum nesting depth
if len(ancestors) + 1 + hierarchy.height(self.pk) > self.MAX_NESTING_DEPTH: new_parent_depth = 0
raise ValidationError({"tn_parent": _("Maximum nesting depth exceeded.")}) if parent:
new_parent_depth = parent.get_ancestors_count() + 1
height = 0 if self.pk is None else self.get_depth()
deepest_new_depth = (new_parent_depth + 1) + height
if deepest_new_depth > self.MAX_NESTING_DEPTH:
raise ValidationError({"parent": _("Maximum nesting depth exceeded.")})
return super().clean() return super().clean()
@@ -572,7 +539,10 @@ class Document(SoftDeleteModel, ModelWithOwner): # type: ignore[django-manager-
return self.created return self.created
def add_nested_tags(self, tags) -> None: def add_nested_tags(self, tags) -> None:
tag_ids = Tag.get_hierarchy().with_ancestors(tag.pk for tag in tags) tag_ids = set()
for tag in tags:
tag_ids.add(tag.id)
tag_ids.update(tag.get_ancestors_pks())
tags_to_add = self.tags.model.objects.filter(id__in=tag_ids) tags_to_add = self.tags.model.objects.filter(id__in=tag_ids)
self.tags.add(*tags_to_add) self.tags.add(*tags_to_add)
+14 -2
View File
@@ -14,8 +14,6 @@ from __future__ import annotations
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from typing import NamedTuple from typing import NamedTuple
import pikepdf
if TYPE_CHECKING: if TYPE_CHECKING:
from collections.abc import Callable from collections.abc import Callable
from collections.abc import Iterable from collections.abc import Iterable
@@ -43,6 +41,8 @@ def rotate_pdf(src: Path, dst: Path, degrees: int) -> None:
Rotate every page relatively on the opened document, not a rebuild, so Info, Rotate every page relatively on the opened document, not a rebuild, so Info,
XMP and outlines are kept. ``src`` is not modified. XMP and outlines are kept. ``src`` is not modified.
""" """
import pikepdf
with pikepdf.open(src) as pdf: with pikepdf.open(src) as pdf:
for page in pdf.pages: for page in pdf.pages:
page.rotate(degrees, relative=True) page.rotate(degrees, relative=True)
@@ -58,6 +58,8 @@ def remove_pages(src: Path, dst: Path, pages: Iterable[int]) -> None:
Duplicates are ignored. Pages are removed highest first so earlier removals Duplicates are ignored. Pages are removed highest first so earlier removals
never shift the index of later ones. never shift the index of later ones.
""" """
import pikepdf
unique = sorted(set(pages)) unique = sorted(set(pages))
_require_positive(unique) _require_positive(unique)
with pikepdf.open(src) as pdf: with pikepdf.open(src) as pdf:
@@ -81,6 +83,8 @@ def build_pdfs(
(Info, XMP, outlines) is not carried over. Returns the written paths in output (Info, XMP, outlines) is not carried over. Returns the written paths in output
order. order.
""" """
import pikepdf
for specs, _ in outputs: for specs, _ in outputs:
_require_positive(spec.page for spec in specs) _require_positive(spec.page for spec in specs)
@@ -140,6 +144,8 @@ def needs_decrypt(src: Path) -> bool:
True if ``src`` is encrypted. A PDF that needs a password to open at all True if ``src`` is encrypted. A PDF that needs a password to open at all
counts as encrypted. counts as encrypted.
""" """
import pikepdf
try: try:
with pikepdf.open(src) as pdf: with pikepdf.open(src) as pdf:
return bool(pdf.is_encrypted) return bool(pdf.is_encrypted)
@@ -154,6 +160,8 @@ def decrypt_pdf(src: Path, make_dst: Callable[[], Path], password: str) -> Path:
``make_dst`` is only called once the password has been accepted, so a wrong ``make_dst`` is only called once the password has been accepted, so a wrong
password never leaves a destination behind. password never leaves a destination behind.
""" """
import pikepdf
with pikepdf.open(src, password=password) as pdf: with pikepdf.open(src, password=password) as pdf:
pdf.remove_unreferenced_resources() pdf.remove_unreferenced_resources()
dst = make_dst() dst = make_dst()
@@ -170,6 +178,8 @@ class PdfMerger:
""" """
def __init__(self) -> None: def __init__(self) -> None:
import pikepdf
self._pdf = pikepdf.new() self._pdf = pikepdf.new()
self._version: str = self._pdf.pdf_version self._version: str = self._pdf.pdf_version
@@ -185,6 +195,8 @@ class PdfMerger:
self._pdf.close() self._pdf.close()
def add(self, path: Path) -> None: def add(self, path: Path) -> None:
import pikepdf
with pikepdf.open(str(path)) as pdf: with pikepdf.open(str(path)) as pdf:
self._version = max(self._version, pdf.pdf_version) self._version = max(self._version, pdf.pdf_version)
self._pdf.pages.extend(pdf.pages) self._pdf.pages.extend(pdf.pages)
+2 -2
View File
@@ -7,8 +7,6 @@ from dataclasses import dataclass
from types import TracebackType from types import TracebackType
from typing import Self from typing import Self
import dateparser
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -80,6 +78,8 @@ class DateParserPluginBase(ABC):
Uses configuration from `self.config`. Uses configuration from `self.config`.
""" """
import dateparser
try: try:
return dateparser.parse( return dateparser.parse(
date_string, date_string,
+50 -28
View File
@@ -589,7 +589,7 @@ class TagSerializer(MatchingModelSerializer, OwnedObjectSerializer):
text_color = serializers.SerializerMethodField() text_color = serializers.SerializerMethodField()
# Preserve the public API parent field. # map to treenode's tn_parent
parent = serializers.PrimaryKeyRelatedField( parent = serializers.PrimaryKeyRelatedField(
queryset=Tag.objects.all(), queryset=Tag.objects.all(),
allow_null=True, allow_null=True,
@@ -692,9 +692,7 @@ class TagSerializer(MatchingModelSerializer, OwnedObjectSerializer):
self.instance.clean() self.instance.clean()
except ValidationError as e: except ValidationError as e:
logger.debug("Tag parent validation failed: %s", e) logger.debug("Tag parent validation failed: %s", e)
raise serializers.ValidationError( raise e
{"parent": e.message_dict["tn_parent"]},
) from e
finally: finally:
self.instance.tn_parent = original_parent self.instance.tn_parent = original_parent
else: else:
@@ -704,9 +702,7 @@ class TagSerializer(MatchingModelSerializer, OwnedObjectSerializer):
temp.clean() temp.clean()
except ValidationError as e: except ValidationError as e:
logger.debug("Tag parent validation failed: %s", e) logger.debug("Tag parent validation failed: %s", e)
raise serializers.ValidationError( raise e
{"parent": e.message_dict["tn_parent"]},
) from e
return super().validate(attrs) return super().validate(attrs)
@@ -1202,35 +1198,61 @@ class DocumentSerializer(
doc_id, doc_id,
) )
if "tags" in validated_data: if "tags" in validated_data:
hierarchy = Tag.get_hierarchy() # Respect tag hierarchy on updates:
previous_ids = set(instance.tags.values_list("pk", flat=True)) # - Adding a child adds its ancestors
requested_ids = {tag.pk for tag in validated_data["tags"]} # - Removing a parent removes all its descendants
required_ids = hierarchy.with_ancestors(requested_ids - previous_ids) prev_tags = set(instance.tags.all())
blocked_ids = hierarchy.with_descendants(previous_ids - requested_ids) requested_tags = set(validated_data["tags"])
blocked_ids.difference_update(required_ids)
final_ids = hierarchy.with_ancestors(requested_ids) - blocked_ids
validated_data["tags"] = list(Tag.objects.filter(pk__in=final_ids))
# Tags newly added in this update and the ancestors they require
added_tags = requested_tags - prev_tags
required_by_add_tags = set(added_tags)
for t in added_tags:
required_by_add_tags.update(t.get_ancestors())
# Tags being removed in this update and all descendants, except
# those required by a tag that is being added in this same update
removed_tags = prev_tags - requested_tags
blocked_tags = set(removed_tags)
for t in removed_tags:
blocked_tags.update(t.get_descendants())
blocked_tags.difference_update(required_by_add_tags)
# Add all parent tags
final_tags = set(requested_tags)
for t in requested_tags:
final_tags.update(t.get_ancestors())
# Drop removed parents and their descendants
final_tags.difference_update(blocked_tags)
validated_data["tags"] = list(final_tags)
if validated_data.get("remove_inbox_tags"): if validated_data.get("remove_inbox_tags"):
hierarchy = Tag.get_hierarchy() current_tag_ids = {t.pk for t in instance.tags.all()}
tags = ( tags = (
validated_data["tags"] validated_data["tags"]
if "tags" in validated_data if "tags" in validated_data
else list(instance.tags.all()) else list(instance.tags.all())
) )
current_ids = set(instance.tags.values_list("pk", flat=True))
keep_ids = hierarchy.with_ancestors( # Tags newly added in this update, plus their ancestors, are kept
tag.pk for tag in tags if tag.pk not in current_ids keep_ids: set[int] = set()
) for tag in tags:
inbox_ids = ( if tag.pk not in current_tag_ids:
keep_ids.add(tag.pk)
keep_ids.update(int(pk) for pk in tag.get_ancestors_pks())
# Remove inbox tags and their descendants, except those being kept
remove_ids: set[int] = set()
for inbox_tag in (
Tag.objects.filter(is_inbox_tag=True) Tag.objects.filter(is_inbox_tag=True)
.exclude( .exclude(pk__in=keep_ids)
pk__in=keep_ids, .only("pk", "tn_descendants_pks")
) ):
.values_list("pk", flat=True) remove_ids.add(inbox_tag.pk)
) remove_ids.update(int(pk) for pk in inbox_tag.get_descendants_pks())
remove_ids = hierarchy.with_descendants(inbox_ids) - keep_ids
validated_data["tags"] = [tag for tag in tags if tag.pk not in remove_ids] validated_data["tags"] = [t for t in tags if t.pk not in remove_ids]
if settings.AUDIT_LOG_ENABLED: if settings.AUDIT_LOG_ENABLED:
with set_actor(self.user): with set_actor(self.user):
-61
View File
@@ -1,61 +0,0 @@
"""An operation-local snapshot of tag edges, with no persistent derived fields.
Never cache this globally: tasks, bulk updates and other processes can change
parents. Callers traversing multiple tags should share one snapshot.
"""
from collections import defaultdict
from collections.abc import Iterable
class TagHierarchy:
def __init__(self, edges: Iterable[tuple[int, int | None]]) -> None:
self.parents = dict(edges)
self.children: dict[int | None, list[int]] = defaultdict(list)
for pk, parent in self.parents.items():
self.children[parent].append(pk)
def ancestors(self, parent_id: int | None) -> list[int]:
result = []
seen = set()
while parent_id is not None and parent_id not in seen:
seen.add(parent_id)
result.append(parent_id)
parent_id = self.parents.get(parent_id)
return result[::-1]
def with_ancestors(self, roots: Iterable[int]) -> set[int]:
result = set(roots)
for pk in list(result):
result.update(self.ancestors(self.parents.get(pk)))
return result
def with_descendants(self, roots: Iterable[int]) -> set[int]:
roots = set(roots)
return roots | self.descendants(roots)
def descendants(self, roots: Iterable[int]) -> set[int]:
roots = {pk for pk in roots if pk is not None}
seen = set(roots)
pending = list(roots)
while pending:
for child in self.children.get(pending.pop(), ()):
if child not in seen:
seen.add(child)
pending.append(child)
return seen - roots
def height(self, pk: int | None) -> int:
if pk is None:
return 0
seen = {pk}
pending = [(pk, 0)]
height = 0
while pending:
parent, depth = pending.pop()
height = max(height, depth)
for child in self.children.get(parent, ()):
if child not in seen:
seen.add(child)
pending.append((child, depth + 1))
return height
+8 -3
View File
@@ -76,9 +76,6 @@ from paperless.logging import consume_task_id
from paperless.parsers import ParserContext from paperless.parsers import ParserContext
from paperless.parsers.registry import get_parser_registry from paperless.parsers.registry import get_parser_registry
from paperless_ai.exceptions import LLMTimeoutError from paperless_ai.exceptions import LLMTimeoutError
from paperless_ai.indexing import llm_index_add_or_update_document
from paperless_ai.indexing import llm_index_remove_document
from paperless_ai.indexing import update_llm_index
if settings.AUDIT_LOG_ENABLED: if settings.AUDIT_LOG_ENABLED:
from auditlog.models import LogEntry from auditlog.models import LogEntry
@@ -339,6 +336,8 @@ def bulk_update_documents(document_ids) -> None:
ai_config = AIConfig() ai_config = AIConfig()
if ai_config.llm_index_enabled: if ai_config.llm_index_enabled:
from paperless_ai.indexing import update_llm_index
update_llm_index( update_llm_index(
rebuild=False, rebuild=False,
document_ids=document_ids, document_ids=document_ids,
@@ -499,6 +498,8 @@ def update_document_content_maybe_archive_file(
ai_config = AIConfig() ai_config = AIConfig()
if ai_config.llm_index_enabled: if ai_config.llm_index_enabled:
from paperless_ai.indexing import llm_index_add_or_update_document
llm_index_add_or_update_document(document) llm_index_add_or_update_document(document)
clear_document_caches(document.pk) clear_document_caches(document.pk)
@@ -800,11 +801,15 @@ def apply_ai_suggestions(self, action_id: int, document_id: int) -> None:
@shared_task @shared_task
def update_document_in_llm_index(document) -> None: def update_document_in_llm_index(document) -> None:
from paperless_ai.indexing import llm_index_add_or_update_document
llm_index_add_or_update_document(document) llm_index_add_or_update_document(document)
@shared_task @shared_task
def remove_document_from_llm_index(document) -> None: def remove_document_from_llm_index(document) -> None:
from paperless_ai.indexing import llm_index_remove_document
llm_index_remove_document(document) llm_index_remove_document(document)
@@ -71,7 +71,7 @@ class TestParseString:
): ):
# We still need to mock dateparser.parse to force the exception # We still need to mock dateparser.parse to force the exception
mocker.patch( mocker.patch(
"documents.plugins.date_parsing.base.dateparser.parse", "dateparser.parse",
side_effect=ValueError( side_effect=ValueError(
"Parsing error: 01/01/2024", "Parsing error: 01/01/2024",
), ),
@@ -260,7 +260,7 @@ class TestRegexDateParser:
parser = RegexDateParserPlugin(base_config) parser = RegexDateParserPlugin(base_config)
# Patch the dateparser.parse # Patch the dateparser.parse
target = "documents.plugins.date_parsing.base.dateparser.parse" target = "dateparser.parse"
def fake_parse( def fake_parse(
date_string: str, date_string: str,
@@ -335,7 +335,7 @@ class TestRegexDateParser:
) )
parser = RegexDateParserPlugin(cfg) parser = RegexDateParserPlugin(cfg)
target = "documents.plugins.date_parsing.base.dateparser.parse" target = "dateparser.parse"
def fake_parse( def fake_parse(
date_string: str, date_string: str,
@@ -400,7 +400,7 @@ class TestRegexDateParser:
parser = RegexDateParserPlugin(cfg) parser = RegexDateParserPlugin(cfg)
# Patch the module's dateparser.parse so we can inspect calls # Patch the module's dateparser.parse so we can inspect calls
target = "documents.plugins.date_parsing.base.dateparser.parse" target = "dateparser.parse"
def fake_parse( def fake_parse(
date_string: str, date_string: str,
+5 -5
View File
@@ -1070,7 +1070,7 @@ class TestApiAppConfig(DirectoriesMixin, APITestCase):
with ( with (
patch("documents.tasks.llmindex_index.apply_async") as mock_update, patch("documents.tasks.llmindex_index.apply_async") as mock_update,
patch("paperless.views.llm_index_exists") as mock_exists, patch("paperless_ai.indexing.llm_index_exists") as mock_exists,
): ):
mock_exists.return_value = False mock_exists.return_value = False
self.client.patch( self.client.patch(
@@ -1095,7 +1095,7 @@ class TestApiAppConfig(DirectoriesMixin, APITestCase):
with ( with (
patch("documents.tasks.llmindex_index.apply_async") as mock_update, patch("documents.tasks.llmindex_index.apply_async") as mock_update,
patch("paperless.views.llm_index_exists", return_value=False), patch("paperless_ai.indexing.llm_index_exists", return_value=False),
): ):
self.client.patch( self.client.patch(
f"{self.ENDPOINT}1/", f"{self.ENDPOINT}1/",
@@ -1115,7 +1115,7 @@ class TestApiAppConfig(DirectoriesMixin, APITestCase):
with ( with (
patch("documents.tasks.llmindex_index.apply_async") as mock_update, patch("documents.tasks.llmindex_index.apply_async") as mock_update,
patch("paperless.views.llm_index_exists") as mock_exists, patch("paperless_ai.indexing.llm_index_exists") as mock_exists,
): ):
mock_exists.return_value = True mock_exists.return_value = True
self.client.patch( self.client.patch(
@@ -1136,7 +1136,7 @@ class TestApiAppConfig(DirectoriesMixin, APITestCase):
with ( with (
patch("documents.tasks.llmindex_index.apply_async") as mock_update, patch("documents.tasks.llmindex_index.apply_async") as mock_update,
patch("paperless.views.llm_index_exists") as mock_exists, patch("paperless_ai.indexing.llm_index_exists") as mock_exists,
): ):
mock_exists.return_value = True mock_exists.return_value = True
self.client.patch( self.client.patch(
@@ -1174,7 +1174,7 @@ class TestApiAppConfig(DirectoriesMixin, APITestCase):
with ( with (
patch("documents.tasks.llmindex_index.apply_async") as mock_update, patch("documents.tasks.llmindex_index.apply_async") as mock_update,
patch("paperless.views.llm_index_exists") as mock_exists, patch("paperless_ai.indexing.llm_index_exists") as mock_exists,
): ):
mock_exists.return_value = True mock_exists.return_value = True
self.client.patch( self.client.patch(
+2 -2
View File
@@ -61,7 +61,7 @@ class TestChatStreamingViewInputValidation(APITestCase):
return_value=self._mock_ai_enabled(), return_value=self._mock_ai_enabled(),
), ),
mock.patch( mock.patch(
"documents.views.stream_chat_with_documents", "paperless_ai.chat.stream_chat_with_documents",
return_value=iter(chunks), return_value=iter(chunks),
), ),
): ):
@@ -104,7 +104,7 @@ class TestChatStreamingViewUnrestrictedFlag:
""" """
mocker.patch("documents.views.AIConfig").return_value.ai_enabled = True mocker.patch("documents.views.AIConfig").return_value.ai_enabled = True
return mocker.patch( return mocker.patch(
"documents.views.stream_chat_with_documents", "paperless_ai.chat.stream_chat_with_documents",
return_value=iter(()), return_value=iter(()),
) )
@@ -1110,7 +1110,7 @@ class TestVersionActionPermissions(DirectoriesMixin, APITestCase):
self.assertEqual(response.status_code, 403) self.assertEqual(response.status_code, 403)
with ( with (
mock.patch("documents.views.AIConfig") as ai_config, mock.patch("documents.views.AIConfig") as ai_config,
mock.patch("documents.views.stream_chat_with_documents") as chat, mock.patch("paperless_ai.chat.stream_chat_with_documents") as chat,
): ):
ai_config.return_value.ai_enabled = True ai_config.return_value.ai_enabled = True
response = self.client.post( response = self.client.post(
+1 -1
View File
@@ -2686,7 +2686,7 @@ class TestDocumentApi(DirectoriesMixin, ConsumeTaskMixin, APITestCase):
response = self.client.get("/api/documents/34676/suggestions/") response = self.client.get("/api/documents/34676/suggestions/")
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
@mock.patch("documents.views.get_ai_document_classification") @mock.patch("paperless_ai.ai_classifier.get_ai_document_classification")
@override_settings(AI_ENABLED=True) @override_settings(AI_ENABLED=True)
def test_suggestions_still_uses_classifier_when_ai_enabled( def test_suggestions_still_uses_classifier_when_ai_enabled(
self, self,
+29
View File
@@ -308,3 +308,32 @@ class TestBulkDownloadSchema:
def test_bulk_download_response_403(self, api_schema: SchemaGenerator) -> None: def test_bulk_download_response_403(self, api_schema: SchemaGenerator) -> None:
op = api_schema["paths"]["/api/documents/bulk_download/"]["post"] op = api_schema["paths"]["/api/documents/bulk_download/"]["post"]
assert "403" in op["responses"] assert "403" in op["responses"]
class TestDocumentListObjectFilterSchema:
"""documents_list: comma-separated ObjectFilter params must be typed as integer arrays."""
@pytest.mark.parametrize(
"param_name",
[
"tags__id__all",
"tags__id__none",
"tags__id__in",
"correspondent__id__none",
"document_type__id__none",
"storage_path__id__none",
"owner__id__none",
"custom_fields__id__all",
"custom_fields__id__none",
"custom_fields__id__in",
],
)
def test_object_filter_param_is_integer_array(
self,
api_schema: SchemaGenerator,
param_name: str,
) -> None:
params = api_schema["paths"]["/api/documents/"]["get"]["parameters"]
param = next(p for p in params if p["name"] == param_name)
assert param["schema"] == {"type": "array", "items": {"type": "integer"}}
assert param["explode"] is False
@@ -572,7 +572,7 @@ class TestAiChatAllDocumentsPermissionBoundary:
ENDPOINT = "/api/documents/chat/" ENDPOINT = "/api/documents/chat/"
@override_settings(AI_ENABLED=True) @override_settings(AI_ENABLED=True)
@patch("documents.views.stream_chat_with_documents") @patch("paperless_ai.chat.stream_chat_with_documents")
def test_chat_all_documents_excludes_unshared_document(self, mock_stream_chat): def test_chat_all_documents_excludes_unshared_document(self, mock_stream_chat):
mock_stream_chat.return_value = iter([b"data"]) mock_stream_chat.return_value = iter([b"data"])
-104
View File
@@ -1,104 +0,0 @@
from django.core.exceptions import FieldDoesNotExist
from django.db import connection
from django.test import TestCase
from django.test.utils import CaptureQueriesContext
from documents.management.commands.document_importer import _deserialize_record
from documents.models import Tag
from documents.tag_hierarchy import TagHierarchy
from paperless_testing.migrations import TestMigrations
class TestTagAdjacency(TestCase):
def test_held_instance_uses_current_parent_edges(self):
first = Tag.objects.create(name="First")
second = Tag.objects.create(name="Second")
child = Tag.objects.create(name="Child", tn_parent=first)
Tag.objects.filter(pk=child.pk).update(tn_parent=second)
assert first.get_descendants_pks() == set()
assert second.get_descendants_pks() == {child.pk}
def test_queryset_delete_preserves_cascade(self):
root = Tag.objects.create(name="Root")
child = Tag.objects.create(name="Child", tn_parent=root)
Tag.objects.create(name="Grandchild", tn_parent=child)
survivor = Tag.objects.create(name="Other root")
Tag.objects.filter(pk=root.pk).delete()
assert list(Tag.objects.values_list("pk", flat=True)) == [survivor.pk]
def test_flat_writes_do_not_update_other_tags(self):
Tag.objects.bulk_create([Tag(name=f"Tag {i}") for i in range(100)])
with CaptureQueriesContext(connection) as queries:
new = Tag.objects.create(name="New")
assert not any(q["sql"].startswith("UPDATE") for q in queries)
with CaptureQueriesContext(connection) as queries:
new.name = "Renamed"
new.save()
tag_updates = [
q["sql"] for q in queries if q["sql"].startswith('UPDATE "documents_tag"')
]
assert len(tag_updates) == 1
assert 'WHERE "documents_tag"."id" =' in tag_updates[0]
def test_batch_snapshot_is_one_query_and_includes_overlapping_roots(self):
root = Tag.objects.create(name="Root")
child = Tag.objects.create(name="Child", tn_parent=root)
leaf = Tag.objects.create(name="Leaf", tn_parent=child)
with self.assertNumQueries(1):
hierarchy = Tag.get_hierarchy()
assert hierarchy.with_ancestors([leaf.pk]) == {root.pk, child.pk, leaf.pk}
assert hierarchy.with_descendants([root.pk, child.pk]) == {
root.pk,
child.pk,
leaf.pk,
}
assert hierarchy.height(None) == 0
def test_legacy_export_fields_are_ignored_but_parent_is_preserved(self):
model, tag, m2m = _deserialize_record(
{
"model": "documents.tag",
"pk": 2,
"fields": {
"name": "Child",
"tn_parent": 1,
"tn_order": 3,
"tn_siblings_pks": "4,5",
"tn_descendants_pks": "6",
},
},
)
assert model is Tag
assert tag.tn_parent_id == 1
assert tag.name == "Child"
assert not m2m
with self.assertRaises(FieldDoesNotExist):
_deserialize_record(
{"model": "documents.tag", "pk": 3, "fields": {"tn_typo": "bad"}},
)
def test_malformed_cycles_terminate(self):
hierarchy = TagHierarchy([(1, 2), (2, 1)])
assert hierarchy.with_descendants([1]) == {1, 2}
assert set(hierarchy.ancestors(2)) == {1, 2}
class TestTagAdjacencyMigration(TestMigrations):
migrate_from = "0027_documentbarcode"
migrate_to = "0028_replace_tag_tree_fields"
def setUpBeforeMigration(self, apps):
tag = apps.get_model("documents", "Tag")
root = tag.objects.create(name="Root")
child = tag.objects.create(name="Child", tn_parent=root)
self.edges = [(root.pk, None), (child.pk, root.pk)]
def test_parent_edges_survive(self):
tag = self.apps.get_model("documents", "Tag")
assert (
list(tag.objects.order_by("pk").values_list("pk", "tn_parent_id"))
== self.edges
)
assert {
field.name for field in tag._meta.fields if field.name.startswith("tn_")
} == {"tn_parent"}
+4 -4
View File
@@ -322,7 +322,7 @@ class TestUpdateContent(DirectoriesMixin, TestCase):
) )
@override_settings(AI_ENABLED=True, LLM_EMBEDDING_BACKEND="huggingface") @override_settings(AI_ENABLED=True, LLM_EMBEDDING_BACKEND="huggingface")
@mock.patch("documents.tasks.llm_index_add_or_update_document") @mock.patch("paperless_ai.indexing.llm_index_add_or_update_document")
@mock.patch("documents.search.get_backend") @mock.patch("documents.search.get_backend")
def test_update_content_version_updates_llm_index( def test_update_content_version_updates_llm_index(
self, self,
@@ -450,7 +450,7 @@ class TestAIIndex(DirectoriesMixin, TestCase):
checksum="wow", checksum="wow",
) )
with mock.patch( with mock.patch(
"documents.tasks.llm_index_add_or_update_document", "paperless_ai.indexing.llm_index_add_or_update_document",
) as llm_index_add_or_update_document: ) as llm_index_add_or_update_document:
tasks.update_document_in_llm_index(doc) tasks.update_document_in_llm_index(doc)
llm_index_add_or_update_document.assert_called_once_with(doc) llm_index_add_or_update_document.assert_called_once_with(doc)
@@ -470,7 +470,7 @@ class TestAIIndex(DirectoriesMixin, TestCase):
checksum="wow", checksum="wow",
) )
with mock.patch( with mock.patch(
"documents.tasks.llm_index_remove_document", "paperless_ai.indexing.llm_index_remove_document",
) as llm_index_remove_document: ) as llm_index_remove_document:
tasks.remove_document_from_llm_index(doc) tasks.remove_document_from_llm_index(doc)
llm_index_remove_document.assert_called_once_with(doc) llm_index_remove_document.assert_called_once_with(doc)
@@ -495,7 +495,7 @@ class TestAIIndex(DirectoriesMixin, TestCase):
"documents.tasks.update_document_in_llm_index", "documents.tasks.update_document_in_llm_index",
) as update_document_in_llm_index, ) as update_document_in_llm_index,
mock.patch( mock.patch(
"documents.tasks.update_llm_index", "paperless_ai.indexing.update_llm_index",
) as update_llm_index, ) as update_llm_index,
): ):
doc_ids = [doc.pk for doc in docs] doc_ids = [doc.pk for doc in docs]
+16 -16
View File
@@ -474,7 +474,7 @@ class TestAISuggestions(DirectoriesMixin, TestCase):
self.assertEqual(response.json()["tags"], []) self.assertEqual(response.json()["tags"], [])
self.assertEqual(response.json()["suggested_tags"], []) self.assertEqual(response.json()["suggested_tags"], [])
@patch("documents.views.get_ai_document_classification") @patch("paperless_ai.ai_classifier.get_ai_document_classification")
@override_settings( @override_settings(
AI_ENABLED=True, AI_ENABLED=True,
LLM_BACKEND="mock_backend", LLM_BACKEND="mock_backend",
@@ -524,7 +524,7 @@ class TestAISuggestions(DirectoriesMixin, TestCase):
None, None,
) )
@patch("documents.views.get_ai_document_classification") @patch("paperless_ai.ai_classifier.get_ai_document_classification")
@override_settings( @override_settings(
AI_ENABLED=True, AI_ENABLED=True,
LLM_BACKEND="mock_backend", LLM_BACKEND="mock_backend",
@@ -562,7 +562,7 @@ class TestAISuggestions(DirectoriesMixin, TestCase):
"KI Title", "KI Title",
) )
@patch("documents.views.get_ai_document_classification") @patch("paperless_ai.ai_classifier.get_ai_document_classification")
@override_settings( @override_settings(
AI_ENABLED=True, AI_ENABLED=True,
LLM_BACKEND="mock_backend", LLM_BACKEND="mock_backend",
@@ -601,7 +601,7 @@ class TestAISuggestions(DirectoriesMixin, TestCase):
"Titre IA", "Titre IA",
) )
@patch("documents.views.get_ai_document_classification") @patch("paperless_ai.ai_classifier.get_ai_document_classification")
@override_settings( @override_settings(
AI_ENABLED=True, AI_ENABLED=True,
LLM_BACKEND="mock_backend", LLM_BACKEND="mock_backend",
@@ -637,7 +637,7 @@ class TestAISuggestions(DirectoriesMixin, TestCase):
), ),
) )
@patch("documents.views.get_ai_document_classification") @patch("paperless_ai.ai_classifier.get_ai_document_classification")
@override_settings( @override_settings(
AI_ENABLED=True, AI_ENABLED=True,
LLM_BACKEND="mock_backend", LLM_BACKEND="mock_backend",
@@ -709,7 +709,7 @@ class TestAISuggestions(DirectoriesMixin, TestCase):
), ),
) )
@patch("documents.views.get_ai_document_classification") @patch("paperless_ai.ai_classifier.get_ai_document_classification")
@override_settings( @override_settings(
AI_ENABLED=True, AI_ENABLED=True,
LLM_BACKEND="openai-like", LLM_BACKEND="openai-like",
@@ -738,7 +738,7 @@ class TestAISuggestions(DirectoriesMixin, TestCase):
get_llm_suggestion_cache(self.document.pk, backend="openai-like"), get_llm_suggestion_cache(self.document.pk, backend="openai-like"),
) )
@patch("documents.views.get_ai_document_classification") @patch("paperless_ai.ai_classifier.get_ai_document_classification")
@override_settings( @override_settings(
AI_ENABLED=True, AI_ENABLED=True,
LLM_BACKEND="openai-like", LLM_BACKEND="openai-like",
@@ -765,7 +765,7 @@ class TestAISuggestions(DirectoriesMixin, TestCase):
get_llm_suggestion_cache(self.document.pk, backend="openai-like"), get_llm_suggestion_cache(self.document.pk, backend="openai-like"),
) )
@patch("documents.views.get_ai_document_classification") @patch("paperless_ai.ai_classifier.get_ai_document_classification")
@override_settings( @override_settings(
AI_ENABLED=True, AI_ENABLED=True,
LLM_BACKEND="openai-like", LLM_BACKEND="openai-like",
@@ -797,7 +797,7 @@ class TestAISuggestions(DirectoriesMixin, TestCase):
get_llm_suggestion_cache(self.document.pk, backend="openai-like"), get_llm_suggestion_cache(self.document.pk, backend="openai-like"),
) )
@patch("documents.views.get_ai_document_classification") @patch("paperless_ai.ai_classifier.get_ai_document_classification")
@override_settings( @override_settings(
AI_ENABLED=True, AI_ENABLED=True,
LLM_BACKEND="mock_backend", LLM_BACKEND="mock_backend",
@@ -835,7 +835,7 @@ class TestAISuggestions(DirectoriesMixin, TestCase):
self.assertEqual(response.json()["tags"], [self.tag1.pk]) self.assertEqual(response.json()["tags"], [self.tag1.pk])
self.assertEqual(response.json()["suggested_tags"], ["Follow-up"]) self.assertEqual(response.json()["suggested_tags"], ["Follow-up"])
@patch("documents.views.get_ai_document_classification") @patch("paperless_ai.ai_classifier.get_ai_document_classification")
@override_settings( @override_settings(
AI_ENABLED=True, AI_ENABLED=True,
LLM_BACKEND="mock_backend", LLM_BACKEND="mock_backend",
@@ -874,7 +874,7 @@ class TestAISuggestions(DirectoriesMixin, TestCase):
self.assertEqual(response.json()["tags"], [self.tag1.pk]) self.assertEqual(response.json()["tags"], [self.tag1.pk])
self.assertEqual(response.json()["suggested_tags"], []) self.assertEqual(response.json()["suggested_tags"], [])
@patch("documents.views.get_ai_document_classification") @patch("paperless_ai.ai_classifier.get_ai_document_classification")
@override_settings( @override_settings(
AI_ENABLED=True, AI_ENABLED=True,
LLM_BACKEND="mock_backend", LLM_BACKEND="mock_backend",
@@ -996,7 +996,7 @@ class TestAIChatStreamingView(DirectoriesMixin, TestCase):
self.assertEqual(response.status_code, 400) self.assertEqual(response.status_code, 400)
self.assertIn(b"AI is required for this feature", response.content) self.assertIn(b"AI is required for this feature", response.content)
@patch("documents.views.stream_chat_with_documents") @patch("paperless_ai.chat.stream_chat_with_documents")
@patch("documents.views.permitted_document_ids") @patch("documents.views.permitted_document_ids")
@override_settings(AI_ENABLED=True) @override_settings(AI_ENABLED=True)
def test_post_no_document_id(self, mock_permitted_ids, mock_stream_chat) -> None: def test_post_no_document_id(self, mock_permitted_ids, mock_stream_chat) -> None:
@@ -1016,7 +1016,7 @@ class TestAIChatStreamingView(DirectoriesMixin, TestCase):
self.assertEqual(list(call_kwargs["documents"]), [self.document]) self.assertEqual(list(call_kwargs["documents"]), [self.document])
self.assertIsNone(call_kwargs["output_language"]) self.assertIsNone(call_kwargs["output_language"])
@patch("documents.views.stream_chat_with_documents") @patch("paperless_ai.chat.stream_chat_with_documents")
@patch("documents.views.permitted_document_ids") @patch("documents.views.permitted_document_ids")
@override_settings(AI_ENABLED=True) @override_settings(AI_ENABLED=True)
def test_post_uses_user_display_language( def test_post_uses_user_display_language(
@@ -1042,7 +1042,7 @@ class TestAIChatStreamingView(DirectoriesMixin, TestCase):
self.assertEqual(list(call_kwargs["documents"]), [self.document]) self.assertEqual(list(call_kwargs["documents"]), [self.document])
self.assertEqual(call_kwargs["output_language"], "de-de") self.assertEqual(call_kwargs["output_language"], "de-de")
@patch("documents.views.stream_chat_with_documents") @patch("paperless_ai.chat.stream_chat_with_documents")
@override_settings(AI_ENABLED=True) @override_settings(AI_ENABLED=True)
def test_post_with_document_id(self, mock_stream_chat) -> None: def test_post_with_document_id(self, mock_stream_chat) -> None:
self.grant_view_document_permission() self.grant_view_document_permission()
@@ -1079,7 +1079,7 @@ class TestAIChatStreamingView(DirectoriesMixin, TestCase):
self.assertEqual(response.status_code, 403) self.assertEqual(response.status_code, 403)
self.assertIn(b"Insufficient permissions", response.content) self.assertIn(b"Insufficient permissions", response.content)
@patch("documents.views.stream_chat_with_documents") @patch("paperless_ai.chat.stream_chat_with_documents")
@override_settings(AI_ENABLED=True) @override_settings(AI_ENABLED=True)
def test_post_no_document_id_requires_view_document_permission( def test_post_no_document_id_requires_view_document_permission(
self, self,
@@ -1093,7 +1093,7 @@ class TestAIChatStreamingView(DirectoriesMixin, TestCase):
self.assertEqual(response.status_code, 403) self.assertEqual(response.status_code, 403)
mock_stream_chat.assert_not_called() mock_stream_chat.assert_not_called()
@patch("documents.views.stream_chat_with_documents") @patch("paperless_ai.chat.stream_chat_with_documents")
@override_settings(AI_ENABLED=True) @override_settings(AI_ENABLED=True)
def test_post_with_document_id_requires_view_document_permission( def test_post_with_document_id_requires_view_document_permission(
self, self,
+33 -27
View File
@@ -250,20 +250,8 @@ from paperless.parsers.remote import RemoteEngineConfig
from paperless.serialisers import GroupSerializer from paperless.serialisers import GroupSerializer
from paperless.serialisers import UserSerializer from paperless.serialisers import UserSerializer
from paperless.views import StandardPagination from paperless.views import StandardPagination
from paperless_ai.ai_classifier import get_ai_document_classification
from paperless_ai.ai_classifier import get_llm_output_language
from paperless_ai.chat import stream_chat_with_documents
from paperless_ai.exceptions import LLMProviderError from paperless_ai.exceptions import LLMProviderError
from paperless_ai.exceptions import LLMTimeoutError from paperless_ai.exceptions import LLMTimeoutError
from paperless_ai.matching import extract_unmatched_names
from paperless_ai.matching import match_correspondents_by_name
from paperless_ai.matching import match_document_types_by_name
from paperless_ai.matching import match_storage_paths_by_name
from paperless_ai.matching import match_tags_by_name
from paperless_ai.matching import resolve_correspondent_ids
from paperless_ai.matching import resolve_document_type_ids
from paperless_ai.matching import resolve_storage_path_ids
from paperless_ai.matching import resolve_tag_ids
from paperless_mail.models import MailAccount from paperless_mail.models import MailAccount
from paperless_mail.models import MailRule from paperless_mail.models import MailRule
from paperless_mail.oauth import PaperlessMailOAuth2Manager from paperless_mail.oauth import PaperlessMailOAuth2Manager
@@ -627,7 +615,7 @@ class TagViewSet(PermissionsAwareDocumentCountMixin, ModelViewSet[Tag]):
queryset = queryset.order_by(*ordering) queryset = queryset.order_by(*ordering)
all_tags = list(queryset) all_tags = list(queryset)
descendant_pks = Tag.get_hierarchy().descendants(t.pk for t in all_tags) descendant_pks = {pk for tag in all_tags for pk in tag.get_descendants_pks()}
if descendant_pks: if descendant_pks:
user = getattr(getattr(self, "request", None), "user", None) user = getattr(getattr(self, "request", None), "user", None)
@@ -699,19 +687,6 @@ class EmailDocumentDetailSchema(EmailSerializer):
@extend_schema_view( @extend_schema_view(
list=extend_schema(
parameters=[
OpenApiParameter(
name=name,
type=OpenApiTypes.INT,
many=True,
style="form",
explode=False,
)
for name, field in DocumentFilterSet.base_filters.items()
if isinstance(field, ObjectFilter)
],
),
retrieve=extend_schema( retrieve=extend_schema(
description="Retrieve a single document", description="Retrieve a single document",
responses={ responses={
@@ -1613,6 +1588,18 @@ class DocumentViewSet(
if not ai_config.ai_enabled: if not ai_config.ai_enabled:
return HttpResponseBadRequest("AI is required for this feature") return HttpResponseBadRequest("AI is required for this feature")
from paperless_ai.ai_classifier import get_ai_document_classification
from paperless_ai.ai_classifier import get_llm_output_language
from paperless_ai.matching import extract_unmatched_names
from paperless_ai.matching import match_correspondents_by_name
from paperless_ai.matching import match_document_types_by_name
from paperless_ai.matching import match_storage_paths_by_name
from paperless_ai.matching import match_tags_by_name
from paperless_ai.matching import resolve_correspondent_ids
from paperless_ai.matching import resolve_document_type_ids
from paperless_ai.matching import resolve_storage_path_ids
from paperless_ai.matching import resolve_tag_ids
output_language = get_llm_output_language( output_language = get_llm_output_language(
ai_config=ai_config, ai_config=ai_config,
user=request.user, user=request.user,
@@ -2446,6 +2433,9 @@ class ChatStreamingView(GenericAPIView[Any]):
) )
unrestricted = user_is_unrestricted(request.user) unrestricted = user_is_unrestricted(request.user)
from paperless_ai.ai_classifier import get_llm_output_language
from paperless_ai.chat import stream_chat_with_documents
output_language = get_llm_output_language( output_language = get_llm_output_language(
ai_config=ai_config, ai_config=ai_config,
user=request.user, user=request.user,
@@ -2467,6 +2457,17 @@ class ChatStreamingView(GenericAPIView[Any]):
list=extend_schema( list=extend_schema(
description="Document views including search", description="Document views including search",
parameters=[ parameters=[
*(
OpenApiParameter(
name=name,
type=OpenApiTypes.INT,
many=True,
style="form",
explode=False,
)
for name, field in DocumentFilterSet.base_filters.items()
if isinstance(field, ObjectFilter)
),
OpenApiParameter( OpenApiParameter(
name="text", name="text",
type=OpenApiTypes.STR, type=OpenApiTypes.STR,
@@ -5060,7 +5061,12 @@ class BulkEditObjectsView(PassUserMixin):
if object_type == "tags": if object_type == "tags":
editable_ids = set(user_permitted_objects.values_list("pk", flat=True)) editable_ids = set(user_permitted_objects.values_list("pk", flat=True))
all_ids = set(objs.values_list("pk", flat=True)) all_ids = set(objs.values_list("pk", flat=True))
all_ids.update(Tag.get_hierarchy().descendants(all_ids) & editable_ids) for tag in objs:
all_ids.update(
descendant.pk
for descendant in tag.get_descendants()
if descendant.pk in editable_ids
)
objs = object_class.objects.filter(pk__in=all_ids) objs = object_class.objects.filter(pk__in=all_ids)
objs = objs.select_related("owner") objs = objs.select_related("owner")
object_ids = list(objs.values_list("pk", flat=True)) object_ids = list(objs.values_list("pk", flat=True))
+12 -10
View File
@@ -6,7 +6,6 @@ from guardian.shortcuts import remove_perm
from documents.data_models import DocumentMetadataOverrides from documents.data_models import DocumentMetadataOverrides
from documents.models import CustomFieldInstance from documents.models import CustomFieldInstance
from documents.models import Document from documents.models import Document
from documents.models import Tag
from documents.models import WorkflowAction from documents.models import WorkflowAction
from documents.permissions import PermissionsSpec from documents.permissions import PermissionsSpec
from documents.permissions import set_permissions_for_objects from documents.permissions import set_permissions_for_objects
@@ -135,9 +134,10 @@ def apply_assignment_to_overrides(
if action.has_assign_tags: if action.has_assign_tags:
if overrides.tag_ids is None: if overrides.tag_ids is None:
overrides.tag_ids = [] overrides.tag_ids = []
tag_ids_to_add = Tag.get_hierarchy().with_ancestors( tag_ids_to_add: set[int] = set()
tag.pk for tag in action.assign_tags.all() for tag in action.assign_tags.all():
) tag_ids_to_add.add(tag.pk)
tag_ids_to_add.update(int(pk) for pk in tag.get_ancestors_pks())
overrides.tag_ids = list(set(overrides.tag_ids) | tag_ids_to_add) overrides.tag_ids = list(set(overrides.tag_ids) | tag_ids_to_add)
@@ -216,9 +216,10 @@ def apply_removal_to_document(
if action.remove_all_tags: if action.remove_all_tags:
Document.objects.get(pk=document.pk).tags.clear() Document.objects.get(pk=document.pk).tags.clear()
else: else:
tag_ids_to_remove = Tag.get_hierarchy().with_descendants( tag_ids_to_remove: set[int] = set()
tag.pk for tag in action.remove_tags.all() for tag in action.remove_tags.all():
) tag_ids_to_remove.add(tag.pk)
tag_ids_to_remove.update(int(pk) for pk in tag.get_descendants_pks())
if tag_ids_to_remove: if tag_ids_to_remove:
Document.objects.get(pk=document.pk).tags.remove(*tag_ids_to_remove) Document.objects.get(pk=document.pk).tags.remove(*tag_ids_to_remove)
@@ -296,9 +297,10 @@ def apply_removal_to_overrides(
if action.remove_all_tags: if action.remove_all_tags:
overrides.tag_ids = None overrides.tag_ids = None
elif overrides.tag_ids: elif overrides.tag_ids:
tag_ids_to_remove = Tag.get_hierarchy().with_descendants( tag_ids_to_remove: set[int] = set()
tag.pk for tag in action.remove_tags.all() for tag in action.remove_tags.all():
) tag_ids_to_remove.add(tag.pk)
tag_ids_to_remove.update(int(pk) for pk in tag.get_descendants_pks())
overrides.tag_ids = [t for t in overrides.tag_ids if t not in tag_ids_to_remove] overrides.tag_ids = [t for t in overrides.tag_ids if t not in tag_ids_to_remove]
+23 -23
View File
@@ -2,8 +2,8 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: paperless-ngx\n" "Project-Id-Version: paperless-ngx\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-10-29 17:25+0000\n" "POT-Creation-Date: 2026-10-31 04:47+0000\n"
"PO-Revision-Date: 2026-10-29 17:27\n" "PO-Revision-Date: 2026-10-31 04:48\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Afrikaans\n" "Language-Team: Afrikaans\n"
"Language: af_ZA\n" "Language: af_ZA\n"
@@ -21,43 +21,43 @@ msgstr ""
msgid "Documents" msgid "Documents"
msgstr "Dokumente" msgstr "Dokumente"
#: documents/filters.py:337 #: documents/filters.py:336
msgid "Expected a date or a relative date such as \"today\" or \"in 30 days\"." msgid "Expected a date or a relative date such as \"today\" or \"in 30 days\"."
msgstr "" msgstr ""
#: documents/filters.py:513 #: documents/filters.py:514
msgid "Value must be valid JSON." msgid "Value must be valid JSON."
msgstr "Waarde moet geldige JSON wees." msgstr "Waarde moet geldige JSON wees."
#: documents/filters.py:534 #: documents/filters.py:535
msgid "Invalid custom field query expression" msgid "Invalid custom field query expression"
msgstr "Ongeldige gepasmaakte veldnavraaguitdrukking" msgstr "Ongeldige gepasmaakte veldnavraaguitdrukking"
#: documents/filters.py:544 #: documents/filters.py:545
msgid "Invalid expression list. Must be nonempty." msgid "Invalid expression list. Must be nonempty."
msgstr "Ongeldige uitdrukking lys. Moet nie leeg wees nie." msgstr "Ongeldige uitdrukking lys. Moet nie leeg wees nie."
#: documents/filters.py:565 #: documents/filters.py:566
msgid "Invalid logical operator {op!r}" msgid "Invalid logical operator {op!r}"
msgstr "Ongeldige logiese uitdrukking {op!r}" msgstr "Ongeldige logiese uitdrukking {op!r}"
#: documents/filters.py:579 #: documents/filters.py:580
msgid "Maximum number of query conditions exceeded." msgid "Maximum number of query conditions exceeded."
msgstr "" msgstr ""
#: documents/filters.py:643 #: documents/filters.py:644
msgid "{name!r} is not a valid custom field." msgid "{name!r} is not a valid custom field."
msgstr "" msgstr ""
#: documents/filters.py:680 #: documents/filters.py:681
msgid "{data_type} does not support query expr {expr!r}." msgid "{data_type} does not support query expr {expr!r}."
msgstr "" msgstr ""
#: documents/filters.py:801 documents/models.py:137 #: documents/filters.py:802 documents/models.py:137
msgid "Maximum nesting depth exceeded." msgid "Maximum nesting depth exceeded."
msgstr "" msgstr ""
#: documents/filters.py:1178 #: documents/filters.py:1179
msgid "Custom field not found" msgid "Custom field not found"
msgstr "" msgstr ""
@@ -1640,7 +1640,7 @@ msgid "workflow runs"
msgstr "" msgstr ""
#: documents/serialisers.py:483 documents/serialisers.py:840 #: documents/serialisers.py:483 documents/serialisers.py:840
#: documents/serialisers.py:2872 documents/views.py:360 documents/views.py:2730 #: documents/serialisers.py:2872 documents/views.py:348 documents/views.py:2731
#: paperless_mail/serialisers.py:156 #: paperless_mail/serialisers.py:156
msgid "Insufficient permissions." msgid "Insufficient permissions."
msgstr "" msgstr ""
@@ -1680,7 +1680,7 @@ msgstr "Ongeldige veranderlike bespeur."
msgid "Duplicate document identifiers are not allowed." msgid "Duplicate document identifiers are not allowed."
msgstr "" msgstr ""
#: documents/serialisers.py:2958 documents/views.py:4780 #: documents/serialisers.py:2958 documents/views.py:4781
#, python-format #, python-format
msgid "Documents not found: %(ids)s" msgid "Documents not found: %(ids)s"
msgstr "" msgstr ""
@@ -1920,40 +1920,40 @@ msgstr ""
msgid ", " msgid ", "
msgstr "" msgstr ""
#: documents/views.py:315 #: documents/views.py:303
msgid "Specify only one of text, title_search, query, or more_like_id." msgid "Specify only one of text, title_search, query, or more_like_id."
msgstr "" msgstr ""
#: documents/views.py:353 documents/views.py:2727 #: documents/views.py:341 documents/views.py:2728
msgid "Invalid more_like_id" msgid "Invalid more_like_id"
msgstr "" msgstr ""
#: documents/views.py:1665 #: documents/views.py:1652
msgid "Invalid AI configuration." msgid "Invalid AI configuration."
msgstr "" msgstr ""
#: documents/views.py:1676 #: documents/views.py:1663
msgid "AI backend request timed out." msgid "AI backend request timed out."
msgstr "" msgstr ""
#: documents/views.py:1688 #: documents/views.py:1675
msgid "AI backend rejected the request. Check logs for details." msgid "AI backend rejected the request. Check logs for details."
msgstr "" msgstr ""
#: documents/views.py:4796 #: documents/views.py:4797
#, python-format #, python-format
msgid "Insufficient permissions to share document %(id)s." msgid "Insufficient permissions to share document %(id)s."
msgstr "" msgstr ""
#: documents/views.py:4843 #: documents/views.py:4844
msgid "Bundle is already being processed." msgid "Bundle is already being processed."
msgstr "" msgstr ""
#: documents/views.py:4909 #: documents/views.py:4910
msgid "The share link bundle is still being prepared. Please try again later." msgid "The share link bundle is still being prepared. Please try again later."
msgstr "" msgstr ""
#: documents/views.py:4923 #: documents/views.py:4924
msgid "The share link bundle is unavailable." msgid "The share link bundle is unavailable."
msgstr "" msgstr ""
+23 -23
View File
@@ -2,8 +2,8 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: paperless-ngx\n" "Project-Id-Version: paperless-ngx\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-10-29 17:25+0000\n" "POT-Creation-Date: 2026-10-31 04:47+0000\n"
"PO-Revision-Date: 2026-10-29 17:27\n" "PO-Revision-Date: 2026-10-31 04:48\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Amharic\n" "Language-Team: Amharic\n"
"Language: am_ET\n" "Language: am_ET\n"
@@ -21,43 +21,43 @@ msgstr ""
msgid "Documents" msgid "Documents"
msgstr "መዝገባት" msgstr "መዝገባት"
#: documents/filters.py:337 #: documents/filters.py:336
msgid "Expected a date or a relative date such as \"today\" or \"in 30 days\"." msgid "Expected a date or a relative date such as \"today\" or \"in 30 days\"."
msgstr "" msgstr ""
#: documents/filters.py:513 #: documents/filters.py:514
msgid "Value must be valid JSON." msgid "Value must be valid JSON."
msgstr "የሚሰራው እሴት \"JSON\" መሆን አለበት" msgstr "የሚሰራው እሴት \"JSON\" መሆን አለበት"
#: documents/filters.py:534 #: documents/filters.py:535
msgid "Invalid custom field query expression" msgid "Invalid custom field query expression"
msgstr "ልክ ያልሆነ የተወሰነ የቦታ መጠይቅ አገላለጽ" msgstr "ልክ ያልሆነ የተወሰነ የቦታ መጠይቅ አገላለጽ"
#: documents/filters.py:544 #: documents/filters.py:545
msgid "Invalid expression list. Must be nonempty." msgid "Invalid expression list. Must be nonempty."
msgstr "ልክ ያልሆነ የመግለጫ ዝርዝር። ባዶ መሆን የለበትም።" msgstr "ልክ ያልሆነ የመግለጫ ዝርዝር። ባዶ መሆን የለበትም።"
#: documents/filters.py:565 #: documents/filters.py:566
msgid "Invalid logical operator {op!r}" msgid "Invalid logical operator {op!r}"
msgstr "ልክ ያልሆነ የሎጂክ ኦፕሬተር {op!r}" msgstr "ልክ ያልሆነ የሎጂክ ኦፕሬተር {op!r}"
#: documents/filters.py:579 #: documents/filters.py:580
msgid "Maximum number of query conditions exceeded." msgid "Maximum number of query conditions exceeded."
msgstr "ከፍተኛው የጥያቄ ሁኔታዎች/መጠን ብዛት አልፏል።" msgstr "ከፍተኛው የጥያቄ ሁኔታዎች/መጠን ብዛት አልፏል።"
#: documents/filters.py:643 #: documents/filters.py:644
msgid "{name!r} is not a valid custom field." msgid "{name!r} is not a valid custom field."
msgstr "{name!r} ይሄ ታዐማኒነት ያለው ልማድ አይደለም።" msgstr "{name!r} ይሄ ታዐማኒነት ያለው ልማድ አይደለም።"
#: documents/filters.py:680 #: documents/filters.py:681
msgid "{data_type} does not support query expr {expr!r}." msgid "{data_type} does not support query expr {expr!r}."
msgstr "ጥያቄን አይደግፍም expr {expr!r}." msgstr "ጥያቄን አይደግፍም expr {expr!r}."
#: documents/filters.py:801 documents/models.py:137 #: documents/filters.py:802 documents/models.py:137
msgid "Maximum nesting depth exceeded." msgid "Maximum nesting depth exceeded."
msgstr "ከፍተኛው የጥገኝነት ጥልቀት አልፏል።" msgstr "ከፍተኛው የጥገኝነት ጥልቀት አልፏል።"
#: documents/filters.py:1178 #: documents/filters.py:1179
msgid "Custom field not found" msgid "Custom field not found"
msgstr "ይህ ልማድ አልተገኘም" msgstr "ይህ ልማድ አልተገኘም"
@@ -1640,7 +1640,7 @@ msgid "workflow runs"
msgstr "" msgstr ""
#: documents/serialisers.py:483 documents/serialisers.py:840 #: documents/serialisers.py:483 documents/serialisers.py:840
#: documents/serialisers.py:2872 documents/views.py:360 documents/views.py:2730 #: documents/serialisers.py:2872 documents/views.py:348 documents/views.py:2731
#: paperless_mail/serialisers.py:156 #: paperless_mail/serialisers.py:156
msgid "Insufficient permissions." msgid "Insufficient permissions."
msgstr "" msgstr ""
@@ -1680,7 +1680,7 @@ msgstr ""
msgid "Duplicate document identifiers are not allowed." msgid "Duplicate document identifiers are not allowed."
msgstr "" msgstr ""
#: documents/serialisers.py:2958 documents/views.py:4780 #: documents/serialisers.py:2958 documents/views.py:4781
#, python-format #, python-format
msgid "Documents not found: %(ids)s" msgid "Documents not found: %(ids)s"
msgstr "" msgstr ""
@@ -1920,40 +1920,40 @@ msgstr ""
msgid ", " msgid ", "
msgstr "" msgstr ""
#: documents/views.py:315 #: documents/views.py:303
msgid "Specify only one of text, title_search, query, or more_like_id." msgid "Specify only one of text, title_search, query, or more_like_id."
msgstr "" msgstr ""
#: documents/views.py:353 documents/views.py:2727 #: documents/views.py:341 documents/views.py:2728
msgid "Invalid more_like_id" msgid "Invalid more_like_id"
msgstr "" msgstr ""
#: documents/views.py:1665 #: documents/views.py:1652
msgid "Invalid AI configuration." msgid "Invalid AI configuration."
msgstr "" msgstr ""
#: documents/views.py:1676 #: documents/views.py:1663
msgid "AI backend request timed out." msgid "AI backend request timed out."
msgstr "" msgstr ""
#: documents/views.py:1688 #: documents/views.py:1675
msgid "AI backend rejected the request. Check logs for details." msgid "AI backend rejected the request. Check logs for details."
msgstr "" msgstr ""
#: documents/views.py:4796 #: documents/views.py:4797
#, python-format #, python-format
msgid "Insufficient permissions to share document %(id)s." msgid "Insufficient permissions to share document %(id)s."
msgstr "" msgstr ""
#: documents/views.py:4843 #: documents/views.py:4844
msgid "Bundle is already being processed." msgid "Bundle is already being processed."
msgstr "" msgstr ""
#: documents/views.py:4909 #: documents/views.py:4910
msgid "The share link bundle is still being prepared. Please try again later." msgid "The share link bundle is still being prepared. Please try again later."
msgstr "" msgstr ""
#: documents/views.py:4923 #: documents/views.py:4924
msgid "The share link bundle is unavailable." msgid "The share link bundle is unavailable."
msgstr "" msgstr ""
+23 -23
View File
@@ -2,8 +2,8 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: paperless-ngx\n" "Project-Id-Version: paperless-ngx\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-10-29 17:25+0000\n" "POT-Creation-Date: 2026-10-31 04:47+0000\n"
"PO-Revision-Date: 2026-10-29 17:27\n" "PO-Revision-Date: 2026-10-31 04:48\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Arabic\n" "Language-Team: Arabic\n"
"Language: ar_SA\n" "Language: ar_SA\n"
@@ -21,43 +21,43 @@ msgstr ""
msgid "Documents" msgid "Documents"
msgstr "المستندات" msgstr "المستندات"
#: documents/filters.py:337 #: documents/filters.py:336
msgid "Expected a date or a relative date such as \"today\" or \"in 30 days\"." msgid "Expected a date or a relative date such as \"today\" or \"in 30 days\"."
msgstr "" msgstr ""
#: documents/filters.py:513 #: documents/filters.py:514
msgid "Value must be valid JSON." msgid "Value must be valid JSON."
msgstr "يجب أن تكون القيمة JSON." msgstr "يجب أن تكون القيمة JSON."
#: documents/filters.py:534 #: documents/filters.py:535
msgid "Invalid custom field query expression" msgid "Invalid custom field query expression"
msgstr "تعبير استعلام غير صالح للحقول المخصصة" msgstr "تعبير استعلام غير صالح للحقول المخصصة"
#: documents/filters.py:544 #: documents/filters.py:545
msgid "Invalid expression list. Must be nonempty." msgid "Invalid expression list. Must be nonempty."
msgstr "قائمة عبارة خاطئة." msgstr "قائمة عبارة خاطئة."
#: documents/filters.py:565 #: documents/filters.py:566
msgid "Invalid logical operator {op!r}" msgid "Invalid logical operator {op!r}"
msgstr "" msgstr ""
#: documents/filters.py:579 #: documents/filters.py:580
msgid "Maximum number of query conditions exceeded." msgid "Maximum number of query conditions exceeded."
msgstr "تجاوز الحد الأقصى لعدد شروط الاستعلام." msgstr "تجاوز الحد الأقصى لعدد شروط الاستعلام."
#: documents/filters.py:643 #: documents/filters.py:644
msgid "{name!r} is not a valid custom field." msgid "{name!r} is not a valid custom field."
msgstr "{name!r} حقل مخصص غير صالح." msgstr "{name!r} حقل مخصص غير صالح."
#: documents/filters.py:680 #: documents/filters.py:681
msgid "{data_type} does not support query expr {expr!r}." msgid "{data_type} does not support query expr {expr!r}."
msgstr "{data_type} لا يدعم تعبير الاستعلام {expr!r}." msgstr "{data_type} لا يدعم تعبير الاستعلام {expr!r}."
#: documents/filters.py:801 documents/models.py:137 #: documents/filters.py:802 documents/models.py:137
msgid "Maximum nesting depth exceeded." msgid "Maximum nesting depth exceeded."
msgstr "" msgstr ""
#: documents/filters.py:1178 #: documents/filters.py:1179
msgid "Custom field not found" msgid "Custom field not found"
msgstr "لم يتم العثور على حقل مخصص" msgstr "لم يتم العثور على حقل مخصص"
@@ -1640,7 +1640,7 @@ msgid "workflow runs"
msgstr "" msgstr ""
#: documents/serialisers.py:483 documents/serialisers.py:840 #: documents/serialisers.py:483 documents/serialisers.py:840
#: documents/serialisers.py:2872 documents/views.py:360 documents/views.py:2730 #: documents/serialisers.py:2872 documents/views.py:348 documents/views.py:2731
#: paperless_mail/serialisers.py:156 #: paperless_mail/serialisers.py:156
msgid "Insufficient permissions." msgid "Insufficient permissions."
msgstr "" msgstr ""
@@ -1680,7 +1680,7 @@ msgstr "اكتشاف متغير خاطئ."
msgid "Duplicate document identifiers are not allowed." msgid "Duplicate document identifiers are not allowed."
msgstr "" msgstr ""
#: documents/serialisers.py:2958 documents/views.py:4780 #: documents/serialisers.py:2958 documents/views.py:4781
#, python-format #, python-format
msgid "Documents not found: %(ids)s" msgid "Documents not found: %(ids)s"
msgstr "" msgstr ""
@@ -1921,40 +1921,40 @@ msgstr "كخطوة أخيرة، يرجى ملء النموذج التالي:"
msgid ", " msgid ", "
msgstr "" msgstr ""
#: documents/views.py:315 #: documents/views.py:303
msgid "Specify only one of text, title_search, query, or more_like_id." msgid "Specify only one of text, title_search, query, or more_like_id."
msgstr "" msgstr ""
#: documents/views.py:353 documents/views.py:2727 #: documents/views.py:341 documents/views.py:2728
msgid "Invalid more_like_id" msgid "Invalid more_like_id"
msgstr "" msgstr ""
#: documents/views.py:1665 #: documents/views.py:1652
msgid "Invalid AI configuration." msgid "Invalid AI configuration."
msgstr "" msgstr ""
#: documents/views.py:1676 #: documents/views.py:1663
msgid "AI backend request timed out." msgid "AI backend request timed out."
msgstr "" msgstr ""
#: documents/views.py:1688 #: documents/views.py:1675
msgid "AI backend rejected the request. Check logs for details." msgid "AI backend rejected the request. Check logs for details."
msgstr "" msgstr ""
#: documents/views.py:4796 #: documents/views.py:4797
#, python-format #, python-format
msgid "Insufficient permissions to share document %(id)s." msgid "Insufficient permissions to share document %(id)s."
msgstr "" msgstr ""
#: documents/views.py:4843 #: documents/views.py:4844
msgid "Bundle is already being processed." msgid "Bundle is already being processed."
msgstr "" msgstr ""
#: documents/views.py:4909 #: documents/views.py:4910
msgid "The share link bundle is still being prepared. Please try again later." msgid "The share link bundle is still being prepared. Please try again later."
msgstr "" msgstr ""
#: documents/views.py:4923 #: documents/views.py:4924
msgid "The share link bundle is unavailable." msgid "The share link bundle is unavailable."
msgstr "" msgstr ""
+23 -23
View File
@@ -2,8 +2,8 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: paperless-ngx\n" "Project-Id-Version: paperless-ngx\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-10-29 17:25+0000\n" "POT-Creation-Date: 2026-10-31 04:47+0000\n"
"PO-Revision-Date: 2026-10-29 17:27\n" "PO-Revision-Date: 2026-10-31 04:48\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Belarusian\n" "Language-Team: Belarusian\n"
"Language: be_BY\n" "Language: be_BY\n"
@@ -21,43 +21,43 @@ msgstr ""
msgid "Documents" msgid "Documents"
msgstr "Дакументы" msgstr "Дакументы"
#: documents/filters.py:337 #: documents/filters.py:336
msgid "Expected a date or a relative date such as \"today\" or \"in 30 days\"." msgid "Expected a date or a relative date such as \"today\" or \"in 30 days\"."
msgstr "" msgstr ""
#: documents/filters.py:513 #: documents/filters.py:514
msgid "Value must be valid JSON." msgid "Value must be valid JSON."
msgstr "" msgstr ""
#: documents/filters.py:534 #: documents/filters.py:535
msgid "Invalid custom field query expression" msgid "Invalid custom field query expression"
msgstr "" msgstr ""
#: documents/filters.py:544 #: documents/filters.py:545
msgid "Invalid expression list. Must be nonempty." msgid "Invalid expression list. Must be nonempty."
msgstr "" msgstr ""
#: documents/filters.py:565 #: documents/filters.py:566
msgid "Invalid logical operator {op!r}" msgid "Invalid logical operator {op!r}"
msgstr "" msgstr ""
#: documents/filters.py:579 #: documents/filters.py:580
msgid "Maximum number of query conditions exceeded." msgid "Maximum number of query conditions exceeded."
msgstr "" msgstr ""
#: documents/filters.py:643 #: documents/filters.py:644
msgid "{name!r} is not a valid custom field." msgid "{name!r} is not a valid custom field."
msgstr "" msgstr ""
#: documents/filters.py:680 #: documents/filters.py:681
msgid "{data_type} does not support query expr {expr!r}." msgid "{data_type} does not support query expr {expr!r}."
msgstr "" msgstr ""
#: documents/filters.py:801 documents/models.py:137 #: documents/filters.py:802 documents/models.py:137
msgid "Maximum nesting depth exceeded." msgid "Maximum nesting depth exceeded."
msgstr "" msgstr ""
#: documents/filters.py:1178 #: documents/filters.py:1179
msgid "Custom field not found" msgid "Custom field not found"
msgstr "" msgstr ""
@@ -1640,7 +1640,7 @@ msgid "workflow runs"
msgstr "" msgstr ""
#: documents/serialisers.py:483 documents/serialisers.py:840 #: documents/serialisers.py:483 documents/serialisers.py:840
#: documents/serialisers.py:2872 documents/views.py:360 documents/views.py:2730 #: documents/serialisers.py:2872 documents/views.py:348 documents/views.py:2731
#: paperless_mail/serialisers.py:156 #: paperless_mail/serialisers.py:156
msgid "Insufficient permissions." msgid "Insufficient permissions."
msgstr "" msgstr ""
@@ -1680,7 +1680,7 @@ msgstr "Выяўлена няправільная зменная."
msgid "Duplicate document identifiers are not allowed." msgid "Duplicate document identifiers are not allowed."
msgstr "" msgstr ""
#: documents/serialisers.py:2958 documents/views.py:4780 #: documents/serialisers.py:2958 documents/views.py:4781
#, python-format #, python-format
msgid "Documents not found: %(ids)s" msgid "Documents not found: %(ids)s"
msgstr "" msgstr ""
@@ -1920,40 +1920,40 @@ msgstr ""
msgid ", " msgid ", "
msgstr "" msgstr ""
#: documents/views.py:315 #: documents/views.py:303
msgid "Specify only one of text, title_search, query, or more_like_id." msgid "Specify only one of text, title_search, query, or more_like_id."
msgstr "" msgstr ""
#: documents/views.py:353 documents/views.py:2727 #: documents/views.py:341 documents/views.py:2728
msgid "Invalid more_like_id" msgid "Invalid more_like_id"
msgstr "" msgstr ""
#: documents/views.py:1665 #: documents/views.py:1652
msgid "Invalid AI configuration." msgid "Invalid AI configuration."
msgstr "" msgstr ""
#: documents/views.py:1676 #: documents/views.py:1663
msgid "AI backend request timed out." msgid "AI backend request timed out."
msgstr "" msgstr ""
#: documents/views.py:1688 #: documents/views.py:1675
msgid "AI backend rejected the request. Check logs for details." msgid "AI backend rejected the request. Check logs for details."
msgstr "" msgstr ""
#: documents/views.py:4796 #: documents/views.py:4797
#, python-format #, python-format
msgid "Insufficient permissions to share document %(id)s." msgid "Insufficient permissions to share document %(id)s."
msgstr "" msgstr ""
#: documents/views.py:4843 #: documents/views.py:4844
msgid "Bundle is already being processed." msgid "Bundle is already being processed."
msgstr "" msgstr ""
#: documents/views.py:4909 #: documents/views.py:4910
msgid "The share link bundle is still being prepared. Please try again later." msgid "The share link bundle is still being prepared. Please try again later."
msgstr "" msgstr ""
#: documents/views.py:4923 #: documents/views.py:4924
msgid "The share link bundle is unavailable." msgid "The share link bundle is unavailable."
msgstr "" msgstr ""
+23 -23
View File
@@ -2,8 +2,8 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: paperless-ngx\n" "Project-Id-Version: paperless-ngx\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-10-29 17:25+0000\n" "POT-Creation-Date: 2026-10-31 04:47+0000\n"
"PO-Revision-Date: 2026-10-29 17:27\n" "PO-Revision-Date: 2026-10-31 04:48\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Bulgarian\n" "Language-Team: Bulgarian\n"
"Language: bg_BG\n" "Language: bg_BG\n"
@@ -21,43 +21,43 @@ msgstr ""
msgid "Documents" msgid "Documents"
msgstr "Документи" msgstr "Документи"
#: documents/filters.py:337 #: documents/filters.py:336
msgid "Expected a date or a relative date such as \"today\" or \"in 30 days\"." msgid "Expected a date or a relative date such as \"today\" or \"in 30 days\"."
msgstr "" msgstr ""
#: documents/filters.py:513 #: documents/filters.py:514
msgid "Value must be valid JSON." msgid "Value must be valid JSON."
msgstr "Стойността трябва да е валидна JSON." msgstr "Стойността трябва да е валидна JSON."
#: documents/filters.py:534 #: documents/filters.py:535
msgid "Invalid custom field query expression" msgid "Invalid custom field query expression"
msgstr "Невалидна заявка на персонализираното полето" msgstr "Невалидна заявка на персонализираното полето"
#: documents/filters.py:544 #: documents/filters.py:545
msgid "Invalid expression list. Must be nonempty." msgid "Invalid expression list. Must be nonempty."
msgstr "Списък с невалиден израз. Не може да е празно." msgstr "Списък с невалиден израз. Не може да е празно."
#: documents/filters.py:565 #: documents/filters.py:566
msgid "Invalid logical operator {op!r}" msgid "Invalid logical operator {op!r}"
msgstr "Невалиден логически оператор {op!r}" msgstr "Невалиден логически оператор {op!r}"
#: documents/filters.py:579 #: documents/filters.py:580
msgid "Maximum number of query conditions exceeded." msgid "Maximum number of query conditions exceeded."
msgstr "Надвишен е максимален брой за заявки." msgstr "Надвишен е максимален брой за заявки."
#: documents/filters.py:643 #: documents/filters.py:644
msgid "{name!r} is not a valid custom field." msgid "{name!r} is not a valid custom field."
msgstr "{name!r} не е валидно персонализирано поле." msgstr "{name!r} не е валидно персонализирано поле."
#: documents/filters.py:680 #: documents/filters.py:681
msgid "{data_type} does not support query expr {expr!r}." msgid "{data_type} does not support query expr {expr!r}."
msgstr "{data_type} не поддържа заявка expr {expr!r}." msgstr "{data_type} не поддържа заявка expr {expr!r}."
#: documents/filters.py:801 documents/models.py:137 #: documents/filters.py:802 documents/models.py:137
msgid "Maximum nesting depth exceeded." msgid "Maximum nesting depth exceeded."
msgstr "Надвишена е максималната дълбочина на вмъкване." msgstr "Надвишена е максималната дълбочина на вмъкване."
#: documents/filters.py:1178 #: documents/filters.py:1179
msgid "Custom field not found" msgid "Custom field not found"
msgstr "Персонализирано поле не е намерено" msgstr "Персонализирано поле не е намерено"
@@ -1640,7 +1640,7 @@ msgid "workflow runs"
msgstr "стартиране на работните процеси" msgstr "стартиране на работните процеси"
#: documents/serialisers.py:483 documents/serialisers.py:840 #: documents/serialisers.py:483 documents/serialisers.py:840
#: documents/serialisers.py:2872 documents/views.py:360 documents/views.py:2730 #: documents/serialisers.py:2872 documents/views.py:348 documents/views.py:2731
#: paperless_mail/serialisers.py:156 #: paperless_mail/serialisers.py:156
msgid "Insufficient permissions." msgid "Insufficient permissions."
msgstr "" msgstr ""
@@ -1680,7 +1680,7 @@ msgstr "Засечена е невалидна променлива."
msgid "Duplicate document identifiers are not allowed." msgid "Duplicate document identifiers are not allowed."
msgstr "" msgstr ""
#: documents/serialisers.py:2958 documents/views.py:4780 #: documents/serialisers.py:2958 documents/views.py:4781
#, python-format #, python-format
msgid "Documents not found: %(ids)s" msgid "Documents not found: %(ids)s"
msgstr "" msgstr ""
@@ -1921,40 +1921,40 @@ msgstr "Като последна стъпка, моля, попълнете с
msgid ", " msgid ", "
msgstr "" msgstr ""
#: documents/views.py:315 #: documents/views.py:303
msgid "Specify only one of text, title_search, query, or more_like_id." msgid "Specify only one of text, title_search, query, or more_like_id."
msgstr "" msgstr ""
#: documents/views.py:353 documents/views.py:2727 #: documents/views.py:341 documents/views.py:2728
msgid "Invalid more_like_id" msgid "Invalid more_like_id"
msgstr "" msgstr ""
#: documents/views.py:1665 #: documents/views.py:1652
msgid "Invalid AI configuration." msgid "Invalid AI configuration."
msgstr "" msgstr ""
#: documents/views.py:1676 #: documents/views.py:1663
msgid "AI backend request timed out." msgid "AI backend request timed out."
msgstr "" msgstr ""
#: documents/views.py:1688 #: documents/views.py:1675
msgid "AI backend rejected the request. Check logs for details." msgid "AI backend rejected the request. Check logs for details."
msgstr "" msgstr ""
#: documents/views.py:4796 #: documents/views.py:4797
#, python-format #, python-format
msgid "Insufficient permissions to share document %(id)s." msgid "Insufficient permissions to share document %(id)s."
msgstr "" msgstr ""
#: documents/views.py:4843 #: documents/views.py:4844
msgid "Bundle is already being processed." msgid "Bundle is already being processed."
msgstr "" msgstr ""
#: documents/views.py:4909 #: documents/views.py:4910
msgid "The share link bundle is still being prepared. Please try again later." msgid "The share link bundle is still being prepared. Please try again later."
msgstr "" msgstr ""
#: documents/views.py:4923 #: documents/views.py:4924
msgid "The share link bundle is unavailable." msgid "The share link bundle is unavailable."
msgstr "" msgstr ""
+23 -23
View File
@@ -2,8 +2,8 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: paperless-ngx\n" "Project-Id-Version: paperless-ngx\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-10-29 17:25+0000\n" "POT-Creation-Date: 2026-10-31 04:47+0000\n"
"PO-Revision-Date: 2026-10-29 17:27\n" "PO-Revision-Date: 2026-10-31 04:48\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Catalan\n" "Language-Team: Catalan\n"
"Language: ca_ES\n" "Language: ca_ES\n"
@@ -21,43 +21,43 @@ msgstr ""
msgid "Documents" msgid "Documents"
msgstr "Documents " msgstr "Documents "
#: documents/filters.py:337 #: documents/filters.py:336
msgid "Expected a date or a relative date such as \"today\" or \"in 30 days\"." msgid "Expected a date or a relative date such as \"today\" or \"in 30 days\"."
msgstr "" msgstr ""
#: documents/filters.py:513 #: documents/filters.py:514
msgid "Value must be valid JSON." msgid "Value must be valid JSON."
msgstr "Valor ha de ser un JSON valid." msgstr "Valor ha de ser un JSON valid."
#: documents/filters.py:534 #: documents/filters.py:535
msgid "Invalid custom field query expression" msgid "Invalid custom field query expression"
msgstr "Expressió de camp de consulta invàlid" msgstr "Expressió de camp de consulta invàlid"
#: documents/filters.py:544 #: documents/filters.py:545
msgid "Invalid expression list. Must be nonempty." msgid "Invalid expression list. Must be nonempty."
msgstr "Expressió de llista invàlida. No ha d'estar buida." msgstr "Expressió de llista invàlida. No ha d'estar buida."
#: documents/filters.py:565 #: documents/filters.py:566
msgid "Invalid logical operator {op!r}" msgid "Invalid logical operator {op!r}"
msgstr "Invàlid operand lògic {op!r}" msgstr "Invàlid operand lògic {op!r}"
#: documents/filters.py:579 #: documents/filters.py:580
msgid "Maximum number of query conditions exceeded." msgid "Maximum number of query conditions exceeded."
msgstr "Condicions de consulta excedits." msgstr "Condicions de consulta excedits."
#: documents/filters.py:643 #: documents/filters.py:644
msgid "{name!r} is not a valid custom field." msgid "{name!r} is not a valid custom field."
msgstr "{name!r} no és un camp personalitzat vàlid." msgstr "{name!r} no és un camp personalitzat vàlid."
#: documents/filters.py:680 #: documents/filters.py:681
msgid "{data_type} does not support query expr {expr!r}." msgid "{data_type} does not support query expr {expr!r}."
msgstr "{data_type} no suporta expressió de consulta {expr!r}." msgstr "{data_type} no suporta expressió de consulta {expr!r}."
#: documents/filters.py:801 documents/models.py:137 #: documents/filters.py:802 documents/models.py:137
msgid "Maximum nesting depth exceeded." msgid "Maximum nesting depth exceeded."
msgstr "Màxima profunditat anidada excedida." msgstr "Màxima profunditat anidada excedida."
#: documents/filters.py:1178 #: documents/filters.py:1179
msgid "Custom field not found" msgid "Custom field not found"
msgstr "Camp personalitzat no trobat" msgstr "Camp personalitzat no trobat"
@@ -1640,7 +1640,7 @@ msgid "workflow runs"
msgstr "flux corrents" msgstr "flux corrents"
#: documents/serialisers.py:483 documents/serialisers.py:840 #: documents/serialisers.py:483 documents/serialisers.py:840
#: documents/serialisers.py:2872 documents/views.py:360 documents/views.py:2730 #: documents/serialisers.py:2872 documents/views.py:348 documents/views.py:2731
#: paperless_mail/serialisers.py:156 #: paperless_mail/serialisers.py:156
msgid "Insufficient permissions." msgid "Insufficient permissions."
msgstr "Permisos insuficients." msgstr "Permisos insuficients."
@@ -1680,7 +1680,7 @@ msgstr "Variable detectada invàlida."
msgid "Duplicate document identifiers are not allowed." msgid "Duplicate document identifiers are not allowed."
msgstr "Duplicat d'identificadors de documents no permès." msgstr "Duplicat d'identificadors de documents no permès."
#: documents/serialisers.py:2958 documents/views.py:4780 #: documents/serialisers.py:2958 documents/views.py:4781
#, python-format #, python-format
msgid "Documents not found: %(ids)s" msgid "Documents not found: %(ids)s"
msgstr "Documents no trobats: %(ids)s" msgstr "Documents no trobats: %(ids)s"
@@ -1921,40 +1921,40 @@ msgstr "Com a pas final, completa el següent formulari:"
msgid ", " msgid ", "
msgstr "" msgstr ""
#: documents/views.py:315 #: documents/views.py:303
msgid "Specify only one of text, title_search, query, or more_like_id." msgid "Specify only one of text, title_search, query, or more_like_id."
msgstr "Especifica només un dels següents valors: text, title_search, query o more_like_id." msgstr "Especifica només un dels següents valors: text, title_search, query o more_like_id."
#: documents/views.py:353 documents/views.py:2727 #: documents/views.py:341 documents/views.py:2728
msgid "Invalid more_like_id" msgid "Invalid more_like_id"
msgstr "Invalid more_like_id" msgstr "Invalid more_like_id"
#: documents/views.py:1665 #: documents/views.py:1652
msgid "Invalid AI configuration." msgid "Invalid AI configuration."
msgstr "Configuració AI invàlida." msgstr "Configuració AI invàlida."
#: documents/views.py:1676 #: documents/views.py:1663
msgid "AI backend request timed out." msgid "AI backend request timed out."
msgstr "" msgstr ""
#: documents/views.py:1688 #: documents/views.py:1675
msgid "AI backend rejected the request. Check logs for details." msgid "AI backend rejected the request. Check logs for details."
msgstr "" msgstr ""
#: documents/views.py:4796 #: documents/views.py:4797
#, python-format #, python-format
msgid "Insufficient permissions to share document %(id)s." msgid "Insufficient permissions to share document %(id)s."
msgstr "Permisos insuficients per compartir document %(id)s." msgstr "Permisos insuficients per compartir document %(id)s."
#: documents/views.py:4843 #: documents/views.py:4844
msgid "Bundle is already being processed." msgid "Bundle is already being processed."
msgstr "Paquet ja s'està processant." msgstr "Paquet ja s'està processant."
#: documents/views.py:4909 #: documents/views.py:4910
msgid "The share link bundle is still being prepared. Please try again later." msgid "The share link bundle is still being prepared. Please try again later."
msgstr "El paquet de link encarà s'està preparant. Prova de nou més tard." msgstr "El paquet de link encarà s'està preparant. Prova de nou més tard."
#: documents/views.py:4923 #: documents/views.py:4924
msgid "The share link bundle is unavailable." msgid "The share link bundle is unavailable."
msgstr "El paquet d'enllaç no està disponible." msgstr "El paquet d'enllaç no està disponible."
Loaded 100 of 153 files, more files were not shown because too many files have changed in this diff. Show more