mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2026-10-03 06:40:31 +00:00
Compare commits
38
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6e8fe8ae09 | ||
|
|
cec0b99d2e | ||
|
|
3615a5a2a5 | ||
|
|
56687614df | ||
|
|
f1ae9c00ac | ||
|
|
bc2ff953ed | ||
|
|
e17689a91b | ||
|
|
764d1a492d | ||
|
|
9d50a3b261 | ||
|
|
da3de299fc | ||
|
|
3a022e2dc4 | ||
|
|
58bda48682 | ||
|
|
b2a2e15ead | ||
|
|
e865185425 | ||
|
|
d02c19a09e | ||
|
|
4a106454ce | ||
|
|
4254100fae | ||
|
|
74f727b1f3 | ||
|
|
fb6fad952e | ||
|
|
f9b4e0c8e0 | ||
|
|
e5041097af | ||
|
|
61f36eb253 | ||
|
|
e50bcc2efb | ||
|
|
88000aab45 | ||
|
|
01b4ab392c | ||
|
|
52aa8758e3 | ||
|
|
4b7cc1c0c3 | ||
|
|
f02d7455be | ||
|
|
a61c35fcd8 | ||
|
|
64552d5d5b | ||
|
|
a59edf3e5b | ||
|
|
6a5d06ee26 | ||
|
|
126ec414a8 | ||
|
|
773744d04b | ||
|
|
7b98085b31 | ||
|
|
b3bf220f56 | ||
|
|
d4429c3cc7 | ||
|
|
4f777d7438 |
@@ -0,0 +1,53 @@
|
|||||||
|
name: Install apt packages
|
||||||
|
description: >
|
||||||
|
Installs apt packages with a per-attempt timeout and retries. The hosted runner's Azure apt mirror intermittently serves archives at a crawl, which apt's own timeout does not catch. A stuck attempt is killed and retried, which usually lands on a healthy mirror node.
|
||||||
|
|
||||||
|
inputs:
|
||||||
|
packages:
|
||||||
|
description: Space separated list of packages to install
|
||||||
|
required: true
|
||||||
|
attempts:
|
||||||
|
description: Maximum number of attempts
|
||||||
|
default: "3"
|
||||||
|
attempt-timeout:
|
||||||
|
description: Seconds before a single attempt is killed
|
||||||
|
default: "180"
|
||||||
|
runs:
|
||||||
|
using: composite
|
||||||
|
steps:
|
||||||
|
- name: Install ${{ inputs.packages }}
|
||||||
|
shell: bash
|
||||||
|
env:
|
||||||
|
PACKAGES: ${{ inputs.packages }}
|
||||||
|
ATTEMPTS: ${{ inputs.attempts }}
|
||||||
|
ATTEMPT_TIMEOUT: ${{ inputs.attempt-timeout }}
|
||||||
|
run: |
|
||||||
|
SUDO=""
|
||||||
|
if [ "$(id -u)" -ne 0 ]; then
|
||||||
|
SUDO="sudo"
|
||||||
|
fi
|
||||||
|
|
||||||
|
attempt_install() {
|
||||||
|
$SUDO apt-get update -q
|
||||||
|
# Intentionally unquoted, this is a list of package names
|
||||||
|
$SUDO apt-get install -q --yes --no-install-recommends $PACKAGES
|
||||||
|
}
|
||||||
|
export -f attempt_install
|
||||||
|
export SUDO PACKAGES
|
||||||
|
|
||||||
|
for attempt in $(seq 1 "${ATTEMPTS}"); do
|
||||||
|
echo "::group::apt install attempt ${attempt}/${ATTEMPTS}"
|
||||||
|
start=$(date +%s)
|
||||||
|
if timeout --kill-after=10 "${ATTEMPT_TIMEOUT}" bash -c attempt_install; then
|
||||||
|
echo "::endgroup::"
|
||||||
|
echo "Installed in $(( $(date +%s) - start ))s"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
echo "::endgroup::"
|
||||||
|
echo "::warning::apt install attempt ${attempt}/${ATTEMPTS} failed or exceeded ${ATTEMPT_TIMEOUT}s"
|
||||||
|
# A killed attempt can leave dpkg half configured
|
||||||
|
$SUDO dpkg --configure -a || true
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "::error::apt install failed after ${ATTEMPTS} attempts"
|
||||||
|
exit 1
|
||||||
@@ -59,7 +59,6 @@ updates:
|
|||||||
- "drf-*"
|
- "drf-*"
|
||||||
- "djangorestframework"
|
- "djangorestframework"
|
||||||
- "whitenoise"
|
- "whitenoise"
|
||||||
- "bleach"
|
|
||||||
- "jinja2"
|
- "jinja2"
|
||||||
# Async, Task Queuing & Caching
|
# Async, Task Queuing & Caching
|
||||||
async-tasks:
|
async-tasks:
|
||||||
|
|||||||
@@ -102,17 +102,16 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
python-version: "${{ matrix.python-version }}"
|
python-version: "${{ matrix.python-version }}"
|
||||||
- name: Install uv
|
- name: Install uv
|
||||||
uses: astral-sh/setup-uv@bec219d24cd3e171d82865faccec33120bb574f4 # v10.1.0
|
uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0
|
||||||
with:
|
with:
|
||||||
version: ${{ env.DEFAULT_UV_VERSION }}
|
version: ${{ env.DEFAULT_UV_VERSION }}
|
||||||
enable-cache: true
|
enable-cache: true
|
||||||
python-version: ${{ steps.setup-python.outputs.python-version }}
|
python-version: ${{ steps.setup-python.outputs.python-version }}
|
||||||
- name: Install system dependencies
|
- name: Install system dependencies
|
||||||
timeout-minutes: 10
|
timeout-minutes: 12
|
||||||
run: |
|
uses: $/.github/actions/apt-install
|
||||||
sudo apt-get update -qq
|
with:
|
||||||
sudo apt-get install -qq --no-install-recommends \
|
packages: unpaper tesseract-ocr imagemagick ghostscript poppler-utils
|
||||||
unpaper tesseract-ocr imagemagick ghostscript poppler-utils
|
|
||||||
- name: Configure ImageMagick
|
- name: Configure ImageMagick
|
||||||
run: |
|
run: |
|
||||||
sudo cp docker/rootfs/etc/ImageMagick-6/paperless-policy.xml /etc/ImageMagick-6/policy.xml
|
sudo cp docker/rootfs/etc/ImageMagick-6/paperless-policy.xml /etc/ImageMagick-6/policy.xml
|
||||||
@@ -139,13 +138,13 @@ jobs:
|
|||||||
pytest
|
pytest
|
||||||
- name: Upload test results to Codecov
|
- name: Upload test results to Codecov
|
||||||
if: always()
|
if: always()
|
||||||
uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0
|
uses: codecov/codecov-action@303a32d7a59b442fa8d48b6a1cc6825c09c847a5 # v7.1.1
|
||||||
with:
|
with:
|
||||||
flags: backend-python-${{ matrix.python-version }}
|
flags: backend-python-${{ matrix.python-version }}
|
||||||
files: junit.xml
|
files: junit.xml
|
||||||
report_type: test_results
|
report_type: test_results
|
||||||
- name: Upload coverage to Codecov
|
- name: Upload coverage to Codecov
|
||||||
uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0
|
uses: codecov/codecov-action@303a32d7a59b442fa8d48b6a1cc6825c09c847a5 # v7.1.1
|
||||||
with:
|
with:
|
||||||
flags: backend-python-${{ matrix.python-version }}
|
flags: backend-python-${{ matrix.python-version }}
|
||||||
files: coverage.xml
|
files: coverage.xml
|
||||||
@@ -176,7 +175,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
python-version: "${{ env.DEFAULT_PYTHON }}"
|
python-version: "${{ env.DEFAULT_PYTHON }}"
|
||||||
- name: Install uv
|
- name: Install uv
|
||||||
uses: astral-sh/setup-uv@bec219d24cd3e171d82865faccec33120bb574f4 # v10.1.0
|
uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0
|
||||||
with:
|
with:
|
||||||
version: ${{ env.DEFAULT_UV_VERSION }}
|
version: ${{ env.DEFAULT_UV_VERSION }}
|
||||||
enable-cache: true
|
enable-cache: true
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ jobs:
|
|||||||
echo "repository=${repo_name}"
|
echo "repository=${repo_name}"
|
||||||
echo "name=${repo_name}" >> $GITHUB_OUTPUT
|
echo "name=${repo_name}" >> $GITHUB_OUTPUT
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@37fe631027851001ddb9b187196cc803df7f5f0e # v4.3.0
|
uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4.4.1
|
||||||
- name: Login to GitHub Container Registry
|
- name: Login to GitHub Container Registry
|
||||||
uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0
|
uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0
|
||||||
with:
|
with:
|
||||||
@@ -132,7 +132,7 @@ jobs:
|
|||||||
type=semver,pattern={{major}}.{{minor}}
|
type=semver,pattern={{major}}.{{minor}}
|
||||||
- name: Build and push by digest
|
- name: Build and push by digest
|
||||||
id: build
|
id: build
|
||||||
uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.3.0
|
uses: docker/build-push-action@c3c9e263c25d99ce0380d002d59b67737d91b0dc # v7.4.0
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
file: ./Dockerfile
|
file: ./Dockerfile
|
||||||
@@ -182,7 +182,7 @@ jobs:
|
|||||||
echo "Downloaded digests:"
|
echo "Downloaded digests:"
|
||||||
ls -la /tmp/digests/
|
ls -la /tmp/digests/
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@37fe631027851001ddb9b187196cc803df7f5f0e # v4.3.0
|
uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4.4.1
|
||||||
- name: Login to GitHub Container Registry
|
- name: Login to GitHub Container Registry
|
||||||
uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0
|
uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0
|
||||||
with:
|
with:
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
python-version: ${{ env.DEFAULT_PYTHON_VERSION }}
|
python-version: ${{ env.DEFAULT_PYTHON_VERSION }}
|
||||||
- name: Install uv
|
- name: Install uv
|
||||||
uses: astral-sh/setup-uv@bec219d24cd3e171d82865faccec33120bb574f4 # v10.1.0
|
uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0
|
||||||
with:
|
with:
|
||||||
version: ${{ env.DEFAULT_UV_VERSION }}
|
version: ${{ env.DEFAULT_UV_VERSION }}
|
||||||
enable-cache: true
|
enable-cache: true
|
||||||
|
|||||||
@@ -174,13 +174,13 @@ jobs:
|
|||||||
run: cd src-ui && pnpm run test --max-workers=2 --shard=${{ matrix.shard-index }}/${{ matrix.shard-count }}
|
run: cd src-ui && pnpm run test --max-workers=2 --shard=${{ matrix.shard-index }}/${{ matrix.shard-count }}
|
||||||
- name: Upload test results to Codecov
|
- name: Upload test results to Codecov
|
||||||
if: always()
|
if: always()
|
||||||
uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0
|
uses: codecov/codecov-action@303a32d7a59b442fa8d48b6a1cc6825c09c847a5 # v7.1.1
|
||||||
with:
|
with:
|
||||||
flags: frontend-node-${{ matrix.node-version }}
|
flags: frontend-node-${{ matrix.node-version }}
|
||||||
directory: src-ui/
|
directory: src-ui/
|
||||||
report_type: test_results
|
report_type: test_results
|
||||||
- name: Upload coverage to Codecov
|
- name: Upload coverage to Codecov
|
||||||
uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0
|
uses: codecov/codecov-action@303a32d7a59b442fa8d48b6a1cc6825c09c847a5 # v7.1.1
|
||||||
with:
|
with:
|
||||||
flags: frontend-node-${{ matrix.node-version }}
|
flags: frontend-node-${{ matrix.node-version }}
|
||||||
directory: src-ui/coverage/
|
directory: src-ui/coverage/
|
||||||
@@ -216,7 +216,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
python-version: '3.12'
|
python-version: '3.12'
|
||||||
- name: Install uv
|
- name: Install uv
|
||||||
uses: astral-sh/setup-uv@bec219d24cd3e171d82865faccec33120bb574f4 # v10.1.0
|
uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0
|
||||||
with:
|
with:
|
||||||
version: '0.12.x'
|
version: '0.12.x'
|
||||||
enable-cache: false
|
enable-cache: false
|
||||||
@@ -231,9 +231,10 @@ jobs:
|
|||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: cd src-ui && pnpm install --frozen-lockfile
|
run: cd src-ui && pnpm install --frozen-lockfile
|
||||||
- name: Install backend system dependencies
|
- name: Install backend system dependencies
|
||||||
run: |
|
timeout-minutes: 12
|
||||||
apt-get update
|
uses: $/.github/actions/apt-install
|
||||||
apt-get install --yes --quiet --no-install-recommends libmagic1
|
with:
|
||||||
|
packages: libmagic1
|
||||||
- name: Install backend dependencies
|
- name: Install backend dependencies
|
||||||
env:
|
env:
|
||||||
PYTHON_VERSION: ${{ steps.setup-python.outputs.python-version }}
|
PYTHON_VERSION: ${{ steps.setup-python.outputs.python-version }}
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
python-version: ${{ env.DEFAULT_PYTHON_VERSION }}
|
python-version: ${{ env.DEFAULT_PYTHON_VERSION }}
|
||||||
- name: Install uv
|
- name: Install uv
|
||||||
uses: astral-sh/setup-uv@bec219d24cd3e171d82865faccec33120bb574f4 # v10.1.0
|
uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0
|
||||||
with:
|
with:
|
||||||
version: ${{ env.DEFAULT_UV_VERSION }}
|
version: ${{ env.DEFAULT_UV_VERSION }}
|
||||||
enable-cache: false
|
enable-cache: false
|
||||||
@@ -70,9 +70,10 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
uv sync --python "${PYTHON_VERSION}" --dev --frozen
|
uv sync --python "${PYTHON_VERSION}" --dev --frozen
|
||||||
- name: Install system dependencies
|
- name: Install system dependencies
|
||||||
run: |
|
timeout-minutes: 12
|
||||||
sudo apt-get update -qq
|
uses: $/.github/actions/apt-install
|
||||||
sudo apt-get install -qq --no-install-recommends gettext liblept5
|
with:
|
||||||
|
packages: gettext liblept5
|
||||||
# ---- Build Documentation ----
|
# ---- Build Documentation ----
|
||||||
- name: Build documentation
|
- name: Build documentation
|
||||||
env:
|
env:
|
||||||
@@ -212,7 +213,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
python-version: ${{ env.DEFAULT_PYTHON_VERSION }}
|
python-version: ${{ env.DEFAULT_PYTHON_VERSION }}
|
||||||
- name: Install uv
|
- name: Install uv
|
||||||
uses: astral-sh/setup-uv@bec219d24cd3e171d82865faccec33120bb574f4 # v10.1.0
|
uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0
|
||||||
with:
|
with:
|
||||||
version: ${{ env.DEFAULT_UV_VERSION }}
|
version: ${{ env.DEFAULT_UV_VERSION }}
|
||||||
enable-cache: false
|
enable-cache: false
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ jobs:
|
|||||||
- name: Run Semgrep
|
- name: Run Semgrep
|
||||||
run: semgrep scan --config auto --sarif-output results.sarif
|
run: semgrep scan --config auto --sarif-output results.sarif
|
||||||
- name: Upload results to GitHub code scanning
|
- name: Upload results to GitHub code scanning
|
||||||
uses: github/codeql-action/upload-sarif@b96794f015dfd88f77b49b1c93e0fa7110f94c63 # v4.38.0
|
uses: github/codeql-action/upload-sarif@1c5b675653bb5c22dbe9b12b556ec555138e09fd # v4.38.1
|
||||||
if: always()
|
if: always()
|
||||||
with:
|
with:
|
||||||
sarif_file: results.sarif
|
sarif_file: results.sarif
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Clean temporary images
|
- name: Clean temporary images
|
||||||
if: "${{ env.TOKEN != '' }}"
|
if: "${{ env.TOKEN != '' }}"
|
||||||
uses: stumpylog/image-cleaner-action/ephemeral@4fe057d991d63b8f6d5d22c40f17c1bca2226537 # v0.12.0
|
uses: stumpylog/image-cleaner-action/ephemeral@21f875bab2376314e0525c614e923c669434f0e4 # v0.13.0
|
||||||
with:
|
with:
|
||||||
token: "${{ env.TOKEN }}"
|
token: "${{ env.TOKEN }}"
|
||||||
owner: "${{ github.repository_owner }}"
|
owner: "${{ github.repository_owner }}"
|
||||||
@@ -56,7 +56,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Clean untagged images
|
- name: Clean untagged images
|
||||||
if: "${{ env.TOKEN != '' }}"
|
if: "${{ env.TOKEN != '' }}"
|
||||||
uses: stumpylog/image-cleaner-action/untagged@4fe057d991d63b8f6d5d22c40f17c1bca2226537 # v0.12.0
|
uses: stumpylog/image-cleaner-action/untagged@21f875bab2376314e0525c614e923c669434f0e4 # v0.13.0
|
||||||
with:
|
with:
|
||||||
token: "${{ env.TOKEN }}"
|
token: "${{ env.TOKEN }}"
|
||||||
owner: "${{ github.repository_owner }}"
|
owner: "${{ github.repository_owner }}"
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ jobs:
|
|||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
# Initializes the CodeQL tools for scanning.
|
# Initializes the CodeQL tools for scanning.
|
||||||
- name: Initialize CodeQL
|
- name: Initialize CodeQL
|
||||||
uses: github/codeql-action/init@b96794f015dfd88f77b49b1c93e0fa7110f94c63 # v4.38.0
|
uses: github/codeql-action/init@1c5b675653bb5c22dbe9b12b556ec555138e09fd # v4.38.1
|
||||||
with:
|
with:
|
||||||
languages: ${{ matrix.language }}
|
languages: ${{ matrix.language }}
|
||||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||||
@@ -47,4 +47,4 @@ jobs:
|
|||||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||||
# queries: ./path/to/local/query, your-org/your-repo/queries@main
|
# queries: ./path/to/local/query, your-org/your-repo/queries@main
|
||||||
- name: Perform CodeQL Analysis
|
- name: Perform CodeQL Analysis
|
||||||
uses: github/codeql-action/analyze@b96794f015dfd88f77b49b1c93e0fa7110f94c63 # v4.38.0
|
uses: github/codeql-action/analyze@1c5b675653bb5c22dbe9b12b556ec555138e09fd # v4.38.1
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ jobs:
|
|||||||
token: ${{ secrets.PNGX_BOT_PAT }}
|
token: ${{ secrets.PNGX_BOT_PAT }}
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: crowdin action
|
- name: crowdin action
|
||||||
uses: crowdin/github-action@0d5670f539973aea2f01abce61a8989934df0025 # v3.0.2
|
uses: crowdin/github-action@df474cdfb9f41d6ae777118749477c2cdf7cacc8 # v3.2.0
|
||||||
with:
|
with:
|
||||||
upload_translations: false
|
upload_translations: false
|
||||||
download_translations: true
|
download_translations: true
|
||||||
|
|||||||
@@ -25,11 +25,12 @@ jobs:
|
|||||||
id: setup-python
|
id: setup-python
|
||||||
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
|
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
|
||||||
- name: Install system dependencies
|
- name: Install system dependencies
|
||||||
run: |
|
timeout-minutes: 12
|
||||||
sudo apt-get update -qq
|
uses: $/.github/actions/apt-install
|
||||||
sudo apt-get install -qq --no-install-recommends gettext
|
with:
|
||||||
|
packages: gettext
|
||||||
- name: Install uv
|
- name: Install uv
|
||||||
uses: astral-sh/setup-uv@bec219d24cd3e171d82865faccec33120bb574f4 # v10.1.0
|
uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0
|
||||||
with:
|
with:
|
||||||
version: ${{ env.DEFAULT_UV_VERSION }}
|
version: ${{ env.DEFAULT_UV_VERSION }}
|
||||||
enable-cache: true
|
enable-cache: true
|
||||||
|
|||||||
+706
-456
File diff suppressed because it is too large
Load Diff
@@ -38,7 +38,7 @@ repos:
|
|||||||
- json
|
- json
|
||||||
# See https://github.com/prettier/prettier/issues/15742 for the fork reason
|
# See https://github.com/prettier/prettier/issues/15742 for the fork reason
|
||||||
- repo: https://github.com/rbubley/mirrors-prettier
|
- repo: https://github.com/rbubley/mirrors-prettier
|
||||||
rev: 'v3.9.6'
|
rev: 'v3.9.8'
|
||||||
hooks:
|
hooks:
|
||||||
- id: prettier
|
- id: prettier
|
||||||
types_or:
|
types_or:
|
||||||
@@ -46,11 +46,11 @@ repos:
|
|||||||
- ts
|
- ts
|
||||||
- markdown
|
- markdown
|
||||||
additional_dependencies:
|
additional_dependencies:
|
||||||
- prettier@3.9.6
|
- prettier@3.9.8
|
||||||
- 'prettier-plugin-organize-imports@4.3.0'
|
- 'prettier-plugin-organize-imports@4.3.0'
|
||||||
# Python hooks
|
# Python hooks
|
||||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||||
rev: v0.16.7
|
rev: v0.16.8
|
||||||
hooks:
|
hooks:
|
||||||
- id: ruff-check
|
- id: ruff-check
|
||||||
- id: ruff-format
|
- id: ruff-format
|
||||||
|
|||||||
+4804
-12941
File diff suppressed because one or more lines are too long
+4
-2
@@ -30,7 +30,7 @@ RUN set -eux \
|
|||||||
# Purpose: Installs s6-overlay and rootfs
|
# Purpose: Installs s6-overlay and rootfs
|
||||||
# Comments:
|
# Comments:
|
||||||
# - Don't leave anything extra in here either
|
# - Don't leave anything extra in here either
|
||||||
FROM ghcr.io/astral-sh/uv:0.12.16-python3.14-trixie-slim AS s6-overlay-base
|
FROM ghcr.io/astral-sh/uv:0.12.20-python3.14-trixie-slim AS s6-overlay-base
|
||||||
|
|
||||||
WORKDIR /usr/src/s6
|
WORKDIR /usr/src/s6
|
||||||
|
|
||||||
@@ -171,7 +171,9 @@ RUN set -eux \
|
|||||||
&& cp /etc/ImageMagick-6/paperless-policy.xml /etc/ImageMagick-6/policy.xml \
|
&& cp /etc/ImageMagick-6/paperless-policy.xml /etc/ImageMagick-6/policy.xml \
|
||||||
&& echo "Cleaning up image layer" \
|
&& echo "Cleaning up image layer" \
|
||||||
&& rm --force --verbose *.deb \
|
&& rm --force --verbose *.deb \
|
||||||
&& rm --recursive --force --verbose /var/lib/apt/lists/*
|
&& rm --recursive --force --verbose /var/lib/apt/lists/* \
|
||||||
|
&& echo "Configuring interactive shells to source the s6 container environment" \
|
||||||
|
&& echo '. /etc/profile.d/contenv.sh' >> /etc/bash.bashrc
|
||||||
|
|
||||||
WORKDIR /usr/src/paperless/src/
|
WORKDIR /usr/src/paperless/src/
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ services:
|
|||||||
network_mode: host
|
network_mode: host
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
greenmail:
|
greenmail:
|
||||||
image: docker.io/greenmail/standalone:2.1.13
|
image: docker.io/greenmail/standalone:2.1.14
|
||||||
hostname: greenmail
|
hostname: greenmail
|
||||||
container_name: greenmail
|
container_name: greenmail
|
||||||
environment:
|
environment:
|
||||||
|
|||||||
Executable
+18
@@ -0,0 +1,18 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Source s6 container environment for interactive shells.
|
||||||
|
# Ensures variables resolved from *_FILE secret injection are visible
|
||||||
|
# when using 'docker exec bash'. Does not affect s6 services (those
|
||||||
|
# use with-contenv directly). Has no effect in non-container contexts
|
||||||
|
# because the directory will not exist.
|
||||||
|
# Note: sh/dash shells opened via 'docker exec sh' are not covered;
|
||||||
|
# only bash-based sessions benefit from this file.
|
||||||
|
_pngx_contenv="/run/s6/container_environment"
|
||||||
|
if [ -d "${_pngx_contenv}" ]; then
|
||||||
|
for _pngx_f in "${_pngx_contenv}"/*; do
|
||||||
|
[ -f "${_pngx_f}" ] || continue
|
||||||
|
_pngx_name=$(basename "${_pngx_f}")
|
||||||
|
_pngx_val=$(cat "${_pngx_f}")
|
||||||
|
export "${_pngx_name}=${_pngx_val}"
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
unset _pngx_contenv _pngx_f _pngx_name _pngx_val
|
||||||
@@ -136,13 +136,15 @@ for suggested generation and embedding models.
|
|||||||
### AI-assisted suggestions
|
### AI-assisted suggestions
|
||||||
|
|
||||||
With AI enabled, Paperless-ngx can suggest a title, tags, correspondent, document type,
|
With AI enabled, Paperless-ngx can suggest a title, tags, correspondent, document type,
|
||||||
storage path and dates by sending the document to the LLM. This is **opt-in per request**
|
storage path and dates by sending the document to the LLM using "Suggest" button on the document
|
||||||
and surfaces through the "Suggest" control on the document detail page, alongside the
|
detail page. You can choose which type of suggestions are requested by default under Settings >
|
||||||
classic classifier-based suggestions — it does not disable them. Suggestions are requested
|
Documents, either ML (classifier-based) suggestions, AI suggestions, or both. When both are requested
|
||||||
automatically when you open a document that carries an inbox tag unless "Automatically request
|
the results are combined.
|
||||||
suggestions for inbox documents" under Settings > Documents is disabled. Suggestion output
|
|
||||||
language can be steered with
|
Suggestions are requested automatically when you open a document that carries an inbox tag
|
||||||
[`PAPERLESS_AI_LLM_OUTPUT_LANGUAGE`](configuration.md#PAPERLESS_AI_LLM_OUTPUT_LANGUAGE)
|
unless "Automatically request suggestions for inbox documents" under Settings > Documents is disabled.
|
||||||
|
|
||||||
|
Suggestion output language can be steered with [`PAPERLESS_AI_LLM_OUTPUT_LANGUAGE`](configuration.md#PAPERLESS_AI_LLM_OUTPUT_LANGUAGE)
|
||||||
(otherwise it follows the user's UI language).
|
(otherwise it follows the user's UI language).
|
||||||
|
|
||||||
### The LLM index (RAG) and similar documents
|
### The LLM index (RAG) and similar documents
|
||||||
|
|||||||
+7
-7
@@ -19,7 +19,6 @@ classifiers = [
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"azure-ai-documentintelligence>=1.0.2",
|
"azure-ai-documentintelligence>=1.0.2",
|
||||||
"babel>=2.17",
|
"babel>=2.17",
|
||||||
"bleach~=6.4.0",
|
|
||||||
"celery[redis]~=5.6.2",
|
"celery[redis]~=5.6.2",
|
||||||
"channels~=4.2",
|
"channels~=4.2",
|
||||||
"channels-redis~=4.2",
|
"channels-redis~=4.2",
|
||||||
@@ -35,7 +34,7 @@ dependencies = [
|
|||||||
"django-cors-headers~=4.9.0",
|
"django-cors-headers~=4.9.0",
|
||||||
"django-extensions~=4.1",
|
"django-extensions~=4.1",
|
||||||
"django-filter~=25.1",
|
"django-filter~=25.1",
|
||||||
"django-guardian>=3.3.3,<3.5",
|
"django-guardian>=3.3.3,<3.6",
|
||||||
"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",
|
||||||
@@ -45,7 +44,7 @@ dependencies = [
|
|||||||
"drf-spectacular-sidecar>=2026.7.1,<2026.10",
|
"drf-spectacular-sidecar>=2026.7.1,<2026.10",
|
||||||
"drf-writable-nested~=0.7.1",
|
"drf-writable-nested~=0.7.1",
|
||||||
"filelock~=3.32.0",
|
"filelock~=3.32.0",
|
||||||
"flower>=2.0.1,<2.2",
|
"flower>=2.0.1,<2.3",
|
||||||
"gotenberg-client[httpx]~=1.0",
|
"gotenberg-client[httpx]~=1.0",
|
||||||
"httpx-oauth~=0.17",
|
"httpx-oauth~=0.17",
|
||||||
"ijson>=3.5.1",
|
"ijson>=3.5.1",
|
||||||
@@ -77,6 +76,7 @@ dependencies = [
|
|||||||
"tantivy~=0.26.0",
|
"tantivy~=0.26.0",
|
||||||
"tika-client[httpx]~=1.0",
|
"tika-client[httpx]~=1.0",
|
||||||
"torch>=2.13,<2.15",
|
"torch>=2.13,<2.15",
|
||||||
|
"turbohtml~=1.10.0",
|
||||||
"watchfiles>=1.2",
|
"watchfiles>=1.2",
|
||||||
"whitenoise~=6.11",
|
"whitenoise~=6.11",
|
||||||
"whoosh-compat[tantivy]==0.3",
|
"whoosh-compat[tantivy]==0.3",
|
||||||
@@ -84,13 +84,13 @@ dependencies = [
|
|||||||
]
|
]
|
||||||
[project.optional-dependencies]
|
[project.optional-dependencies]
|
||||||
mariadb = [
|
mariadb = [
|
||||||
"mysqlclient~=2.2.7",
|
"mysqlclient>=2.2.7,<2.4",
|
||||||
]
|
]
|
||||||
postgres = [
|
postgres = [
|
||||||
"psycopg[c,pool]==3.3.4",
|
"psycopg[c,pool]==3.3.4",
|
||||||
# Direct dependency for proper resolution of the pre-built wheels
|
# Direct dependency for proper resolution of the pre-built wheels
|
||||||
"psycopg-c==3.3.4",
|
"psycopg-c==3.3.4",
|
||||||
"psycopg-pool==3.3.1",
|
"psycopg-pool==3.3.2",
|
||||||
]
|
]
|
||||||
webserver = [
|
webserver = [
|
||||||
"granian[uvloop]>=2.7,<2.9",
|
"granian[uvloop]>=2.7,<2.9",
|
||||||
@@ -112,7 +112,7 @@ lint = [
|
|||||||
testing = [
|
testing = [
|
||||||
"daphne",
|
"daphne",
|
||||||
"factory-boy~=3.3.1",
|
"factory-boy~=3.3.1",
|
||||||
"faker>=40.36,<40.39",
|
"faker>=40.36,<40.40",
|
||||||
"imagehash",
|
"imagehash",
|
||||||
"pytest~=9.1.1",
|
"pytest~=9.1.1",
|
||||||
"pytest-cov~=7.1.0",
|
"pytest-cov~=7.1.0",
|
||||||
@@ -136,7 +136,6 @@ typing = [
|
|||||||
"mypy",
|
"mypy",
|
||||||
"mypy-baseline",
|
"mypy-baseline",
|
||||||
"pyrefly",
|
"pyrefly",
|
||||||
"types-bleach",
|
|
||||||
"types-channels",
|
"types-channels",
|
||||||
"types-colorama",
|
"types-colorama",
|
||||||
"types-dateparser",
|
"types-dateparser",
|
||||||
@@ -151,6 +150,7 @@ typing = [
|
|||||||
|
|
||||||
[tool.uv]
|
[tool.uv]
|
||||||
required-version = ">=0.9.0"
|
required-version = ">=0.9.0"
|
||||||
|
prerelease = "disallow"
|
||||||
environments = [
|
environments = [
|
||||||
"sys_platform == 'darwin'",
|
"sys_platform == 'darwin'",
|
||||||
"sys_platform == 'linux'",
|
"sys_platform == 'linux'",
|
||||||
|
|||||||
@@ -91,6 +91,11 @@
|
|||||||
"glob": "**/*",
|
"glob": "**/*",
|
||||||
"input": "node_modules/pdfjs-dist/iccs/",
|
"input": "node_modules/pdfjs-dist/iccs/",
|
||||||
"output": "/assets/iccs/"
|
"output": "/assets/iccs/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"glob": "**/*",
|
||||||
|
"input": "node_modules/pdfjs-dist/cmaps/",
|
||||||
|
"output": "/assets/cmaps/"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"styles": [
|
"styles": [
|
||||||
|
|||||||
+280
-217
File diff suppressed because it is too large
Load Diff
+22
-22
@@ -15,16 +15,16 @@
|
|||||||
},
|
},
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@angular/cdk": "^22.1.6",
|
"@angular/cdk": "^22.2.0",
|
||||||
"@angular/common": "~22.1.6",
|
"@angular/common": "~22.2.0",
|
||||||
"@angular/compiler": "~22.1.6",
|
"@angular/compiler": "~22.2.0",
|
||||||
"@angular/core": "~22.1.6",
|
"@angular/core": "~22.2.0",
|
||||||
"@angular/forms": "~22.1.6",
|
"@angular/forms": "~22.2.0",
|
||||||
"@angular/localize": "~22.1.6",
|
"@angular/localize": "~22.2.0",
|
||||||
"@angular/platform-browser": "~22.1.6",
|
"@angular/platform-browser": "~22.2.0",
|
||||||
"@angular/router": "~22.1.6",
|
"@angular/router": "~22.2.0",
|
||||||
"@ng-bootstrap/ng-bootstrap": "^21.0.0",
|
"@ng-bootstrap/ng-bootstrap": "^21.0.0",
|
||||||
"@ng-select/ng-select": "~24.1.1",
|
"@ng-select/ng-select": "~24.1.2",
|
||||||
"@ngneat/dirty-check-forms": "^3.0.3",
|
"@ngneat/dirty-check-forms": "^3.0.3",
|
||||||
"@popperjs/core": "^2.11.8",
|
"@popperjs/core": "^2.11.8",
|
||||||
"bootstrap": "^5.3.8",
|
"bootstrap": "^5.3.8",
|
||||||
@@ -45,29 +45,29 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@angular-builders/jest": "^22.0.1",
|
"@angular-builders/jest": "^22.0.1",
|
||||||
"@angular-devkit/core": "^22.1.8",
|
"@angular-devkit/core": "^22.2.0",
|
||||||
"@angular-devkit/schematics": "^22.1.8",
|
"@angular-devkit/schematics": "^22.2.0",
|
||||||
"@angular-eslint/builder": "22.5.0",
|
"@angular-eslint/builder": "22.5.0",
|
||||||
"@angular-eslint/eslint-plugin": "22.5.0",
|
"@angular-eslint/eslint-plugin": "22.5.0",
|
||||||
"@angular-eslint/eslint-plugin-template": "22.5.0",
|
"@angular-eslint/eslint-plugin-template": "22.5.0",
|
||||||
"@angular-eslint/schematics": "22.5.0",
|
"@angular-eslint/schematics": "22.5.0",
|
||||||
"@angular-eslint/template-parser": "22.5.0",
|
"@angular-eslint/template-parser": "22.5.0",
|
||||||
"@angular/build": "22.1.8",
|
"@angular/build": "22.2.0",
|
||||||
"@angular/cli": "22.1.8",
|
"@angular/cli": "22.2.0",
|
||||||
"@angular/compiler-cli": "~22.1.6",
|
"@angular/compiler-cli": "~22.2.0",
|
||||||
"@playwright/test": "^1.62.1",
|
"@playwright/test": "^1.62.1",
|
||||||
"@types/jest": "^30.0.0",
|
"@types/jest": "^30.0.0",
|
||||||
"@types/node": "^26.5.0",
|
"@types/node": "^26.6.2",
|
||||||
"@typescript-eslint/eslint-plugin": "^8.70.0",
|
"@typescript-eslint/eslint-plugin": "^8.70.1",
|
||||||
"@typescript-eslint/parser": "^8.70.0",
|
"@typescript-eslint/parser": "^8.70.1",
|
||||||
"@typescript-eslint/utils": "^8.70.0",
|
"@typescript-eslint/utils": "^8.70.1",
|
||||||
"eslint": "^10.10.0",
|
"eslint": "^10.11.0",
|
||||||
"jest": "30.5.1",
|
"jest": "30.5.2",
|
||||||
"jest-environment-jsdom": "^30.5.1",
|
"jest-environment-jsdom": "^30.5.2",
|
||||||
"jest-junit": "^17.0.0",
|
"jest-junit": "^17.0.0",
|
||||||
"jest-preset-angular": "^17.0.0",
|
"jest-preset-angular": "^17.0.0",
|
||||||
"jest-websocket-mock": "^2.5.0",
|
"jest-websocket-mock": "^2.5.0",
|
||||||
"prettier": "^3.9.6",
|
"prettier": "^3.9.9",
|
||||||
"prettier-plugin-organize-imports": "^4.3.0",
|
"prettier-plugin-organize-imports": "^4.3.0",
|
||||||
"ts-node": "~10.9.2",
|
"ts-node": "~10.9.2",
|
||||||
"typescript": "^6.0.3"
|
"typescript": "^6.0.3"
|
||||||
|
|||||||
Generated
+1312
-1960
File diff suppressed because it is too large
Load Diff
@@ -253,6 +253,24 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@if (aiEnabled) {
|
||||||
|
<div class="row mb-3">
|
||||||
|
<div class="col-md-3 col-form-label pt-0">
|
||||||
|
<span i18n>Suggestions default to</span>
|
||||||
|
</div>
|
||||||
|
<div class="col">
|
||||||
|
<fieldset class="btn-group btn-group-sm">
|
||||||
|
<input type="radio" class="btn-check" id="suggestionSourceBoth" [value]="SuggestionSource.Both" formControlName="documentEditingSuggestionSource">
|
||||||
|
<label class="btn btn-outline-primary" for="suggestionSourceBoth"><ng-container i18n>Both</ng-container></label>
|
||||||
|
<input type="radio" class="btn-check" id="suggestionSourceML" [value]="SuggestionSource.ML" formControlName="documentEditingSuggestionSource">
|
||||||
|
<label class="btn btn-outline-primary" for="suggestionSourceML"><i-bs class="me-1" name="cpu"></i-bs><ng-container i18n>ML only</ng-container></label>
|
||||||
|
<input type="radio" class="btn-check" id="suggestionSourceAI" [value]="SuggestionSource.AI" formControlName="documentEditingSuggestionSource">
|
||||||
|
<label class="btn btn-outline-primary" for="suggestionSourceAI"><i-bs class="me-1" name="stars"></i-bs><ng-container i18n>AI only</ng-container></label>
|
||||||
|
</fieldset>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<pngx-input-check i18n-title title="Automatically request suggestions for inbox documents" i18n-hint hint="If un-checked, suggestions must be requested via the Suggest button." formControlName="documentEditingAutoSuggest"></pngx-input-check>
|
<pngx-input-check i18n-title title="Automatically request suggestions for inbox documents" i18n-hint hint="If un-checked, suggestions must be requested via the Suggest button." formControlName="documentEditingAutoSuggest"></pngx-input-check>
|
||||||
|
|||||||
@@ -307,7 +307,7 @@ describe('SettingsComponent', () => {
|
|||||||
expect(toastErrorSpy).toHaveBeenCalled()
|
expect(toastErrorSpy).toHaveBeenCalled()
|
||||||
expect(storeSpy).toHaveBeenCalled()
|
expect(storeSpy).toHaveBeenCalled()
|
||||||
expect(appearanceSettingsSpy).not.toHaveBeenCalled()
|
expect(appearanceSettingsSpy).not.toHaveBeenCalled()
|
||||||
expect(setSpy).toHaveBeenCalledTimes(34)
|
expect(setSpy).toHaveBeenCalledTimes(35)
|
||||||
expect(setSpy).toHaveBeenCalledWith(SETTINGS_KEYS.SIDEBAR_HIDDEN_ITEMS, [
|
expect(setSpy).toHaveBeenCalledWith(SETTINGS_KEYS.SIDEBAR_HIDDEN_ITEMS, [
|
||||||
HideableSidebarItemID.Workflows,
|
HideableSidebarItemID.Workflows,
|
||||||
])
|
])
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ import {
|
|||||||
HIDEABLE_SIDEBAR_ITEM_IDS,
|
HIDEABLE_SIDEBAR_ITEM_IDS,
|
||||||
HideableSidebarItemID,
|
HideableSidebarItemID,
|
||||||
SETTINGS_KEYS,
|
SETTINGS_KEYS,
|
||||||
|
SuggestionSource,
|
||||||
} from 'src/app/data/ui-settings'
|
} from 'src/app/data/ui-settings'
|
||||||
import { User } from 'src/app/data/user'
|
import { User } from 'src/app/data/user'
|
||||||
import { IfPermissionsDirective } from 'src/app/directives/if-permissions.directive'
|
import { IfPermissionsDirective } from 'src/app/directives/if-permissions.directive'
|
||||||
@@ -184,6 +185,7 @@ export class SettingsComponent
|
|||||||
documentEditingRemoveInboxTags: new FormControl(null),
|
documentEditingRemoveInboxTags: new FormControl(null),
|
||||||
documentEditingOverlayThumbnail: new FormControl(null),
|
documentEditingOverlayThumbnail: new FormControl(null),
|
||||||
documentEditingAutoSuggest: new FormControl(null),
|
documentEditingAutoSuggest: new FormControl(null),
|
||||||
|
documentEditingSuggestionSource: new FormControl(null),
|
||||||
documentDetailsHiddenFields: new FormControl([]),
|
documentDetailsHiddenFields: new FormControl([]),
|
||||||
searchDbOnly: new FormControl(null),
|
searchDbOnly: new FormControl(null),
|
||||||
searchLink: new FormControl(null),
|
searchLink: new FormControl(null),
|
||||||
@@ -217,6 +219,11 @@ export class SettingsComponent
|
|||||||
public readonly PdfZoomScale = PdfZoomScale
|
public readonly PdfZoomScale = PdfZoomScale
|
||||||
|
|
||||||
public readonly PdfEditorEditMode = PdfEditorEditMode
|
public readonly PdfEditorEditMode = PdfEditorEditMode
|
||||||
|
public readonly SuggestionSource = SuggestionSource
|
||||||
|
|
||||||
|
get aiEnabled(): boolean {
|
||||||
|
return this.settings.get(SETTINGS_KEYS.AI_ENABLED)
|
||||||
|
}
|
||||||
|
|
||||||
public readonly documentDetailFieldOptions = documentDetailFieldOptions
|
public readonly documentDetailFieldOptions = documentDetailFieldOptions
|
||||||
public readonly sidebarItemOptions = HIDEABLE_SIDEBAR_ITEM_IDS.map((id) => ({
|
public readonly sidebarItemOptions = HIDEABLE_SIDEBAR_ITEM_IDS.map((id) => ({
|
||||||
@@ -404,6 +411,9 @@ export class SettingsComponent
|
|||||||
documentEditingAutoSuggest: this.settings.get(
|
documentEditingAutoSuggest: this.settings.get(
|
||||||
SETTINGS_KEYS.DOCUMENT_EDITING_AUTO_SUGGEST
|
SETTINGS_KEYS.DOCUMENT_EDITING_AUTO_SUGGEST
|
||||||
),
|
),
|
||||||
|
documentEditingSuggestionSource: this.settings.get(
|
||||||
|
SETTINGS_KEYS.DOCUMENT_EDITING_SUGGESTION_SOURCE
|
||||||
|
),
|
||||||
documentDetailsHiddenFields: this.settings.get(
|
documentDetailsHiddenFields: this.settings.get(
|
||||||
SETTINGS_KEYS.DOCUMENT_DETAILS_HIDDEN_FIELDS
|
SETTINGS_KEYS.DOCUMENT_DETAILS_HIDDEN_FIELDS
|
||||||
),
|
),
|
||||||
@@ -625,6 +635,10 @@ export class SettingsComponent
|
|||||||
SETTINGS_KEYS.DOCUMENT_EDITING_AUTO_SUGGEST,
|
SETTINGS_KEYS.DOCUMENT_EDITING_AUTO_SUGGEST,
|
||||||
this.settingsForm.value.documentEditingAutoSuggest
|
this.settingsForm.value.documentEditingAutoSuggest
|
||||||
)
|
)
|
||||||
|
this.settings.set(
|
||||||
|
SETTINGS_KEYS.DOCUMENT_EDITING_SUGGESTION_SOURCE,
|
||||||
|
this.settingsForm.value.documentEditingSuggestionSource
|
||||||
|
)
|
||||||
this.settings.set(
|
this.settings.set(
|
||||||
SETTINGS_KEYS.DOCUMENT_DETAILS_HIDDEN_FIELDS,
|
SETTINGS_KEYS.DOCUMENT_DETAILS_HIDDEN_FIELDS,
|
||||||
this.settingsForm.value.documentDetailsHiddenFields
|
this.settingsForm.value.documentDetailsHiddenFields
|
||||||
|
|||||||
@@ -154,11 +154,29 @@
|
|||||||
& section {
|
& section {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
text-align: initial;
|
text-align: initial;
|
||||||
|
pointer-events: auto;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
transform-origin: 0 0;
|
transform-origin: 0 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
& :is(.linkAnnotation, .buttonWidgetAnnotation.pushButton) > a {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
font-size: 1em;
|
||||||
|
transition: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
& :is(.linkAnnotation, .buttonWidgetAnnotation.pushButton):not(.hasBorder)
|
||||||
|
> a:hover {
|
||||||
|
opacity: 0.2;
|
||||||
|
background-color: rgb(255 255 0);
|
||||||
|
}
|
||||||
|
|
||||||
& .annotationTextContent {
|
& .annotationTextContent {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
:host ::ng-deep .textLayer.selecting ~ .annotationLayer section {
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
import { SimpleChange } from '@angular/core'
|
import { SimpleChange } from '@angular/core'
|
||||||
import { ComponentFixture, TestBed } from '@angular/core/testing'
|
import { ComponentFixture, TestBed } from '@angular/core/testing'
|
||||||
import * as pdfjs from 'pdfjs-dist/legacy/build/pdf.mjs'
|
import * as pdfjs from 'pdfjs-dist/legacy/build/pdf.mjs'
|
||||||
import { PDFSinglePageViewer, PDFViewer } from 'pdfjs-dist/web/pdf_viewer.mjs'
|
import {
|
||||||
|
LinkTarget,
|
||||||
|
PDFSinglePageViewer,
|
||||||
|
PDFViewer,
|
||||||
|
} from 'pdfjs-dist/web/pdf_viewer.mjs'
|
||||||
import { PngxPdfViewerComponent } from './pdf-viewer.component'
|
import { PngxPdfViewerComponent } from './pdf-viewer.component'
|
||||||
import { PdfRenderMode, PdfZoomLevel, PdfZoomScale } from './pdf-viewer.types'
|
import { PdfRenderMode, PdfZoomLevel, PdfZoomScale } from './pdf-viewer.types'
|
||||||
|
|
||||||
@@ -58,6 +62,16 @@ describe('PngxPdfViewerComponent', () => {
|
|||||||
expect((component as any).pdfViewer).toBeInstanceOf(PDFViewer)
|
expect((component as any).pdfViewer).toBeInstanceOf(PDFViewer)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('opens external links in a new tab', () => {
|
||||||
|
const linkService = (component as any).linkService
|
||||||
|
expect(linkService.options).toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
externalLinkTarget: LinkTarget.BLANK,
|
||||||
|
externalLinkRel: 'noopener noreferrer nofollow',
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
it('resolves the worker source relative to the document base URI', async () => {
|
it('resolves the worker source relative to the document base URI', async () => {
|
||||||
setBaseHref('/paperless/')
|
setBaseHref('/paperless/')
|
||||||
const getDocumentSpy = jest.spyOn(pdfjs, 'getDocument')
|
const getDocumentSpy = jest.spyOn(pdfjs, 'getDocument')
|
||||||
@@ -76,6 +90,7 @@ describe('PngxPdfViewerComponent', () => {
|
|||||||
withCredentials: true,
|
withCredentials: true,
|
||||||
wasmUrl: expect.stringContaining('/paperless/assets/wasm/'),
|
wasmUrl: expect.stringContaining('/paperless/assets/wasm/'),
|
||||||
iccUrl: expect.stringContaining('/paperless/assets/iccs/'),
|
iccUrl: expect.stringContaining('/paperless/assets/iccs/'),
|
||||||
|
cMapUrl: expect.stringContaining('/paperless/assets/cmaps/'),
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import {
|
|||||||
} from 'pdfjs-dist/legacy/build/pdf.mjs'
|
} from 'pdfjs-dist/legacy/build/pdf.mjs'
|
||||||
import {
|
import {
|
||||||
EventBus,
|
EventBus,
|
||||||
|
LinkTarget,
|
||||||
PDFFindController,
|
PDFFindController,
|
||||||
PDFLinkService,
|
PDFLinkService,
|
||||||
PDFSinglePageViewer,
|
PDFSinglePageViewer,
|
||||||
@@ -75,7 +76,11 @@ export class PngxPdfViewerComponent
|
|||||||
private lastViewerPage?: number
|
private lastViewerPage?: number
|
||||||
|
|
||||||
private readonly eventBus = new EventBus()
|
private readonly eventBus = new EventBus()
|
||||||
private readonly linkService = new PDFLinkService({ eventBus: this.eventBus })
|
private readonly linkService = new PDFLinkService({
|
||||||
|
eventBus: this.eventBus,
|
||||||
|
externalLinkTarget: LinkTarget.BLANK,
|
||||||
|
externalLinkRel: 'noopener noreferrer nofollow',
|
||||||
|
})
|
||||||
private readonly findController = new PDFFindController({
|
private readonly findController = new PDFFindController({
|
||||||
eventBus: this.eventBus,
|
eventBus: this.eventBus,
|
||||||
linkService: this.linkService,
|
linkService: this.linkService,
|
||||||
@@ -185,6 +190,7 @@ export class PngxPdfViewerComponent
|
|||||||
withCredentials: true,
|
withCredentials: true,
|
||||||
wasmUrl: new URL('assets/wasm/', this.document.baseURI).toString(),
|
wasmUrl: new URL('assets/wasm/', this.document.baseURI).toString(),
|
||||||
iccUrl: new URL('assets/iccs/', this.document.baseURI).toString(),
|
iccUrl: new URL('assets/iccs/', this.document.baseURI).toString(),
|
||||||
|
cMapUrl: new URL('assets/cmaps/', this.document.baseURI).toString(),
|
||||||
}
|
}
|
||||||
this.loadingTask = getDocument(initOptions)
|
this.loadingTask = getDocument(initOptions)
|
||||||
try {
|
try {
|
||||||
|
|||||||
+77
-51
@@ -1,58 +1,84 @@
|
|||||||
<div class="btn-group">
|
<div class="d-flex align-items-center">
|
||||||
<button type="button" class="btn btn-sm btn-outline-primary" (click)="clickSuggest()" [disabled]="disabled() || loading() || (suggestions() && !aiEnabled())" [aria-label]="noSuggestions ? 'No suggestions' : 'Suggest'" i18n-aria-label>
|
<div class="btn-group">
|
||||||
@if (loading()) {
|
<button type="button" class="btn btn-sm btn-outline-primary" (click)="clickSuggest()" [disabled]="disabled() || loading() || (suggestions() && !aiEnabled())" [aria-label]="noSuggestions ? 'No suggestions' : 'Suggest'" i18n-aria-label>
|
||||||
<div class="spinner-border spinner-border-sm" role="status"></div>
|
@if (loading()) {
|
||||||
} @else if (noSuggestions) {
|
<div class="spinner-border spinner-border-sm" role="status"></div>
|
||||||
<i-bs width="1.2em" height="1.2em" name="check-circle"></i-bs>
|
} @else if (noSuggestions) {
|
||||||
} @else {
|
<i-bs width="1.2em" height="1.2em" name="check-circle"></i-bs>
|
||||||
<i-bs width="1.2em" height="1.2em" name="stars"></i-bs>
|
} @else {
|
||||||
|
<i-bs width="1.2em" height="1.2em" name="lightbulb"></i-bs>
|
||||||
|
}
|
||||||
|
@if (noSuggestions) {
|
||||||
|
<span class="d-none d-lg-inline ps-1" i18n>No suggestions</span>
|
||||||
|
} @else {
|
||||||
|
<span class="d-none d-lg-inline ps-1" i18n>Suggest</span>
|
||||||
|
}
|
||||||
|
@if (totalSuggestions > 0) {
|
||||||
|
<span class="badge bg-primary ms-2">{{ totalSuggestions }}</span>
|
||||||
|
}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
@if (aiEnabled()) {
|
||||||
|
<div class="btn-group" ngbDropdown #dropdown="ngbDropdown" [popperOptions]="popperOptions">
|
||||||
|
<button type="button" class="btn btn-sm btn-outline-primary" ngbDropdownToggle [disabled]="disabled() || loading() || !suggestions()" aria-expanded="false" aria-controls="suggestionsDropdown" aria-label="Suggestions dropdown">
|
||||||
|
<span class="visually-hidden" i18n>Show suggestions</span>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<div ngbDropdownMenu aria-labelledby="suggestionsDropdown" class="shadow suggestions-dropdown">
|
||||||
|
<div class="list-group list-group-flush small pb-0">
|
||||||
|
@if (novelSuggestions === 0 && reusableSuggestions === 0) {
|
||||||
|
<div class="list-group-item text-muted fst-italic">
|
||||||
|
<small class="text-muted small fst-italic" i18n>No novel suggestions</small>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
@if (suggestions()?.suggested_tags?.length > 0) {
|
||||||
|
<small class="list-group-item text-uppercase text-muted small"><i-bs class="me-2" name="tags"></i-bs><ng-container i18n>Tags</ng-container></small>
|
||||||
|
@for (tag of suggestions().suggested_tags; track tag) {
|
||||||
|
<button type="button" class="list-group-item list-group-item-action bg-light" (click)="addTag.emit(tag)">{{ tag }}</button>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@if (suggestions()?.suggested_document_types?.length > 0) {
|
||||||
|
<div class="list-group-item text-uppercase text-muted small"><i-bs class="me-2" name="hash"></i-bs><ng-container i18n>Document Types</ng-container></div>
|
||||||
|
@for (type of suggestions().suggested_document_types; track type) {
|
||||||
|
<button type="button" class="list-group-item list-group-item-action bg-light" (click)="addDocumentType.emit(type)">{{ type }}</button>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@if (suggestions()?.suggested_correspondents?.length > 0) {
|
||||||
|
<div class="list-group-item text-uppercase text-muted small"><i-bs class="me-2" name="person"></i-bs><ng-container i18n>Correspondents</ng-container></div>
|
||||||
|
@for (correspondent of suggestions().suggested_correspondents; track correspondent) {
|
||||||
|
<button type="button" class="list-group-item list-group-item-action bg-light" (click)="addCorrespondent.emit(correspondent)">{{ correspondent }}</button>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@if (reusableSuggestions > 0) {
|
||||||
|
<div class="list-group-item text-muted fst-italic">
|
||||||
|
<small class="text-muted small fst-italic" i18n>{reusableSuggestions, plural, =1 {1 existing value suggested below} other {{{reusableSuggestions}} existing values suggested below}}</small>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
}
|
}
|
||||||
@if (noSuggestions) {
|
</div>
|
||||||
<span class="d-none d-lg-inline ps-1" i18n>No suggestions</span>
|
|
||||||
} @else {
|
|
||||||
<span class="d-none d-lg-inline ps-1" i18n>Suggest</span>
|
|
||||||
}
|
|
||||||
@if (totalSuggestions > 0) {
|
|
||||||
<span class="badge bg-primary ms-2">{{ totalSuggestions }}</span>
|
|
||||||
}
|
|
||||||
</button>
|
|
||||||
|
|
||||||
@if (aiEnabled()) {
|
@if (aiEnabled()) {
|
||||||
<div class="btn-group" ngbDropdown #dropdown="ngbDropdown" [popperOptions]="popperOptions">
|
<div ngbDropdown autoClose="outside" placement="bottom-end" [popperOptions]="popperOptions">
|
||||||
<button type="button" class="btn btn-sm btn-outline-primary" ngbDropdownToggle [disabled]="disabled() || loading() || !suggestions()" aria-expanded="false" aria-controls="suggestionsDropdown" aria-label="Suggestions dropdown">
|
<button type="button" class="btn btn-sm btn-link position-relative" ngbDropdownToggle [disabled]="disabled() || loading()" i18n-title title="Suggestion options">
|
||||||
<span class="visually-hidden" i18n>Show suggestions</span>
|
<i-bs name="three-dots"></i-bs>
|
||||||
|
@if (source() !== defaultSource()) {
|
||||||
|
<span class="position-absolute top-0 start-100 translate-middle p-1 bg-primary border border-light rounded-circle">
|
||||||
|
<span class="visually-hidden" i18n>Not using default</span>
|
||||||
|
</span>
|
||||||
|
}
|
||||||
</button>
|
</button>
|
||||||
|
<div ngbDropdownMenu class="shadow p-3">
|
||||||
<div ngbDropdownMenu aria-labelledby="suggestionsDropdown" class="shadow suggestions-dropdown">
|
<div class="small text-muted mb-2" i18n>Suggest using:</div>
|
||||||
<div class="list-group list-group-flush small pb-0">
|
<div class="form-check small">
|
||||||
@if (novelSuggestions === 0 && reusableSuggestions === 0) {
|
<input class="form-check-input" type="checkbox" id="suggestionSourceML" [checked]="useML" [disabled]="useML && !useAI" (change)="setSources($event.target.checked, useAI)">
|
||||||
<div class="list-group-item text-muted fst-italic">
|
<label class="form-check-label d-inline-flex align-items-center gap-1" for="suggestionSourceML"><i-bs name="cpu"></i-bs><ng-container i18n>ML</ng-container></label>
|
||||||
<small class="text-muted small fst-italic" i18n>No novel suggestions</small>
|
</div>
|
||||||
</div>
|
<div class="form-check small">
|
||||||
}
|
<input class="form-check-input" type="checkbox" id="suggestionSourceAI" [checked]="useAI" [disabled]="useAI && !useML" (change)="setSources(useML, $event.target.checked)">
|
||||||
@if (suggestions()?.suggested_tags?.length > 0) {
|
<label class="form-check-label d-inline-flex align-items-center gap-1" for="suggestionSourceAI"><i-bs name="stars"></i-bs><ng-container i18n>AI</ng-container></label>
|
||||||
<small class="list-group-item text-uppercase text-muted small"><i-bs class="me-2" name="tags"></i-bs><ng-container i18n>Tags</ng-container></small>
|
|
||||||
@for (tag of suggestions().suggested_tags; track tag) {
|
|
||||||
<button type="button" class="list-group-item list-group-item-action bg-light" (click)="addTag.emit(tag)">{{ tag }}</button>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@if (suggestions()?.suggested_document_types?.length > 0) {
|
|
||||||
<div class="list-group-item text-uppercase text-muted small"><i-bs class="me-2" name="hash"></i-bs><ng-container i18n>Document Types</ng-container></div>
|
|
||||||
@for (type of suggestions().suggested_document_types; track type) {
|
|
||||||
<button type="button" class="list-group-item list-group-item-action bg-light" (click)="addDocumentType.emit(type)">{{ type }}</button>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@if (suggestions()?.suggested_correspondents?.length > 0) {
|
|
||||||
<div class="list-group-item text-uppercase text-muted small"><i-bs class="me-2" name="person"></i-bs><ng-container i18n>Correspondents</ng-container></div>
|
|
||||||
@for (correspondent of suggestions().suggested_correspondents; track correspondent) {
|
|
||||||
<button type="button" class="list-group-item list-group-item-action bg-light" (click)="addCorrespondent.emit(correspondent)">{{ correspondent }}</button>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@if (reusableSuggestions > 0) {
|
|
||||||
<div class="list-group-item text-muted fst-italic">
|
|
||||||
<small class="text-muted small fst-italic" i18n>{reusableSuggestions, plural, =1 {1 existing value suggested below} other {{{reusableSuggestions}} existing values suggested below}}</small>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+4
@@ -1,3 +1,7 @@
|
|||||||
.suggestions-dropdown {
|
.suggestions-dropdown {
|
||||||
min-width: 250px;
|
min-width: 250px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.btn-link.dropdown-toggle::after {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|||||||
+59
-1
@@ -1,6 +1,7 @@
|
|||||||
import { ComponentFixture, TestBed } from '@angular/core/testing'
|
import { ComponentFixture, TestBed } from '@angular/core/testing'
|
||||||
import { NgbDropdownModule } from '@ng-bootstrap/ng-bootstrap'
|
import { NgbDropdownModule } from '@ng-bootstrap/ng-bootstrap'
|
||||||
import { NgxBootstrapIconsModule, allIcons } from 'ngx-bootstrap-icons'
|
import { NgxBootstrapIconsModule, allIcons } from 'ngx-bootstrap-icons'
|
||||||
|
import { SuggestionSource } from 'src/app/data/ui-settings'
|
||||||
import { SuggestionsDropdownComponent } from './suggestions-dropdown.component'
|
import { SuggestionsDropdownComponent } from './suggestions-dropdown.component'
|
||||||
|
|
||||||
describe('SuggestionsDropdownComponent', () => {
|
describe('SuggestionsDropdownComponent', () => {
|
||||||
@@ -179,14 +180,71 @@ describe('SuggestionsDropdownComponent', () => {
|
|||||||
|
|
||||||
it('should toggle dropdown when clickSuggest is called and suggestions are not null', () => {
|
it('should toggle dropdown when clickSuggest is called and suggestions are not null', () => {
|
||||||
fixture.componentRef.setInput('aiEnabled', true)
|
fixture.componentRef.setInput('aiEnabled', true)
|
||||||
|
fixture.componentRef.setInput('fetchedSources', [SuggestionSource.ML])
|
||||||
fixture.detectChanges()
|
fixture.detectChanges()
|
||||||
fixture.componentRef.setInput('suggestions', {
|
fixture.componentRef.setInput('suggestions', {
|
||||||
suggested_correspondents: [],
|
suggested_correspondents: [],
|
||||||
suggested_tags: [],
|
suggested_tags: [],
|
||||||
suggested_document_types: [],
|
suggested_document_types: [],
|
||||||
})
|
})
|
||||||
|
fixture.detectChanges()
|
||||||
component.clickSuggest()
|
component.clickSuggest()
|
||||||
expect(component.dropdown.open).toBeTruthy()
|
expect(component.dropdown.isOpen()).toBeTruthy()
|
||||||
expect(fixture.nativeElement.textContent).toContain('No novel suggestions')
|
expect(fixture.nativeElement.textContent).toContain('No novel suggestions')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should fetch unfetched sources and show existing suggestions', () => {
|
||||||
|
jest.spyOn(component.getSuggestions, 'emit')
|
||||||
|
fixture.componentRef.setInput('aiEnabled', true)
|
||||||
|
fixture.componentRef.setInput('source', SuggestionSource.Both)
|
||||||
|
fixture.componentRef.setInput('fetchedSources', [SuggestionSource.ML])
|
||||||
|
fixture.componentRef.setInput('suggestions', { tags: [1] })
|
||||||
|
fixture.detectChanges()
|
||||||
|
component.clickSuggest()
|
||||||
|
expect(component.getSuggestions.emit).toHaveBeenCalledWith(
|
||||||
|
SuggestionSource.Both
|
||||||
|
)
|
||||||
|
expect(component.dropdown.isOpen()).toBeTruthy()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should only show source options when AI is enabled', () => {
|
||||||
|
expect(
|
||||||
|
fixture.nativeElement.querySelector('#suggestionSourceML')
|
||||||
|
).toBeNull()
|
||||||
|
fixture.componentRef.setInput('aiEnabled', true)
|
||||||
|
fixture.detectChanges()
|
||||||
|
fixture.nativeElement
|
||||||
|
.querySelector('button[title="Suggestion options"]')
|
||||||
|
.click()
|
||||||
|
fixture.detectChanges()
|
||||||
|
expect(
|
||||||
|
fixture.nativeElement.querySelector('#suggestionSourceML')
|
||||||
|
).not.toBeNull()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should emit source changes and never allow no source', () => {
|
||||||
|
const emitSpy = jest.spyOn(component.sourceChange, 'emit')
|
||||||
|
component.setSources(true, true)
|
||||||
|
expect(emitSpy).toHaveBeenCalledWith(SuggestionSource.Both)
|
||||||
|
component.setSources(true, false)
|
||||||
|
expect(emitSpy).toHaveBeenCalledWith(SuggestionSource.ML)
|
||||||
|
component.setSources(false, true)
|
||||||
|
expect(emitSpy).toHaveBeenCalledWith(SuggestionSource.AI)
|
||||||
|
|
||||||
|
emitSpy.mockClear()
|
||||||
|
component.setSources(false, false)
|
||||||
|
expect(emitSpy).not.toHaveBeenCalled()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should indicate a non-default source', () => {
|
||||||
|
fixture.componentRef.setInput('aiEnabled', true)
|
||||||
|
fixture.componentRef.setInput('source', SuggestionSource.AI)
|
||||||
|
fixture.componentRef.setInput('defaultSource', SuggestionSource.AI)
|
||||||
|
fixture.detectChanges()
|
||||||
|
expect(fixture.nativeElement.textContent).not.toContain('Not using default')
|
||||||
|
|
||||||
|
fixture.componentRef.setInput('source', SuggestionSource.Both)
|
||||||
|
fixture.detectChanges()
|
||||||
|
expect(fixture.nativeElement.textContent).toContain('Not using default')
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
+40
-3
@@ -8,6 +8,7 @@ import {
|
|||||||
import { NgbDropdown, NgbDropdownModule } from '@ng-bootstrap/ng-bootstrap'
|
import { NgbDropdown, NgbDropdownModule } from '@ng-bootstrap/ng-bootstrap'
|
||||||
import { NgxBootstrapIconsModule } from 'ngx-bootstrap-icons'
|
import { NgxBootstrapIconsModule } from 'ngx-bootstrap-icons'
|
||||||
import { DocumentSuggestions } from 'src/app/data/document-suggestions'
|
import { DocumentSuggestions } from 'src/app/data/document-suggestions'
|
||||||
|
import { SuggestionSource } from 'src/app/data/ui-settings'
|
||||||
import { pngxPopperOptions } from 'src/app/utils/popper-options'
|
import { pngxPopperOptions } from 'src/app/utils/popper-options'
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@@ -18,12 +19,16 @@ import { pngxPopperOptions } from 'src/app/utils/popper-options'
|
|||||||
})
|
})
|
||||||
export class SuggestionsDropdownComponent {
|
export class SuggestionsDropdownComponent {
|
||||||
public popperOptions = pngxPopperOptions
|
public popperOptions = pngxPopperOptions
|
||||||
|
public readonly SuggestionSource = SuggestionSource
|
||||||
|
|
||||||
@ViewChild('dropdown') dropdown: NgbDropdown
|
@ViewChild('dropdown') dropdown: NgbDropdown
|
||||||
readonly suggestions = input<DocumentSuggestions>(null)
|
readonly suggestions = input<DocumentSuggestions>(null)
|
||||||
readonly aiEnabled = input(false)
|
readonly aiEnabled = input(false)
|
||||||
readonly loading = input(false)
|
readonly loading = input(false)
|
||||||
readonly disabled = input(false)
|
readonly disabled = input(false)
|
||||||
|
readonly source = input<SuggestionSource>(SuggestionSource.ML)
|
||||||
|
readonly defaultSource = input<SuggestionSource>(SuggestionSource.ML)
|
||||||
|
readonly fetchedSources = input<SuggestionSource[]>([])
|
||||||
|
|
||||||
readonly appliedTags = input<number[]>([])
|
readonly appliedTags = input<number[]>([])
|
||||||
readonly appliedCorrespondent = input<number>(null)
|
readonly appliedCorrespondent = input<number>(null)
|
||||||
@@ -31,8 +36,10 @@ export class SuggestionsDropdownComponent {
|
|||||||
readonly appliedStoragePath = input<number>(null)
|
readonly appliedStoragePath = input<number>(null)
|
||||||
|
|
||||||
@Output()
|
@Output()
|
||||||
getSuggestions: EventEmitter<SuggestionsDropdownComponent> =
|
getSuggestions: EventEmitter<SuggestionSource> = new EventEmitter()
|
||||||
new EventEmitter()
|
|
||||||
|
@Output()
|
||||||
|
sourceChange: EventEmitter<SuggestionSource> = new EventEmitter()
|
||||||
|
|
||||||
@Output()
|
@Output()
|
||||||
addTag: EventEmitter<string> = new EventEmitter()
|
addTag: EventEmitter<string> = new EventEmitter()
|
||||||
@@ -53,12 +60,42 @@ export class SuggestionsDropdownComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!this.suggestions()) {
|
if (!this.suggestions()) {
|
||||||
this.getSuggestions.emit(this)
|
this.getSuggestions.emit(this.source())
|
||||||
|
} else if (this.hasUnfetchedSources) {
|
||||||
|
// sources changed, fetch the rest and show what we have meanwhile
|
||||||
|
this.getSuggestions.emit(this.source())
|
||||||
|
this.dropdown?.open()
|
||||||
} else {
|
} else {
|
||||||
this.dropdown?.toggle()
|
this.dropdown?.toggle()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get useML(): boolean {
|
||||||
|
return this.source() !== SuggestionSource.AI
|
||||||
|
}
|
||||||
|
|
||||||
|
get useAI(): boolean {
|
||||||
|
return this.source() !== SuggestionSource.ML
|
||||||
|
}
|
||||||
|
|
||||||
|
get hasUnfetchedSources(): boolean {
|
||||||
|
const fetched = this.fetchedSources()
|
||||||
|
return (
|
||||||
|
(this.useML && !fetched.includes(SuggestionSource.ML)) ||
|
||||||
|
(this.useAI && !fetched.includes(SuggestionSource.AI))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
public setSources(ml: boolean, ai: boolean) {
|
||||||
|
if (ml && ai) {
|
||||||
|
this.sourceChange.emit(SuggestionSource.Both)
|
||||||
|
} else if (ml) {
|
||||||
|
this.sourceChange.emit(SuggestionSource.ML)
|
||||||
|
} else if (ai) {
|
||||||
|
this.sourceChange.emit(SuggestionSource.AI)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
get novelSuggestions(): number {
|
get novelSuggestions(): number {
|
||||||
return (
|
return (
|
||||||
(this.suggestions()?.suggested_correspondents?.length ?? 0) +
|
(this.suggestions()?.suggested_correspondents?.length ?? 0) +
|
||||||
|
|||||||
@@ -134,11 +134,15 @@
|
|||||||
[loading]="suggestionsLoading()"
|
[loading]="suggestionsLoading()"
|
||||||
[suggestions]="suggestions()"
|
[suggestions]="suggestions()"
|
||||||
[aiEnabled]="aiEnabled"
|
[aiEnabled]="aiEnabled"
|
||||||
|
[source]="suggestionSource"
|
||||||
|
[defaultSource]="defaultSuggestionSource"
|
||||||
|
[fetchedSources]="fetchedSuggestionSources()"
|
||||||
[appliedTags]="documentForm.value.tags"
|
[appliedTags]="documentForm.value.tags"
|
||||||
[appliedCorrespondent]="documentForm.value.correspondent"
|
[appliedCorrespondent]="documentForm.value.correspondent"
|
||||||
[appliedDocumentType]="documentForm.value.document_type"
|
[appliedDocumentType]="documentForm.value.document_type"
|
||||||
[appliedStoragePath]="documentForm.value.storage_path"
|
[appliedStoragePath]="documentForm.value.storage_path"
|
||||||
(getSuggestions)="getSuggestions()"
|
(getSuggestions)="getSuggestions($event)"
|
||||||
|
(sourceChange)="suggestionSourceOverride.set($event)"
|
||||||
(addTag)="createTag($event)"
|
(addTag)="createTag($event)"
|
||||||
(addDocumentType)="createDocumentType($event)"
|
(addDocumentType)="createDocumentType($event)"
|
||||||
(addCorrespondent)="createCorrespondent($event)">
|
(addCorrespondent)="createCorrespondent($event)">
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ import {
|
|||||||
} from 'src/app/data/filter-rule-type'
|
} from 'src/app/data/filter-rule-type'
|
||||||
import { StoragePath } from 'src/app/data/storage-path'
|
import { StoragePath } from 'src/app/data/storage-path'
|
||||||
import { Tag } from 'src/app/data/tag'
|
import { Tag } from 'src/app/data/tag'
|
||||||
import { SETTINGS_KEYS } from 'src/app/data/ui-settings'
|
import { SETTINGS_KEYS, SuggestionSource } from 'src/app/data/ui-settings'
|
||||||
import { PermissionsGuard } from 'src/app/guards/permissions.guard'
|
import { PermissionsGuard } from 'src/app/guards/permissions.guard'
|
||||||
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'
|
||||||
@@ -1528,6 +1528,113 @@ describe('DocumentDetailComponent', () => {
|
|||||||
expect(component.suggestionsLoading()).toBeFalsy()
|
expect(component.suggestionsLoading()).toBeFalsy()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should get and merge ML and AI suggestions when source is both', () => {
|
||||||
|
settingsService.set(
|
||||||
|
SETTINGS_KEYS.DOCUMENT_EDITING_SUGGESTION_SOURCE,
|
||||||
|
SuggestionSource.Both
|
||||||
|
)
|
||||||
|
const getSetting = settingsService.get.bind(settingsService)
|
||||||
|
jest
|
||||||
|
.spyOn(settingsService, 'get')
|
||||||
|
.mockImplementation((key) =>
|
||||||
|
key === SETTINGS_KEYS.AI_ENABLED ? true : getSetting(key)
|
||||||
|
)
|
||||||
|
const suggestionsSpy = jest
|
||||||
|
.spyOn(documentService, 'getSuggestions')
|
||||||
|
.mockReturnValue(of({ tags: [42], dates: ['2024-01-01'] }))
|
||||||
|
const aiSuggestionsSpy = jest
|
||||||
|
.spyOn(documentService, 'getAiSuggestions')
|
||||||
|
.mockReturnValue(
|
||||||
|
of({ title: 'AI title', tags: [42, 43], suggested_tags: ['New'] })
|
||||||
|
)
|
||||||
|
initNormally()
|
||||||
|
expect(suggestionsSpy).toHaveBeenCalled()
|
||||||
|
expect(aiSuggestionsSpy).toHaveBeenCalled()
|
||||||
|
expect(component.suggestions().title).toEqual('AI title')
|
||||||
|
expect(component.suggestions().tags).toEqual([42, 43])
|
||||||
|
expect(component.suggestions().suggested_tags).toEqual(['New'])
|
||||||
|
expect(component.suggestions().dates).toEqual(['2024-01-01'])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should only fetch sources not yet fetched for the document', () => {
|
||||||
|
settingsService.set(SETTINGS_KEYS.DOCUMENT_EDITING_AUTO_SUGGEST, false)
|
||||||
|
settingsService.set(
|
||||||
|
SETTINGS_KEYS.DOCUMENT_EDITING_SUGGESTION_SOURCE,
|
||||||
|
SuggestionSource.ML
|
||||||
|
)
|
||||||
|
const getSetting = settingsService.get.bind(settingsService)
|
||||||
|
jest
|
||||||
|
.spyOn(settingsService, 'get')
|
||||||
|
.mockImplementation((key) =>
|
||||||
|
key === SETTINGS_KEYS.AI_ENABLED ? true : getSetting(key)
|
||||||
|
)
|
||||||
|
const suggestionsSpy = jest
|
||||||
|
.spyOn(documentService, 'getSuggestions')
|
||||||
|
.mockReturnValue(of({ tags: [42] }))
|
||||||
|
const aiSuggestionsSpy = jest
|
||||||
|
.spyOn(documentService, 'getAiSuggestions')
|
||||||
|
.mockReturnValue(of({ tags: [43] }))
|
||||||
|
initNormally()
|
||||||
|
|
||||||
|
component.getSuggestions()
|
||||||
|
expect(suggestionsSpy).toHaveBeenCalledTimes(1)
|
||||||
|
expect(aiSuggestionsSpy).not.toHaveBeenCalled()
|
||||||
|
|
||||||
|
component.getSuggestions(SuggestionSource.Both)
|
||||||
|
expect(suggestionsSpy).toHaveBeenCalledTimes(1)
|
||||||
|
expect(aiSuggestionsSpy).toHaveBeenCalledTimes(1)
|
||||||
|
expect(component.suggestions().tags).toEqual([42, 43])
|
||||||
|
|
||||||
|
component.getSuggestions(SuggestionSource.Both)
|
||||||
|
expect(suggestionsSpy).toHaveBeenCalledTimes(1)
|
||||||
|
expect(aiSuggestionsSpy).toHaveBeenCalledTimes(1)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should use the per-document source override and reset it on document change', () => {
|
||||||
|
settingsService.set(SETTINGS_KEYS.DOCUMENT_EDITING_AUTO_SUGGEST, false)
|
||||||
|
const getSetting = settingsService.get.bind(settingsService)
|
||||||
|
jest
|
||||||
|
.spyOn(settingsService, 'get')
|
||||||
|
.mockImplementation((key) =>
|
||||||
|
key === SETTINGS_KEYS.AI_ENABLED ? true : getSetting(key)
|
||||||
|
)
|
||||||
|
initNormally()
|
||||||
|
expect(component.suggestionSource).toEqual(SuggestionSource.AI)
|
||||||
|
component.suggestionSourceOverride.set(SuggestionSource.ML)
|
||||||
|
expect(component.suggestionSource).toEqual(SuggestionSource.ML)
|
||||||
|
|
||||||
|
jest
|
||||||
|
.spyOn(documentService, 'get')
|
||||||
|
.mockReturnValueOnce(of(Object.assign({}, doc)))
|
||||||
|
;(component as any).loadDocument(doc.id, true)
|
||||||
|
expect(component.suggestionSourceOverride()).toBeNull()
|
||||||
|
expect(component.fetchedSuggestionSources()).toEqual([])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should keep suggestions from one source if the other fails', () => {
|
||||||
|
settingsService.set(
|
||||||
|
SETTINGS_KEYS.DOCUMENT_EDITING_SUGGESTION_SOURCE,
|
||||||
|
SuggestionSource.Both
|
||||||
|
)
|
||||||
|
const getSetting = settingsService.get.bind(settingsService)
|
||||||
|
jest
|
||||||
|
.spyOn(settingsService, 'get')
|
||||||
|
.mockImplementation((key) =>
|
||||||
|
key === SETTINGS_KEYS.AI_ENABLED ? true : getSetting(key)
|
||||||
|
)
|
||||||
|
const errorSpy = jest.spyOn(toastService, 'showError')
|
||||||
|
jest
|
||||||
|
.spyOn(documentService, 'getSuggestions')
|
||||||
|
.mockReturnValue(of({ tags: [42] }))
|
||||||
|
jest
|
||||||
|
.spyOn(documentService, 'getAiSuggestions')
|
||||||
|
.mockReturnValue(throwError(() => new Error('failed')))
|
||||||
|
initNormally()
|
||||||
|
expect(errorSpy).toHaveBeenCalled()
|
||||||
|
expect(component.suggestions().tags).toEqual([42])
|
||||||
|
expect(component.fetchedSuggestionSources()).toEqual([SuggestionSource.ML])
|
||||||
|
})
|
||||||
|
|
||||||
it('should show error if needed for get suggestions', () => {
|
it('should show error if needed for get suggestions', () => {
|
||||||
const suggestionsSpy = jest.spyOn(documentService, 'getSuggestions')
|
const suggestionsSpy = jest.spyOn(documentService, 'getSuggestions')
|
||||||
const errorSpy = jest.spyOn(toastService, 'showError')
|
const errorSpy = jest.spyOn(toastService, 'showError')
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ import {
|
|||||||
import { dirtyCheck, DirtyComponent } from '@ngneat/dirty-check-forms'
|
import { dirtyCheck, DirtyComponent } from '@ngneat/dirty-check-forms'
|
||||||
import { NgxBootstrapIconsModule } from 'ngx-bootstrap-icons'
|
import { NgxBootstrapIconsModule } from 'ngx-bootstrap-icons'
|
||||||
import { DeviceDetectorService } from 'ngx-device-detector'
|
import { DeviceDetectorService } from 'ngx-device-detector'
|
||||||
import { BehaviorSubject, Observable, of, Subject, timer } from 'rxjs'
|
import { BehaviorSubject, merge, Observable, of, Subject, timer } from 'rxjs'
|
||||||
import {
|
import {
|
||||||
catchError,
|
catchError,
|
||||||
debounceTime,
|
debounceTime,
|
||||||
@@ -48,7 +48,10 @@ import { DataType } from 'src/app/data/datatype'
|
|||||||
import { Document, DocumentVersionInfo } from 'src/app/data/document'
|
import { Document, DocumentVersionInfo } from 'src/app/data/document'
|
||||||
import { DocumentMetadata } from 'src/app/data/document-metadata'
|
import { DocumentMetadata } from 'src/app/data/document-metadata'
|
||||||
import { DocumentNote } from 'src/app/data/document-note'
|
import { DocumentNote } from 'src/app/data/document-note'
|
||||||
import { DocumentSuggestions } from 'src/app/data/document-suggestions'
|
import {
|
||||||
|
DocumentSuggestions,
|
||||||
|
mergeSuggestions,
|
||||||
|
} from 'src/app/data/document-suggestions'
|
||||||
import { DocumentType } from 'src/app/data/document-type'
|
import { DocumentType } from 'src/app/data/document-type'
|
||||||
import { FilterRule } from 'src/app/data/filter-rule'
|
import { FilterRule } from 'src/app/data/filter-rule'
|
||||||
import {
|
import {
|
||||||
@@ -63,7 +66,7 @@ import {
|
|||||||
import { ObjectWithId } from 'src/app/data/object-with-id'
|
import { ObjectWithId } from 'src/app/data/object-with-id'
|
||||||
import { StoragePath } from 'src/app/data/storage-path'
|
import { StoragePath } from 'src/app/data/storage-path'
|
||||||
import { Tag } from 'src/app/data/tag'
|
import { Tag } from 'src/app/data/tag'
|
||||||
import { SETTINGS_KEYS } from 'src/app/data/ui-settings'
|
import { SETTINGS_KEYS, SuggestionSource } from 'src/app/data/ui-settings'
|
||||||
import { User } from 'src/app/data/user'
|
import { User } from 'src/app/data/user'
|
||||||
import { IfPermissionsDirective } from 'src/app/directives/if-permissions.directive'
|
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'
|
||||||
@@ -240,6 +243,10 @@ export class DocumentDetailComponent
|
|||||||
private readonly autoSuggestSetting = this.settings.getSignal<boolean>(
|
private readonly autoSuggestSetting = this.settings.getSignal<boolean>(
|
||||||
SETTINGS_KEYS.DOCUMENT_EDITING_AUTO_SUGGEST
|
SETTINGS_KEYS.DOCUMENT_EDITING_AUTO_SUGGEST
|
||||||
)
|
)
|
||||||
|
private readonly suggestionSourceSetting =
|
||||||
|
this.settings.getSignal<SuggestionSource>(
|
||||||
|
SETTINGS_KEYS.DOCUMENT_EDITING_SUGGESTION_SOURCE
|
||||||
|
)
|
||||||
private readonly hiddenFieldsSetting = this.settings.getSignal<
|
private readonly hiddenFieldsSetting = this.settings.getSignal<
|
||||||
DocumentDetailFieldID[]
|
DocumentDetailFieldID[]
|
||||||
>(SETTINGS_KEYS.DOCUMENT_DETAILS_HIDDEN_FIELDS)
|
>(SETTINGS_KEYS.DOCUMENT_DETAILS_HIDDEN_FIELDS)
|
||||||
@@ -261,6 +268,9 @@ export class DocumentDetailComponent
|
|||||||
readonly metadata = signal<DocumentMetadata>(undefined)
|
readonly metadata = signal<DocumentMetadata>(undefined)
|
||||||
readonly suggestions = signal<DocumentSuggestions>(undefined)
|
readonly suggestions = signal<DocumentSuggestions>(undefined)
|
||||||
readonly suggestionsLoading = signal(false)
|
readonly suggestionsLoading = signal(false)
|
||||||
|
// per-document, resets on navigation
|
||||||
|
readonly suggestionSourceOverride = signal<SuggestionSource>(null)
|
||||||
|
readonly fetchedSuggestionSources = signal<SuggestionSource[]>([])
|
||||||
readonly users = signal<User[]>(undefined)
|
readonly users = signal<User[]>(undefined)
|
||||||
|
|
||||||
readonly title = signal<string>(undefined)
|
readonly title = signal<string>(undefined)
|
||||||
@@ -365,6 +375,15 @@ export class DocumentDetailComponent
|
|||||||
return this.autoSuggestSetting()
|
return this.autoSuggestSetting()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get defaultSuggestionSource(): SuggestionSource {
|
||||||
|
return this.aiEnabled ? this.suggestionSourceSetting() : SuggestionSource.ML
|
||||||
|
}
|
||||||
|
|
||||||
|
get suggestionSource(): SuggestionSource {
|
||||||
|
if (!this.aiEnabled) return SuggestionSource.ML
|
||||||
|
return this.suggestionSourceOverride() ?? this.defaultSuggestionSource
|
||||||
|
}
|
||||||
|
|
||||||
get archiveContentRenderType(): ContentRenderType {
|
get archiveContentRenderType(): ContentRenderType {
|
||||||
const hasArchiveVersion =
|
const hasArchiveVersion =
|
||||||
this.metadata()?.has_archive_version ??
|
this.metadata()?.has_archive_version ??
|
||||||
@@ -590,6 +609,8 @@ export class DocumentDetailComponent
|
|||||||
}
|
}
|
||||||
this.documentId.set(doc.id)
|
this.documentId.set(doc.id)
|
||||||
this.suggestions.set(null)
|
this.suggestions.set(null)
|
||||||
|
this.suggestionSourceOverride.set(null)
|
||||||
|
this.fetchedSuggestionSources.set([])
|
||||||
const openDocument = this.openDocumentService.getOpenDocument(
|
const openDocument = this.openDocumentService.getOpenDocument(
|
||||||
this.documentId()
|
this.documentId()
|
||||||
)
|
)
|
||||||
@@ -1077,29 +1098,44 @@ export class DocumentDetailComponent
|
|||||||
return this.documentForm.get('custom_fields') as FormArray
|
return this.documentForm.get('custom_fields') as FormArray
|
||||||
}
|
}
|
||||||
|
|
||||||
getSuggestions() {
|
getSuggestions(source: SuggestionSource = this.suggestionSource) {
|
||||||
|
const sources = (
|
||||||
|
source === SuggestionSource.Both
|
||||||
|
? [SuggestionSource.ML, SuggestionSource.AI]
|
||||||
|
: [source]
|
||||||
|
).filter((s) => !this.fetchedSuggestionSources().includes(s))
|
||||||
|
if (!sources.length) return
|
||||||
|
|
||||||
this.suggestionsLoading.set(true)
|
this.suggestionsLoading.set(true)
|
||||||
const suggestionsObservable = this.aiEnabled
|
merge(
|
||||||
? this.documentsService.getAiSuggestions(this.documentId())
|
...sources.map((s) =>
|
||||||
: this.documentsService.getSuggestions(this.documentId())
|
(s === SuggestionSource.AI
|
||||||
suggestionsObservable
|
? this.documentsService.getAiSuggestions(this.documentId())
|
||||||
|
: this.documentsService.getSuggestions(this.documentId())
|
||||||
|
).pipe(
|
||||||
|
first(),
|
||||||
|
map((result) => ({ source: s, result })),
|
||||||
|
catchError((error) => {
|
||||||
|
this.toastService.showError(
|
||||||
|
$localize`Error retrieving suggestions.`,
|
||||||
|
error
|
||||||
|
)
|
||||||
|
return of(null)
|
||||||
|
})
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
.pipe(
|
.pipe(
|
||||||
first(),
|
|
||||||
takeUntil(this.unsubscribeNotifier),
|
takeUntil(this.unsubscribeNotifier),
|
||||||
takeUntil(this.docChangeNotifier),
|
takeUntil(this.docChangeNotifier),
|
||||||
finalize(() => this.suggestionsLoading.set(false))
|
finalize(() => this.suggestionsLoading.set(false))
|
||||||
)
|
)
|
||||||
.subscribe({
|
.subscribe((response) => {
|
||||||
next: (result) => {
|
if (!response) return
|
||||||
this.suggestions.set(result)
|
this.fetchedSuggestionSources.update((f) => [...f, response.source])
|
||||||
},
|
this.suggestions.set(
|
||||||
error: (error) => {
|
mergeSuggestions(this.suggestions(), response.result)
|
||||||
this.suggestions.set(null)
|
)
|
||||||
this.toastService.showError(
|
|
||||||
$localize`Error retrieving suggestions.`,
|
|
||||||
error
|
|
||||||
)
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,3 +15,33 @@ export interface DocumentSuggestions {
|
|||||||
|
|
||||||
dates?: string[] // ISO-formatted date string e.g. 2022-11-03
|
dates?: string[] // ISO-formatted date string e.g. 2022-11-03
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const union = <T>(a: T[] = [], b: T[] = []): T[] => [...new Set([...a, ...b])]
|
||||||
|
|
||||||
|
export function mergeSuggestions(
|
||||||
|
a: DocumentSuggestions,
|
||||||
|
b: DocumentSuggestions
|
||||||
|
): DocumentSuggestions {
|
||||||
|
if (!a) return b
|
||||||
|
return {
|
||||||
|
title: a.title || b.title,
|
||||||
|
tags: union(a.tags, b.tags),
|
||||||
|
suggested_tags: union(a.suggested_tags, b.suggested_tags),
|
||||||
|
correspondents: union(a.correspondents, b.correspondents),
|
||||||
|
suggested_correspondents: union(
|
||||||
|
a.suggested_correspondents,
|
||||||
|
b.suggested_correspondents
|
||||||
|
),
|
||||||
|
document_types: union(a.document_types, b.document_types),
|
||||||
|
suggested_document_types: union(
|
||||||
|
a.suggested_document_types,
|
||||||
|
b.suggested_document_types
|
||||||
|
),
|
||||||
|
storage_paths: union(a.storage_paths, b.storage_paths),
|
||||||
|
suggested_storage_paths: union(
|
||||||
|
a.suggested_storage_paths,
|
||||||
|
b.suggested_storage_paths
|
||||||
|
),
|
||||||
|
dates: union(a.dates, b.dates),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -20,6 +20,12 @@ export enum GlobalSearchType {
|
|||||||
TITLE_CONTENT = 'title-content',
|
TITLE_CONTENT = 'title-content',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum SuggestionSource {
|
||||||
|
ML = 'ml',
|
||||||
|
AI = 'ai',
|
||||||
|
Both = 'both',
|
||||||
|
}
|
||||||
|
|
||||||
export enum CollapsibleSection {
|
export enum CollapsibleSection {
|
||||||
ATTRIBUTES = 'attributes',
|
ATTRIBUTES = 'attributes',
|
||||||
}
|
}
|
||||||
@@ -98,6 +104,8 @@ export const SETTINGS_KEYS = {
|
|||||||
'general-settings:document-editing:overlay-thumbnail',
|
'general-settings:document-editing:overlay-thumbnail',
|
||||||
DOCUMENT_EDITING_AUTO_SUGGEST:
|
DOCUMENT_EDITING_AUTO_SUGGEST:
|
||||||
'general-settings:document-editing:auto-suggest',
|
'general-settings:document-editing:auto-suggest',
|
||||||
|
DOCUMENT_EDITING_SUGGESTION_SOURCE:
|
||||||
|
'general-settings:document-editing:suggestion-source',
|
||||||
DOCUMENT_DETAILS_HIDDEN_FIELDS:
|
DOCUMENT_DETAILS_HIDDEN_FIELDS:
|
||||||
'general-settings:document-details:hidden-fields',
|
'general-settings:document-details:hidden-fields',
|
||||||
SEARCH_DB_ONLY: 'general-settings:search:db-only',
|
SEARCH_DB_ONLY: 'general-settings:search:db-only',
|
||||||
@@ -326,6 +334,11 @@ export const SETTINGS: UiSetting[] = [
|
|||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
default: true,
|
default: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: SETTINGS_KEYS.DOCUMENT_EDITING_SUGGESTION_SOURCE,
|
||||||
|
type: 'string',
|
||||||
|
default: SuggestionSource.AI,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
key: SETTINGS_KEYS.DOCUMENT_DETAILS_HIDDEN_FIELDS,
|
key: SETTINGS_KEYS.DOCUMENT_DETAILS_HIDDEN_FIELDS,
|
||||||
type: 'array',
|
type: 'array',
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -74,6 +74,7 @@ import {
|
|||||||
clipboardCheckFill,
|
clipboardCheckFill,
|
||||||
clipboardFill,
|
clipboardFill,
|
||||||
clockHistory,
|
clockHistory,
|
||||||
|
cpu,
|
||||||
creditCard,
|
creditCard,
|
||||||
dash,
|
dash,
|
||||||
dashCircle,
|
dashCircle,
|
||||||
@@ -118,6 +119,7 @@ import {
|
|||||||
infoCircle,
|
infoCircle,
|
||||||
journalBookmarkFill,
|
journalBookmarkFill,
|
||||||
journals,
|
journals,
|
||||||
|
lightbulb,
|
||||||
link,
|
link,
|
||||||
list,
|
list,
|
||||||
listNested,
|
listNested,
|
||||||
@@ -322,6 +324,7 @@ const icons = {
|
|||||||
clipboardCheckFill,
|
clipboardCheckFill,
|
||||||
clipboardFill,
|
clipboardFill,
|
||||||
clockHistory,
|
clockHistory,
|
||||||
|
cpu,
|
||||||
cash,
|
cash,
|
||||||
creditCard,
|
creditCard,
|
||||||
dash,
|
dash,
|
||||||
@@ -367,6 +370,7 @@ const icons = {
|
|||||||
infoCircle,
|
infoCircle,
|
||||||
journalBookmarkFill,
|
journalBookmarkFill,
|
||||||
journals,
|
journals,
|
||||||
|
lightbulb,
|
||||||
link,
|
link,
|
||||||
list,
|
list,
|
||||||
listNested,
|
listNested,
|
||||||
|
|||||||
@@ -292,6 +292,7 @@ a.btn-link:active,
|
|||||||
a.btn-link:focus-visible,
|
a.btn-link:focus-visible,
|
||||||
.btn-link:hover,
|
.btn-link:hover,
|
||||||
.btn-link:active,
|
.btn-link:active,
|
||||||
|
.btn-link.show,
|
||||||
.btn-link:focus-visible {
|
.btn-link:focus-visible {
|
||||||
color: var(--pngx-primary-lighten-10) !important;
|
color: var(--pngx-primary-lighten-10) !important;
|
||||||
.primary-light & {
|
.primary-light & {
|
||||||
|
|||||||
@@ -25,10 +25,20 @@ export class PDFFindController {
|
|||||||
onIsPageVisible?: () => boolean
|
onIsPageVisible?: () => boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const LinkTarget = {
|
||||||
|
NONE: 0,
|
||||||
|
SELF: 1,
|
||||||
|
BLANK: 2,
|
||||||
|
PARENT: 3,
|
||||||
|
TOP: 4,
|
||||||
|
}
|
||||||
|
|
||||||
export class PDFLinkService {
|
export class PDFLinkService {
|
||||||
private document?: unknown
|
private document?: unknown
|
||||||
private viewer?: unknown
|
private viewer?: unknown
|
||||||
|
|
||||||
|
constructor(readonly options: Record<string, unknown> = {}) {}
|
||||||
|
|
||||||
setDocument(document: unknown): void {
|
setDocument(document: unknown): void {
|
||||||
this.document = document
|
this.document = document
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1079,6 +1079,16 @@ class DocumentSerializer(
|
|||||||
)
|
)
|
||||||
|
|
||||||
def get_page_count(self, obj) -> int | None:
|
def get_page_count(self, obj) -> int | None:
|
||||||
|
# Like content versions get their own page count from the newest version,
|
||||||
|
# use the prefetched versions cache to avoid an extra query
|
||||||
|
prefetched_cache = getattr(obj, "_prefetched_objects_cache", None)
|
||||||
|
prefetched_versions = (
|
||||||
|
prefetched_cache.get("versions")
|
||||||
|
if isinstance(prefetched_cache, dict)
|
||||||
|
else None
|
||||||
|
)
|
||||||
|
if obj.root_document_id is None and prefetched_versions:
|
||||||
|
return sort_versions_newest_first(prefetched_versions)[0].page_count
|
||||||
return obj.page_count
|
return obj.page_count
|
||||||
|
|
||||||
@extend_schema_field(DuplicateDocumentSummarySerializer(many=True))
|
@extend_schema_field(DuplicateDocumentSummarySerializer(many=True))
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
<meta name="robots" content="noindex,nofollow">
|
<meta name="robots" content="noindex,nofollow">
|
||||||
<meta name="author" content="The Paperless-ngx Team">
|
<meta name="author" content="The Paperless-ngx Team">
|
||||||
<link rel="icon" type="image/x-icon" href="favicon.ico">
|
<link rel="icon" type="image/x-icon" href="favicon.ico">
|
||||||
<link rel="manifest" href="{% static webmanifest %}">
|
<link rel="manifest" href="{% static webmanifest %}" crossorigin="use-credentials">
|
||||||
<link rel="stylesheet" href="{% static styles_css %}">
|
<link rel="stylesheet" href="{% static styles_css %}">
|
||||||
<link rel="apple-touch-icon" href="{% static apple_touch_icon %}">
|
<link rel="apple-touch-icon" href="{% static apple_touch_icon %}">
|
||||||
</head>
|
</head>
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ from documents.models import Document
|
|||||||
from documents.versioning import annotate_effective_content
|
from documents.versioning import annotate_effective_content
|
||||||
from documents.views import DocumentSelectionMixin
|
from documents.views import DocumentSelectionMixin
|
||||||
from paperless_testing.dirs import DirectoriesMixin
|
from paperless_testing.dirs import DirectoriesMixin
|
||||||
|
from paperless_testing.factories import DocumentFactory
|
||||||
from paperless_testing.factories import UserFactory
|
from paperless_testing.factories import UserFactory
|
||||||
from paperless_testing.http import read_streaming_response
|
from paperless_testing.http import read_streaming_response
|
||||||
from paperless_testing.permissions import grant_global
|
from paperless_testing.permissions import grant_global
|
||||||
@@ -821,6 +822,26 @@ class TestDocumentVersioningApi(DirectoriesMixin, APITestCase):
|
|||||||
self.assertEqual(resp.status_code, status.HTTP_200_OK)
|
self.assertEqual(resp.status_code, status.HTTP_200_OK)
|
||||||
self.assertEqual(resp.data["content"], "v1-content")
|
self.assertEqual(resp.data["content"], "v1-content")
|
||||||
|
|
||||||
|
def test_page_count_resolves_to_latest_version(self) -> None:
|
||||||
|
root = DocumentFactory(page_count=2)
|
||||||
|
DocumentFactory(root_document=root, version_index=1, page_count=1)
|
||||||
|
unversioned = DocumentFactory(page_count=5)
|
||||||
|
|
||||||
|
resp = self.client.get("/api/documents/?fields=id,page_count")
|
||||||
|
self.assertEqual(resp.status_code, status.HTTP_200_OK)
|
||||||
|
self.assertEqual(
|
||||||
|
{doc["id"]: doc["page_count"] for doc in resp.data["results"]},
|
||||||
|
{root.id: 1, unversioned.id: 5},
|
||||||
|
)
|
||||||
|
|
||||||
|
resp = self.client.get(f"/api/documents/{root.id}/")
|
||||||
|
self.assertEqual(resp.status_code, status.HTTP_200_OK)
|
||||||
|
self.assertEqual(resp.data["page_count"], 1)
|
||||||
|
|
||||||
|
resp = self.client.get(f"/api/documents/{root.id}/?version={root.id}")
|
||||||
|
self.assertEqual(resp.status_code, status.HTTP_200_OK)
|
||||||
|
self.assertEqual(resp.data["page_count"], 2)
|
||||||
|
|
||||||
def _make_root_with_out_of_order_versions(self) -> tuple[Document, ...]:
|
def _make_root_with_out_of_order_versions(self) -> tuple[Document, ...]:
|
||||||
"""
|
"""
|
||||||
A root whose newest version has a *lower* id than an older one, which is
|
A root whose newest version has a *lower* id than an older one, which is
|
||||||
|
|||||||
@@ -1192,6 +1192,7 @@ class DocumentViewSet(
|
|||||||
"version_label",
|
"version_label",
|
||||||
"root_document_id",
|
"root_document_id",
|
||||||
"version_index",
|
"version_index",
|
||||||
|
"page_count",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
"tags",
|
"tags",
|
||||||
@@ -1271,13 +1272,16 @@ class DocumentViewSet(
|
|||||||
if (
|
if (
|
||||||
"version" not in request.query_params
|
"version" not in request.query_params
|
||||||
or not isinstance(response.data, dict)
|
or not isinstance(response.data, dict)
|
||||||
or "content" not in response.data
|
or not ({"content", "page_count"} & response.data.keys())
|
||||||
):
|
):
|
||||||
return response
|
return response
|
||||||
|
|
||||||
root_doc = self.get_object()
|
root_doc = self.get_object()
|
||||||
content_doc = self._resolve_file_doc(root_doc, request)
|
content_doc = self._resolve_file_doc(root_doc, request)
|
||||||
response.data["content"] = content_doc.content or ""
|
if "content" in response.data:
|
||||||
|
response.data["content"] = content_doc.content or ""
|
||||||
|
if "page_count" in response.data:
|
||||||
|
response.data["page_count"] = content_doc.page_count
|
||||||
return response
|
return response
|
||||||
|
|
||||||
def update(self, request, *args, **kwargs):
|
def update(self, request, *args, **kwargs):
|
||||||
|
|||||||
@@ -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-09-18 01:29+0000\n"
|
"POT-Creation-Date: 2026-10-02 23:09+0000\n"
|
||||||
"PO-Revision-Date: 2026-09-18 01:30\n"
|
"PO-Revision-Date: 2026-10-02 23:10\n"
|
||||||
"Last-Translator: \n"
|
"Last-Translator: \n"
|
||||||
"Language-Team: Afrikaans\n"
|
"Language-Team: Afrikaans\n"
|
||||||
"Language: af_ZA\n"
|
"Language: af_ZA\n"
|
||||||
@@ -1615,7 +1615,7 @@ msgid "workflow runs"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: documents/serialisers.py:514 documents/serialisers.py:871
|
#: documents/serialisers.py:514 documents/serialisers.py:871
|
||||||
#: documents/serialisers.py:2883 documents/views.py:343 documents/views.py:2726
|
#: documents/serialisers.py:2895 documents/views.py:342 documents/views.py:2729
|
||||||
#: paperless_mail/serialisers.py:156
|
#: paperless_mail/serialisers.py:156
|
||||||
msgid "Insufficient permissions."
|
msgid "Insufficient permissions."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -1624,38 +1624,38 @@ msgstr ""
|
|||||||
msgid "Invalid color."
|
msgid "Invalid color."
|
||||||
msgstr "Ongeldige kleur."
|
msgstr "Ongeldige kleur."
|
||||||
|
|
||||||
#: documents/serialisers.py:2350
|
#: documents/serialisers.py:2362
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "File type %(type)s not supported"
|
msgid "File type %(type)s not supported"
|
||||||
msgstr "Lêertipe %(type)s word nie ondersteun nie"
|
msgstr "Lêertipe %(type)s word nie ondersteun nie"
|
||||||
|
|
||||||
#: documents/serialisers.py:2394
|
#: documents/serialisers.py:2406
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Custom field id must be an integer: %(id)s"
|
msgid "Custom field id must be an integer: %(id)s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: documents/serialisers.py:2401
|
#: documents/serialisers.py:2413
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Custom field with id %(id)s does not exist"
|
msgid "Custom field with id %(id)s does not exist"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: documents/serialisers.py:2418 documents/serialisers.py:2428
|
#: documents/serialisers.py:2430 documents/serialisers.py:2440
|
||||||
msgid "Custom fields must be a list of integers or an object mapping ids to values."
|
msgid "Custom fields must be a list of integers or an object mapping ids to values."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: documents/serialisers.py:2423
|
#: documents/serialisers.py:2435
|
||||||
msgid "Some custom fields don't exist or were specified twice."
|
msgid "Some custom fields don't exist or were specified twice."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: documents/serialisers.py:2570
|
#: documents/serialisers.py:2582
|
||||||
msgid "Invalid variable detected."
|
msgid "Invalid variable detected."
|
||||||
msgstr "Ongeldige veranderlike bespeur."
|
msgstr "Ongeldige veranderlike bespeur."
|
||||||
|
|
||||||
#: documents/serialisers.py:2939
|
#: documents/serialisers.py:2951
|
||||||
msgid "Duplicate document identifiers are not allowed."
|
msgid "Duplicate document identifiers are not allowed."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: documents/serialisers.py:2969 documents/views.py:4763
|
#: documents/serialisers.py:2981 documents/views.py:4784
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Documents not found: %(ids)s"
|
msgid "Documents not found: %(ids)s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -1910,40 +1910,40 @@ msgstr ""
|
|||||||
msgid "Unable to parse URI {value}"
|
msgid "Unable to parse URI {value}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: documents/views.py:336 documents/views.py:2723
|
#: documents/views.py:335 documents/views.py:2726
|
||||||
msgid "Invalid more_like_id"
|
msgid "Invalid more_like_id"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: documents/views.py:1670
|
#: documents/views.py:1673
|
||||||
msgid "Invalid AI configuration."
|
msgid "Invalid AI configuration."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: documents/views.py:1681
|
#: documents/views.py:1684
|
||||||
msgid "AI backend request timed out."
|
msgid "AI backend request timed out."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: documents/views.py:1693
|
#: documents/views.py:1696
|
||||||
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:2548 documents/views.py:2864
|
#: documents/views.py:2551 documents/views.py:2867
|
||||||
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:4776
|
#: 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:4822
|
#: documents/views.py:4843
|
||||||
msgid "Bundle is already being processed."
|
msgid "Bundle is already being processed."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: documents/views.py:4886
|
#: documents/views.py:4907
|
||||||
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:4900
|
#: documents/views.py:4921
|
||||||
msgid "The share link bundle is unavailable."
|
msgid "The share link bundle is unavailable."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -2188,194 +2188,198 @@ msgid "Sets the LLM embedding model"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/models.py:369
|
#: paperless/models.py:369
|
||||||
msgid "Sets the LLM embedding endpoint, optional"
|
msgid "Sets the LLM embedding API key"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/models.py:376
|
#: paperless/models.py:376
|
||||||
|
msgid "Sets the LLM embedding endpoint, optional"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: paperless/models.py:383
|
||||||
msgid "Sets the LLM embedding chunk size"
|
msgid "Sets the LLM embedding chunk size"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/models.py:382
|
#: paperless/models.py:389
|
||||||
msgid "Sets the LLM context size"
|
msgid "Sets the LLM context size"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/models.py:388
|
#: paperless/models.py:395
|
||||||
msgid "Sets the LLM backend"
|
msgid "Sets the LLM backend"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/models.py:396
|
#: paperless/models.py:403
|
||||||
msgid "Sets the LLM model"
|
msgid "Sets the LLM model"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/models.py:403
|
#: paperless/models.py:410
|
||||||
msgid "Sets the LLM API key"
|
msgid "Sets the LLM API key"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/models.py:410
|
#: paperless/models.py:417
|
||||||
msgid "Sets the LLM endpoint, optional"
|
msgid "Sets the LLM endpoint, optional"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/models.py:417
|
#: paperless/models.py:424
|
||||||
msgid "Sets the LLM output language"
|
msgid "Sets the LLM output language"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/models.py:424
|
#: paperless/models.py:431
|
||||||
msgid "Sets the LLM timeout in seconds"
|
msgid "Sets the LLM timeout in seconds"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/models.py:430
|
#: paperless/models.py:437
|
||||||
msgid "paperless application settings"
|
msgid "paperless application settings"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:558
|
#: paperless/settings/__init__.py:560
|
||||||
msgid "English (US)"
|
msgid "English (US)"
|
||||||
msgstr "Engels (VS)"
|
msgstr "Engels (VS)"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:559
|
#: paperless/settings/__init__.py:561
|
||||||
msgid "Arabic"
|
msgid "Arabic"
|
||||||
msgstr "Arabies"
|
msgstr "Arabies"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:560
|
#: paperless/settings/__init__.py:562
|
||||||
msgid "Afrikaans"
|
msgid "Afrikaans"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:561
|
#: paperless/settings/__init__.py:563
|
||||||
msgid "Belarusian"
|
msgid "Belarusian"
|
||||||
msgstr "Belorussies"
|
msgstr "Belorussies"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:562
|
#: paperless/settings/__init__.py:564
|
||||||
msgid "Bulgarian"
|
msgid "Bulgarian"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:563
|
#: paperless/settings/__init__.py:565
|
||||||
msgid "Catalan"
|
msgid "Catalan"
|
||||||
msgstr "Katalaans"
|
msgstr "Katalaans"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:564
|
#: paperless/settings/__init__.py:566
|
||||||
msgid "Czech"
|
msgid "Czech"
|
||||||
msgstr "Tsjeggies"
|
msgstr "Tsjeggies"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:565
|
#: paperless/settings/__init__.py:567
|
||||||
msgid "Danish"
|
msgid "Danish"
|
||||||
msgstr "Deens"
|
msgstr "Deens"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:566
|
#: paperless/settings/__init__.py:568
|
||||||
msgid "German"
|
msgid "German"
|
||||||
msgstr "Duits"
|
msgstr "Duits"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:567
|
#: paperless/settings/__init__.py:569
|
||||||
msgid "Greek"
|
msgid "Greek"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:568
|
#: paperless/settings/__init__.py:570
|
||||||
msgid "English (GB)"
|
msgid "English (GB)"
|
||||||
msgstr "Engels (GB)"
|
msgstr "Engels (GB)"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:569
|
#: paperless/settings/__init__.py:571
|
||||||
msgid "Spanish"
|
msgid "Spanish"
|
||||||
msgstr "Spaans"
|
msgstr "Spaans"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:570
|
#: paperless/settings/__init__.py:572
|
||||||
msgid "Persian"
|
msgid "Persian"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:571
|
#: paperless/settings/__init__.py:573
|
||||||
msgid "Finnish"
|
msgid "Finnish"
|
||||||
msgstr "Fins"
|
msgstr "Fins"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:572
|
#: paperless/settings/__init__.py:574
|
||||||
msgid "French"
|
msgid "French"
|
||||||
msgstr "Frans"
|
msgstr "Frans"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:573
|
#: paperless/settings/__init__.py:575
|
||||||
msgid "Hungarian"
|
msgid "Hungarian"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:574
|
#: paperless/settings/__init__.py:576
|
||||||
msgid "Indonesian"
|
msgid "Indonesian"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:575
|
#: paperless/settings/__init__.py:577
|
||||||
msgid "Italian"
|
msgid "Italian"
|
||||||
msgstr "Italiaans"
|
msgstr "Italiaans"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:576
|
#: paperless/settings/__init__.py:578
|
||||||
msgid "Japanese"
|
msgid "Japanese"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:577
|
#: paperless/settings/__init__.py:579
|
||||||
msgid "Korean"
|
msgid "Korean"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:578
|
#: paperless/settings/__init__.py:580
|
||||||
msgid "Luxembourgish"
|
msgid "Luxembourgish"
|
||||||
msgstr "Luxemburgs"
|
msgstr "Luxemburgs"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:579
|
#: paperless/settings/__init__.py:581
|
||||||
msgid "Norwegian"
|
msgid "Norwegian"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:580
|
#: paperless/settings/__init__.py:582
|
||||||
msgid "Dutch"
|
msgid "Dutch"
|
||||||
msgstr "Nederlands"
|
msgstr "Nederlands"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:581
|
#: paperless/settings/__init__.py:583
|
||||||
msgid "Polish"
|
msgid "Polish"
|
||||||
msgstr "Pools"
|
msgstr "Pools"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:582
|
#: paperless/settings/__init__.py:584
|
||||||
msgid "Portuguese (Brazil)"
|
msgid "Portuguese (Brazil)"
|
||||||
msgstr "Portugees (Brasilië)"
|
msgstr "Portugees (Brasilië)"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:583
|
#: paperless/settings/__init__.py:585
|
||||||
msgid "Portuguese"
|
msgid "Portuguese"
|
||||||
msgstr "Portugees"
|
msgstr "Portugees"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:584
|
#: paperless/settings/__init__.py:586
|
||||||
msgid "Romanian"
|
msgid "Romanian"
|
||||||
msgstr "Roemeens"
|
msgstr "Roemeens"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:585
|
#: paperless/settings/__init__.py:587
|
||||||
msgid "Russian"
|
msgid "Russian"
|
||||||
msgstr "Russies"
|
msgstr "Russies"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:586
|
#: paperless/settings/__init__.py:588
|
||||||
msgid "Slovak"
|
msgid "Slovak"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:587
|
#: paperless/settings/__init__.py:589
|
||||||
msgid "Slovenian"
|
msgid "Slovenian"
|
||||||
msgstr "Sloweens"
|
msgstr "Sloweens"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:588
|
#: paperless/settings/__init__.py:590
|
||||||
msgid "Serbian"
|
msgid "Serbian"
|
||||||
msgstr "Serwies"
|
msgstr "Serwies"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:589
|
#: paperless/settings/__init__.py:591
|
||||||
msgid "Swedish"
|
msgid "Swedish"
|
||||||
msgstr "Sweeds"
|
msgstr "Sweeds"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:590
|
#: paperless/settings/__init__.py:592
|
||||||
msgid "Turkish"
|
msgid "Turkish"
|
||||||
msgstr "Turks"
|
msgstr "Turks"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:591
|
#: paperless/settings/__init__.py:593
|
||||||
msgid "Ukrainian"
|
msgid "Ukrainian"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:592
|
#: paperless/settings/__init__.py:594
|
||||||
msgid "Vietnamese"
|
msgid "Vietnamese"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:593
|
#: paperless/settings/__init__.py:595
|
||||||
msgid "Chinese Simplified"
|
msgid "Chinese Simplified"
|
||||||
msgstr "Vereenvoudigde Sjinees"
|
msgstr "Vereenvoudigde Sjinees"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:594
|
#: paperless/settings/__init__.py:596
|
||||||
msgid "Chinese Traditional"
|
msgid "Chinese Traditional"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/urls.py:435
|
#: paperless/urls.py:438
|
||||||
msgid "Paperless-ngx administration"
|
msgid "Paperless-ngx administration"
|
||||||
msgstr "Paperless-ngx administrasie"
|
msgstr "Paperless-ngx administrasie"
|
||||||
|
|
||||||
|
|||||||
@@ -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-09-18 01:29+0000\n"
|
"POT-Creation-Date: 2026-10-02 23:09+0000\n"
|
||||||
"PO-Revision-Date: 2026-09-18 01:30\n"
|
"PO-Revision-Date: 2026-10-02 23:10\n"
|
||||||
"Last-Translator: \n"
|
"Last-Translator: \n"
|
||||||
"Language-Team: Amharic\n"
|
"Language-Team: Amharic\n"
|
||||||
"Language: am_ET\n"
|
"Language: am_ET\n"
|
||||||
@@ -1615,7 +1615,7 @@ msgid "workflow runs"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: documents/serialisers.py:514 documents/serialisers.py:871
|
#: documents/serialisers.py:514 documents/serialisers.py:871
|
||||||
#: documents/serialisers.py:2883 documents/views.py:343 documents/views.py:2726
|
#: documents/serialisers.py:2895 documents/views.py:342 documents/views.py:2729
|
||||||
#: paperless_mail/serialisers.py:156
|
#: paperless_mail/serialisers.py:156
|
||||||
msgid "Insufficient permissions."
|
msgid "Insufficient permissions."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -1624,38 +1624,38 @@ msgstr ""
|
|||||||
msgid "Invalid color."
|
msgid "Invalid color."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: documents/serialisers.py:2350
|
#: documents/serialisers.py:2362
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "File type %(type)s not supported"
|
msgid "File type %(type)s not supported"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: documents/serialisers.py:2394
|
#: documents/serialisers.py:2406
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Custom field id must be an integer: %(id)s"
|
msgid "Custom field id must be an integer: %(id)s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: documents/serialisers.py:2401
|
#: documents/serialisers.py:2413
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Custom field with id %(id)s does not exist"
|
msgid "Custom field with id %(id)s does not exist"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: documents/serialisers.py:2418 documents/serialisers.py:2428
|
#: documents/serialisers.py:2430 documents/serialisers.py:2440
|
||||||
msgid "Custom fields must be a list of integers or an object mapping ids to values."
|
msgid "Custom fields must be a list of integers or an object mapping ids to values."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: documents/serialisers.py:2423
|
#: documents/serialisers.py:2435
|
||||||
msgid "Some custom fields don't exist or were specified twice."
|
msgid "Some custom fields don't exist or were specified twice."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: documents/serialisers.py:2570
|
#: documents/serialisers.py:2582
|
||||||
msgid "Invalid variable detected."
|
msgid "Invalid variable detected."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: documents/serialisers.py:2939
|
#: documents/serialisers.py:2951
|
||||||
msgid "Duplicate document identifiers are not allowed."
|
msgid "Duplicate document identifiers are not allowed."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: documents/serialisers.py:2969 documents/views.py:4763
|
#: documents/serialisers.py:2981 documents/views.py:4784
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Documents not found: %(ids)s"
|
msgid "Documents not found: %(ids)s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -1910,40 +1910,40 @@ msgstr ""
|
|||||||
msgid "Unable to parse URI {value}"
|
msgid "Unable to parse URI {value}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: documents/views.py:336 documents/views.py:2723
|
#: documents/views.py:335 documents/views.py:2726
|
||||||
msgid "Invalid more_like_id"
|
msgid "Invalid more_like_id"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: documents/views.py:1670
|
#: documents/views.py:1673
|
||||||
msgid "Invalid AI configuration."
|
msgid "Invalid AI configuration."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: documents/views.py:1681
|
#: documents/views.py:1684
|
||||||
msgid "AI backend request timed out."
|
msgid "AI backend request timed out."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: documents/views.py:1693
|
#: documents/views.py:1696
|
||||||
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:2548 documents/views.py:2864
|
#: documents/views.py:2551 documents/views.py:2867
|
||||||
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:4776
|
#: 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:4822
|
#: documents/views.py:4843
|
||||||
msgid "Bundle is already being processed."
|
msgid "Bundle is already being processed."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: documents/views.py:4886
|
#: documents/views.py:4907
|
||||||
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:4900
|
#: documents/views.py:4921
|
||||||
msgid "The share link bundle is unavailable."
|
msgid "The share link bundle is unavailable."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -2188,194 +2188,198 @@ msgid "Sets the LLM embedding model"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/models.py:369
|
#: paperless/models.py:369
|
||||||
msgid "Sets the LLM embedding endpoint, optional"
|
msgid "Sets the LLM embedding API key"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/models.py:376
|
#: paperless/models.py:376
|
||||||
|
msgid "Sets the LLM embedding endpoint, optional"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: paperless/models.py:383
|
||||||
msgid "Sets the LLM embedding chunk size"
|
msgid "Sets the LLM embedding chunk size"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/models.py:382
|
#: paperless/models.py:389
|
||||||
msgid "Sets the LLM context size"
|
msgid "Sets the LLM context size"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/models.py:388
|
#: paperless/models.py:395
|
||||||
msgid "Sets the LLM backend"
|
msgid "Sets the LLM backend"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/models.py:396
|
#: paperless/models.py:403
|
||||||
msgid "Sets the LLM model"
|
msgid "Sets the LLM model"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/models.py:403
|
#: paperless/models.py:410
|
||||||
msgid "Sets the LLM API key"
|
msgid "Sets the LLM API key"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/models.py:410
|
#: paperless/models.py:417
|
||||||
msgid "Sets the LLM endpoint, optional"
|
msgid "Sets the LLM endpoint, optional"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/models.py:417
|
#: paperless/models.py:424
|
||||||
msgid "Sets the LLM output language"
|
msgid "Sets the LLM output language"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/models.py:424
|
#: paperless/models.py:431
|
||||||
msgid "Sets the LLM timeout in seconds"
|
msgid "Sets the LLM timeout in seconds"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/models.py:430
|
#: paperless/models.py:437
|
||||||
msgid "paperless application settings"
|
msgid "paperless application settings"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:558
|
#: paperless/settings/__init__.py:560
|
||||||
msgid "English (US)"
|
msgid "English (US)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:559
|
#: paperless/settings/__init__.py:561
|
||||||
msgid "Arabic"
|
msgid "Arabic"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:560
|
#: paperless/settings/__init__.py:562
|
||||||
msgid "Afrikaans"
|
msgid "Afrikaans"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:561
|
#: paperless/settings/__init__.py:563
|
||||||
msgid "Belarusian"
|
msgid "Belarusian"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:562
|
#: paperless/settings/__init__.py:564
|
||||||
msgid "Bulgarian"
|
msgid "Bulgarian"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:563
|
#: paperless/settings/__init__.py:565
|
||||||
msgid "Catalan"
|
msgid "Catalan"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:564
|
#: paperless/settings/__init__.py:566
|
||||||
msgid "Czech"
|
msgid "Czech"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:565
|
#: paperless/settings/__init__.py:567
|
||||||
msgid "Danish"
|
msgid "Danish"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:566
|
#: paperless/settings/__init__.py:568
|
||||||
msgid "German"
|
msgid "German"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:567
|
#: paperless/settings/__init__.py:569
|
||||||
msgid "Greek"
|
msgid "Greek"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:568
|
#: paperless/settings/__init__.py:570
|
||||||
msgid "English (GB)"
|
msgid "English (GB)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:569
|
#: paperless/settings/__init__.py:571
|
||||||
msgid "Spanish"
|
msgid "Spanish"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:570
|
#: paperless/settings/__init__.py:572
|
||||||
msgid "Persian"
|
msgid "Persian"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:571
|
#: paperless/settings/__init__.py:573
|
||||||
msgid "Finnish"
|
msgid "Finnish"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:572
|
#: paperless/settings/__init__.py:574
|
||||||
msgid "French"
|
msgid "French"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:573
|
#: paperless/settings/__init__.py:575
|
||||||
msgid "Hungarian"
|
msgid "Hungarian"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:574
|
#: paperless/settings/__init__.py:576
|
||||||
msgid "Indonesian"
|
msgid "Indonesian"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:575
|
#: paperless/settings/__init__.py:577
|
||||||
msgid "Italian"
|
msgid "Italian"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:576
|
#: paperless/settings/__init__.py:578
|
||||||
msgid "Japanese"
|
msgid "Japanese"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:577
|
#: paperless/settings/__init__.py:579
|
||||||
msgid "Korean"
|
msgid "Korean"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:578
|
#: paperless/settings/__init__.py:580
|
||||||
msgid "Luxembourgish"
|
msgid "Luxembourgish"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:579
|
#: paperless/settings/__init__.py:581
|
||||||
msgid "Norwegian"
|
msgid "Norwegian"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:580
|
#: paperless/settings/__init__.py:582
|
||||||
msgid "Dutch"
|
msgid "Dutch"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:581
|
#: paperless/settings/__init__.py:583
|
||||||
msgid "Polish"
|
msgid "Polish"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:582
|
#: paperless/settings/__init__.py:584
|
||||||
msgid "Portuguese (Brazil)"
|
msgid "Portuguese (Brazil)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:583
|
#: paperless/settings/__init__.py:585
|
||||||
msgid "Portuguese"
|
msgid "Portuguese"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:584
|
#: paperless/settings/__init__.py:586
|
||||||
msgid "Romanian"
|
msgid "Romanian"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:585
|
#: paperless/settings/__init__.py:587
|
||||||
msgid "Russian"
|
msgid "Russian"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:586
|
#: paperless/settings/__init__.py:588
|
||||||
msgid "Slovak"
|
msgid "Slovak"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:587
|
#: paperless/settings/__init__.py:589
|
||||||
msgid "Slovenian"
|
msgid "Slovenian"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:588
|
#: paperless/settings/__init__.py:590
|
||||||
msgid "Serbian"
|
msgid "Serbian"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:589
|
#: paperless/settings/__init__.py:591
|
||||||
msgid "Swedish"
|
msgid "Swedish"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:590
|
#: paperless/settings/__init__.py:592
|
||||||
msgid "Turkish"
|
msgid "Turkish"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:591
|
#: paperless/settings/__init__.py:593
|
||||||
msgid "Ukrainian"
|
msgid "Ukrainian"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:592
|
#: paperless/settings/__init__.py:594
|
||||||
msgid "Vietnamese"
|
msgid "Vietnamese"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:593
|
#: paperless/settings/__init__.py:595
|
||||||
msgid "Chinese Simplified"
|
msgid "Chinese Simplified"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:594
|
#: paperless/settings/__init__.py:596
|
||||||
msgid "Chinese Traditional"
|
msgid "Chinese Traditional"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/urls.py:435
|
#: paperless/urls.py:438
|
||||||
msgid "Paperless-ngx administration"
|
msgid "Paperless-ngx administration"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|||||||
@@ -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-09-18 01:29+0000\n"
|
"POT-Creation-Date: 2026-10-02 23:09+0000\n"
|
||||||
"PO-Revision-Date: 2026-09-18 01:30\n"
|
"PO-Revision-Date: 2026-10-02 23:10\n"
|
||||||
"Last-Translator: \n"
|
"Last-Translator: \n"
|
||||||
"Language-Team: Arabic\n"
|
"Language-Team: Arabic\n"
|
||||||
"Language: ar_SA\n"
|
"Language: ar_SA\n"
|
||||||
@@ -1615,7 +1615,7 @@ msgid "workflow runs"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: documents/serialisers.py:514 documents/serialisers.py:871
|
#: documents/serialisers.py:514 documents/serialisers.py:871
|
||||||
#: documents/serialisers.py:2883 documents/views.py:343 documents/views.py:2726
|
#: documents/serialisers.py:2895 documents/views.py:342 documents/views.py:2729
|
||||||
#: paperless_mail/serialisers.py:156
|
#: paperless_mail/serialisers.py:156
|
||||||
msgid "Insufficient permissions."
|
msgid "Insufficient permissions."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -1624,38 +1624,38 @@ msgstr ""
|
|||||||
msgid "Invalid color."
|
msgid "Invalid color."
|
||||||
msgstr "لون خاطئ."
|
msgstr "لون خاطئ."
|
||||||
|
|
||||||
#: documents/serialisers.py:2350
|
#: documents/serialisers.py:2362
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "File type %(type)s not supported"
|
msgid "File type %(type)s not supported"
|
||||||
msgstr "نوع الملف %(type)s غير مدعوم"
|
msgstr "نوع الملف %(type)s غير مدعوم"
|
||||||
|
|
||||||
#: documents/serialisers.py:2394
|
#: documents/serialisers.py:2406
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Custom field id must be an integer: %(id)s"
|
msgid "Custom field id must be an integer: %(id)s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: documents/serialisers.py:2401
|
#: documents/serialisers.py:2413
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Custom field with id %(id)s does not exist"
|
msgid "Custom field with id %(id)s does not exist"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: documents/serialisers.py:2418 documents/serialisers.py:2428
|
#: documents/serialisers.py:2430 documents/serialisers.py:2440
|
||||||
msgid "Custom fields must be a list of integers or an object mapping ids to values."
|
msgid "Custom fields must be a list of integers or an object mapping ids to values."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: documents/serialisers.py:2423
|
#: documents/serialisers.py:2435
|
||||||
msgid "Some custom fields don't exist or were specified twice."
|
msgid "Some custom fields don't exist or were specified twice."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: documents/serialisers.py:2570
|
#: documents/serialisers.py:2582
|
||||||
msgid "Invalid variable detected."
|
msgid "Invalid variable detected."
|
||||||
msgstr "اكتشاف متغير خاطئ."
|
msgstr "اكتشاف متغير خاطئ."
|
||||||
|
|
||||||
#: documents/serialisers.py:2939
|
#: documents/serialisers.py:2951
|
||||||
msgid "Duplicate document identifiers are not allowed."
|
msgid "Duplicate document identifiers are not allowed."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: documents/serialisers.py:2969 documents/views.py:4763
|
#: documents/serialisers.py:2981 documents/views.py:4784
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Documents not found: %(ids)s"
|
msgid "Documents not found: %(ids)s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -1911,40 +1911,40 @@ msgstr ""
|
|||||||
msgid "Unable to parse URI {value}"
|
msgid "Unable to parse URI {value}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: documents/views.py:336 documents/views.py:2723
|
#: documents/views.py:335 documents/views.py:2726
|
||||||
msgid "Invalid more_like_id"
|
msgid "Invalid more_like_id"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: documents/views.py:1670
|
#: documents/views.py:1673
|
||||||
msgid "Invalid AI configuration."
|
msgid "Invalid AI configuration."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: documents/views.py:1681
|
#: documents/views.py:1684
|
||||||
msgid "AI backend request timed out."
|
msgid "AI backend request timed out."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: documents/views.py:1693
|
#: documents/views.py:1696
|
||||||
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:2548 documents/views.py:2864
|
#: documents/views.py:2551 documents/views.py:2867
|
||||||
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:4776
|
#: 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:4822
|
#: documents/views.py:4843
|
||||||
msgid "Bundle is already being processed."
|
msgid "Bundle is already being processed."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: documents/views.py:4886
|
#: documents/views.py:4907
|
||||||
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:4900
|
#: documents/views.py:4921
|
||||||
msgid "The share link bundle is unavailable."
|
msgid "The share link bundle is unavailable."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -2189,194 +2189,198 @@ msgid "Sets the LLM embedding model"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/models.py:369
|
#: paperless/models.py:369
|
||||||
msgid "Sets the LLM embedding endpoint, optional"
|
msgid "Sets the LLM embedding API key"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/models.py:376
|
#: paperless/models.py:376
|
||||||
|
msgid "Sets the LLM embedding endpoint, optional"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: paperless/models.py:383
|
||||||
msgid "Sets the LLM embedding chunk size"
|
msgid "Sets the LLM embedding chunk size"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/models.py:382
|
#: paperless/models.py:389
|
||||||
msgid "Sets the LLM context size"
|
msgid "Sets the LLM context size"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/models.py:388
|
#: paperless/models.py:395
|
||||||
msgid "Sets the LLM backend"
|
msgid "Sets the LLM backend"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/models.py:396
|
#: paperless/models.py:403
|
||||||
msgid "Sets the LLM model"
|
msgid "Sets the LLM model"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/models.py:403
|
#: paperless/models.py:410
|
||||||
msgid "Sets the LLM API key"
|
msgid "Sets the LLM API key"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/models.py:410
|
#: paperless/models.py:417
|
||||||
msgid "Sets the LLM endpoint, optional"
|
msgid "Sets the LLM endpoint, optional"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/models.py:417
|
#: paperless/models.py:424
|
||||||
msgid "Sets the LLM output language"
|
msgid "Sets the LLM output language"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/models.py:424
|
#: paperless/models.py:431
|
||||||
msgid "Sets the LLM timeout in seconds"
|
msgid "Sets the LLM timeout in seconds"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/models.py:430
|
#: paperless/models.py:437
|
||||||
msgid "paperless application settings"
|
msgid "paperless application settings"
|
||||||
msgstr "إعدادات التطبيق paperless"
|
msgstr "إعدادات التطبيق paperless"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:558
|
#: paperless/settings/__init__.py:560
|
||||||
msgid "English (US)"
|
msgid "English (US)"
|
||||||
msgstr "الإنجليزية (الولايات المتحدة)"
|
msgstr "الإنجليزية (الولايات المتحدة)"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:559
|
#: paperless/settings/__init__.py:561
|
||||||
msgid "Arabic"
|
msgid "Arabic"
|
||||||
msgstr "العربية"
|
msgstr "العربية"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:560
|
#: paperless/settings/__init__.py:562
|
||||||
msgid "Afrikaans"
|
msgid "Afrikaans"
|
||||||
msgstr "اللغة الأفريقانية"
|
msgstr "اللغة الأفريقانية"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:561
|
#: paperless/settings/__init__.py:563
|
||||||
msgid "Belarusian"
|
msgid "Belarusian"
|
||||||
msgstr "البيلاروسية"
|
msgstr "البيلاروسية"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:562
|
#: paperless/settings/__init__.py:564
|
||||||
msgid "Bulgarian"
|
msgid "Bulgarian"
|
||||||
msgstr "البلغارية"
|
msgstr "البلغارية"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:563
|
#: paperless/settings/__init__.py:565
|
||||||
msgid "Catalan"
|
msgid "Catalan"
|
||||||
msgstr "اللغة الكتالونية"
|
msgstr "اللغة الكتالونية"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:564
|
#: paperless/settings/__init__.py:566
|
||||||
msgid "Czech"
|
msgid "Czech"
|
||||||
msgstr "التشيكية"
|
msgstr "التشيكية"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:565
|
#: paperless/settings/__init__.py:567
|
||||||
msgid "Danish"
|
msgid "Danish"
|
||||||
msgstr "الدانماركية"
|
msgstr "الدانماركية"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:566
|
#: paperless/settings/__init__.py:568
|
||||||
msgid "German"
|
msgid "German"
|
||||||
msgstr "الألمانية"
|
msgstr "الألمانية"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:567
|
#: paperless/settings/__init__.py:569
|
||||||
msgid "Greek"
|
msgid "Greek"
|
||||||
msgstr "اليونانية"
|
msgstr "اليونانية"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:568
|
#: paperless/settings/__init__.py:570
|
||||||
msgid "English (GB)"
|
msgid "English (GB)"
|
||||||
msgstr "الإنجليزية (المملكة المتحدة)"
|
msgstr "الإنجليزية (المملكة المتحدة)"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:569
|
#: paperless/settings/__init__.py:571
|
||||||
msgid "Spanish"
|
msgid "Spanish"
|
||||||
msgstr "الإسبانية"
|
msgstr "الإسبانية"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:570
|
#: paperless/settings/__init__.py:572
|
||||||
msgid "Persian"
|
msgid "Persian"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:571
|
#: paperless/settings/__init__.py:573
|
||||||
msgid "Finnish"
|
msgid "Finnish"
|
||||||
msgstr "الفنلندية"
|
msgstr "الفنلندية"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:572
|
#: paperless/settings/__init__.py:574
|
||||||
msgid "French"
|
msgid "French"
|
||||||
msgstr "الفرنسية"
|
msgstr "الفرنسية"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:573
|
#: paperless/settings/__init__.py:575
|
||||||
msgid "Hungarian"
|
msgid "Hungarian"
|
||||||
msgstr "المجرية"
|
msgstr "المجرية"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:574
|
#: paperless/settings/__init__.py:576
|
||||||
msgid "Indonesian"
|
msgid "Indonesian"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:575
|
#: paperless/settings/__init__.py:577
|
||||||
msgid "Italian"
|
msgid "Italian"
|
||||||
msgstr "الإيطالية"
|
msgstr "الإيطالية"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:576
|
#: paperless/settings/__init__.py:578
|
||||||
msgid "Japanese"
|
msgid "Japanese"
|
||||||
msgstr "اليابانية"
|
msgstr "اليابانية"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:577
|
#: paperless/settings/__init__.py:579
|
||||||
msgid "Korean"
|
msgid "Korean"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:578
|
#: paperless/settings/__init__.py:580
|
||||||
msgid "Luxembourgish"
|
msgid "Luxembourgish"
|
||||||
msgstr "اللوكسمبرجية"
|
msgstr "اللوكسمبرجية"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:579
|
#: paperless/settings/__init__.py:581
|
||||||
msgid "Norwegian"
|
msgid "Norwegian"
|
||||||
msgstr "النرويجية"
|
msgstr "النرويجية"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:580
|
#: paperless/settings/__init__.py:582
|
||||||
msgid "Dutch"
|
msgid "Dutch"
|
||||||
msgstr "الهولندية"
|
msgstr "الهولندية"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:581
|
#: paperless/settings/__init__.py:583
|
||||||
msgid "Polish"
|
msgid "Polish"
|
||||||
msgstr "البولندية"
|
msgstr "البولندية"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:582
|
#: paperless/settings/__init__.py:584
|
||||||
msgid "Portuguese (Brazil)"
|
msgid "Portuguese (Brazil)"
|
||||||
msgstr "البرتغالية (البرازيل)"
|
msgstr "البرتغالية (البرازيل)"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:583
|
#: paperless/settings/__init__.py:585
|
||||||
msgid "Portuguese"
|
msgid "Portuguese"
|
||||||
msgstr "البرتغالية"
|
msgstr "البرتغالية"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:584
|
#: paperless/settings/__init__.py:586
|
||||||
msgid "Romanian"
|
msgid "Romanian"
|
||||||
msgstr "الرومانية"
|
msgstr "الرومانية"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:585
|
#: paperless/settings/__init__.py:587
|
||||||
msgid "Russian"
|
msgid "Russian"
|
||||||
msgstr "الروسية"
|
msgstr "الروسية"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:586
|
#: paperless/settings/__init__.py:588
|
||||||
msgid "Slovak"
|
msgid "Slovak"
|
||||||
msgstr "السلوفاكية"
|
msgstr "السلوفاكية"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:587
|
#: paperless/settings/__init__.py:589
|
||||||
msgid "Slovenian"
|
msgid "Slovenian"
|
||||||
msgstr "السلوفانية"
|
msgstr "السلوفانية"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:588
|
#: paperless/settings/__init__.py:590
|
||||||
msgid "Serbian"
|
msgid "Serbian"
|
||||||
msgstr "الصربية"
|
msgstr "الصربية"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:589
|
#: paperless/settings/__init__.py:591
|
||||||
msgid "Swedish"
|
msgid "Swedish"
|
||||||
msgstr "السويدية"
|
msgstr "السويدية"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:590
|
#: paperless/settings/__init__.py:592
|
||||||
msgid "Turkish"
|
msgid "Turkish"
|
||||||
msgstr "التركية"
|
msgstr "التركية"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:591
|
#: paperless/settings/__init__.py:593
|
||||||
msgid "Ukrainian"
|
msgid "Ukrainian"
|
||||||
msgstr "الأوكرانية"
|
msgstr "الأوكرانية"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:592
|
#: paperless/settings/__init__.py:594
|
||||||
msgid "Vietnamese"
|
msgid "Vietnamese"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:593
|
#: paperless/settings/__init__.py:595
|
||||||
msgid "Chinese Simplified"
|
msgid "Chinese Simplified"
|
||||||
msgstr "الصينية المبسطة"
|
msgstr "الصينية المبسطة"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:594
|
#: paperless/settings/__init__.py:596
|
||||||
msgid "Chinese Traditional"
|
msgid "Chinese Traditional"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/urls.py:435
|
#: paperless/urls.py:438
|
||||||
msgid "Paperless-ngx administration"
|
msgid "Paperless-ngx administration"
|
||||||
msgstr "Paperless-ngx الإدارة"
|
msgstr "Paperless-ngx الإدارة"
|
||||||
|
|
||||||
|
|||||||
@@ -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-09-18 01:29+0000\n"
|
"POT-Creation-Date: 2026-10-02 23:09+0000\n"
|
||||||
"PO-Revision-Date: 2026-09-18 01:30\n"
|
"PO-Revision-Date: 2026-10-02 23:10\n"
|
||||||
"Last-Translator: \n"
|
"Last-Translator: \n"
|
||||||
"Language-Team: Belarusian\n"
|
"Language-Team: Belarusian\n"
|
||||||
"Language: be_BY\n"
|
"Language: be_BY\n"
|
||||||
@@ -1615,7 +1615,7 @@ msgid "workflow runs"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: documents/serialisers.py:514 documents/serialisers.py:871
|
#: documents/serialisers.py:514 documents/serialisers.py:871
|
||||||
#: documents/serialisers.py:2883 documents/views.py:343 documents/views.py:2726
|
#: documents/serialisers.py:2895 documents/views.py:342 documents/views.py:2729
|
||||||
#: paperless_mail/serialisers.py:156
|
#: paperless_mail/serialisers.py:156
|
||||||
msgid "Insufficient permissions."
|
msgid "Insufficient permissions."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -1624,38 +1624,38 @@ msgstr ""
|
|||||||
msgid "Invalid color."
|
msgid "Invalid color."
|
||||||
msgstr "Няправільны колер."
|
msgstr "Няправільны колер."
|
||||||
|
|
||||||
#: documents/serialisers.py:2350
|
#: documents/serialisers.py:2362
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "File type %(type)s not supported"
|
msgid "File type %(type)s not supported"
|
||||||
msgstr "Тып файла %(type)s не падтрымліваецца"
|
msgstr "Тып файла %(type)s не падтрымліваецца"
|
||||||
|
|
||||||
#: documents/serialisers.py:2394
|
#: documents/serialisers.py:2406
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Custom field id must be an integer: %(id)s"
|
msgid "Custom field id must be an integer: %(id)s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: documents/serialisers.py:2401
|
#: documents/serialisers.py:2413
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Custom field with id %(id)s does not exist"
|
msgid "Custom field with id %(id)s does not exist"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: documents/serialisers.py:2418 documents/serialisers.py:2428
|
#: documents/serialisers.py:2430 documents/serialisers.py:2440
|
||||||
msgid "Custom fields must be a list of integers or an object mapping ids to values."
|
msgid "Custom fields must be a list of integers or an object mapping ids to values."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: documents/serialisers.py:2423
|
#: documents/serialisers.py:2435
|
||||||
msgid "Some custom fields don't exist or were specified twice."
|
msgid "Some custom fields don't exist or were specified twice."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: documents/serialisers.py:2570
|
#: documents/serialisers.py:2582
|
||||||
msgid "Invalid variable detected."
|
msgid "Invalid variable detected."
|
||||||
msgstr "Выяўлена няправільная зменная."
|
msgstr "Выяўлена няправільная зменная."
|
||||||
|
|
||||||
#: documents/serialisers.py:2939
|
#: documents/serialisers.py:2951
|
||||||
msgid "Duplicate document identifiers are not allowed."
|
msgid "Duplicate document identifiers are not allowed."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: documents/serialisers.py:2969 documents/views.py:4763
|
#: documents/serialisers.py:2981 documents/views.py:4784
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Documents not found: %(ids)s"
|
msgid "Documents not found: %(ids)s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -1910,40 +1910,40 @@ msgstr ""
|
|||||||
msgid "Unable to parse URI {value}"
|
msgid "Unable to parse URI {value}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: documents/views.py:336 documents/views.py:2723
|
#: documents/views.py:335 documents/views.py:2726
|
||||||
msgid "Invalid more_like_id"
|
msgid "Invalid more_like_id"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: documents/views.py:1670
|
#: documents/views.py:1673
|
||||||
msgid "Invalid AI configuration."
|
msgid "Invalid AI configuration."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: documents/views.py:1681
|
#: documents/views.py:1684
|
||||||
msgid "AI backend request timed out."
|
msgid "AI backend request timed out."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: documents/views.py:1693
|
#: documents/views.py:1696
|
||||||
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:2548 documents/views.py:2864
|
#: documents/views.py:2551 documents/views.py:2867
|
||||||
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:4776
|
#: 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:4822
|
#: documents/views.py:4843
|
||||||
msgid "Bundle is already being processed."
|
msgid "Bundle is already being processed."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: documents/views.py:4886
|
#: documents/views.py:4907
|
||||||
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:4900
|
#: documents/views.py:4921
|
||||||
msgid "The share link bundle is unavailable."
|
msgid "The share link bundle is unavailable."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -2188,194 +2188,198 @@ msgid "Sets the LLM embedding model"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/models.py:369
|
#: paperless/models.py:369
|
||||||
msgid "Sets the LLM embedding endpoint, optional"
|
msgid "Sets the LLM embedding API key"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/models.py:376
|
#: paperless/models.py:376
|
||||||
|
msgid "Sets the LLM embedding endpoint, optional"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: paperless/models.py:383
|
||||||
msgid "Sets the LLM embedding chunk size"
|
msgid "Sets the LLM embedding chunk size"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/models.py:382
|
#: paperless/models.py:389
|
||||||
msgid "Sets the LLM context size"
|
msgid "Sets the LLM context size"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/models.py:388
|
#: paperless/models.py:395
|
||||||
msgid "Sets the LLM backend"
|
msgid "Sets the LLM backend"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/models.py:396
|
#: paperless/models.py:403
|
||||||
msgid "Sets the LLM model"
|
msgid "Sets the LLM model"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/models.py:403
|
#: paperless/models.py:410
|
||||||
msgid "Sets the LLM API key"
|
msgid "Sets the LLM API key"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/models.py:410
|
#: paperless/models.py:417
|
||||||
msgid "Sets the LLM endpoint, optional"
|
msgid "Sets the LLM endpoint, optional"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/models.py:417
|
#: paperless/models.py:424
|
||||||
msgid "Sets the LLM output language"
|
msgid "Sets the LLM output language"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/models.py:424
|
#: paperless/models.py:431
|
||||||
msgid "Sets the LLM timeout in seconds"
|
msgid "Sets the LLM timeout in seconds"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/models.py:430
|
#: paperless/models.py:437
|
||||||
msgid "paperless application settings"
|
msgid "paperless application settings"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:558
|
#: paperless/settings/__init__.py:560
|
||||||
msgid "English (US)"
|
msgid "English (US)"
|
||||||
msgstr "Англійская (ЗША)"
|
msgstr "Англійская (ЗША)"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:559
|
#: paperless/settings/__init__.py:561
|
||||||
msgid "Arabic"
|
msgid "Arabic"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:560
|
#: paperless/settings/__init__.py:562
|
||||||
msgid "Afrikaans"
|
msgid "Afrikaans"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:561
|
#: paperless/settings/__init__.py:563
|
||||||
msgid "Belarusian"
|
msgid "Belarusian"
|
||||||
msgstr "Беларуская"
|
msgstr "Беларуская"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:562
|
#: paperless/settings/__init__.py:564
|
||||||
msgid "Bulgarian"
|
msgid "Bulgarian"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:563
|
#: paperless/settings/__init__.py:565
|
||||||
msgid "Catalan"
|
msgid "Catalan"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:564
|
#: paperless/settings/__init__.py:566
|
||||||
msgid "Czech"
|
msgid "Czech"
|
||||||
msgstr "Чэшская"
|
msgstr "Чэшская"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:565
|
#: paperless/settings/__init__.py:567
|
||||||
msgid "Danish"
|
msgid "Danish"
|
||||||
msgstr "Дацкая"
|
msgstr "Дацкая"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:566
|
#: paperless/settings/__init__.py:568
|
||||||
msgid "German"
|
msgid "German"
|
||||||
msgstr "Нямецкая"
|
msgstr "Нямецкая"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:567
|
#: paperless/settings/__init__.py:569
|
||||||
msgid "Greek"
|
msgid "Greek"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:568
|
#: paperless/settings/__init__.py:570
|
||||||
msgid "English (GB)"
|
msgid "English (GB)"
|
||||||
msgstr "Англійская (Вялікабрытанія)"
|
msgstr "Англійская (Вялікабрытанія)"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:569
|
#: paperless/settings/__init__.py:571
|
||||||
msgid "Spanish"
|
msgid "Spanish"
|
||||||
msgstr "Іспанская"
|
msgstr "Іспанская"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:570
|
#: paperless/settings/__init__.py:572
|
||||||
msgid "Persian"
|
msgid "Persian"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:571
|
#: paperless/settings/__init__.py:573
|
||||||
msgid "Finnish"
|
msgid "Finnish"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:572
|
#: paperless/settings/__init__.py:574
|
||||||
msgid "French"
|
msgid "French"
|
||||||
msgstr "Французская"
|
msgstr "Французская"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:573
|
#: paperless/settings/__init__.py:575
|
||||||
msgid "Hungarian"
|
msgid "Hungarian"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:574
|
#: paperless/settings/__init__.py:576
|
||||||
msgid "Indonesian"
|
msgid "Indonesian"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:575
|
#: paperless/settings/__init__.py:577
|
||||||
msgid "Italian"
|
msgid "Italian"
|
||||||
msgstr "Італьянская"
|
msgstr "Італьянская"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:576
|
#: paperless/settings/__init__.py:578
|
||||||
msgid "Japanese"
|
msgid "Japanese"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:577
|
#: paperless/settings/__init__.py:579
|
||||||
msgid "Korean"
|
msgid "Korean"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:578
|
#: paperless/settings/__init__.py:580
|
||||||
msgid "Luxembourgish"
|
msgid "Luxembourgish"
|
||||||
msgstr "Люксембургская"
|
msgstr "Люксембургская"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:579
|
#: paperless/settings/__init__.py:581
|
||||||
msgid "Norwegian"
|
msgid "Norwegian"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:580
|
#: paperless/settings/__init__.py:582
|
||||||
msgid "Dutch"
|
msgid "Dutch"
|
||||||
msgstr "Нідэрландская"
|
msgstr "Нідэрландская"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:581
|
#: paperless/settings/__init__.py:583
|
||||||
msgid "Polish"
|
msgid "Polish"
|
||||||
msgstr "Польская"
|
msgstr "Польская"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:582
|
#: paperless/settings/__init__.py:584
|
||||||
msgid "Portuguese (Brazil)"
|
msgid "Portuguese (Brazil)"
|
||||||
msgstr "Партугальская (Бразілія)"
|
msgstr "Партугальская (Бразілія)"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:583
|
#: paperless/settings/__init__.py:585
|
||||||
msgid "Portuguese"
|
msgid "Portuguese"
|
||||||
msgstr "Партугальская"
|
msgstr "Партугальская"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:584
|
#: paperless/settings/__init__.py:586
|
||||||
msgid "Romanian"
|
msgid "Romanian"
|
||||||
msgstr "Румынская"
|
msgstr "Румынская"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:585
|
#: paperless/settings/__init__.py:587
|
||||||
msgid "Russian"
|
msgid "Russian"
|
||||||
msgstr "Руская"
|
msgstr "Руская"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:586
|
#: paperless/settings/__init__.py:588
|
||||||
msgid "Slovak"
|
msgid "Slovak"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:587
|
#: paperless/settings/__init__.py:589
|
||||||
msgid "Slovenian"
|
msgid "Slovenian"
|
||||||
msgstr "Славенская"
|
msgstr "Славенская"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:588
|
#: paperless/settings/__init__.py:590
|
||||||
msgid "Serbian"
|
msgid "Serbian"
|
||||||
msgstr "Сербская"
|
msgstr "Сербская"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:589
|
#: paperless/settings/__init__.py:591
|
||||||
msgid "Swedish"
|
msgid "Swedish"
|
||||||
msgstr "Шведская"
|
msgstr "Шведская"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:590
|
#: paperless/settings/__init__.py:592
|
||||||
msgid "Turkish"
|
msgid "Turkish"
|
||||||
msgstr "Турэцкая"
|
msgstr "Турэцкая"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:591
|
#: paperless/settings/__init__.py:593
|
||||||
msgid "Ukrainian"
|
msgid "Ukrainian"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:592
|
#: paperless/settings/__init__.py:594
|
||||||
msgid "Vietnamese"
|
msgid "Vietnamese"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:593
|
#: paperless/settings/__init__.py:595
|
||||||
msgid "Chinese Simplified"
|
msgid "Chinese Simplified"
|
||||||
msgstr "Кітайская спрошчаная"
|
msgstr "Кітайская спрошчаная"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:594
|
#: paperless/settings/__init__.py:596
|
||||||
msgid "Chinese Traditional"
|
msgid "Chinese Traditional"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/urls.py:435
|
#: paperless/urls.py:438
|
||||||
msgid "Paperless-ngx administration"
|
msgid "Paperless-ngx administration"
|
||||||
msgstr "Адміністраванне Paperless-ngx"
|
msgstr "Адміністраванне Paperless-ngx"
|
||||||
|
|
||||||
|
|||||||
@@ -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-09-18 01:29+0000\n"
|
"POT-Creation-Date: 2026-10-02 23:09+0000\n"
|
||||||
"PO-Revision-Date: 2026-09-18 01:30\n"
|
"PO-Revision-Date: 2026-10-02 23:10\n"
|
||||||
"Last-Translator: \n"
|
"Last-Translator: \n"
|
||||||
"Language-Team: Bulgarian\n"
|
"Language-Team: Bulgarian\n"
|
||||||
"Language: bg_BG\n"
|
"Language: bg_BG\n"
|
||||||
@@ -1615,7 +1615,7 @@ msgid "workflow runs"
|
|||||||
msgstr "стартиране на работните процеси"
|
msgstr "стартиране на работните процеси"
|
||||||
|
|
||||||
#: documents/serialisers.py:514 documents/serialisers.py:871
|
#: documents/serialisers.py:514 documents/serialisers.py:871
|
||||||
#: documents/serialisers.py:2883 documents/views.py:343 documents/views.py:2726
|
#: documents/serialisers.py:2895 documents/views.py:342 documents/views.py:2729
|
||||||
#: paperless_mail/serialisers.py:156
|
#: paperless_mail/serialisers.py:156
|
||||||
msgid "Insufficient permissions."
|
msgid "Insufficient permissions."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -1624,38 +1624,38 @@ msgstr ""
|
|||||||
msgid "Invalid color."
|
msgid "Invalid color."
|
||||||
msgstr "Невалиден цвят."
|
msgstr "Невалиден цвят."
|
||||||
|
|
||||||
#: documents/serialisers.py:2350
|
#: documents/serialisers.py:2362
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "File type %(type)s not supported"
|
msgid "File type %(type)s not supported"
|
||||||
msgstr "Файловия тип %(type)s не се поддържа"
|
msgstr "Файловия тип %(type)s не се поддържа"
|
||||||
|
|
||||||
#: documents/serialisers.py:2394
|
#: documents/serialisers.py:2406
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Custom field id must be an integer: %(id)s"
|
msgid "Custom field id must be an integer: %(id)s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: documents/serialisers.py:2401
|
#: documents/serialisers.py:2413
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Custom field with id %(id)s does not exist"
|
msgid "Custom field with id %(id)s does not exist"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: documents/serialisers.py:2418 documents/serialisers.py:2428
|
#: documents/serialisers.py:2430 documents/serialisers.py:2440
|
||||||
msgid "Custom fields must be a list of integers or an object mapping ids to values."
|
msgid "Custom fields must be a list of integers or an object mapping ids to values."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: documents/serialisers.py:2423
|
#: documents/serialisers.py:2435
|
||||||
msgid "Some custom fields don't exist or were specified twice."
|
msgid "Some custom fields don't exist or were specified twice."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: documents/serialisers.py:2570
|
#: documents/serialisers.py:2582
|
||||||
msgid "Invalid variable detected."
|
msgid "Invalid variable detected."
|
||||||
msgstr "Засечена е невалидна променлива."
|
msgstr "Засечена е невалидна променлива."
|
||||||
|
|
||||||
#: documents/serialisers.py:2939
|
#: documents/serialisers.py:2951
|
||||||
msgid "Duplicate document identifiers are not allowed."
|
msgid "Duplicate document identifiers are not allowed."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: documents/serialisers.py:2969 documents/views.py:4763
|
#: documents/serialisers.py:2981 documents/views.py:4784
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Documents not found: %(ids)s"
|
msgid "Documents not found: %(ids)s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -1911,40 +1911,40 @@ msgstr ""
|
|||||||
msgid "Unable to parse URI {value}"
|
msgid "Unable to parse URI {value}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: documents/views.py:336 documents/views.py:2723
|
#: documents/views.py:335 documents/views.py:2726
|
||||||
msgid "Invalid more_like_id"
|
msgid "Invalid more_like_id"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: documents/views.py:1670
|
#: documents/views.py:1673
|
||||||
msgid "Invalid AI configuration."
|
msgid "Invalid AI configuration."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: documents/views.py:1681
|
#: documents/views.py:1684
|
||||||
msgid "AI backend request timed out."
|
msgid "AI backend request timed out."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: documents/views.py:1693
|
#: documents/views.py:1696
|
||||||
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:2548 documents/views.py:2864
|
#: documents/views.py:2551 documents/views.py:2867
|
||||||
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:4776
|
#: 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:4822
|
#: documents/views.py:4843
|
||||||
msgid "Bundle is already being processed."
|
msgid "Bundle is already being processed."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: documents/views.py:4886
|
#: documents/views.py:4907
|
||||||
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:4900
|
#: documents/views.py:4921
|
||||||
msgid "The share link bundle is unavailable."
|
msgid "The share link bundle is unavailable."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -2189,194 +2189,198 @@ msgid "Sets the LLM embedding model"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/models.py:369
|
#: paperless/models.py:369
|
||||||
msgid "Sets the LLM embedding endpoint, optional"
|
msgid "Sets the LLM embedding API key"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/models.py:376
|
#: paperless/models.py:376
|
||||||
|
msgid "Sets the LLM embedding endpoint, optional"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: paperless/models.py:383
|
||||||
msgid "Sets the LLM embedding chunk size"
|
msgid "Sets the LLM embedding chunk size"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/models.py:382
|
#: paperless/models.py:389
|
||||||
msgid "Sets the LLM context size"
|
msgid "Sets the LLM context size"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/models.py:388
|
#: paperless/models.py:395
|
||||||
msgid "Sets the LLM backend"
|
msgid "Sets the LLM backend"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/models.py:396
|
#: paperless/models.py:403
|
||||||
msgid "Sets the LLM model"
|
msgid "Sets the LLM model"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/models.py:403
|
#: paperless/models.py:410
|
||||||
msgid "Sets the LLM API key"
|
msgid "Sets the LLM API key"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/models.py:410
|
#: paperless/models.py:417
|
||||||
msgid "Sets the LLM endpoint, optional"
|
msgid "Sets the LLM endpoint, optional"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/models.py:417
|
#: paperless/models.py:424
|
||||||
msgid "Sets the LLM output language"
|
msgid "Sets the LLM output language"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/models.py:424
|
#: paperless/models.py:431
|
||||||
msgid "Sets the LLM timeout in seconds"
|
msgid "Sets the LLM timeout in seconds"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/models.py:430
|
#: paperless/models.py:437
|
||||||
msgid "paperless application settings"
|
msgid "paperless application settings"
|
||||||
msgstr "настройки на софтуера"
|
msgstr "настройки на софтуера"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:558
|
#: paperless/settings/__init__.py:560
|
||||||
msgid "English (US)"
|
msgid "English (US)"
|
||||||
msgstr "Английски (САЩ)"
|
msgstr "Английски (САЩ)"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:559
|
#: paperless/settings/__init__.py:561
|
||||||
msgid "Arabic"
|
msgid "Arabic"
|
||||||
msgstr "Арабски"
|
msgstr "Арабски"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:560
|
#: paperless/settings/__init__.py:562
|
||||||
msgid "Afrikaans"
|
msgid "Afrikaans"
|
||||||
msgstr "Африканс"
|
msgstr "Африканс"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:561
|
#: paperless/settings/__init__.py:563
|
||||||
msgid "Belarusian"
|
msgid "Belarusian"
|
||||||
msgstr "Беларуски"
|
msgstr "Беларуски"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:562
|
#: paperless/settings/__init__.py:564
|
||||||
msgid "Bulgarian"
|
msgid "Bulgarian"
|
||||||
msgstr "Български"
|
msgstr "Български"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:563
|
#: paperless/settings/__init__.py:565
|
||||||
msgid "Catalan"
|
msgid "Catalan"
|
||||||
msgstr "Каталунски"
|
msgstr "Каталунски"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:564
|
#: paperless/settings/__init__.py:566
|
||||||
msgid "Czech"
|
msgid "Czech"
|
||||||
msgstr "Чешки"
|
msgstr "Чешки"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:565
|
#: paperless/settings/__init__.py:567
|
||||||
msgid "Danish"
|
msgid "Danish"
|
||||||
msgstr "Датски"
|
msgstr "Датски"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:566
|
#: paperless/settings/__init__.py:568
|
||||||
msgid "German"
|
msgid "German"
|
||||||
msgstr "Немски"
|
msgstr "Немски"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:567
|
#: paperless/settings/__init__.py:569
|
||||||
msgid "Greek"
|
msgid "Greek"
|
||||||
msgstr "Гръцки"
|
msgstr "Гръцки"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:568
|
#: paperless/settings/__init__.py:570
|
||||||
msgid "English (GB)"
|
msgid "English (GB)"
|
||||||
msgstr "Английски (Великобритания)"
|
msgstr "Английски (Великобритания)"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:569
|
#: paperless/settings/__init__.py:571
|
||||||
msgid "Spanish"
|
msgid "Spanish"
|
||||||
msgstr "Испански"
|
msgstr "Испански"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:570
|
#: paperless/settings/__init__.py:572
|
||||||
msgid "Persian"
|
msgid "Persian"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:571
|
#: paperless/settings/__init__.py:573
|
||||||
msgid "Finnish"
|
msgid "Finnish"
|
||||||
msgstr "Финландски"
|
msgstr "Финландски"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:572
|
#: paperless/settings/__init__.py:574
|
||||||
msgid "French"
|
msgid "French"
|
||||||
msgstr "Френски"
|
msgstr "Френски"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:573
|
#: paperless/settings/__init__.py:575
|
||||||
msgid "Hungarian"
|
msgid "Hungarian"
|
||||||
msgstr "Унгарски"
|
msgstr "Унгарски"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:574
|
#: paperless/settings/__init__.py:576
|
||||||
msgid "Indonesian"
|
msgid "Indonesian"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:575
|
#: paperless/settings/__init__.py:577
|
||||||
msgid "Italian"
|
msgid "Italian"
|
||||||
msgstr "Италиански"
|
msgstr "Италиански"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:576
|
#: paperless/settings/__init__.py:578
|
||||||
msgid "Japanese"
|
msgid "Japanese"
|
||||||
msgstr "Японски"
|
msgstr "Японски"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:577
|
#: paperless/settings/__init__.py:579
|
||||||
msgid "Korean"
|
msgid "Korean"
|
||||||
msgstr "Корейски"
|
msgstr "Корейски"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:578
|
#: paperless/settings/__init__.py:580
|
||||||
msgid "Luxembourgish"
|
msgid "Luxembourgish"
|
||||||
msgstr "Люксембургски"
|
msgstr "Люксембургски"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:579
|
#: paperless/settings/__init__.py:581
|
||||||
msgid "Norwegian"
|
msgid "Norwegian"
|
||||||
msgstr "Норвежки"
|
msgstr "Норвежки"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:580
|
#: paperless/settings/__init__.py:582
|
||||||
msgid "Dutch"
|
msgid "Dutch"
|
||||||
msgstr "Холандски"
|
msgstr "Холандски"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:581
|
#: paperless/settings/__init__.py:583
|
||||||
msgid "Polish"
|
msgid "Polish"
|
||||||
msgstr "Полски"
|
msgstr "Полски"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:582
|
#: paperless/settings/__init__.py:584
|
||||||
msgid "Portuguese (Brazil)"
|
msgid "Portuguese (Brazil)"
|
||||||
msgstr "Португалски (Бразилия)"
|
msgstr "Португалски (Бразилия)"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:583
|
#: paperless/settings/__init__.py:585
|
||||||
msgid "Portuguese"
|
msgid "Portuguese"
|
||||||
msgstr "Португалски"
|
msgstr "Португалски"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:584
|
#: paperless/settings/__init__.py:586
|
||||||
msgid "Romanian"
|
msgid "Romanian"
|
||||||
msgstr "Румънски"
|
msgstr "Румънски"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:585
|
#: paperless/settings/__init__.py:587
|
||||||
msgid "Russian"
|
msgid "Russian"
|
||||||
msgstr "Руски"
|
msgstr "Руски"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:586
|
#: paperless/settings/__init__.py:588
|
||||||
msgid "Slovak"
|
msgid "Slovak"
|
||||||
msgstr "Словашки"
|
msgstr "Словашки"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:587
|
#: paperless/settings/__init__.py:589
|
||||||
msgid "Slovenian"
|
msgid "Slovenian"
|
||||||
msgstr "Словенски"
|
msgstr "Словенски"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:588
|
#: paperless/settings/__init__.py:590
|
||||||
msgid "Serbian"
|
msgid "Serbian"
|
||||||
msgstr "Сръбски"
|
msgstr "Сръбски"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:589
|
#: paperless/settings/__init__.py:591
|
||||||
msgid "Swedish"
|
msgid "Swedish"
|
||||||
msgstr "Шведски"
|
msgstr "Шведски"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:590
|
#: paperless/settings/__init__.py:592
|
||||||
msgid "Turkish"
|
msgid "Turkish"
|
||||||
msgstr "Турски"
|
msgstr "Турски"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:591
|
#: paperless/settings/__init__.py:593
|
||||||
msgid "Ukrainian"
|
msgid "Ukrainian"
|
||||||
msgstr "Украински"
|
msgstr "Украински"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:592
|
#: paperless/settings/__init__.py:594
|
||||||
msgid "Vietnamese"
|
msgid "Vietnamese"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:593
|
#: paperless/settings/__init__.py:595
|
||||||
msgid "Chinese Simplified"
|
msgid "Chinese Simplified"
|
||||||
msgstr "Китайски опростен"
|
msgstr "Китайски опростен"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:594
|
#: paperless/settings/__init__.py:596
|
||||||
msgid "Chinese Traditional"
|
msgid "Chinese Traditional"
|
||||||
msgstr "Китайски традиционен"
|
msgstr "Китайски традиционен"
|
||||||
|
|
||||||
#: paperless/urls.py:435
|
#: paperless/urls.py:438
|
||||||
msgid "Paperless-ngx administration"
|
msgid "Paperless-ngx administration"
|
||||||
msgstr "Paperless-ngx администрация"
|
msgstr "Paperless-ngx администрация"
|
||||||
|
|
||||||
|
|||||||
@@ -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-09-18 01:29+0000\n"
|
"POT-Creation-Date: 2026-10-02 23:09+0000\n"
|
||||||
"PO-Revision-Date: 2026-09-18 01:30\n"
|
"PO-Revision-Date: 2026-10-02 23:10\n"
|
||||||
"Last-Translator: \n"
|
"Last-Translator: \n"
|
||||||
"Language-Team: Catalan\n"
|
"Language-Team: Catalan\n"
|
||||||
"Language: ca_ES\n"
|
"Language: ca_ES\n"
|
||||||
@@ -1615,7 +1615,7 @@ msgid "workflow runs"
|
|||||||
msgstr "flux corrents"
|
msgstr "flux corrents"
|
||||||
|
|
||||||
#: documents/serialisers.py:514 documents/serialisers.py:871
|
#: documents/serialisers.py:514 documents/serialisers.py:871
|
||||||
#: documents/serialisers.py:2883 documents/views.py:343 documents/views.py:2726
|
#: documents/serialisers.py:2895 documents/views.py:342 documents/views.py:2729
|
||||||
#: paperless_mail/serialisers.py:156
|
#: paperless_mail/serialisers.py:156
|
||||||
msgid "Insufficient permissions."
|
msgid "Insufficient permissions."
|
||||||
msgstr "Permisos insuficients."
|
msgstr "Permisos insuficients."
|
||||||
@@ -1624,38 +1624,38 @@ msgstr "Permisos insuficients."
|
|||||||
msgid "Invalid color."
|
msgid "Invalid color."
|
||||||
msgstr "Color Invàlid."
|
msgstr "Color Invàlid."
|
||||||
|
|
||||||
#: documents/serialisers.py:2350
|
#: documents/serialisers.py:2362
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "File type %(type)s not supported"
|
msgid "File type %(type)s not supported"
|
||||||
msgstr "Tipus arxiu %(type)s no suportat"
|
msgstr "Tipus arxiu %(type)s no suportat"
|
||||||
|
|
||||||
#: documents/serialisers.py:2394
|
#: documents/serialisers.py:2406
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Custom field id must be an integer: %(id)s"
|
msgid "Custom field id must be an integer: %(id)s"
|
||||||
msgstr "ID de camp personalizat ha de ser enter: %(id)s"
|
msgstr "ID de camp personalizat ha de ser enter: %(id)s"
|
||||||
|
|
||||||
#: documents/serialisers.py:2401
|
#: documents/serialisers.py:2413
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Custom field with id %(id)s does not exist"
|
msgid "Custom field with id %(id)s does not exist"
|
||||||
msgstr "Camp personalitzat amb ID %(id)s no existeix"
|
msgstr "Camp personalitzat amb ID %(id)s no existeix"
|
||||||
|
|
||||||
#: documents/serialisers.py:2418 documents/serialisers.py:2428
|
#: documents/serialisers.py:2430 documents/serialisers.py:2440
|
||||||
msgid "Custom fields must be a list of integers or an object mapping ids to values."
|
msgid "Custom fields must be a list of integers or an object mapping ids to values."
|
||||||
msgstr "Camps personalitzats han de ser una llista d'enters o un objecte que mapegi els identificadors amb els valors."
|
msgstr "Camps personalitzats han de ser una llista d'enters o un objecte que mapegi els identificadors amb els valors."
|
||||||
|
|
||||||
#: documents/serialisers.py:2423
|
#: documents/serialisers.py:2435
|
||||||
msgid "Some custom fields don't exist or were specified twice."
|
msgid "Some custom fields don't exist or were specified twice."
|
||||||
msgstr "Alguns camps personalitzats no existeixen o s'han especificat dues vegades."
|
msgstr "Alguns camps personalitzats no existeixen o s'han especificat dues vegades."
|
||||||
|
|
||||||
#: documents/serialisers.py:2570
|
#: documents/serialisers.py:2582
|
||||||
msgid "Invalid variable detected."
|
msgid "Invalid variable detected."
|
||||||
msgstr "Variable detectada invàlida."
|
msgstr "Variable detectada invàlida."
|
||||||
|
|
||||||
#: documents/serialisers.py:2939
|
#: documents/serialisers.py:2951
|
||||||
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:2969 documents/views.py:4763
|
#: documents/serialisers.py:2981 documents/views.py:4784
|
||||||
#, 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"
|
||||||
@@ -1911,40 +1911,40 @@ msgstr "L'esquema d'URI '{parts.scheme}' no està permès. Esquemes permesos: {'
|
|||||||
msgid "Unable to parse URI {value}"
|
msgid "Unable to parse URI {value}"
|
||||||
msgstr "No s'ha pogut analitzar l'URI {value}"
|
msgstr "No s'ha pogut analitzar l'URI {value}"
|
||||||
|
|
||||||
#: documents/views.py:336 documents/views.py:2723
|
#: documents/views.py:335 documents/views.py:2726
|
||||||
msgid "Invalid more_like_id"
|
msgid "Invalid more_like_id"
|
||||||
msgstr "Invalid more_like_id"
|
msgstr "Invalid more_like_id"
|
||||||
|
|
||||||
#: documents/views.py:1670
|
#: documents/views.py:1673
|
||||||
msgid "Invalid AI configuration."
|
msgid "Invalid AI configuration."
|
||||||
msgstr "Configuració AI invàlida."
|
msgstr "Configuració AI invàlida."
|
||||||
|
|
||||||
#: documents/views.py:1681
|
#: documents/views.py:1684
|
||||||
msgid "AI backend request timed out."
|
msgid "AI backend request timed out."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: documents/views.py:1693
|
#: documents/views.py:1696
|
||||||
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:2548 documents/views.py:2864
|
#: documents/views.py:2551 documents/views.py:2867
|
||||||
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:4776
|
#: 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:4822
|
#: documents/views.py:4843
|
||||||
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:4886
|
#: documents/views.py:4907
|
||||||
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:4900
|
#: documents/views.py:4921
|
||||||
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."
|
||||||
|
|
||||||
@@ -2189,194 +2189,198 @@ msgid "Sets the LLM embedding model"
|
|||||||
msgstr "Defineix model d'incrustació LLM"
|
msgstr "Defineix model d'incrustació LLM"
|
||||||
|
|
||||||
#: paperless/models.py:369
|
#: paperless/models.py:369
|
||||||
|
msgid "Sets the LLM embedding API key"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: paperless/models.py:376
|
||||||
msgid "Sets the LLM embedding endpoint, optional"
|
msgid "Sets the LLM embedding endpoint, optional"
|
||||||
msgstr "Defineix el punt final d'incrustació de LLM, opcional"
|
msgstr "Defineix el punt final d'incrustació de LLM, opcional"
|
||||||
|
|
||||||
#: paperless/models.py:376
|
#: paperless/models.py:383
|
||||||
msgid "Sets the LLM embedding chunk size"
|
msgid "Sets the LLM embedding chunk size"
|
||||||
msgstr "Defineix la mida del fragment d'incrustació de LLM"
|
msgstr "Defineix la mida del fragment d'incrustació de LLM"
|
||||||
|
|
||||||
#: paperless/models.py:382
|
#: paperless/models.py:389
|
||||||
msgid "Sets the LLM context size"
|
msgid "Sets the LLM context size"
|
||||||
msgstr "Defineix la mida del context LLM"
|
msgstr "Defineix la mida del context LLM"
|
||||||
|
|
||||||
#: paperless/models.py:388
|
#: paperless/models.py:395
|
||||||
msgid "Sets the LLM backend"
|
msgid "Sets the LLM backend"
|
||||||
msgstr "Estableix backend LLM"
|
msgstr "Estableix backend LLM"
|
||||||
|
|
||||||
#: paperless/models.py:396
|
#: paperless/models.py:403
|
||||||
msgid "Sets the LLM model"
|
msgid "Sets the LLM model"
|
||||||
msgstr "Estableix model LLM"
|
msgstr "Estableix model LLM"
|
||||||
|
|
||||||
#: paperless/models.py:403
|
#: paperless/models.py:410
|
||||||
msgid "Sets the LLM API key"
|
msgid "Sets the LLM API key"
|
||||||
msgstr "Estableix clau API de LLM"
|
msgstr "Estableix clau API de LLM"
|
||||||
|
|
||||||
#: paperless/models.py:410
|
#: paperless/models.py:417
|
||||||
msgid "Sets the LLM endpoint, optional"
|
msgid "Sets the LLM endpoint, optional"
|
||||||
msgstr "Estableix el punt final de l'LLM, opcional"
|
msgstr "Estableix el punt final de l'LLM, opcional"
|
||||||
|
|
||||||
#: paperless/models.py:417
|
#: paperless/models.py:424
|
||||||
msgid "Sets the LLM output language"
|
msgid "Sets the LLM output language"
|
||||||
msgstr "Estableix l'idioma de sortida de LLM"
|
msgstr "Estableix l'idioma de sortida de LLM"
|
||||||
|
|
||||||
#: paperless/models.py:424
|
#: paperless/models.py:431
|
||||||
msgid "Sets the LLM timeout in seconds"
|
msgid "Sets the LLM timeout in seconds"
|
||||||
msgstr "Estableix temps d'espera en segons"
|
msgstr "Estableix temps d'espera en segons"
|
||||||
|
|
||||||
#: paperless/models.py:430
|
#: paperless/models.py:437
|
||||||
msgid "paperless application settings"
|
msgid "paperless application settings"
|
||||||
msgstr "configuració de l'aplicació paperless"
|
msgstr "configuració de l'aplicació paperless"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:558
|
#: paperless/settings/__init__.py:560
|
||||||
msgid "English (US)"
|
msgid "English (US)"
|
||||||
msgstr "Anglès (US)"
|
msgstr "Anglès (US)"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:559
|
#: paperless/settings/__init__.py:561
|
||||||
msgid "Arabic"
|
msgid "Arabic"
|
||||||
msgstr "Àrab"
|
msgstr "Àrab"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:560
|
#: paperless/settings/__init__.py:562
|
||||||
msgid "Afrikaans"
|
msgid "Afrikaans"
|
||||||
msgstr "Africà"
|
msgstr "Africà"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:561
|
#: paperless/settings/__init__.py:563
|
||||||
msgid "Belarusian"
|
msgid "Belarusian"
|
||||||
msgstr "Bielorús"
|
msgstr "Bielorús"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:562
|
#: paperless/settings/__init__.py:564
|
||||||
msgid "Bulgarian"
|
msgid "Bulgarian"
|
||||||
msgstr "Búlgar"
|
msgstr "Búlgar"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:563
|
#: paperless/settings/__init__.py:565
|
||||||
msgid "Catalan"
|
msgid "Catalan"
|
||||||
msgstr "Català"
|
msgstr "Català"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:564
|
#: paperless/settings/__init__.py:566
|
||||||
msgid "Czech"
|
msgid "Czech"
|
||||||
msgstr "Txec"
|
msgstr "Txec"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:565
|
#: paperless/settings/__init__.py:567
|
||||||
msgid "Danish"
|
msgid "Danish"
|
||||||
msgstr "Danès"
|
msgstr "Danès"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:566
|
#: paperless/settings/__init__.py:568
|
||||||
msgid "German"
|
msgid "German"
|
||||||
msgstr "Alemany"
|
msgstr "Alemany"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:567
|
#: paperless/settings/__init__.py:569
|
||||||
msgid "Greek"
|
msgid "Greek"
|
||||||
msgstr "Grec"
|
msgstr "Grec"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:568
|
#: paperless/settings/__init__.py:570
|
||||||
msgid "English (GB)"
|
msgid "English (GB)"
|
||||||
msgstr "Anglès (GB)"
|
msgstr "Anglès (GB)"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:569
|
#: paperless/settings/__init__.py:571
|
||||||
msgid "Spanish"
|
msgid "Spanish"
|
||||||
msgstr "Espanyol"
|
msgstr "Espanyol"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:570
|
#: paperless/settings/__init__.py:572
|
||||||
msgid "Persian"
|
msgid "Persian"
|
||||||
msgstr "Persa"
|
msgstr "Persa"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:571
|
#: paperless/settings/__init__.py:573
|
||||||
msgid "Finnish"
|
msgid "Finnish"
|
||||||
msgstr "Finès"
|
msgstr "Finès"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:572
|
#: paperless/settings/__init__.py:574
|
||||||
msgid "French"
|
msgid "French"
|
||||||
msgstr "Francès"
|
msgstr "Francès"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:573
|
#: paperless/settings/__init__.py:575
|
||||||
msgid "Hungarian"
|
msgid "Hungarian"
|
||||||
msgstr "Hongarès"
|
msgstr "Hongarès"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:574
|
#: paperless/settings/__init__.py:576
|
||||||
msgid "Indonesian"
|
msgid "Indonesian"
|
||||||
msgstr "Indonesi"
|
msgstr "Indonesi"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:575
|
#: paperless/settings/__init__.py:577
|
||||||
msgid "Italian"
|
msgid "Italian"
|
||||||
msgstr "Italià"
|
msgstr "Italià"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:576
|
#: paperless/settings/__init__.py:578
|
||||||
msgid "Japanese"
|
msgid "Japanese"
|
||||||
msgstr "Japonès"
|
msgstr "Japonès"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:577
|
#: paperless/settings/__init__.py:579
|
||||||
msgid "Korean"
|
msgid "Korean"
|
||||||
msgstr "Coreà"
|
msgstr "Coreà"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:578
|
#: paperless/settings/__init__.py:580
|
||||||
msgid "Luxembourgish"
|
msgid "Luxembourgish"
|
||||||
msgstr "Luxemburguès"
|
msgstr "Luxemburguès"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:579
|
#: paperless/settings/__init__.py:581
|
||||||
msgid "Norwegian"
|
msgid "Norwegian"
|
||||||
msgstr "Noruec"
|
msgstr "Noruec"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:580
|
#: paperless/settings/__init__.py:582
|
||||||
msgid "Dutch"
|
msgid "Dutch"
|
||||||
msgstr "Holandès"
|
msgstr "Holandès"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:581
|
#: paperless/settings/__init__.py:583
|
||||||
msgid "Polish"
|
msgid "Polish"
|
||||||
msgstr "Polonès"
|
msgstr "Polonès"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:582
|
#: paperless/settings/__init__.py:584
|
||||||
msgid "Portuguese (Brazil)"
|
msgid "Portuguese (Brazil)"
|
||||||
msgstr "Portuguès (Brasil)"
|
msgstr "Portuguès (Brasil)"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:583
|
#: paperless/settings/__init__.py:585
|
||||||
msgid "Portuguese"
|
msgid "Portuguese"
|
||||||
msgstr "Portuguès"
|
msgstr "Portuguès"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:584
|
#: paperless/settings/__init__.py:586
|
||||||
msgid "Romanian"
|
msgid "Romanian"
|
||||||
msgstr "Romanès"
|
msgstr "Romanès"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:585
|
#: paperless/settings/__init__.py:587
|
||||||
msgid "Russian"
|
msgid "Russian"
|
||||||
msgstr "Rus"
|
msgstr "Rus"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:586
|
#: paperless/settings/__init__.py:588
|
||||||
msgid "Slovak"
|
msgid "Slovak"
|
||||||
msgstr "Eslovac"
|
msgstr "Eslovac"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:587
|
#: paperless/settings/__init__.py:589
|
||||||
msgid "Slovenian"
|
msgid "Slovenian"
|
||||||
msgstr "Eslovè"
|
msgstr "Eslovè"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:588
|
#: paperless/settings/__init__.py:590
|
||||||
msgid "Serbian"
|
msgid "Serbian"
|
||||||
msgstr "Serbi"
|
msgstr "Serbi"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:589
|
#: paperless/settings/__init__.py:591
|
||||||
msgid "Swedish"
|
msgid "Swedish"
|
||||||
msgstr "Suec"
|
msgstr "Suec"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:590
|
#: paperless/settings/__init__.py:592
|
||||||
msgid "Turkish"
|
msgid "Turkish"
|
||||||
msgstr "Turc"
|
msgstr "Turc"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:591
|
#: paperless/settings/__init__.py:593
|
||||||
msgid "Ukrainian"
|
msgid "Ukrainian"
|
||||||
msgstr "Ucranià"
|
msgstr "Ucranià"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:592
|
#: paperless/settings/__init__.py:594
|
||||||
msgid "Vietnamese"
|
msgid "Vietnamese"
|
||||||
msgstr "Vietnamita"
|
msgstr "Vietnamita"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:593
|
#: paperless/settings/__init__.py:595
|
||||||
msgid "Chinese Simplified"
|
msgid "Chinese Simplified"
|
||||||
msgstr "Xinès Simplificat"
|
msgstr "Xinès Simplificat"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:594
|
#: paperless/settings/__init__.py:596
|
||||||
msgid "Chinese Traditional"
|
msgid "Chinese Traditional"
|
||||||
msgstr "Xinès tradicional"
|
msgstr "Xinès tradicional"
|
||||||
|
|
||||||
#: paperless/urls.py:435
|
#: paperless/urls.py:438
|
||||||
msgid "Paperless-ngx administration"
|
msgid "Paperless-ngx administration"
|
||||||
msgstr "Administració Paperless-ngx"
|
msgstr "Administració Paperless-ngx"
|
||||||
|
|
||||||
|
|||||||
@@ -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-09-18 01:29+0000\n"
|
"POT-Creation-Date: 2026-10-02 23:09+0000\n"
|
||||||
"PO-Revision-Date: 2026-09-18 01:30\n"
|
"PO-Revision-Date: 2026-10-02 23:10\n"
|
||||||
"Last-Translator: \n"
|
"Last-Translator: \n"
|
||||||
"Language-Team: Czech\n"
|
"Language-Team: Czech\n"
|
||||||
"Language: cs_CZ\n"
|
"Language: cs_CZ\n"
|
||||||
@@ -1615,7 +1615,7 @@ msgid "workflow runs"
|
|||||||
msgstr "spuštění pracovních postupů"
|
msgstr "spuštění pracovních postupů"
|
||||||
|
|
||||||
#: documents/serialisers.py:514 documents/serialisers.py:871
|
#: documents/serialisers.py:514 documents/serialisers.py:871
|
||||||
#: documents/serialisers.py:2883 documents/views.py:343 documents/views.py:2726
|
#: documents/serialisers.py:2895 documents/views.py:342 documents/views.py:2729
|
||||||
#: paperless_mail/serialisers.py:156
|
#: paperless_mail/serialisers.py:156
|
||||||
msgid "Insufficient permissions."
|
msgid "Insufficient permissions."
|
||||||
msgstr "Nedostatečná oprávnění."
|
msgstr "Nedostatečná oprávnění."
|
||||||
@@ -1624,38 +1624,38 @@ msgstr "Nedostatečná oprávnění."
|
|||||||
msgid "Invalid color."
|
msgid "Invalid color."
|
||||||
msgstr "Neplatná barva."
|
msgstr "Neplatná barva."
|
||||||
|
|
||||||
#: documents/serialisers.py:2350
|
#: documents/serialisers.py:2362
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "File type %(type)s not supported"
|
msgid "File type %(type)s not supported"
|
||||||
msgstr "Typ souboru %(type)s není podporován"
|
msgstr "Typ souboru %(type)s není podporován"
|
||||||
|
|
||||||
#: documents/serialisers.py:2394
|
#: documents/serialisers.py:2406
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Custom field id must be an integer: %(id)s"
|
msgid "Custom field id must be an integer: %(id)s"
|
||||||
msgstr "Vlastní ID pole musí být celé číslo: %(id)s"
|
msgstr "Vlastní ID pole musí být celé číslo: %(id)s"
|
||||||
|
|
||||||
#: documents/serialisers.py:2401
|
#: documents/serialisers.py:2413
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Custom field with id %(id)s does not exist"
|
msgid "Custom field with id %(id)s does not exist"
|
||||||
msgstr "Vlastní pole s ID %(id)s neexistuje"
|
msgstr "Vlastní pole s ID %(id)s neexistuje"
|
||||||
|
|
||||||
#: documents/serialisers.py:2418 documents/serialisers.py:2428
|
#: documents/serialisers.py:2430 documents/serialisers.py:2440
|
||||||
msgid "Custom fields must be a list of integers or an object mapping ids to values."
|
msgid "Custom fields must be a list of integers or an object mapping ids to values."
|
||||||
msgstr "Vlastní pole musí být seznam celých čísel nebo ID pro mapování objektů na hodnoty."
|
msgstr "Vlastní pole musí být seznam celých čísel nebo ID pro mapování objektů na hodnoty."
|
||||||
|
|
||||||
#: documents/serialisers.py:2423
|
#: documents/serialisers.py:2435
|
||||||
msgid "Some custom fields don't exist or were specified twice."
|
msgid "Some custom fields don't exist or were specified twice."
|
||||||
msgstr "Některá vlastní pole neexistují nebo byla zadána dvakrát."
|
msgstr "Některá vlastní pole neexistují nebo byla zadána dvakrát."
|
||||||
|
|
||||||
#: documents/serialisers.py:2570
|
#: documents/serialisers.py:2582
|
||||||
msgid "Invalid variable detected."
|
msgid "Invalid variable detected."
|
||||||
msgstr "Zjištěna neplatná proměnná."
|
msgstr "Zjištěna neplatná proměnná."
|
||||||
|
|
||||||
#: documents/serialisers.py:2939
|
#: documents/serialisers.py:2951
|
||||||
msgid "Duplicate document identifiers are not allowed."
|
msgid "Duplicate document identifiers are not allowed."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: documents/serialisers.py:2969 documents/views.py:4763
|
#: documents/serialisers.py:2981 documents/views.py:4784
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Documents not found: %(ids)s"
|
msgid "Documents not found: %(ids)s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -1912,40 +1912,40 @@ msgstr "URI schéma '{parts.scheme}' není povoleno. Povolená schémata: {',\n"
|
|||||||
msgid "Unable to parse URI {value}"
|
msgid "Unable to parse URI {value}"
|
||||||
msgstr "Nelze zpracovat URI {value}"
|
msgstr "Nelze zpracovat URI {value}"
|
||||||
|
|
||||||
#: documents/views.py:336 documents/views.py:2723
|
#: documents/views.py:335 documents/views.py:2726
|
||||||
msgid "Invalid more_like_id"
|
msgid "Invalid more_like_id"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: documents/views.py:1670
|
#: documents/views.py:1673
|
||||||
msgid "Invalid AI configuration."
|
msgid "Invalid AI configuration."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: documents/views.py:1681
|
#: documents/views.py:1684
|
||||||
msgid "AI backend request timed out."
|
msgid "AI backend request timed out."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: documents/views.py:1693
|
#: documents/views.py:1696
|
||||||
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:2548 documents/views.py:2864
|
#: documents/views.py:2551 documents/views.py:2867
|
||||||
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:4776
|
#: 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 "Nedostatečná oprávnění ke sdílení dokumentu %(id)s."
|
msgstr "Nedostatečná oprávnění ke sdílení dokumentu %(id)s."
|
||||||
|
|
||||||
#: documents/views.py:4822
|
#: documents/views.py:4843
|
||||||
msgid "Bundle is already being processed."
|
msgid "Bundle is already being processed."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: documents/views.py:4886
|
#: documents/views.py:4907
|
||||||
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:4900
|
#: documents/views.py:4921
|
||||||
msgid "The share link bundle is unavailable."
|
msgid "The share link bundle is unavailable."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -2190,194 +2190,198 @@ msgid "Sets the LLM embedding model"
|
|||||||
msgstr "Nastaví model vkládání LLM"
|
msgstr "Nastaví model vkládání LLM"
|
||||||
|
|
||||||
#: paperless/models.py:369
|
#: paperless/models.py:369
|
||||||
|
msgid "Sets the LLM embedding API key"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: paperless/models.py:376
|
||||||
msgid "Sets the LLM embedding endpoint, optional"
|
msgid "Sets the LLM embedding endpoint, optional"
|
||||||
msgstr "Nastaví koncový bod vkládání LLM, volitelné"
|
msgstr "Nastaví koncový bod vkládání LLM, volitelné"
|
||||||
|
|
||||||
#: paperless/models.py:376
|
#: paperless/models.py:383
|
||||||
msgid "Sets the LLM embedding chunk size"
|
msgid "Sets the LLM embedding chunk size"
|
||||||
msgstr "Nastaví velikost bloků vkládání LLM"
|
msgstr "Nastaví velikost bloků vkládání LLM"
|
||||||
|
|
||||||
#: paperless/models.py:382
|
#: paperless/models.py:389
|
||||||
msgid "Sets the LLM context size"
|
msgid "Sets the LLM context size"
|
||||||
msgstr "Nastaví velikost kontextu LLM"
|
msgstr "Nastaví velikost kontextu LLM"
|
||||||
|
|
||||||
#: paperless/models.py:388
|
#: paperless/models.py:395
|
||||||
msgid "Sets the LLM backend"
|
msgid "Sets the LLM backend"
|
||||||
msgstr "Nastaví backend LLM"
|
msgstr "Nastaví backend LLM"
|
||||||
|
|
||||||
#: paperless/models.py:396
|
#: paperless/models.py:403
|
||||||
msgid "Sets the LLM model"
|
msgid "Sets the LLM model"
|
||||||
msgstr "Nastaví model LLM"
|
msgstr "Nastaví model LLM"
|
||||||
|
|
||||||
#: paperless/models.py:403
|
#: paperless/models.py:410
|
||||||
msgid "Sets the LLM API key"
|
msgid "Sets the LLM API key"
|
||||||
msgstr "Nastaví klíč API LLM"
|
msgstr "Nastaví klíč API LLM"
|
||||||
|
|
||||||
#: paperless/models.py:410
|
#: paperless/models.py:417
|
||||||
msgid "Sets the LLM endpoint, optional"
|
msgid "Sets the LLM endpoint, optional"
|
||||||
msgstr "Nastaví koncový bod LLM, volitelné"
|
msgstr "Nastaví koncový bod LLM, volitelné"
|
||||||
|
|
||||||
#: paperless/models.py:417
|
#: paperless/models.py:424
|
||||||
msgid "Sets the LLM output language"
|
msgid "Sets the LLM output language"
|
||||||
msgstr "Nastaví výstupní jazyk LLM"
|
msgstr "Nastaví výstupní jazyk LLM"
|
||||||
|
|
||||||
#: paperless/models.py:424
|
#: paperless/models.py:431
|
||||||
msgid "Sets the LLM timeout in seconds"
|
msgid "Sets the LLM timeout in seconds"
|
||||||
msgstr "Nastaví časový limit LLM v sekundách"
|
msgstr "Nastaví časový limit LLM v sekundách"
|
||||||
|
|
||||||
#: paperless/models.py:430
|
#: paperless/models.py:437
|
||||||
msgid "paperless application settings"
|
msgid "paperless application settings"
|
||||||
msgstr "nastavení aplikace paperless"
|
msgstr "nastavení aplikace paperless"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:558
|
#: paperless/settings/__init__.py:560
|
||||||
msgid "English (US)"
|
msgid "English (US)"
|
||||||
msgstr "Angličtina (US)"
|
msgstr "Angličtina (US)"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:559
|
#: paperless/settings/__init__.py:561
|
||||||
msgid "Arabic"
|
msgid "Arabic"
|
||||||
msgstr "Arabština"
|
msgstr "Arabština"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:560
|
#: paperless/settings/__init__.py:562
|
||||||
msgid "Afrikaans"
|
msgid "Afrikaans"
|
||||||
msgstr "Afrikánština"
|
msgstr "Afrikánština"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:561
|
#: paperless/settings/__init__.py:563
|
||||||
msgid "Belarusian"
|
msgid "Belarusian"
|
||||||
msgstr "Běloruština"
|
msgstr "Běloruština"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:562
|
#: paperless/settings/__init__.py:564
|
||||||
msgid "Bulgarian"
|
msgid "Bulgarian"
|
||||||
msgstr "Bulharština"
|
msgstr "Bulharština"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:563
|
#: paperless/settings/__init__.py:565
|
||||||
msgid "Catalan"
|
msgid "Catalan"
|
||||||
msgstr "Katalánština"
|
msgstr "Katalánština"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:564
|
#: paperless/settings/__init__.py:566
|
||||||
msgid "Czech"
|
msgid "Czech"
|
||||||
msgstr "Čeština"
|
msgstr "Čeština"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:565
|
#: paperless/settings/__init__.py:567
|
||||||
msgid "Danish"
|
msgid "Danish"
|
||||||
msgstr "Dánština"
|
msgstr "Dánština"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:566
|
#: paperless/settings/__init__.py:568
|
||||||
msgid "German"
|
msgid "German"
|
||||||
msgstr "Němčina"
|
msgstr "Němčina"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:567
|
#: paperless/settings/__init__.py:569
|
||||||
msgid "Greek"
|
msgid "Greek"
|
||||||
msgstr "Řečtina"
|
msgstr "Řečtina"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:568
|
#: paperless/settings/__init__.py:570
|
||||||
msgid "English (GB)"
|
msgid "English (GB)"
|
||||||
msgstr "Angličtina (GB)"
|
msgstr "Angličtina (GB)"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:569
|
#: paperless/settings/__init__.py:571
|
||||||
msgid "Spanish"
|
msgid "Spanish"
|
||||||
msgstr "Španělština"
|
msgstr "Španělština"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:570
|
#: paperless/settings/__init__.py:572
|
||||||
msgid "Persian"
|
msgid "Persian"
|
||||||
msgstr "Perština"
|
msgstr "Perština"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:571
|
#: paperless/settings/__init__.py:573
|
||||||
msgid "Finnish"
|
msgid "Finnish"
|
||||||
msgstr "Finština"
|
msgstr "Finština"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:572
|
#: paperless/settings/__init__.py:574
|
||||||
msgid "French"
|
msgid "French"
|
||||||
msgstr "Francouzština"
|
msgstr "Francouzština"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:573
|
#: paperless/settings/__init__.py:575
|
||||||
msgid "Hungarian"
|
msgid "Hungarian"
|
||||||
msgstr "Maďarština"
|
msgstr "Maďarština"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:574
|
#: paperless/settings/__init__.py:576
|
||||||
msgid "Indonesian"
|
msgid "Indonesian"
|
||||||
msgstr "Indonéština"
|
msgstr "Indonéština"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:575
|
#: paperless/settings/__init__.py:577
|
||||||
msgid "Italian"
|
msgid "Italian"
|
||||||
msgstr "Italština"
|
msgstr "Italština"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:576
|
#: paperless/settings/__init__.py:578
|
||||||
msgid "Japanese"
|
msgid "Japanese"
|
||||||
msgstr "Japonština"
|
msgstr "Japonština"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:577
|
#: paperless/settings/__init__.py:579
|
||||||
msgid "Korean"
|
msgid "Korean"
|
||||||
msgstr "Korejština"
|
msgstr "Korejština"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:578
|
#: paperless/settings/__init__.py:580
|
||||||
msgid "Luxembourgish"
|
msgid "Luxembourgish"
|
||||||
msgstr "Lucemburština"
|
msgstr "Lucemburština"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:579
|
#: paperless/settings/__init__.py:581
|
||||||
msgid "Norwegian"
|
msgid "Norwegian"
|
||||||
msgstr "Norština"
|
msgstr "Norština"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:580
|
#: paperless/settings/__init__.py:582
|
||||||
msgid "Dutch"
|
msgid "Dutch"
|
||||||
msgstr "Holandština"
|
msgstr "Holandština"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:581
|
#: paperless/settings/__init__.py:583
|
||||||
msgid "Polish"
|
msgid "Polish"
|
||||||
msgstr "Polština"
|
msgstr "Polština"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:582
|
#: paperless/settings/__init__.py:584
|
||||||
msgid "Portuguese (Brazil)"
|
msgid "Portuguese (Brazil)"
|
||||||
msgstr "Portugalština (Brazílie)"
|
msgstr "Portugalština (Brazílie)"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:583
|
#: paperless/settings/__init__.py:585
|
||||||
msgid "Portuguese"
|
msgid "Portuguese"
|
||||||
msgstr "Portugalština"
|
msgstr "Portugalština"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:584
|
#: paperless/settings/__init__.py:586
|
||||||
msgid "Romanian"
|
msgid "Romanian"
|
||||||
msgstr "Rumunština"
|
msgstr "Rumunština"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:585
|
#: paperless/settings/__init__.py:587
|
||||||
msgid "Russian"
|
msgid "Russian"
|
||||||
msgstr "Ruština"
|
msgstr "Ruština"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:586
|
#: paperless/settings/__init__.py:588
|
||||||
msgid "Slovak"
|
msgid "Slovak"
|
||||||
msgstr "Slovenština"
|
msgstr "Slovenština"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:587
|
#: paperless/settings/__init__.py:589
|
||||||
msgid "Slovenian"
|
msgid "Slovenian"
|
||||||
msgstr "Slovinština"
|
msgstr "Slovinština"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:588
|
#: paperless/settings/__init__.py:590
|
||||||
msgid "Serbian"
|
msgid "Serbian"
|
||||||
msgstr "Srbština"
|
msgstr "Srbština"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:589
|
#: paperless/settings/__init__.py:591
|
||||||
msgid "Swedish"
|
msgid "Swedish"
|
||||||
msgstr "Švédština"
|
msgstr "Švédština"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:590
|
#: paperless/settings/__init__.py:592
|
||||||
msgid "Turkish"
|
msgid "Turkish"
|
||||||
msgstr "Turečtina"
|
msgstr "Turečtina"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:591
|
#: paperless/settings/__init__.py:593
|
||||||
msgid "Ukrainian"
|
msgid "Ukrainian"
|
||||||
msgstr "Ukrajinština"
|
msgstr "Ukrajinština"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:592
|
#: paperless/settings/__init__.py:594
|
||||||
msgid "Vietnamese"
|
msgid "Vietnamese"
|
||||||
msgstr "Vietnamština"
|
msgstr "Vietnamština"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:593
|
#: paperless/settings/__init__.py:595
|
||||||
msgid "Chinese Simplified"
|
msgid "Chinese Simplified"
|
||||||
msgstr "Čínština (zjednodušená)"
|
msgstr "Čínština (zjednodušená)"
|
||||||
|
|
||||||
#: paperless/settings/__init__.py:594
|
#: paperless/settings/__init__.py:596
|
||||||
msgid "Chinese Traditional"
|
msgid "Chinese Traditional"
|
||||||
msgstr "Čínština (tradiční)"
|
msgstr "Čínština (tradiční)"
|
||||||
|
|
||||||
#: paperless/urls.py:435
|
#: paperless/urls.py:438
|
||||||
msgid "Paperless-ngx administration"
|
msgid "Paperless-ngx administration"
|
||||||
msgstr "Administrace Paperless-ngx"
|
msgstr "Administrace Paperless-ngx"
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user